Created
March 23, 2019 18:12
-
-
Save pingud98/6bb3755a10e8fae77b0f3ad6966f6f77 to your computer and use it in GitHub Desktop.
Current beta code for the OpenAuto
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Open Auto code | |
//Arezzo release July 2018 | |
//Released under the GPL V3. | |
//note that the number of live reservations in the system is stored in eeprom location 2046 (i.e. the last slot) | |
//ConfigCarFun | |
//Config string function - pass the master RFID and door mode via function. | |
//Car types | |
//1 = one button, wire to relay 1; pulse open, pulse close | |
//2 = standard two button config; relay#1= open | |
// standard, relay#2 = close | |
//3 = two button with double push, push twice open, push twice close - i.e. open all doors, dead-lock close. | |
//status 1/5/18: | |
//homebox function needs writing | |
// This #include statement was automatically added by the Particle IDE. | |
#include <ParticleSoftSerial.h> | |
#include <Particle-GPS.h> | |
#include "Particle.h" | |
#define RECEIVER SoftSer | |
#define PROTOCOL SERIAL_8N1 | |
const int MAX_RESERVATIONS = 1000; //blocks of 15 minute lookahead for reservations. | |
const int MAX_RESERVATION_LENGTH = 24; //blocks of 15 minutes allowed for a single reservation - 6 hours. | |
retained int RESERVATION_POINTER = 0; //the current position of the timer relative to the reservations | |
retained long REFERENCE_TIME; //the reference time, in 15 minute blocks stored in RAM (updated every second, stays stored while powered) - NOT initialised on reboot. | |
long RESERVATION_BLOCK_TIME; //the start time for the current reservation block | |
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 | |
long int Epoch; //calendar day | |
int Duration; //the number of 15 minute slots. Max reservation is 360 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]; | |
}; | |
int ReservationSize = 4; //number of bytes per reservation | |
//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; | |
void clearEEPROM(); // forward declaration | |
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("StDy=")); | |
} | |
int Epoch (void) { | |
return (argument.substring(argument.indexOf("Epoch=")+6, argument.indexOf("Dur="))).toInt(); | |
} | |
int 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; | |
} | |
void setup() | |
{ | |
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("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); // but SoftSerial can ;-) | |
//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, RESERVATION_BLOCK_TIME); | |
//run the 'justify' reservation eeprom routine | |
if (REFERENCE_TIME < (time.now()/(15*60))) { | |
//the system stopped for more than 15 minutes | |
//we must move the reservation pointer forward to compensate | |
debug("Clock_stopped for 15+m",1); | |
long Ref_Delta = 0; | |
Ref_Delta = (time.now()/(15*60)) - REFERENCE_TIME //how many blocks of 15 minutes did we miss? | |
if (Ref_Delta <= MAX_RESERVATIONS) { | |
//make sure we didn't miss more than 250 hours (total reservation storage) | |
RESERVATION_POINTER = RESERVATION_POINTER + Ref_Delta; | |
debug("ResvnPtr_Adjusted",1); | |
} | |
} | |
} | |
void onSerialData() | |
{ | |
_gps.onSerialData(); | |
} | |
void loop() | |
{ | |
//every second we check which reservation slot we're in and advance the reservation pointer as necessary | |
if (REFERENCE_TIME < (time.now()/(15*60))){ | |
//if true we're now in a new block of reservation time, so update reference time and advance the Reservation Pointer | |
REFERENCE_TIME = (time.now()/(15*60)) //reference time updated | |
if (RESERVATION_POINTER < MAX_RESERVATIONS) { | |
//the pointer isn't at the end of the block yet, increment | |
RESERVATION_POINTER++; | |
} | |
else { | |
//the pointer is at the end of the block (MAX_RESERVATIONS) therefore loop back to 0. | |
RESERVATION_POINTER=0; | |
} | |
} | |
//gps stuff | |
Rmc rmc = Rmc(_gps); | |
//leave this for now; pull out useful data later | |
//if (rmc.parse()) | |
//{ | |
/*Serial.println("3) Recommended Minimum Navigation Information ($GPRMC)"); | |
Serial.println("======================================================"); | |
Serial.print("UTC Time: "); Serial.println(rmc.utcTime); | |
Serial.print("Latitude: "); Serial.println(rmc.latitude); | |
Serial.print("North/SouthIndicator: "); Serial.println(rmc.northSouthIndicator); | |
Serial.print("Longitude: "); Serial.println(rmc.longitude); | |
Serial.print("East/WestIndicator: "); Serial.println(rmc.eastWestIndicator); | |
Serial.print("Speed Over Ground: "); Serial.println(rmc.speedOverGround); | |
Serial.print("Course Over Ground: "); Serial.println(rmc.courseOverGround); | |
Serial.print("Date: "); Serial.println(rmc.date); | |
Serial.print("Magnetic Variation: "); Serial.print(rmc.magneticVariation); Serial.print(" "); Serial.println(rmc.magneticVariationDirection); | |
Serial.print("Mode: "); Serial.println(rmc.mode); | |
Serial.println(""); | |
*/ | |
//} | |
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(cardpublish); | |
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; | |
} | |
//Store a reservation | |
int ReserveString(String mssgArgs){ | |
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("Epoch = "); | |
Serial.println(command.Epoch()); | |
Serial.println("Duration = "); | |
Serial.println(command.DurationInt()); | |
long int ReservationTime = Time.now(); //store current epoch time in | |
ReservationTime = command.Epoch() - ReservationTime; //how many seconds in to the future | |
int ReservedBlocks; //variable for the number of 15m intervals in the future | |
int ReservationDuration; | |
ReservedBlocks = ReservationTime / (60*15); //divide by 15 minute blocks | |
if (FutureBlocks <= MAX_RESERVATION_LENGTH) //check that we're not exceeding the reservation | |
{ | |
ReservationDuration = (command.DurationInt() / (60*15)); | |
debug("Reservation length",1); | |
//debug(ReservationDuration,1); | |
//i was here, adding the structure to reserve the EEPROM blocks with the code in a loop. | |
debug("Reservation ok",1); | |
return 1; | |
} | |
else | |
{ | |
debug("Reservation too far in the future",1); | |
return -1; | |
} | |
} | |
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: | |
digitalWrite(CloseRelay,HIGH); | |
delay(400); | |
digitalWrite(CloseRelay,LOW); | |
} | |
} | |
void clearEEPROM() { | |
for(int addr = 0; addr < 2047; addr++) { | |
EEPROM.write(addr, 0); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment