Skip to content

Instantly share code, notes, and snippets.

@pingud98
Last active April 14, 2018 20:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save pingud98/1d87fae92681dbe68ff0f5aac2d681cd to your computer and use it in GitHub Desktop.
Save pingud98/1d87fae92681dbe68ff0f5aac2d681cd to your computer and use it in GitHub Desktop.
latest code for Open Auto particle board
// This #include statement was automatically added by the Particle IDE.
#include <Particle-GPS.h>
#include <ParticleSoftSerial.h>
#include "Particle.h"
//note that the number of live reservations in the system is stored in eeprom location 2046 (i.e. the last slot)
//This is licensed under GPL V3.
//status:
//master rfid is encoded.
//gps position feedback up and running
//Battery Voltage added.
//working on adding reservations
//homebox function needs writing
//Reservation command works -> prints out data locally from parser;
//Reservation data is now stored in the EEPROM (36 bytes per reservation, starting from byte 0)
//the number of reservations needs to be limited; to 50 - to allow some space for other persistent variables (?)
//This limiting must be added to the code; if reservations > 50; return -1.
//Recalling reservation data mechanism to be done most easily via publish process
//then work on the indexing + 'live' reservation and reservation deletion.
//Somehow reservations need to be archived in a sequential order. Bubble sort?
#define RECEIVER SoftSer
#define PROTOCOL SERIAL_8N1
const uint32_t baud = 9600;
//init GPS device on Serial1
Gps _gps = Gps(&Serial1);
//Create a 1ms timer to feed in the GPS data
Timer _timer = Timer(1, onSerialData);
//Pin assignments for the RFID reader
#define PSS_RX D3 // RX must be interrupt enabled (on Photon/Electron D0/A5 are not)
#define PSS_TX C5 //this pin isn't something we use, I couldn't find a null pin
ParticleSoftSerial SoftSer(PSS_RX, PSS_TX);
struct Reservation {
char UserID[9];
int StartDay;
int StartMonth;
int StartYear;
int StartHour;
int StartMinute;
int Duration;
};
//variable for RFID card reading process
char CARDcurrent[4];
//Pin asignments
int OpenRelay = D4;
int CloseRelay = D5;
int StatusLED = D7;
//boolean to track the door status; actually we'll only use it as a toggle.
bool DoorsOpenBool = false;
void clearEEPROM(); // forward declaration
int EEPROMctr; //eeprom index
//Note that the 0th value of the EEPROM is used to store the number of reservations
//Values 1+ store reservations in blocks of 36 bytes.
int ReservationSize = 36; //number of bytes per reservation
//some strings that we'll use for system variables
String ReservationsTable;
String ValidGPSPosition;
int BatteryVoltageRead;
double BatteryVoltage;
//define a master RFID card that can always open/close the door regardless of reservation status (i.e. for pool manager)
String MasterRFIDCard = "983553fe";
class ReservationCmd {
String argument;
public:
void extractValues(String);
String UserIDStr (void) {
return argument.substring(argument.indexOf("UserID=")+7, argument.indexOf("StDy="));
}
int StartDayInt (void) {
return (argument.substring(argument.indexOf("StDy=")+5, argument.indexOf("StMon="))).toInt();
}
int StartMonInt (void) {
return (argument.substring(argument.indexOf("StMon=")+6, argument.indexOf("StYr="))).toInt();
}
int StartYearInt (void) {
return (argument.substring(argument.indexOf("StYr=")+5, argument.indexOf("StHr="))).toInt();
}
int StartHourInt (void) {
return (argument.substring(argument.indexOf("StHr=")+5, argument.indexOf("StMin="))).toInt();
}
int StartMinuteInt (void) {
return (argument.substring(argument.indexOf("StMin=")+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;
}
void debug(String message, int value) {
char msg [50];
sprintf(msg, message.c_str(), value);
Particle.publish("DEBUG", msg);
}
void DoorOpenFn()
{
digitalWrite(OpenRelay,HIGH);
delay(400);
digitalWrite(OpenRelay,LOW);
DoorsOpenBool = true;
}
void DoorCloseFn()
{
digitalWrite(CloseRelay,HIGH);
delay(400);
digitalWrite(CloseRelay,LOW);
DoorsOpenBool = false;
}
void StatusLEDFn()
{
digitalWrite(StatusLED,HIGH);
delay(1000);
digitalWrite(StatusLED,LOW);
}
Reservation CreateReservation(String CUserID, int CStartDay, int CStartMonth, int CStartYear, int CStartHour, int CStartMinute, int CDuration)
{
//make a buffer for the reservation
Reservation CreateResvn;
//transfer the data from the function - there's probably a better way to do the string transfer
CreateResvn.UserID[0] = CUserID[0];
CreateResvn.UserID[1] = CUserID[1];
CreateResvn.UserID[2] = CUserID[2];
CreateResvn.UserID[3] = CUserID[3];
CreateResvn.UserID[4] = CUserID[4];
CreateResvn.UserID[5] = CUserID[5];
CreateResvn.UserID[6] = CUserID[6];
CreateResvn.UserID[7] = CUserID[7];
CreateResvn.StartDay = CStartDay;
CreateResvn.StartMonth = CStartMonth;
CreateResvn.StartYear = CStartYear;
CreateResvn.StartHour = CStartHour;
CreateResvn.StartMinute = CStartMinute;
CreateResvn.Duration = CDuration;
//send the created variable back
return CreateResvn;
}
int AddReservation(Reservation ReservationToAdd)
{
//work out the next free spot and put it in that reservation
EEPROM.put((EEPROMctr*ReservationSize), ReservationToAdd);
//update the counter
EEPROMctr++;
//re-write the counter back to eeprom for synchronisation, which we store at the end of the memory space.
EEPROM.put(2046,EEPROMctr);
//return the reservation number
return EEPROMctr;
}
void clearEEPROM() {
for(int addr = 0; addr < 2047; addr++) {
EEPROM.write(addr, 0);
}
}
void setup()
{
//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("PubPosn", SendPosition); deprecated
Particle.function("MkResvn", ReserveString);
Particle.function("CanResvn", CancelString);
Particle.function("HomeBox", HomeCoords);
Particle.function("PubResvn", ShowReservations);
Particle.function("WipeResvn", WipeReservations);
//define variables
Particle.variable("CarResvn", ReservationsTable);
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();
//initialise the EEPROM counter with the number of reservations that were in memory before poweroff.
EEPROM.get(2046, EEPROMctr);
}
void onSerialData()
{
_gps.onSerialData();
}
void loop()
{
Serial.print("Data[0] = "); Serial.println(_gps.data[0]);
Serial.print("Data[1] = "); Serial.println(_gps.data[1]);
Serial.print("Data[2] = "); Serial.println(_gps.data[2]);
Serial.print("Data[3] = "); Serial.println(_gps.data[3]);
Serial.print("Data[4] = "); Serial.println(_gps.data[4]);
Serial.print("Data[5] = "); Serial.println(_gps.data[5]);
Serial.print("Data[6] = "); Serial.println(_gps.data[6]);
Rmc rmc = Rmc(_gps);
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;
Serial.println(ValidGPSPosition);
BatteryVoltageRead = analogRead(A1);
BatteryVoltage = (((BatteryVoltageRead * 3.3)/4096)/.26);
int counter = 0;
unsigned long cardread = 0;
String cardpublish;
while (RECEIVER.available())
{
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]);
Serial.println("card raw");
Serial.println(cardread, HEX);
cardpublish = String(cardread, HEX);
Serial.println("card string");
Serial.println(cardpublish);
bool success;
success = Particle.publish("RFIDident", String(cardread, HEX), 0, PUBLIC);
if (!success) {
Serial.println("failedtopublish"); // get here if event publish did not work
}
if (String(cardread, HEX)==MasterRFIDCard) {
Serial.println("match");
StatusLEDFn();
if (DoorsOpenBool) {
DoorCloseFn();
Serial.println("closing");
}
else
{
DoorOpenFn();
Serial.println("Opening");
}
}
}
RECEIVER.flush();
if (Particle.connected()) {
Serial.println("Connected!");
}
delay(1000);
}
int OpenRelayCmd(String command) {
/* Particle.functions always take a string as an argument and return an integer.
Since we can pass a string, it means that we can give the program commands on how the function should be used.
In this case, telling the function "on" will turn the LED on and telling it "off" will turn the LED off.
Then, the function returns a value to us to let us know what happened.
In this case, it will return 1 for the LEDs turning on, 0 for the LEDs turning off,
and -1 if we received a totally bogus command that didn't do anything to the LEDs.
*/
if (command=="on") {
DoorOpenFn();
return 1;
}
else {
return -1;
}
}
int CloseRelayCmd(String command) {
/* Particle.functions always take a string as an argument and return an integer.
Since we can pass a string, it means that we can give the program commands on how the function should be used.
In this case, telling the function "on" will turn the LED on and telling it "off" will turn the LED off.
Then, the function returns a value to us to let us know what happened.
In this case, it will return 1 for the LEDs turning on, 0 for the LEDs turning off,
and -1 if we received a totally bogus command that didn't do anything to the LEDs.
*/
if (command=="on") {
DoorCloseFn();
return 1;
}
else {
return -1;
}
}
int StatusLEDFlash(String command) {
/* Particle.functions always take a string as an argument and return an integer.
Since we can pass a string, it means that we can give the program commands on how the function should be used.
In this case, telling the function "on" will turn the LED on and telling it "off" will turn the LED off.
Then, the function returns a value to us to let us know what happened.
In this case, it will return 1 for the LEDs turning on, 0 for the LEDs turning off,
and -1 if we received a totally bogus command that didn't do anything to the LEDs.
*/
if (command=="on") {
StatusLEDFn();
return 1;
}
else {
return -1;
}
}
/*
//deprecated
int SendPosition(String command){
if (command=="on") {
//flash the led
StatusLEDFn();
ValidGPSPosition = _gps.data[4];
return 1;
}
else {
return -1;
}
}
*/
int ReserveString(String mssgArgs){
Serial.println("command recieved...");
Serial.println(mssgArgs);
//oldData = false;
//lastDataTransmitTime = millis();
ReservationCmd command;
command.extractValues(mssgArgs);
Serial.println("Valid Reservation Recieved...");
Serial.print("UserID: ");
Serial.println(command.UserIDStr());
debug(command.UserIDStr(),1);
Serial.println("Start Day = ");
Serial.println(command.StartDayInt());
Serial.println("Start Month = ");
Serial.println(command.StartMonInt());
Serial.println("Start Year = ");
Serial.println(command.StartYearInt());
Serial.println("Start Hour = ");
Serial.println(command.StartHourInt());
Serial.println("Start Minute = ");
Serial.println(command.StartMinuteInt());
Serial.println("Duration = ");
Serial.println(command.DurationInt());
// updateVariables(i, command.mssgText(), command.mssgValue0(), command.mssgValue1()); // Pass decoded variables to function
// badMessage = false;
//now create a temporary reservation record
Reservation ResvToInsert;
//and populate it with the values we just parsed
ResvToInsert = CreateReservation(command.UserIDStr(), command.StartDayInt(), command.StartMonInt(), command.StartYearInt(), command.StartHourInt(), command.StartMinuteInt(), command.DurationInt());
//and now insert it into the EEPROM
//initialise a dummy variable to hold the reservation number (it'll be >1 by the time it comes back)
int ReservationNumberAdded = 0;
//use the return from AddReservation to pass the reservation number post insertion
ReservationNumberAdded = AddReservation(ResvToInsert);
//return the reservation number.
return ReservationNumberAdded;
}
int CancelString(String command){
if (command=="on") {
digitalWrite(StatusLED,HIGH);
delay(1000);
digitalWrite(StatusLED,LOW);
return 1;
}
else {
return -1;
}
}
int HomeCoords(String command){
if (command=="on") {
digitalWrite(StatusLED,HIGH);
delay(1000);
digitalWrite(StatusLED,LOW);
return 1;
}
else {
return -1;
}
}
int ShowReservations(String command){
//is the reservation in the table? (i.e. is it higher than the max resvn. number, if so fail)
if (command.toInt()<= EEPROMctr) {
//Create a buffer to store the recalled data
Reservation RetRes;
//extract it from the EEPROM
EEPROM.get(((command.toInt()-1)*ReservationSize), RetRes);
//Now format it as a string
const int STRING_BUF_SIZE = 9;
char stringBuf[STRING_BUF_SIZE];
stringBuf[sizeof(stringBuf) - 1] = 0; // make sure it's null terminated
// Initialize a String object from the buffer
String str(stringBuf);
str = String(RetRes.UserID);
//Print it out
Serial.printlnf("ReservationNum=%d, UserID=%s, Day=%d, Month=%d, Year=%d, Hour=%d, Minute=%d, Duration=%d, sizeof(RetRes)=%d", command.toInt(), str.c_str(), RetRes.StartDay, RetRes.StartMonth, RetRes.StartYear, RetRes.StartHour, RetRes.StartMinute, RetRes.Duration, sizeof(RetRes));
debug(str.c_str(),1);
return 1;
}
else {
return -1;
}
}
int WipeReservations(String command) {
if (command=="on") {
//flash the LED
StatusLEDFn();
//Wipe the EEPROM
clearEEPROM();
//Reset the onboard reservation counter to 0 (assuming EEPROM is wiped)
EEPROMctr = 0;
EEPROM.put(2046, EEPROMctr);
return 1;
}
else {
return -1;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment