V1.8.6 - Random delay after habitat 409 conflict; payload array for JSON

pull/26/merge
Dave Akerman 2016-10-16 16:05:37 +00:00
rodzic 3450c9274e
commit 0843b3027b
5 zmienionych plików z 195 dodań i 184 usunięć

Wyświetl plik

@ -12,7 +12,7 @@ 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
%.o: %.c *.h # combined w/ next line will compile recently changed .c files
$(CC) $(CFLAGS) -o $@ -c $<
.PHONY : all # .PHONY ignores files named all

179
gateway.c
Wyświetl plik

@ -34,7 +34,7 @@
#include "gateway.h"
#include "config.h"
#define VERSION "V1.8.5"
#define VERSION "V1.8.6"
bool run = TRUE;
// RFM98
@ -293,8 +293,7 @@ void LogPacket( int Channel, int8_t SNR, int RSSI, double FreqError, int Bytes,
}
}
void
LogTelemetryPacket( char *Telemetry )
void LogTelemetryPacket(char *Telemetry)
{
// if (Config.EnableTelemetryLogging)
{
@ -784,93 +783,132 @@ void UploadListenerTelemetry( char *callsign, float gps_lat, float gps_lon, char
}
}
void RemoveOldPayloads(void)
{
int i;
for (i=0; i<MAX_PAYLOADS; i++)
{
if (Config.Payloads[i].InUse)
{
if ((time(NULL) - Config.Payloads[i].LastPacketAt) > 10800)
{
// More than 3 hours old, so remove it
}
Config.Payloads[i].InUse = 0;
}
}
}
void DoPositionCalcs(Channel)
int FindFreePayload(char *Payload)
{
int i, Oldest;
// First pass - find match for payload
for (i=0; i<MAX_PAYLOADS; i++)
{
if (Config.Payloads[i].InUse)
{
if (strcmp(Payload, Config.Payloads[i].Payload) == 0)
{
return i;
}
}
}
// Second pass - just find a free position
for (i=0; i<MAX_PAYLOADS; i++)
{
if (!Config.Payloads[i].InUse)
{
Config.Payloads[i].InUse = 1;
strcpy(Config.Payloads[i].Payload, Payload);
return i;
}
}
// Third pass - find oldest payload
Oldest = 0;
for (i=1; i<MAX_PAYLOADS; i++)
{
if (Config.Payloads[i].LastPositionAt < Config.Payloads[Oldest].LastPositionAt)
{
Oldest = i;
}
}
strcpy(Config.Payloads[Oldest].Payload, Payload);
return i;
}
void DoPositionCalcs(int PayloadIndex)
{
unsigned long Now;
struct tm tm;
float Climb, Period;
strptime( Config.LoRaDevices[Channel].Time, "%H:%M:%S", &tm );
strptime(Config.Payloads[PayloadIndex].Time, "%H:%M:%S", &tm);
Now = tm.tm_hour * 3600 + tm.tm_min * 60 + tm.tm_sec;
if ( ( Config.LoRaDevices[Channel].LastPositionAt > 0 )
&& ( Now > Config.LoRaDevices[Channel].LastPositionAt ) )
if ((Config.Payloads[PayloadIndex].LastPositionAt > 0 )
&& ( Now > Config.Payloads[PayloadIndex].LastPositionAt ) )
{
Climb =
( float ) Config.LoRaDevices[Channel].Altitude -
( float ) Config.LoRaDevices[Channel].PreviousAltitude;
Period =
( float ) Now -
( float ) Config.LoRaDevices[Channel].LastPositionAt;
Config.LoRaDevices[Channel].AscentRate = Climb / Period;
Climb = (float)Config.Payloads[PayloadIndex].Altitude - (float)Config.Payloads[PayloadIndex].PreviousAltitude;
Period = (float)Now - (float)Config.Payloads[PayloadIndex].LastPositionAt;
Config.Payloads[PayloadIndex].AscentRate = Climb / Period;
}
else
{
Config.LoRaDevices[Channel].AscentRate = 0;
Config.Payloads[PayloadIndex].AscentRate = 0;
}
Config.LoRaDevices[Channel].PreviousAltitude =
Config.LoRaDevices[Channel].Altitude;
Config.LoRaDevices[Channel].LastPositionAt = Now;
ChannelPrintf( Channel, 4, 1, "%8.5lf, %8.5lf, %05u ",
Config.LoRaDevices[Channel].Latitude,
Config.LoRaDevices[Channel].Longitude,
Config.LoRaDevices[Channel].Altitude );
Config.Payloads[PayloadIndex].LastPositionAt = Now;
Config.Payloads[PayloadIndex].PreviousAltitude = Config.Payloads[PayloadIndex].Altitude;
}
void ProcessLine(int Channel, char *Line)
{
int Satellites;
float TempInt, TempExt;
int PayloadIndex;
char Payload[32];
Config.LoRaDevices[Channel].FlightMode = -1;
// Find free position for this payload
sscanf(Line + 2, "%31[^,]", Payload);
PayloadIndex = FindFreePayload(Payload);
if ( Config.EnableDev )
{
sscanf( Line + 2,
"%15[^,],%u,%8[^,],%lf,%lf,%u,%d,%d,%d,%f,%f,%lf,%lf,%lf,%lf,%d,%d,%d,%lf,%d,%d,%d,%d,%lf,%d",
( Config.LoRaDevices[Channel].Payload ),
&( Config.LoRaDevices[Channel].Counter ),
( Config.LoRaDevices[Channel].Time ),
&( Config.LoRaDevices[Channel].Latitude ),
&( Config.LoRaDevices[Channel].Longitude ),
&( Config.LoRaDevices[Channel].Altitude ),
&( Config.LoRaDevices[Channel].Speed ),
&( Config.LoRaDevices[Channel].Heading ), &Satellites,
&TempInt, &TempExt, &( Config.LoRaDevices[Channel].cda ),
&( Config.LoRaDevices[Channel].PredictedLatitude ),
&( Config.LoRaDevices[Channel].PredictedLongitude ),
&( Config.LoRaDevices[Channel].PredictedLandingSpeed ),
&( Config.LoRaDevices[Channel].PredictedTime ),
&( Config.LoRaDevices[Channel].CompassActual ),
&( Config.LoRaDevices[Channel].CompassTarget ),
&( Config.LoRaDevices[Channel].AirSpeed ),
&( Config.LoRaDevices[Channel].AirDirection ),
&( Config.LoRaDevices[Channel].ServoLeft ),
&( Config.LoRaDevices[Channel].ServoRight ),
&( Config.LoRaDevices[Channel].ServoTime ),
&( Config.LoRaDevices[Channel].GlideRatio ),
&( Config.LoRaDevices[Channel].FlightMode ) );
}
else
{
sscanf( Line + 2, "%15[^,],%u,%8[^,],%lf,%lf,%u",
( Config.LoRaDevices[Channel].Payload ),
&( Config.LoRaDevices[Channel].Counter ),
( Config.LoRaDevices[Channel].Time ),
&( Config.LoRaDevices[Channel].Latitude ),
&( Config.LoRaDevices[Channel].Longitude ),
&( Config.LoRaDevices[Channel].Altitude ) );
}
// Store sentence against this payload
strcpy(Config.Payloads[PayloadIndex].Telemetry, Line);
// Fill in source channel
Config.Payloads[PayloadIndex].Channel = Channel;
// Parse key fields from sentence
sscanf( Line + 2, "%15[^,],%u,%8[^,],%lf,%lf,%u",
(Config.Payloads[PayloadIndex].Payload),
&(Config.Payloads[PayloadIndex].Counter),
(Config.Payloads[PayloadIndex].Time),
&(Config.Payloads[PayloadIndex].Latitude),
&(Config.Payloads[PayloadIndex].Longitude),
&(Config.Payloads[PayloadIndex].Altitude));
// Mark when this was received, so we can time-out old payloads
Config.Payloads[PayloadIndex].LastPacketAt = time(NULL);
// Ascent rate
DoPositionCalcs(PayloadIndex);
// Update display
ChannelPrintf(Channel, 4, 1, "%8.5lf, %8.5lf, %05u ",
Config.Payloads[PayloadIndex].Latitude,
Config.Payloads[PayloadIndex].Longitude,
Config.Payloads[PayloadIndex].Altitude);
}
void ProcessTelemetryMessage( int Channel, char *Message)
void ProcessTelemetryMessage(int Channel, char *Message)
{
if ( strlen( Message + 1 ) < 250 )
if (strlen(Message + 1) < 250)
{
char *startmessage, *endmessage;
@ -897,9 +935,6 @@ void ProcessTelemetryMessage( int Channel, char *Message)
*startmessage = '$';
}
strcpy( Config.LoRaDevices[Channel].Telemetry, startmessage );
// UploadTelemetryPacket(startmessage);
ProcessLine(Channel, startmessage);
now = time( 0 );
@ -939,8 +974,6 @@ void ProcessTelemetryMessage( int Channel, char *Message)
endmessage = strchr( startmessage, '\n' );
}
DoPositionCalcs( Channel );
Config.LoRaDevices[Channel].LastTelemetryPacketAt = time( NULL );
}
}
@ -1240,7 +1273,7 @@ void DIO0_Interrupt( int Channel )
Config.LoRaDevices[Channel].UnknownCount++;
}
Config.LoRaDevices[Channel].LastPacketAt = time( NULL );
// Config.LoRaDevices[Channel].LastPacketAt = time( NULL );
if (Config.LoRaDevices[Channel].InCallingMode && (Config.CallingTimeout > 0))
{
@ -1979,7 +2012,7 @@ rjh_post_message( int Channel, char *buffer )
Config.LoRaDevices[Channel].UnknownCount++;
}
Config.LoRaDevices[Channel].LastPacketAt = time( NULL );
// Config.LoRaDevices[Channel].LastPacketAt = time( NULL );
ShowPacketCounts( Channel );
}

Wyświetl plik

@ -2,7 +2,26 @@
#define RUNNING 1 // The main program is running
#define STOPPED 0 // The main program has stopped
struct TLoRaDevice {
#define MAX_PAYLOADS 32
struct TPayload
{
int InUse;
int Channel;
time_t LastPacketAt;
char Telemetry[256];
char Payload[32];
char Time[12];
unsigned int Counter, LastCounter;
double Longitude, Latitude;
unsigned int Altitude, PreviousAltitude;
float AscentRate;
unsigned long LastPositionAt;
}; struct TLoRaDevice {
double Frequency;
double Bandwidth;
double CurrentBandwidth;
@ -22,25 +41,16 @@
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;
// unsigned long Seconds;
// double PredictedLongitude, PredictedLatitude;
// unsigned int Satellites;
time_t LastSSDVPacketAt, LastTelemetryPacketAt;
time_t ReturnToCallingModeAt;
time_t ReturnToOriginalFrequencyAt;
int InCallingMode;
int ActivityLED;
double UplinkFrequency;
int UplinkMode;
int Speed, Heading, PredictedTime, CompassActual, CompassTarget, AirDirection, ServoLeft, ServoRight, ServoTime, FlightMode;
double cda, PredictedLandingSpeed, AirSpeed, GlideRatio;
// Normal (non TDM) uplink
int UplinkTime;
@ -58,7 +68,8 @@
char ftpUser[32];
char ftpPassword[32];
char ftpFolder[64];
struct TLoRaDevice LoRaDevices[2];
struct TLoRaDevice LoRaDevices[2];
struct TPayload Payloads[MAX_PAYLOADS];
int NetworkLED;
int InternetLED;
int ServerPort; // JSON port for telemetry, settings

Wyświetl plik

@ -29,15 +29,13 @@ extern pthread_mutex_t var;
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;
@ -46,12 +44,9 @@ hash_to_hex( unsigned char *hash, char *line )
sprintf( &( line[idx * 2] ), "%02x", hash[idx] );
}
line[64] = '\0';
// LogMessage(line);
}
void
UploadTelemetryPacket( telemetry_t * t )
void UploadTelemetryPacket( telemetry_t * t )
{
CURL *curl;
CURLcode res;
@ -72,8 +67,8 @@ UploadTelemetryPacket( telemetry_t * t )
struct curl_slist *headers = NULL;
time_t rawtime;
struct tm *tm;
int retries;
long int http_resp;
int retries;
long int http_resp;
// Get formatted timestamp
time( &rawtime );
@ -119,59 +114,59 @@ UploadTelemetryPacket( telemetry_t * t )
// 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");
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" );
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 );
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);
retries = 0;
do {
// Perform the request, res will get the return code
res = curl_easy_perform( curl );
// Check for errors
if ( res == CURLE_OK )
retries = 0;
do
{
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp);
if (http_resp != 201 && http_resp != 403 && http_resp != 409)
// Perform the request, res will get the return code
res = curl_easy_perform( curl );
// Check for errors
if ( res == CURLE_OK )
{
LogMessage("Unexpected HTTP response %ld for URL '%s'\n", http_resp, url);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp);
if (http_resp != 201 && http_resp != 403 && http_resp != 409)
{
LogMessage("Unexpected HTTP response %ld for URL '%s'\n", http_resp, url);
}
}
}
else
{
http_resp = 0;
LogMessage( "Failed for URL '%s'\n", url );
LogMessage( "curl_easy_perform() failed: %s\n",
curl_easy_strerror( res ) );
LogMessage( "error: %s\n", curl_error );
}
} while ((http_resp == 409) && (++retries < 5));
else
{
http_resp = 0;
LogMessage("Failed for URL '%s'\n", url);
LogMessage("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
LogMessage("error: %s\n", curl_error);
}
if (http_resp == 409)
{
// conflict between us and another uploader at the same time
// wait for a random period before trying again
delay(random() & 255); // 0-255 ms
}
} while ((http_resp == 409) && (++retries < 5));
// always cleanup
curl_slist_free_all( headers );
curl_easy_cleanup( curl );
// free(base64_data);
}
}
void *
HabitatLoop( void *vars )
void *HabitatLoop( void *vars )
{
if ( Config.EnableHabitat )

Wyświetl plik

@ -80,63 +80,35 @@ void ProcessJSONClientLine(int connfd, char *line)
int SendJSON(int connfd)
{
int Channel, port_closed;
int PayloadIndex, port_closed;
char sendBuff[1025];
port_closed = 0;
memset( sendBuff, '0', sizeof( sendBuff ) );
for (Channel=0; Channel<=1; Channel++)
for (PayloadIndex=0; PayloadIndex<MAX_PAYLOADS; PayloadIndex++)
{
if ( Config.EnableDev )
if (Config.Payloads[PayloadIndex].InUse)
{
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\",\"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,
Config.LoRaDevices[Channel].Longitude,
Config.LoRaDevices[Channel].Altitude,
Config.LoRaDevices[Channel].AscentRate);
}
sprintf(sendBuff, "{\"class\":\"POSN\",\"index\":%d,\"channel\":%d,\"payload\":\"%s\",\"time\":\"%s\",\"lat\":%.5lf,\"lon\":%.5lf,\"alt\":%d,\"rate\":%.1lf}\r\n",
PayloadIndex,
Config.Payloads[PayloadIndex].Channel,
Config.Payloads[PayloadIndex].Payload,
Config.Payloads[PayloadIndex].Time,
Config.Payloads[PayloadIndex].Latitude,
Config.Payloads[PayloadIndex].Longitude,
Config.Payloads[PayloadIndex].Altitude,
Config.Payloads[PayloadIndex].AscentRate);
if ( !run )
{
port_closed = 1;
}
else if ( send(connfd, sendBuff, strlen(sendBuff), MSG_NOSIGNAL ) <= 0 )
{
LogMessage( "Disconnected from client\n" );
port_closed = 1;
if ( !run )
{
port_closed = 1;
}
else if ( send(connfd, sendBuff, strlen(sendBuff), MSG_NOSIGNAL ) <= 0 )
{
LogMessage( "Disconnected from client\n" );
port_closed = 1;
}
}
}