Work towards SD-over-sysex
parent
14d026d81d
commit
d75f392284
@ -0,0 +1,108 @@
|
||||
// intellectual property is bullshit bgdc
|
||||
|
||||
#include "ascii85.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define ASCII85_BASE 33
|
||||
|
||||
static inline uint8_t divmod85(uint32_t * x)
|
||||
{
|
||||
uint8_t mod = *x % 85;
|
||||
*x /= 85;
|
||||
return mod;
|
||||
}
|
||||
|
||||
size_t ascii85_encode(uint8_t * dest, uint8_t const * src, size_t len)
|
||||
{
|
||||
size_t total = 0;
|
||||
|
||||
while (len >= 4)
|
||||
{
|
||||
uint32_t n = (
|
||||
((uint32_t) src[0] << 24uL) |
|
||||
((uint32_t) src[1] << 16uL) |
|
||||
((uint32_t) src[2] << 8uL) |
|
||||
((uint32_t) src[3] << 0uL));
|
||||
|
||||
dest[4] = divmod85(&n) + ASCII85_BASE;
|
||||
dest[3] = divmod85(&n) + ASCII85_BASE;
|
||||
dest[2] = divmod85(&n) + ASCII85_BASE;
|
||||
dest[1] = divmod85(&n) + ASCII85_BASE;
|
||||
dest[0] = n + ASCII85_BASE; // Guaranteed < 85
|
||||
|
||||
src += 4;
|
||||
dest += 5;
|
||||
len -= 4;
|
||||
total += 5;
|
||||
}
|
||||
|
||||
if (len)
|
||||
{
|
||||
uint32_t n = 0;
|
||||
n = (uint32_t) src[0] << 24uL;
|
||||
if (len > 1) n |= ((uint32_t) src[1] << 16uL);
|
||||
if (len > 2) n |= ((uint32_t) src[2] << 8uL);
|
||||
if (len > 3) n |= ((uint32_t) src[3] << 0uL);
|
||||
|
||||
char a85[5];
|
||||
a85[4] = divmod85(&n) + ASCII85_BASE;
|
||||
a85[3] = divmod85(&n) + ASCII85_BASE;
|
||||
a85[2] = divmod85(&n) + ASCII85_BASE;
|
||||
a85[1] = divmod85(&n) + ASCII85_BASE;
|
||||
a85[0] = n + ASCII85_BASE; // As above
|
||||
|
||||
dest[0] = a85[0];
|
||||
dest[1] = a85[1];
|
||||
dest[2] = (len > 1) ? a85[2] : 0;
|
||||
dest[3] = (len > 2) ? a85[3] : 0;
|
||||
dest[4] = 0; // if we get here we're dropping at least one
|
||||
|
||||
total += len + 1;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
size_t ascii85_decode(uint8_t * dest, uint8_t const * src, size_t len)
|
||||
{
|
||||
size_t total = 0;
|
||||
|
||||
while (len >= 5)
|
||||
{
|
||||
uint32_t n = src[0] - ASCII85_BASE;
|
||||
n = 85 * n + src[1] - ASCII85_BASE;
|
||||
n = 85 * n + src[2] - ASCII85_BASE;
|
||||
n = 85 * n + src[3] - ASCII85_BASE;
|
||||
n = 85 * n + src[4] - ASCII85_BASE;
|
||||
|
||||
dest[0] = (n >> 24uL) & 0xFF;
|
||||
dest[1] = (n >> 16uL) & 0xFF;
|
||||
dest[2] = (n >> 8uL) & 0xFF;
|
||||
dest[3] = (n >> 0uL) & 0xFF;
|
||||
|
||||
src += 5;
|
||||
dest += 4;
|
||||
len -= 5;
|
||||
total += 4;
|
||||
}
|
||||
|
||||
if (len > 1)
|
||||
{
|
||||
uint32_t n = src[0] - ASCII85_BASE;
|
||||
n = 85 * n + src[1] - ASCII85_BASE;
|
||||
n = 85 * n + (len > 2 ? src[2] : 'u') - ASCII85_BASE;
|
||||
n = 85 * n + (len > 3 ? src[3] : 'u') - ASCII85_BASE;
|
||||
n = 85 * n;
|
||||
|
||||
dest[0] = (n >> 24uL) & 0xFF;
|
||||
if (len > 2) dest[1] = (n >> 16uL) & 0xFF;
|
||||
if (len > 3) dest[2] = (n >> 8uL) & 0xFF;
|
||||
|
||||
total += len - 1;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
// intellectual property is bullshit bgdc
|
||||
|
||||
#ifndef ASCII85_H
|
||||
#define ASCII85_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Encode a block to ascii85. The destination buffer must contain at least
|
||||
// (5/4) * rounded_up(len, 4) bytes (that is, enough bytes to encode src
|
||||
// including padding bytes).
|
||||
//
|
||||
// "z" as an abbreviation for a block of four null bytes is not implemented
|
||||
// to simplify buffer size requirements.
|
||||
//
|
||||
// Returns the total number of bytes used.
|
||||
size_t ascii85_encode(uint8_t * dest, uint8_t const * src, size_t len);
|
||||
|
||||
// Decode a block from ascii85. The destination buffer must contain at least
|
||||
// (4/5) * rounded_up(len, 5) bytes (that is, enough bytes to encode src
|
||||
// including possible padding bytes).
|
||||
//
|
||||
// "z" as an abbreviation for a block of four null bytes is not implemented
|
||||
// to simplify buffer size requirements.
|
||||
//
|
||||
// Returns the total number of bytes used.
|
||||
size_t ascii85_decode(uint8_t * dest, uint8_t const * src, size_t len);
|
||||
|
||||
#endif // !defined(ASCII85_H)
|
@ -0,0 +1,152 @@
|
||||
// intellectual property is bullshit bgdc
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// TODO make these progmem
|
||||
static const uint8_t enc_lut[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
// ascii 0x20 through 0x7F
|
||||
static const uint8_t dec_lut[] =
|
||||
{
|
||||
// ! " # $ % & '
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
|
||||
// ( ) * + , - . /
|
||||
-1, -1, -1, 62, -1, -1, -1, 63,
|
||||
|
||||
// 0 1 2 3 4 5 6 7
|
||||
52, 53, 54, 55, 56, 57, 58, 59,
|
||||
|
||||
// 8 9 : ; < = > ?
|
||||
60, 61, -1, -1, -1, 0, -1, -1,
|
||||
|
||||
// @ A B C D E F G
|
||||
-1, 0, 1, 2, 3, 4, 5, 6,
|
||||
|
||||
// H I J K L M N O
|
||||
7, 8, 9, 10, 11, 12, 13, 14,
|
||||
|
||||
// P Q R S T U V W
|
||||
15, 16, 17, 18, 19, 20, 21, 22,
|
||||
|
||||
// X Y Z [ \ ] ^ _
|
||||
23, 24, 25, -1, -1, -1, -1, -1,
|
||||
|
||||
// ` a b c d e f g
|
||||
-1, 26, 27, 28, 29, 30, 31, 32,
|
||||
|
||||
// h i j k l m n o
|
||||
33, 34, 35, 36, 37, 38, 39, 40,
|
||||
|
||||
// p q r s t u v w
|
||||
41, 42, 43, 44, 45, 46, 47, 48,
|
||||
|
||||
// x y z { | } ~ del
|
||||
49, 50, 51, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
#define DECODE(c) (((c) >= 0x20 && (c) <= 0x7F) ? dec_lut[(c) - 0x20] : (uint8_t)(-1))
|
||||
|
||||
static inline uint8_t divmod64(uint32_t * x)
|
||||
{
|
||||
uint8_t mod = *x & 0x3F;
|
||||
*x >>= 6;
|
||||
return mod;
|
||||
}
|
||||
|
||||
size_t base64_encode(uint8_t * dest, uint8_t const * src, size_t len)
|
||||
{
|
||||
size_t total = 0;
|
||||
|
||||
while (len >= 3)
|
||||
{
|
||||
uint32_t n = (
|
||||
((uint32_t) src[0] << 16uL) |
|
||||
((uint32_t) src[1] << 8uL) |
|
||||
((uint32_t) src[2] << 0uL));
|
||||
|
||||
dest[3] = enc_lut[divmod64(&n)];
|
||||
dest[2] = enc_lut[divmod64(&n)];
|
||||
dest[1] = enc_lut[divmod64(&n)];
|
||||
dest[0] = enc_lut[n]; // Guaranteed < 64
|
||||
|
||||
src += 3;
|
||||
dest += 4;
|
||||
len -= 3;
|
||||
total += 4;
|
||||
}
|
||||
|
||||
if (len)
|
||||
{
|
||||
uint32_t n = 0;
|
||||
n = (uint32_t) src[0] << 16uL;
|
||||
if (len > 1) n |= ((uint32_t) src[1] << 8uL);
|
||||
if (len > 2) n |= ((uint32_t) src[2] << 0uL);
|
||||
|
||||
divmod64(&n); // dropping at least one
|
||||
dest[3] = '=';
|
||||
dest[2] = enc_lut[divmod64(&n)];
|
||||
dest[1] = enc_lut[divmod64(&n)];
|
||||
dest[0] = enc_lut[n]; // Guaranteed < 64
|
||||
|
||||
if (len == 1) dest[2] = '=';
|
||||
total += 4;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
size_t base64_decode(uint8_t * dest, uint8_t const * src, size_t len)
|
||||
{
|
||||
size_t total = 0;
|
||||
|
||||
// Splitting the loops this way ensures the final block (possibly
|
||||
// containing =) is always processed by the last section but still
|
||||
// tolerates extra garbage (whitespace) on the end.
|
||||
|
||||
while (len >= 7)
|
||||
{
|
||||
uint32_t n = 0;
|
||||
n |= (uint32_t) DECODE(src[0]) << 18uL;
|
||||
n |= (uint32_t) DECODE(src[1]) << 12uL;
|
||||
n |= (uint32_t) DECODE(src[2]) << 6uL;
|
||||
n |= (uint32_t) DECODE(src[3]);
|
||||
|
||||
dest[0] = (n >> 16uL) & 0xFF;
|
||||
dest[1] = (n >> 8uL) & 0xFF;
|
||||
dest[2] = (n >> 0uL) & 0xFF;
|
||||
|
||||
src += 4;
|
||||
dest += 3;
|
||||
len -= 4;
|
||||
total += 3;
|
||||
}
|
||||
|
||||
if (len >= 4)
|
||||
{
|
||||
|
||||
uint32_t n = 0;
|
||||
n |= (uint32_t) DECODE(src[0]) << 18uL;
|
||||
n |= (uint32_t) DECODE(src[1]) << 12uL;
|
||||
n |= (uint32_t) DECODE(src[2]) << 6uL;
|
||||
n |= (uint32_t) DECODE(src[3]);
|
||||
|
||||
dest[0] = (n >> 16uL) & 0xFF;
|
||||
dest[1] = (n >> 8uL) & 0xFF;
|
||||
dest[2] = (n >> 0uL) & 0xFF;
|
||||
|
||||
int neq = !!(src[3] == '=') + !!(src[2] == '=');
|
||||
|
||||
src += 4;
|
||||
dest += 3 - neq;
|
||||
len -= 4;
|
||||
total += 3 - neq;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// intellectual property is bullshit bgdc
|
||||
|
||||
#ifndef BASE64_H
|
||||
#define BASE64_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Encode a block to base64. The destination buffer must contain at least
|
||||
// (4/3) * rounded_up(len, 3) bytes (that is, enough bytes to encode src
|
||||
// including padding bytes).
|
||||
//
|
||||
// Returns the total number of bytes used.
|
||||
size_t base64_encode(uint8_t * dest, uint8_t const * src, size_t len);
|
||||
|
||||
// Decode a block from base64. The destination buffer must contain at least
|
||||
// (3/4) * rounded_up(len, 4) bytes (that is, enough bytes to encode src
|
||||
// including possible padding bytes).
|
||||
//
|
||||
// Returns the total number of bytes used.
|
||||
size_t base64_decode(uint8_t * dest, uint8_t const * src, size_t len);
|
||||
|
||||
#endif // !defined(BASE64_H)
|
@ -1,7 +1,11 @@
|
||||
#pragma once
|
||||
#include "boarddefs.h"
|
||||
#include <avrstuff/spi_avrdx.hpp>
|
||||
|
||||
// Initialize pins on startup. Peripherals are not started here.
|
||||
void board_pins_init();
|
||||
|
||||
// Initialize peripherals.
|
||||
void board_peripherals_init();
|
||||
|
||||
extern spi_avrdx<SPI_SDCARD> spi_sdcard;
|
||||
|
@ -1,67 +0,0 @@
|
||||
#include "sd_spi_platform_dependencies.h"
|
||||
|
||||
void
|
||||
sd_spi_pin_mode(
|
||||
uint8_t pin,
|
||||
uint8_t mode
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
sd_spi_digital_write(
|
||||
uint8_t pin,
|
||||
uint8_t state
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint32_t
|
||||
sd_spi_millis(
|
||||
void
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
sd_spi_begin(
|
||||
void
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
sd_spi_begin_transaction(
|
||||
uint32_t transfer_speed_hz
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
sd_spi_end_transaction(
|
||||
void
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
sd_spi_send_byte(
|
||||
uint8_t b
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint8_t
|
||||
sd_spi_receive_byte(
|
||||
void
|
||||
)
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
#include <avrstuff/avlr.h>
|
||||
#include <board.hpp>
|
||||
|
||||
extern "C" {
|
||||
#include "sd_spi_platform_dependencies.h"
|
||||
}
|
||||
|
||||
extern "C" void sd_spi_pin_mode(uint8_t pin, uint8_t mode)
|
||||
{
|
||||
if (mode == OUTPUT)
|
||||
PORT_FOR(pin).DIRSET = BIT_FOR(pin);
|
||||
else
|
||||
PORT_FOR(pin).DIRCLR = BIT_FOR(pin);
|
||||
}
|
||||
|
||||
extern "C" void sd_spi_digital_write(uint8_t pin, uint8_t state)
|
||||
{
|
||||
if (state)
|
||||
PORT_FOR(pin).OUTSET = BIT_FOR(pin);
|
||||
else
|
||||
PORT_FOR(pin).OUTCLR = BIT_FOR(pin);
|
||||
}
|
||||
|
||||
extern "C" uint32_t sd_spi_millis()
|
||||
{
|
||||
// TODO - we don't have a millisecond counter until the timer module
|
||||
// is implemented
|
||||
static uint32_t m = 0;
|
||||
return m++;
|
||||
}
|
||||
|
||||
extern "C" void sd_spi_begin()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
extern "C" void sd_spi_begin_transaction(uint32_t transfer_speed_hz)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
extern "C" void sd_spi_end_transaction()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
extern "C" void sd_spi_send_byte(uint8_t b)
|
||||
{
|
||||
spi_sdcard.transfer(b);
|
||||
}
|
||||
|
||||
extern "C" uint8_t sd_spi_receive_byte()
|
||||
{
|
||||
return spi_sdcard.transfer(0xFF);
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
// intellectual property is bullshit bgdc
|
||||
|
||||
#ifndef SYSEX_HPP
|
||||
#define SYSEX_HPP
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// All sysex messages start with manuf id 7D (prototyping, test, private use,
|
||||
// and experimentation).
|
||||
//
|
||||
//
|
||||
// 7D 00 - front panel controls
|
||||
// 7D 01 - storage commands
|
||||
// 7D 7F - status codes
|
||||
//
|
||||
//
|
||||
// -- Storage commands --
|
||||
//
|
||||
// Storage commands interface with the onboard storage (SD card). Large
|
||||
// arguments are generally encoded using Ascii85.
|
||||
//
|
||||
// 7D 01 01 ... - data response message, Ascii85
|
||||
// 7D 01 02 A A A A A - request SD block AAA... (ascii85, data sent via 7D 01 01)
|
||||
// 7D 01 03 A A A A A ... - write SD block AAA... (data sent as Ascii85)
|
||||
// If data is not exactly 512 bytes long, nothing
|
||||
// is written and an error SYSEX_FMT is sent.
|
||||
//
|
||||
// -- Status codes --
|
||||
// 7D 7F 01 - general ACK
|
||||
// 7D 7F 02 - message format error
|
||||
|
||||
#define MIDI_MANUF_ID 0x7D
|
||||
|
||||
#define MIDI_SYSEX_STORAGE_GRP 0x01
|
||||
#define MIDI_SYSEX_STORAGE_RESPONSE 0x01
|
||||
#define MIDI_SYSEX_STORAGE_READ 0x02
|
||||
#define MIDI_SYSEX_STORAGE_WRITE 0x03
|
||||
|
||||
#define MIDI_SYSEX_STATUS_GRP 0x7F
|
||||
#define MIDI_SYSEX_STATUS_ACK 0x01
|
||||
#define MIDI_SYSEX_STATUS_FMT_ERR 0x02
|
||||
|
||||
#endif // !defined(SYSEX_HPP)
|
@ -0,0 +1,120 @@
|
||||
// intellectual property is bullshit bgdc
|
||||
|
||||
#include "ascii85.h"
|
||||
#include "base64.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static void usage(char const * argv0)
|
||||
{
|
||||
fprintf(stderr, "%s 85enc|85dec|64enc|64dec [IN [OUT]]\n", argv0);
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
bool decode = false;
|
||||
bool base64 = false;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "85enc"))
|
||||
{
|
||||
decode = false;
|
||||
base64 = false;
|
||||
}
|
||||
else if (!strcmp(argv[1], "85dec"))
|
||||
{
|
||||
decode = true;
|
||||
base64 = false;
|
||||
}
|
||||
else if (!strcmp(argv[1], "64enc"))
|
||||
{
|
||||
decode = false;
|
||||
base64 = true;
|
||||
}
|
||||
else if (!strcmp(argv[1], "64dec"))
|
||||
{
|
||||
decode = true;
|
||||
base64 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE * f_in = NULL, * f_out = NULL;
|
||||
|
||||
if (argc < 3)
|
||||
f_in = stdin;
|
||||
else if (!strcmp(argv[2], "-"))
|
||||
f_in = stdin;
|
||||
else
|
||||
{
|
||||
f_in = fopen(argv[2], "r");
|
||||
if (!f_in)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc < 4)
|
||||
f_out = stdout;
|
||||
else if (!strcmp(argv[3], "-"))
|
||||
f_out = stdout;
|
||||
else
|
||||
{
|
||||
f_out = fopen(argv[3], "w");
|
||||
if (!f_out)
|
||||
{
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t n_raw, n_encoded;
|
||||
|
||||
if (base64)
|
||||
{
|
||||
n_raw = 513;
|
||||
n_encoded = 684;
|
||||
}
|
||||
else
|
||||
{
|
||||
n_raw = 512;
|
||||
n_encoded = 640;
|
||||
}
|
||||
|
||||
uint8_t in_buffer[decode ? n_encoded : n_raw];
|
||||
uint8_t out_buffer[decode ? n_raw : n_encoded];
|
||||
|
||||
while (!ferror(f_in) && !feof(f_in) && !ferror(f_out) && !feof(f_out))
|
||||
{
|
||||
size_t n = fread(in_buffer, 1, sizeof(in_buffer), f_in);
|
||||
size_t n_converted;
|
||||
|
||||
if (decode && base64)
|
||||
n_converted = base64_decode(out_buffer, in_buffer, n);
|
||||
else if (!decode && base64)
|
||||
n_converted = base64_encode(out_buffer, in_buffer, n);
|
||||
else if (decode && !base64)
|
||||
n_converted = ascii85_encode(out_buffer, in_buffer, n);
|
||||
else
|
||||
n_converted = ascii85_decode(out_buffer, in_buffer, n);
|
||||
|
||||
fwrite(out_buffer, 1, n_converted, f_out);
|
||||
}
|
||||
|
||||
fclose(f_in);
|
||||
fclose(f_out);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue