Work towards SD-over-sysex

trunk
alexis 2022-09-03 17:26:48 -06:00
parent 14d026d81d
commit d75f392284
15 changed files with 564 additions and 79 deletions

108
ascii85.c Normal file
View File

@ -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;
}

30
ascii85.h Normal file
View File

@ -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)

152
base64.c Normal file
View File

@ -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;
}

24
base64.h Normal file
View File

@ -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)

View File

@ -14,6 +14,8 @@ FUSES = {
.BOOTSIZE = 0x00
};
spi_avrdx<SPI_SDCARD> spi_sdcard;
void board_pins_init()
{
// We have a lot of analog inputs. Just disable ALL input buffers, then
@ -68,3 +70,8 @@ void board_pins_init()
DEBUGPINS_RUN();
}
void board_peripherals_init()
{
spi_sdcard.init(spi_sdcard.clockdiv::div2, true, 0);
}

View File

@ -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;

View File

@ -50,3 +50,6 @@
#define PIN_CIPO PINDEF(PORTG, 5)
#define PIN_SCK PINDEF(PORTG, 6)
#define PIN_nVS PINDEF(PORTG, 7)
#define SPI_VOICES 0
#define SPI_SDCARD 1

View File

@ -23,6 +23,7 @@ static midix midi(usbmidi_usart, midi_q);
int main(void)
{
board_pins_init();
board_peripherals_init();
usbmidi_usart.set_baud(31250);
usbmidi_usart.start(true, true, 'N', false);

View File

@ -1,16 +1,16 @@
project('poly1', ['cpp', 'c'], default_options: ['optimization=s', 'cpp_std=c++17'])
project('poly1', ['cpp', 'c'], default_options: ['optimization=2', 'cpp_std=c++17'])
atpack_zip = 'Microchip.AVR-Dx_DFP.2.1.152.atpack'
dependencies = []
local_headers = ['.', 'etl/include', 'sd-spi']
local_headers = ['.', 'etl/include']
sources = [
'main.cpp',
'board.cpp',
'midix.cpp',
'sd-spi/sd_spi.c',
'sd-spi/sd_spi_platform_dependencies.c',
'ascii85.c',
'base64.c',
]
_includes = local_headers
@ -23,16 +23,20 @@ if host_machine.cpu_family() != 'avr'
['test_midi.cpp', 'midix.cpp'],
include_directories: _incl_dirs,
)
test_ascii85 = executable(
'test_ascii85',
['test_ascii85.c', 'ascii85.c', 'base64.c'],
include_directories: _incl_dirs,
)
subdir_done()
endif
# debug build
if get_option('buildtype') == 'debug'
add_project_arguments(['-DDEBUG=1', '-ggdb3'], language: ['c', 'cpp'])
add_project_link_arguments(['-ggdb3'], language: ['c', 'cpp'])
else
add_project_arguments(['-ggdb3'], language: ['c', 'cpp'])
add_project_link_arguments(['-ggdb3'], language: ['c', 'cpp'])
endif
objcopy = find_program('objcopy')
@ -53,10 +57,7 @@ add_project_arguments(['-I' + atpack_path / 'include'], language: ['c', 'cpp'])
add_project_arguments(['-DETL_NO_STL=1'], language: ['c', 'cpp'])
opt_opts = ['-mrelax', '-flto']
add_project_arguments(opt_opts, language: ['c', 'cpp'])
add_project_link_arguments(opt_opts, language: ['c', 'cpp'])
add_project_arguments(['-mrelax'], language: ['c', 'cpp'])
atpack = custom_target(
'atpack',
command: [ 'unzip', '@INPUT@', '-d', '@OUTPUT@' ],

View File

@ -8,6 +8,8 @@
By defining SD_BUFFER, the library also implements a 512 byte buffer
for reading and writing.
modified in 2022 by alexis
@copyright Copyright 2015 Wade Penson
@license Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -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
)
{
}

View File

@ -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);
}

45
sysex.hpp Normal file
View File

@ -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)

120
test_ascii85.c Normal file
View File

@ -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;
}