From b933776dd34b09581a1c0b7c398a80439d7dd80d Mon Sep 17 00:00:00 2001 From: "ANGARA Technology (RERo)" Date: Fri, 15 Nov 2019 16:28:27 +0100 Subject: [PATCH] Initial commit migrating James' initial code. --- OpenAutoRoutines.cpp | 0 OpenAutoRoutines.h | 0 open-auto-june19.ino | 649 +++++++++++++++++++++++++++++++++++++++++++ project.properties | 2 + 4 files changed, 651 insertions(+) create mode 100644 OpenAutoRoutines.cpp create mode 100644 OpenAutoRoutines.h create mode 100644 open-auto-june19.ino create mode 100644 project.properties diff --git a/OpenAutoRoutines.cpp b/OpenAutoRoutines.cpp new file mode 100644 index 0000000..e69de29 diff --git a/OpenAutoRoutines.h b/OpenAutoRoutines.h new file mode 100644 index 0000000..e69de29 diff --git a/open-auto-june19.ino b/open-auto-june19.ino new file mode 100644 index 0000000..e53f911 --- /dev/null +++ b/open-auto-june19.ino @@ -0,0 +1,649 @@ +// This #include statement was automatically added by the Particle IDE. +#include "OpenAutoRoutines.h" + +//Open Auto code GPL V3 +// This #include statement was automatically added by the Particle IDE. +#include +#include +#include "Particle.h" +#define RECEIVER SoftSer +#define PROTOCOL SERIAL_8N1 + +const int MAX_RESERVATIONS = 145; //blocks of 10 minute lookahead for reservations to cover 24 hours. +const int ReservationResetClock=0; //0 = midnight +byte ReservationCtr =0; //initalise the reservation counter on boot +int CarType = 2; //default car type + +//set baud rate for software serial +const uint32_t baud = 9600; + +//Pin asignments +int OpenRelay = D4; +int CloseRelay = D5; +int StatusLED = D7; + +//temp variable for the RFID card last read value +String CardReadStr; + +//init GPS device on Serial1 +Gps _gps = Gps(&Serial1); + +//Create a 1ms timer to feed in the GPS data +Timer _timer = Timer(1, onSerialData); + +#define PSS_RX D3 // RX must be interrupt enabled (on Photon/Electron D0/A5 are not) +//#define PSS_TX null //this pin isn't something we use, I couldn't find a null pin so I just used the number 1. +ParticleSoftSerial SoftSer(PSS_RX, 1); //note this is a work-around so that the code works on a Particle Photon (development) and an Electron (deployment) + +//Reservation structure for incoming reservations +struct RemoteReservation { + char UserID[9]; //the RFID key to unlock the doors with a null terminator, stored as text + int Start; //block number for start of reservation + int Duration; //the number of 15 minute slots. Max reservation is 1425 minutes (can be handled upstream by odoo to block out more time in multiple grouped reservations) + +}; + +//Reservation structure for local data storage in EEPROM +struct LocalReservation { + char UserID[4]; //stored as hex + }; + +int ReservationSize = 4; //number of bytes per reservation card code + +//variable for RFID card reading process +char CARDcurrent[4]; + +//boolean to track the door status; actually we'll only use it as a toggle. +bool DoorsOpenBool = false; + +String ValidGPSPosition; +int BatteryVoltageRead; +double BatteryVoltage; + +//define a master RFID card which is loaded either from the EEPROM (on boot) or via the config command. +String MasterRFIDCard = ""; //example = "983553fe"; +char RFIDpass[8]; + +//define a variable for the currently active reservation card number and a boolean to say if it's live or not +bool ActiveReservation = false; //Active if the reservation is within it's time period. +String ReservationRFIDCard = ""; + + +//parse reservations +class ReservationCmd { + String argument; +public: + void extractValues(String); + String UserIDStr (void) { + return argument.substring(argument.indexOf("UserID=")+7, argument.indexOf("Start=")); + } + byte StartInt (void) { + return (argument.substring(argument.indexOf("Start=")+6, argument.indexOf("Dur="))).toInt(); + } + byte DurationInt (void) { + return (argument.substring(argument.indexOf("Dur=")+4, argument.indexOf("f"))).toInt(); + } +}; +void ReservationCmd::extractValues (String stringPassed){ + argument = stringPassed; +} + +//parse configuration commands +class ConfigCmd { + String argument; +public: + void extractValues(String); + String MasterRFIDStr (void) { + return argument.substring(argument.indexOf("MasterRFID=")+11, argument.indexOf("CarType=")); + } + int CarTypeInt (void) { + return (argument.substring(argument.indexOf("CarType=")+8, argument.indexOf("f"))).toInt(); + } +//eventually add some more things here? +}; +void ConfigCmd::extractValues (String stringPassed){ + argument = stringPassed; +} + + + +int AddReservation(int ReservationToAdd, char Start, char Duration, int Odometer) +{ //note we added one to the ReservationCtr variable before we started this sub + //work out the next free spot and put it in that reservation + EEPROM.put((ReservationCtr), Start); + EEPROM.put((ReservationCtr+150), Duration); + EEPROM.put((300+(ReservationCtr*ReservationSize)), ReservationToAdd); + EEPROM.put((900+(ReservationCtr*ReservationSize)),0); //write 0s to the Odo register + + //now update the reservation hash table, stored in the first 96 byte blocks from 1000. + for (int j = 0; j < Duration; j++) + { + EEPROM.put(1500+((Start+j)), ReservationCtr); + } + + //re-write the counter back to eeprom for synchronisation, which we store at the end of the memory space. + EEPROM.put(2043,ReservationCtr); + + return ReservationCtr;//return the reservation number +} + +void clearEEPROM(); + +void setup() +{ Serial.begin(9600); + debug("Running setup",1); + Serial.println("Setup running..."); + //set pin modes for hardwired devices + pinMode(OpenRelay, OUTPUT); + pinMode(CloseRelay, OUTPUT); + pinMode(StatusLED, OUTPUT); + pinMode(A1,AN_INPUT); + //set these outputs correctly + digitalWrite(OpenRelay, LOW); + digitalWrite(CloseRelay, LOW); + digitalWrite(StatusLED, LOW); + + + //define functions + Particle.function("Open", OpenRelayCmd); + Particle.function("Close", CloseRelayCmd); + Particle.function("StatusLED", StatusLEDFlash); + Particle.function("MkResvn", ReserveString); + Particle.function("PubResvn", PubResvn); + Particle.function("ConfigCar", ConfigString); + Particle.function("HomeBox", HomeCoords); + Particle.function("WipeResvn", WipeReservations); + + //define variables + Particle.variable("CarPos", ValidGPSPosition); + Particle.variable("BatLevel", BatteryVoltage); + + //set up serial debug link + //Serial.begin(); + Serial.printlnf("ready for data"); + //setup RFID reader soft serial + RECEIVER.begin(baud, PROTOCOL); + + //Init GPS + _gps.begin(9600); + _gps.sendCommand(PMTK_SET_NMEA_OUTPUT_ALLDATA); + _timer.start(); + + //retrive the master RFID card + EEPROM.get(2020, RFIDpass); + MasterRFIDCard = ""; + MasterRFIDCard = MasterRFIDCard + RFIDpass[0]; + MasterRFIDCard = MasterRFIDCard + RFIDpass[1]; + MasterRFIDCard = MasterRFIDCard + RFIDpass[2]; + MasterRFIDCard = MasterRFIDCard + RFIDpass[3]; + MasterRFIDCard = MasterRFIDCard + RFIDpass[4]; + MasterRFIDCard = MasterRFIDCard + RFIDpass[5]; + MasterRFIDCard = MasterRFIDCard + RFIDpass[6]; + MasterRFIDCard = MasterRFIDCard + RFIDpass[7]; + Serial.print("MasterRFID set:"); + Serial.print(MasterRFIDCard); + debug(MasterRFIDCard,1); + //set the car type from eeprom + EEPROM.get(2038, CarType); + //debug(CarType,1); + + //recall the reservation pointer on power up/reset + EEPROM.get(2010, ReservationCtr); //how many reservations are there + + + } + + +void onSerialData() +{ + _gps.onSerialData(); +} + + +void loop() +{ + + +//gps stuff + Rmc rmc = Rmc(_gps); + ValidGPSPosition = rmc.latitude + ";" + rmc.northSouthIndicator + ";" + rmc.longitude + ";" + rmc.eastWestIndicator + ";" + rmc.utcTime; + BatteryVoltageRead = analogRead(A1); + BatteryVoltage = (((BatteryVoltageRead * 3.3)/4096)/.26); + +int counter = 0; +unsigned long cardread = 0; + +//read the input from the card reader and open/close the doors if valid +while (RECEIVER.available()) + { //Particle.process(); + //delay(500); + for (int cardident = 0; cardident < 5; cardident++) { + counter = (RECEIVER.read()); + if (cardident > 0) Serial.print(int(counter), HEX); + CARDcurrent[cardident-1] = counter; + //Serial.print(" "); + } + //Serial.println(""); + cardread=int(CARDcurrent[0]); + cardread=cardread << 8; + cardread=cardread+ int(CARDcurrent[1]); + cardread=cardread << 8; + cardread=cardread+ int(CARDcurrent[2]); + cardread=cardread << 8; + cardread=cardread+ int(CARDcurrent[3]); + CardReadStr = String(cardread, HEX); + Serial.println("card string"); + Serial.println(cardread); + bool success; + + if (String(cardread, HEX)==MasterRFIDCard) { + debug("MasterRFIDused",1); + //Serial.println("ReservationRFIDused"); + StatusLEDFn(); + if (DoorsOpenBool) { + DoorCloseFn(); + Serial.println("closing"); + } + else + { + DoorOpenFn(); + Serial.println("Opening"); + } + } + + if ((String(cardread, HEX)==ReservationRFIDCard)) { + debug("ReservationRFIDused",1); + Serial.println("ReservationRFIDused"); + StatusLEDFn(); + if (DoorsOpenBool) { + DoorCloseFn(); + Serial.println("closing"); + } + else + { + DoorOpenFn(); + Serial.println("Opening"); + } + } + + success = Particle.publish("RFIDident", String(cardread, HEX), 0, PUBLIC); + if (!success) { + Serial.println("failedtopublish"); // get here if event publish did not work + } + + } + RECEIVER.flush(); + + if (Particle.connected()) { + Serial.println("Connected!"); + } + + //put in a delay to prevent double reads + delay(1000); +} + + +//Allow the doors to be opened from Particle Cloud +int OpenRelayCmd(String command) { + if (command=="on") { + DoorOpenFn(); + return 1; + } + else { + return -1; + } +} + + +//Allow the doors to be closed from Particle Cloud +int CloseRelayCmd(String command) { + if (command=="on") { + DoorCloseFn(); + return 1; + } + else { + return -1; + } +} + +//Allow the status LED to be flashed from Particle Cloud +int StatusLEDFlash(String command) { + if (command=="on") { + StatusLEDFn(); + return 1; + } + else { + return -1; + } + +} + +//Configure car from Particle Cloud +int ConfigString(String ConfigmssgArgs){ + + Serial.println("Config command recieved..."); + Serial.println(ConfigmssgArgs); + ConfigCmd command; + command.extractValues(ConfigmssgArgs); + Serial.println("Valid data received..."); + Serial.print("MasterRFID: "); + Serial.println(command.MasterRFIDStr()); + debug(command.MasterRFIDStr(),1); + Serial.println("CarType = "); + Serial.println(command.CarTypeInt()); + MasterRFIDCard=command.MasterRFIDStr(); + CarType = command.CarTypeInt(); + char MasterRFIDstore[8]; + MasterRFIDstore[0] = MasterRFIDCard[0]; + MasterRFIDstore[1] = MasterRFIDCard[1]; + MasterRFIDstore[2] = MasterRFIDCard[2]; + MasterRFIDstore[3] = MasterRFIDCard[3]; + MasterRFIDstore[4] = MasterRFIDCard[4]; + MasterRFIDstore[5] = MasterRFIDCard[5]; + MasterRFIDstore[6] = MasterRFIDCard[6]; + MasterRFIDstore[7] = MasterRFIDCard[7]; + EEPROM.put(2020, MasterRFIDstore); + EEPROM.put(2038, CarType); +return 1; +} + +int PubResvn(String mssgArgs){ +byte ResToPub; +ResToPub = mssgArgs.toInt(); +char RFIDVal[8]; +byte ExportVal; +int DistanceCovered; +EEPROM.get(300+(ResToPub*4),RFIDVal); +Particle.publish("Reservation RFID", RFIDVal, PUBLIC); + + +// EEPROM.put((ReservationCtr), Start); +// EEPROM.put((ReservationCtr+150), Duration); +// EEPROM.put((300+(ReservationCtr*ReservationSize)), ReservationToAdd); +// EEPROM.put((900+ReservationCtr*ReservationSize),0); //write 0s to the Odo register + +EEPROM.get(ResToPub,ExportVal); +sprintf(RFIDVal, "%d", ExportVal); +Particle.publish("Reservation Start", RFIDVal, PUBLIC); + +EEPROM.get(ResToPub+150,ExportVal); +sprintf(RFIDVal, "%d", ExportVal); +Particle.publish("Reservation Duration", RFIDVal, PUBLIC); + +EEPROM.get(900+(ResToPub*4),DistanceCovered); +sprintf(RFIDVal, "%d", DistanceCovered); +Particle.publish("Reservation ODO", RFIDVal, PUBLIC); +return ResToPub; + +} + +//Store a reservation +int ReserveString(String mssgArgs){ + StatusLEDFn(); +int StartSlot; +int DurationSlot; +String ResCardId; //text string for rfid card +int RFIDRes; //hex numeric rfid card string +String StartString; +String DurationString; + + Serial.println("command received..."); + Serial.println(mssgArgs); + ReservationCmd command; + command.extractValues(mssgArgs); + Serial.println("Valid reservation received..."); + Serial.print("UserID: "); + Serial.println(command.UserIDStr()); + debug(command.UserIDStr(),1); + Serial.println("Start = "); + Serial.println(command.StartInt()); + Serial.println("Duration = "); + Serial.println(command.DurationInt()); + + //is reservation valid? + ResCardId= command.UserIDStr(); + StartSlot = command.StartInt(); + //sprintf(StartString, StartSlot); + DurationSlot = command.DurationInt(); + //sprintf(DurationString, DurationSlot); + if ((StartSlot >= 0) * (StartSlot < 145)) + { + if ((DurationSlot >= 0 ) * (DurationSlot <145)) + { + //note there's no clash detection for reservations on the device! We assume it's done upstream + debug("Reservation ok",1); + //debug("Start Index", StartString); + //debug("End String", DurationString); + ReservationCtr++; + //command.UserIDStr(); + + RFIDRes=ConvertToHex(ResCardId[0])>>28; + RFIDRes=RFIDRes+ConvertToHex(ResCardId[1])>>24; + RFIDRes=RFIDRes+ConvertToHex(ResCardId[2])>>20; + RFIDRes=RFIDRes+ConvertToHex(ResCardId[3])>>16; + RFIDRes=RFIDRes+ConvertToHex(ResCardId[4])>>12; + RFIDRes=RFIDRes+ConvertToHex(ResCardId[5])>>8; + RFIDRes=RFIDRes+ConvertToHex(ResCardId[6])>>4; + RFIDRes=RFIDRes+ConvertToHex(ResCardId[7]); + + + AddReservation(RFIDRes, char(StartSlot), char(DurationSlot), 0); + debug("Reservation stored",1); + + //ReservationCtr++; //increment the number of reservations. + + + + } + } +return ReservationCtr; + StatusLEDFn(); +} + +int HomeCoords(String command){ + if (command=="on") { + digitalWrite(StatusLED,HIGH); + delay(1000); + digitalWrite(StatusLED,LOW); + return 1; + } + else { + return -1; + } +} + +int WipeReservations(String command) { + //wipes all reservations, retains MasterRFID and CarType variables + char TempMasterRFID[8]; + int TempCarType; + //status complete + if (command=="on") { + //flash the LED + StatusLEDFn(); + //get the fixed variables + EEPROM.get(2020, TempMasterRFID); + EEPROM.get(2038, TempCarType); + debug("EEPROM about to be wiped",1); + debug(TempMasterRFID,1); + //Wipe the EEPROM + clearEEPROM(); + //Reset the onboard reservation counter to 0 (assuming EEPROM is wiped) + EEPROM.put(2020, TempMasterRFID); + EEPROM.put(2038, TempCarType); + debug("EEPROM Wipe complete",1); + debug(TempMasterRFID,1); + return 1; + } + else { + return -1; + } +} + + +//print messages to the console +void debug(String message, int value) +{ + char msg [50]; + sprintf(msg, message.c_str(), value); + Particle.publish("DEBUG", msg); +} + +void DoorOpenFn() //open the doors, set the door status to open +{ + switch (CarType) + { + case 1: + digitalWrite(OpenRelay,HIGH); + delay(400); + digitalWrite(OpenRelay,LOW); + break; + case 2: + digitalWrite(OpenRelay,HIGH); + delay(400); + digitalWrite(OpenRelay,LOW); + case 3: + digitalWrite(OpenRelay,HIGH); + delay(400); + digitalWrite(OpenRelay,LOW); + delay(200); + digitalWrite(OpenRelay,HIGH); + delay(400); + digitalWrite(OpenRelay,LOW); + break; + default: + digitalWrite(OpenRelay,HIGH); + delay(400); + digitalWrite(OpenRelay,LOW); + } + DoorsOpenBool = true; + debug("Opened Doors",1); + //return true; +} + +void DoorCloseFn() //close the doors, set the door open state to false +{ + switch (CarType) + { + case 1: + digitalWrite(OpenRelay,HIGH); + delay(400); + digitalWrite(OpenRelay,LOW); + break; + case 2: + digitalWrite(CloseRelay,HIGH); + delay(400); + digitalWrite(CloseRelay,LOW); + case 3: + digitalWrite(CloseRelay,HIGH); + delay(400); + digitalWrite(CloseRelay,LOW); + delay(200); + digitalWrite(CloseRelay,HIGH); + delay(400); + digitalWrite(CloseRelay,LOW); + break; + default: + digitalWrite(CloseRelay,HIGH); + delay(400); + digitalWrite(CloseRelay,LOW); + } + DoorsOpenBool = false; + debug("Closed Doors",1); + +} + +void StatusLEDFn() //flash the status led once. +{ + digitalWrite(StatusLED,HIGH); + delay(1000); + digitalWrite(StatusLED,LOW); +} + + + + +char ConvertToHex(char inputcharacter) +{ + char outputchar; + switch (int(inputcharacter)) + { + case 48: //0 + outputchar = char(0); + break; + case 49: //1 + outputchar = char(1); + break; + case 50: //2 + outputchar = char(2); + break; + case 51: //3 + outputchar = char(3); + break; + case 52: //4 + outputchar = char(4); + break; + case 53: //5 + outputchar = char(5); + break; + case 54: //6 + outputchar = char(6); + break; + case 55: //7 + outputchar = char(7); + break; + case 56: //8 + outputchar = char(8); + break; + case 57: //9 + outputchar = char(9); + break; + case 65: //A + outputchar = char(10); + break; + case 66: //B + outputchar = char(11); + break; + case 67: //C + outputchar = char(12); + break; + case 68: //D + outputchar = char(13); + break; + case 69: //E + outputchar = char(14); + break; + case 70: //F + outputchar = char(15); + break; + case 71: //a + outputchar = char(10); + break; + case 72: //b + outputchar = char(11); + break; + case 73: //c + outputchar = char(12); + break; + case 74: //d + outputchar = char(13); + break; + case 75: //e + outputchar = char(14); + break; + case 76: //f + outputchar = char(15); + break; + //default + + } +} + +void clearEEPROM() { + for(int addr = 0; addr < 2047; addr++) { + EEPROM.write(addr, 0); + } +} + + + + diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..f0cff38 --- /dev/null +++ b/project.properties @@ -0,0 +1,2 @@ +dependencies.Particle-GPS=1.0.4 +dependencies.ParticleSoftSerial=0.0.6 \ No newline at end of file