Skip to content

Commit

Permalink
Merge pull request #12 from anarkiwi/msgs
Browse files Browse the repository at this point in the history
rearrange config messages, allow masking of status messages.
  • Loading branch information
anarkiwi committed Oct 1, 2020
2 parents 3ec4d87 + 3199451 commit 5102d38
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 28 deletions.
18 changes: 12 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Vessel's main points of differences from other C64 MIDI interfaces are:
* it uses the user port, not the cartridge port
* it does not use/need any CIA shift register ports
* it can transfer multiple bytes per transaction (unlike ACIA/6850 designs)
* the C64 can have configure Vessel to filter MIDI messages to save CPU time

If you are interested in acquiring a Vessel please contact [email protected].

Expand Down Expand Up @@ -67,12 +68,17 @@ The C64 can send Vessel a command, by sending byte 0xFD (not used by MIDI),
and then a command, and then a fixed number of data bytes (depending on the
command - unless otherwise specified, a command is followed by 0 data bytes).

By default, NMI on external input is off, all MIDI channels are masked (only
channel-less messages will be sent to the C64), and MIDI through is disabled.

* 0x00 HH LL CN: Config: channel mask high byte (HH), low byte (LL), and config byte (CN). Config byte bit 0 enables NMI, bit 1 enables MIDI through.
* 0x01: Reset. Vessel will reset to default config,
* 0x02: Version. Vessel will return a version string (currently ASCII "vessel0").
By default, NMI on external input is off, all MIDI channels are masked and
all status messages will be masked (no MIDI messages will be sent to the C64)
and MIDI through is disabled.

|byte|command |arg bytes|description
|----|------------|---------|--------------------------------------------------------------------------
|0x00|Reset | |Vessel will reset to default config,
|0x01|Version | |Vessel will return a version string (currently C64 screen code "vessel00").
|0x02|Config |CF |CF bit 0 enables NMI, bit 1 enables MIDI through.
|0x03|Channel mask|HH LL |High byte (HH), low byte (LL) for channels 1 to 16
|0x04|Status mask |HH LL |High byte (HH), low byte (LL) for messages F0 to FF


Upgrading firmware
Expand Down
Binary file added test/vesseltest.d64
Binary file not shown.
69 changes: 47 additions & 22 deletions vessel.ino
Original file line number Diff line number Diff line change
Expand Up @@ -105,21 +105,26 @@ volatile byte outBufWritePtr = 0;
volatile byte *outBufReadPtr = outBuf;
volatile IsrModeEnum isrMode = ISR_INPUT;
volatile uint16_t receiveChannelMask = 0;
volatile uint16_t receiveStatusMask = 0;
volatile bool nmiEnabled = false;

void (*cmds[])(void) = {
configCmd,
resetCmd,
versionCmd,
configFlagsCmd,
configChannelCmd,
configStatusCmd,
};
void (*cmd)(void) = NULL;
const byte cmdLens[] = {
3,
0,
0,
1,
2,
2,
};
byte const *cmdLen = cmdLens;
volatile byte *cmdByte = inCmdBuf + 1;
const byte maxCmd = sizeof(cmdLens) - 1;
volatile byte cmdLen = 0;
const byte maxCmd = 4;

class FakeSerial {
public:
Expand Down Expand Up @@ -167,6 +172,7 @@ MIDI_CREATE_CUSTOM_INSTANCE(FakeSerial, fs, MIDI, VesselSettings);
#define NMI_MIDI_SEND(x) NMI_WRAP(MIDI.x)

#define NMI_CHANNEL_SEND(x) if (channelMasked(channel)) { NMI_MIDI_SEND(x) }
#define NMI_STATUS_SEND(x, y) if (statusMasked(x)) { NMI_MIDI_SEND(y) }

inline void handleNoteOn(byte channel, byte note, byte velocity) {
NMI_CHANNEL_SEND(sendNoteOn(note, velocity, channel))
Expand Down Expand Up @@ -197,39 +203,44 @@ inline void handlePitchBend(byte channel, int bend) {
}

inline void handleTimeCodeQuarterFrame(byte data) {
NMI_MIDI_SEND(sendTimeCodeQuarterFrame(data))
NMI_STATUS_SEND(midi::TimeCodeQuarterFrame, sendTimeCodeQuarterFrame(data))
}

inline void handleSongPosition(unsigned int beats) {
NMI_MIDI_SEND(sendSongPosition(beats))
NMI_STATUS_SEND(midi::SongPosition, sendSongPosition(beats))
}

inline void handleSongSelect(byte songnumber) {
NMI_MIDI_SEND(sendSongSelect(songnumber))
NMI_STATUS_SEND(midi::SongSelect, sendSongSelect(songnumber))
}

inline void handleTuneRequest() {
NMI_MIDI_SEND(sendTuneRequest())
NMI_STATUS_SEND(midi::TuneRequest, sendTuneRequest())
}

inline void handleClock(void) {
NMI_MIDI_SEND(sendClock())
NMI_STATUS_SEND(midi::Clock, sendClock())
}

inline void handleStart(void) {
NMI_MIDI_SEND(sendStart())
NMI_STATUS_SEND(midi::Start, sendStart())
}

inline void handleContinue(void) {
NMI_MIDI_SEND(sendContinue())
NMI_STATUS_SEND(midi::Continue, sendContinue())
}

inline void handleStop(void) {
NMI_MIDI_SEND(sendStop())
NMI_STATUS_SEND(midi::Stop, sendStop())
}

inline void handleSystemReset(void) {
NMI_MIDI_SEND(sendSystemReset())
NMI_STATUS_SEND(midi::SystemReset, sendSystemReset())
}

inline bool statusMasked(byte status) {
uint16_t mask = 1 << (status & 0xf);
return mask & receiveStatusMask;
}

inline bool channelMasked(byte channel) {
Expand Down Expand Up @@ -345,11 +356,13 @@ inline void readByte() {

inline void readCmdByte() {
inCmdBuf[++inCmdBufReadPtr] = getByte();
if (*cmdByte > maxCmd) {
byte cmdNo = inCmdBuf[1];
if (cmdNo > maxCmd) {
isrMode = ISR_INPUT;
} else {
cmdLen = cmdLens + *cmdByte;
if (*cmdLen) {
cmdLen = cmdLens[cmdNo];
cmd = cmds[cmdNo];
if (cmdLen) {
isrMode = ISR_INPUT_CMD_DATA;
} else {
runCmd();
Expand All @@ -367,14 +380,14 @@ inline void versionCmd() {

inline void resetCmd() {
receiveChannelMask = 0;
receiveStatusMask = 0;
nmiEnabled = false;
MIDI.turnThruOff();
resetWritePtrs();
}

inline void configCmd() {
receiveChannelMask = (inCmdBuf[2] << 8) + inCmdBuf[3];
byte configFlags = inCmdBuf[4];
inline void configFlagsCmd() {
byte configFlags = inCmdBuf[2];
nmiEnabled = configFlags & 1;
if (configFlags & 2) {
MIDI.turnThruOn();
Expand All @@ -383,14 +396,26 @@ inline void configCmd() {
}
}

inline uint16_t getMask() {
return (inCmdBuf[2] << 8) + inCmdBuf[3];
}

inline void configChannelCmd() {
receiveChannelMask = getMask();
}

inline void configStatusCmd() {
receiveStatusMask = getMask();
}

inline void runCmd() {
isrMode = ISR_INPUT;
cmds[*cmdByte]();
(*cmd)();
}

inline void readCmdData() {
inCmdBuf[++inCmdBufReadPtr] = getByte();
if (inCmdBufReadPtr > *cmdLen) {
if (inCmdBufReadPtr > cmdLen) {
runCmd();
}
}
Expand Down

0 comments on commit 5102d38

Please sign in to comment.