V1.8 - Various fixes; extra uplink config; JSON changes

pull/26/head
Dave Akerman 2016-09-03 06:32:10 +00:00
rodzic 97e532d58e
commit c92f0cac24
25 zmienionych plików z 3321 dodań i 2625 usunięć

30
Makefile 100644
Wyświetl plik

@ -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 *~

Wyświetl plik

@ -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
-----------------

138
base64.c
Wyświetl plik

@ -2,93 +2,109 @@
#include <stdlib.h>
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);
}
void
base64_cleanup( )
{
free( decoding_table );
}

Wyświetl plik

@ -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( );

148
ftp.c
Wyświetl plik

@ -2,12 +2,12 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <stdio.h> // Standard input/output definitions
#include <string.h> // String function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions
#include <stdio.h> // Standard input/output definitions
#include <string.h> // String function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions
#include <stdint.h>
#include <stdlib.h>
#include <dirent.h>
@ -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 );
}
}

2
ftp.h
Wyświetl plik

@ -1 +1 @@
void *FTPLoop(void *some_void_ptr);
void *FTPLoop( void *some_void_ptr );

58
gateway-sample.txt 100644
Wyświetl plik

@ -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

3807
gateway.c

Plik diff jest za duży Load Diff

14
gateway.h 100644
Wyświetl plik

@ -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

Wyświetl plik

@ -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

198
global.h
Wyświetl plik

@ -1,103 +1,103 @@
#include <curses.h>
#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, ...);
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, ... );

353
habitat.c
Wyświetl plik

@ -2,175 +2,228 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <stdio.h> // Standard input/output definitions
#include <string.h> // String function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions
#include <stdio.h> // Standard input/output definitions
#include <string.h> // String function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions
#include <stdint.h>
#include <stdlib.h>
#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;
// 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/<doc_id> 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/<doc_id> 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;
}

Wyświetl plik

@ -1 +1 @@
void *HabitatLoop(void *some_void_ptr);
void *HabitatLoop( void *some_void_ptr );

Wyświetl plik

@ -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

172
network.c
Wyświetl plik

@ -2,12 +2,12 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <stdio.h> // Standard input/output definitions
#include <string.h> // String function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions
#include <stdio.h> // Standard input/output definitions
#include <string.h> // String function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions
#include <stdint.h>
#include <stdlib.h>
#include <dirent.h>
@ -18,99 +18,103 @@
#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;
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 );
}
}

Wyświetl plik

@ -1 +1 @@
void *NetworkLoop(void *some_void_ptr);
void *NetworkLoop( void *some_void_ptr );

178
server.c
Wyświetl plik

@ -2,12 +2,12 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <stdio.h> // Standard input/output definitions
#include <string.h> // String function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions
#include <stdio.h> // Standard input/output definitions
#include <string.h> // String function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions
#include <stdint.h>
#include <stdlib.h>
#include <dirent.h>
@ -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);
}
}
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;
}

Wyświetl plik

@ -1 +1,2 @@
void *ServerLoop(void *some_void_ptr);
void *ServerLoop( void *some_void_ptr );

258
sha256.c 100755 → 100644
Wyświetl plik

@ -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;
}
}

16
sha256.h 100755 → 100644
Wyświetl plik

@ -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[] );

327
ssdv.c
Wyświetl plik

@ -2,167 +2,208 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <stdio.h> // Standard input/output definitions
#include <string.h> // String function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions
#include <stdio.h> // Standard input/output definitions
#include <string.h> // String function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions
#include <stdint.h>
#include <stdlib.h>
#include <dirent.h>
#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;
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<Length; i++)
{
*Target++ = Hex[Source[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);
}
}

3
ssdv.h
Wyświetl plik

@ -1 +1,2 @@
void *SSDVLoop(void *some_void_ptr);
void *SSDVLoop( void *some_void_ptr );

0
ssdv_resend.py 100755 → 100644
Wyświetl plik

Wyświetl plik

@ -1,52 +1,71 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* 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;
}
*pbuf = '\0';
return buf;
}

Wyświetl plik

@ -1 +1,2 @@
char *url_encode(char *str);
char *url_encode( char *str );