mirror of
https://codeberg.org/portospaceteam/ground-dashboard.git
synced 2024-11-25 08:26:26 +00:00
328 lines
12 KiB
C++
328 lines
12 KiB
C++
#include <SPI.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <base64.hpp>
|
|
|
|
#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() {
|
|
}
|