Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <SPI.h>
- #include <Ethernet.h>
- #include <Wire.h>
- #include <I2cDiscreteIoExpander.h>
- byte mac[] = {
- 0x90, 0xA2, 0xDA, 0x00, 0x72, 0x07 };
- int timerData[32] = {
- 0, 0, 0, 0, 0, 0, 0, 0, // port A
- 0, 0, 0, 0, 0, 0, 0, 0, // port B
- 0, 0, 0, 0, 0, 0, 0, 0, // port C
- 0, 0, 0, 0, 0, 0, 0, 0 // port D
- };
- byte serverState = 0; // holds what state main state machine is in
- int statePortsAB = 0; // 16-bit value representing ports A, B, input states
- int statePortsCD = 0; // 16-bit value representing ports C, D, input states
- int portABCmd = 0; // 16-bit value representing ports A and B output states
- int portCDCmd = 0; // 16-bit value representing ports C and D output states
- String cmd = "";
- bool changed = false; // were any outputs changed in the interrupt
- bool allZero = true; // are all the timers zero?
- byte opState = 0; // current operational state {0: idle, 1: running}
- // States are:
- // 0 = Wait for client connection
- // 1 = Wait for client command
- EthernetServer server(23);
- EthernetClient client;
- I2cDiscreteIoExpander IOPorts[5] = {0, 1, 2, 3, 4}; //Order is; 0, 1 -> PortsABCD Output: 2, 3 -> PortsABCD Input: 4 -> IPAddress Input
- void setup() {
- Wire.begin();
- IPAddress ip(192, 168, 0, getIPAddress()); // Get the IP address based on the top 8-bits of the IPAddrSetting I/O Expander
- IPAddress gateway(192, 168, 0, 1);
- IPAddress subnet(255, 255, 255, 0);
- Ethernet.begin(mac, ip, gateway, subnet);
- noInterrupts(); // disable all interrupts
- TCCR1A = 0;
- TCCR1B = 0;
- TCNT1 = 0;
- OCR1A = 125; // compare match register 16MHz/64/2kHz
- TCCR1B |= (1 << WGM12); // CTC mode
- TCCR1B |= (1 << CS11) | (1 << CS10); // 64 prescaler
- TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
- interrupts();
- server.begin();
- getStatus(); // make an initial read of the current status of the PCF8575's
- }
- ISR(TIMER1_COMPA_vect) { // the interrupt that's used once the command is executed to determine which outputs to shut off
- checkTimers();
- }
- void loop() {
- getStatus();
- switch (serverState) {
- case 0:
- checkConnection();
- break;
- case 1:
- checkCommand();
- break;
- }
- }
- void checkConnection() { // check to see if a client has connected to us
- client = server.available();
- if (client) {
- client.flush();
- serverState = 1;
- }
- }
- void checkCommand() { // read the command from the client and send to parseCommand when complete
- if (client.available() > 0) {
- char c = client.read();
- cmd += c;
- if(cmd.substring(cmd.length()-3) == ">>>") {
- cmd = cmd.substring(0, cmd.length() - 3); // cut off the >>> before we parse it
- parseCommand(cmd);
- cmd = ""; // clear the command and go back to waiting for a client
- serverState = 0;
- }
- }
- }
- void parseCommand(String cmd) { // parse the command portion of the incoming string and determine the function to call
- char has[512];
- cmd.toCharArray(has, 512);
- rc4(has);
- String cmdString = has;
- cmd = cmdString.substring(cmdString.indexOf("cmd:") + 4, (cmdString.indexOf(","))); // parse out the specific command
- String parameters = cmdString.substring(cmd.length()+7); // remove the command from the command string so we can pass parameters if needed
- if (cmd == "abort"){ // state machine to handle command parsing
- handleAbort();
- server.print(F("{response:'Aborted'}"));
- } else if (cmd == "getStatus") {
- sendStatus();
- } else if (cmd == "getUUID") {
- getUUID();
- } else if (cmd == "getOp") {
- server.print(opState);
- } else if (cmd == "getTimers") {
- sendTimers();
- } else if (cmd == "setupTimer") {
- setupTimer(parameters);
- } else if (cmd == "resetTimers") {
- if (opState == 0){
- for (int i = 0; i < 32; i++) { timerData[i] = 0; } // reset the timer data array
- }
- } else if (cmd == "staticWrite") {
- staticWrite(parameters);
- } else if (cmd == "setupOutputs") {
- setupOutputs(parameters);
- } else if (cmd == "execute") {
- executeCommand();
- server.print(F("{response:'Executing command'}"));
- } else {
- server.println(F("{response:'Invalid Command'}"));
- }
- }
- void getUUID() { // return the UUID to the client
- server.print(F("{UUID:0x"));
- for (int i = 0; i < 6; i++) {
- server.print(mac[i], HEX);
- }
- server.println(F("}"));
- }
- void rc4(char *data) { // this is the RC4 encryption algorithm
- unsigned char S[256];
- int i,j,temp;
- char key[] = "3CYUcW6mCd4ZdVuZ"; // PSK - TODO: This should be dynamic and created on connect
- for (i=0;i<256;i++) {
- S[i] = i;
- }
- j = 0;
- for (i=0;i<256;i++) {
- j = (j+S[i]+key[i%strlen(key)]) %256;
- temp = S[i];
- S[i] = S[j];
- S[j] = temp;
- }
- i = j = 0;
- for (int k=0;k<strlen(data);k++) {
- i = (i+1) %256;
- j = (j+S[i]) %256;
- temp = S[i];
- S[i] = S[j];
- S[j] = temp;
- data[k] = data[k]^S[(S[i]+S[j]) %256];
- }
- data[strlen(data)+1] = '\0';
- }
- void sendStatus() { // send the current input port status to the client
- server.print(F("{PortsAB:"));
- server.print(statePortsAB);
- server.print(F(", PortsCD:"));
- server.print(statePortsCD);
- server.println(F("}"));
- }
- void sendTimers() { // send back the timing array to the client
- server.print(F("{"));
- for (int i = 0; i < 32; i++) {
- server.print(F("timer"));
- server.print(i);
- server.print(F(":"));
- server.print(timerData[i]/2); // we divide by two because we multipled by two going in (see the updateTimers function)
- server.print(F(", "));
- }
- server.print(F("}"));
- }
- void getStatus() { // check the current input port statuses and write them to the global variables
- for (int i = 2; i < 4; i++) {
- uint8_t status = IOPorts[i].digitalRead();
- if (TWI_SUCCESS == status) {
- statePortsAB = status;
- } else {
- statePortsAB = 0;
- }
- }
- }
- int getIPAddress() { // check the IPADDR ports and use them to construct the subnet portion of the IP address
- uint8_t status = IOPorts[4].digitalRead();
- if (TWI_SUCCESS == status) {
- return status;
- } else {
- return 0;
- }
- }
- void setupOutputs(String cmdString) { // parse the command string and setup the state to send to the port expanders
- portABCmd = parseValueFromCmd(cmdString, "portAB:");
- cmdString = cmdString.substring(cmdString.indexOf("portAB:") + 12); // trim out the AB command
- portCDCmd = parseValueFromCmd(cmdString, "portCD:");
- }
- void setupTimer(String cmdString) { // parse the command string and setup the timer array used in the timer interrupt function
- if (opState == 0) { // only allow updates to the timer array if we're not currently running
- //get the output number and value, put them in the array, delete them from the string
- int outputNum = parseOutputFromCmd(cmdString);
- int outputVal = parseValueFromCmd(cmdString, "output", 9) * 2; // we multiply by two because timer is running at 2kHz and
- timerData[outputNum] = outputVal; // timers are decremented by one each tick so our values need to be double
- } else {
- server.print(F("{response:'Command not allowed in current state'}"));
- }
- }
- void executeCommand() { // send the output commands to the port expanders and begin the timer interrupt
- opState = 1;
- updateOutputs();
- }
- void staticWrite(String cmdString) { // writes a static value to a single output
- int output = parseOutputFromCmd(cmdString);
- int outputState = parseValueFromCmd(cmdString, "output", 7);
- if (output < 16) {
- bitWrite(portABCmd, output, outputState);
- } else {
- bitWrite(portCDCmd, output - 16, outputState);
- }
- }
- void updateOutputs() { // updates the register outputs based on the current global values
- uint8_t status = IOPorts[0].digitalWrite(portABCmd);
- status = IOPorts[1].digitalWrite(portCDCmd);
- }
- void handleAbort() { // stops the timers and resets all ports to false when an 'abort' command is received
- portABCmd = 0;
- portCDCmd = 0;
- updateOutputs();
- opState = 0;
- }
- void checkTimers() {
- if (opState == 1) { // this only runs if in the 'running' state
- for (int i = 0; i < 32; i++) { // iterate over all of the timing values...
- if (timerData[i] != 0){ // if the timer is not at 0 decrement it...
- allZero = false; // not all timers are at zero
- timerData[i]--; // decrement the value, but we should replace this with a timing mechanism instead of assuming our timing is perfect, especially now since the interrupt is running at 2kHz not 1.
- if (timerData[i] == 0) { // if the value is 0 now...
- if (i < 16) { // if the value is in the first 16 its ports A and B...
- bitWrite(portABCmd, i, 0); // update the appropriate bit
- } else { // if the value is in the second 16 its ports C and D...
- bitWrite(portCDCmd, i-16, 0); // update the appropriate bit
- }
- changed = true; // mark it as changed so we know we need to send a new command to the chip
- allZero = true; // this one is at zero now, so reset the boolean
- }
- }
- }
- }
- if (allZero) {
- handleAbort(); // everyone is done, stop timing
- } else if (changed) {
- updateOutputs(); // something changed, update the outputs
- } // short-circuit on abort, so we only send an update once
- }
- int parseValueFromCmd(String cmdString, String value) { // parse on integer value from in incoming command string
- return cmdString.substring(cmdString.indexOf(value) + value.length(), (cmdString.indexOf(","))).toInt();
- }
- int parseValueFromCmd(String cmdString, String value, int length) { // parse on integer value from in incoming command string
- return cmdString.substring(cmdString.indexOf(value) + length, (cmdString.indexOf(","))).toInt();
- }
- int parseOutputFromCmd(String cmdString) { // parse an integer value from a output command to determine which output is being commanded
- return cmdString.substring(cmdString.indexOf("output") + 6, (cmdString.indexOf(":"))).toInt();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement