diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1f21566 --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ +# RJH Generic makefile + +SRC=$(wildcard *.c) +HED=$(wildcard *.h) +OBJ=$(SRC:.c=.o) # replaces the .c from SRC with .o +EXE=gateway + +INDOPT= -bap -bl -blf -bli0 -brs -cbi0 -cdw -cs -ci4 -cli4 -i4 -ip0 -nbc -nce -lp -npcs -nut -pmt -psl -prs -ts4 + +CC=gcc +CFLAGS=-Wall -O3 #-std=c99 +LDFLAGS= -lm -lwiringPi -lwiringPiDev -lcurl -lncurses -lpthread +RM=rm + +%.o: %.c # combined w/ next line will compile recently changed .c files + $(CC) $(CFLAGS) -o $@ -c $< + +.PHONY : all # .PHONY ignores files named all +all: $(EXE) # all is dependent on $(EXE) to be complete + +$(EXE): $(OBJ) # $(EXE) is dependent on all of the files in $(OBJ) to exist + $(CC) $(OBJ) $(LDFLAGS) -o $@ + +.PHONY : clean # .PHONY ignores files named clean +clean: + -$(RM) $(OBJ) + +tidy: + indent $(INDOPT) $(SRC) $(HED) + rm *~ diff --git a/README.md b/README.md index 7f994e0..790b2e2 100644 --- a/README.md +++ b/README.md @@ -46,10 +46,8 @@ Install the LoRa gateway 2. git clone https://github.com/PiInTheSky/lora-gateway.git 3. cd lora-gateway 4. make - 5. cp gateway_sample.txt gateway.txt + 5. cp gateway-sample.txt gateway.txt -** That last step is new - to prevent overwriting existing configurations, gateway.txt is supplied as a sample file that you need to copy first ** - Configuration @@ -228,6 +226,47 @@ Many thanks to David Brooke for coding this feature and the AFC. Change History ============== +03/09/2016 - V1.8 +----------------- + + Add configuration of uplink frequency, mode and power + LoRa modes now in array so easier to add new ones + Added LoRa mode for uplink + Re-instated logging to telemetry.txt + Fixed pipe errors which happened if packets arrived during program exit + Merged in changes to JSON format + Sends data both LoRa channels in JSON + Config disables CE0 by default (most cards have CE1 only) + Fixed typos in gateway-sample.txt + Accept new SSDV types + + +25/08/2016 - V1.7 +----------------- + + Robert Harrison (RJH) has made numerous changes. + + Highlights include :- + + Changed makefile to include -Wall and fixed all warnings generated + Added pipes for Inter-Process Communication + Moved none thread safe curl funtions from threads and into main() + Added reporting of curl errors to habitat and ssdv threads + Changed color to green but requires 256 color support in your terminal + + For putty users please set your terminal as shown + +![Alt text](http://i.imgur.com/B81bvEQ.png "Putty config") + + when you are connected to your pi + + # echo $TERM # should show something with 256 in + + or + + # tpu colors # Should show 256 + + 27/06/2016 - V1.6 ----------------- diff --git a/base64.c b/base64.c index f31ac08..5383f30 100644 --- a/base64.c +++ b/base64.c @@ -2,93 +2,109 @@ #include -static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', '+', '/'}; +static char encoding_table[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' +}; + static char *decoding_table = NULL; -static int mod_table[] = {0, 2, 1}; +static int mod_table[] = { 0, 2, 1 }; -void *base64_encode(const unsigned char *data, - size_t input_length, - size_t *output_length, - char *encoded_data) +char * +base64_encode( const char *data, + size_t input_length, + size_t * output_length, char *encoded_data ) { - int i, j; - - *output_length = 4 * ((input_length + 2) / 3); + int i, j; + + *output_length = 4 * ( ( input_length + 2 ) / 3 ); // char *encoded_data = malloc(*output_length); // if (encoded_data == NULL) return NULL; - for (i = 0, j = 0; i < input_length;) - { - uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0; - uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0; - uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0; + for ( i = 0, j = 0; i < input_length; ) + { + uint32_t octet_a = i < input_length ? ( unsigned char ) data[i++] : 0; + uint32_t octet_b = i < input_length ? ( unsigned char ) data[i++] : 0; + uint32_t octet_c = i < input_length ? ( unsigned char ) data[i++] : 0; - uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; + uint32_t triple = ( octet_a << 0x10 ) + ( octet_b << 0x08 ) + octet_c; - encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F]; - encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F]; - encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F]; - encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F]; + encoded_data[j++] = encoding_table[( triple >> 3 * 6 ) & 0x3F]; + encoded_data[j++] = encoding_table[( triple >> 2 * 6 ) & 0x3F]; + encoded_data[j++] = encoding_table[( triple >> 1 * 6 ) & 0x3F]; + encoded_data[j++] = encoding_table[( triple >> 0 * 6 ) & 0x3F]; } - for (i = 0; i < mod_table[input_length % 3]; i++) + for ( i = 0; i < mod_table[input_length % 3]; i++ ) encoded_data[*output_length - 1 - i] = '='; - // return encoded_data; + return encoded_data; } -void build_decoding_table() { +void +build_decoding_table( ) +{ - int i; - - decoding_table = malloc(256); + int i; - for (i = 0; i < 64; i++) - decoding_table[(unsigned char) encoding_table[i]] = i; + decoding_table = malloc( 256 ); + + for ( i = 0; i < 64; i++ ) + decoding_table[( unsigned char ) encoding_table[i]] = i; } -unsigned char *base64_decode(const char *data, - size_t input_length, - size_t *output_length) { - int i, j; - - if (decoding_table == NULL) build_decoding_table(); +char * +base64_decode( const char *data, size_t input_length, size_t * output_length ) +{ + int i, j; - if (input_length % 4 != 0) return NULL; + if ( decoding_table == NULL ) + build_decoding_table( ); + + if ( input_length % 4 != 0 ) + return NULL; *output_length = input_length / 4 * 3; - if (data[input_length - 1] == '=') (*output_length)--; - if (data[input_length - 2] == '=') (*output_length)--; + if ( data[input_length - 1] == '=' ) + ( *output_length )--; + if ( data[input_length - 2] == '=' ) + ( *output_length )--; - unsigned char *decoded_data = malloc(*output_length); - if (decoded_data == NULL) return NULL; + char *decoded_data = malloc( *output_length ); + if ( decoded_data == NULL ) + return NULL; - for (i = 0, j = 0; i < input_length;) { + for ( i = 0, j = 0; i < input_length; ) + { - uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; - uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; - uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; - uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; + uint32_t sextet_a = + data[i] == '=' ? 0 & i++ : decoding_table[( int ) data[i++]]; + uint32_t sextet_b = + data[i] == '=' ? 0 & i++ : decoding_table[( int ) data[i++]]; + uint32_t sextet_c = + data[i] == '=' ? 0 & i++ : decoding_table[( int ) data[i++]]; + uint32_t sextet_d = + data[i] == '=' ? 0 & i++ : decoding_table[( int ) data[i++]]; - uint32_t triple = (sextet_a << 3 * 6) - + (sextet_b << 2 * 6) - + (sextet_c << 1 * 6) - + (sextet_d << 0 * 6); + uint32_t triple = ( sextet_a << 3 * 6 ) + + ( sextet_b << 2 * 6 ) + + ( sextet_c << 1 * 6 ) + ( sextet_d << 0 * 6 ); - if (j < *output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF; - if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF; - if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF; + if ( j < *output_length ) + decoded_data[j++] = ( triple >> 2 * 8 ) & 0xFF; + if ( j < *output_length ) + decoded_data[j++] = ( triple >> 1 * 8 ) & 0xFF; + if ( j < *output_length ) + decoded_data[j++] = ( triple >> 0 * 8 ) & 0xFF; } return decoded_data; @@ -96,6 +112,8 @@ unsigned char *base64_decode(const char *data, -void base64_cleanup() { - free(decoding_table); -} \ No newline at end of file +void +base64_cleanup( ) +{ + free( decoding_table ); +} diff --git a/base64.h b/base64.h index d691104..bd1bd2a 100644 --- a/base64.h +++ b/base64.h @@ -1,3 +1,8 @@ #include - -void base64_encode(const unsigned char *data, size_t input_length, size_t *output_length, char *encoded_data); \ No newline at end of file + +void build_decoding_table( ); +char *base64_encode( const char *data, size_t input_length, + size_t * output_length, char *encoded_data ); +char *base64_decode( const char *data, size_t input_length, + size_t * output_length ); +void base64_cleanup( ); diff --git a/ftp.c b/ftp.c index 1557120..07627a0 100644 --- a/ftp.c +++ b/ftp.c @@ -2,12 +2,12 @@ #include #include #include -#include // Standard input/output definitions -#include // String function definitions -#include // UNIX standard function definitions -#include // File control definitions -#include // Error number definitions -#include // POSIX terminal control definitions +#include // Standard input/output definitions +#include // String function definitions +#include // UNIX standard function definitions +#include // File control definitions +#include // Error number definitions +#include // POSIX terminal control definitions #include #include #include @@ -17,71 +17,79 @@ #include "ftp.h" #include "global.h" -void ConvertFile(char *FileName) +void +ConvertFile( char *FileName ) { - char TargetFile[100], CommandLine[200], *ptr; - - strcpy(TargetFile, FileName); - ptr = strchr(TargetFile, '.'); - if (ptr && Config.SSDVJpegFolder[0]) - { - *ptr = '\0'; - strcat(TargetFile, ".JPG"); - - // Now convert the file - // LogMessage("Converting %s to %s\n", FileName, TargetFile); + char TargetFile[100], CommandLine[200], *ptr; - sprintf(CommandLine, "ssdv -d /tmp/%s %s/%s 2> /dev/null > /dev/null", FileName, Config.SSDVJpegFolder, TargetFile); - // LogMessage("COMMAND %s\n", CommandLine); - system(CommandLine); - - if (Config.ftpServer[0] && Config.ftpUser[0] && Config.ftpPassword[0]) - { - // Upload to ftp server - sprintf(CommandLine, "curl -T %s %s -Q \"TYPE I\" --user %s:%s 2> /dev/null > /dev/null", TargetFile, Config.ftpServer, Config.ftpUser, Config.ftpPassword); - system(CommandLine); - } - } -} - - -void *FTPLoop(void *some_void_ptr) -{ - while (1) + strcpy( TargetFile, FileName ); + ptr = strchr( TargetFile, '.' ); + if ( ptr && Config.SSDVJpegFolder[0] ) { - DIR *dp; - struct dirent *ep; - struct stat st; - char *SSDVFolder; - char FileName[100], TempName[100]; - - SSDVFolder = "/tmp"; - - dp = opendir(SSDVFolder); - if (dp != NULL) - { - while (ep = readdir (dp)) - { - if (strstr(ep->d_name, ".bin") != NULL) - { - sprintf(FileName, "%s/%s", SSDVFolder, ep->d_name); - stat(FileName, &st); - // LogMessage("Age of '%s' is %ld seconds\n", FileName, time(0) - st.st_mtime); - if ((time(0) - st.st_mtime) < 20) - { - ConvertFile(ep->d_name); - } - else if ((time(0) - st.st_mtime) > 120) - { - sprintf(TempName, "%s/%s", SSDVFolder, ep->d_name); - // LogMessage("Removing %s\n", TempName); - remove(TempName); - } - } - } - } - (void) closedir (dp); - - sleep(5); - } + *ptr = '\0'; + strcat( TargetFile, ".JPG" ); + + // Now convert the file + // LogMessage("Converting %s to %s\n", FileName, TargetFile); + + sprintf( CommandLine, + "ssdv -d /tmp/%s %s/%s 2> /dev/null > /dev/null", FileName, + Config.SSDVJpegFolder, TargetFile ); + // LogMessage("COMMAND %s\n", CommandLine); + system( CommandLine ); + + if ( Config.ftpServer[0] && Config.ftpUser[0] + && Config.ftpPassword[0] ) + { + // Upload to ftp server + sprintf( CommandLine, + "curl -T %s %s -Q \"TYPE I\" --user %s:%s 2> /dev/null > /dev/null", + TargetFile, Config.ftpServer, Config.ftpUser, + Config.ftpPassword ); + system( CommandLine ); + } + } +} + + +void * +FTPLoop( void *some_void_ptr ) +{ + while ( 1 ) + { + DIR *dp; + struct dirent *ep; + struct stat st; + char *SSDVFolder; + char FileName[100], TempName[100]; + + SSDVFolder = "/tmp"; + + dp = opendir( SSDVFolder ); + if ( dp != NULL ) + { + while ( ( ep = readdir( dp ) ) ) + { + if ( strstr( ep->d_name, ".bin" ) != NULL ) + { + sprintf( FileName, "%s/%s", SSDVFolder, ep->d_name ); + stat( FileName, &st ); + // LogMessage("Age of '%s' is %ld seconds\n", FileName, time(0) - st.st_mtime); + if ( ( time( 0 ) - st.st_mtime ) < 20 ) + { + ConvertFile( ep->d_name ); + } + else if ( ( time( 0 ) - st.st_mtime ) > 120 ) + { + sprintf( TempName, "%s/%s", SSDVFolder, ep->d_name ); + // LogMessage("Removing %s\n", TempName); + remove( TempName ); + } + } + } + } + ( void ) closedir( dp ); + + sleep( 5 ); + } } diff --git a/ftp.h b/ftp.h index 5eacf46..b9cc578 100644 --- a/ftp.h +++ b/ftp.h @@ -1 +1 @@ -void *FTPLoop(void *some_void_ptr); \ No newline at end of file +void *FTPLoop( void *some_void_ptr ); diff --git a/gateway-sample.txt b/gateway-sample.txt new file mode 100644 index 0000000..0c30b8f --- /dev/null +++ b/gateway-sample.txt @@ -0,0 +1,58 @@ + +##### Your details ##### + +tracker=YOUR_CALLSIGN +Latitude=0.0 +Longitude=0.0 +Antenna=Watson W-50 + + +##### Config Options ##### + +EnableHabitat=Y +EnableSSDV=Y +JPGFolder=ssdv +LogTelemetry=Y +LogPackets=Y +CallingTimeout=60 +ServerPort=6004 +#SMSFolder=./ +EnableDev=N + +NetworkLED=22 +InternetLED=23 +ActivityLED_0=21 +ActivityLED_1=29 + +##### Config CE0 ##### + +#frequency_0=434.250 +#mode_0=1 +#AFC_0=Y +#bandwidth_0=125K +#implicit_0=0 +#coding_0=5 +#sf_0=8 +#lowopt_0=0 +#power_0=255 +#DIO0_0=31 +#DIO5_0=26 +#UplinkTime_0=2 +#UplinkCycle_0=60 + + +##### Config CE1 ##### + +frequency_1=434.500 +mode_1=1 +AFC_1=Y +#bandwidth_1=125K +#implicit_1=0 +#coding_1=5 +#sf_1=8 +#lowopt_1=0 +#power_1=255 +#DIO0_1=6 +#DIO5_1=5 +#UplinkTime_1=5 +#UplinkCycle_1=60 diff --git a/gateway.c b/gateway.c index a8a1442..e279686 100644 --- a/gateway.c +++ b/gateway.c @@ -1,3 +1,5 @@ +#include +#define __USE_XOPEN #include #include #include @@ -12,15 +14,14 @@ #include #include #include -#include #include #include #include #include #include - #include #include +#include #include "urlencode.h" #include "base64.h" @@ -30,15 +31,16 @@ #include "network.h" #include "global.h" #include "server.h" +#include "gateway.h" -#define VERSION "V1.6" +#define VERSION "V1.8.0" bool run = TRUE; // RFM98 uint8_t currentMode = 0x81; #define REG_FIFO 0x00 -#define REG_FIFO_ADDR_PTR 0x0D +#define REG_FIFO_ADDR_PTR 0x0D #define REG_FIFO_TX_BASE_AD 0x0E #define REG_FIFO_RX_BASE_AD 0x0F #define REG_RX_NB_BYTES 0x13 @@ -112,1945 +114,2336 @@ uint8_t currentMode = 0x81; // LOW NOISE AMPLIFIER #define REG_LNA 0x0C -#define LNA_MAX_GAIN 0x23 // 0010 0011 +#define LNA_MAX_GAIN 0x23 // 0010 0011 #define LNA_OFF_GAIN 0x00 -#define LNA_LOW_GAIN 0xC0 // 1100 0000 +#define LNA_LOW_GAIN 0xC0 // 1100 0000 -struct TPayload -{ - int InUse; - char Payload[32]; +struct TPayload { + int InUse; + char Payload[32]; }; +struct TLoRaMode +{ + int ImplicitOrExplicit; + int ErrorCoding; + int Bandwidth; + int SpreadingFactor; + int LowDataRateOptimize; + int BaudRate; + char *Description; +} LoRaModes[] = +{ + {EXPLICIT_MODE, ERROR_CODING_4_8, BANDWIDTH_20K8, SPREADING_11, 8, 60, "Telemetry"}, // 0: Normal mode for telemetry + {IMPLICIT_MODE, ERROR_CODING_4_5, BANDWIDTH_20K8, SPREADING_6, 0, 1400, "SSDV"}, // 1: Normal mode for SSDV + {EXPLICIT_MODE, ERROR_CODING_4_8, BANDWIDTH_62K5, SPREADING_8, 0, 2000, "Repeater"}, // 2: Normal mode for repeater network + {EXPLICIT_MODE, ERROR_CODING_4_6, BANDWIDTH_250K, SPREADING_7, 0, 8000, "Turbo"}, // 3: Normal mode for high speed images in 868MHz band + {IMPLICIT_MODE, ERROR_CODING_4_5, BANDWIDTH_250K, SPREADING_6, 0, 16828, "TurboX"}, // 4: Fastest mode within IR2030 in 868MHz band + {EXPLICIT_MODE, ERROR_CODING_4_8, BANDWIDTH_41K7, SPREADING_11, 0, 200, "Calling"}, // 5: Calling mode + {IMPLICIT_MODE, ERROR_CODING_4_5, BANDWIDTH_41K7, SPREADING_6, 0, 2800, "Uplink"} // 6: Uplink mode for 868 +}; struct TConfig Config; struct TPayload Payloads[16]; -struct TSSDVPacketArray SSDVPacketArrays[2]; -int SSDVSendArrayIndex=-1; -pthread_mutex_t ssdv_mutex=PTHREAD_MUTEX_INITIALIZER; int LEDCounts[2]; -pthread_mutex_t var=PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t var = PTHREAD_MUTEX_INITIALIZER; #pragma pack(1) -struct TBinaryPacket -{ - uint8_t PayloadIDs; - uint16_t Counter; - uint16_t BiSeconds; - float Latitude; - float Longitude; - uint16_t Altitude; +struct TBinaryPacket { + uint8_t PayloadIDs; + uint16_t Counter; + uint16_t BiSeconds; + float Latitude; + float Longitude; + uint16_t Altitude; }; -const char *Modes[6] = {"Slow", "SSDV", "Repeater", "Turbo", "TurboX", "Calling"}; +const char *Modes[6] = + { "Slow", "SSDV", "Repeater", "Turbo", "TurboX", "Calling" }; -void writeRegister(int Channel, uint8_t reg, uint8_t val) +// Create pipes for inter proces communication +// GLOBAL AS CALLED FROM INTERRRUPT +int telem_pipe_fd[2]; +int ssdv_pipe_fd[2]; + +// Create a structure to share some variables with the habitat child process +// GLOBAL AS CALLED FROM INTERRRUPT +thread_shared_vars_t htsv; + +// Create a structure to share some variables with the ssdv child process +// GLOBAL AS CALLED FROM INTERRRUPT +thread_shared_vars_t stsv; + +int habitate_telem_packets = 0; + +void +hexdump_buffer( const char *title, const char *buffer, const int len_buffer ) { - unsigned char data[2]; - - data[0] = reg | 0x80; - data[1] = val; - wiringPiSPIDataRW(Channel, data, 2); + int i, j = 0; + char message[200]; + FILE *fp; + + fp = fopen( "pkt.txt", "a" ); + + fprintf( fp, "Title = %s\n", title ); + + for ( i = 0; i < len_buffer; i++ ) + { + sprintf( &message[3 * j], "%02x ", buffer[i] ); + j++; + if ( i % 16 == 15 ) + { + j = 0; + fprintf( fp, "%s\n", message ); + message[0] = '\0'; + } + } + fprintf( fp, "%s\n", message ); + fclose( fp ); + } -uint8_t readRegister(int Channel, uint8_t reg) +void +writeRegister( int Channel, uint8_t reg, uint8_t val ) { - unsigned char data[2]; - uint8_t val; - - data[0] = reg & 0x7F; - data[1] = 0; - wiringPiSPIDataRW(Channel, data, 2); - val = data[1]; - + unsigned char data[2]; + + data[0] = reg | 0x80; + data[1] = val; + wiringPiSPIDataRW( Channel, data, 2 ); +} + +uint8_t +readRegister( int Channel, uint8_t reg ) +{ + unsigned char data[2]; + uint8_t val; + + data[0] = reg & 0x7F; + data[1] = 0; + wiringPiSPIDataRW( Channel, data, 2 ); + val = data[1]; + return val; } -void LogPacket(int Channel, int8_t SNR, int RSSI, double FreqError, int Bytes, unsigned char MessageType) +void +LogPacket( int Channel, int8_t SNR, int RSSI, double FreqError, int Bytes, + unsigned char MessageType ) { - if (Config.EnablePacketLogging) - { - FILE *fp; - - if ((fp = fopen("packets.txt", "at")) != NULL) - { - time_t now; - struct tm *tm; - - now = time(0); - tm = localtime(&now); - - fprintf(fp, "%02d:%02d:%02d - Ch %d, SNR %d, RSSI %d, FreqErr %.1lf, Bytes %d, Type %02Xh\n", tm->tm_hour, tm->tm_min, tm->tm_sec, Channel, SNR, RSSI, FreqError, Bytes, MessageType); - - fclose(fp); - } - } + if ( Config.EnablePacketLogging ) + { + FILE *fp; + + if ( ( fp = fopen( "packets.txt", "at" ) ) != NULL ) + { + time_t now; + struct tm *tm; + + now = time( 0 ); + tm = localtime( &now ); + + fprintf( fp, + "%02d:%02d:%02d - Ch %d, SNR %d, RSSI %d, FreqErr %.1lf, Bytes %d, Type %02Xh\n", + tm->tm_hour, tm->tm_min, tm->tm_sec, Channel, SNR, RSSI, + FreqError, Bytes, MessageType ); + + fclose( fp ); + } + } } -void LogTelemetryPacket(char *Telemetry) +void +LogTelemetryPacket( char *Telemetry ) { - if (Config.EnableTelemetryLogging) - { - FILE *fp; - - if ((fp = fopen("telemetry.txt", "at")) != NULL) - { - time_t now; - struct tm *tm; - - now = time(0); - tm = localtime(&now); - - fprintf(fp, "%02d:%02d:%02d - %s\n", tm->tm_hour, tm->tm_min, tm->tm_sec, Telemetry); - - fclose(fp); - } - } + // if (Config.EnableTelemetryLogging) + { + FILE *fp; + + if ( ( fp = fopen( "telemetry.txt", "at" ) ) != NULL ) + { + time_t now; + struct tm *tm; + + now = time( 0 ); + tm = localtime( &now ); + + fprintf( fp, "%02d:%02d:%02d - %s\n", tm->tm_hour, tm->tm_min, + tm->tm_sec, Telemetry ); + + fclose( fp ); + } + } } -void LogMessage(const char *format, ...) +void +LogMessage( const char *format, ... ) { - static WINDOW *Window=NULL; - char Buffer[512]; + static WINDOW *Window = NULL; + char Buffer[512]; + + pthread_mutex_lock( &var ); // lock the critical section + + if ( Window == NULL ) + { + // Window = newwin(25, 30, 0, 50); + Window = newwin( LINES - 16, COLS, 16, 0 ); + scrollok( Window, TRUE ); + } - pthread_mutex_lock(&var); // lock the critical section - - if (Window == NULL) - { - // Window = newwin(25, 30, 0, 50); - Window = newwin(9, 80, 16, 0); - scrollok(Window, TRUE); - } - va_list args; - va_start(args, format); + va_start( args, format ); - vsprintf(Buffer, format, args); + vsprintf( Buffer, format, args ); - va_end(args); + va_end( args ); - if (strlen(Buffer) > 79) - { - Buffer[77] = '.'; - Buffer[78] = '.'; - Buffer[79] = '\n'; - Buffer[80] = 0; - } - - waddstr(Window, Buffer); - - wrefresh(Window); + if ( strlen( Buffer ) > COLS - 1 ) + { + Buffer[COLS - 3] = '.'; + Buffer[COLS - 2] = '.'; + Buffer[COLS - 1] = '\n'; + Buffer[COLS] = 0; + } + + waddstr( Window, Buffer ); + + wrefresh( Window ); + + pthread_mutex_unlock( &var ); // unlock once you are done - pthread_mutex_unlock(&var); // unlock once you are done } -void ChannelPrintf(int Channel, int row, int column, const char *format, ...) +void +ChannelPrintf( int Channel, int row, int column, const char *format, ... ) { - pthread_mutex_lock(&var); // lock the critical section - - char Buffer[80]; - va_list args; - - va_start(args, format); + char Buffer[80]; + va_list args; - vsprintf(Buffer, format, args); + pthread_mutex_lock( &var ); // lock the critical section - va_end(args); + va_start( args, format ); + + vsprintf( Buffer, format, args ); + + va_end( args ); + + mvwaddstr( Config.LoRaDevices[Channel].Window, row, column, Buffer ); + + wrefresh( Config.LoRaDevices[Channel].Window ); + + pthread_mutex_unlock( &var ); // unlock once you are done - mvwaddstr(Config.LoRaDevices[Channel].Window, row, column, Buffer); - - wrefresh(Config.LoRaDevices[Channel].Window); - - pthread_mutex_unlock(&var); // unlock once you are done } -void setMode(int Channel, uint8_t newMode) +void +setMode( int Channel, uint8_t newMode ) { - if(newMode == currentMode) - return; - - switch (newMode) - { - case RF98_MODE_TX: - writeRegister(Channel, REG_LNA, LNA_OFF_GAIN); // TURN LNA OFF FOR TRANSMITT - writeRegister(Channel, REG_PA_CONFIG, Config.LoRaDevices[Channel].Power); // PA_MAX_UK - writeRegister(Channel, REG_OPMODE, newMode); - currentMode = newMode; - break; - case RF98_MODE_RX_CONTINUOUS: - writeRegister(Channel, REG_PA_CONFIG, PA_OFF_BOOST); // TURN PA OFF FOR RECIEVE?? - writeRegister(Channel, REG_LNA, LNA_MAX_GAIN); // MAX GAIN FOR RECEIVE - writeRegister(Channel, REG_OPMODE, newMode); - currentMode = newMode; - // LogMessage("Changing to Receive Continuous Mode\n"); - break; - case RF98_MODE_SLEEP: - writeRegister(Channel, REG_OPMODE, newMode); - currentMode = newMode; - // LogMessage("Changing to Sleep Mode\n"); - break; - case RF98_MODE_STANDBY: - writeRegister(Channel, REG_OPMODE, newMode); - currentMode = newMode; - // LogMessage("Changing to Standby Mode\n"); - break; - default: return; - } - - if(newMode != RF98_MODE_SLEEP) - { - while(digitalRead(Config.LoRaDevices[Channel].DIO5) == 0) - { - } - // delay(1); - } - - // LogMessage("Mode Change Done\n"); - return; + if ( newMode == currentMode ) + return; + + switch ( newMode ) + { + case RF98_MODE_TX: + writeRegister( Channel, REG_LNA, LNA_OFF_GAIN ); // TURN LNA OFF FOR TRANSMITT + writeRegister( Channel, REG_PA_CONFIG, Config.LoRaDevices[Channel].Power ); // PA_MAX_UK + writeRegister( Channel, REG_OPMODE, newMode ); + currentMode = newMode; + break; + case RF98_MODE_RX_CONTINUOUS: + writeRegister( Channel, REG_PA_CONFIG, PA_OFF_BOOST ); // TURN PA OFF FOR RECIEVE?? + writeRegister( Channel, REG_LNA, LNA_MAX_GAIN ); // MAX GAIN FOR RECEIVE + writeRegister( Channel, REG_OPMODE, newMode ); + currentMode = newMode; + // LogMessage("Changing to Receive Continuous Mode\n"); + break; + case RF98_MODE_SLEEP: + writeRegister( Channel, REG_OPMODE, newMode ); + currentMode = newMode; + // LogMessage("Changing to Sleep Mode\n"); + break; + case RF98_MODE_STANDBY: + writeRegister( Channel, REG_OPMODE, newMode ); + currentMode = newMode; + // LogMessage("Changing to Standby Mode\n"); + break; + default: + return; + } + + if ( newMode != RF98_MODE_SLEEP ) + { + while ( digitalRead( Config.LoRaDevices[Channel].DIO5 ) == 0 ) + { + } + // delay(1); + } + + // LogMessage("Mode Change Done\n"); + return; } -void setFrequency(int Channel, double Frequency) +void +setFrequency( int Channel, double Frequency ) { - unsigned long FrequencyValue; - char FrequencyString [10]; + unsigned long FrequencyValue; + char FrequencyString[10]; - // Format frequency as xxx.xxx.x Mhz - sprintf (FrequencyString,"%8.4lf ", Frequency); - FrequencyString[8] = FrequencyString[7]; - FrequencyString[7] = '.'; + // Format frequency as xxx.xxx.x Mhz + sprintf( FrequencyString, "%8.4lf ", Frequency ); + FrequencyString[8] = FrequencyString[7]; + FrequencyString[7] = '.'; - FrequencyValue = (unsigned long)(Frequency * 7110656 / 434); + FrequencyValue = ( unsigned long ) ( Frequency * 7110656 / 434 ); - writeRegister(Channel, 0x06, (FrequencyValue >> 16) & 0xFF); // Set frequency - writeRegister(Channel, 0x07, (FrequencyValue >> 8) & 0xFF); - writeRegister(Channel, 0x08, FrequencyValue & 0xFF); + writeRegister( Channel, 0x06, ( FrequencyValue >> 16 ) & 0xFF ); // Set frequency + writeRegister( Channel, 0x07, ( FrequencyValue >> 8 ) & 0xFF ); + writeRegister( Channel, 0x08, FrequencyValue & 0xFF ); - Config.LoRaDevices[Channel].activeFreq = Frequency; + Config.LoRaDevices[Channel].activeFreq = Frequency; - // LogMessage("Set Frequency to %lf\n", Frequency); - - ChannelPrintf(Channel, 1, 1, "Channel %d %s MHz ", Channel, FrequencyString); + // LogMessage("Set Frequency to %lf\n", Frequency); + + ChannelPrintf( Channel, 1, 1, "Channel %d %s MHz ", Channel, + FrequencyString ); } -void setLoRaMode(int Channel) +void +setLoRaMode( int Channel ) { - double Frequency; - unsigned long FrequencyValue; + double Frequency; - // LogMessage("Setting LoRa Mode\n"); - setMode(Channel, RF98_MODE_SLEEP); - writeRegister(Channel, REG_OPMODE,0x80); - - setMode(Channel, RF98_MODE_SLEEP); - - if (sscanf(Config.LoRaDevices[Channel].Frequency, "%lf", &Frequency)) - { - // LogMessage("Set Default Frequency\n"); - setFrequency(Channel, Frequency); - } + // LogMessage("Setting LoRa Mode\n"); + setMode( Channel, RF98_MODE_SLEEP ); + writeRegister( Channel, REG_OPMODE, 0x80 ); + + setMode( Channel, RF98_MODE_SLEEP ); + + if ( sscanf( Config.LoRaDevices[Channel].Frequency, "%lf", &Frequency ) ) + { + // LogMessage("Set Default Frequency\n"); + setFrequency( Channel, Frequency ); + } } -char *BandwidthString(int Bandwidth) +char * +BandwidthString( int Bandwidth ) { - if (Bandwidth == BANDWIDTH_7K8) return "7.8k"; - if (Bandwidth == BANDWIDTH_10K4) return "10.4k"; - if (Bandwidth == BANDWIDTH_15K6) return "15.6k"; - if (Bandwidth == BANDWIDTH_20K8) return "20.8k"; - if (Bandwidth == BANDWIDTH_31K25) return "31.25k"; - if (Bandwidth == BANDWIDTH_41K7) return "41.7k"; - if (Bandwidth == BANDWIDTH_62K5) return "62.5k"; - if (Bandwidth == BANDWIDTH_125K) return "125k"; - if (Bandwidth == BANDWIDTH_250K) return "250k"; - if (Bandwidth == BANDWIDTH_500K) return "500k"; - return "??k"; + if ( Bandwidth == BANDWIDTH_7K8 ) + return "7.8k"; + if ( Bandwidth == BANDWIDTH_10K4 ) + return "10.4k"; + if ( Bandwidth == BANDWIDTH_15K6 ) + return "15.6k"; + if ( Bandwidth == BANDWIDTH_20K8 ) + return "20.8k"; + if ( Bandwidth == BANDWIDTH_31K25 ) + return "31.25k"; + if ( Bandwidth == BANDWIDTH_41K7 ) + return "41.7k"; + if ( Bandwidth == BANDWIDTH_62K5 ) + return "62.5k"; + if ( Bandwidth == BANDWIDTH_125K ) + return "125k"; + if ( Bandwidth == BANDWIDTH_250K ) + return "250k"; + if ( Bandwidth == BANDWIDTH_500K ) + return "500k"; + return "??k"; } -void SetLoRaParameters(int Channel, int ImplicitOrExplicit, int ErrorCoding, int Bandwidth, int SpreadingFactor, int LowDataRateOptimize) +void +SetLoRaParameters( int Channel, int ImplicitOrExplicit, int ErrorCoding, + int Bandwidth, int SpreadingFactor, + int LowDataRateOptimize ) { - writeRegister(Channel, REG_MODEM_CONFIG, ImplicitOrExplicit | ErrorCoding | Bandwidth); - writeRegister(Channel, REG_MODEM_CONFIG2, SpreadingFactor | CRC_ON); - writeRegister(Channel, REG_MODEM_CONFIG3, 0x04 | LowDataRateOptimize); // 0x04: AGC sets LNA gain - writeRegister(Channel, REG_DETECT_OPT, (readRegister(Channel, REG_DETECT_OPT) & 0xF8) | ((SpreadingFactor == SPREADING_6) ? 0x05 : 0x03)); // 0x05 For SF6; 0x03 otherwise - writeRegister(Channel, REG_DETECTION_THRESHOLD, (SpreadingFactor == SPREADING_6) ? 0x0C : 0x0A); // 0x0C for SF6, 0x0A otherwise - - Config.LoRaDevices[Channel].CurrentBandwidth = Bandwidth; - - ChannelPrintf(Channel, 2, 1, "%s, %s, SF%d, EC4:%d %s", - ImplicitOrExplicit == IMPLICIT_MODE ? "Implicit" : "Explicit", - BandwidthString(Bandwidth), - SpreadingFactor >> 4, - (ErrorCoding >> 1) + 4, - LowDataRateOptimize ? "LDRO" : ""); + writeRegister( Channel, REG_MODEM_CONFIG, + ImplicitOrExplicit | ErrorCoding | Bandwidth ); + writeRegister( Channel, REG_MODEM_CONFIG2, SpreadingFactor | CRC_ON ); + writeRegister( Channel, REG_MODEM_CONFIG3, 0x04 | LowDataRateOptimize ); // 0x04: AGC sets LNA gain + writeRegister( Channel, REG_DETECT_OPT, ( readRegister( Channel, REG_DETECT_OPT ) & 0xF8 ) | ( ( SpreadingFactor == SPREADING_6 ) ? 0x05 : 0x03 ) ); // 0x05 For SF6; 0x03 otherwise + writeRegister( Channel, REG_DETECTION_THRESHOLD, ( SpreadingFactor == SPREADING_6 ) ? 0x0C : 0x0A ); // 0x0C for SF6, 0x0A otherwise + + Config.LoRaDevices[Channel].CurrentBandwidth = Bandwidth; + + ChannelPrintf( Channel, 2, 1, "%s, %s, SF%d, EC4:%d %s", + ImplicitOrExplicit == + IMPLICIT_MODE ? "Implicit" : "Explicit", + BandwidthString( Bandwidth ), SpreadingFactor >> 4, + ( ErrorCoding >> 1 ) + 4, + LowDataRateOptimize ? "LDRO" : "" ); } -void SetDefaultLoRaParameters(int Channel) +void +SetDefaultLoRaParameters( int Channel ) { - // LogMessage("Set Default Parameters\n"); - - SetLoRaParameters(Channel, - Config.LoRaDevices[Channel].ImplicitOrExplicit, - Config.LoRaDevices[Channel].ErrorCoding, - Config.LoRaDevices[Channel].Bandwidth, - Config.LoRaDevices[Channel]. SpreadingFactor, - Config.LoRaDevices[Channel].LowDataRateOptimize); + // LogMessage("Set Default Parameters\n"); + + SetLoRaParameters( Channel, + Config.LoRaDevices[Channel].ImplicitOrExplicit, + Config.LoRaDevices[Channel].ErrorCoding, + Config.LoRaDevices[Channel].Bandwidth, + Config.LoRaDevices[Channel].SpreadingFactor, + Config.LoRaDevices[Channel].LowDataRateOptimize ); } ///////////////////////////////////// // Method: Setup to receive continuously ////////////////////////////////////// -void startReceiving(int Channel) +void +startReceiving( int Channel ) { - writeRegister(Channel, REG_DIO_MAPPING_1, 0x00); // 00 00 00 00 maps DIO0 to RxDone - - writeRegister(Channel, REG_PAYLOAD_LENGTH, 255); - writeRegister(Channel, REG_RX_NB_BYTES, 255); + writeRegister( Channel, REG_DIO_MAPPING_1, 0x00 ); // 00 00 00 00 maps DIO0 to RxDone - writeRegister(Channel, REG_FIFO_RX_BASE_AD, 0); - writeRegister(Channel, REG_FIFO_ADDR_PTR, 0); - - // Setup Receive Continous Mode - setMode(Channel, RF98_MODE_RX_CONTINUOUS); + writeRegister( Channel, REG_PAYLOAD_LENGTH, 255 ); + writeRegister( Channel, REG_RX_NB_BYTES, 255 ); + + writeRegister( Channel, REG_FIFO_RX_BASE_AD, 0 ); + writeRegister( Channel, REG_FIFO_ADDR_PTR, 0 ); + + // Setup Receive Continous Mode + setMode( Channel, RF98_MODE_RX_CONTINUOUS ); } -void ReTune(int Channel, double FreqShift) +void ReTune( int Channel, double FreqShift ) { - setMode(Channel, RF98_MODE_SLEEP); - LogMessage("Retune by %lf kHz\n", FreqShift * 1000); - setFrequency(Channel, Config.LoRaDevices[Channel].activeFreq + FreqShift); - startReceiving(Channel); + setMode( Channel, RF98_MODE_SLEEP ); + LogMessage( "Retune by %lf kHz\n", FreqShift * 1000 ); + setFrequency( Channel, Config.LoRaDevices[Channel].activeFreq + FreqShift ); + startReceiving( Channel ); } -void SendLoRaData(int Channel, unsigned char *buffer, int Length) +void SendLoRaData(int Channel, char *buffer, int Length) { - unsigned char data[257]; - int i; - - LogMessage("LoRa Channel %d Sending %d bytes\n", Channel, Length); - Config.LoRaDevices[Channel].Sending = 1; - - setMode(Channel, RF98_MODE_STANDBY); - - writeRegister(Channel, REG_DIO_MAPPING_1, 0x40); // 01 00 00 00 maps DIO0 to TxDone + unsigned char data[257]; + int i; - writeRegister(Channel, REG_FIFO_TX_BASE_AD, 0x00); // Update the address ptr to the current tx base address - writeRegister(Channel, REG_FIFO_ADDR_PTR, 0x00); - - data[0] = REG_FIFO | 0x80; - for (i=0; i 0) { - data[i+1] = buffer[i]; - } - wiringPiSPIDataRW(Channel, data, Length+1); - - // Set the length. For implicit mode, since the length needs to match what the receiver expects, we have to set a value which is 255 for an SSDV packet - writeRegister(Channel, REG_PAYLOAD_LENGTH, Config.LoRaDevices[Channel].PayloadLength ? Config.LoRaDevices[Channel].PayloadLength : Length); - - // go into transmit mode - setMode(Channel, RF98_MODE_TX); -} - -void ShowPacketCounts(int Channel) -{ - if (Config.LoRaDevices[Channel].InUse) - { - int i; - - ChannelPrintf(Channel, 7, 1, "Telem Packets = %d (%us) ", Config.LoRaDevices[Channel].TelemetryCount, Config.LoRaDevices[Channel].LastTelemetryPacketAt ? (unsigned int)(time(NULL) - Config.LoRaDevices[Channel].LastTelemetryPacketAt) : 0); - ChannelPrintf(Channel, 8, 1, "Image Packets = %d (%us) ", Config.LoRaDevices[Channel].SSDVCount, Config.LoRaDevices[Channel].LastSSDVPacketAt ? (unsigned int)(time(NULL) - Config.LoRaDevices[Channel].LastSSDVPacketAt) : 0); - - ChannelPrintf(Channel, 9, 1, "Bad CRC = %d Bad Type = %d", Config.LoRaDevices[Channel].BadCRCCount, Config.LoRaDevices[Channel].UnknownCount); - - ChannelPrintf(Channel, 6, 16, "SSDV %d%c %d%c ", SSDVPacketArrays[0].Count, SSDVSendArrayIndex==0 ? '*' : ' ', - SSDVPacketArrays[1].Count, SSDVSendArrayIndex==1 ? '*' : ' '); - } -} - -void ProcessUploadMessage(int Channel, char *Message) -{ - // LogMessage("Ch %d: Uploaded message %s\n", Channel, Message); -} - -void ProcessCallingMessage(int Channel, char *Message) -{ - char Payload[16]; - double Frequency; - int ImplicitOrExplicit, ErrorCoding, Bandwidth, SpreadingFactor, LowDataRateOptimize; - - ChannelPrintf(Channel, 3, 1, "Calling message %d bytes ", strlen(Message)); - - if (sscanf(Message+2, "%15[^,],%lf,%d,%d,%d,%d,%d,%d", - Payload, - &Frequency, - &ImplicitOrExplicit, - &ErrorCoding, - &Bandwidth, - &SpreadingFactor, - &LowDataRateOptimize) == 7) - { - if (Config.LoRaDevices[Channel].AFC) - { - double MasterFrequency; - - sscanf(Config.LoRaDevices[Channel].Frequency, "%lf", &MasterFrequency); - - Frequency += Config.LoRaDevices[Channel].activeFreq - MasterFrequency; - } - - LogMessage("Ch %d: Calling message, new frequency %7.3lf\n", Channel, Frequency); - - // Decoded OK - setMode(Channel, RF98_MODE_SLEEP); - - // setFrequency(Channel, Config.LoRaDevices[Channel].activeFreq + ); - setFrequency(Channel, Frequency); - - SetLoRaParameters(Channel, ImplicitOrExplicit, ErrorCoding, Bandwidth, SpreadingFactor, LowDataRateOptimize); - - setMode(Channel, RF98_MODE_RX_CONTINUOUS); - - Config.LoRaDevices[Channel].InCallingMode = 1; - - // ChannelPrintf(Channel, 1, 1, "Channel %d %7.3lfMHz ", Channel, Frequency); - } -} - -size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp) -{ - return size * nmemb; -} - -void UploadListenerTelemetry(char *callsign, float gps_lat, float gps_lon, char *antenna) -{ - int time_epoch = (int)time(NULL); - if (Config.EnableHabitat) - { - CURL *curl; - CURLcode res; - char PostFields[300]; - char JsonData[200]; - - /* In windows, this will init the winsock stuff */ - // curl_global_init(CURL_GLOBAL_ALL); // RJH moved to main in gateway.c not thread safe - - /* get a curl handle */ - curl = curl_easy_init(); - if (curl) - { - // So that the response to the curl POST doesn;'t mess up my finely crafted display! - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); - - // Set the URL that is about to receive our POST - curl_easy_setopt(curl, CURLOPT_URL, "http://habitat.habhub.org/transition/listener_telemetry"); - - // Now specify the POST data - sprintf(JsonData,"{\"latitude\": %f, \"longitude\": %f}", gps_lat, gps_lon); - sprintf(PostFields, "callsign=%s&time=%d&data=%s", callsign, time_epoch, JsonData); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, PostFields); - - // Perform the request, res will get the return code - res = curl_easy_perform(curl); - - // Check for errors - if(res == CURLE_OK) - { - LogMessage("Uploaded listener %s position %f,%f\n", Config.Tracker, Config.latitude, Config.longitude); - } - else - { - LogMessage("curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); - } - - // always cleanup - curl_easy_cleanup(curl); - } - - // curl_global_cleanup(); // RJH moved to main in gateway.c not thread safe - - /* In windows, this will init the winsock stuff */ - // curl_global_init(CURL_GLOBAL_ALL); // RJH moved to main in gateway.c not thread safe - - /* get a curl handle */ - curl = curl_easy_init(); - if (curl) - { - // So that the response to the curl POST doesn;'t mess up my finely crafted display! - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); - - // Set the URL that is about to receive our POST - curl_easy_setopt(curl, CURLOPT_URL, "http://habitat.habhub.org/transition/listener_information"); - - // Now specify the POST data - sprintf(JsonData, "{\"radio\": \"%s\", \"antenna\": \"%s\"}", "LoRa RFM98W", antenna); - sprintf(PostFields, "callsign=%s&time=%d&data=%s", Config.Tracker, time_epoch, JsonData); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, PostFields); - - // Perform the request, res will get the return code - res = curl_easy_perform(curl); - - // Check for errors - if(res != CURLE_OK) - { - LogMessage("curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); - } - - // always cleanup - curl_easy_cleanup(curl); - } - - // curl_global_cleanup(); // RJH moved to main in gateway.c not thread safe - } -} - - -void DoPositionCalcs(Channel) -{ - unsigned long Now; - struct tm tm; - float Climb, Period; - - strptime(Config.LoRaDevices[Channel].Time, "%H:%M:%S", &tm); - Now = tm.tm_hour * 3600 + tm.tm_min * 60 + tm.tm_sec; - - if ((Config.LoRaDevices[Channel].LastPositionAt > 0) && (Now > Config.LoRaDevices[Channel].LastPositionAt)) - { - Climb = (float)Config.LoRaDevices[Channel].Altitude - (float)Config.LoRaDevices[Channel].PreviousAltitude; - Period = (float)Now - (float)Config.LoRaDevices[Channel].LastPositionAt; - Config.LoRaDevices[Channel].AscentRate = Climb / Period; - } - else - { - Config.LoRaDevices[Channel].AscentRate = 0; + LogMessage("Change frequency to %.3lfMHz\n", Config.LoRaDevices[Channel].UplinkFrequency); + setFrequency(Channel, Config.LoRaDevices[Channel].UplinkFrequency); } - Config.LoRaDevices[Channel].PreviousAltitude = Config.LoRaDevices[Channel].Altitude; - Config.LoRaDevices[Channel].LastPositionAt = Now; + // Change mode for the uplink ? + if (Config.LoRaDevices[Channel].UplinkMode >= 0) + { + int UplinkMode; + + UplinkMode = Config.LoRaDevices[Channel].UplinkMode; + + LogMessage("Change LoRa mode to %d\n", Config.LoRaDevices[Channel].UplinkMode); + + SetLoRaParameters(Channel, + LoRaModes[UplinkMode].ImplicitOrExplicit, + LoRaModes[UplinkMode].ErrorCoding, + LoRaModes[UplinkMode].Bandwidth, + LoRaModes[UplinkMode].SpreadingFactor, + 0); + } - ChannelPrintf(Channel, 4, 1, "%8.5lf, %8.5lf, %05u ", - Config.LoRaDevices[Channel].Latitude, - Config.LoRaDevices[Channel].Longitude, - Config.LoRaDevices[Channel].Altitude); + LogMessage( "LoRa Channel %d Sending %d bytes\n", Channel, Length ); + Config.LoRaDevices[Channel].Sending = 1; + + setMode( Channel, RF98_MODE_STANDBY ); + + writeRegister( Channel, REG_DIO_MAPPING_1, 0x40 ); // 01 00 00 00 maps DIO0 to TxDone + + writeRegister( Channel, REG_FIFO_TX_BASE_AD, 0x00 ); // Update the address ptr to the current tx base address + writeRegister( Channel, REG_FIFO_ADDR_PTR, 0x00 ); + + data[0] = REG_FIFO | 0x80; + for ( i = 0; i < Length; i++ ) + { + data[i + 1] = buffer[i]; + } + wiringPiSPIDataRW( Channel, data, Length + 1 ); + + // Set the length. For implicit mode, since the length needs to match what the receiver expects, we have to set a value which is 255 for an SSDV packet + writeRegister( Channel, REG_PAYLOAD_LENGTH, Length ); + + // go into transmit mode + setMode( Channel, RF98_MODE_TX ); +} + +void +ShowPacketCounts( int Channel ) +{ + if ( Config.LoRaDevices[Channel].InUse ) + { + ChannelPrintf( Channel, 7, 1, "Telem Packets = %d (%us) ", + Config.LoRaDevices[Channel].TelemetryCount, + Config.LoRaDevices[Channel]. + LastTelemetryPacketAt ? ( unsigned int ) ( time( NULL ) + - + Config. + LoRaDevices + [Channel]. + LastTelemetryPacketAt ) + : 0 ); + ChannelPrintf( Channel, 8, 1, "Image Packets = %d (%us) ", + Config.LoRaDevices[Channel].SSDVCount, + Config.LoRaDevices[Channel]. + LastSSDVPacketAt ? ( unsigned int ) ( time( NULL ) - + Config. + LoRaDevices + [Channel]. + LastSSDVPacketAt ) + : 0 ); + + ChannelPrintf( Channel, 9, 1, "Bad CRC = %d Bad Type = %d", + Config.LoRaDevices[Channel].BadCRCCount, + Config.LoRaDevices[Channel].UnknownCount ); + + ChannelPrintf( Channel, 6, 16, "SSDV %d ", + Config.LoRaDevices[Channel].SSDVCount ); + } +} + +void +ProcessUploadMessage( int Channel, char *Message ) +{ + // LogMessage("Ch %d: Uploaded message %s\n", Channel, Message); +} + +void +ProcessCallingMessage( int Channel, char *Message ) +{ + char Payload[16]; + double Frequency; + int ImplicitOrExplicit, ErrorCoding, Bandwidth, SpreadingFactor, + LowDataRateOptimize; + + ChannelPrintf( Channel, 3, 1, "Calling message %d bytes ", + strlen( Message ) ); + + if ( sscanf( Message + 2, "%15[^,],%lf,%d,%d,%d,%d,%d", + Payload, + &Frequency, + &ImplicitOrExplicit, + &ErrorCoding, + &Bandwidth, &SpreadingFactor, &LowDataRateOptimize ) == 7 ) + { + if ( Config.LoRaDevices[Channel].AFC ) + { + double MasterFrequency; + + sscanf( Config.LoRaDevices[Channel].Frequency, "%lf", + &MasterFrequency ); + + Frequency += + Config.LoRaDevices[Channel].activeFreq - MasterFrequency; + } + + LogMessage( "Ch %d: Calling message, new frequency %7.3lf\n", Channel, + Frequency ); + + // Decoded OK + setMode( Channel, RF98_MODE_SLEEP ); + + // setFrequency(Channel, Config.LoRaDevices[Channel].activeFreq + ); + setFrequency( Channel, Frequency ); + + SetLoRaParameters( Channel, ImplicitOrExplicit, ErrorCoding, + Bandwidth, SpreadingFactor, LowDataRateOptimize ); + + setMode( Channel, RF98_MODE_RX_CONTINUOUS ); + + Config.LoRaDevices[Channel].InCallingMode = 1; + + // ChannelPrintf(Channel, 1, 1, "Channel %d %7.3lfMHz ", Channel, Frequency); + } +} + +size_t +write_data( void *buffer, size_t size, size_t nmemb, void *userp ) +{ + return size * nmemb; +} + +void +UploadListenerTelemetry( char *callsign, float gps_lat, float gps_lon, + char *antenna ) +{ + int time_epoch = ( int ) time( NULL ); + if ( Config.EnableHabitat ) + { + CURL *curl; + CURLcode res; + char PostFields[300]; + char JsonData[200]; + + /* In windows, this will init the winsock stuff */ + + /* get a curl handle */ + curl = curl_easy_init( ); + if ( curl ) + { + // So that the response to the curl POST doesn;'t mess up my finely crafted display! + curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, write_data ); + + // Set the URL that is about to receive our POST + curl_easy_setopt( curl, CURLOPT_URL, + "http://habitat.habhub.org/transition/listener_telemetry" ); + + // Now specify the POST data + sprintf( JsonData, "{\"latitude\": %f, \"longitude\": %f}", + gps_lat, gps_lon ); + sprintf( PostFields, "callsign=%s&time=%d&data=%s", callsign, + time_epoch, JsonData ); + curl_easy_setopt( curl, CURLOPT_POSTFIELDS, PostFields ); + + // Perform the request, res will get the return code + res = curl_easy_perform( curl ); + + // Check for errors + if ( res == CURLE_OK ) + { + LogMessage( "Uploaded listener %s position %f,%f\n", + Config.Tracker, Config.latitude, + Config.longitude ); + } + else + { + LogMessage( "curl_easy_perform() failed: %s\n", + curl_easy_strerror( res ) ); + } + + // always cleanup + curl_easy_cleanup( curl ); + } + + /* In windows, this will init the winsock stuff */ + + /* get a curl handle */ + curl = curl_easy_init( ); + if ( curl ) + { + // So that the response to the curl POST doesn;'t mess up my finely crafted display! + curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, write_data ); + + // Set the URL that is about to receive our POST + curl_easy_setopt( curl, CURLOPT_URL, + "http://habitat.habhub.org/transition/listener_information" ); + + // Now specify the POST data + sprintf( JsonData, "{\"radio\": \"%s\", \"antenna\": \"%s\"}", + "LoRa RFM98W", antenna ); + sprintf( PostFields, "callsign=%s&time=%d&data=%s", Config.Tracker, time_epoch, JsonData ); + curl_easy_setopt( curl, CURLOPT_POSTFIELDS, PostFields ); + + // Perform the request, res will get the return code + res = curl_easy_perform( curl ); + + // Check for errors + if ( res != CURLE_OK ) + { + LogMessage( "curl_easy_perform() failed: %s\n", + curl_easy_strerror( res ) ); + } + + // always cleanup + curl_easy_cleanup( curl ); + } + + } } -void ProcessLine(int Channel, char *Line) +void +DoPositionCalcs( Channel ) { - int FieldCount; - int Speed, Heading, Satellites; - float TempInt, TempExt; + unsigned long Now; + struct tm tm; + float Climb, Period; - Config.LoRaDevices[Channel].FlightMode = -1; - - if (Config.EnableDev) - { - FieldCount = sscanf(Line+2, "%15[^,],%u,%8[^,],%lf,%lf,%u,%d,%d,%d,%f,%f,%lf,%lf,%lf,%lf,%d,%d,%d,%lf,%d,%d,%d,%d,%lf,%d", - &(Config.LoRaDevices[Channel].Payload), - &(Config.LoRaDevices[Channel].Counter), - &(Config.LoRaDevices[Channel].Time), - &(Config.LoRaDevices[Channel].Latitude), - &(Config.LoRaDevices[Channel].Longitude), - &(Config.LoRaDevices[Channel].Altitude), - &(Config.LoRaDevices[Channel].Speed), - &(Config.LoRaDevices[Channel].Heading), - &Satellites, - &TempInt, &TempExt, - &(Config.LoRaDevices[Channel].cda), - &(Config.LoRaDevices[Channel].PredictedLatitude), - &(Config.LoRaDevices[Channel].PredictedLongitude), - &(Config.LoRaDevices[Channel].PredictedLandingSpeed), - &(Config.LoRaDevices[Channel].PredictedTime), - &(Config.LoRaDevices[Channel].CompassActual), - &(Config.LoRaDevices[Channel].CompassTarget), - &(Config.LoRaDevices[Channel].AirSpeed), - &(Config.LoRaDevices[Channel].AirDirection), - &(Config.LoRaDevices[Channel].ServoLeft), - &(Config.LoRaDevices[Channel].ServoRight), - &(Config.LoRaDevices[Channel].ServoTime), - &(Config.LoRaDevices[Channel].GlideRatio), - &(Config.LoRaDevices[Channel].FlightMode)); - } - else - { - FieldCount = sscanf(Line+2, "%15[^,],%u,%8[^,],%lf,%lf,%u", - &(Config.LoRaDevices[Channel].Payload), - &(Config.LoRaDevices[Channel].Counter), - &(Config.LoRaDevices[Channel].Time), - &(Config.LoRaDevices[Channel].Latitude), - &(Config.LoRaDevices[Channel].Longitude), - &(Config.LoRaDevices[Channel].Altitude)); - } + strptime( Config.LoRaDevices[Channel].Time, "%H:%M:%S", &tm ); + Now = tm.tm_hour * 3600 + tm.tm_min * 60 + tm.tm_sec; + + if ( ( Config.LoRaDevices[Channel].LastPositionAt > 0 ) + && ( Now > Config.LoRaDevices[Channel].LastPositionAt ) ) + { + Climb = + ( float ) Config.LoRaDevices[Channel].Altitude - + ( float ) Config.LoRaDevices[Channel].PreviousAltitude; + Period = + ( float ) Now - + ( float ) Config.LoRaDevices[Channel].LastPositionAt; + Config.LoRaDevices[Channel].AscentRate = Climb / Period; + } + else + { + Config.LoRaDevices[Channel].AscentRate = 0; + } + + Config.LoRaDevices[Channel].PreviousAltitude = + Config.LoRaDevices[Channel].Altitude; + Config.LoRaDevices[Channel].LastPositionAt = Now; + + ChannelPrintf( Channel, 4, 1, "%8.5lf, %8.5lf, %05u ", + Config.LoRaDevices[Channel].Latitude, + Config.LoRaDevices[Channel].Longitude, + Config.LoRaDevices[Channel].Altitude ); } - -void ProcessTelemetryMessage(int Channel, char *Message) + +void +ProcessLine( int Channel, char *Line ) { - if (strlen(Message+1) < 250) - { - int i; - unsigned char *startmessage, *endmessage; + int Satellites; + float TempInt, TempExt; - ChannelPrintf(Channel, 3, 1, "Telemetry %d bytes ", strlen(Message+1)); + Config.LoRaDevices[Channel].FlightMode = -1; - endmessage = Message; - - startmessage = endmessage; - endmessage = strchr(startmessage, '\n'); + if ( Config.EnableDev ) + { + sscanf( Line + 2, + "%15[^,],%u,%8[^,],%lf,%lf,%u,%d,%d,%d,%f,%f,%lf,%lf,%lf,%lf,%d,%d,%d,%lf,%d,%d,%d,%d,%lf,%d", + ( Config.LoRaDevices[Channel].Payload ), + &( Config.LoRaDevices[Channel].Counter ), + ( Config.LoRaDevices[Channel].Time ), + &( Config.LoRaDevices[Channel].Latitude ), + &( Config.LoRaDevices[Channel].Longitude ), + &( Config.LoRaDevices[Channel].Altitude ), + &( Config.LoRaDevices[Channel].Speed ), + &( Config.LoRaDevices[Channel].Heading ), &Satellites, + &TempInt, &TempExt, &( Config.LoRaDevices[Channel].cda ), + &( Config.LoRaDevices[Channel].PredictedLatitude ), + &( Config.LoRaDevices[Channel].PredictedLongitude ), + &( Config.LoRaDevices[Channel].PredictedLandingSpeed ), + &( Config.LoRaDevices[Channel].PredictedTime ), + &( Config.LoRaDevices[Channel].CompassActual ), + &( Config.LoRaDevices[Channel].CompassTarget ), + &( Config.LoRaDevices[Channel].AirSpeed ), + &( Config.LoRaDevices[Channel].AirDirection ), + &( Config.LoRaDevices[Channel].ServoLeft ), + &( Config.LoRaDevices[Channel].ServoRight ), + &( Config.LoRaDevices[Channel].ServoTime ), + &( Config.LoRaDevices[Channel].GlideRatio ), + &( Config.LoRaDevices[Channel].FlightMode ) ); + } + else + { + sscanf( Line + 2, "%15[^,],%u,%8[^,],%lf,%lf,%u", + ( Config.LoRaDevices[Channel].Payload ), + &( Config.LoRaDevices[Channel].Counter ), + ( Config.LoRaDevices[Channel].Time ), + &( Config.LoRaDevices[Channel].Latitude ), + &( Config.LoRaDevices[Channel].Longitude ), + &( Config.LoRaDevices[Channel].Altitude ) ); + } +} - if (endmessage != NULL) - { - time_t now; - struct tm *tm; - - *endmessage = '\0'; + +void +ProcessTelemetryMessage( int Channel, char *Message ) +{ + if ( strlen( Message + 1 ) < 250 ) + { + char *startmessage, *endmessage; + + ChannelPrintf( Channel, 3, 1, "Telemetry %d bytes ", + strlen( Message + 1 ) ); + + startmessage = Message; + endmessage = strchr( startmessage, '\n' ); + + if ( endmessage != NULL ) + { + habitate_telem_packets++; + + time_t now; + struct tm *tm; + + *endmessage = '\0'; LogTelemetryPacket(startmessage); - - strcpy(Config.LoRaDevices[Channel].Telemetry, startmessage); - // UploadTelemetryPacket(startmessage); - ProcessLine(Channel, startmessage); - + strcpy( Config.LoRaDevices[Channel].Telemetry, startmessage ); + // UploadTelemetryPacket(startmessage); - now = time(0); - tm = localtime(&now); - - LogMessage("%02d:%02d:%02d Ch%d: %s\n", tm->tm_hour, tm->tm_min, tm->tm_sec, Channel, startmessage); - } - - DoPositionCalcs(Channel); - - Config.LoRaDevices[Channel].TelemetryCount++; - Config.LoRaDevices[Channel].LastTelemetryPacketAt = time(NULL); - } + ProcessLine( Channel, startmessage ); + + now = time( 0 ); + tm = localtime( &now ); + + + if ( Config.EnableHabitat ) + { + + // Create a telemetry packet + telemetry_t t; + t.Channel = Channel; + t.Packet_Number = habitate_telem_packets; + memcpy( t.Telemetry, startmessage, + strlen( startmessage ) + 1 ); + + // Add the telemetry packet to the pipe + int result = write( telem_pipe_fd[1], &t, sizeof( t ) ); + if ( result == -1 ) + { + printf( "Error writing to the telemetry pipe\n" ); + exit( 1 ); + } + if ( result == 0 ) + { + LogMessage( "Nothing written to telemetry pipe \n" ); + } + if ( result > 1 ) + { + htsv.packet_count++; + } + } + + LogMessage( "%02d:%02d:%02d Ch%d: %s\n", tm->tm_hour, tm->tm_min, + tm->tm_sec, Channel, startmessage ); + + } + + DoPositionCalcs( Channel ); + + // RJH I think this should be moved up to the bottom of the loop above + Config.LoRaDevices[Channel].TelemetryCount++; + Config.LoRaDevices[Channel].LastTelemetryPacketAt = time( NULL ); + } } -static char *decode_callsign(char *callsign, uint32_t code) +static char * +decode_callsign( char *callsign, uint32_t code ) { - char *c, s; - - *callsign = '\0'; - - /* Is callsign valid? */ - if(code > 0xF423FFFF) return(callsign); - - for(c = callsign; code; c++) - { - s = code % 40; - if(s == 0) *c = '-'; - else if(s < 11) *c = '0' + s - 1; - else if(s < 14) *c = '-'; - else *c = 'A' + s - 14; - code /= 40; - } - *c = '\0'; - - return(callsign); + char *c, s; + + *callsign = '\0'; + + /* Is callsign valid? */ + if ( code > 0xF423FFFF ) + return ( callsign ); + + for ( c = callsign; code; c++ ) + { + s = code % 40; + if ( s == 0 ) + *c = '-'; + else if ( s < 11 ) + *c = '0' + s - 1; + else if ( s < 14 ) + *c = '-'; + else + *c = 'A' + s - 14; + code /= 40; + } + *c = '\0'; + + return ( callsign ); } -int FileExists(char *filename) +int +FileExists( char *filename ) { - struct stat st; + struct stat st; - return stat(filename, &st) == 0; -} - -void ProcessSSDVMessage(int Channel, char *Message) -{ - // SSDV packet - static uint32_t PreviousCallsignCode=0; - static int PreviousImageNumber=-1, PreviousPacketNumber=0; - uint32_t CallsignCode; - char Callsign[7], *FileMode, *EncodedEncoding, *Base64Data, *EncodedData, HexString[513], Command[1000]; - int output_length, ImageNumber, PacketNumber; - char filename[100]; - FILE *fp; - - Message[0] = 0x55; - - CallsignCode = Message[2]; CallsignCode <<= 8; - CallsignCode |= Message[3]; CallsignCode <<= 8; - CallsignCode |= Message[4]; CallsignCode <<= 8; - CallsignCode |= Message[5]; - - decode_callsign(Callsign, CallsignCode); - - ImageNumber = Message[6]; - PacketNumber = Message[7] * 256 + Message[8]; - - LogMessage("Ch%d: SSDV Packet, Callsign %s, Image %d, Packet %d\n", Channel, Callsign, Message[6], PacketNumber); - ChannelPrintf(Channel, 3, 1, "SSDV Packet "); - ChannelPrintf(Channel, 5, 1, "SSDV %s: Image %d, Packet %d", Callsign, Message[6], PacketNumber); - - PreviousImageNumber = ImageNumber; - PreviousPacketNumber = PacketNumber; - PreviousCallsignCode = CallsignCode; - - // Create new file ? - sprintf(filename, "/tmp/%s_%d.bin", Callsign, ImageNumber); - if (!FileExists(filename)) - { - // New image so new file - LogMessage("Started image %d\n", ImageNumber); - - // AddImageNumberToLog(Channel, ImageNumber); - - FileMode = "wb"; - } - else - { - FileMode = "r+b"; - } - - // Save to file - if (fp = fopen(filename, FileMode)) - { - fseek(fp, PacketNumber*256, SEEK_SET); - if (fwrite(Message, 1, 256, fp) == 256) - { - // AddImagePacketToLog(Channel, ImageNumber, PacketNumber); - } - else - { - LogMessage("** FAILED TO WRITE TO SSDV FILE\n"); - } - - fclose(fp); - } - - // ShowMissingPackets(Channel); - - if (Config.EnableSSDV) - { - int ArrayIndex, PacketIndex; - - - pthread_mutex_lock(&ssdv_mutex); - - ArrayIndex = (SSDVSendArrayIndex == 0) ? 1 : 0; - - // Place in array for upload to server - PacketIndex = SSDVPacketArrays[ArrayIndex].Count; - - if (PacketIndex < SSDV_PACKETS) - { - // LogMessage("Adding to array %d packet %d\n", ArrayIndex, PacketIndex); - - // Copy packet etc - memcpy(SSDVPacketArrays[ArrayIndex].Packets[PacketIndex].Packet, Message, 256); - strcpy(SSDVPacketArrays[ArrayIndex].Packets[PacketIndex].Callsign, Callsign); - - // Update packet count - SSDVPacketArrays[ArrayIndex].Count++; - } - else - { - LogMessage("No free SSDV packets\n"); - } - - if (SSDVSendArrayIndex < 0) - { - SSDVSendArrayIndex = ArrayIndex; - } - pthread_mutex_unlock(&ssdv_mutex); - } - - Config.LoRaDevices[Channel].SSDVCount++; - Config.LoRaDevices[Channel].LastSSDVPacketAt = time(NULL); + return stat( filename, &st ) == 0; } -void TestMessageForSMSAcknowledgement(int Channel, char *Message) +void +ProcessSSDVMessage( int Channel, char *Message ) { - if (Config.SMSFolder[0]) - { - if (strlen(Message) < 250) - { - char Line[256]; - char *token, *value1, *value2; - int FileNumber; - - value1 = NULL; - value2 = NULL; - - strcpy(Line, Message); - token = strtok(Line, ","); - while (token != NULL) - { - value1 = value2; - value2 = token; - token = strtok(NULL, ","); - } + // SSDV packet + uint32_t CallsignCode; + char Callsign[7], *FileMode; + int ImageNumber, PacketNumber; + char filename[100]; + FILE *fp; - // Rename the file matching this parameter - if (value1) - { - char OldFileName[256], NewFileName[256]; - FileNumber = atoi(value1); - if (FileNumber > 0) - { - sprintf(OldFileName, "%s%d.sms", Config.SMSFolder, FileNumber); - if (FileExists(OldFileName)) - { - sprintf(NewFileName, "%s%d.ack", Config.SMSFolder, FileNumber); - if (FileExists(NewFileName)) - { - remove(NewFileName); - } - rename(OldFileName, NewFileName); - LogMessage("Renamed %s as %s\n", OldFileName, NewFileName); - } - } - } - } - } + Message[0] = 0x55; + + CallsignCode = Message[2]; + CallsignCode <<= 8; + CallsignCode |= Message[3]; + CallsignCode <<= 8; + CallsignCode |= Message[4]; + CallsignCode <<= 8; + CallsignCode |= Message[5]; + + decode_callsign( Callsign, CallsignCode ); + + ImageNumber = Message[6]; + PacketNumber = Message[7] * 256 + Message[8]; + + LogMessage( "Ch%d: SSDV Packet, Callsign %s, Image %d, Packet %d\n", + Channel, Callsign, Message[6], PacketNumber ); + ChannelPrintf( Channel, 3, 1, "SSDV Packet " ); + ChannelPrintf( Channel, 5, 1, "SSDV %s: Image %d, Packet %d", Callsign, + Message[6], PacketNumber ); + + // Create new file ? + sprintf( filename, "/tmp/%s_%d.bin", Callsign, ImageNumber ); + if ( !FileExists( filename ) ) + { + // New image so new file + LogMessage( "Started image %d\n", ImageNumber ); + + // AddImageNumberToLog(Channel, ImageNumber); + + FileMode = "wb"; + } + else + { + FileMode = "r+b"; + } + + // Save to file + if ( ( fp = fopen( filename, FileMode ) ) ) + { + fseek( fp, PacketNumber * 256, SEEK_SET ); + if ( fwrite( Message, 1, 256, fp ) == 256 ) + { + // AddImagePacketToLog(Channel, ImageNumber, PacketNumber); + } + else + { + LogMessage( "** FAILED TO WRITE TO SSDV FILE\n" ); + } + + fclose( fp ); + } + + // ShowMissingPackets(Channel); + + if ( Config.EnableSSDV ) + { + // Create a SSDV packet + ssdv_t s; + s.Channel = Channel; + s.Packet_Number = Config.LoRaDevices[Channel].SSDVCount; + memcpy( s.SSDV_Packet, Message, 256 ); + + // Add the SSDV packet to the pipe + int result = write( ssdv_pipe_fd[1], &s, sizeof( s ) ); + if ( result == -1 ) + { + printf( "Error writing to the issdv pipe\n" ); + exit( 1 ); + } + if ( result == 0 ) + { + LogMessage( "Nothing written to ssdv pipe \n" ); + } + if ( result > 1 ) + { + stsv.packet_count++; + } + + } + + Config.LoRaDevices[Channel].SSDVCount++; + Config.LoRaDevices[Channel].LastSSDVPacketAt = time( NULL ); } -void DIO0_Interrupt(int Channel) +void +TestMessageForSMSAcknowledgement( int Channel, char *Message ) { - if (Config.LoRaDevices[Channel].Sending) - { - Config.LoRaDevices[Channel].Sending = 0; - LogMessage("Ch%d: End of Tx\n", Channel); + if ( Config.SMSFolder[0] ) + { + if ( strlen( Message ) < 250 ) + { + char Line[256]; + char *token, *value1, *value2; + int FileNumber; - setLoRaMode(Channel); - SetDefaultLoRaParameters(Channel); - startReceiving(Channel); - } - else - { - int Bytes; - unsigned char Message[257]; - - Bytes = receiveMessage(Channel, Message+1); - - if (Bytes > 0) - { - if (Config.LoRaDevices[Channel].ActivityLED >= 0) - { - digitalWrite(Config.LoRaDevices[Channel].ActivityLED, 1); - LEDCounts[Channel] = 5; - } - - if (Message[1] == '!') - { - ProcessUploadMessage(Channel, Message+1); - } - else if (Message[1] == '^') - { - ProcessCallingMessage(Channel, Message+1); - } - else if (Message[1] == '$') - { - ProcessTelemetryMessage(Channel, Message+1); - TestMessageForSMSAcknowledgement(Channel, Message+1); - } - else if (Message[1] == '>') - { - LogMessage("Flight Controller message %d bytes = %s", Bytes, Message+1); - } - else if (Message[1] == '*') - { - LogMessage("Uplink Command message %d bytes = %s", Bytes, Message+1); - } - else if (Message[1] == 0x66) - { - ProcessSSDVMessage(Channel, Message); - } - else - { - LogMessage("Unknown packet type is %02Xh, RSSI %d\n", Message[1], readRegister(Channel, REG_PACKET_RSSI) - 157); - ChannelPrintf(Channel, 3, 1, "Unknown Packet %d, %d bytes", Message[0], Bytes); - Config.LoRaDevices[Channel].UnknownCount++; - } - - Config.LoRaDevices[Channel].LastPacketAt = time(NULL); - - if (Config.LoRaDevices[Channel].InCallingMode && (Config.CallingTimeout > 0)) - { - Config.LoRaDevices[Channel].ReturnToCallingModeAt = time(NULL) + Config.CallingTimeout; - } - - ShowPacketCounts(Channel); - } - } + value1 = NULL; + value2 = NULL; + + strcpy( Line, Message ); + token = strtok( Line, "," ); + while ( token != NULL ) + { + value1 = value2; + value2 = token; + token = strtok( NULL, "," ); + } + + // Rename the file matching this parameter + if ( value1 ) + { + char OldFileName[256], NewFileName[256]; + FileNumber = atoi( value1 ); + if ( FileNumber > 0 ) + { + sprintf( OldFileName, "%s%d.sms", Config.SMSFolder, + FileNumber ); + if ( FileExists( OldFileName ) ) + { + sprintf( NewFileName, "%s%d.ack", Config.SMSFolder, + FileNumber ); + if ( FileExists( NewFileName ) ) + { + remove( NewFileName ); + } + rename( OldFileName, NewFileName ); + LogMessage( "Renamed %s as %s\n", OldFileName, + NewFileName ); + } + } + } + } + } } -void DIO0_Interrupt_0(void) +void +DIO0_Interrupt( int Channel ) { - DIO0_Interrupt(0); + if ( Config.LoRaDevices[Channel].Sending ) + { + Config.LoRaDevices[Channel].Sending = 0; + LogMessage( "Ch%d: End of Tx\n", Channel ); + + setLoRaMode( Channel ); + SetDefaultLoRaParameters( Channel ); + startReceiving( Channel ); + } + else + { + int Bytes; + char Message[257]; + + Bytes = receiveMessage( Channel, Message + 1 ); + + // hexdump_buffer ("Raw Data", Message, 257); + + + if ( Bytes > 0 ) + { + if ( Config.LoRaDevices[Channel].ActivityLED >= 0 ) + { + digitalWrite( Config.LoRaDevices[Channel].ActivityLED, 1 ); + LEDCounts[Channel] = 5; + } + + if ( Message[1] == '!' ) + { + ProcessUploadMessage( Channel, Message + 1 ); + } + else if ( Message[1] == '^' ) + { + ProcessCallingMessage( Channel, Message + 1 ); + } + else if ( Message[1] == '$' ) + { + ProcessTelemetryMessage( Channel, Message + 1 ); + TestMessageForSMSAcknowledgement( Channel, Message + 1 ); + } + else if ( Message[1] == '>' ) + { + LogMessage( "Flight Controller message %d bytes = %s", Bytes, + Message + 1 ); + } + else if ( Message[1] == '*' ) + { + LogMessage( "Uplink Command message %d bytes = %s", Bytes, + Message + 1 ); + } + else if ((Message[1] == 0x66) || (Message[1] == 0x67) || (Message[1] == 0x68) || (Message[1] == 0x69)) + { + ProcessSSDVMessage( Channel, Message ); + } + else + { + LogMessage( "Unknown packet type is %02Xh, RSSI %d\n", + Message[1], readRegister( Channel, + REG_PACKET_RSSI ) - + 157 ); + ChannelPrintf( Channel, 3, 1, "Unknown Packet %d, %d bytes", + Message[0], Bytes ); + Config.LoRaDevices[Channel].UnknownCount++; + } + + Config.LoRaDevices[Channel].LastPacketAt = time( NULL ); + + if ( Config.LoRaDevices[Channel].InCallingMode + && ( Config.CallingTimeout > 0 ) ) + { + Config.LoRaDevices[Channel].ReturnToCallingModeAt = + time( NULL ) + Config.CallingTimeout; + } + + ShowPacketCounts( Channel ); + } + } } -void DIO0_Interrupt_1(void) +void DIO_Ignore_Interrupt_0( void ) { - DIO0_Interrupt(1); + // nothing, obviously! } -void setupRFM98(int Channel) +void +DIO0_Interrupt_0( void ) { - if (Config.LoRaDevices[Channel].InUse) - { - // initialize the pins - pinMode(Config.LoRaDevices[Channel].DIO0, INPUT); - pinMode(Config.LoRaDevices[Channel].DIO5, INPUT); - - wiringPiISR (Config.LoRaDevices[Channel].DIO0, INT_EDGE_RISING, Channel>0 ? &DIO0_Interrupt_1 : &DIO0_Interrupt_0); - - if (wiringPiSPISetup(Channel, 500000) < 0) - { - fprintf(stderr, "Failed to open SPI port. Try loading spi library with 'gpio load spi'"); - exit(1); - } - - // LoRa mode - setLoRaMode(Channel); - - SetDefaultLoRaParameters(Channel); - - startReceiving(Channel); - } + DIO0_Interrupt( 0 ); } -double FrequencyReference(int Channel) +void +DIO0_Interrupt_1( void ) { - switch (Config.LoRaDevices[Channel].CurrentBandwidth) - { - case BANDWIDTH_7K8: return 7800; - case BANDWIDTH_10K4: return 10400; - case BANDWIDTH_15K6: return 15600; - case BANDWIDTH_20K8: return 20800; - case BANDWIDTH_31K25: return 31250; - case BANDWIDTH_41K7: return 41700; - case BANDWIDTH_62K5: return 62500; - case BANDWIDTH_125K: return 125000; - case BANDWIDTH_250K: return 250000; - case BANDWIDTH_500K: return 500000; - } + DIO0_Interrupt( 1 ); } -double FrequencyError(int Channel) +void +setupRFM98( int Channel ) { - int32_t Temp; - - Temp = (int32_t)readRegister(Channel, REG_FREQ_ERROR) & 7; - Temp <<= 8L; - Temp += (int32_t)readRegister(Channel, REG_FREQ_ERROR+1); - Temp <<= 8L; - Temp += (int32_t)readRegister(Channel, REG_FREQ_ERROR+2); - - if (readRegister(Channel, REG_FREQ_ERROR) & 8) - { - Temp = Temp - 524288; - } + if ( Config.LoRaDevices[Channel].InUse ) + { + // initialize the pins + pinMode( Config.LoRaDevices[Channel].DIO0, INPUT ); + pinMode( Config.LoRaDevices[Channel].DIO5, INPUT ); - return - ((double)Temp * (1<<24) / 32000000.0) * (FrequencyReference(Channel) / 500000.0); -} + wiringPiISR( Config.LoRaDevices[Channel].DIO0, INT_EDGE_RISING, + Channel > 0 ? &DIO0_Interrupt_1 : &DIO0_Interrupt_0 ); -int receiveMessage(int Channel, unsigned char *message) -{ - int i, Bytes, currentAddr, x; - unsigned char data[257]; - double FreqError; + if ( wiringPiSPISetup( Channel, 500000 ) < 0 ) + { + fprintf( stderr, + "Failed to open SPI port. Try loading spi library with 'gpio load spi'" ); + exit( 1 ); + } - Bytes = 0; - - x = readRegister(Channel, REG_IRQ_FLAGS); - // LogMessage("Message status = %02Xh\n", x); - - // clear the rxDone flag - writeRegister(Channel, REG_IRQ_FLAGS, 0x40); - - // check for payload crc issues (0x20 is the bit we are looking for - if((x & 0x20) == 0x20) - { - LogMessage("Ch%d: CRC Failure, RSSI %d\n", Channel, readRegister(Channel, REG_PACKET_RSSI) - 157); - // reset the crc flags - writeRegister(Channel, REG_IRQ_FLAGS, 0x20); - ChannelPrintf(Channel, 3, 1, "CRC Failure %02Xh!!\n", x); - Config.LoRaDevices[Channel].BadCRCCount++; - ShowPacketCounts(Channel); - } - else - { - int8_t SNR; - int RSSI; - - currentAddr = readRegister(Channel, REG_FIFO_RX_CURRENT_ADDR); - Bytes = readRegister(Channel, REG_RX_NB_BYTES); - - SNR = readRegister(Channel, REG_PACKET_SNR); - SNR /= 4; - RSSI = readRegister(Channel, REG_PACKET_RSSI) - 157; - if (SNR < 0) - { - RSSI += SNR; - } - - ChannelPrintf(Channel, 10, 1, "Packet SNR = %d, RSSI = %d ", (int)SNR, RSSI); + // LoRa mode + setLoRaMode( Channel ); - FreqError = FrequencyError(Channel) / 1000; - ChannelPrintf(Channel, 11, 1, "Freq. Error = %5.1lfkHz ", FreqError); - + SetDefaultLoRaParameters( Channel ); - writeRegister(Channel, REG_FIFO_ADDR_PTR, currentAddr); - - data[0] = REG_FIFO; - wiringPiSPIDataRW(Channel, data, Bytes+1); - for (i=0; i<=Bytes; i++) - { - message[i] = data[i+1]; - } - - message[Bytes] = '\0'; - - LogPacket(Channel, SNR, RSSI, FreqError, Bytes, message[1]); - - if(Config.LoRaDevices[Channel].AFC && (fabs(FreqError)>0.5)) - { - ReTune(Channel, FreqError/1000); - } - } - - // Clear all flags - writeRegister(Channel, REG_IRQ_FLAGS, 0xFF); - - return Bytes; + startReceiving( Channel ); + } } -void ReadString(FILE *fp, char *keyword, char *Result, int Length, int NeedValue) +double +FrequencyReference( int Channel ) { - char line[100], *token, *value; - - fseek(fp, 0, SEEK_SET); - *Result = '\0'; + switch ( Config.LoRaDevices[Channel].CurrentBandwidth ) + { + case BANDWIDTH_7K8: + return 7800; + case BANDWIDTH_10K4: + return 10400; + case BANDWIDTH_15K6: + return 15600; + case BANDWIDTH_20K8: + return 20800; + case BANDWIDTH_31K25: + return 31250; + case BANDWIDTH_41K7: + return 41700; + case BANDWIDTH_62K5: + return 62500; + case BANDWIDTH_125K: + return 125000; + case BANDWIDTH_250K: + return 250000; + case BANDWIDTH_500K: + return 500000; + } - while (fgets(line, sizeof(line), fp) != NULL) - { - token = strtok(line, "="); - if (strcasecmp(keyword, token) == 0) - { - value = strtok(NULL, "\n"); - strcpy(Result, value); - return; - } - } - - if (NeedValue) - { - LogMessage("Missing value for '%s' in configuration file\n", keyword); - exit(1); - } + return 0; } -int ReadInteger(FILE *fp, char *keyword, int NeedValue, int DefaultValue) +double +FrequencyError( int Channel ) { - char Temp[64]; + int32_t Temp; - ReadString(fp, keyword, Temp, sizeof(Temp), NeedValue); + Temp = ( int32_t ) readRegister( Channel, REG_FREQ_ERROR ) & 7; + Temp <<= 8L; + Temp += ( int32_t ) readRegister( Channel, REG_FREQ_ERROR + 1 ); + Temp <<= 8L; + Temp += ( int32_t ) readRegister( Channel, REG_FREQ_ERROR + 2 ); - if (Temp[0]) - { - return atoi(Temp); - } - - return DefaultValue; + if ( readRegister( Channel, REG_FREQ_ERROR ) & 8 ) + { + Temp = Temp - 524288; + } + + return -( ( double ) Temp * ( 1 << 24 ) / 32000000.0 ) * + ( FrequencyReference( Channel ) / 500000.0 ); } -float ReadFloat(FILE *fp, char *keyword) +int +receiveMessage( int Channel, char *message ) { - char Temp[64]; + int i, Bytes, currentAddr, x; + unsigned char data[257]; + double FreqError; - ReadString(fp, keyword, Temp, sizeof(Temp), 0); + Bytes = 0; - if (Temp[0]) - { - return atof(Temp); - } - - return 0; + x = readRegister( Channel, REG_IRQ_FLAGS ); + // LogMessage("Message status = %02Xh\n", x); + + // clear the rxDone flag + writeRegister( Channel, REG_IRQ_FLAGS, 0x40 ); + + // check for payload crc issues (0x20 is the bit we are looking for + if ( ( x & 0x20 ) == 0x20 ) + { + LogMessage( "Ch%d: CRC Failure, RSSI %d\n", Channel, + readRegister( Channel, REG_PACKET_RSSI ) - 157 ); + // reset the crc flags + writeRegister( Channel, REG_IRQ_FLAGS, 0x20 ); + ChannelPrintf( Channel, 3, 1, "CRC Failure %02Xh!!\n", x ); + Config.LoRaDevices[Channel].BadCRCCount++; + ShowPacketCounts( Channel ); + } + else + { + int8_t SNR; + int RSSI; + + currentAddr = readRegister( Channel, REG_FIFO_RX_CURRENT_ADDR ); + Bytes = readRegister( Channel, REG_RX_NB_BYTES ); + + SNR = readRegister( Channel, REG_PACKET_SNR ); + SNR /= 4; + RSSI = readRegister( Channel, REG_PACKET_RSSI ) - 157; + if ( SNR < 0 ) + { + RSSI += SNR; + } + + ChannelPrintf( Channel, 10, 1, "Packet SNR = %d, RSSI = %d ", + ( int ) SNR, RSSI ); + + FreqError = FrequencyError( Channel ) / 1000; + ChannelPrintf( Channel, 11, 1, "Freq. Error = %5.1lfkHz ", + FreqError ); + + + writeRegister( Channel, REG_FIFO_ADDR_PTR, currentAddr ); + + data[0] = REG_FIFO; + wiringPiSPIDataRW( Channel, data, Bytes + 1 ); + for ( i = 0; i <= Bytes; i++ ) + { + message[i] = data[i + 1]; + } + + message[Bytes] = '\0'; + + LogPacket( Channel, SNR, RSSI, FreqError, Bytes, message[1] ); + + if ( Config.LoRaDevices[Channel].AFC && ( fabs( FreqError ) > 0.5 ) ) + { + ReTune( Channel, FreqError / 1000 ); + } + } + + // Clear all flags + writeRegister( Channel, REG_IRQ_FLAGS, 0xFF ); + + return Bytes; } -int ReadBoolean(FILE *fp, char *keyword, int NeedValue, int *Result) +void +ReadString( FILE * fp, char *keyword, char *Result, int Length, + int NeedValue ) { - char Temp[32]; + char line[100], *token, *value; - ReadString(fp, keyword, Temp, sizeof(Temp), NeedValue); + fseek( fp, 0, SEEK_SET ); + *Result = '\0'; - if (*Temp) - { - *Result = (*Temp == '1') || (*Temp == 'Y') || (*Temp == 'y') || (*Temp == 't') || (*Temp == 'T'); - } + while ( fgets( line, sizeof( line ), fp ) != NULL ) + { + token = strtok( line, "=" ); + if ( strcasecmp( keyword, token ) == 0 ) + { + value = strtok( NULL, "\n" ); + strcpy( Result, value ); + return; + } + } - return *Temp; -} - -void LoadConfigFile() -{ - FILE *fp; - char *filename = "gateway.txt"; - char Keyword[32]; - int Channel, Temp; - char TempString[16]; - - Config.EnableHabitat = 1; - Config.EnableSSDV = 1; - Config.EnableTelemetryLogging = 0; - Config.EnablePacketLogging = 0; - Config.SSDVJpegFolder[0] = '\0'; - Config.ftpServer[0] = '\0'; - Config.ftpUser[0] = '\0'; - Config.ftpPassword[0] = '\0'; - Config.ftpFolder[0] = '\0'; - Config.latitude = -999; - Config.longitude = -999; - Config.antenna[0] = '\0'; - Config.EnableDev = 0; - - if ((fp = fopen(filename, "r")) == NULL) - { - printf("\nFailed to open config file %s (error %d - %s).\nPlease check that it exists and has read permission.\n", filename, errno, strerror(errno)); - exit(1); - } - - // Receiver config - ReadString(fp, "tracker", Config.Tracker, sizeof(Config.Tracker), 1); - LogMessage("Tracker = '%s'\n", Config.Tracker); - - // Enable uploads - ReadBoolean(fp, "EnableHabitat", 0, &Config.EnableHabitat); - ReadBoolean(fp, "EnableSSDV", 0, &Config.EnableSSDV); - - // Enable telemetry logging - ReadBoolean(fp, "LogTelemetry", 0, &Config.EnableTelemetryLogging); - - // Enable packet logging - ReadBoolean(fp, "LogPackets", 0, &Config.EnablePacketLogging); - - // Calling mode - Config.CallingTimeout = ReadInteger(fp, "CallingTimeout", 0, 300); - - // LED allocations - Config.NetworkLED = ReadInteger(fp, "NetworkLED", 0, -1); - Config.InternetLED = ReadInteger(fp, "InternetLED", 0, -1); - Config.LoRaDevices[0].ActivityLED = ReadInteger(fp, "ActivityLED_0", 0, -1); - Config.LoRaDevices[1].ActivityLED = ReadInteger(fp, "ActivityLED_1", 0, -1); - - // Server Port - Config.ServerPort = ReadInteger(fp, "ServerPort", 0, -1); - - // SSDV Settings - ReadString(fp, "jpgFolder", Config.SSDVJpegFolder, sizeof(Config.SSDVJpegFolder), 0); - if (Config.SSDVJpegFolder[0]) - { - // Create SSDV Folders - struct stat st = {0}; - - if (stat(Config.SSDVJpegFolder, &st) == -1) - { - mkdir(Config.SSDVJpegFolder, 0777); - } - } - - // ftp images - ReadString(fp, "ftpserver", Config.ftpServer, sizeof(Config.ftpServer), 0); - ReadString(fp, "ftpUser", Config.ftpUser, sizeof(Config.ftpUser), 0); - ReadString(fp, "ftpPassword", Config.ftpPassword, sizeof(Config.ftpPassword), 0); - ReadString(fp, "ftpFolder", Config.ftpFolder, sizeof(Config.ftpFolder), 0); - - // Listener - Config.latitude = ReadFloat(fp, "Latitude"); - Config.longitude = ReadFloat(fp, "Longitude"); - ReadString(fp, "antenna", Config.antenna, sizeof(Config.antenna), 0); - - // Dev mode - ReadBoolean(fp, "EnableDev", 0, &Config.EnableDev); - - // SMS upload to tracker - Config.SMSFolder[0] = '\0'; - ReadString(fp, "SMSFolder", Config.SMSFolder, sizeof(Config.SMSFolder), 0); - if (Config.SMSFolder[0]) - { - LogMessage("Scanning folder %s for messages to upload\n", Config.SMSFolder); - } - - for (Channel=0; Channel<=1; Channel++) - { - // Defaults - Config.LoRaDevices[Channel].Frequency[0] = '\0'; - - sprintf(Keyword, "frequency_%d", Channel); - ReadString(fp, Keyword, Config.LoRaDevices[Channel].Frequency, sizeof(Config.LoRaDevices[Channel].Frequency), 0); - if (Config.LoRaDevices[Channel].Frequency[0]) - { - Config.LoRaDevices[Channel].ImplicitOrExplicit = EXPLICIT_MODE; - Config.LoRaDevices[Channel].ErrorCoding = ERROR_CODING_4_8; - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_20K8; - Config.LoRaDevices[Channel].SpreadingFactor = SPREADING_11; - Config.LoRaDevices[Channel].LowDataRateOptimize = 0x00; - Config.LoRaDevices[Channel].AFC = FALSE; - - LogMessage("Channel %d frequency set to %s\n", Channel, Config.LoRaDevices[Channel].Frequency); - Config.LoRaDevices[Channel].InUse = 1; - - // DIO0 / DIO5 overrides - sprintf(Keyword, "DIO0_%d", Channel); - Config.LoRaDevices[Channel].DIO0 = ReadInteger(fp, Keyword, 0, Config.LoRaDevices[Channel].DIO0); - - sprintf(Keyword, "DIO5_%d", Channel); - Config.LoRaDevices[Channel].DIO5 = ReadInteger(fp, Keyword, 0, Config.LoRaDevices[Channel].DIO5); - - LogMessage("LoRa Channel %d DIO0=%d DIO5=%d\n", Channel, Config.LoRaDevices[Channel].DIO0, Config.LoRaDevices[Channel].DIO5); - - // Uplink - sprintf(Keyword, "UplinkTime_%d", Channel); - Config.LoRaDevices[Channel].UplinkTime = ReadInteger(fp, Keyword, 0, 0); - sprintf(Keyword, "UplinkCycle_%d", Channel); - Config.LoRaDevices[Channel].UplinkCycle = ReadInteger(fp, Keyword, 0, 0); - LogMessage("Channel %d UplinkTime %d Uplink Cycle %d\n", Channel, Config.LoRaDevices[Channel].UplinkTime, Config.LoRaDevices[Channel].UplinkCycle); - - sprintf(Keyword, "Power_%d", Channel); - Config.LoRaDevices[Channel].Power = ReadInteger(fp, Keyword, 0, PA_MAX_UK); - LogMessage("Channel %d power set to %02Xh\n", Channel, Config.LoRaDevices[Channel].Power); - - - Config.LoRaDevices[Channel].SpeedMode = 0; - - sprintf(Keyword, "mode_%d", Channel); - Config.LoRaDevices[Channel].SpeedMode = ReadInteger(fp, Keyword, 0, 0); - - if (Config.LoRaDevices[Channel].SpeedMode == 5) - { - // Calling channel - Config.LoRaDevices[Channel].ImplicitOrExplicit = EXPLICIT_MODE; - Config.LoRaDevices[Channel].ErrorCoding = ERROR_CODING_4_8; - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_41K7; - Config.LoRaDevices[Channel].SpreadingFactor = SPREADING_11; - Config.LoRaDevices[Channel].LowDataRateOptimize = 0; - } - else if (Config.LoRaDevices[Channel].SpeedMode == 4) - { - // Testing - Config.LoRaDevices[Channel].ImplicitOrExplicit = IMPLICIT_MODE; - Config.LoRaDevices[Channel].ErrorCoding = ERROR_CODING_4_5; - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_250K; - Config.LoRaDevices[Channel].SpreadingFactor = SPREADING_6; - Config.LoRaDevices[Channel].LowDataRateOptimize = 0; - } - else if (Config.LoRaDevices[Channel].SpeedMode == 3) - { - // Normal mode for high speed images in 868MHz band - Config.LoRaDevices[Channel].ImplicitOrExplicit = EXPLICIT_MODE; - Config.LoRaDevices[Channel].ErrorCoding = ERROR_CODING_4_6; - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_250K; - Config.LoRaDevices[Channel].SpreadingFactor = SPREADING_7; - Config.LoRaDevices[Channel].LowDataRateOptimize = 0; - } - else if (Config.LoRaDevices[Channel].SpeedMode == 2) - { - // Normal mode for repeater network - Config.LoRaDevices[Channel].ImplicitOrExplicit = EXPLICIT_MODE; - Config.LoRaDevices[Channel].ErrorCoding = ERROR_CODING_4_8; - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_62K5; - Config.LoRaDevices[Channel].SpreadingFactor = SPREADING_8; - Config.LoRaDevices[Channel].LowDataRateOptimize = 0x00; - } - else if (Config.LoRaDevices[Channel].SpeedMode == 1) - { - // Normal mode for SSDV - Config.LoRaDevices[Channel].ImplicitOrExplicit = IMPLICIT_MODE; - Config.LoRaDevices[Channel].ErrorCoding = ERROR_CODING_4_5; - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_20K8; - Config.LoRaDevices[Channel].SpreadingFactor = SPREADING_6; - Config.LoRaDevices[Channel].LowDataRateOptimize = 0; - } - else - { - Config.LoRaDevices[Channel].ImplicitOrExplicit = EXPLICIT_MODE; - Config.LoRaDevices[Channel].ErrorCoding = ERROR_CODING_4_8; - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_20K8; - Config.LoRaDevices[Channel].SpreadingFactor = SPREADING_11; - Config.LoRaDevices[Channel].LowDataRateOptimize = 0x08; - } - - sprintf(Keyword, "sf_%d", Channel); - Temp = ReadInteger(fp, Keyword, 0, 0); - if ((Temp >= 6) && (Temp <= 12)) - { - Config.LoRaDevices[Channel].SpreadingFactor = Temp << 4; - LogMessage("Setting SF=%d\n", Temp); - } - - sprintf(Keyword, "bandwidth_%d", Channel); - ReadString(fp, Keyword, TempString, sizeof(TempString), 0); - if (*TempString) - { - LogMessage("Setting BW=%s\n", TempString); - } - if (strcmp(TempString, "7K8") == 0) - { - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_7K8; - } - else if (strcmp(TempString, "10K4") == 0) - { - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_10K4; - } - else if (strcmp(TempString, "15K6") == 0) - { - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_15K6; - } - else if (strcmp(TempString, "20K8") == 0) - { - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_20K8; - } - else if (strcmp(TempString, "31K25") == 0) - { - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_31K25; - } - else if (strcmp(TempString, "41K7") == 0) - { - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_41K7; - } - else if (strcmp(TempString, "62K5") == 0) - { - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_62K5; - } - else if (strcmp(TempString, "125K") == 0) - { - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_125K; - } - else if (strcmp(TempString, "250K") == 0) - { - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_250K; - } - else if (strcmp(TempString, "500K") == 0) - { - Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_500K; - } - - sprintf(Keyword, "implicit_%d", Channel); - if (ReadBoolean(fp, Keyword, 0, &Temp)) - { - Config.LoRaDevices[Channel].ImplicitOrExplicit = Temp ? IMPLICIT_MODE : EXPLICIT_MODE; - } - - sprintf(Keyword, "coding_%d", Channel); - Temp = ReadInteger(fp, Keyword, 0, 0); - if ((Temp >= 5) && (Temp <= 8)) - { - Config.LoRaDevices[Channel].ErrorCoding = (Temp-4) << 1; - LogMessage("Setting Error Coding=%d\n", Temp); - } - - sprintf(Keyword, "lowopt_%d", Channel); - if (ReadBoolean(fp, Keyword, 0, &Temp)) - { - if (Temp) - { - Config.LoRaDevices[Channel].LowDataRateOptimize = 0x08; - } - } - - sprintf(Keyword, "AFC_%d", Channel); - if (ReadBoolean(fp, Keyword, 0, &Temp)) - { - if (Temp) - { - Config.LoRaDevices[Channel].AFC = TRUE; - ChannelPrintf(Channel, 11, 24, "AFC"); - } - } - - // Clear any flags left over from a previous run - writeRegister(Channel, REG_IRQ_FLAGS, 0xFF); - } - } - - fclose(fp); + if ( NeedValue ) + { + LogMessage( "Missing value for '%s' in configuration file\n", + keyword ); + exit( 1 ); + } } -void LoadPayloadFile(int ID) +int +ReadInteger( FILE * fp, char *keyword, int NeedValue, int DefaultValue ) { - FILE *fp; - char filename[16]; - char Keyword[32]; - int Channel, Temp; - char TempString[16]; - - sprintf(filename, "payload_%d.txt", ID); + char Temp[64]; - if ((fp = fopen(filename, "r")) != NULL) - { - LogMessage("Reading payload file %s\n", filename); - ReadString(fp, "payload", Payloads[ID].Payload, sizeof(Payloads[ID].Payload), 1); - LogMessage("Payload %d = '%s'\n", ID, Payloads[ID].Payload); - - Payloads[ID].InUse = 1; + ReadString( fp, keyword, Temp, sizeof( Temp ), NeedValue ); - fclose(fp); - } - else - { - strcpy(Payloads[ID].Payload, "Unknown"); - Payloads[ID].InUse = 0; - } + if ( Temp[0] ) + { + return atoi( Temp ); + } + + return DefaultValue; } -void LoadPayloadFiles(void) +float +ReadFloat( FILE * fp, char *keyword ) { - int ID; - - for (ID=0; ID<16; ID++) - { - LoadPayloadFile(ID); - } + char Temp[64]; + + ReadString( fp, keyword, Temp, sizeof( Temp ), 0 ); + + if ( Temp[0] ) + { + return atof( Temp ); + } + + return 0; } -WINDOW * InitDisplay(void) +int +ReadBoolean( FILE * fp, char *keyword, int NeedValue, int *Result ) { - WINDOW * mainwin; - int Channel; + char Temp[32]; + + ReadString( fp, keyword, Temp, sizeof( Temp ), NeedValue ); + + if ( *Temp ) + { + *Result = ( *Temp == '1' ) || ( *Temp == 'Y' ) || ( *Temp == 'y' ) + || ( *Temp == 't' ) || ( *Temp == 'T' ); + } + + return *Temp; +} + +void LoadConfigFile(void) +{ + FILE *fp; + char *filename = "gateway.txt"; + char Keyword[32]; + int Channel, Temp; + char TempString[16]; + + Config.LoRaDevices[0].InUse = 0; + Config.LoRaDevices[1].InUse = 0; + Config.EnableHabitat = 1; + Config.EnableSSDV = 1; + Config.EnableTelemetryLogging = 0; + Config.EnablePacketLogging = 0; + Config.SSDVJpegFolder[0] = '\0'; + Config.ftpServer[0] = '\0'; + Config.ftpUser[0] = '\0'; + Config.ftpPassword[0] = '\0'; + Config.ftpFolder[0] = '\0'; + Config.latitude = -999; + Config.longitude = -999; + Config.antenna[0] = '\0'; + Config.EnableDev = 0; + + // Default pin allocations + Config.LoRaDevices[0].DIO0 = 6; + Config.LoRaDevices[0].DIO5 = 5; + + Config.LoRaDevices[1].DIO0 = 27; + Config.LoRaDevices[1].DIO5 = 26; + + if ( ( fp = fopen( filename, "r" ) ) == NULL ) + { + printf + ( "\nFailed to open config file %s (error %d - %s).\nPlease check that it exists and has read permission.\n", + filename, errno, strerror( errno ) ); + exit( 1 ); + } + + // Receiver config + ReadString( fp, "tracker", Config.Tracker, sizeof( Config.Tracker ), 1 ); + LogMessage( "Tracker = '%s'\n", Config.Tracker ); + + // Enable uploads + ReadBoolean( fp, "EnableHabitat", 0, &Config.EnableHabitat ); + ReadBoolean( fp, "EnableSSDV", 0, &Config.EnableSSDV ); + + // Enable telemetry logging + ReadBoolean( fp, "LogTelemetry", 0, &Config.EnableTelemetryLogging ); + + // Enable packet logging + ReadBoolean( fp, "LogPackets", 0, &Config.EnablePacketLogging ); + + // Calling mode + Config.CallingTimeout = ReadInteger( fp, "CallingTimeout", 0, 300 ); + + // LED allocations + Config.NetworkLED = ReadInteger( fp, "NetworkLED", 0, -1 ); + Config.InternetLED = ReadInteger( fp, "InternetLED", 0, -1 ); + Config.LoRaDevices[0].ActivityLED = + ReadInteger( fp, "ActivityLED_0", 0, -1 ); + Config.LoRaDevices[1].ActivityLED = + ReadInteger( fp, "ActivityLED_1", 0, -1 ); + + // Server Port + Config.ServerPort = ReadInteger( fp, "ServerPort", 0, -1 ); + + // SSDV Settings + ReadString( fp, "jpgFolder", Config.SSDVJpegFolder, + sizeof( Config.SSDVJpegFolder ), 0 ); + if ( Config.SSDVJpegFolder[0] ) + { + // Create SSDV Folders + struct stat st = { 0 }; + + if ( stat( Config.SSDVJpegFolder, &st ) == -1 ) + { + mkdir( Config.SSDVJpegFolder, 0777 ); + } + } + + // ftp images + ReadString( fp, "ftpserver", Config.ftpServer, sizeof( Config.ftpServer ), + 0 ); + ReadString( fp, "ftpUser", Config.ftpUser, sizeof( Config.ftpUser ), 0 ); + ReadString( fp, "ftpPassword", Config.ftpPassword, + sizeof( Config.ftpPassword ), 0 ); + ReadString( fp, "ftpFolder", Config.ftpFolder, sizeof( Config.ftpFolder ), + 0 ); + + // Listener + Config.latitude = ReadFloat( fp, "Latitude" ); + Config.longitude = ReadFloat( fp, "Longitude" ); + ReadString( fp, "antenna", Config.antenna, sizeof( Config.antenna ), 0 ); + + // Dev mode + ReadBoolean( fp, "EnableDev", 0, &Config.EnableDev ); + + // SMS upload to tracker + Config.SMSFolder[0] = '\0'; + ReadString(fp, "SMSFolder", Config.SMSFolder, sizeof( Config.SMSFolder ), 0); + if ( Config.SMSFolder[0] ) + { + LogMessage( "Folder %s will be scanned for messages to upload\n", + Config.SMSFolder ); + } + + for ( Channel = 0; Channel <= 1; Channel++ ) + { + // Defaults + Config.LoRaDevices[Channel].Frequency[0] = '\0'; + + sprintf( Keyword, "frequency_%d", Channel ); + ReadString( fp, Keyword, Config.LoRaDevices[Channel].Frequency, + sizeof( Config.LoRaDevices[Channel].Frequency ), 0 ); + if ( Config.LoRaDevices[Channel].Frequency[0] ) + { + Config.LoRaDevices[Channel].ImplicitOrExplicit = EXPLICIT_MODE; + Config.LoRaDevices[Channel].ErrorCoding = ERROR_CODING_4_8; + Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_20K8; + Config.LoRaDevices[Channel].SpreadingFactor = SPREADING_11; + Config.LoRaDevices[Channel].LowDataRateOptimize = 0x00; + Config.LoRaDevices[Channel].AFC = FALSE; + + LogMessage( "Channel %d frequency set to %s\n", Channel, + Config.LoRaDevices[Channel].Frequency ); + Config.LoRaDevices[Channel].InUse = 1; + + // DIO0 / DIO5 overrides + sprintf( Keyword, "DIO0_%d", Channel ); + Config.LoRaDevices[Channel].DIO0 = + ReadInteger( fp, Keyword, 0, + Config.LoRaDevices[Channel].DIO0 ); + + sprintf( Keyword, "DIO5_%d", Channel ); + Config.LoRaDevices[Channel].DIO5 = + ReadInteger( fp, Keyword, 0, + Config.LoRaDevices[Channel].DIO5 ); + + LogMessage( "LoRa Channel %d DIO0=%d DIO5=%d\n", Channel, + Config.LoRaDevices[Channel].DIO0, + Config.LoRaDevices[Channel].DIO5 ); + + // Uplink + sprintf( Keyword, "UplinkTime_%d", Channel ); + Config.LoRaDevices[Channel].UplinkTime = ReadInteger( fp, Keyword, 0, 0 ); + sprintf( Keyword, "UplinkCycle_%d", Channel ); + Config.LoRaDevices[Channel].UplinkCycle = ReadInteger( fp, Keyword, 0, 0 ); + LogMessage( "Channel %d UplinkTime %d Uplink Cycle %d\n", Channel, + Config.LoRaDevices[Channel].UplinkTime, + Config.LoRaDevices[Channel].UplinkCycle ); + + sprintf( Keyword, "Power_%d", Channel ); + Config.LoRaDevices[Channel].Power = ReadInteger( fp, Keyword, 0, PA_MAX_UK ); + LogMessage( "Channel %d power set to %02Xh\n", Channel, Config.LoRaDevices[Channel].Power ); + + sprintf( Keyword, "UplinkMode_%d", Channel ); + Config.LoRaDevices[Channel].UplinkMode = ReadInteger( fp, Keyword, 0, -1); + if (Config.LoRaDevices[Channel].UplinkMode >= 0) + { + LogMessage( "Channel %d uplink mode %d\n", Channel, Config.LoRaDevices[Channel].UplinkMode); + } + + sprintf( Keyword, "UplinkFrequency_%d", Channel ); + Config.LoRaDevices[Channel].UplinkFrequency = 0; + Config.LoRaDevices[Channel].UplinkFrequency = ReadFloat(fp, Keyword); + if (Config.LoRaDevices[Channel].UplinkFrequency > 0) + { + LogMessage( "Channel %d uplink frequency %.3lfMHz\n", Channel, Config.LoRaDevices[Channel].UplinkFrequency); + } + + Config.LoRaDevices[Channel].SpeedMode = 0; + + sprintf( Keyword, "mode_%d", Channel ); + Config.LoRaDevices[Channel].SpeedMode = ReadInteger( fp, Keyword, 0, 0 ); + + if ((Config.LoRaDevices[Channel].SpeedMode < 0) || (Config.LoRaDevices[Channel].SpeedMode >= sizeof(LoRaModes)/sizeof(LoRaModes[0]))) Config.LoRaDevices[Channel].SpeedMode = 0; + + Config.LoRaDevices[Channel].ImplicitOrExplicit = LoRaModes[Config.LoRaDevices[Channel].SpeedMode].ImplicitOrExplicit; + Config.LoRaDevices[Channel].ErrorCoding = LoRaModes[Config.LoRaDevices[Channel].SpeedMode].ErrorCoding; + Config.LoRaDevices[Channel].Bandwidth = LoRaModes[Config.LoRaDevices[Channel].SpeedMode].Bandwidth; + Config.LoRaDevices[Channel].SpreadingFactor = LoRaModes[Config.LoRaDevices[Channel].SpeedMode].SpreadingFactor; + Config.LoRaDevices[Channel].LowDataRateOptimize = LoRaModes[Config.LoRaDevices[Channel].SpeedMode].LowDataRateOptimize; + + sprintf( Keyword, "sf_%d", Channel ); + Temp = ReadInteger( fp, Keyword, 0, 0 ); + if ( ( Temp >= 6 ) && ( Temp <= 12 ) ) + { + Config.LoRaDevices[Channel].SpreadingFactor = Temp << 4; + LogMessage( "Setting SF=%d\n", Temp ); + } + + sprintf( Keyword, "bandwidth_%d", Channel ); + ReadString( fp, Keyword, TempString, sizeof( TempString ), 0 ); + if ( *TempString ) + { + LogMessage( "Setting BW=%s\n", TempString ); + } + if ( strcmp( TempString, "7K8" ) == 0 ) + { + Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_7K8; + } + else if ( strcmp( TempString, "10K4" ) == 0 ) + { + Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_10K4; + } + else if ( strcmp( TempString, "15K6" ) == 0 ) + { + Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_15K6; + } + else if ( strcmp( TempString, "20K8" ) == 0 ) + { + Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_20K8; + } + else if ( strcmp( TempString, "31K25" ) == 0 ) + { + Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_31K25; + } + else if ( strcmp( TempString, "41K7" ) == 0 ) + { + Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_41K7; + } + else if ( strcmp( TempString, "62K5" ) == 0 ) + { + Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_62K5; + } + else if ( strcmp( TempString, "125K" ) == 0 ) + { + Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_125K; + } + else if ( strcmp( TempString, "250K" ) == 0 ) + { + Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_250K; + } + else if ( strcmp( TempString, "500K" ) == 0 ) + { + Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_500K; + } + + sprintf( Keyword, "implicit_%d", Channel ); + if ( ReadBoolean( fp, Keyword, 0, &Temp ) ) + { + Config.LoRaDevices[Channel].ImplicitOrExplicit = + Temp ? IMPLICIT_MODE : EXPLICIT_MODE; + } + + sprintf( Keyword, "coding_%d", Channel ); + Temp = ReadInteger( fp, Keyword, 0, 0 ); + if ( ( Temp >= 5 ) && ( Temp <= 8 ) ) + { + Config.LoRaDevices[Channel].ErrorCoding = ( Temp - 4 ) << 1; + LogMessage( "Setting Error Coding=%d\n", Temp ); + } + + sprintf( Keyword, "lowopt_%d", Channel ); + if ( ReadBoolean( fp, Keyword, 0, &Temp ) ) + { + if ( Temp ) + { + Config.LoRaDevices[Channel].LowDataRateOptimize = 0x08; + } + } + + sprintf( Keyword, "AFC_%d", Channel ); + if ( ReadBoolean( fp, Keyword, 0, &Temp ) ) + { + if ( Temp ) + { + Config.LoRaDevices[Channel].AFC = TRUE; + ChannelPrintf( Channel, 11, 24, "AFC" ); + } + } + + // Clear any flags left over from a previous run + writeRegister( Channel, REG_IRQ_FLAGS, 0xFF ); + } + } + + fclose( fp ); +} + +void +LoadPayloadFile( int ID ) +{ + FILE *fp; + char filename[16]; + + sprintf( filename, "payload_%d.txt", ID ); + + if ( ( fp = fopen( filename, "r" ) ) != NULL ) + { + LogMessage( "Reading payload file %s\n", filename ); + ReadString( fp, "payload", Payloads[ID].Payload, + sizeof( Payloads[ID].Payload ), 1 ); + LogMessage( "Payload %d = '%s'\n", ID, Payloads[ID].Payload ); + + Payloads[ID].InUse = 1; + + fclose( fp ); + } + else + { + strcpy( Payloads[ID].Payload, "Unknown" ); + Payloads[ID].InUse = 0; + } +} + +void +LoadPayloadFiles( void ) +{ + int ID; + + for ( ID = 0; ID < 16; ID++ ) + { + LoadPayloadFile( ID ); + } +} + +WINDOW * +InitDisplay( void ) +{ + WINDOW *mainwin; + int Channel; /* Initialize ncurses */ - if ( (mainwin = initscr()) == NULL ) { - fprintf(stderr, "Error initialising ncurses.\n"); - exit(EXIT_FAILURE); + if ( ( mainwin = initscr( ) ) == NULL ) + { + fprintf( stderr, "Error initialising ncurses.\n" ); + exit( EXIT_FAILURE ); } - start_color(); /* Initialize colours */ + start_color( ); /* Initialize colours */ - init_pair(1, COLOR_WHITE, COLOR_BLUE); - init_pair(2, COLOR_YELLOW, COLOR_BLUE); + if ( COLORS == 256 ) + { + init_pair( 1, COLOR_WHITE, 22 ); + init_pair( 2, COLOR_YELLOW, 22 ); + } + else + { + init_pair( 1, COLOR_WHITE, COLOR_BLUE ); + init_pair( 2, COLOR_YELLOW, COLOR_BLUE ); + } - color_set(1, NULL); - // bkgd(COLOR_PAIR(1)); - // attrset(COLOR_PAIR(1) | A_BOLD); + color_set( 1, NULL ); + // bkgd(COLOR_PAIR(1)); + // attrset(COLOR_PAIR(1) | A_BOLD); - // Title bar - mvaddstr(0, 17, " LoRa Habitat and SSDV Gateway " VERSION " by daveake "); - refresh(); + char title[80]; - // Windows for LoRa live data - for (Channel=0; Channel<=1; Channel++) - { - Config.LoRaDevices[Channel].Window = newwin(14, 38, 1, Channel ? 41 : 1); - wbkgd(Config.LoRaDevices[Channel].Window, COLOR_PAIR(2)); - - // wcolor_set(Config.LoRaDevices[Channel].Window, 2, NULL); - // waddstr(Config.LoRaDevices[Channel].Window, "WINDOW"); - // mvwaddstr(Config.LoRaDevices[Channel].Window, 0, 0, "Window"); - wrefresh(Config.LoRaDevices[Channel].Window); - } - - curs_set(0); - - return mainwin; -} + sprintf( title, "LoRa Habitat and SSDV Gateway by M0RPI - " VERSION); -void CloseDisplay(WINDOW * mainwin) + // Title bar + mvaddstr( 0, ( 80 - strlen( title ) ) / 2, title ); + refresh( ); + + // Windows for LoRa live data + for ( Channel = 0; Channel <= 1; Channel++ ) + { + Config.LoRaDevices[Channel].Window = + newwin( 14, 38, 1, Channel ? 41 : 1 ); + wbkgd( Config.LoRaDevices[Channel].Window, COLOR_PAIR( 2 ) ); + + // wcolor_set(Config.LoRaDevices[Channel].Window, 2, NULL); + // waddstr(Config.LoRaDevices[Channel].Window, "WINDOW"); + // mvwaddstr(Config.LoRaDevices[Channel].Window, 0, 0, "Window"); + wrefresh( Config.LoRaDevices[Channel].Window ); + } + + curs_set( 0 ); + + return mainwin; +} + +void +CloseDisplay( WINDOW * mainwin ) { /* Clean up after ourselves */ - delwin(mainwin); - endwin(); - refresh(); + delwin( mainwin ); + endwin( ); + refresh( ); } - -uint16_t CRC16(unsigned char *ptr) + +uint16_t +CRC16( unsigned char *ptr ) { - uint16_t CRC, xPolynomial; - int j; - - CRC = 0xffff; // Seed - xPolynomial = 0x1021; - - for (; *ptr; ptr++) - { // For speed, repeat calculation instead of looping for each bit - CRC ^= (((unsigned int)*ptr) << 8); - for (j=0; j<8; j++) + uint16_t CRC; + int j; + + CRC = 0xffff; // Seed + + for ( ; *ptr; ptr++ ) + { // For speed, repeat calculation instead of looping for each bit + CRC ^= ( ( ( unsigned int ) *ptr ) << 8 ); + for ( j = 0; j < 8; j++ ) { - if (CRC & 0x8000) - CRC = (CRC << 1) ^ 0x1021; + if ( CRC & 0x8000 ) + CRC = ( CRC << 1 ) ^ 0x1021; else CRC <<= 1; } } - - return CRC; + + return CRC; } -void ProcessKeyPress(int ch) +void +ProcessKeyPress( int ch ) { - int Channel = 0; + int Channel = 0; - /* shifted keys act on channel 1 */ - if (ch >= 'A' && ch <= 'Z') - { - Channel = 1; - /* change from upper to lower case */ - ch += ('a' - 'A'); - } + /* shifted keys act on channel 1 */ + if ( ch >= 'A' && ch <= 'Z' ) + { + Channel = 1; + /* change from upper to lower case */ + ch += ( 'a' - 'A' ); + } - if (ch == 'q') - { - run = FALSE; - return; - } + if ( ch == 'q' ) + { + run = FALSE; + return; + } - /* ignore if channel is not in use */ - if (!Config.LoRaDevices[Channel].InUse) - { - return; - } + /* ignore if channel is not in use */ + if ( !Config.LoRaDevices[Channel].InUse ) + { + return; + } - switch(ch) - { - case 'f': - Config.LoRaDevices[Channel].AFC = !Config.LoRaDevices[Channel].AFC; - ChannelPrintf(Channel, 11, 24, "%s", Config.LoRaDevices[Channel].AFC?"AFC":" "); - break; - case 'a': - ReTune(Channel, 0.1); - break; - case 'z': - ReTune(Channel, -0.1); - break; - case 's': - ReTune(Channel, 0.01); - break; - case 'x': - ReTune(Channel, -0.01); - break; - case 'd': - ReTune(Channel, 0.001); - break; - case 'c': - ReTune(Channel, -0.001); - break; - default: - //LogMessage("KeyPress %d\n", ch); - return; - } + switch ( ch ) + { + case 'f': + Config.LoRaDevices[Channel].AFC = + !Config.LoRaDevices[Channel].AFC; + ChannelPrintf( Channel, 11, 24, "%s", + Config.LoRaDevices[Channel].AFC ? "AFC" : " " ); + break; + case 'a': + ReTune( Channel, 0.1 ); + break; + case 'z': + ReTune( Channel, -0.1 ); + break; + case 's': + ReTune( Channel, 0.01 ); + break; + case 'x': + ReTune( Channel, -0.01 ); + break; + case 'd': + ReTune( Channel, 0.001 ); + break; + case 'c': + ReTune( Channel, -0.001 ); + break; + default: + //LogMessage("KeyPress %d\n", ch); + return; + } } -int prog_count(char* name) +int +prog_count( char *name ) { - DIR* dir; - struct dirent* ent; + DIR *dir; + struct dirent *ent; char buf[512]; - long pid; - char pname[100] = {0,}; + long pid; + char pname[100] = { 0, }; char state; - FILE *fp=NULL; - int Count=0; + FILE *fp = NULL; + int Count = 0; - if (!(dir = opendir("/proc"))) - { - perror("can't open /proc"); + if ( !( dir = opendir( "/proc" ) ) ) + { + perror( "can't open /proc" ); return 0; } - while((ent = readdir(dir)) != NULL) - { - long lpid = atol(ent->d_name); - if (lpid < 0) + while ( ( ent = readdir( dir ) ) != NULL ) + { + long lpid = atol( ent->d_name ); + if ( lpid < 0 ) continue; - snprintf(buf, sizeof(buf), "/proc/%ld/stat", lpid); - fp = fopen(buf, "r"); + snprintf( buf, sizeof( buf ), "/proc/%ld/stat", lpid ); + fp = fopen( buf, "r" ); - if (fp) - { - if ((fscanf(fp, "%ld (%[^)]) %c", &pid, pname, &state)) != 3 ) - { - printf("fscanf failed \n"); - fclose(fp); - closedir(dir); + if ( fp ) + { + if ( ( fscanf( fp, "%ld (%[^)]) %c", &pid, pname, &state ) ) != + 3 ) + { + printf( "fscanf failed \n" ); + fclose( fp ); + closedir( dir ); return 0; } - - if (!strcmp(pname, name)) - { + + if ( !strcmp( pname, name ) ) + { Count++; } - fclose(fp); + fclose( fp ); } } - closedir(dir); - - return Count; + closedir( dir ); + + return Count; } -int GetTextMessageToUpload(int Channel, char *Message) +int +GetTextMessageToUpload( int Channel, char *Message ) { - DIR *dp; - struct dirent *ep; - int Result; - - Result = 0; - - // LogMessage("Checking for SMS file ...\n"); - - if (Config.SMSFolder[0]) - { - dp = opendir (Config.SMSFolder); - if (dp != NULL) - { - while ((ep = readdir (dp)) && !Result) - { - if (strstr(ep->d_name, ".sms")) - { - FILE *fp; - char Line[256], FileName[256]; - int FileNumber; - - sprintf(FileName, "%s%s", Config.SMSFolder, ep->d_name); - sscanf(ep->d_name, "%d", &FileNumber); - - if ((fp = fopen(FileName, "rt")) != NULL) - { - if (fscanf(fp, "%[^\r]", Line)) - { - // #001,@daveake: Good Luck Tim !!\n - // @jonathenharty: RT @ProjectHeT: #astroPiTest The Essex Space Agency is looking forward to tweeting the real @esa! @GallarottiA: RT @ProjectHeT: #astroPiTest The Essex Space Agency is looking forward to tweeting the real @esa! - sprintf(Message, "#%d,%s\n", FileNumber, Line); + DIR *dp; + struct dirent *ep; + int Result; - LogMessage("UPLINK: %s", Message); - Result = 1; - } - else - { - LogMessage("FAIL\n"); - } - fclose(fp); - } - } - } - closedir(dp); - } - } - - return Result; + Result = 0; + + LogMessage("Checking for SMS file ...\n"); + + if ( Config.SMSFolder[0] ) + { + dp = opendir( Config.SMSFolder ); + if ( dp != NULL ) + { + while ( ( ep = readdir( dp ) ) && !Result ) + { + if ( strstr( ep->d_name, ".sms" ) ) + { + FILE *fp; + char Line[256], FileName[256]; + int FileNumber; + + sprintf( FileName, "%s%s", Config.SMSFolder, ep->d_name ); + sscanf( ep->d_name, "%d", &FileNumber ); + + if ( ( fp = fopen( FileName, "rt" ) ) != NULL ) + { + if ( fscanf( fp, "%[^\r]", Line ) ) + { + // #001,@daveake: Good Luck Tim !!\n + // @jonathenharty: RT @ProjectHeT: #astroPiTest The Essex Space Agency is looking forward to tweeting the real @esa! @GallarottiA: RT @ProjectHeT: #astroPiTest The Essex Space Agency is looking forward to tweeting the real @esa! + sprintf( Message, "#%d,%s\n", FileNumber, Line ); + + LogMessage( "UPLINK: %s", Message ); + Result = 1; + } + else + { + LogMessage( "FAIL\n" ); + } + fclose( fp ); + } + } + } + closedir( dp ); + } + } + + return Result; } -int GetExternalListOfMissingSSDVPackets(int Channel, char *Message) +int +GetExternalListOfMissingSSDVPackets( int Channel, char *Message ) { - // First, create request file - FILE *fp; - - // LogMessage("GetExternalListOfMissingSSDVPackets()\n"); - - // if ((fp = fopen("get_list.txt", "wt")) != NULL) - { - int i; - - // fprintf(fp, "No Message\n"); - // fclose(fp); - - // LogMessage("File created\n"); - - // Now wait for uplink.txt file to appear. - // Timeout before the end of our Tx slot if no file appears - - for (i=0; i<20; i++) - { - if (fp = fopen("uplink.txt", "r")) - { - Message[0] = '\0'; - fgets(Message, 256, fp); + // First, create request file + FILE *fp; - fclose(fp); - - LogMessage("Got uplink.txt %d bytes\n", strlen(Message)); - - // remove("get_list.txt"); - remove("uplink.txt"); - - return strlen(Message); - } + // LogMessage("GetExternalListOfMissingSSDVPackets()\n"); - usleep(100000); - } - - // LogMessage("Timed out waiting for file\n"); - // remove("get_list.txt"); - } + // if ((fp = fopen("get_list.txt", "wt")) != NULL) + { + int i; - return 0; + // fprintf(fp, "No Message\n"); + // fclose(fp); + + // LogMessage("File created\n"); + + // Now wait for uplink.txt file to appear. + // Timeout before the end of our Tx slot if no file appears + + for ( i = 0; i < 20; i++ ) + { + if ( ( fp = fopen( "uplink.txt", "r" ) ) ) + { + Message[0] = '\0'; + fgets( Message, 256, fp ); + + fclose( fp ); + + LogMessage( "Got uplink.txt %d bytes\n", strlen( Message ) ); + + // remove("get_list.txt"); + remove( "uplink.txt" ); + + return strlen( Message ); + } + + usleep( 100000 ); + } + + // LogMessage("Timed out waiting for file\n"); + // remove("get_list.txt"); + } + + return 0; } -/* -int BuildListOfMissingSSDVPackets(int Channel, char *Message) +void SendUplinkMessage( int Channel ) { - char Temp[10], *Comma; - int i, FirstMissing; - - Comma = ""; - FirstMissing = -1; - sprintf(Message, "!%d:%d=", Config.LoRaDevices[Channel].SSDVPackets[0].ImageNumber, Config.LoRaDevices[Channel].SSDVPackets[0].HighestPacket); - - for (i=0; i<=Config.LoRaDevices[Channel].SSDVPackets[0].HighestPacket; i++) - { - if ((Config.LoRaDevices[Channel].SSDVPackets[0].Packets[i]) || (i == Config.LoRaDevices[Channel].SSDVPackets[0].HighestPacket)) - { - // This packet present - if (FirstMissing >= 0) - { - if (i > (FirstMissing+1)) - { - // Group of adjacent missing packets - sprintf(Temp, "%s%d-%d", Comma, FirstMissing, i-1); - if ((strlen(Temp) + strlen(Message)) < 255) - { - strcat(Message, Temp); - Comma = ","; - } - } - else - { - // Missing packet is isolated - sprintf(Temp, "%s%d", Comma, FirstMissing); - if ((strlen(Temp) + strlen(Message)) < 255) - { - strcat(Message, Temp); - Comma = ","; - } - } - } - - FirstMissing = -1; - } - else - { - // This packet missing - // If previous packet also missing then extend the range - // Otherwise we need to start the range - if (FirstMissing < 0) - { - FirstMissing = i; - } - } - } - - if (*Comma) - { - strcat(Message, "\n"); - LogMessage("Uplink: %s", Message); - } - - return *Comma; -} -*/ + char Message[512]; -void SendUplinkMessage(int Channel) + // Decide what type of message we need to send + if ( GetTextMessageToUpload( Channel, Message ) ) + { + SendLoRaData( Channel, Message, 255 ); + } + else if ( GetExternalListOfMissingSSDVPackets( Channel, Message ) ) + { + SendLoRaData( Channel, Message, 255 ); + } +} + +void +rjh_post_message( int Channel, char *buffer ) { - char Message[512]; - - // Decide what type of message we need to send - if (GetTextMessageToUpload(Channel, Message)) - { - SendLoRaData(Channel, Message, 255); - } - else if (GetExternalListOfMissingSSDVPackets(Channel, Message)) - { - setFrequency(Channel, 869.5); - SetLoRaParameters(Channel, EXPLICIT_MODE, ERROR_CODING_4_8, BANDWIDTH_125K, SPREADING_8, 0); - SendLoRaData(Channel, Message, 255); - } + if ( Config.LoRaDevices[Channel].Sending ) + { + Config.LoRaDevices[Channel].Sending = 0; + // LogMessage("Ch%d: End of Tx\n", Channel); + + setLoRaMode( Channel ); + SetDefaultLoRaParameters( Channel ); + startReceiving( Channel ); + } + else + { + int Bytes; + char Message[257]; + + memcpy( Message + 1, buffer, 256 ); + + // hexdump_buffer ("RJH Raw Data", Message, 257); + + Bytes = strlen( buffer ); + + if ( Bytes > 0 ) + { + if ( Config.LoRaDevices[Channel].ActivityLED >= 0 ) + { + digitalWrite( Config.LoRaDevices[Channel].ActivityLED, 1 ); + LEDCounts[Channel] = 5; + } + + if ( Message[1] == '!' ) + { + ProcessUploadMessage( Channel, Message + 1 ); + } + else if ( Message[1] == '^' ) + { + ProcessCallingMessage( Channel, Message + 1 ); + } + else if ( Message[1] == '$' ) + { + //LogMessage("Ch %d: Uploaded message %s\n", Channel, Message+1); + ProcessTelemetryMessage( Channel, Message + 1 ); + } + else if ( Message[1] == '>' ) + { + LogMessage( "Flight Controller message %d bytes = %s", Bytes, + Message + 1 ); + } + else if ( Message[1] == '*' ) + { + LogMessage( "Uplink Command message %d bytes = %s", Bytes, + Message + 1 ); + } + else if ( Message[1] == 0x66 || Message[1] == 0x68 ) + { + ProcessSSDVMessage( Channel, Message ); + } + else + { + LogMessage( "Unknown packet type is %02Xh, RSSI %d\n", + Message[1], readRegister( Channel, + REG_PACKET_RSSI ) - + 157 ); + ChannelPrintf( Channel, 3, 1, "Unknown Packet %d, %d bytes", + Message[0], Bytes ); + Config.LoRaDevices[Channel].UnknownCount++; + } + + Config.LoRaDevices[Channel].LastPacketAt = time( NULL ); + + if ( Config.LoRaDevices[Channel].InCallingMode + && ( Config.CallingTimeout > 0 ) ) + { + Config.LoRaDevices[Channel].ReturnToCallingModeAt = + time( NULL ) + Config.CallingTimeout; + } + + ShowPacketCounts( Channel ); + } + } } -int main(int argc, char **argv) +int +main( int argc, char **argv ) { - unsigned char Command[200], Telemetry[100], *dest, *src; - int ch, i; - int LoopPeriod; - pthread_t SSDVThread, FTPThread, NetworkThread, HabitatThread, ServerThread; - WINDOW * mainwin; + int ch; + int LoopPeriod; + int Channel; + pthread_t SSDVThread, FTPThread, NetworkThread, HabitatThread, + ServerThread; + WINDOW *mainwin; + + if ( prog_count( "gateway" ) > 1 ) + { + printf( "\nThe gateway program is already running!\n\n" ); + exit( 1 ); + } - if (prog_count("gateway") > 1) + curl_global_init( CURL_GLOBAL_ALL ); // RJH thread safe + + mainwin = InitDisplay( ); + + // Settings for character input + noecho( ); + cbreak( ); + nodelay( stdscr, TRUE ); + keypad( stdscr, TRUE ); + + LEDCounts[0] = 0; + LEDCounts[1] = 0; + + // Remove any old SSDV files + // system("rm -f /tmp/*.bin"); + + LoadConfigFile(); + LoadPayloadFiles( ); + + int result; + + result = pipe( telem_pipe_fd ); + if ( result < 0 ) + { + fprintf( stderr, "Error creating telemetry pipe\n" ); + return 1; + } + + result = pipe( ssdv_pipe_fd ); + if ( result < 0 ) + { + fprintf( stderr, "Error creating ssdv pipe\n" ); + return 1; + } + + if ( wiringPiSetup( ) < 0 ) + { + fprintf( stderr, "Failed to open wiringPi\n" ); + exit( 1 ); + } + + if ( Config.LoRaDevices[0].ActivityLED >= 0 ) + pinMode( Config.LoRaDevices[0].ActivityLED, OUTPUT ); + if ( Config.LoRaDevices[1].ActivityLED >= 0 ) + pinMode( Config.LoRaDevices[1].ActivityLED, OUTPUT ); + if ( Config.InternetLED >= 0 ) + pinMode( Config.InternetLED, OUTPUT ); + if ( Config.NetworkLED >= 0 ) + pinMode( Config.NetworkLED, OUTPUT ); + + setupRFM98( 0 ); + setupRFM98( 1 ); + + ShowPacketCounts( 0 ); + ShowPacketCounts( 1 ); + + + LoopPeriod = 0; + + // Initialise the vars + stsv.parent_status = RUNNING; + stsv.packet_count = 0; + + if ( pthread_create( &SSDVThread, NULL, SSDVLoop, ( void * ) &stsv ) ) + { + fprintf( stderr, "Error creating SSDV thread\n" ); + return 1; + } + + if ( pthread_create( &FTPThread, NULL, FTPLoop, NULL ) ) + { + fprintf( stderr, "Error creating FTP thread\n" ); + return 1; + } + + + // Initialise the vars + htsv.parent_status = RUNNING; + htsv.packet_count = 0; + + + if ( pthread_create + ( &HabitatThread, NULL, HabitatLoop, ( void * ) &htsv ) ) + { + fprintf( stderr, "Error creating Habitat thread\n" ); + return 1; + } + + // RJH close (telem_pipe_fd[0]); // Close the read side of the pipe as we are writing here + + if ( Config.ServerPort > 0 ) + { + if ( pthread_create( &ServerThread, NULL, ServerLoop, NULL ) ) + { + fprintf( stderr, "Error creating server thread\n" ); + return 1; + } + } + + if ( ( Config.NetworkLED >= 0 ) && ( Config.InternetLED >= 0 ) ) + { + if ( pthread_create( &NetworkThread, NULL, NetworkLoop, NULL ) ) + { + fprintf( stderr, "Error creating Network thread\n" ); + return 1; + } + } + + if ( ( Config.latitude > -90 ) && ( Config.longitude > -90 ) ) + { + UploadListenerTelemetry( Config.Tracker, Config.latitude, + Config.longitude, Config.antenna ); + } + + char buffer[300]; + char ssdv_buff[257]; + int message_count = 0; + + char fileName[20] = "telem.txt"; + FILE *file_telem = fopen( fileName, "r" ); + + char fileName_ssdv[20] = "ssdv.bin"; + FILE *file_ssdv = fopen( fileName_ssdv, "rb" ); + + LogMessage( "Starting now ...\n" ); + + while ( run ) // && message_count< 9) // RJH Used for debug + { + if ( ( ch = getch( ) ) != ERR ) + { + ProcessKeyPress( ch ); + } + + /* RJH TEST */ + if ( message_count % 10 == 9 ) + { + if ( file_telem ) + { + if ( fgets( buffer, sizeof( buffer ), file_telem ) ) + { + rjh_post_message( 1, buffer ); + } + } + message_count++; // We need to increment this here or we will lock + } + else + { + if ( file_ssdv ) + { + if ( fread( ssdv_buff, 256, 1, file_ssdv ) ) + { + ssdv_buff[256] = '\0'; + rjh_post_message( 1, &ssdv_buff[1] ); + } + } + message_count++; // We need to increment this here or we will lock + } + + + /* RJH TEST */ + if ( LoopPeriod > 1000 ) + { + // Every 1 second + time_t now; + struct tm *tm; + + now = time( 0 ); + tm = localtime( &now ); + + LoopPeriod = 0; + + + for ( Channel = 0; Channel <= 1; Channel++ ) + { + if ( Config.LoRaDevices[Channel].InUse ) + { + + ShowPacketCounts( Channel ); + + ChannelPrintf( Channel, 12, 1, "Current RSSI = %4d ", + readRegister( Channel, + REG_CURRENT_RSSI ) - 157 ); + + // if (Config.LoRaDevices[Channel].LastPacketAt > 0) + // { + // ChannelPrintf(Channel, 6, 1, "%us since last packet ", (unsigned int)(time(NULL) - Config.LoRaDevices[Channel].LastPacketAt)); + // } + + if ( Config.LoRaDevices[Channel].InCallingMode + && ( Config.CallingTimeout > 0 ) + && ( Config. + LoRaDevices[Channel].ReturnToCallingModeAt > 0 ) + && ( time( NULL ) > + Config. + LoRaDevices[Channel].ReturnToCallingModeAt ) ) + { + Config.LoRaDevices[Channel].InCallingMode = 0; + Config.LoRaDevices[Channel].ReturnToCallingModeAt = 0; + + LogMessage( "Return to calling mode\n" ); + + setLoRaMode( Channel ); + + SetDefaultLoRaParameters( Channel ); + + setMode( Channel, RF98_MODE_RX_CONTINUOUS ); + + ChannelPrintf( Channel, 1, 1, + "Channel %d %sMHz %s mode", Channel, + Config.LoRaDevices[Channel].Frequency, + Modes[Config.LoRaDevices + [Channel].SpeedMode] ); + } + + if ( ( Config.LoRaDevices[Channel].UplinkTime > 0 ) + && ( Config.LoRaDevices[Channel].UplinkCycle > 0 ) ) + { + long CycleSeconds; + + + CycleSeconds = + ( tm->tm_hour * 3600 + tm->tm_min * 60 + + tm->tm_sec ) % + Config.LoRaDevices[Channel].UplinkCycle; + + if ( CycleSeconds == + Config.LoRaDevices[Channel].UplinkTime ) + { + // LogMessage("%02d:%02d:%02d - Time to send uplink message\n", tm->tm_hour, tm->tm_min, tm->tm_sec); + + SendUplinkMessage( Channel ); + } + } + + if ( LEDCounts[Channel] + && ( Config.LoRaDevices[Channel].ActivityLED >= 0 ) ) + { + if ( --LEDCounts[Channel] == 0 ) + { + digitalWrite( Config.LoRaDevices[Channel]. + ActivityLED, 0 ); + } + } + } + } + } + + delay( 10 ); + LoopPeriod += 10; + } + + LogMessage("Disabling DIO0 ISRs\n"); + for (Channel=0; Channel<2; Channel++) { - printf("\nThe gateway program is already running!\n\n"); - exit(1); - } - - curl_global_init(CURL_GLOBAL_ALL); // RJH thread safe - - mainwin = InitDisplay(); - - // Settings for character input - noecho(); - cbreak(); - nodelay(stdscr, TRUE); - keypad(stdscr, TRUE); - - Config.LoRaDevices[0].InUse = 0; - Config.LoRaDevices[1].InUse = 0; - - LEDCounts[0] = 0; - LEDCounts[1] = 0; - - // Remove any old SSDV files - // system("rm -f /tmp/*.bin"); - - // Default pin allocations - - Config.LoRaDevices[0].DIO0 = 6; - Config.LoRaDevices[0].DIO5 = 5; - - Config.LoRaDevices[1].DIO0 = 27; - Config.LoRaDevices[1].DIO5 = 26; - - LoadConfigFile(); - LoadPayloadFiles(); - - if (wiringPiSetup() < 0) - { - fprintf(stderr, "Failed to open wiringPi\n"); - exit(1); - } - - if (Config.LoRaDevices[0].ActivityLED >= 0) pinMode(Config.LoRaDevices[0].ActivityLED, OUTPUT); - if (Config.LoRaDevices[1].ActivityLED >= 0) pinMode(Config.LoRaDevices[1].ActivityLED, OUTPUT); - if (Config.InternetLED >= 0) pinMode(Config.InternetLED, OUTPUT); - if (Config.NetworkLED >= 0) pinMode(Config.NetworkLED, OUTPUT); - - setupRFM98(0); - setupRFM98(1); - - ShowPacketCounts(0); - ShowPacketCounts(1); - - LoopPeriod = 0; - - if (pthread_create(&SSDVThread, NULL, SSDVLoop, NULL)) - { - fprintf(stderr, "Error creating SSDV thread %d\n", i); - return 1; - } - - if (pthread_create(&FTPThread, NULL, FTPLoop, NULL)) - { - fprintf(stderr, "Error creating FTP thread\n"); - return 1; - } - - if (pthread_create(&HabitatThread, NULL, HabitatLoop, NULL)) - { - fprintf(stderr, "Error creating Habitat thread\n"); - return 1; - } - - if (Config.ServerPort > 0) - { - if (pthread_create(&ServerThread, NULL, ServerLoop, NULL)) + if (Config.LoRaDevices[Channel].InUse) { - fprintf(stderr, "Error creating server thread\n"); - return 1; + wiringPiISR(Config.LoRaDevices[Channel].DIO0, INT_EDGE_RISING, &DIO_Ignore_Interrupt_0); } } - if ((Config.NetworkLED >= 0) && (Config.InternetLED >= 0)) - { - if (pthread_create(&NetworkThread, NULL, NetworkLoop, NULL)) - { - fprintf(stderr, "Error creating Network thread\n"); - return 1; - } - } + LogMessage( "Closing SSDV pipe\n" ); + close( ssdv_pipe_fd[1] ); - if ((Config.latitude > -90) && (Config.longitude > -90)) - { - UploadListenerTelemetry(Config.Tracker, Config.latitude, Config.longitude, Config.antenna); - } + LogMessage( "Closing Habitat pipe\n" ); + close( telem_pipe_fd[1] ); - while (run) - { - if ((ch = getch()) != ERR) - { - ProcessKeyPress(ch); - } - - if (LoopPeriod > 1000) - { - // Every 1 second - int Channel; - time_t now; - struct tm *tm; + LogMessage( "Stopping SSDV thread\n" ); + stsv.parent_status = STOPPED; - now = time(0); - tm = localtime(&now); - - LoopPeriod = 0; - - for (Channel=0; Channel<=1; Channel++) - { - if (Config.LoRaDevices[Channel].InUse) - { - int8_t SNR; - - ShowPacketCounts(Channel); - - ChannelPrintf(Channel, 12, 1, "Current RSSI = %4d ", readRegister(Channel, REG_CURRENT_RSSI) - 157); - - // if (Config.LoRaDevices[Channel].LastPacketAt > 0) - // { - // ChannelPrintf(Channel, 6, 1, "%us since last packet ", (unsigned int)(time(NULL) - Config.LoRaDevices[Channel].LastPacketAt)); - // } - - if (Config.LoRaDevices[Channel].InCallingMode && (Config.CallingTimeout > 0) && (Config.LoRaDevices[Channel].ReturnToCallingModeAt > 0) && (time(NULL) > Config.LoRaDevices[Channel].ReturnToCallingModeAt)) - { - Config.LoRaDevices[Channel].InCallingMode = 0; - Config.LoRaDevices[Channel].ReturnToCallingModeAt = 0; - - LogMessage("Return to calling mode\n"); - - setLoRaMode(Channel); + LogMessage( "Stopping Habitat thread\n" ); + htsv.parent_status = STOPPED; + + LogMessage( "Waiting for SSDV thread to close ...\n" ); + pthread_join( SSDVThread, NULL ); + LogMessage( "SSDV thread closed\n" ); + + LogMessage( "Waiting for Habitat thread to close ...\n" ); + pthread_join( HabitatThread, NULL ); + LogMessage( "Habitat thread closed\n" ); + + pthread_mutex_destroy( &var ); + + // sleep (3); + + CloseDisplay( mainwin ); + curl_global_cleanup( ); // RJH thread safe + + if ( Config.NetworkLED >= 0 ) + digitalWrite( Config.NetworkLED, 0 ); + if ( Config.InternetLED >= 0 ) + digitalWrite( Config.InternetLED, 0 ); + if ( Config.LoRaDevices[0].ActivityLED >= 0 ) + digitalWrite( Config.LoRaDevices[0].ActivityLED, 0 ); + if ( Config.LoRaDevices[1].ActivityLED >= 0 ) + digitalWrite( Config.LoRaDevices[1].ActivityLED, 0 ); + + return 0; - SetDefaultLoRaParameters(Channel); - - setMode(Channel, RF98_MODE_RX_CONTINUOUS); - - ChannelPrintf(Channel, 1, 1, "Channel %d %sMHz %s mode", Channel, Config.LoRaDevices[Channel].Frequency, Modes[Config.LoRaDevices[Channel].SpeedMode]); - } - - if ((Config.LoRaDevices[Channel].UplinkTime > 0) && (Config.LoRaDevices[Channel].UplinkCycle > 0)) - { - long CycleSeconds; - - - CycleSeconds = (tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec) % Config.LoRaDevices[Channel].UplinkCycle; - - if (CycleSeconds == Config.LoRaDevices[Channel].UplinkTime) - { - // LogMessage("%02d:%02d:%02d - Time to send uplink message\n", tm->tm_hour, tm->tm_min, tm->tm_sec); - - SendUplinkMessage(Channel); - } - } - - if (LEDCounts[Channel] && (Config.LoRaDevices[Channel].ActivityLED >= 0)) - { - if (--LEDCounts[Channel] == 0) - { - digitalWrite(Config.LoRaDevices[Channel].ActivityLED, 0); - } - } - } - } - } - - delay(100); - LoopPeriod += 100; - } - - CloseDisplay(mainwin); - curl_global_cleanup(); // RJH thread safe - - if (Config.NetworkLED >= 0) digitalWrite(Config.NetworkLED, 0); - if (Config.InternetLED >= 0) digitalWrite(Config.InternetLED, 0); - if (Config.LoRaDevices[0].ActivityLED >= 0) digitalWrite(Config.LoRaDevices[0].ActivityLED, 0); - if (Config.LoRaDevices[1].ActivityLED >= 0) digitalWrite(Config.LoRaDevices[1].ActivityLED, 0); - - return 0; } - diff --git a/gateway.h b/gateway.h new file mode 100644 index 0000000..4b9d09d --- /dev/null +++ b/gateway.h @@ -0,0 +1,14 @@ +#ifndef _H_Gateway +#define _H_Gateway + +int receiveMessage( int Channel, char *message ); +void hexdump_buffer( const char *title, const char *buffer, + const int len_buffer ); +void LogPacket( int Channel, int8_t SNR, int RSSI, double FreqError, + int Bytes, unsigned char MessageType ); +void LogTelemetryPacket( char *Telemetry ); +void LogMessage( const char *format, ... ); +void ChannelPrintf( int Channel, int row, int column, const char *format, + ... ); + +#endif diff --git a/gateway.txt b/gateway.txt index c673b36..89fb8f0 100644 --- a/gateway.txt +++ b/gateway.txt @@ -1,4 +1,14 @@ + +##### Your details ##### + tracker=M0RPI/5 +Latitude=51.95023 +Longitude=-2.5445 +Antenna=Watso W-50 + + +##### Config Options ##### + EnableHabitat=Y EnableSSDV=Y JPGFolder=ssdv @@ -6,41 +16,40 @@ LogTelemetry=Y LogPackets=Y CallingTimeout=60 ServerPort=6004 -Latitude=51.95023 -Longitude=-2.5445 -Antenna=868MHz Yagi -#SMSFolder=./ -EnableDev=Y +SMSFolder=./ +EnableDev=N -#NetworkLED=21 -#InternetLED=22 -#ActivityLED_0=23 -#ActivityLED_1=24 +NetworkLED=22 +InternetLED=23 +ActivityLED_0=21 +ActivityLED_1=29 -frequency_0=869.860 -mode_0=3 -#implicit_0=1 -#coding_0=5 -#sf_0=6 +##### Config CE0 ##### -#frequency_0=869.500 -#mode_0= -#bandwidth_0=125K -#implicit_0=0 -#coding_0=5 -#sf_0=8 -#lowopt_0=0 -#power_0=255 +frequency_0=869.870 +mode_0=4 +AFC_0=N DIO0_0=31 DIO5_0=26 -AFC_0=N UplinkTime_0=2 UplinkCycle_0=60 +UplinkMode_0=6 +UplinkFrequency_0=869.490 +#Power_0=255 -frequency_1=434.455 -mode_1=2 + +##### Config CE1 ##### + +frequency_1=434.454 +mode_1=1 +AFC_1=N +#bandwidth_1=125K +#implicit_1=0 +#coding_1=5 +#sf_1=8 +#lowopt_1=0 +#power_1=255 DIO0_1=6 DIO5_1=5 -#AFC_1=Y #UplinkTime_1=5 #UplinkCycle_1=60 diff --git a/global.h b/global.h index 57613da..75cb1c1 100644 --- a/global.h +++ b/global.h @@ -1,103 +1,103 @@ #include -#define SSDV_PACKETS 64 +#define RUNNING 1 // The main program is running +#define STOPPED 0 // The main program has stopped + struct TSSDVPacket { + char Packet[256]; + char Callsign[7]; + }; + struct TSSDVPackets { + int ImageNumber; + int HighestPacket; + bool Packets[1024]; + }; + struct TLoRaDevice { + int InUse; + int DIO0; + int DIO5; + char Frequency[16]; + double activeFreq; + bool AFC; + int SpeedMode; + int Power; + int PayloadLength; + int ImplicitOrExplicit; + int ErrorCoding; + int Bandwidth; + int SpreadingFactor; + int LowDataRateOptimize; + int CurrentBandwidth; + WINDOW * Window; + unsigned int TelemetryCount, SSDVCount, BadCRCCount, UnknownCount; + int Sending; + char Telemetry[256]; + char Payload[16], Time[12]; + unsigned int Counter, LastCounter; + unsigned long Seconds; + double PredictedLongitude, PredictedLatitude; + double Longitude, Latitude; + unsigned int Altitude, PreviousAltitude; + unsigned int Satellites; + unsigned long LastPositionAt; + time_t LastPacketAt, LastSSDVPacketAt, LastTelemetryPacketAt; + float AscentRate; + time_t ReturnToCallingModeAt; + int InCallingMode; + int ActivityLED; -struct TSSDVPacket -{ - unsigned char Packet[256]; - char Callsign[7]; -}; +double UplinkFrequency; -struct TSSDVPacketArray -{ - struct TSSDVPacket Packets[SSDV_PACKETS]; - int Count; - int Sending; -}; - -struct TSSDVPackets -{ - int ImageNumber; - int HighestPacket; - bool Packets[1024]; -}; - -struct TLoRaDevice -{ - int InUse; - int DIO0; - int DIO5; - char Frequency[16]; - double activeFreq; - bool AFC; - int SpeedMode; - int Power; - int PayloadLength; - int ImplicitOrExplicit; - int ErrorCoding; - int Bandwidth; - int SpreadingFactor; - int LowDataRateOptimize; - int CurrentBandwidth; - - WINDOW *Window; - - unsigned int TelemetryCount, SSDVCount, BadCRCCount, UnknownCount; - - int Sending; - - char Telemetry[256]; - char Payload[16], Time[12]; - unsigned int Counter, LastCounter; - unsigned long Seconds; - double PredictedLongitude, PredictedLatitude; - double Longitude, Latitude; - unsigned int Altitude, PreviousAltitude; - unsigned int Satellites; - unsigned long LastPositionAt; - time_t LastPacketAt, LastSSDVPacketAt, LastTelemetryPacketAt; - float AscentRate; - time_t ReturnToCallingModeAt; - int InCallingMode; - int ActivityLED; - - int Speed, Heading, PredictedTime, CompassActual, CompassTarget, AirDirection, ServoLeft, ServoRight, ServoTime, FlightMode; - double cda, PredictedLandingSpeed, AirSpeed, GlideRatio; - - // Normal (non TDM) uplink - int UplinkTime; - int UplinkCycle; - - // SSDV Packet Log - struct TSSDVPackets SSDVPackets[3]; -}; - -struct TConfig -{ - char Tracker[16]; - int EnableHabitat; - int EnableSSDV; - int EnableTelemetryLogging; - int EnablePacketLogging; - int CallingTimeout; - char SSDVJpegFolder[100]; - char ftpServer[100]; - char ftpUser[32]; - char ftpPassword[32]; - char ftpFolder[64]; - struct TLoRaDevice LoRaDevices[2]; - int NetworkLED; - int InternetLED; - int ServerPort; - float latitude, longitude; - char SMSFolder[64]; - char antenna[64]; - int EnableDev; -}; - -extern struct TConfig Config; -extern struct TSSDVPacketArray SSDVPacketArrays[]; -extern int SSDVSendArrayIndex; -extern pthread_mutex_t ssdv_mutex; - -void LogMessage(const char *format, ...); \ No newline at end of file +int UplinkMode; + int Speed, Heading, PredictedTime, CompassActual, CompassTarget, + AirDirection, ServoLeft, ServoRight, ServoTime, FlightMode; + double cda, PredictedLandingSpeed, AirSpeed, GlideRatio; + + // Normal (non TDM) uplink + int UplinkTime; + int UplinkCycle; + + // SSDV Packet Log + struct TSSDVPackets SSDVPackets[3]; + }; + struct TConfig { + char Tracker[16]; + int EnableHabitat; + int EnableSSDV; + int EnableTelemetryLogging; + int EnablePacketLogging; + int CallingTimeout; + char SSDVJpegFolder[100]; + char ftpServer[100]; + char ftpUser[32]; + char ftpPassword[32]; + char ftpFolder[64]; + struct TLoRaDevice LoRaDevices[2]; + int NetworkLED; + int InternetLED; + int ServerPort; + float latitude, longitude; + char SMSFolder[64]; + char antenna[64]; + int EnableDev; + }; + typedef struct { + int parent_status; + unsigned long packet_count; +} thread_shared_vars_t; + +typedef struct { + short int Channel; + char Telemetry[257]; + int Packet_Number; +} telemetry_t; + +typedef struct { + short int Channel; + char SSDV_Packet[257]; + int Packet_Number; +} ssdv_t; + +extern struct TConfig Config; + extern int SSDVSendArrayIndex; + extern pthread_mutex_t ssdv_mutex; + void LogMessage( const char *format, ... ); diff --git a/habitat.c b/habitat.c index ed51447..e3874c1 100644 --- a/habitat.c +++ b/habitat.c @@ -2,175 +2,228 @@ #include #include #include -#include // Standard input/output definitions -#include // String function definitions -#include // UNIX standard function definitions -#include // File control definitions -#include // Error number definitions -#include // POSIX terminal control definitions +#include // Standard input/output definitions +#include // String function definitions +#include // UNIX standard function definitions +#include // File control definitions +#include // Error number definitions +#include // POSIX terminal control definitions #include #include #include #include #include -#include #include #include +#include #include "base64.h" #include "habitat.h" #include "global.h" #include "sha256.h" +#include "wiringPi.h" +#include "gateway.h" +extern int telem_pipe_fd[2]; +extern pthread_mutex_t var; +extern void ChannelPrintf( int Channel, int row, int column, + const char *format, ... ); -extern void ChannelPrintf(int Channel, int row, int column, const char *format, ...); - -size_t habitat_write_data(void *buffer, size_t size, size_t nmemb, void *userp) +size_t +habitat_write_data( void *buffer, size_t size, size_t nmemb, void *userp ) { - // LogMessage("%s\n", (char *)buffer); - return size * nmemb; + // LogMessage("%s\n", (char *)buffer); + return size * nmemb; } -void hash_to_hex(unsigned char *hash, char *line) +void +hash_to_hex( unsigned char *hash, char *line ) { - int idx; + int idx; - for (idx=0; idx < 32; idx++) - { - sprintf(&(line[idx*2]), "%02x", hash[idx]); - } - line[64] = '\0'; - - // LogMessage(line); -} - -void UploadTelemetryPacket(int Channel) -{ - CURL *curl; - CURLcode res; - - /* In windows, this will init the winsock stuff */ - // curl_global_init(CURL_GLOBAL_ALL); // RJH moved to main in gateway.c not thread safe - - /* get a curl handle */ - curl = curl_easy_init(); - if (curl) - { - char url[200]; - char base64_data[1000]; - size_t base64_length; - SHA256_CTX ctx; - unsigned char hash[32]; - char doc_id[100]; - char json[1000], now[32]; - char PostFields[400], Sentence[512]; - struct curl_slist *headers = NULL; - time_t rawtime; - struct tm *tm; - - // Get formatted timestamp - time(&rawtime); - tm = gmtime(&rawtime); - strftime(now, sizeof(now), "%Y-%0m-%0dT%H:%M:%SZ", tm); - - // So that the response to the curl PUT doesn't mess up my finely crafted display! - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, habitat_write_data); - - // Set the timeout - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5); - - // RJH capture http errors and report - curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); - - // Avoid curl library bug that happens if above timeout occurs (sigh) - curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); - - // Grab current telemetry string and append a linefeed - sprintf(Sentence, "%s\n", Config.LoRaDevices[Channel].Telemetry); - - // Convert sentence to base64 - base64_encode(Sentence, strlen(Sentence), &base64_length, base64_data); - base64_data[base64_length] = '\0'; - - // Take SHA256 hash of the base64 version and express as hex. This will be the document ID - sha256_init(&ctx); - sha256_update(&ctx, base64_data, base64_length); - sha256_final(&ctx, hash); - hash_to_hex(hash, doc_id); - - // Create json with the base64 data in hex, the tracker callsign and the current timestamp - sprintf(json, - "{\"data\": {\"_raw\": \"%s\"},\"receivers\": {\"%s\": {\"time_created\": \"%s\",\"time_uploaded\": \"%s\"}}}", - base64_data, - Config.Tracker, - now, - now); - - // Set the URL that is about to receive our PUT - sprintf(url, "http://habitat.habhub.org/habitat/_design/payload_telemetry/_update/add_listener/%s", doc_id); - - // Set the headers - headers = NULL; - headers = curl_slist_append(headers, "Accept: application/json"); - headers = curl_slist_append(headers, "Content-Type: application/json"); - headers = curl_slist_append(headers, "charsets: utf-8"); - - // PUT to http://habitat.habhub.org/habitat/_design/payload_telemetry/_update/add_listener/ with content-type application/json - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl, CURLOPT_URL, url); - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json); - - // LogMessage("%s\n", Config.LoRaDevices[Channel].Telemetry); - - // Perform the request, res will get the return code - res = curl_easy_perform(curl); - - // Check for errors - if (res == CURLE_OK) - { - // LogMessage("OK\n"); - } - else - { - LogMessage("curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); - } - - // always cleanup - curl_slist_free_all(headers); - curl_easy_cleanup(curl); - // free(base64_data); - } - - // curl_global_cleanup(); // RJH moved to main in gateway.c not thread safe -} - - -void *HabitatLoop(void *some_void_ptr) -{ - while (1) + for ( idx = 0; idx < 32; idx++ ) { - if (Config.EnableHabitat) - { - int Channel; - - for (Channel=0; Channel<=1; Channel++) - { - if (Config.LoRaDevices[Channel].Counter != Config.LoRaDevices[Channel].LastCounter) - { - ChannelPrintf(Channel, 6, 1, "Habitat"); - - UploadTelemetryPacket(Channel); - - Config.LoRaDevices[Channel].LastCounter = Config.LoRaDevices[Channel].Counter; + sprintf( &( line[idx * 2] ), "%02x", hash[idx] ); + } + line[64] = '\0'; - delay(100); - - ChannelPrintf(Channel, 6, 1, " "); - } - } - } - - delay(100); - } + // LogMessage(line); +} + +void +UploadTelemetryPacket( telemetry_t * t ) +{ + CURL *curl; + CURLcode res; + char curl_error[CURL_ERROR_SIZE]; + + /* get a curl handle */ + curl = curl_easy_init( ); + if ( curl ) + { + char url[200]; + char base64_data[1000]; + size_t base64_length; + SHA256_CTX ctx; + unsigned char hash[32]; + char doc_id[100]; + char json[1000], now[32]; + char Sentence[512]; + struct curl_slist *headers = NULL; + time_t rawtime; + struct tm *tm; + + // Get formatted timestamp + time( &rawtime ); + tm = gmtime( &rawtime ); + strftime( now, sizeof( now ), "%Y-%0m-%0dT%H:%M:%SZ", tm ); + + // So that the response to the curl PUT doesn't mess up my finely crafted display! + curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, habitat_write_data ); + + // Set the timeout + curl_easy_setopt( curl, CURLOPT_TIMEOUT, 15 ); + + // RJH capture http errors and report + curl_easy_setopt( curl, CURLOPT_FAILONERROR, 1 ); + curl_easy_setopt( curl, CURLOPT_ERRORBUFFER, curl_error ); + + // Avoid curl library bug that happens if above timeout occurs (sigh) + curl_easy_setopt( curl, CURLOPT_NOSIGNAL, 1 ); + + // Grab current telemetry string and append a linefeed + sprintf( Sentence, "%s\n", t->Telemetry ); + + // Convert sentence to base64 + base64_encode( Sentence, strlen( Sentence ), &base64_length, + base64_data ); + base64_data[base64_length] = '\0'; + + // Take SHA256 hash of the base64 version and express as hex. This will be the document ID + sha256_init( &ctx ); + sha256_update( &ctx, base64_data, base64_length ); + sha256_final( &ctx, hash ); + hash_to_hex( hash, doc_id ); + + char counter[10]; + sprintf( counter, "%d", t->Packet_Number ); + + // Create json with the base64 data in hex, the tracker callsign and the current timestamp + sprintf( json, + "{\"data\": {\"_raw\": \"%s\"},\"receivers\": {\"%s\": {\"time_created\": \"%s\",\"time_uploaded\": \"%s\"}}}", + base64_data, Config.Tracker, now, now ); + + // LogTelemetryPacket(json); + + + // Set the URL that is about to receive our PUT + sprintf( url, + "http://habitat.habhub.org/habitat/_design/payload_telemetry/_update/add_listener/%s", + doc_id ); +// sprintf(url, "http://ext.hgf.com/ssdv/rjh.php"); + + // Set the headers + headers = NULL; + headers = curl_slist_append( headers, "Accept: application/json" ); + headers = + curl_slist_append( headers, "Content-Type: application/json" ); + headers = curl_slist_append( headers, "charsets: utf-8" ); + + // PUT to http://habitat.habhub.org/habitat/_design/payload_telemetry/_update/add_listener/ with content-type application/json + curl_easy_setopt( curl, CURLOPT_HTTPHEADER, headers ); + curl_easy_setopt( curl, CURLOPT_URL, url ); + curl_easy_setopt( curl, CURLOPT_CUSTOMREQUEST, "PUT" ); + curl_easy_setopt( curl, CURLOPT_POSTFIELDS, json ); + + // Perform the request, res will get the return code + res = curl_easy_perform( curl ); + + // Check for errors + if ( res == CURLE_OK ) + { + // LogMessage("OK\n"); + } + else + { + LogMessage( "Failed for URL '%s'\n", url ); + LogMessage( "curl_easy_perform() failed: %s\n", + curl_easy_strerror( res ) ); + LogMessage( "error: %s\n", curl_error ); + } + + // always cleanup + curl_slist_free_all( headers ); + curl_easy_cleanup( curl ); + // free(base64_data); + } + +} + + +void * +HabitatLoop( void *vars ) +{ + + if ( Config.EnableHabitat ) + { + thread_shared_vars_t *htsv; + htsv = vars; + telemetry_t t; + int packets = 0; + unsigned long total_packets = 0; + + int i = 1; + + // Keep looping until the parent quits and there are no more packets to + // send to habitat. + while ( ( htsv->parent_status == RUNNING ) || ( packets > 0 ) ) + { + + //THis is neded for some reason habitat thread has a pthread_mutex_lock set + // and this removes it + if ( i ) + { + // pthread_mutex_lock(&var); + pthread_mutex_unlock( &var ); + i = 0; + } + if ( htsv->packet_count > total_packets ) + { + packets = read( telem_pipe_fd[0], &t, sizeof( t ) ); + } + else + { + packets = 0; + // pthread_mutex_unlock(&var); + + // If we have have a rollover after processing 4294967295 packets + if ( htsv->packet_count < total_packets ) + total_packets = 0; + + } + + if ( packets ) + { + // LogMessage ("%s\n", t.Telemetry); + + ChannelPrintf( t.Channel, 6, 1, "Habitat" ); + + LogTelemetryPacket( t.Telemetry ); + + UploadTelemetryPacket( &t ); + + ChannelPrintf( t.Channel, 6, 1, " " ); + + total_packets++; + + } + } + } + + close( telem_pipe_fd[0] ); + close( telem_pipe_fd[1] ); + + LogMessage( "Habitat thread closing\n" ); + + return NULL; } diff --git a/habitat.h b/habitat.h index a0048ff..febfc3a 100644 --- a/habitat.h +++ b/habitat.h @@ -1 +1 @@ -void *HabitatLoop(void *some_void_ptr); \ No newline at end of file +void *HabitatLoop( void *some_void_ptr ); diff --git a/makefile b/makefile deleted file mode 100644 index 2c7404c..0000000 --- a/makefile +++ /dev/null @@ -1,30 +0,0 @@ -gateway: gateway.o urlencode.o base64.o sha256.o habitat.o ssdv.o ftp.o network.o server.o - cc -o gateway gateway.o urlencode.o base64.o sha256.o habitat.o ssdv.o ftp.o network.o server.o -lm -lwiringPi -lwiringPiDev -lcurl -lncurses -lpthread - -gateway.o: gateway.c global.h - gcc -c gateway.c - -habitat.o: habitat.c habitat.h global.h - gcc -c habitat.c - -ssdv.o: ssdv.c ssdv.h global.h - gcc -c ssdv.c - -ftp.o: ftp.c ftp.h global.h - gcc -c ftp.c - -server.o: server.c server.h global.h - gcc -c server.c - -network.o: network.c network.h global.h - gcc -c network.c - -urlencode.o: urlencode.c - gcc -c urlencode.c - -base64.o: base64.c - gcc -c base64.c - -sha256.o: sha256.c - gcc -c sha256.c - diff --git a/network.c b/network.c index 4095a95..36d483c 100644 --- a/network.c +++ b/network.c @@ -2,12 +2,12 @@ #include #include #include -#include // Standard input/output definitions -#include // String function definitions -#include // UNIX standard function definitions -#include // File control definitions -#include // Error number definitions -#include // POSIX terminal control definitions +#include // Standard input/output definitions +#include // String function definitions +#include // UNIX standard function definitions +#include // File control definitions +#include // Error number definitions +#include // POSIX terminal control definitions #include #include #include @@ -18,99 +18,103 @@ #include #include #include +#include // Include WiringPi library! #include "network.h" #include "global.h" -int HaveAnIPAddress(void) +int +HaveAnIPAddress( void ) { struct ifaddrs *ifap, *ifa; struct sockaddr_in *sa; char *addr; - int FoundAddress; + int FoundAddress; - FoundAddress = 0; - - if (getifaddrs(&ifap) == 0) - { - // Success - for (ifa = ifap; ifa; ifa = ifa->ifa_next) - { - if (ifa->ifa_addr != NULL) - { - // Family is known (which it isn't for a VPN) - if (ifa->ifa_addr->sa_family==AF_INET) - { - sa = (struct sockaddr_in *) ifa->ifa_addr; - addr = inet_ntoa(sa->sin_addr); - if (strcmp(addr, "127.0.0.1") != 0) - { - FoundAddress = 1; - } - } - } + FoundAddress = 0; + + if ( getifaddrs( &ifap ) == 0 ) + { + // Success + for ( ifa = ifap; ifa; ifa = ifa->ifa_next ) + { + if ( ifa->ifa_addr != NULL ) + { + // Family is known (which it isn't for a VPN) + if ( ifa->ifa_addr->sa_family == AF_INET ) + { + sa = ( struct sockaddr_in * ) ifa->ifa_addr; + addr = inet_ntoa( sa->sin_addr ); + if ( strcmp( addr, "127.0.0.1" ) != 0 ) + { + FoundAddress = 1; + } + } + } } } - freeifaddrs(ifap); - - return FoundAddress; + freeifaddrs( ifap ); + + return FoundAddress; } -int CanSeeTheInternet(void) +int +CanSeeTheInternet( void ) { - struct addrinfo hints, *res, *p; - int status, sockfd, FoundInternet; - - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version - hints.ai_socktype = SOCK_STREAM; + struct addrinfo hints, *res; + int status, sockfd, FoundInternet; - if ((status = getaddrinfo("google.com", "80", &hints, &res)) != 0) - { - return 0; - } + memset( &hints, 0, sizeof hints ); + hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version + hints.ai_socktype = SOCK_STREAM; - sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - - FoundInternet = 1; - if(connect(sockfd, res->ai_addr, res->ai_addrlen) == -1) - { - FoundInternet = 0; - } - - close(sockfd); - - freeaddrinfo(res); // free the linked list - - return FoundInternet; -} - -void *NetworkLoop(void *some_void_ptr) -{ - while (1) + if ( ( status = getaddrinfo( "google.com", "80", &hints, &res ) ) != 0 ) { - digitalWrite(Config.NetworkLED, 0); - digitalWrite(Config.InternetLED, 0); - if (HaveAnIPAddress()) - { - digitalWrite(Config.NetworkLED, 1); -// LogMessage("On network :-)\n"); - - if (CanSeeTheInternet()) - { - digitalWrite(Config.InternetLED, 1); -// LogMessage("On the internet :-)\n"); - } - else - { -// LogMessage("Not on internet :-(\n"); - } - } - else - { -// LogMessage("No network :-(\n"); - } - - sleep(5); - } + return 0; + } + + sockfd = socket( res->ai_family, res->ai_socktype, res->ai_protocol ); + + FoundInternet = 1; + if ( connect( sockfd, res->ai_addr, res->ai_addrlen ) == -1 ) + { + FoundInternet = 0; + } + + close( sockfd ); + + freeaddrinfo( res ); // free the linked list + + return FoundInternet; +} + +void * +NetworkLoop( void *some_void_ptr ) +{ + while ( 1 ) + { + if ( HaveAnIPAddress( ) ) + { + digitalWrite( Config.NetworkLED, 1 ); +// LogMessage("On network :-)\n"); + + if ( CanSeeTheInternet( ) ) + { + digitalWrite( Config.InternetLED, 1 ); +// LogMessage("On the internet :-)\n"); + } + else + { + digitalWrite( Config.InternetLED, 0 ); +// LogMessage("Not on internet :-(\n"); + } + } + else + { + digitalWrite( Config.NetworkLED, 0 ); +// LogMessage("No network :-(\n"); + } + + sleep( 5 ); + } } diff --git a/network.h b/network.h index d2df8d6..4da403a 100644 --- a/network.h +++ b/network.h @@ -1 +1 @@ -void *NetworkLoop(void *some_void_ptr); \ No newline at end of file +void *NetworkLoop( void *some_void_ptr ); diff --git a/server.c b/server.c index 0ce5f3c..4461d8d 100644 --- a/server.c +++ b/server.c @@ -2,12 +2,12 @@ #include #include #include -#include // Standard input/output definitions -#include // String function definitions -#include // UNIX standard function definitions -#include // File control definitions -#include // Error number definitions -#include // POSIX terminal control definitions +#include // Standard input/output definitions +#include // String function definitions +#include // UNIX standard function definitions +#include // File control definitions +#include // Error number definitions +#include // POSIX terminal control definitions #include #include #include @@ -23,83 +23,89 @@ extern bool run; extern bool server_closed; -void *ServerLoop(void *some_void_ptr) +void *ServerLoop( void *some_void_ptr ) { int listenfd = 0, connfd = 0; - struct sockaddr_in serv_addr; + struct sockaddr_in serv_addr; char sendBuff[1025]; - time_t ticks; - listenfd = socket(AF_INET, SOCK_STREAM, 0); - memset(&serv_addr, '0', sizeof(serv_addr)); - memset(sendBuff, '0', sizeof(sendBuff)); + listenfd = socket( AF_INET, SOCK_STREAM, 0 ); + memset( &serv_addr, '0', sizeof( serv_addr ) ); + memset( sendBuff, '0', sizeof( sendBuff ) ); serv_addr.sin_family = AF_INET; - serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); - serv_addr.sin_port = htons(Config.ServerPort); - - LogMessage("Listening on port %d\n", Config.ServerPort); + serv_addr.sin_addr.s_addr = htonl( INADDR_ANY ); + serv_addr.sin_port = htons( Config.ServerPort ); - if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)) < 0) + LogMessage( "Listening on port %d\n", Config.ServerPort ); + + if ( setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR, &( int ) + { + 1}, sizeof( int ) ) < 0 ) { - LogMessage("setsockopt(SO_REUSEADDR) failed"); - } - - if (bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) - { - LogMessage("Server failed errno %d\n", errno); - return; - } + LogMessage( "setsockopt(SO_REUSEADDR) failed" ); + } - listen(listenfd, 10); - - while (run) + if ( bind + ( listenfd, ( struct sockaddr * ) &serv_addr, + sizeof( serv_addr ) ) < 0 ) { - int port_closed; - - connfd = accept(listenfd, (struct sockaddr*)NULL, NULL); + LogMessage( "Server failed errno %d\n", errno ); + exit( -1 ); + } - LogMessage("Connected to client\n"); + listen( listenfd, 10 ); - for (port_closed=0; !port_closed; ) - { - int Channel; - // Build json - // sprintf(sendBuff, "{\"class\":\"POSN\",\"time\":\"12:34:56\",\"lat\":54.12345,\"lon\":-2.12345,\"alt\":169}\r\n"); - - Channel = 1; - if (Config.EnableDev) + while ( run ) + { + int port_closed; + + connfd = accept( listenfd, ( struct sockaddr * ) NULL, NULL ); + + LogMessage( "Connected to client\n" ); + + for ( port_closed = 0; !port_closed; ) + { + int Channel; + // Build json + // sprintf(sendBuff, "{\"class\":\"POSN\",\"time\":\"12:34:56\",\"lat\":54.12345,\"lon\":-2.12345,\"alt\":169}\r\n"); + + for (Channel=0; Channel<=1; Channel++) { - sprintf(sendBuff, "{\"class\":\"POSN\",\"payload\":\"%s\",\"time\":\"%s\",\"lat\":%.5lf,\"lon\":%.5lf,\"alt\":%d,\"predlat\":%.5lf,\"predlon\":%.5lf,\"speed\":%d," - "\"head\":%d,\"cda\":%.2lf,\"pls\":%.1lf,\"pt\":%d,\"ca\":%d,\"ct\":%d,\"as\":%.1lf,\"ad\":%d,\"sl\":%d,\"sr\":%d,\"st\":%d,\"gr\":%.2lf,\"fm\":%d}\r\n", - Config.LoRaDevices[Channel].Payload, - Config.LoRaDevices[Channel].Time, - Config.LoRaDevices[Channel].Latitude, - Config.LoRaDevices[Channel].Longitude, - Config.LoRaDevices[Channel].Altitude, - Config.LoRaDevices[Channel].PredictedLatitude, - Config.LoRaDevices[Channel].PredictedLongitude, - Config.LoRaDevices[Channel].Speed, - - Config.LoRaDevices[Channel].Heading, - Config.LoRaDevices[Channel].cda, - Config.LoRaDevices[Channel].PredictedLandingSpeed, - Config.LoRaDevices[Channel].PredictedTime, - Config.LoRaDevices[Channel].CompassActual, - Config.LoRaDevices[Channel].CompassTarget, - Config.LoRaDevices[Channel].AirSpeed, - Config.LoRaDevices[Channel].AirDirection, - Config.LoRaDevices[Channel].ServoLeft, - Config.LoRaDevices[Channel].ServoRight, - Config.LoRaDevices[Channel].ServoTime, - Config.LoRaDevices[Channel].GlideRatio, - Config.LoRaDevices[Channel].FlightMode); + if ( Config.EnableDev ) + { + sprintf(sendBuff, "{\"class\":\"POSN\",\"index\":%d,\"payload\":\"%s\",\"time\":\"%s\",\"lat\":%.5lf,\"lon\":%.5lf,\"alt\":%d,\"rate\":%.1lf,\"predlat\":%.5lf,\"predlon\":%.5lf,\"speed\":%d," + "\"head\":%d,\"cda\":%.2lf,\"pls\":%.1lf,\"pt\":%d,\"ca\":%d,\"ct\":%d,\"as\":%.1lf,\"ad\":%d,\"sl\":%d,\"sr\":%d,\"st\":%d,\"gr\":%.2lf,\"fm\":%d}\r\n", + Channel, + Config.LoRaDevices[Channel].Payload, + Config.LoRaDevices[Channel].Time, + Config.LoRaDevices[Channel].Latitude, + Config.LoRaDevices[Channel].Longitude, + Config.LoRaDevices[Channel].Altitude, + Config.LoRaDevices[Channel].AscentRate, + Config.LoRaDevices[Channel].PredictedLatitude, + Config.LoRaDevices[Channel].PredictedLongitude, + Config.LoRaDevices[Channel].Speed, + + Config.LoRaDevices[Channel].Heading, + Config.LoRaDevices[Channel].cda, + Config.LoRaDevices[Channel].PredictedLandingSpeed, + Config.LoRaDevices[Channel].PredictedTime, + Config.LoRaDevices[Channel].CompassActual, + Config.LoRaDevices[Channel].CompassTarget, + Config.LoRaDevices[Channel].AirSpeed, + Config.LoRaDevices[Channel].AirDirection, + Config.LoRaDevices[Channel].ServoLeft, + Config.LoRaDevices[Channel].ServoRight, + Config.LoRaDevices[Channel].ServoTime, + Config.LoRaDevices[Channel].GlideRatio, + Config.LoRaDevices[Channel].FlightMode); } else { - sprintf(sendBuff, "{\"class\":\"POSN\",\"payload\":\"%s\",\"time\":\"%s\",\"lat\":%.5lf,\"lon\":%.5lf,\"alt\":%d,\"rate\":%.1lf}\r\n", - + sprintf(sendBuff, "{\"class\":\"POSN\",\"index\":%d,\"payload\":\"%s\",\"time\":\"%s\",\"lat\":%.5lf,\"lon\":%.5lf,\"alt\":%d,\"rate\":%.1lf}\r\n", + Channel, Config.LoRaDevices[Channel].Payload, Config.LoRaDevices[Channel].Time, Config.LoRaDevices[Channel].Latitude, @@ -107,23 +113,25 @@ void *ServerLoop(void *some_void_ptr) Config.LoRaDevices[Channel].Altitude, Config.LoRaDevices[Channel].AscentRate); } - - if (!run) - { - port_closed = 1; - } - else if (send(connfd, sendBuff, strlen(sendBuff), MSG_NOSIGNAL) <= 0) - { - LogMessage("Disconnected from client\n"); - port_closed = 1; - } - else - { - sleep(1); - } - } - - close(connfd); - } -} \ No newline at end of file + if ( !run ) + { + port_closed = 1; + } + else if ( send(connfd, sendBuff, strlen(sendBuff), MSG_NOSIGNAL ) <= 0 ) + { + LogMessage( "Disconnected from client\n" ); + port_closed = 1; + } + else + { + sleep(1); + } + } + } + + close( connfd ); + } + + return NULL; +} diff --git a/server.h b/server.h index f828e2b..44d908e 100644 --- a/server.h +++ b/server.h @@ -1 +1,2 @@ -void *ServerLoop(void *some_void_ptr); +void *ServerLoop( void *some_void_ptr ); + diff --git a/sha256.c b/sha256.c old mode 100755 new mode 100644 index aac9bf3..3790b0f --- a/sha256.c +++ b/sha256.c @@ -21,130 +21,150 @@ uint32_t k[64] = { - 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, - 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, - 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, - 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, - 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, - 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, - 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, - 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, + 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, + 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, + 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, + 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, + 0xbef9a3f7, 0xc67178f2 }; -void sha256_transform(SHA256_CTX *ctx, uint8_t data[]) -{ - uint32_t a,b,c,d,e,f,g,h,i,j,t1,t2,m[64]; - - for (i=0,j=0; i < 16; ++i, j += 4) - m[i] = (data[j] << 24) | (data[j+1] << 16) | (data[j+2] << 8) | (data[j+3]); - for ( ; i < 64; ++i) - m[i] = SIG1(m[i-2]) + m[i-7] + SIG0(m[i-15]) + m[i-16]; +void +sha256_transform( SHA256_CTX * ctx, uint8_t data[] ) +{ + uint32_t a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; - a = ctx->state[0]; - b = ctx->state[1]; - c = ctx->state[2]; - d = ctx->state[3]; - e = ctx->state[4]; - f = ctx->state[5]; - g = ctx->state[6]; - h = ctx->state[7]; - - for (i = 0; i < 64; ++i) { - t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; - t2 = EP0(a) + MAJ(a,b,c); - h = g; - g = f; - f = e; - e = d + t1; - d = c; - c = b; - b = a; - a = t1 + t2; - } - - ctx->state[0] += a; - ctx->state[1] += b; - ctx->state[2] += c; - ctx->state[3] += d; - ctx->state[4] += e; - ctx->state[5] += f; - ctx->state[6] += g; - ctx->state[7] += h; -} + for ( i = 0, j = 0; i < 16; ++i, j += 4 ) + m[i] = + ( data[j] << 24 ) | ( data[j + 1] << 16 ) | ( data[j + 2] << 8 ) | + ( data[j + 3] ); + for ( ; i < 64; ++i ) + m[i] = SIG1( m[i - 2] ) + m[i - 7] + SIG0( m[i - 15] ) + m[i - 16]; -void sha256_init(SHA256_CTX *ctx) -{ - ctx->datalen = 0; - ctx->bitlen[0] = 0; - ctx->bitlen[1] = 0; - ctx->state[0] = 0x6a09e667; - ctx->state[1] = 0xbb67ae85; - ctx->state[2] = 0x3c6ef372; - ctx->state[3] = 0xa54ff53a; - ctx->state[4] = 0x510e527f; - ctx->state[5] = 0x9b05688c; - ctx->state[6] = 0x1f83d9ab; - ctx->state[7] = 0x5be0cd19; + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + for ( i = 0; i < 64; ++i ) + { + t1 = h + EP1( e ) + CH( e, f, g ) + k[i] + m[i]; + t2 = EP0( a ) + MAJ( a, b, c ); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; } -void sha256_update(SHA256_CTX *ctx, uint8_t data[], uint32_t len) -{ - uint32_t t,i; - - for (i=0; i < len; ++i) { - ctx->data[ctx->datalen] = data[i]; - ctx->datalen++; - if (ctx->datalen == 64) { - sha256_transform(ctx,ctx->data); - DBL_INT_ADD(ctx->bitlen[0],ctx->bitlen[1],512); - ctx->datalen = 0; - } - } -} +void +sha256_init( SHA256_CTX * ctx ) +{ + ctx->datalen = 0; + ctx->bitlen[0] = 0; + ctx->bitlen[1] = 0; + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; +} -void sha256_final(SHA256_CTX *ctx, uint8_t hash[]) -{ - uint32_t i; - - i = ctx->datalen; - - // Pad whatever data is left in the buffer. - if (ctx->datalen < 56) { - ctx->data[i++] = 0x80; - while (i < 56) - ctx->data[i++] = 0x00; - } - else { - ctx->data[i++] = 0x80; - while (i < 64) - ctx->data[i++] = 0x00; - sha256_transform(ctx,ctx->data); - memset(ctx->data,0,56); - } - - // Append to the padding the total message's length in bits and transform. - DBL_INT_ADD(ctx->bitlen[0],ctx->bitlen[1],ctx->datalen * 8); - ctx->data[63] = ctx->bitlen[0]; - ctx->data[62] = ctx->bitlen[0] >> 8; - ctx->data[61] = ctx->bitlen[0] >> 16; - ctx->data[60] = ctx->bitlen[0] >> 24; - ctx->data[59] = ctx->bitlen[1]; - ctx->data[58] = ctx->bitlen[1] >> 8; - ctx->data[57] = ctx->bitlen[1] >> 16; - ctx->data[56] = ctx->bitlen[1] >> 24; - sha256_transform(ctx,ctx->data); - - // Since this implementation uses little endian byte ordering and SHA uses big endian, - // reverse all the bytes when copying the final state to the output hash. - for (i=0; i < 4; ++i) { - hash[i] = (ctx->state[0] >> (24-i*8)) & 0x000000ff; - hash[i+4] = (ctx->state[1] >> (24-i*8)) & 0x000000ff; - hash[i+8] = (ctx->state[2] >> (24-i*8)) & 0x000000ff; - hash[i+12] = (ctx->state[3] >> (24-i*8)) & 0x000000ff; - hash[i+16] = (ctx->state[4] >> (24-i*8)) & 0x000000ff; - hash[i+20] = (ctx->state[5] >> (24-i*8)) & 0x000000ff; - hash[i+24] = (ctx->state[6] >> (24-i*8)) & 0x000000ff; - hash[i+28] = (ctx->state[7] >> (24-i*8)) & 0x000000ff; - } -} +void +sha256_update( SHA256_CTX * ctx, char data[], uint32_t len ) +{ + uint32_t i; + + for ( i = 0; i < len; ++i ) + { + ctx->data[ctx->datalen] = data[i]; + ctx->datalen++; + if ( ctx->datalen == 64 ) + { + sha256_transform( ctx, ctx->data ); + DBL_INT_ADD( ctx->bitlen[0], ctx->bitlen[1], 512 ); + ctx->datalen = 0; + } + } +} + +void +sha256_final( SHA256_CTX * ctx, uint8_t hash[] ) +{ + uint32_t i; + + i = ctx->datalen; + + // Pad whatever data is left in the buffer. + if ( ctx->datalen < 56 ) + { + ctx->data[i++] = 0x80; + while ( i < 56 ) + ctx->data[i++] = 0x00; + } + else + { + ctx->data[i++] = 0x80; + while ( i < 64 ) + ctx->data[i++] = 0x00; + sha256_transform( ctx, ctx->data ); + memset( ctx->data, 0, 56 ); + } + + // Append to the padding the total message's length in bits and transform. + DBL_INT_ADD( ctx->bitlen[0], ctx->bitlen[1], ctx->datalen * 8 ); + ctx->data[63] = ctx->bitlen[0]; + ctx->data[62] = ctx->bitlen[0] >> 8; + ctx->data[61] = ctx->bitlen[0] >> 16; + ctx->data[60] = ctx->bitlen[0] >> 24; + ctx->data[59] = ctx->bitlen[1]; + ctx->data[58] = ctx->bitlen[1] >> 8; + ctx->data[57] = ctx->bitlen[1] >> 16; + ctx->data[56] = ctx->bitlen[1] >> 24; + sha256_transform( ctx, ctx->data ); + + // Since this implementation uses little endian byte ordering and SHA uses big endian, + // reverse all the bytes when copying the final state to the output hash. + for ( i = 0; i < 4; ++i ) + { + hash[i] = ( ctx->state[0] >> ( 24 - i * 8 ) ) & 0x000000ff; + hash[i + 4] = ( ctx->state[1] >> ( 24 - i * 8 ) ) & 0x000000ff; + hash[i + 8] = ( ctx->state[2] >> ( 24 - i * 8 ) ) & 0x000000ff; + hash[i + 12] = ( ctx->state[3] >> ( 24 - i * 8 ) ) & 0x000000ff; + hash[i + 16] = ( ctx->state[4] >> ( 24 - i * 8 ) ) & 0x000000ff; + hash[i + 20] = ( ctx->state[5] >> ( 24 - i * 8 ) ) & 0x000000ff; + hash[i + 24] = ( ctx->state[6] >> ( 24 - i * 8 ) ) & 0x000000ff; + hash[i + 28] = ( ctx->state[7] >> ( 24 - i * 8 ) ) & 0x000000ff; + } +} diff --git a/sha256.h b/sha256.h old mode 100755 new mode 100644 index 8175454..63c4945 --- a/sha256.h +++ b/sha256.h @@ -1,6 +1,10 @@ -typedef struct { - uint8_t data[64]; - uint32_t datalen; - uint32_t bitlen[2]; - uint32_t state[8]; -} SHA256_CTX; +typedef struct { + uint8_t data[64]; + uint32_t datalen; + uint32_t bitlen[2]; + uint32_t state[8]; + } SHA256_CTX; + void sha256_transform( SHA256_CTX * ctx, uint8_t data[] ); +void sha256_init( SHA256_CTX * ctx ); +void sha256_update( SHA256_CTX * ctx, char data[], uint32_t len ); +void sha256_final( SHA256_CTX * ctx, uint8_t hash[] ); diff --git a/ssdv.c b/ssdv.c index d6b691f..91cc0d7 100644 --- a/ssdv.c +++ b/ssdv.c @@ -2,167 +2,208 @@ #include #include #include -#include // Standard input/output definitions -#include // String function definitions -#include // UNIX standard function definitions -#include // File control definitions -#include // Error number definitions -#include // POSIX terminal control definitions +#include // Standard input/output definitions +#include // String function definitions +#include // UNIX standard function definitions +#include // File control definitions +#include // Error number definitions +#include // POSIX terminal control definitions #include #include #include #include #include #include +#include #include "urlencode.h" #include "base64.h" #include "ssdv.h" +#include "gateway.h" #include "global.h" -size_t write_ssdv_data(void *buffer, size_t size, size_t nmemb, void *userp) +extern int ssdv_pipe_fd[2]; +extern pthread_mutex_t var; + +size_t +write_ssdv_data( void *buffer, size_t size, size_t nmemb, void *userp ) { - return size * nmemb; + return size * nmemb; } -void ConvertStringToHex(unsigned char *Target, unsigned char *Source, int Length) +void +ConvertStringToHex( unsigned char *Target, unsigned char *Source, int Length ) { - const char Hex[16] = "0123456789ABCDEF"; - int i; - - for (i=0; i> 4]; - *Target++ = Hex[Source[i] & 0x0F]; - } + const char Hex[16] = "0123456789ABCDEF"; + int i; - *Target++ = '\0'; -} - - -int UploadImagePackets(void) -{ - CURL *curl; - CURLcode res; - char PostFields[1000], base64_data[512], json[32768], packet_json[1000]; - struct curl_slist *headers = NULL; - int UploadedOK, base64_length; - char now[32]; - time_t rawtime; - struct tm *tm; - - UploadedOK = 0; - - /* In windows, this will init the winsock stuff */ - // curl_global_init(CURL_GLOBAL_ALL); // RJH moved to main in gateway.c not thread safe - - /* get a curl handle */ - curl = curl_easy_init(); - if (curl) - { - int PacketIndex; - - // So that the response to the curl POST doesn;'t mess up my finely crafted display! - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_ssdv_data); - - // Set the timeout - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5); - - // RJH capture http errors and report - curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); - - // Avoid curl library bug that happens if above timeout occurs (sigh) - curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); - - // Get formatted timestamp - time(&rawtime); - tm = gmtime(&rawtime); - strftime(now, sizeof(now), "%Y-%0m-%0dT%H:%M:%SZ", tm); - - // Create json with the base64 data in hex, the tracker callsign and the current timestamp - strcpy(json, "{\"type\": \"packets\",\"packets\":["); - for (PacketIndex = 0; PacketIndex < SSDVPacketArrays[SSDVSendArrayIndex].Count; PacketIndex++) - { - base64_encode(SSDVPacketArrays[SSDVSendArrayIndex].Packets[PacketIndex].Packet, 256, &base64_length, base64_data); - base64_data[base64_length] = '\0'; - - sprintf(packet_json, "{\"type\": \"packet\", \"packet\": \"%s\", \"encoding\": \"base64\", \"received\": \"%s\", \"receiver\": \"%s\"}%s", - base64_data, now, Config.Tracker, PacketIndex == (SSDVPacketArrays[SSDVSendArrayIndex].Count-1) ? "" : ","); - strcat(json, packet_json); - } - strcat(json, "]}"); - - // Set the headers - headers = NULL; - headers = curl_slist_append(headers, "Accept: application/json"); - headers = curl_slist_append(headers, "Content-Type: application/json"); - headers = curl_slist_append(headers, "charsets: utf-8"); - - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl, CURLOPT_URL, "http://ssdv.habhub.org/api/v0/packets"); - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json); - - // Perform the request, res will get the return code - res = curl_easy_perform(curl); - - /* Check for errors */ - if(res == CURLE_OK) - { - UploadedOK = 1; - } - else - { - LogMessage("curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); - } - - /* always cleanup */ - curl_slist_free_all(headers); // RJH Added this from habitat.c as was missing - curl_easy_cleanup(curl); - } - - // curl_global_cleanup(); // RJH moved to main in gateway.c not thread safe - - return UploadedOK; -} - -void *SSDVLoop(void *arguments) -{ - char HexString[513]; - - while (1) + for ( i = 0; i < Length; i++ ) { - int ArrayIndex; - - pthread_mutex_lock(&ssdv_mutex); + *Target++ = Hex[Source[i] >> 4]; + *Target++ = Hex[Source[i] & 0x0F]; + } + + *Target++ = '\0'; +} + + +void +UploadImagePacket( ssdv_t * s, unsigned int packets ) +{ + CURL *curl; + CURLcode res; + char curl_error[CURL_ERROR_SIZE]; + char base64_data[512], json[32768], packet_json[1000]; + struct curl_slist *headers = NULL; + size_t base64_length; + char now[32]; + time_t rawtime; + struct tm *tm; + char url[250]; + + /* get a curl handle */ + curl = curl_easy_init( ); + if ( curl ) + { + + // So that the response to the curl POST doesn;'t mess up my finely crafted display! + curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, write_ssdv_data ); + + // Set the timeout + curl_easy_setopt( curl, CURLOPT_TIMEOUT, 15 ); + + // RJH capture http errors and report + curl_easy_setopt( curl, CURLOPT_FAILONERROR, 1 ); + curl_easy_setopt( curl, CURLOPT_ERRORBUFFER, curl_error ); + + // Avoid curl library bug that happens if above timeout occurs (sigh) + curl_easy_setopt( curl, CURLOPT_NOSIGNAL, 1 ); + + // Get formatted timestamp + time( &rawtime ); + tm = gmtime( &rawtime ); + strftime( now, sizeof( now ), "%Y-%0m-%0dT%H:%M:%SZ", tm ); + + int PacketIndex; + + // Create json with the base64 data in hex, the tracker callsign and the current timestamp + strcpy( json, "{\"type\": \"packets\",\"packets\":[" ); + + for ( PacketIndex = 0; PacketIndex < packets; PacketIndex++ ) + { + base64_encode( s[PacketIndex].SSDV_Packet, 256, &base64_length, + base64_data ); + base64_data[base64_length] = '\0'; + + sprintf( packet_json, + "{\"type\": \"packet\", \"packet\": \"%s\", \"encoding\": \"base64\", \"received\": \"%s\", \"receiver\": \"%s\"}%s", + base64_data, now, Config.Tracker, + PacketIndex == ( packets - 1 ) ? "" : "," ); + strcat( json, packet_json ); + } + strcat( json, "]}" ); + + // LogTelemetryPacket(json); + + strcpy( url, "http://ssdv.habhub.org/api/v0/packets" ); + // strcpy(url,"http://ext.hgf.com/ssdv/rjh.php"); + // strcpy(url,"http://ext.hgf.com/ssdv/apiv0.php?q=packets"); + + // Set the headers + headers = NULL; + headers = curl_slist_append( headers, "Accept: application/json" ); + headers = + curl_slist_append( headers, "Content-Type: application/json" ); + headers = curl_slist_append( headers, "charsets: utf-8" ); + + curl_easy_setopt( curl, CURLOPT_HTTPHEADER, headers ); + curl_easy_setopt( curl, CURLOPT_URL, url ); + + curl_easy_setopt( curl, CURLOPT_CUSTOMREQUEST, "POST" ); + curl_easy_setopt( curl, CURLOPT_POSTFIELDS, json ); + + // Perform the request, res will get the return code + res = curl_easy_perform( curl ); + + /* Check for errors */ + if ( res == CURLE_OK ) + { + } + else + { + LogMessage( "Failed for URL '%s'\n", url ); + LogMessage( "curl_easy_perform() failed: %s\n", + curl_easy_strerror( res ) ); + LogMessage( "error: %s\n", curl_error ); + } + + /* always cleanup */ + curl_slist_free_all( headers ); // RJH Added this from habitat.c as was missing + curl_easy_cleanup( curl ); + } +} + +void * +SSDVLoop( void *vars ) +{ + + if ( Config.EnableSSDV ) + { + const int max_packets = 51; + thread_shared_vars_t *stsv; + stsv = vars; + ssdv_t s[max_packets]; + unsigned int j = 0; + unsigned int packets = 0; + unsigned long total_packets = 0; + + // Keep looping until the parent quits and there are no more packets to + // send to ssdv. + while ( ( stsv->parent_status == RUNNING ) || ( packets > 0 ) ) + { + + if ( stsv->packet_count > total_packets ) + { + packets = read( ssdv_pipe_fd[0], &s[j], sizeof( ssdv_t ) ); + } + else + { + packets = 0; + + // If we have have a rollover after processing 4294967295 packets + if ( stsv->packet_count < total_packets ) + total_packets = 0; + + } + + if ( packets ) + { + j++; + total_packets++; + } + + if ( j == 50 || ( ( packets == 0 ) && ( j > 0 ) ) ) + { + ChannelPrintf( s[0].Channel, 6, 1, "Habitat" ); + + UploadImagePacket( s, j ); + + ChannelPrintf( s[0].Channel, 6, 1, " " ); + + j = 0; + + packets = 0; + } + + } + } + + close( ssdv_pipe_fd[0] ); + close( ssdv_pipe_fd[1] ); + + LogMessage( "SSDV thread closing\n" ); + + return NULL; - if (SSDVPacketArrays[0].Count > 0) - { - SSDVSendArrayIndex = 0; - } - else if (SSDVPacketArrays[1].Count > 0) - { - SSDVSendArrayIndex = 1; - } - else - { - SSDVSendArrayIndex = -1; - } - - pthread_mutex_unlock(&ssdv_mutex); - - if (SSDVSendArrayIndex >= 0) - { - if (UploadImagePackets()) - { - // Mark packets as sent - SSDVPacketArrays[SSDVSendArrayIndex].Count = 0; - } - - SSDVSendArrayIndex = -1; - } - - delay(100); - } } diff --git a/ssdv.h b/ssdv.h index 6093519..681a300 100644 --- a/ssdv.h +++ b/ssdv.h @@ -1 +1,2 @@ -void *SSDVLoop(void *some_void_ptr); +void *SSDVLoop( void *some_void_ptr ); + diff --git a/ssdv_resend.py b/ssdv_resend.py old mode 100755 new mode 100644 diff --git a/urlencode.c b/urlencode.c index 8ecde62..d44b5be 100644 --- a/urlencode.c +++ b/urlencode.c @@ -1,52 +1,71 @@ #include #include +#include /* Converts a hex character to its integer value */ -char from_hex(char ch) { - return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10; +char +from_hex( char ch ) +{ + return isdigit( ch ) ? ch - '0' : tolower( ch ) - 'a' + 10; } /* Converts an integer value to its hex character*/ -char to_hex(char code) { - static char hex[] = "0123456789abcdef"; - return hex[code & 15]; +char +to_hex( char code ) +{ + static char hex[] = "0123456789abcdef"; + return hex[code & 15]; } /* Returns a url-encoded version of str */ /* IMPORTANT: be sure to free() the returned string after use */ -char *url_encode(char *str) { - char *pstr = str, *buf = malloc(strlen(str) * 3 + 1), *pbuf = buf; - while (*pstr) { - if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') - *pbuf++ = *pstr; - else if (*pstr == ' ') - *pbuf++ = '+'; - else - *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15); - pstr++; - } - *pbuf = '\0'; - return buf; +char * +url_encode( char *str ) +{ + char *pstr = str, *buf = malloc( strlen( str ) * 3 + 1 ), *pbuf = buf; + while ( *pstr ) + { + if ( isalnum( *pstr ) || *pstr == '-' || *pstr == '_' || *pstr == '.' + || *pstr == '~' ) + *pbuf++ = *pstr; + else if ( *pstr == ' ' ) + *pbuf++ = '+'; + else + *pbuf++ = '%', *pbuf++ = to_hex( *pstr >> 4 ), *pbuf++ = + to_hex( *pstr & 15 ); + pstr++; + } + *pbuf = '\0'; + return buf; } /* Returns a url-decoded version of str */ /* IMPORTANT: be sure to free() the returned string after use */ -char *url_decode(char *str) { - char *pstr = str, *buf = malloc(strlen(str) + 1), *pbuf = buf; - while (*pstr) { - if (*pstr == '%') { - if (pstr[1] && pstr[2]) { - *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]); - pstr += 2; - } - } else if (*pstr == '+') { - *pbuf++ = ' '; - } else { - *pbuf++ = *pstr; +char * +url_decode( char *str ) +{ + char *pstr = str, *buf = malloc( strlen( str ) + 1 ), *pbuf = buf; + while ( *pstr ) + { + if ( *pstr == '%' ) + { + if ( pstr[1] && pstr[2] ) + { + *pbuf++ = from_hex( pstr[1] ) << 4 | from_hex( pstr[2] ); + pstr += 2; + } + } + else if ( *pstr == '+' ) + { + *pbuf++ = ' '; + } + else + { + *pbuf++ = *pstr; + } + pstr++; } - pstr++; - } - *pbuf = '\0'; - return buf; -} \ No newline at end of file + *pbuf = '\0'; + return buf; +} diff --git a/urlencode.h b/urlencode.h index 546d5cb..e8fc38f 100644 --- a/urlencode.h +++ b/urlencode.h @@ -1 +1,2 @@ -char *url_encode(char *str); +char *url_encode( char *str ); +