V1.10.0 - Removed all Habitat/HABHUB support

master
Dave Akerman 2023-01-05 12:49:16 +00:00
rodzic 2afab21f05
commit 76638b8c2b
8 zmienionych plików z 8 dodań i 414 usunięć

Wyświetl plik

@ -1,7 +1,9 @@
Habitat LoRa Gateway
====================
Part of the LoRa Balloon Tracking System
Part of the LoRa Balloon Tracking System. Receives balloon telemetry and uploads to Sondehub and/or MQTT.
** ALL HABHUB SUPPORT HAS BEEN REMOVED since the server has been decommissioned **
Runs on a Raspberry Pi with 1 or 2 RFM98HW modules attached to the SPI port.
Also works with other compatible HopeRF and Semtec LoRa devices.
@ -92,8 +94,7 @@ Configuration
The configuration is in the file gateway.txt. Example:
tracker=M0RPI
EnableHabitat=N
EnableSondehub=N
EnableSondehub=Y
EnableSSDV=Y
LogTelemetry=Y
LogPackets=Y

Wyświetl plik

@ -10,15 +10,13 @@ Antenna=Your antenna
##### Config Options #####
EnableHabitat=Y
EnableSondehub=Y
EnableSSDV=Y
JPGFolder=ssdv
LogTelemetry=Y
LogPackets=Y
CallingTimeout=60
ServerPort=6004
#SMSFolder=./
EnableDev=N
NetworkLED=22
InternetLED=23

Wyświetl plik

@ -32,7 +32,6 @@
#include "base64.h"
#include "ssdv.h"
#include "ftp.h"
#include "habitat.h"
#include "sondehub.h"
#include "mqtt.h"
#include "network.h"
@ -42,12 +41,11 @@
#include "gateway.h"
#include "config.h"
#include "gui.h"
#include "listener.h"
#include "habpack.h"
#include "udpclient.h"
#include "lifo_buffer.h"
#define VERSION "V1.9.6"
#define VERSION "V1.10.0"
bool run = TRUE;
// RFM98
@ -196,7 +194,6 @@ struct TBinaryPacket {
#pragma pack(pop)
lifo_buffer_t Habitat_Upload_Buffer;
lifo_buffer_t MQTT_Upload_Buffer;
// Create pipes for inter proces communication
@ -1143,22 +1140,6 @@ int ProcessTelemetryMessage(int Channel, received_t *Received)
strcpy(Config.LoRaDevices[Channel].Telemetry, startmessage);
Config.LoRaDevices[Channel].TelemetryCount++;
if (Config.EnableHabitat)
{
// Add to Habitat upload queue
received_t *queueReceived = malloc(sizeof(received_t));
if(queueReceived != NULL)
{
strcpy(Received->HabitatString, startmessage);
memcpy(queueReceived, Received, sizeof(received_t));
/* We haven't copied the linked list, this'll be free()ed later, so remove pointer */
queueReceived->Telemetry.habpack_extra = NULL;
/* Push pointer onto upload queue */
lifo_buffer_push(&Habitat_Upload_Buffer, (void *)queueReceived);
}
}
if (Config.EnableMQTT)
{
// Add to MQTT upload queue
@ -2059,7 +2040,6 @@ void LoadConfigFile(void)
LogMessage( "Tracker = '%s'\n", Config.Tracker );
// Enable uploads
RegisterConfigBoolean(MainSection, -1, "EnableHabitat", &Config.EnableHabitat, NULL);
RegisterConfigBoolean(MainSection, -1, "EnableSSDV", &Config.EnableSSDV, NULL);
RegisterConfigBoolean(MainSection, -1, "EnableSondehub", &Config.EnableSondehub, NULL);
@ -2316,7 +2296,7 @@ WINDOW *InitDisplay(void)
char buffer[80];
sprintf( buffer, "LoRa Habitat and SSDV Gateway by M0RPI, M0DNY, M0RJX - " VERSION);
sprintf( buffer, "LoRa HAB Sondehub, SSDV and MQTT Gateway by M0RPI, M0DNY, M0RJX - " VERSION);
// Title bar
mvaddstr(0, ( 80 - strlen( buffer ) ) / 2, buffer );
@ -2656,7 +2636,7 @@ int main( int argc, char **argv )
int ch;
int LoopPeriod, MSPerLoop;
int Channel;
pthread_t SSDVThread, FTPThread, NetworkThread, HabitatThread, SondehubThread, ServerThread, TelnetThread, ListenerThread, DataportThread, ChatportThread, MQTTThread;
pthread_t SSDVThread, FTPThread, NetworkThread, SondehubThread, ServerThread, TelnetThread, DataportThread, ChatportThread, MQTTThread;
struct TServerInfo JSONInfo, TelnetInfo, DataportInfo, ChatportInfo;
atexit(bye);
@ -2742,17 +2722,6 @@ int main( int argc, char **argv )
return 1;
}
if (Config.EnableHabitat)
{
lifo_buffer_init(&Habitat_Upload_Buffer, 1024);
if ( pthread_create (&HabitatThread, NULL, HabitatLoop, NULL))
{
fprintf( stderr, "Error creating Habitat thread\n" );
return 1;
}
}
if (Config.EnableMQTT)
{
lifo_buffer_init(&MQTT_Upload_Buffer, 1024);
@ -2843,15 +2812,6 @@ int main( int argc, char **argv )
}
}
if (( Config.latitude >= -90) && (Config.latitude <= 90) && (Config.longitude >= -180) && (Config.longitude <= 180))
{
if ( pthread_create( &ListenerThread, NULL, ListenerLoop, NULL ) )
{
fprintf( stderr, "Error creating Listener thread\n" );
return 1;
}
}
// Initializes the structure used for storing calling mode settings
callingModeSettings[0].Channel = -1;
callingModeSettings[1].Channel = -1;
@ -3004,9 +2964,6 @@ int main( int argc, char **argv )
LogMessage( "Stopping SSDV thread\n" );
stsv.parent_status = STOPPED;
LogMessage( "Stopping Habitat thread\n" );
lifo_buffer_quitwait(&Habitat_Upload_Buffer);
if (Config.EnableSSDV)
{
LogMessage( "Waiting for SSDV thread to close ...\n" );
@ -3014,15 +2971,6 @@ int main( int argc, char **argv )
LogMessage( "SSDV thread closed\n" );
}
if (Config.EnableHabitat)
{
LogMessage( "Waiting for Habitat thread to close ...\n" );
pthread_join( HabitatThread, NULL );
LogMessage( "Habitat thread closed\n" );
}
// CloseDisplay( mainwin );
pthread_mutex_destroy( &var );
curl_global_cleanup( ); // RJH thread safe

Wyświetl plik

@ -115,7 +115,6 @@ struct TConfig
char Tracker[16]; // Callsign or name of receiver
double latitude, longitude, altitude; // Receiver's location
int EnableHabitat;
int EnableSSDV;
int EnableHablink;
int EnableSondehub;

228
habitat.c
Wyświetl plik

@ -1,228 +0,0 @@
#include <unistd.h>
#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 <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#include <dirent.h>
#include <math.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"
#include "lifo_buffer.h"
extern lifo_buffer_t Habitat_Upload_Buffer;
extern int telem_pipe_fd[2];
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 )
{
// LogMessage("%s\n", (char *)buffer);
return size * nmemb;
}
void hash_to_hex( unsigned char *hash, char *line )
{
int idx;
for ( idx = 0; idx < 32; idx++ )
{
sprintf( &( line[idx * 2] ), "%02x", hash[idx] );
}
line[64] = '\0';
}
bool UploadTelemetryPacket( received_t * t )
{
CURL *curl;
CURLcode res;
char curl_error[CURL_ERROR_SIZE];
/* get a curl handle */
curl = curl_easy_init( );
if ( curl )
{
bool result;
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], doc_time[32];
char Sentence[512];
struct curl_slist *headers = NULL;
time_t rawtime;
struct tm *tm, *doc_tm;
int retries;
long int http_resp;
// Get formatted timestamp for now
time( &rawtime );
tm = gmtime( &rawtime );
strftime( now, sizeof( now ), "%Y-%0m-%0dT%H:%M:%SZ", tm );
// Get formatted timestamp for doc timestamp
doc_tm = gmtime( &t->Metadata.Timestamp );
strftime( doc_time, sizeof( doc_time ), "%Y-%0m-%0dT%H:%M:%SZ", doc_tm );
// Grab current telemetry string and append a linefeed
sprintf(Sentence, "%s\n", t->HabitatString);
// 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\",\"rig_info\": {\"frequency\":%.0f}}}}",
base64_data, Config.Tracker, doc_time, now, (t->Metadata.Frequency + t->Metadata.FrequencyError) * 1000000 );
// 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);
// 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 );
// 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);
retries = 0;
do
{
// Perform the request, res will get the return code
res = curl_easy_perform( curl );
// Check for errors
if ( res == CURLE_OK )
{
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);
result = false;
}
else
{
/* Everything performing nominally (even if we didn't successfully insert this time) */
result = true;
}
}
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);
/* Likely a network error, so return false to requeue */
result = false;
}
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 );
return result;
}
else
{
/* CURL error, return false so we requeue */
return false;
}
}
void *HabitatLoop( void *vars )
{
if ( Config.EnableHabitat )
{
received_t *dequeued_telemetry_ptr;
// Keep looping until the parent quits
while ( true )
{
dequeued_telemetry_ptr = lifo_buffer_waitpop(&Habitat_Upload_Buffer);
if(dequeued_telemetry_ptr != NULL)
{
ChannelPrintf( dequeued_telemetry_ptr->Metadata.Channel, 6, 1, "Habitat (%d queued)", lifo_buffer_queued(&Habitat_Upload_Buffer) );
if(UploadTelemetryPacket( dequeued_telemetry_ptr ))
{
ChannelPrintf( dequeued_telemetry_ptr->Metadata.Channel, 6, 1, " " );
free(dequeued_telemetry_ptr);
}
else
{
/* Network / CURL Error, requeue packet */
ChannelPrintf( dequeued_telemetry_ptr->Metadata.Channel, 6, 1, "Habitat Net Error! " );
if(!lifo_buffer_requeue(&Habitat_Upload_Buffer, dequeued_telemetry_ptr))
{
/* Requeue failed, drop packet */
free(dequeued_telemetry_ptr);
}
}
}
else
{
/* NULL returned: We've been asked to quit */
/* Don't bother free()ing stuff, as application is quitting */
break;
}
}
}
return NULL;
}

Wyświetl plik

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

Wyświetl plik

@ -1,122 +0,0 @@
#include <stdio.h>
#include <wiringPi.h>
#include <curl/curl.h>
#include "global.h"
#include "gateway.h"
#define LISTENER_UPDATE_INTERVAL 30 // Minutes
#define LISTENER_LOOP_SLEEP 1000 // Milliseconds
size_t write_data( void *buffer, size_t size, size_t nmemb, void *userp )
{
return size * nmemb;
}
void UploadListenerTelemetry( char *callsign, time_t gps_time, float gps_lat, float gps_lon, char *radio, char *antenna )
{
char time_string[20];
struct tm * time_info;
time_info = localtime (&gps_time);
strftime(time_string, sizeof(time_string), "%H:%M:%S", time_info);
if ( Config.EnableHabitat )
{
CURL *curl;
CURLcode res;
char PostFields[300];
char JsonData[200];
/* In windows, this will init the winsock stuff */
/* get a curl handle */
curl = curl_easy_init( );
if ( curl )
{
// So that the response to the curl POST doesn;'t mess up my finely crafted display!
curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, write_data );
// Set the URL that is about to receive our POST
curl_easy_setopt( curl, CURLOPT_URL,
"http://habitat.habhub.org/transition/listener_telemetry" );
// Now specify the POST data
sprintf( JsonData, "{\"latitude\": %f, \"longitude\": %f}",
gps_lat, gps_lon );
sprintf( PostFields, "callsign=%s&time=%d&data=%s", callsign,
(int)gps_time, JsonData );
curl_easy_setopt( curl, CURLOPT_POSTFIELDS, PostFields );
// Perform the request, res will get the return code
res = curl_easy_perform( curl );
// Check for errors
if ( res == CURLE_OK )
{
LogMessage( "Uploaded listener %s %s,%f,%f\n",
callsign, time_string, gps_lat, gps_lon );
}
else
{
LogMessage( "curl_easy_perform() failed: %s\n",
curl_easy_strerror( res ) );
}
// always cleanup
curl_easy_cleanup( curl );
}
/* In windows, this will init the winsock stuff */
/* get a curl handle */
curl = curl_easy_init( );
if ( curl )
{
// So that the response to the curl POST doesn;'t mess up my finely crafted display!
curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, write_data );
// Set the URL that is about to receive our POST
curl_easy_setopt( curl, CURLOPT_URL,
"http://habitat.habhub.org/transition/listener_information" );
// Now specify the POST data
sprintf( JsonData, "{\"radio\": \"%s\", \"antenna\": \"%s\"}",
radio, antenna );
sprintf( PostFields, "callsign=%s&time=%d&data=%s", callsign, (int)gps_time, JsonData );
curl_easy_setopt( curl, CURLOPT_POSTFIELDS, PostFields );
// Perform the request, res will get the return code
res = curl_easy_perform( curl );
// Check for errors
if ( res != CURLE_OK )
{
LogMessage( "curl_easy_perform() failed: %s\n",
curl_easy_strerror( res ) );
}
// always cleanup
curl_easy_cleanup( curl );
}
}
}
void *ListenerLoop(void *ptr)
{
(void) ptr;
uint32_t LoopPeriod = LISTENER_UPDATE_INTERVAL*60*1000; // So we upload listener at start, as well as every LISTENER_UPDATE_INTERVAL minutes thereafter
while (1)
{
if (LoopPeriod > LISTENER_UPDATE_INTERVAL*60*1000)
{
UploadListenerTelemetry( Config.Tracker, time(NULL), Config.latitude, Config.longitude, Config.radio, Config.antenna );
LoopPeriod = 0;
}
delay(LISTENER_LOOP_SLEEP);
LoopPeriod += LISTENER_LOOP_SLEEP;
}
}

Wyświetl plik

@ -1 +0,0 @@
void *ListenerLoop(void *ptr);