Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ struct ServoData {
#define EXIOINITA 0xE8 // Flag to send analogue pin info
#define EXIOPINS 0xE9 // Flag we need to send pin counts
#define EXIOWRAN 0xEA // Flag we're receiving an analogue write (PWM)
#define EXIOSHIFTIN 0xEB
#define EXIOSHIFTOUT 0xEC
#define EXIOERR 0xEF // Flag something has errored to send to device driver

/////////////////////////////////////////////////////////////////////////////////////
Expand Down
93 changes: 86 additions & 7 deletions i2c_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,32 @@
#include "i2c_functions.h"
#include "display_functions.h"
#include "pin_io_functions.h"
#include "shiftio_functions.h"

uint8_t numAnaloguePins = 0; // Init with 0, will be overridden by config
uint8_t numDigitalPins = 0; // Init with 0, will be overridden by config
uint8_t numPWMPins = 0; // Number of PWM capable pins
bool setupComplete = false; // Flag when initial configuration/setup has been received
uint8_t outboundFlag; // Used to determine what data to send back to the CommandStation
byte commandBuffer[3]; // Command buffer to interact with device driver
byte responseBuffer[1]; // Buffer to send single response back to device driver
uint8_t numReceivedPins = 0;

static const uint8_t EXIO_SHIFT_MAX_BYTES = 16; // up to 16 bytes (128 bits) safely under I2C 32-byte limit
byte responseBuffer[1 + EXIO_SHIFT_MAX_BYTES]; // [status][payload...]
uint8_t responseLength = 0;

/*
* Function triggered when CommandStation is sending data to this device.
*/
void receiveEvent(int numBytes) {
if (numBytes == 0) {
return;
}
byte buffer[numBytes];
for (uint8_t byte = 0; byte < numBytes; byte++) {
buffer[byte] = Wire.read(); // Read all received bytes into our buffer array
if (numBytes <= 0) return;

byte buffer[32];
if (numBytes > 32) numBytes = 32;
for (uint8_t i = 0; i < numBytes; i++) {
buffer[i] = Wire.read();
}

switch(buffer[0]) {
// Initial configuration start, must be 2 bytes
case EXIOINIT:
Expand Down Expand Up @@ -151,6 +156,76 @@ void receiveEvent(int numBytes) {
responseBuffer[0] = EXIOERR;
}
break;
case EXIOSHIFTIN: {
outboundFlag = EXIOSHIFTIN;

// Payload: [cmd][clkPin][latchPin][dataPin][nBytes]
if (numBytes != 5) {
responseBuffer[0] = EXIOERR;
responseLength = 1;
break;
}

uint8_t clk = buffer[1];
uint8_t latch = buffer[2];
uint8_t data = buffer[3];
uint8_t n = buffer[4];

USB_SERIAL.print("SHIFTIN clk=");
USB_SERIAL.print(clk);
USB_SERIAL.print(" latch=");
USB_SERIAL.print(latch);
USB_SERIAL.print(" data=");
USB_SERIAL.print(data);
USB_SERIAL.print(" n=");
USB_SERIAL.println(n);

if (n == 0 || n > EXIO_SHIFT_MAX_BYTES) {
responseBuffer[0] = EXIOERR;
responseLength = 1;
break;
}

responseBuffer[0] = EXIORDY;
exioShiftInBytes(clk, latch, data, &responseBuffer[1], n);

responseLength = 1 + n;
break;
}

case EXIOSHIFTOUT: {
outboundFlag = EXIOSHIFTOUT;

// Payload: [cmd][clkPin][latchPin][dataPin][nBytes][byte0..byteN-1]
if (numBytes < 6) {
responseBuffer[0] = EXIOERR;
responseLength = 1;
break;
}

uint8_t clk = buffer[1];
uint8_t latch = buffer[2];
uint8_t data = buffer[3];
uint8_t n = buffer[4];

if (n == 0 || n > EXIO_SHIFT_MAX_BYTES) {
responseBuffer[0] = EXIOERR;
responseLength = 1;
break;
}

if (numBytes != (5 + n)) {
responseBuffer[0] = EXIOERR;
responseLength = 1;
break;
}

exioShiftOutBytes(clk, latch, data, &buffer[5], n);

responseBuffer[0] = EXIORDY;
responseLength = 1;
break;
}
default:
break;
}
Expand Down Expand Up @@ -197,6 +272,10 @@ void requestEvent() {
case EXIOWRD:
Wire.write(responseBuffer, 1);
break;
case EXIOSHIFTIN:
case EXIOSHIFTOUT:
Wire.write(responseBuffer, responseLength);
break;
default:
break;
}
Expand Down
84 changes: 84 additions & 0 deletions shiftio_functions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#include <Arduino.h>
#include "shiftio_functions.h"
#include "globals.h" // pinMap[], pinNameMap[], numPins

static bool mapPins(uint8_t clk, uint8_t latch, uint8_t data,
uint8_t &pClk, uint8_t &pLatch, uint8_t &pData) {
if (clk >= numPins || latch >= numPins || data >= numPins) return false;
pClk = pinMap[clk].physicalPin;
pLatch = pinMap[latch].physicalPin;
pData = pinMap[data].physicalPin;
return true;
}

static uint8_t shiftInByte_phys(uint8_t pClk, uint8_t pLatch, uint8_t pData) {
uint8_t value = 0;

digitalWrite(pLatch, HIGH);
delayMicroseconds(1);
digitalWrite(pLatch, LOW);

for (int i = 0; i < 8; i++) {
digitalWrite(pClk, LOW);
delayMicroseconds(1);

if (digitalRead(pData)) value |= (1 << (7 - i));

digitalWrite(pClk, HIGH);
delayMicroseconds(1);
}
return value;
}

static void shiftOutByte_phys(uint8_t pClk, uint8_t pData, uint8_t value) {
for (int i = 7; i >= 0; i--) {
digitalWrite(pData, (value >> i) & 0x01);
digitalWrite(pClk, HIGH);
delayMicroseconds(1);
digitalWrite(pClk, LOW);
}
}

void exioShiftInBytes(uint8_t clk, uint8_t latch, uint8_t data, uint8_t* out, uint8_t nBytes) {
uint8_t pClk, pLatch, pData;
if (!mapPins(clk, latch, data, pClk, pLatch, pData)) {
// fail-safe: return all 0xFF so you can spot it (or all 0x00, your choice)
for (uint8_t i = 0; i < nBytes; i++) out[i] = 0xFF;
return;
}

pinMode(pClk, OUTPUT);
pinMode(pLatch, OUTPUT);
pinMode(pData, INPUT_PULLUP);
digitalWrite(pClk, LOW);
digitalWrite(pLatch, LOW);

USB_SERIAL.print(F("SHIFTIN idx "));
USB_SERIAL.print(clk); USB_SERIAL.print("/");
USB_SERIAL.print(latch); USB_SERIAL.print("/");
USB_SERIAL.print(data); USB_SERIAL.print(F(" => phys "));
USB_SERIAL.print(pClk); USB_SERIAL.print("/");
USB_SERIAL.print(pLatch); USB_SERIAL.print("/");
USB_SERIAL.println(pData);

for (uint8_t i = 0; i < nBytes; i++) {
out[i] = shiftInByte_phys(pClk, pLatch, pData);
}
}

void exioShiftOutBytes(uint8_t clk, uint8_t latch, uint8_t data, const uint8_t* in, uint8_t nBytes) {
uint8_t pClk, pLatch, pData;
if (!mapPins(clk, latch, data, pClk, pLatch, pData)) return;

pinMode(pClk, OUTPUT);
pinMode(pLatch, OUTPUT);
pinMode(pData, OUTPUT);
digitalWrite(pClk, LOW);
digitalWrite(pLatch, LOW);

for (int i = (int)nBytes - 1; i >= 0; i--) {
shiftOutByte_phys(pClk, pData, in[i]);
}

digitalWrite(pLatch, HIGH);
}
5 changes: 5 additions & 0 deletions shiftio_functions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once
#include <Arduino.h>

void exioShiftInBytes(uint8_t clk, uint8_t latch, uint8_t data, uint8_t* out, uint8_t nBytes);
void exioShiftOutBytes(uint8_t clk, uint8_t latch, uint8_t data, const uint8_t* in, uint8_t nBytes);
Loading