// intellectual property is bullshit bgdc

#ifndef SYSEX_HPP
#define SYSEX_HPP

#include <stdbool.h>
#include <stddef.h>
#include <inttypes.h>

#include "midi.hpp"

// All sysex messages start with manuf id 7D (prototyping, test, private use,
// and experimentation).
//
//
// 7D 01        - storage commands
// 7D 02        - front panel controls
// 7D 7F        - status codes
//
//
// -- Storage commands --
//
// Storage commands interface with the onboard storage (SD card). Large
// arguments are generally encoded using base64, while smaller arguments are
// generally ascii hex.
//
// 7D 01 01 cksum ...          - data response message, base64
// 7D 01 02 AAAAAAAA           - request SD block AAA... (hex, data sent via 7D 01 01)
// 7D 01 03 AAAAAAAA           - open SD block AAA... for write (hex). If a
//                               write is ongoing, will return STATUS_BUSY.
// 7D 01 04 cksum ...          - append data to the write buffer.
// 7D 01 05                    - commit the in-progress write
// 7D 01 06                    - cancel the in-progress write
//
// -- Status codes --
// 7D 7F 01                    - general ACK
// 7D 7F 02                    - message format error
//
//
// == Writing data to storage ==
//
// To write a sector to the storage card, the sector must be opened using
// MIDI_SYSEX_STORAGE_OPENWR. The argument is a 32-bit (hex encoded) sector
// number, in 512-byte sectors. Following this, MIDI_SYSEX_STORAGE_WRDATA is
// sent repeatedly to append data to the write buffer. This data is encoded
// using base64, and up to (MIDIX_SYSEX_LEN - 8) base64 characters representing
// 42 bytes of data (assuming MIDIX_SYSEX_LEN is 64) may be sent at once. If
// more than 512 bytes are sent, the extras are dropped; if fewer than 512
// bytes are sent, the sector is padded with undefined data. Once the write
// buffer is full, commit it with MIDI_SYSEX_STORAGE_COMMIT or cancel the
// write with MIDI_SYSEX_STORAGE_CANCEL.  TODO: add a command to query this
// length limit
//
// No matter how many midi ports exist on the system, there is only one storage
// buffer, so you must expect to receive MIDI_SYSEX_STATUS_BUSY in response to
// OPENWR. In this case, poll with the same message to await completion. A user-
// confirmed hard cancel may be performed by sending MIDI_SYSEX_STORAGE_CANCEL
// (this can cancel the buffer regardless of which interface holds it).
//
// == Reading data from storage ==
//
// To read a sector from the storage card, send the sector number in the same
// format as for a write, using MIDI_SYSEX_STORAGE_READ. The data will be sent
// back in a series of MIDI_SYSEX_STORAGE_RESPONSE packets, followed by a
// MIDI_SYSEX_STATUS_ACK to acknowledge completion, or a MIDI_SYSEX_STATUS_IOERR
// at any point to terminate the process and report an error.
//
// == Storage checksums ==
//
// Both MIDI_SYSEX_STORAGE_RESPONSE and MIDI_SYSEX_STORAGE_WRDATA contain a
// checksum byte. This byte is simply the bit-inverted lower 7 bits of the sum
// of all data bytes in the message, prior to encoding as base64. If you send
// data and it is received with a bad checksum, a MIDI_SYSEX_STATUS_CKSUM will
// be sent back to you; you must cancel the write operation and retry it.
// If you receive a bad checksum, your recourse is to request it again.

#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_OPENWR   0x03
#define MIDI_SYSEX_STORAGE_WRDATA   0x04
#define MIDI_SYSEX_STORAGE_COMMIT   0x05
#define MIDI_SYSEX_STORAGE_CANCEL   0x06

#define MIDI_SYSEX_STATUS_GRP       0x7F
#define MIDI_SYSEX_STATUS_ACK       0x01
#define MIDI_SYSEX_STATUS_FMT_ERR   0x02
#define MIDI_SYSEX_STATUS_UNKNOWN   0x03
#define MIDI_SYSEX_STATUS_BUSY      0x04
#define MIDI_SYSEX_STATUS_IOERR     0x05
#define MIDI_SYSEX_STATUS_CKSUM     0x06

// Handle a sysex message
void sysex_handle(struct midi_message const * msg);

#endif // !defined(SYSEX_HPP)
