diff --git a/animus-3/source/animus/..arduino.samd.arduino_zero_native.bin b/animus-3/source/animus/..arduino.samd.arduino_zero_native.bin deleted file mode 100755 index aa9feed..0000000 Binary files a/animus-3/source/animus/..arduino.samd.arduino_zero_native.bin and /dev/null differ diff --git a/animus-3/source/animus/..arduino.samd.arduino_zero_native.elf b/animus-3/source/animus/..arduino.samd.arduino_zero_native.elf deleted file mode 100755 index 55dea7b..0000000 Binary files a/animus-3/source/animus/..arduino.samd.arduino_zero_native.elf and /dev/null differ diff --git a/animus-3/source/animus/Global.h b/animus-3/source/animus/Global.h index e2050f2..2c47ae7 100644 --- a/animus-3/source/animus/Global.h +++ b/animus-3/source/animus/Global.h @@ -1,5 +1,7 @@ #define DEFAULT_ROW 12 #define DEFAULT_COL 12 +#define I2C_HOST_ADDRESS 7 +#define I2C_GUEST_ADDRESS 8 #ifndef ANIMUS_GLOBAL #define ANIMUS_GLOBAL diff --git a/animus-3/source/animus/ModI2CGuest.cpp b/animus-3/source/animus/ModI2CGuest.cpp index 64df909..05e712b 100644 --- a/animus-3/source/animus/ModI2CGuest.cpp +++ b/animus-3/source/animus/ModI2CGuest.cpp @@ -12,79 +12,79 @@ void CModI2CGuest::Begin(void) //TODO add method to return entire EEPROM to host if (!Global.HasUSB) // if no usb { - Wire.begin(8); - Wire.onRequest([] {ModI2CGuest.OnRequest();}); - Wire.onReceive([] (int numBytes) {ModI2CGuest.OnReceive(numBytes);}); - } -} - -void CModI2CGuest::OnRequest() -{ - if (SlaveIndex == 0) // if slave array is empty, add single byte - { - Wire.write(0); + isMaster = false; + SetMaster(true); } - Wire.write(SlaveArray, SlaveIndex); - SlaveIndex = 0; } void CModI2CGuest::OnReceive(int numBytes) { + byte errorOffset = 0; - byte type = Wire.read(); - if (type == 1) // received templay - { - byte input = Wire.read(); - Global.TempLayer = input; - } - else if (type == 2) // setEEPROM + while (Wire.available()) { + byte type = Wire.read(); - byte byteA = Wire.read(); - byte byteB = Wire.read(); - short startAddr = (byteA << 8) | byteB; - while (Wire.available()) + if (type == 1) // received templay { - PersMem.SetEEPROM(startAddr, Wire.read()); - startAddr++; + byte input = Wire.read(); + Global.TempLayer = input; } - PersMem.CommitEEPROM(); - } - else if (type == 3) // return part of the EEPROM - { - byte byteA = Wire.read(); - byte byteB = Wire.read(); - short startAddr = (byteA << 8) | byteB; - SlaveIndex = 0; - while (SlaveIndex < 32 && startAddr < MEM_EEPROM_SIZE) + else if (type == 2) // setEEPROM { - SlaveArray[SlaveIndex] = PersMem.GetEEPROM(startAddr); - SlaveIndex++; - startAddr++; + byte byteA = Wire.read(); + byte byteB = Wire.read(); + for (short i = (byteA << 8) | byteB; i < MEM_EEPROM_SIZE && Wire.available(); i++) + { + PersMem.SetEEPROM(i, Wire.read()); + } + PersMem.CommitEEPROM(); } - } - else if (type == 4) // update brightness - { - Global.LEDBrightness = Wire.read(); - } - else if (type == 5) // update keyboard delays - { - Global.KeyDownDelay = Wire.read(); - Global.KeyUpDelay = Wire.read(); - } - else if (type == 6) // resend for erreneous key - { - byte x = Wire.read(); - byte y = Wire.read(); - Global.LayerState[x][y] = Global.TempLayer; - if (SlaveIndex < 32) + else if (type == 3) // return part of the EEPROM { - SlaveArray[SlaveIndex] = PersMem.GetKeyData(x, y, Global.TempLayer); - SlaveIndex++; - SlaveArray[SlaveIndex] = PersMem.GetKeyType(x, y, Global.TempLayer); - SlaveIndex++; + byte byteA = Wire.read(); + byte byteB = Wire.read(); + SlaveIndex = 0; + for (short i = (byteA << 8) | byteB; i < MEM_EEPROM_SIZE; i++) + { + SlaveArray[SlaveIndex] = PersMem.GetEEPROM(i); + SlaveIndex++; + } + } + else if (type == 4) // update brightness + { + Global.LEDBrightness = Wire.read(); + } + else if (type == 5) // update refresh rate + { + Global.KeyDownDelay = Wire.read(); + Global.KeyUpDelay = Wire.read(); + } + else if (type == 6) // erreneous key + { + byte x = Wire.read(); + byte y = Wire.read(); + Global.LayerState[x][y] = Global.TempLayer; + + if (32 - SlaveIndex >= 3) + { + // We want all erreneous keys to appear before any keypresses that might have + // occured, in chronological order. + if (SlaveIndex > 0) + { + memcpy(SlaveArray + errorOffset + 3, SlaveArray + errorOffset, SlaveIndex - errorOffset); + } + SlaveArray[errorOffset + 0] = PersMem.GetKeyData(x, y, Global.TempLayer); + SlaveArray[errorOffset + 1] = PersMem.GetKeyType(x, y, Global.TempLayer); + SlaveArray[errorOffset + 2] = 5; + SlaveIndex += 3; + errorOffset += 3; + } } } + + SetMaster(true); + pullTimeout = 0; } void CModI2CGuest::LoadData(void) @@ -101,12 +101,25 @@ void CModI2CGuest::Loop(void) { CModTemplate::Loop(); - if (Animus.Async1MSDelay()) + if (!Global.HasUSB && isMaster) { - - if (Global.HasUSB) + if (SlaveIndex > 0) { - + Wire.beginTransmission(I2C_HOST_ADDRESS); + Wire.write(SlaveArray, SlaveIndex); + Wire.endTransmission(); + SlaveIndex = 0; + SetMaster(false); + } + else if (Animus.Async1MSDelay()) + { + pullTimeout++; + if (pullTimeout >= PULL_RATE) // Send an empty message to pull updates from the host + { + Wire.beginTransmission(I2C_HOST_ADDRESS); + Wire.endTransmission(); + SetMaster(false); + } } } } @@ -187,4 +200,23 @@ void CModI2CGuest::SerialComms(byte mode) } +void CModI2CGuest::SetMaster(bool value) +{ + if (isMaster == value) return; + + isMaster = value; + Wire.end(); + + if (value) + { + Wire.begin(); + Wire.onReceive([] (int numBytes) {ModI2CGuest.OnReceive(numBytes);}); + } + else + { + Wire.begin(I2C_GUEST_ADDRESS); + } +} + + CModI2CGuest ModI2CGuest; diff --git a/animus-3/source/animus/ModI2CGuest.h b/animus-3/source/animus/ModI2CGuest.h index 1d8e493..8a951ba 100644 --- a/animus-3/source/animus/ModI2CGuest.h +++ b/animus-3/source/animus/ModI2CGuest.h @@ -4,11 +4,15 @@ #include "Animus.h" #include "Wire.h" +#define PULL_RATE 50 + class CModI2CGuest : public CModTemplate { private: byte SlaveArray[32]; byte SlaveIndex = 0; + bool isMaster = false; + byte pullTimeout = 0; public: CModI2CGuest(void); void Begin(void); @@ -18,11 +22,11 @@ class CModI2CGuest : public CModTemplate void PrePress(byte val, byte type); void PressKey(byte val, byte type); void ReleaseKey(byte val, byte type); - void OnRequest(); void OnReceive(int numBytes); static void RequestEvent(); static void ReceiveEvent(int numBytes); void SerialComms(byte mode); + void SetMaster(bool value); }; extern CModI2CGuest ModI2CGuest; diff --git a/animus-3/source/animus/ModI2CHost.cpp b/animus-3/source/animus/ModI2CHost.cpp index d1b5fe8..3395fc1 100644 --- a/animus-3/source/animus/ModI2CHost.cpp +++ b/animus-3/source/animus/ModI2CHost.cpp @@ -11,7 +11,8 @@ void CModI2CHost::Begin(void) if (Global.HasUSB) // i2c host only activates if this device is plugged into the PC { - Wire.begin(); + isMaster = true; + SetMaster(false); } } @@ -28,127 +29,6 @@ void CModI2CHost::LoadData(void) void CModI2CHost::Loop(void) { - CModTemplate::Loop(); - - if (Global.HasUSB) - { - // syncs templayer value with guest - if (Global.TempLayer != I2CTempLayer) - { - SetTempLayer(); - I2CTempLayer = Global.TempLayer; - } - if (Global.LEDBrightness != I2CLEDBrightness) - { - SetSubLEDBrightness(); - I2CLEDBrightness = Global.LEDBrightness; - } - if (Global.KeyDownDelay != I2CKeyDown || Global.KeyUpDelay != I2CKeyUp) - { - SetSubKeyboardDelay(); - I2CKeyUp = Global.KeyDownDelay; - I2CKeyDown = Global.KeyUpDelay; - } - // gets keystrokes from guest - Wire.requestFrom(8, 32); - bool hasInput = true; - byte keyData[8]; - byte keyType[8]; - byte keyMode[8]; - byte keyX[8]; - byte keyY[8]; - byte keyIndex = 0; - while (hasInput) - { - - if (Wire.available()) // need to put ifs in here so trailing bytes are left out - { - // gets XY coords for pressed key - byte tempByte = Wire.read(); - keyX[keyIndex] = tempByte & 0x0f; // bitwise structure is YYYYXXXX - keyY[keyIndex] = tempByte >> 4; - } - else - { - hasInput = false; - } - - if (Wire.available()) // need to put ifs in here so trailing bytes are left out - { - keyData[keyIndex] = Wire.read(); - } - else - { - hasInput = false; - } - - if (Wire.available()) // need to put ifs in here so trailing bytes are left out - { - keyType[keyIndex] = Wire.read(); - } - else - { - hasInput = false; - } - - if (Wire.available()) // need to put ifs in here so trailing bytes are left out - { - keyMode[keyIndex] = Wire.read(); - keyIndex++; - } - else - { - hasInput = false; - } - } - - for (byte i = 0; i < keyIndex; i++) - { - - if (keyMode[i] == 1) // release key - { - Animus.ReleaseKey(keyData[i], keyType[i]); - } - else if (keyMode[i] == 5) // press key - { - Animus.PrePress(keyData[i], keyType[i]); - if (Global.TempLayer != I2CTempLayer) - { - SetTempLayer(); - I2CTempLayer = Global.TempLayer; - Wire.beginTransmission(8); - Wire.write(6); - Wire.write(keyX[i]); - Wire.write(keyY[i]); - Wire.endTransmission(); - Wire.requestFrom(8, 2); - if (Wire.available()) // need to put ifs in here so trailing bytes are left out - { - keyData[i] = Wire.read(); - } - if (Wire.available()) // need to put ifs in here so trailing bytes are left out - { - keyType[i] = Wire.read(); - } - } - Animus.PressKey(keyData[i], keyType[i]); - } - } - } - - - - if (Animus.Async1MSDelay()) - { - - if (Global.HasUSB) - { - - } - } - - - } void CModI2CHost::PressCoords(byte x, byte y) @@ -198,7 +78,7 @@ void CModI2CHost::SerialComms(byte mode) // holy shit this is complicated { if (Comms.mode == 6) // write to guest eeprom starting at addr = 0 or MEM_BOARD_TYPE, ending at first short read from serial { - if (Serial.available()) //TODO I might want to work in a timeout or fail check for this + if (Serial.available()) // TODO I might want to work in a timeout or fail check for this { if (SerialLoaderByteStatus == 0) // if this is the first time mode 6 has made contact { @@ -227,9 +107,7 @@ void CModI2CHost::SerialComms(byte mode) // holy shit this is complicated } if (EEPROMPacketSize <= 0) { - SetSubEEPROM(); - EEPROMPacketIndex = 2; - SerialLoaderByteStatus = 0; + pendingEEPROMUpdate = true; Comms.mode = 0; } } @@ -238,10 +116,10 @@ void CModI2CHost::SerialComms(byte mode) // holy shit this is complicated else if (Comms.mode == 7) // request read sub EEPROM { short addr = 0; - while(addr < MEM_EEPROM_SIZE) + while (addr < MEM_EEPROM_SIZE) { - GetSubEEPROM(addr); - Wire.requestFrom(8, 32); + GetSubEEPROM(addr); // TODO + Wire.requestFrom(I2C_GUEST_ADDRESS, 32); while(Wire.available()) { Serial.println(Wire.read()); @@ -258,18 +136,14 @@ void CModI2CHost::SerialComms(byte mode) // holy shit this is complicated void CModI2CHost::SetTempLayer() { - Wire.beginTransmission(8); Wire.write(1); Wire.write(Global.TempLayer); - Wire.endTransmission(); } void CModI2CHost::SetSubEEPROM(void) { - Wire.beginTransmission(8); Wire.write(2); Wire.write(EEPROMPacket, EEPROMPacketIndex); - Wire.endTransmission(); } void CModI2CHost::GetSubEEPROM(short startAddr) @@ -285,21 +159,115 @@ void CModI2CHost::GetSubEEPROM(short startAddr) void CModI2CHost::SetSubLEDBrightness(void) { - Wire.beginTransmission(8); Wire.write(4); Wire.write(Global.LEDBrightness); - Wire.endTransmission(); } void CModI2CHost::SetSubKeyboardDelay(void) { - Wire.beginTransmission(8); Wire.write(5); Wire.write(Global.KeyDownDelay); Wire.write(Global.KeyUpDelay); +} + + + +void CModI2CHost::OnReceive(int numBytes) +{ + SetMaster (true); + Wire.beginTransmission(I2C_GUEST_ADDRESS); + + // Parse package + byte buffer[numBytes]; + Wire.readBytes(buffer, numBytes); + + byte keyData[8]; + byte keyType[8]; + byte keyMode[8]; + byte keyX[8]; + byte keyY[8]; + byte keyIndex = 0; + + for (int i = 0; i < numBytes; i+=4, keyIndex++) + { + keyX[keyIndex] = buffer[i+0] & 0x0f; // bitwise structure is YYYYXXXX + keyY[keyIndex] = buffer[i+0] >> 4; + keyData[keyIndex] = buffer[i+1]; + keyType[keyIndex] = buffer[i+2]; + keyMode[keyIndex] = buffer[i+3]; + } + + // Execute keypresses + for (byte i = 0; i < keyIndex; i++) + { + if (keyMode[i] == 1) // release key + { + Animus.ReleaseKey(keyData[i], keyType[i]); + } + else if (keyMode[i] == 5) // press key + { + if (Global.TempLayer != I2CTempLayer) // Wrong layout! + { + SetTempLayer(); + I2CTempLayer = Global.TempLayer; + Wire.write(6); + Wire.write(keyX[i]); + Wire.write(keyY[i]); + } + else + { + Animus.PrePress(keyData[i], keyType[i]); + Animus.PressKey(keyData[i], keyType[i]); + } + } + } + + // Send updates + if (Global.TempLayer != I2CTempLayer) + { + SetTempLayer(); + I2CTempLayer = Global.TempLayer; + } + if (Global.LEDBrightness != I2CLEDBrightness) + { + SetSubLEDBrightness(); + I2CLEDBrightness = Global.LEDBrightness; + } + if (Global.KeyDownDelay != I2CKeyDown || Global.KeyUpDelay != I2CKeyUp) + { + SetSubKeyboardDelay(); + I2CKeyDown = Global.KeyDownDelay; + I2CKeyUp = Global.KeyUpDelay; + } + if (pendingEEPROMUpdate) + { + SetSubEEPROM(); + EEPROMPacketIndex = 2; + SerialLoaderByteStatus = 0; + pendingEEPROMUpdate = false; + } + Wire.endTransmission(); + SetMaster(false); } +void CModI2CHost::SetMaster(bool value) +{ + if (isMaster == value) return; + + isMaster = value; + Wire.end(); + + if (value) + { + Wire.begin(); + } + else + { + Wire.begin(I2C_HOST_ADDRESS); + Wire.onReceive([] (int numBytes) {ModI2CHost.OnReceive(numBytes);}); + } +} CModI2CHost ModI2CHost; diff --git a/animus-3/source/animus/ModI2CHost.h b/animus-3/source/animus/ModI2CHost.h index ad93315..d5a59da 100644 --- a/animus-3/source/animus/ModI2CHost.h +++ b/animus-3/source/animus/ModI2CHost.h @@ -28,12 +28,16 @@ class CModI2CHost : public CModTemplate byte I2CKeyUp = 0; byte SerialLoaderByteStatus = 0; byte EEPROMPacketSize = 0; + bool isMaster = false; + bool pendingEEPROMUpdate = false; void SetTempLayer(void); void SetSubEEPROM(void); void SetSubBoardSettings(void); void SetSubLEDBrightness(void); void SetSubKeyboardDelay(void); void GetSubEEPROM(short startAddr); + void OnReceive(int numBytes); + void SetMaster(bool value); public: