kopia lustrzana https://github.com/PiInTheSky/lora-gateway
V1.8 - Various fixes; extra uplink config; JSON changes
rodzic
97e532d58e
commit
c92f0cac24
|
@ -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 *~
|
45
README.md
45
README.md
|
@ -46,9 +46,7 @@ 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
|
||||
|
||||
** That last step is new - to prevent overwriting existing configurations, gateway.txt is supplied as a sample file that you need to copy first **
|
||||
5. cp gateway-sample.txt gateway.txt
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
-----------------
|
||||
|
||||
|
|
70
base64.c
70
base64.c
|
@ -9,15 +9,17 @@ static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
|||
'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', '+', '/'};
|
||||
'4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
|
||||
static char *decoding_table = NULL;
|
||||
static int mod_table[] = { 0, 2, 1 };
|
||||
|
||||
|
||||
void *base64_encode(const unsigned char *data,
|
||||
char *
|
||||
base64_encode( const char *data,
|
||||
size_t input_length,
|
||||
size_t *output_length,
|
||||
char *encoded_data)
|
||||
size_t * output_length, char *encoded_data )
|
||||
{
|
||||
|
||||
int i, j;
|
||||
|
@ -44,11 +46,13 @@ void *base64_encode(const unsigned char *data,
|
|||
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;
|
||||
|
||||
|
@ -58,37 +62,49 @@ void build_decoding_table() {
|
|||
decoding_table[( unsigned char ) encoding_table[i]] = i;
|
||||
}
|
||||
|
||||
unsigned char *base64_decode(const char *data,
|
||||
size_t input_length,
|
||||
size_t *output_length) {
|
||||
char *
|
||||
base64_decode( const char *data, size_t input_length, size_t * output_length )
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (decoding_table == NULL) build_decoding_table();
|
||||
if ( decoding_table == NULL )
|
||||
build_decoding_table( );
|
||||
|
||||
if (input_length % 4 != 0) return NULL;
|
||||
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);
|
||||
+ ( 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() {
|
||||
void
|
||||
base64_cleanup( )
|
||||
{
|
||||
free( decoding_table );
|
||||
}
|
7
base64.h
7
base64.h
|
@ -1,3 +1,8 @@
|
|||
#include <stdint.h>
|
||||
|
||||
void base64_encode(const unsigned char *data, size_t input_length, size_t *output_length, char *encoded_data);
|
||||
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( );
|
||||
|
|
20
ftp.c
20
ftp.c
|
@ -17,7 +17,8 @@
|
|||
#include "ftp.h"
|
||||
#include "global.h"
|
||||
|
||||
void ConvertFile(char *FileName)
|
||||
void
|
||||
ConvertFile( char *FileName )
|
||||
{
|
||||
char TargetFile[100], CommandLine[200], *ptr;
|
||||
|
||||
|
@ -31,21 +32,28 @@ void ConvertFile(char *FileName)
|
|||
// 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);
|
||||
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])
|
||||
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);
|
||||
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)
|
||||
void *
|
||||
FTPLoop( void *some_void_ptr )
|
||||
{
|
||||
while ( 1 )
|
||||
{
|
||||
|
@ -60,7 +68,7 @@ void *FTPLoop(void *some_void_ptr)
|
|||
dp = opendir( SSDVFolder );
|
||||
if ( dp != NULL )
|
||||
{
|
||||
while (ep = readdir (dp))
|
||||
while ( ( ep = readdir( dp ) ) )
|
||||
{
|
||||
if ( strstr( ep->d_name, ".bin" ) != NULL )
|
||||
{
|
||||
|
|
|
@ -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
|
|
@ -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
|
61
gateway.txt
61
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
|
||||
|
|
56
global.h
56
global.h
|
@ -1,29 +1,17 @@
|
|||
#include <curses.h>
|
||||
|
||||
#define SSDV_PACKETS 64
|
||||
|
||||
struct TSSDVPacket
|
||||
{
|
||||
unsigned char Packet[256];
|
||||
#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 TSSDVPacketArray
|
||||
{
|
||||
struct TSSDVPacket Packets[SSDV_PACKETS];
|
||||
int Count;
|
||||
int Sending;
|
||||
};
|
||||
|
||||
struct TSSDVPackets
|
||||
{
|
||||
struct TSSDVPackets
{
|
||||
int ImageNumber;
|
||||
int HighestPacket;
|
||||
bool Packets[1024];
|
||||
};
|
||||
|
||||
struct TLoRaDevice
|
||||
{
|
||||
struct TLoRaDevice
{
|
||||
int InUse;
|
||||
int DIO0;
|
||||
int DIO5;
|
||||
|
@ -39,13 +27,9 @@ struct TLoRaDevice
|
|||
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;
|
||||
|
@ -61,7 +45,11 @@ struct TLoRaDevice
|
|||
int InCallingMode;
|
||||
int ActivityLED;
|
||||
|
||||
int Speed, Heading, PredictedTime, CompassActual, CompassTarget, AirDirection, ServoLeft, ServoRight, ServoTime, FlightMode;
|
||||
double UplinkFrequency;
|
||||
|
||||
int UplinkMode;
|
||||
int Speed, Heading, PredictedTime, CompassActual, CompassTarget,
|
||||
AirDirection, ServoLeft, ServoRight, ServoTime, FlightMode;
|
||||
double cda, PredictedLandingSpeed, AirSpeed, GlideRatio;
|
||||
|
||||
// Normal (non TDM) uplink
|
||||
|
@ -71,9 +59,7 @@ struct TLoRaDevice
|
|||
// SSDV Packet Log
|
||||
struct TSSDVPackets SSDVPackets[3];
|
||||
};
|
||||
|
||||
struct TConfig
|
||||
{
|
||||
struct TConfig
{
|
||||
char Tracker[16];
|
||||
int EnableHabitat;
|
||||
int EnableSSDV;
|
||||
|
@ -94,10 +80,24 @@ struct TConfig
|
|||
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 struct TSSDVPacketArray SSDVPacketArrays[];
|
||||
extern int SSDVSendArrayIndex;
|
||||
extern pthread_mutex_t ssdv_mutex;
|
||||
|
||||
void LogMessage( const char *format, ... );
|
125
habitat.c
125
habitat.c
|
@ -13,25 +13,31 @@
|
|||
#include <stddef.h>
|
||||
#include <dirent.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <curl/curl.h>
|
||||
#include <wiringPi.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
void hash_to_hex(unsigned char *hash, char *line)
|
||||
void
|
||||
hash_to_hex( unsigned char *hash, char *line )
|
||||
{
|
||||
int idx;
|
||||
|
||||
|
@ -44,13 +50,12 @@ void hash_to_hex(unsigned char *hash, char *line)
|
|||
// LogMessage(line);
|
||||
}
|
||||
|
||||
void UploadTelemetryPacket(int Channel)
|
||||
void
|
||||
UploadTelemetryPacket( telemetry_t * t )
|
||||
{
|
||||
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
|
||||
char curl_error[CURL_ERROR_SIZE];
|
||||
|
||||
/* get a curl handle */
|
||||
curl = curl_easy_init( );
|
||||
|
@ -63,7 +68,7 @@ void UploadTelemetryPacket(int Channel)
|
|||
unsigned char hash[32];
|
||||
char doc_id[100];
|
||||
char json[1000], now[32];
|
||||
char PostFields[400], Sentence[512];
|
||||
char Sentence[512];
|
||||
struct curl_slist *headers = NULL;
|
||||
time_t rawtime;
|
||||
struct tm *tm;
|
||||
|
@ -77,19 +82,21 @@ void UploadTelemetryPacket(int Channel)
|
|||
curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, habitat_write_data );
|
||||
|
||||
// Set the timeout
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5);
|
||||
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", Config.LoRaDevices[Channel].Telemetry);
|
||||
sprintf( Sentence, "%s\n", t->Telemetry );
|
||||
|
||||
// Convert sentence to base64
|
||||
base64_encode(Sentence, strlen(Sentence), &base64_length, base64_data);
|
||||
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
|
||||
|
@ -98,21 +105,28 @@ void UploadTelemetryPacket(int Channel)
|
|||
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);
|
||||
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://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, "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/<doc_id> with content-type application/json
|
||||
|
@ -121,8 +135,6 @@ void UploadTelemetryPacket(int Channel)
|
|||
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 );
|
||||
|
||||
|
@ -133,7 +145,10 @@ void UploadTelemetryPacket(int Channel)
|
|||
}
|
||||
else
|
||||
{
|
||||
LogMessage("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||
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
|
||||
|
@ -142,35 +157,73 @@ void UploadTelemetryPacket(int Channel)
|
|||
// free(base64_data);
|
||||
}
|
||||
|
||||
// curl_global_cleanup(); // RJH moved to main in gateway.c not thread safe
|
||||
}
|
||||
|
||||
|
||||
void *HabitatLoop(void *some_void_ptr)
|
||||
{
|
||||
while (1)
|
||||
void *
|
||||
HabitatLoop( void *vars )
|
||||
{
|
||||
|
||||
if ( Config.EnableHabitat )
|
||||
{
|
||||
int Channel;
|
||||
thread_shared_vars_t *htsv;
|
||||
htsv = vars;
|
||||
telemetry_t t;
|
||||
int packets = 0;
|
||||
unsigned long total_packets = 0;
|
||||
|
||||
for (Channel=0; Channel<=1; Channel++)
|
||||
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 ) )
|
||||
{
|
||||
if (Config.LoRaDevices[Channel].Counter != Config.LoRaDevices[Channel].LastCounter)
|
||||
|
||||
//THis is neded for some reason habitat thread has a pthread_mutex_lock set
|
||||
// and this removes it
|
||||
if ( i )
|
||||
{
|
||||
ChannelPrintf(Channel, 6, 1, "Habitat");
|
||||
// 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);
|
||||
|
||||
UploadTelemetryPacket(Channel);
|
||||
// If we have have a rollover after processing 4294967295 packets
|
||||
if ( htsv->packet_count < total_packets )
|
||||
total_packets = 0;
|
||||
|
||||
Config.LoRaDevices[Channel].LastCounter = Config.LoRaDevices[Channel].Counter;
|
||||
}
|
||||
|
||||
delay(100);
|
||||
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++;
|
||||
|
||||
ChannelPrintf(Channel, 6, 1, " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delay(100);
|
||||
}
|
||||
close( telem_pipe_fd[0] );
|
||||
close( telem_pipe_fd[1] );
|
||||
|
||||
LogMessage( "Habitat thread closing\n" );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
30
makefile
30
makefile
|
@ -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
|
||||
|
16
network.c
16
network.c
|
@ -18,10 +18,12 @@
|
|||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <wiringPi.h> // Include WiringPi library!
|
||||
#include "network.h"
|
||||
#include "global.h"
|
||||
|
||||
int HaveAnIPAddress(void)
|
||||
int
|
||||
HaveAnIPAddress( void )
|
||||
{
|
||||
struct ifaddrs *ifap, *ifa;
|
||||
struct sockaddr_in *sa;
|
||||
|
@ -56,9 +58,10 @@ int HaveAnIPAddress(void)
|
|||
return FoundAddress;
|
||||
}
|
||||
|
||||
int CanSeeTheInternet(void)
|
||||
int
|
||||
CanSeeTheInternet( void )
|
||||
{
|
||||
struct addrinfo hints, *res, *p;
|
||||
struct addrinfo hints, *res;
|
||||
int status, sockfd, FoundInternet;
|
||||
|
||||
memset( &hints, 0, sizeof hints );
|
||||
|
@ -85,12 +88,11 @@ int CanSeeTheInternet(void)
|
|||
return FoundInternet;
|
||||
}
|
||||
|
||||
void *NetworkLoop(void *some_void_ptr)
|
||||
void *
|
||||
NetworkLoop( void *some_void_ptr )
|
||||
{
|
||||
while ( 1 )
|
||||
{
|
||||
digitalWrite(Config.NetworkLED, 0);
|
||||
digitalWrite(Config.InternetLED, 0);
|
||||
if ( HaveAnIPAddress( ) )
|
||||
{
|
||||
digitalWrite( Config.NetworkLED, 1 );
|
||||
|
@ -103,11 +105,13 @@ void *NetworkLoop(void *some_void_ptr)
|
|||
}
|
||||
else
|
||||
{
|
||||
digitalWrite( Config.InternetLED, 0 );
|
||||
// LogMessage("Not on internet :-(\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
digitalWrite( Config.NetworkLED, 0 );
|
||||
// LogMessage("No network :-(\n");
|
||||
}
|
||||
|
||||
|
|
26
server.c
26
server.c
|
@ -29,7 +29,6 @@ void *ServerLoop(void *some_void_ptr)
|
|||
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 ) );
|
||||
|
@ -41,15 +40,19 @@ void *ServerLoop(void *some_void_ptr)
|
|||
|
||||
LogMessage( "Listening on port %d\n", Config.ServerPort );
|
||||
|
||||
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)) < 0)
|
||||
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)
|
||||
if ( bind
|
||||
( listenfd, ( struct sockaddr * ) &serv_addr,
|
||||
sizeof( serv_addr ) ) < 0 )
|
||||
{
|
||||
LogMessage( "Server failed errno %d\n", errno );
|
||||
return;
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
listen( listenfd, 10 );
|
||||
|
@ -68,16 +71,19 @@ void *ServerLoop(void *some_void_ptr)
|
|||
// Build json
|
||||
// sprintf(sendBuff, "{\"class\":\"POSN\",\"time\":\"12:34:56\",\"lat\":54.12345,\"lon\":-2.12345,\"alt\":169}\r\n");
|
||||
|
||||
Channel = 1;
|
||||
for (Channel=0; Channel<=1; Channel++)
|
||||
{
|
||||
if ( Config.EnableDev )
|
||||
{
|
||||
sprintf(sendBuff, "{\"class\":\"POSN\",\"payload\":\"%s\",\"time\":\"%s\",\"lat\":%.5lf,\"lon\":%.5lf,\"alt\":%d,\"predlat\":%.5lf,\"predlon\":%.5lf,\"speed\":%d,"
|
||||
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,
|
||||
|
@ -98,8 +104,8 @@ void *ServerLoop(void *some_void_ptr)
|
|||
}
|
||||
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,
|
||||
|
@ -122,8 +128,10 @@ void *ServerLoop(void *some_void_ptr)
|
|||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
close( connfd );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
1
server.h
1
server.h
|
@ -1 +1,2 @@
|
|||
void *ServerLoop( void *some_void_ptr );
|
||||
|
||||
|
|
|
@ -21,23 +21,34 @@
|
|||
|
||||
|
||||
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[])
|
||||
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]);
|
||||
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];
|
||||
|
||||
|
@ -50,7 +61,8 @@ void sha256_transform(SHA256_CTX *ctx, uint8_t data[])
|
|||
g = ctx->state[6];
|
||||
h = ctx->state[7];
|
||||
|
||||
for (i = 0; i < 64; ++i) {
|
||||
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;
|
||||
|
@ -73,7 +85,8 @@ void sha256_transform(SHA256_CTX *ctx, uint8_t data[])
|
|||
ctx->state[7] += h;
|
||||
}
|
||||
|
||||
void sha256_init(SHA256_CTX *ctx)
|
||||
void
|
||||
sha256_init( SHA256_CTX * ctx )
|
||||
{
|
||||
ctx->datalen = 0;
|
||||
ctx->bitlen[0] = 0;
|
||||
|
@ -88,14 +101,17 @@ void sha256_init(SHA256_CTX *ctx)
|
|||
ctx->state[7] = 0x5be0cd19;
|
||||
}
|
||||
|
||||
void sha256_update(SHA256_CTX *ctx, uint8_t data[], uint32_t len)
|
||||
void
|
||||
sha256_update( SHA256_CTX * ctx, char data[], uint32_t len )
|
||||
{
|
||||
uint32_t t,i;
|
||||
uint32_t i;
|
||||
|
||||
for (i=0; i < len; ++i) {
|
||||
for ( i = 0; i < len; ++i )
|
||||
{
|
||||
ctx->data[ctx->datalen] = data[i];
|
||||
ctx->datalen++;
|
||||
if (ctx->datalen == 64) {
|
||||
if ( ctx->datalen == 64 )
|
||||
{
|
||||
sha256_transform( ctx, ctx->data );
|
||||
DBL_INT_ADD( ctx->bitlen[0], ctx->bitlen[1], 512 );
|
||||
ctx->datalen = 0;
|
||||
|
@ -103,19 +119,22 @@ void sha256_update(SHA256_CTX *ctx, uint8_t data[], uint32_t len)
|
|||
}
|
||||
}
|
||||
|
||||
void sha256_final(SHA256_CTX *ctx, uint8_t hash[])
|
||||
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) {
|
||||
if ( ctx->datalen < 56 )
|
||||
{
|
||||
ctx->data[i++] = 0x80;
|
||||
while ( i < 56 )
|
||||
ctx->data[i++] = 0x00;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
ctx->data[i++] = 0x80;
|
||||
while ( i < 64 )
|
||||
ctx->data[i++] = 0x00;
|
||||
|
@ -137,7 +156,8 @@ void sha256_final(SHA256_CTX *ctx, uint8_t hash[])
|
|||
|
||||
// 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) {
|
||||
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;
|
||||
|
|
|
@ -4,3 +4,7 @@ typedef struct {
|
|||
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[] );
|
||||
|
|
131
ssdv.c
131
ssdv.c
|
@ -14,19 +14,26 @@
|
|||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <curl/curl.h>
|
||||
#include <wiringPi.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
@ -41,36 +48,34 @@ void ConvertStringToHex(unsigned char *Target, unsigned char *Source, int Length
|
|||
}
|
||||
|
||||
|
||||
int UploadImagePackets(void)
|
||||
void
|
||||
UploadImagePacket( ssdv_t * s, unsigned int packets )
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
char PostFields[1000], base64_data[512], json[32768], packet_json[1000];
|
||||
char curl_error[CURL_ERROR_SIZE];
|
||||
char base64_data[512], json[32768], packet_json[1000];
|
||||
struct curl_slist *headers = NULL;
|
||||
int UploadedOK, base64_length;
|
||||
size_t 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
|
||||
char url[250];
|
||||
|
||||
/* 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);
|
||||
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 );
|
||||
|
@ -80,27 +85,41 @@ int UploadImagePackets(void)
|
|||
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 < SSDVPacketArrays[SSDVSendArrayIndex].Count; PacketIndex++)
|
||||
|
||||
for ( PacketIndex = 0; PacketIndex < packets; PacketIndex++ )
|
||||
{
|
||||
base64_encode(SSDVPacketArrays[SSDVSendArrayIndex].Packets[PacketIndex].Packet, 256, &base64_length, base64_data);
|
||||
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 == (SSDVPacketArrays[SSDVSendArrayIndex].Count-1) ? "" : ",");
|
||||
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, "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_URL, url );
|
||||
|
||||
curl_easy_setopt( curl, CURLOPT_CUSTOMREQUEST, "POST" );
|
||||
curl_easy_setopt( curl, CURLOPT_POSTFIELDS, json );
|
||||
|
||||
|
@ -110,59 +129,81 @@ int UploadImagePackets(void)
|
|||
/* Check for errors */
|
||||
if ( res == CURLE_OK )
|
||||
{
|
||||
UploadedOK = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogMessage("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||
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 );
|
||||
}
|
||||
|
||||
// curl_global_cleanup(); // RJH moved to main in gateway.c not thread safe
|
||||
|
||||
return UploadedOK;
|
||||
}
|
||||
|
||||
void *SSDVLoop(void *arguments)
|
||||
void *
|
||||
SSDVLoop( void *vars )
|
||||
{
|
||||
char HexString[513];
|
||||
|
||||
while (1)
|
||||
if ( Config.EnableSSDV )
|
||||
{
|
||||
int ArrayIndex;
|
||||
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;
|
||||
|
||||
pthread_mutex_lock(&ssdv_mutex);
|
||||
// Keep looping until the parent quits and there are no more packets to
|
||||
// send to ssdv.
|
||||
while ( ( stsv->parent_status == RUNNING ) || ( packets > 0 ) )
|
||||
{
|
||||
|
||||
if (SSDVPacketArrays[0].Count > 0)
|
||||
if ( stsv->packet_count > total_packets )
|
||||
{
|
||||
SSDVSendArrayIndex = 0;
|
||||
}
|
||||
else if (SSDVPacketArrays[1].Count > 0)
|
||||
{
|
||||
SSDVSendArrayIndex = 1;
|
||||
packets = read( ssdv_pipe_fd[0], &s[j], sizeof( ssdv_t ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
SSDVSendArrayIndex = -1;
|
||||
packets = 0;
|
||||
|
||||
// If we have have a rollover after processing 4294967295 packets
|
||||
if ( stsv->packet_count < total_packets )
|
||||
total_packets = 0;
|
||||
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&ssdv_mutex);
|
||||
|
||||
if (SSDVSendArrayIndex >= 0)
|
||||
if ( packets )
|
||||
{
|
||||
if (UploadImagePackets())
|
||||
j++;
|
||||
total_packets++;
|
||||
}
|
||||
|
||||
if ( j == 50 || ( ( packets == 0 ) && ( j > 0 ) ) )
|
||||
{
|
||||
// Mark packets as sent
|
||||
SSDVPacketArrays[SSDVSendArrayIndex].Count = 0;
|
||||
ChannelPrintf( s[0].Channel, 6, 1, "Habitat" );
|
||||
|
||||
UploadImagePacket( s, j );
|
||||
|
||||
ChannelPrintf( s[0].Channel, 6, 1, " " );
|
||||
|
||||
j = 0;
|
||||
|
||||
packets = 0;
|
||||
}
|
||||
|
||||
SSDVSendArrayIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
delay(100);
|
||||
}
|
||||
close( ssdv_pipe_fd[0] );
|
||||
close( ssdv_pipe_fd[1] );
|
||||
|
||||
LogMessage( "SSDV thread closing\n" );
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
|
1
ssdv.h
1
ssdv.h
|
@ -1 +1,2 @@
|
|||
void *SSDVLoop( void *some_void_ptr );
|
||||
|
||||
|
|
43
urlencode.c
43
urlencode.c
|
@ -1,29 +1,39 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
/* Converts a hex character to its integer value */
|
||||
char from_hex(char ch) {
|
||||
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) {
|
||||
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 *
|
||||
url_encode( char *str )
|
||||
{
|
||||
char *pstr = str, *buf = malloc( strlen( str ) * 3 + 1 ), *pbuf = buf;
|
||||
while (*pstr) {
|
||||
if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
|
||||
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);
|
||||
*pbuf++ = '%', *pbuf++ = to_hex( *pstr >> 4 ), *pbuf++ =
|
||||
to_hex( *pstr & 15 );
|
||||
pstr++;
|
||||
}
|
||||
*pbuf = '\0';
|
||||
|
@ -32,17 +42,26 @@ char *url_encode(char *str) {
|
|||
|
||||
/* Returns a url-decoded version of str */
|
||||
/* IMPORTANT: be sure to free() the returned string after use */
|
||||
char *url_decode(char *str) {
|
||||
char *
|
||||
url_decode( char *str )
|
||||
{
|
||||
char *pstr = str, *buf = malloc( strlen( str ) + 1 ), *pbuf = buf;
|
||||
while (*pstr) {
|
||||
if (*pstr == '%') {
|
||||
if (pstr[1] && pstr[2]) {
|
||||
while ( *pstr )
|
||||
{
|
||||
if ( *pstr == '%' )
|
||||
{
|
||||
if ( pstr[1] && pstr[2] )
|
||||
{
|
||||
*pbuf++ = from_hex( pstr[1] ) << 4 | from_hex( pstr[2] );
|
||||
pstr += 2;
|
||||
}
|
||||
} else if (*pstr == '+') {
|
||||
}
|
||||
else if ( *pstr == '+' )
|
||||
{
|
||||
*pbuf++ = ' ';
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
*pbuf++ = *pstr;
|
||||
}
|
||||
pstr++;
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
char *url_encode( char *str );
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue