#include #include #include #include #include #include #define BIT(n) (1 << (n)) #define BIT_FLIGHT_TIME BIT(0) #define BIT_ALTITUDE_100 BIT(1) #define BIT_ALTITUDE BIT(2) #define BIT_VELOCITY BIT(3) #define BIT_ACCELERATION BIT(4) #define BIT_FLIGHT_PHASE BIT(5) #define BIT_CHANNEL BIT(6) #define BIT_TEMPERATURE_10 BIT(7) #define BIT_NAME BIT(8) #define BIT_BATERY_10 BIT(9) #define BIT_APOGEE BIT(10) #define BIT_MAX_VELOCITY BIT(11) #define BIT_MAX_ACCELERATION BIT(12) #define ALL_ELEMENTS 0b1111111111111 #define TRIGGER_FLIGHT_TIME '#' #define TRIGGER_ALTITUDE_100 '{' #define TRIGGER_ALTITUDE '<' #define TRIGGER_VELOCITY '(' #define TRIGGER_ACCELERATION_10 '\\' #define TRIGGER_FLIGHT_PHASE '@' #define TRIGGER_CHANNEL '~' #define TRIGGER_TEMPERATURE_10 '!' #define TRIGGER_NAME '=' #define TRIGGER_BATERY_10 '?' #define TRIGGER_APOGEE '%' #define TRIGGER_MAX_VELOCITY '^' #define TRIGGER_MAX_ACCELERATION '[' #define TRIGGER_END_PACKET '>' #define MAX_DATA_SIZE 100 typedef struct WhiteVestsPacket{ double flight_time; double flight_phase; double altitude; double velocity; double acceleration; double temperature; double latitude; double longitude; double gpsSignal; // GPS Signal Strength double gpsstat; // GPS Status }WhiteVestsPacket; typedef struct EggtimerElement{ char type; char data[MAX_DATA_SIZE]; } EggtimerElement; /** * @brief This function is used to parse the data received from the Eggtimer * @param byte_received byte received * @param packet package to store the data * * @return true if receive new data packet, false otherwise */ bool decode_eggtimer_data(char byte_received, EggtimerElement * packet){ static size_t counter = 0; static char last_state = 0; switch (byte_received) { case TRIGGER_FLIGHT_TIME: case TRIGGER_ALTITUDE_100: case TRIGGER_ALTITUDE: case TRIGGER_VELOCITY: case TRIGGER_ACCELERATION_10: case TRIGGER_FLIGHT_PHASE: case TRIGGER_CHANNEL: case TRIGGER_TEMPERATURE_10: case TRIGGER_NAME: case TRIGGER_BATERY_10: case TRIGGER_APOGEE: case TRIGGER_MAX_VELOCITY: case TRIGGER_MAX_ACCELERATION: last_state = byte_received; packet->type = byte_received; memset(&packet->data, 0, sizeof packet->data); counter = 0; break; case TRIGGER_END_PACKET: if (last_state){ packet->type = last_state; packet->data[counter] = '\0'; last_state = 0; return true; } last_state = 0; break; default: // save data if(last_state) packet->data[counter++] = byte_received; break; } return false; } bool buildPacket(EggtimerElement *eggt_packet, WhiteVestsPacket *wv_packet){ static int16_t elements_received = 0; static WhiteVestsPacket nextPacket; // packet used when the packet is sent but it is not complete static bool sentIncomplete = false; if(sentIncomplete){ memcpy(wv_packet, &nextPacket, sizeof(WhiteVestsPacket)); sentIncomplete = false; } int16_t element_bit = NULL; double *element_pointer = NULL; double *nextElement_pointer = NULL; // convert data to double bool converted = true; char *endptr; double element = strtol((char*)&eggt_packet->data, &endptr, 10); if(endptr == (char*)&eggt_packet->data|| *endptr != NULL){ // error converted = false; element = 0; } switch (eggt_packet->type){ case TRIGGER_FLIGHT_TIME: element_bit = BIT_FLIGHT_TIME; element_pointer = &wv_packet->flight_time; nextElement_pointer = &nextPacket.flight_time; break; case TRIGGER_ALTITUDE_100: element_bit = BIT_ALTITUDE_100; element_pointer = &wv_packet->altitude; nextElement_pointer = &nextPacket.altitude; element *= 100.0; break; case TRIGGER_ALTITUDE: element_bit = BIT_ALTITUDE; element_pointer = &wv_packet->altitude; nextElement_pointer = &nextPacket.altitude; break; case TRIGGER_VELOCITY: element_bit = BIT_VELOCITY; element_pointer = &wv_packet->velocity; nextElement_pointer = &nextPacket.velocity; break; case TRIGGER_ACCELERATION_10: element_bit = BIT_ACCELERATION; element_pointer = &wv_packet->acceleration; nextElement_pointer = &nextPacket.acceleration; element /= 10; break; case TRIGGER_FLIGHT_PHASE: element_bit = BIT_FLIGHT_PHASE; element_pointer = &wv_packet->flight_phase; nextElement_pointer = &nextPacket.flight_phase; break; case TRIGGER_TEMPERATURE_10: element_bit = BIT_TEMPERATURE_10; element_pointer = &wv_packet->temperature; nextElement_pointer = &nextPacket.temperature; element /= 10; break; case TRIGGER_BATERY_10: element_bit = BIT_BATERY_10; break; case TRIGGER_APOGEE: element_bit = BIT_APOGEE; break; case TRIGGER_MAX_VELOCITY: element_bit = BIT_MAX_VELOCITY; break; case TRIGGER_MAX_ACCELERATION: element_bit = BIT_MAX_ACCELERATION; break; case TRIGGER_CHANNEL: element_bit = BIT_CHANNEL; break; case TRIGGER_NAME: element_bit = BIT_NAME; break; default: break; } // check if the data received is from current packet, if not, it will be stored in the next packet if((elements_received & element_bit) && element_pointer != NULL && nextElement_pointer != NULL && converted){ memcpy(&nextPacket, wv_packet, sizeof(WhiteVestsPacket)); *nextElement_pointer = element; // stores element in nextPacket elements_received = element_bit; sentIncomplete = true; return true; } if( element_pointer != NULL){ if(converted) *element_pointer = element; else return false; // error converting data } elements_received |= element_bit; // check if the packet is complete if(elements_received == ALL_ELEMENTS){ elements_received = 0; return true; } return false; } /** * @brief This function send the packet to the server */ void sendPacket(WhiteVestsPacket * packet){ unsigned char data_base64[255]; encode_base64((unsigned char*)packet, sizeof(WhiteVestsPacket), data_base64); char rssi_base64[] = "//8="; Serial.print("T,"); Serial.print((char *) data_base64); Serial.print(","); Serial.print((char *) rssi_base64); Serial.print("\n"); } bool test(){ char str[] ="{000>@1>#0000>~AB---->?079>!211>=KM6ZFL>" "{000>@1>#0000>~AB---->?079>!211>=KM6ZFL>" "{040>@2>#0010>~AB---->(0213>\\-001>?079>!212>=KM6ZFL>01>?079>!212>=KM6ZFL>" "{045>@2>#0014>~AB---->(0072>\\-001>?079>!212>=KM6ZFL>" "{046>@4>#0016>~AB---->(0033>\\-001>?079>!212>=KM6ZFL>" "{046>@5>#0018>~1B---->(2787>\\000>%04679>^0660>[025>?079>!210>=KM6ZFL> " "{045>@5>#0020>~1B---->(-0354>\\0=KM6ZFL>" "{043>@5>#0022>~1B---->(-0029>\\004>%04679>^0660>[025>?079>!209>=KM6ZFL>" "{043>@5>#0024>~1B---->(-0023>\\000>%04679>^0660>[025>?079>!209>=KM6ZFL>" "{042>@5>#0026>~1B---->(-0028>\\000>%04679>^0660>[025>?079>!209>=KM6ZFL>" "{042>@5>#0028>~1B---->(-0035>\\000>%04679>^0660>[025>?079>!209>=KM6ZFL>" "{041>@5>#0030>~1B---->(-0029>\\000>%04679>^0660>[025>?079>!209>=KM6ZFL>" "{040>@5>#0032>~1B---->(-0032>\\000>%04679>^0660>[025>?079>!209>=KM6ZFL>" "{040>@5>#0034>~1B---->(-0021>\\000>%04679>^0660>[025>?079>!209>=KM6ZFL>" "{039>@5>#0036>~1B---->(-0028>\\000>%04679>^0660>[025>?079>!209>=KM6ZFL>" "{038>@5>#0038>~1B---->(-0028>\\000>%04679>^0660>[025>?079>!209>=KM6ZFL>" "{038>@5>#0040>~1B---->(-0031>\\000>%04679>^0660>[025>?079>!209>=KM6ZFL>" "{037>@5>#0042>~1B---->(-0043>\\000>%04679>^0660>[025>?079>!208>=KM6ZFL>" "{037>@5>#0044>~1B---->(-0040>\\000>%04679>^0660>[025>?079>!209>=KM6ZFL>" "{036>@5>#0046>~1B---->(-0022>\\000>%04679>^0660>[025>?079>!208>=KM6ZFL>" "{035>@5>#0048>~1B---->(-0038>\\000>%04679>^0660>[025>?079>!208>=KM6ZFL>" "{034>@5>#0050>~1B---->(-0028>\\000>%04679>^0660>[025>?079>!208>=KM6ZFL>" "{034>@5>#0052>~1B---->(-0043>\\0=KM6ZFL>" "{033>@5>#0054>~1B---->(-0033>\\000>%04679>^0660>[025>?079>!208>=KM6ZFL>" "{032>@5>#0056>~1B---->(-0041>\\000>%04679>^0660>[025>?079>!208>=KM6ZFL>" "{032>@5>#0058>~1B---->(-0026>\\000>%04679>^0660>[025>?079>!207>=KM6ZFL>" "{031>@5>#0060>~1B---->(-0035>\\000>%04679>^0660>[025>?079>!208>=KM6ZFL>" "{030>@5>#0062>~1B---->(-0037>\\000>%04679>^0660>[025>?079>!207>=KM6ZFL>" "{029>@5>#0064>~1B---->(-0032>\\000>%04679>^0660>[025>?079>!207>=KM6ZFL>" "{029>@5>#0066>~1B---->(-0035>\\000>%04679>^0660>[025>?079>!207>=KM6ZFL>" "{028>@5>#0068>~1B---->(-0044>\\000>%04679>^0660>[025>?079>!207>=KM6ZFL>" "{027>@5>#0070>~1B---->(-0045>\\000>%04679>^0660>[025>?079>!207>=KM6ZFL>" "{026>@5>#0072>~1B---->(-0035>\\000>%04679>^0660>[025>?079>!206>=KM6ZFL>" "{025>@5>#0074>~1B---->(-0045>\\000>%04679>^0660>[025>?079>!206>=KM6ZFL>" "{025>@5>#0076>~1B---->(-0043>\\000>%04679>^0660>[025>?079>!206>=KM6ZFL>" "{024>@5>#0078>~1B---->(-0046>\\000>%04679>^0660>[025>?079>!206>=KM6ZFL>" "{023>@5>#0080>~1B---->(-0046>\\000>%04679>^0660>[025>?079>!206>=KM6ZFL>" "{022>@5>#0082>~1B---->(-0037>\\000>%04679>^0660>[025>?079>!206>=KM6ZFL>" "{021>@5>#0084>~1B---->(-0039>\\000>%04679>^0660>[025>?079>!205>=KM6ZFL>" "{020>@5>#0086>~1B---->(-0043>\\000>%04679>^0660>[025>?079>!205>=KM6ZFL>" "{020>@5>#0088>~1B---->(-0046>\\000>%04679>^0660>[025>?079>!205>=KM6ZFL>" "{019>@5>#0090>~1B---->(-0037>\\000>%04679>^0660>[025>?079>!205>=KM6ZFL>" "{018>@5>#0092>~1B---->(-0046>\\000>%04679>^0660>[025>?079>!205>=KM6ZFL>" "{017>@5>#0094>~1B---->(-0035>\\000>%04679>^0660>[025>?079>!205>=KM6ZFL>" "{016>@5>#0096>~1B---->(-0046>\\000>%04679>^0660>[025>?079>!205>=KM6ZFL>" "{016>@5>#0098>~1B---->(-0032>\\000>%04679>^0660>[025>?079>!204>=KM6ZFL>" "{015>@5>#0100>~1B---->(-0043>\\000>%04679>^0660>[025>?079>!204>=KM6ZFL>" "{014>@5>#0102>~1B---->(-0037>\\000>%04679>^0660>[025>?079>!204>=KM6ZFL>" "{013>@5>#0104>~1B---->(-0033>\\000>%04679>^0660>[025>?079>!204>=KM6ZFL>" "{012>@5>#0106>~1B---->(-0026>\\000>%04679>^0660>[025>?079>!204>=KM6ZFL>" "{012>@5>#0108>~1B---->(-0029>\\000>%04679>^0660>[025>?079>!204>=KM6ZFL>" "{011>@5>#0110>~1B---->(-0042>\\000>%04679>^0660>[025>?079>!203>=KM6ZFL>" "{010>@5>#0112>~1B---->(-0041>\\000>%04679>^0660>[025>?079>!203>=KM6ZFL>" "{009>@5>#0114>~1B---->(-0037>\\000>%04679>^0660>[025>?079>!203>=KM6ZFL>" "{009>@5>#0116>~1B---->(-0040>\\000>%04679>^0660>[025>?079>!203>=KM6ZFL>" "{008>@5>#0118>~1B---->(-0043>\\000>%04679>^0660>[025>?079>!202>=KM6ZFL>"; char *p = str; EggtimerElement eggt_packet; WhiteVestsPacket wv_packet; memset(&wv_packet, 0, sizeof(WhiteVestsPacket)); for (; *p; p++){ if(decode_eggtimer_data(*p, &eggt_packet) && buildPacket(&eggt_packet, &wv_packet)){ sendPacket(&wv_packet); delay(2000); } } return true; } void setup() { Serial.begin(9600); Serial.flush(); while (!Serial); Serial.println(); test(); } void loop() { }