Skip to content

Instantly share code, notes, and snippets.

@drewandre
Created January 26, 2018 01:16
Show Gist options
  • Save drewandre/2fdfa85d64ccf78a32dcca94cac93342 to your computer and use it in GitHub Desktop.
Save drewandre/2fdfa85d64ccf78a32dcca94cac93342 to your computer and use it in GitHub Desktop.
// Main code for Master Node RF Reading and GPRS Transmitting //
// Written by Kuan-Sheng Chen and Karim Abdallah. July 26 2017. Save the Date.
//
// v 1.0. Includes RF Reading, data parsing, and trasmitting to AWS database with POST.
// Ain't she a beauty.
// Libraries and inspiration courtesy of Adafruit and various partners.
#include <SPI.h>
#include <RH_RF95.h>
#include <SoftwareSerial.h>
#include "Adafruit_FONA.h"
// port number for the adafruit fona feather board to connect to IoT parts.
#define FONA_RX 9
#define FONA_TX 8
#define FONA_RST 4
#define FONA_RI 7
#define RFM95_RST 11 // "A"
#define RFM95_CS 10 // "B"
#define RFM95_INT 2 // "D"
char replybuffer[255]; // Reply Buffer for FONA
#define RF95_FREQ 915.0
RH_RF95 rf95(RFM95_CS, RFM95_INT);
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout = 0);
uint8_t type;
// !!!!!!!!!!!!!!!!!!!!!Change this two constansts for IP address of EC2 server and master Id of the master node
#define MASTER_ID "1" //Change back to "1 once persmission is granted to m1_sA table"
//#define SERVER_IP "http://71.232.12.24"
//#define SERVER_IP "http://172.16.11.188"
//#define SERVER_IP "http://52.90.102.195"
#define SERVER_IP "http://palmos.localtunnel.me/api/v1/data_store"
char master_Id[2], url[40];
#define LED 13
void setup()
{
int counter = 0;
pinMode(LED, OUTPUT);
pinMode(RFM95_RST, OUTPUT);
digitalWrite(RFM95_RST, HIGH);
while (!Serial);
Serial.begin(115200);
delay(100);
Serial.println("Master Node Test!");
// Initializing FONA, referred from Library
fonaSerial->begin(4800);
if (! fona.begin(*fonaSerial)) {
Serial.println(F("Couldn't find FONA"));
while (1);
}
type = fona.type();
Serial.println(F("FONA is OK"));
Serial.print(F("Found "));
switch (type) {
case FONA800L:
Serial.println(F("FONA 800L")); break;
case FONA800H:
Serial.println(F("FONA 800H")); break;
case FONA808_V1:
Serial.println(F("FONA 808 (v1)")); break;
case FONA808_V2:
Serial.println(F("FONA 808 (v2)")); break;
case FONA3G_A:
Serial.println(F("FONA 3G (American)")); break;
case FONA3G_E:
Serial.println(F("FONA 3G (European)")); break;
default:
Serial.println(F("???")); break;
}
// Initializing LoRa module
// manual reset
digitalWrite(RFM95_RST, LOW);
delay(10);
digitalWrite(RFM95_RST, HIGH);
delay(10);
while (1)
{
uint8_t n = fona.getNetworkStatus();
Serial.print(F("Network status "));
Serial.print(n);
Serial.print(F(": "));
if (n == 0) Serial.println(F("Not registered"));
if (n == 1) {
Serial.println(F("Registered (home)"));
break;
}
if (n == 2) Serial.println(F("Not registered (searching)"));
if (n == 3) Serial.println(F("Denied"));
if (n == 4) Serial.println(F("Unknown"));
if (n == 5) Serial.println(F("Registered roaming"));
if (counter == 5) {
Serial.println("Failure to connect to network. Reboot or contact your system administrator.");
break;
}
counter ++;
delay(1000);
}
counter = 0;
//wait for 10 seconds for GSM to setup
Serial.println("plz wait for 10 seconds here for GSM to set up!!");
for (int i = 9 ; i >= 0 ; i--) {
Serial.println(i);
delay(1000);
}
while(!fona.enableGPRS(true)) {
Serial.println(F("Enabling GPRS..."));
delay(1000);
} Serial.println(F("GPRS: enabled!"));
uint16_t statuscode;
int16_t length;
// send a handshake to the http server
char data[11] = "Hand Shake";
data[10] = '\0';
flushSerial();
Serial.println("Do a handshake to filter the first Error http transmition");
if (!fona.HTTP_POST_start(SERVER_IP, F("text/plain"), (uint8_t *) data, strlen(data), &statuscode, (uint16_t *)&length)) {
Serial.println("Success!");
}
delay(3000);
Serial.println("Hand Shake with server done");
// handshake done
// radio frequency setup, referred from Library
while (!rf95.init()) {
Serial.println("LoRa radio init failed");
while (1);
}
Serial.println("LoRa radio init OK!");
// Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
if (!rf95.setFrequency(RF95_FREQ)) {
Serial.println("setFrequency failed");
while (1);
}
Serial.print("Set Freq to: "); Serial.println(RF95_FREQ);
rf95.setTxPower(23, false);
}
int global_counter = 0;
void loop()
{
//If haven't received any packet from child node for a too long time, reset RF.
//global counter is used as a tick, which will increase by one, and reset to 0 when master node receives packet
if (global_counter > 180) {
Serial.println("Receiver seems to be disconnected, refresh starts");
pinMode(LED, OUTPUT);
pinMode(RFM95_RST, OUTPUT);
digitalWrite(RFM95_RST, HIGH);
while (!Serial);
Serial.begin(9600);
delay(100);
Serial.println("Feather LoRa RX Test!");
// manual reset
digitalWrite(RFM95_RST, LOW);
delay(10);
digitalWrite(RFM95_RST, HIGH);
delay(10);
while (!rf95.init()) {
Serial.println("LoRa radio init failed");
while (1);
}
Serial.println("LoRa radio init OK!");
if (!rf95.setFrequency(RF95_FREQ)) {
Serial.println("setFrequency failed");
while (1);
}
Serial.print("Set Freq to: "); Serial.println(RF95_FREQ);
rf95.setTxPower(23, false);
Serial.println("refresh done");
global_counter = 0;
return;
}
// Reset RF end
if (rf95.available())
{
//received successfully, reset global_counter
global_counter = 0;
// Should be a message for us now
uint8_t buff[RH_RF95_MAX_MESSAGE_LEN];
uint8_t len = sizeof(buff);
if (rf95.recv(buff, &len))
{
digitalWrite(LED, HIGH);
char *buf = (char*)buff;
Serial.println(buf);
//////////////////////////////////////////////////////////////////////gps code area
if (buf[strlen(buf) - 2] != 'S') {
char sensor_Id[2]; //read sensor Id of the received packet
memset(sensor_Id, 0, 2);
memcpy(sensor_Id, &buf[strlen(buf) - 1], 1);
strcat(sensor_Id, '\0');
//use a integer table to store the index of each comma in the received string
int index_table[10];
int index = 0, count = 0;
for (int i = 0 ; i < strlen(buf) ; i++) {
if (buf[i] == ',') {
index_table[index] = i;
index += 1;
}
}
//table finished, now we can get the gps data by reading the substring
//ex incoming string from sensor 18/20/32,17/8/15,67.5N,34.6E,........
//index for each comma : 0 8 15 21 26......
//to get the latitude data, we can copy the substring with characters in between index 15 to index 21 to a new string
//we will use this concept to copy all the data we need in the following code
char cur_time_converted[11];
memset(cur_time_converted, 0, 9);
char cur_time[index_table[0] + 2];
memcpy( cur_time, &buf[0], index_table[0] );
//memcpy is used to copy the current time to a new string cur_time, so that we can process it.
//cur_time above is used to store the temporary time string, which format is illegal
//cur_time_converted is used to store the processed, legal time string
//time processing starts, delete slash and merge hour, minute, and second, and add a "0" before every single digit stuff
//ex: string "16/20/8" which indicates the time 16:20:08 will be converted to 162008
cur_time[sizeof(cur_time) / sizeof(char) - 2] = '/';
cur_time[sizeof(cur_time) / sizeof(char) - 1] = '\0';
index = 0;
for (int i = 0 ; i < sizeof(cur_time) / sizeof(char) ; i++) {
if (cur_time[i] != '/') {
index++;
}
else {
if (index == 1) {
char str1[2] = {cur_time[i - 1], '\0'};
char str2[3] = "0";
strcat(str2, str1);
str2[2] = '\0';
strcat(cur_time_converted, str2);
} else {
char str2[3];
memcpy( str2, &cur_time[i - 2], 2 );
str2[2] = '\0';
strcat(cur_time_converted, str2);
}
index = 0;
}
}
cur_time_converted[8] = '\0';
Serial.print("The current time is: "); Serial.println(cur_time_converted);
//time processing done
//date processing starts, use the same way as above, adding slash and 0 to legalize the received string, plus "20" before year
//ex: 17/2/30 which indicates the date 2017/02/30 will be converted to 20170230
char cur_date[index_table[1] - index_table[0]], cur_date_converted[11];
char year[5];
cur_date[sizeof(cur_date) / sizeof(char) - 1] = '\0';
memset( cur_date, 0 , sizeof(cur_date) / sizeof(char) - 1);
memcpy( cur_date, &buf[index_table[0] + 1], index_table[1] - index_table[0] - 3);
memset( cur_date_converted, 0, 11);
memset( year, 0, 5);
memcpy( year, "20", 2);
char var[2];
memcpy(var, &buf[index_table[1] - 2], 2);
strcat( year, var);
year[4] = '\0';
memcpy(cur_date_converted, year, 5);
index = 0;
for (int i = 0 ; i < sizeof(cur_date) / sizeof(char) ; i++) {
if (cur_date[i] != '/') {
index++;
}
else {
if (index == 1) {
char str1[2] = {cur_date[i - 1], '\0'};
char str2[3] = "0";
strcat(str2, str1);
str2[2] = '\0';
strcat(cur_date_converted, str2);
} else {
char str2[3];
memcpy( str2, &cur_date[i - 2], 2 );
str2[2] = '\0';
strcat(cur_date_converted, str2);
}
index = 0;
}
}
cur_date_converted[10] = '\0';
Serial.print("The date is: "); Serial.println(cur_date_converted);
//date processing done
//location processing
char latitude[index_table[2] - index_table[1] - 1], latitude_converted[index_table[2] - index_table[1]];
memcpy(latitude, &buf[index_table[1] + 1], index_table[2] - index_table[1] - 2);
//copy latitude
//convert the latitude substring
// ex: 23.5N will become 23.5, and 23.5S will become -23.5
latitude[sizeof(latitude) / sizeof(char) - 1] = '\0';
memset(latitude_converted, 0 , sizeof(latitude_converted) / sizeof(char));
if (buf[index_table[2] - 1] == 'S') {
memcpy( latitude_converted, "-", 1);
}
strcat(latitude_converted, latitude);
latitude_converted[sizeof(latitude_converted) / sizeof(char)] = '\0';
//Same concept on longitude processing
//ex : 67.5W will become -67.5
char longitude[index_table[3] - index_table[2] - 1], longitude_converted[index_table[3] - index_table[2]];
memcpy(longitude, &buf[index_table[2] + 1], index_table[3] - index_table[2] - 2);
longitude[sizeof(longitude) / sizeof(char) - 1] = '\0';
memset(longitude_converted, 0 , sizeof(longitude_converted) / sizeof(char));
if (buf[index_table[3] - 1] == 'W') {
memcpy( longitude_converted, "-", 1);
}
strcat(longitude_converted, longitude);
longitude_converted[sizeof(longitude_converted) / sizeof(char)] = '\0';
Serial.print("The location is: "); Serial.print(latitude_converted);
Serial.print(", "); Serial.println(longitude_converted);
//processing height
// same concept as above
char height[10];
memset(height, 0, 10);
memcpy(height, &buf[index_table[3] + 1], index_table[4] - index_table[3] - 1);
height[sizeof(height) / sizeof(char) - 1] = '\0';
Serial.print("The height is: "); Serial.println(height);
Serial.print("The master Id is: "); Serial.println(master_Id);
uint16_t statuscode = 0;
int16_t length;
char data[80];
flushSerial();
char *space = " ";
//Now we've got all the gps data we need, and we can start sending these data to http server.
//The concept here is very easy, create a new string which will store all the datastamp, adding a space in each datastamp
//so that the python http server can split it easily, and store these data to Palmos database
memset(data, 0, 80);
memcpy(data, cur_date_converted, sizeof(cur_date_converted) / sizeof(char));
strcat(data, cur_time_converted);
strcat(data, space);
strcat(data, latitude_converted);
strcat(data, space);
strcat(data, longitude_converted);
strcat(data, space);
strcat(data, height);
strcat(data, space);
strcat(data, MASTER_ID);
strcat(data, space);
strcat(data, sensor_Id);
strcat(data, space);
strcat(data, "#");
strcat(data, '\0');
Serial.println(data);
int counter = 0;
//Network transmission protocol
//The concept is making a Integer counter "counter", if the master node doesn't recieve acknowledgement from http server
//, resend it and add counter by 1. So if the counter number reaches 5, it means there are 5 packets lost consecutively in
//this transmission, inferring that master node's gsm device could have been out of work. In such case, we reset the gsm.
//On the other hand, if the status code is 200, meaning that the transmission goes very well, then we don't need to reset
//gsm, we just have to let the counter become 1 and the network transmission is finished.
while (statuscode != 200 && counter < 5) {
if (!fona.HTTP_POST_start(SERVER_IP, F("text/plain"), (uint8_t *) data, strlen(data), &statuscode, (uint16_t *)&length)) {
}
Serial.print("Status code = ");
Serial.println(statuscode);
if (statuscode != 200) counter += 1;
delay(3000);
}
//Reset function when gsm out of work, which means it lost five packet continuoulsy.
if (counter == 5) {
boolean st = false;
Serial.println("GSM transmission seems to be out of work, reset begins");
delay(3000);
if (!fona.enableGPRS(false)) {
st = true;
Serial.println(F("Failed to turn off"));
}
if (st) {
delay(3000);
if (!fona.enableGPRS(false)) {
Serial.println(F("Failed to turn off"));
}
} Serial.println("turn gsm off");
st = false;
delay(3000);
if (!fona.enableGPRS(true)) {
st = true;
Serial.println(F("Failed to turn on"));
}
if (st) {
delay(3000);
if (!fona.enableGPRS(true)) {
Serial.println(F("Failed to turn on"));
}
} Serial.println("turn gsm on");
}
// Reset GSM ends
if (counter < 5)
Serial.println("http post request for S packet done");
}
///////////////////////////////////////////////////////////////////gps code ends
///////////////////////////////////////////////////////////////////sensor code area
else {
//get Id of the sensor which sends this string
char sensor_Id[2];
memset(sensor_Id, 0, 2);
memcpy(sensor_Id, &buf[strlen(buf) - 1], 1);
sensor_Id[1] = '\0';
//Same thing, create a index table to record the index of each comma in the recieved string
int index_table[10];
int index = 0, count = 0;
for (int i = 0 ; i < strlen(buf) ; i++) {
if (buf[i] == ',') {
index_table[index] = i;
index += 1;
}
}
//Same stuff, make the current time substring in a legal format
char cur_time_converted[9];
memset(cur_time_converted, 0, 9);
char cur_time[index_table[0] + 2];
memcpy( cur_time, &buf[0], index_table[0] );
cur_time[sizeof(cur_time) / sizeof(char) - 2] = '/';
cur_time[sizeof(cur_time) / sizeof(char) - 1] = '\0';
index = 0;
for (int i = 0 ; i < sizeof(cur_time) / sizeof(char) ; i++) {
if (cur_time[i] != '/') {
index++;
}
else {
if (index == 1) {
char str1[2] = {cur_time[i - 1], '\0'};
char str2[3] = "0";
strcat(str2, str1);
str2[2] = '\0';
strcat(cur_time_converted, str2);
} else {
char str2[3];
memcpy( str2, &cur_time[i - 2], 2 );
str2[2] = '\0';
strcat(cur_time_converted, str2);
}
index = 0;
}
}
cur_time_converted[8] = '\0';
Serial.print("The current time is: "); Serial.println(cur_time_converted);
//process the date substring into a legal format, same as above.
char cur_date[index_table[1] - index_table[0]], cur_date_converted[11];
char year[5];
cur_date[sizeof(cur_date) / sizeof(char) - 1] = '\0';
memset( cur_date, 0 , sizeof(cur_date) / sizeof(char) - 1);
memcpy( cur_date, &buf[index_table[0] + 1], index_table[1] - index_table[0] - 3);
memset( cur_date_converted, 0, 11);
memset( year, 0, 5);
memcpy( year, "20", 2);
char var[2];
memcpy(var, &buf[index_table[1] - 2], 2);
strcat( year, var);
year[4] = '\0';
memcpy(cur_date_converted, year, 5);
index = 0;
for (int i = 0 ; i < sizeof(cur_date) / sizeof(char) ; i++) {
if (cur_date[i] != '/') {
index++;
}
else {
if (index == 1) {
char str1[2] = {cur_date[i - 1], '\0'};
char str2[3] = "0";
strcat(str2, str1);
str2[2] = '\0';
strcat(cur_date_converted, str2);
} else {
char str2[3];
memcpy( str2, &cur_date[i - 2], 2 );
str2[2] = '\0';
strcat(cur_date_converted, str2);
}
index = 0;
}
}
cur_date_converted[10] = '\0';
Serial.print("The date is: "); Serial.println(cur_date_converted);
/* UNCOMMENT WHEN TEMPERATURE AND HUMIDITY SENSORS ARE RE-ATTACHED
//processing temperautre
char temperature[8];
memset(temperature, 0, 8);
memcpy(temperature, &buf[index_table[1]+1], index_table[2]-index_table[1]-1);
temperature[sizeof(temperature)/sizeof(char)-1]='\0';
Serial.print("The temperature is: ");
Serial.print(temperature);
Serial.println(" Celcius degree");
//parsing humidity
char humidity[8];
memset(humidity, 0, 8);
memcpy(humidity, &buf[index_table[2]+1], index_table[3]-index_table[2]-1);
humidity[sizeof(humidity)/sizeof(char)-1]='\0';
Serial.print("The Humidity is : ");
Serial.print(humidity);
Serial.println("%"); */
//Distance
char dist[10];
memset(dist, 0, 10);
memcpy(dist, &buf[index_table[4] + 1], index_table[5] - index_table[4] - 1);
dist[9] = '\0';
//parsing axis x, y, z
char axis_x[10];
memset(axis_x, 0, 10);
memcpy(axis_x, &buf[index_table[1] + 1], index_table[2] - index_table[1] - 1);
axis_x[9] = '\0';
char axis_y[10];
memset(axis_y, 0, 10);
memcpy(axis_y, &buf[index_table[2] + 1], index_table[3] - index_table[2] - 1);
axis_y[9] = '\0';
char axis_z[10];
memset(axis_z, 0, 10);
memcpy(axis_z, &buf[index_table[3] + 1], index_table[4] - index_table[3] - 1);
axis_z[sizeof(axis_z) / sizeof(char) - 1] = '\0';
Serial.print("the axis of the tilt is x: "); Serial.print(axis_x);
Serial.print(" y: "); Serial.print(axis_y);
Serial.print(" z: "); Serial.println(axis_z);
Serial.print( "Distance: "); Serial.println(dist);
uint16_t statuscode = 0;
int16_t length;
char data[80];
flushSerial();
char *space = " ";
//Now we've got all the sensor data we need, and we can start sending these data to http server.
//The concept is the same as above.
memset(data, 0, 80);
memcpy(data, cur_date_converted, sizeof(cur_date_converted) / sizeof(char));
strcat(data, cur_time_converted);
//strcat(data,space);
//strcat(data,temperature);
// strcat(data,space);
//strcat(data,humidity);
strcat(data, space);
strcat(data, axis_x);
strcat(data, space);
strcat(data, axis_y);
strcat(data, space);
strcat(data, axis_z);
strcat(data, space);
strcat(data, dist);
strcat(sensor_Id, '\0');
strcat(data, space);
strcat(data, MASTER_ID);
strcat(data, space);
strcat(data, sensor_Id); //Add the Id in the end of the string so that server can differentiate the source of data.
strcat(data, '\0');
Serial.print("This is message sent from master node with ID ");
Serial.println(MASTER_ID);
Serial.print("Data for child ID ");
Serial.print(sensor_Id);
Serial.print(" is :");
Serial.println(data);
int counter = 0;
Serial.print("The master Id is: "); Serial.println(master_Id);
//Data transmission protection, the concept is same as above.
while (statuscode != 200 && counter < 5) {
if (!fona.HTTP_POST_start(SERVER_IP, F("text/plain"), (uint8_t *) data, strlen(data), &statuscode, (uint16_t *)&length)) {
}
Serial.print("Status code = ");
Serial.println(statuscode);
if (statuscode != 200) counter += 1;
delay(3000);
}
//Reset function when gsm out of work, which means it lost five packet continuoulsy.
if (counter == 5) {
boolean st = false;
Serial.println("GSM transmission seems to be out of work, reset begins");
delay(3000);
if (!fona.enableGPRS(false)) {
st = true;
Serial.println(F("Failed to turn off"));
}
if (st) {
delay(3000);
if (!fona.enableGPRS(false)) {
Serial.println(F("Failed to turn off"));
}
} Serial.println("turn gsm off");
st = false;
delay(3000);
if (!fona.enableGPRS(true)) {
st = true;
Serial.println(F("Failed to turn on"));
}
if (st) {
delay(3000);
if (!fona.enableGPRS(true)) {
Serial.println(F("Failed to turn on"));
}
} Serial.println("turn gsm on");
}
// Reset GSM ends
if (counter < 5)
Serial.println("http post request for S packet done");
}
//Rf transmission done, referred from Library.
Serial.println("Whole RF transmission is done");
uint8_t resp[] = "And hello back to you";
rf95.send(resp, sizeof(resp));
//rf95.waitPacketSent();
delay(1000);
digitalWrite(LED, LOW);
}
////////////////////////////////////////////////////////////////////////sensor code ends
else
{
Serial.println("Receive failed");
}
}
else {
// increase counter by 1 since no message came in in the past one second
global_counter++;
delay(1000);
}
}
void flushSerial() {
while (Serial.available())
Serial.read();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment