kopia lustrzana https://github.com/PiInTheSky/lora-gateway
Merge branch 'master' of https://github.com/PiInTheSky/lora-gateway
Conflicts: habitat.cpull/27/head
commit
6015f3be7d
30
*.dpa
30
*.dpa
|
@ -1,30 +0,0 @@
|
|||
tracker=LCARS
|
||||
EnableHabitat=N
|
||||
EnableSSDV=N
|
||||
LogTelemetry=Y
|
||||
LogPackets=Y
|
||||
CallingTimeout=60
|
||||
ServerPort=6004
|
||||
Latitude=51.950230
|
||||
Longitude=-2.544500
|
||||
Antenna=MagMount
|
||||
JPGFolder=SSDV
|
||||
EnableDev=N
|
||||
|
||||
#NetworkLED=21
|
||||
#InternetLED=22
|
||||
#ActivityLED_0=23
|
||||
#ActivityLED_1=24
|
||||
|
||||
frequency_0=434.450000
|
||||
mode_0=1
|
||||
#mode_0=1
|
||||
DIO0_0=6
|
||||
DIO5_0=5
|
||||
AFC_0=N
|
||||
|
||||
frequency_1=869.850000
|
||||
mode_1=3
|
||||
DIO0_1=27
|
||||
DIO5_1=26
|
||||
AFC_1=N
|
16
README.md
16
README.md
|
@ -226,6 +226,22 @@ Many thanks to David Brooke for coding this feature and the AFC.
|
|||
Change History
|
||||
==============
|
||||
|
||||
27/09/2016 - V1.8.5
|
||||
-------------------
|
||||
|
||||
New config setting - AFCMaxStep - limits AFC delta to this amount in kHz for each new packet
|
||||
New config setting - AFCTimeout - Resets AFC changes if no packets received in this period (in seconds)
|
||||
If gateway.txt missing, and gateway-sample.txt present, rename latter as former
|
||||
Fixed SSDV upload status marker
|
||||
Fix to frequency format when retuning after calling mode
|
||||
Some log display messages now only appear if the feature they describe is in use
|
||||
|
||||
|
||||
15/09/2016 - V1.8.4
|
||||
-------------------
|
||||
|
||||
Fix to handle disabled channel
|
||||
|
||||
14/09/2016 - V1.8.3
|
||||
-------------------
|
||||
|
||||
|
|
229
gateway.c
229
gateway.c
|
@ -14,7 +14,7 @@
|
|||
#include <sys/shm.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdarg.h>
|
||||
#include <pthread.h>
|
||||
#include <curses.h>
|
||||
#include <math.h>
|
||||
|
@ -34,7 +34,7 @@
|
|||
#include "gateway.h"
|
||||
#include "config.h"
|
||||
|
||||
#define VERSION "V1.8.4"
|
||||
#define VERSION "V1.8.5"
|
||||
bool run = TRUE;
|
||||
|
||||
// RFM98
|
||||
|
@ -174,8 +174,6 @@ struct TBinaryPacket {
|
|||
uint16_t Altitude;
|
||||
};
|
||||
|
||||
const char *Modes[6] = { "Slow", "SSDV", "Repeater", "Turbo", "TurboX", "Calling" };
|
||||
|
||||
// Create pipes for inter proces communication
|
||||
// GLOBAL AS CALLED FROM INTERRRUPT
|
||||
int telem_pipe_fd[2];
|
||||
|
@ -458,32 +456,6 @@ void setLoRaMode( int Channel )
|
|||
setFrequency( Channel, Config.LoRaDevices[Channel].Frequency);
|
||||
}
|
||||
|
||||
char *BandwidthString( int Bandwidth )
|
||||
{
|
||||
if ( Bandwidth == BANDWIDTH_7K8 )
|
||||
return "7.8k";
|
||||
if ( Bandwidth == BANDWIDTH_10K4 )
|
||||
return "10.4k";
|
||||
if ( Bandwidth == BANDWIDTH_15K6 )
|
||||
return "15.6k";
|
||||
if ( Bandwidth == BANDWIDTH_20K8 )
|
||||
return "20.8k";
|
||||
if ( Bandwidth == BANDWIDTH_31K25 )
|
||||
return "31.25k";
|
||||
if ( Bandwidth == BANDWIDTH_41K7 )
|
||||
return "41.7k";
|
||||
if ( Bandwidth == BANDWIDTH_62K5 )
|
||||
return "62.5k";
|
||||
if ( Bandwidth == BANDWIDTH_125K )
|
||||
return "125k";
|
||||
if ( Bandwidth == BANDWIDTH_250K )
|
||||
return "250k";
|
||||
if ( Bandwidth == BANDWIDTH_500K )
|
||||
return "500k";
|
||||
return "??k";
|
||||
}
|
||||
|
||||
|
||||
int IntToSF(int Value)
|
||||
{
|
||||
return Value << 4;
|
||||
|
@ -595,7 +567,7 @@ startReceiving( int Channel )
|
|||
void ReTune( int Channel, double FreqShift )
|
||||
{
|
||||
setMode( Channel, RF98_MODE_SLEEP );
|
||||
LogMessage( "Retune by %lf kHz\n", FreqShift * 1000 );
|
||||
LogMessage( "Retune by %.1lfkHz\n", FreqShift * 1000 );
|
||||
setFrequency( Channel, Config.LoRaDevices[Channel].activeFreq + FreqShift );
|
||||
startReceiving( Channel );
|
||||
}
|
||||
|
@ -673,20 +645,15 @@ void ShowPacketCounts(int Channel)
|
|||
ChannelPrintf( Channel, 9, 1, "Bad CRC = %d Bad Type = %d",
|
||||
Config.LoRaDevices[Channel].BadCRCCount,
|
||||
Config.LoRaDevices[Channel].UnknownCount );
|
||||
|
||||
ChannelPrintf( Channel, 6, 16, "SSDV %d ",
|
||||
Config.LoRaDevices[Channel].SSDVCount );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ProcessUploadMessage( int Channel, char *Message )
|
||||
void ProcessUploadMessage(int Channel, char *Message)
|
||||
{
|
||||
// LogMessage("Ch %d: Uploaded message %s\n", Channel, Message);
|
||||
}
|
||||
|
||||
void
|
||||
ProcessCallingMessage( int Channel, char *Message )
|
||||
void ProcessCallingMessage(int Channel, char *Message)
|
||||
{
|
||||
char Payload[16];
|
||||
double Frequency;
|
||||
|
@ -702,7 +669,7 @@ ProcessCallingMessage( int Channel, char *Message )
|
|||
&ErrorCoding,
|
||||
&Bandwidth, &SpreadingFactor, &LowDataRateOptimize ) == 7 )
|
||||
{
|
||||
if ( Config.LoRaDevices[Channel].AFC )
|
||||
if (Config.LoRaDevices[Channel].AFC)
|
||||
{
|
||||
Frequency += (Config.LoRaDevices[Channel].activeFreq - Config.LoRaDevices[Channel].Frequency);
|
||||
}
|
||||
|
@ -726,15 +693,12 @@ ProcessCallingMessage( int Channel, char *Message )
|
|||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
write_data( void *buffer, size_t size, size_t nmemb, void *userp )
|
||||
size_t write_data( void *buffer, size_t size, size_t nmemb, void *userp )
|
||||
{
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
void
|
||||
UploadListenerTelemetry( char *callsign, float gps_lat, float gps_lon,
|
||||
char *antenna )
|
||||
void UploadListenerTelemetry( char *callsign, float gps_lat, float gps_lon, char *antenna )
|
||||
{
|
||||
int time_epoch = ( int ) time( NULL );
|
||||
if ( Config.EnableHabitat )
|
||||
|
@ -821,8 +785,7 @@ UploadListenerTelemetry( char *callsign, float gps_lat, float gps_lon,
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
DoPositionCalcs( Channel )
|
||||
void DoPositionCalcs(Channel)
|
||||
{
|
||||
unsigned long Now;
|
||||
struct tm tm;
|
||||
|
@ -982,8 +945,7 @@ void ProcessTelemetryMessage( int Channel, char *Message)
|
|||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
decode_callsign( char *callsign, uint32_t code )
|
||||
static char *decode_callsign( char *callsign, uint32_t code )
|
||||
{
|
||||
char *c, s;
|
||||
|
||||
|
@ -1216,7 +1178,7 @@ void DIO0_Interrupt( int Channel )
|
|||
if ( Config.LoRaDevices[Channel].Sending )
|
||||
{
|
||||
Config.LoRaDevices[Channel].Sending = 0;
|
||||
LogMessage( "Ch%d: End of Tx\n", Channel );
|
||||
// LogMessage( "Ch%d: End of Tx\n", Channel );
|
||||
|
||||
setLoRaMode( Channel );
|
||||
SetDefaultLoRaParameters( Channel );
|
||||
|
@ -1229,11 +1191,8 @@ void DIO0_Interrupt( int Channel )
|
|||
|
||||
Bytes = receiveMessage( Channel, Message + 1 );
|
||||
|
||||
// hexdump_buffer ("Raw Data", Message, 257);
|
||||
|
||||
|
||||
if ( Bytes > 0 )
|
||||
{
|
||||
{
|
||||
if ( Config.LoRaDevices[Channel].ActivityLED >= 0 )
|
||||
{
|
||||
digitalWrite( Config.LoRaDevices[Channel].ActivityLED, 1 );
|
||||
|
@ -1255,12 +1214,11 @@ void DIO0_Interrupt( int Channel )
|
|||
}
|
||||
else if ( Message[1] == '>' )
|
||||
{
|
||||
LogMessage( "Flight Controller message %d bytes = %s", Bytes,
|
||||
Message + 1 );
|
||||
LogMessage( "Flight Controller message %d bytes = %s\n", Bytes, Message + 1 );
|
||||
}
|
||||
else if ( Message[1] == '*' )
|
||||
{
|
||||
LogMessage( "Uplink Command message %d bytes = %s", Bytes, Message + 1 );
|
||||
LogMessage( "Uplink Command message %d bytes = %s\n", Bytes, Message + 1 );
|
||||
}
|
||||
else if (((Message[1] & 0x7F) == 0x66) || // SSDV JPG format
|
||||
((Message[1] & 0x7F) == 0x67) || // SSDV other formats
|
||||
|
@ -1284,13 +1242,16 @@ void DIO0_Interrupt( int Channel )
|
|||
|
||||
Config.LoRaDevices[Channel].LastPacketAt = time( NULL );
|
||||
|
||||
if ( Config.LoRaDevices[Channel].InCallingMode
|
||||
&& ( Config.CallingTimeout > 0 ) )
|
||||
if (Config.LoRaDevices[Channel].InCallingMode && (Config.CallingTimeout > 0))
|
||||
{
|
||||
Config.LoRaDevices[Channel].ReturnToCallingModeAt =
|
||||
time( NULL ) + Config.CallingTimeout;
|
||||
Config.LoRaDevices[Channel].ReturnToCallingModeAt = time( NULL ) + Config.CallingTimeout;
|
||||
}
|
||||
|
||||
if (!Config.LoRaDevices[Channel].InCallingMode && (Config.LoRaDevices[Channel].AFCTimeout > 0))
|
||||
{
|
||||
Config.LoRaDevices[Channel].ReturnToOriginalFrequencyAt = time(NULL) + Config.LoRaDevices[Channel].AFCTimeout;
|
||||
}
|
||||
|
||||
ShowPacketCounts( Channel );
|
||||
}
|
||||
}
|
||||
|
@ -1313,8 +1274,7 @@ DIO0_Interrupt_1( void )
|
|||
DIO0_Interrupt( 1 );
|
||||
}
|
||||
|
||||
void
|
||||
setupRFM98( int Channel )
|
||||
void setupRFM98( int Channel )
|
||||
{
|
||||
if ( Config.LoRaDevices[Channel].InUse )
|
||||
{
|
||||
|
@ -1354,8 +1314,7 @@ double FrequencyError( int Channel )
|
|||
Temp = Temp - 524288;
|
||||
}
|
||||
|
||||
return -( ( double ) Temp * ( 1 << 24 ) / 32000000.0 ) *
|
||||
( Config.LoRaDevices[Channel].CurrentBandwidth / 500.0 );
|
||||
return -( ( double ) Temp * ( 1 << 24 ) / 32000000.0 ) * (Config.LoRaDevices[Channel].CurrentBandwidth / 500.0);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1407,8 +1366,20 @@ receiveMessage( int Channel, char *message )
|
|||
|
||||
LogPacket(Channel, PacketSNR(Channel), PacketRSSI(Channel), FreqError, Bytes, message[1]);
|
||||
|
||||
if ( Config.LoRaDevices[Channel].AFC && ( fabs( FreqError ) > 0.5 ) )
|
||||
if (Config.LoRaDevices[Channel].AFC && (fabs( FreqError ) > 0.5))
|
||||
{
|
||||
if (Config.LoRaDevices[Channel].MaxAFCStep > 0)
|
||||
{
|
||||
// Limit step to MaxAFCStep
|
||||
if (FreqError > Config.LoRaDevices[Channel].MaxAFCStep)
|
||||
{
|
||||
FreqError = Config.LoRaDevices[Channel].MaxAFCStep;
|
||||
}
|
||||
else if (FreqError < -Config.LoRaDevices[Channel].MaxAFCStep)
|
||||
{
|
||||
FreqError = -Config.LoRaDevices[Channel].MaxAFCStep;
|
||||
}
|
||||
}
|
||||
ReTune( Channel, FreqError / 1000 );
|
||||
}
|
||||
}
|
||||
|
@ -1436,7 +1407,18 @@ void LoadConfigFile(void)
|
|||
{
|
||||
FILE *fp;
|
||||
char *filename = "gateway.txt";
|
||||
char *sample_filename = "gateway-sample.txt";
|
||||
int Channel, MainSection;
|
||||
|
||||
if (access(filename, F_OK) != 0)
|
||||
{
|
||||
LogMessage("%s missing\n", filename);
|
||||
if (access(sample_filename, F_OK) == 0)
|
||||
{
|
||||
LogMessage("Renaming %s as %s\n", sample_filename, filename);
|
||||
rename(sample_filename, filename);
|
||||
}
|
||||
}
|
||||
|
||||
// Default configuration
|
||||
Config.latitude = -999;
|
||||
|
@ -1489,9 +1471,9 @@ void LoadConfigFile(void)
|
|||
RegisterConfigInteger(MainSection, -1, "ActivityLED_0", &Config.LoRaDevices[0].ActivityLED, NULL);
|
||||
RegisterConfigInteger(MainSection, -1, "ActivityLED_1", &Config.LoRaDevices[1].ActivityLED, NULL);
|
||||
|
||||
// Server Port
|
||||
RegisterConfigInteger(MainSection, -1, "ServerPort", &Config.ServerPort, NULL);
|
||||
|
||||
// Socket
|
||||
RegisterConfigInteger(MainSection, -1, "ServerPort", &Config.ServerPort, NULL); // JSON server
|
||||
|
||||
// SSDV Settings
|
||||
RegisterConfigString(MainSection, -1, "JPGFolder", Config.SSDVJpegFolder, sizeof(Config.SSDVJpegFolder), NULL);
|
||||
if ( Config.SSDVJpegFolder[0] )
|
||||
|
@ -1553,12 +1535,17 @@ void LoadConfigFile(void)
|
|||
|
||||
// Uplink
|
||||
RegisterConfigInteger(MainSection, Channel, "UplinkTime", &Config.LoRaDevices[Channel].UplinkTime, NULL);
|
||||
|
||||
RegisterConfigInteger(MainSection, Channel, "UplinkCycle", &Config.LoRaDevices[Channel].UplinkCycle, NULL);
|
||||
LogMessage( "Channel %d UplinkTime %d Uplink Cycle %d\n", Channel, Config.LoRaDevices[Channel].UplinkTime, Config.LoRaDevices[Channel].UplinkCycle);
|
||||
if ((Config.LoRaDevices[Channel].UplinkTime > 0) && (Config.LoRaDevices[Channel].UplinkCycle))
|
||||
{
|
||||
LogMessage( "Channel %d UplinkTime %d Uplink Cycle %d\n", Channel, Config.LoRaDevices[Channel].UplinkTime, Config.LoRaDevices[Channel].UplinkCycle);
|
||||
}
|
||||
|
||||
RegisterConfigInteger(MainSection, Channel, "Power", &Config.LoRaDevices[Channel].Power, NULL);
|
||||
LogMessage( "Channel %d power set to %02Xh\n", Channel, Config.LoRaDevices[Channel].Power );
|
||||
if ((Config.LoRaDevices[Channel].UplinkTime > 0) && (Config.LoRaDevices[Channel].UplinkCycle))
|
||||
{
|
||||
LogMessage( "Channel %d power set to %02Xh\n", Channel, Config.LoRaDevices[Channel].Power );
|
||||
}
|
||||
|
||||
RegisterConfigInteger(MainSection, Channel, "UplinkMode", &Config.LoRaDevices[Channel].UplinkMode, NULL);
|
||||
if (Config.LoRaDevices[Channel].UplinkMode >= 0)
|
||||
|
@ -1608,6 +1595,18 @@ void LoadConfigFile(void)
|
|||
if (Config.LoRaDevices[Channel].AFC)
|
||||
{
|
||||
ChannelPrintf( Channel, 11, 24, "AFC" );
|
||||
|
||||
RegisterConfigDouble(MainSection, Channel, "MaxAFCStep", &Config.LoRaDevices[Channel].MaxAFCStep, NULL);
|
||||
if (Config.LoRaDevices[Channel].MaxAFCStep > 0)
|
||||
{
|
||||
LogMessage("Maximum AFC Step = %.0lfkHz\n", Config.LoRaDevices[Channel].MaxAFCStep);
|
||||
}
|
||||
|
||||
RegisterConfigInteger(MainSection, Channel, "AFCTimeout", &Config.LoRaDevices[Channel].AFCTimeout, NULL);
|
||||
if (Config.LoRaDevices[Channel].AFCTimeout > 0)
|
||||
{
|
||||
LogMessage("AFC Timeout = %.0ds\n", Config.LoRaDevices[Channel].AFCTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear any flags left over from a previous run
|
||||
|
@ -1615,10 +1614,10 @@ void LoadConfigFile(void)
|
|||
}
|
||||
}
|
||||
|
||||
fclose( fp );
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
WINDOW *InitDisplay( void )
|
||||
WINDOW *InitDisplay(void)
|
||||
{
|
||||
WINDOW *mainwin;
|
||||
int Channel;
|
||||
|
@ -1982,13 +1981,6 @@ rjh_post_message( int Channel, char *buffer )
|
|||
|
||||
Config.LoRaDevices[Channel].LastPacketAt = time( NULL );
|
||||
|
||||
if ( Config.LoRaDevices[Channel].InCallingMode
|
||||
&& ( Config.CallingTimeout > 0 ) )
|
||||
{
|
||||
Config.LoRaDevices[Channel].ReturnToCallingModeAt =
|
||||
time( NULL ) + Config.CallingTimeout;
|
||||
}
|
||||
|
||||
ShowPacketCounts( Channel );
|
||||
}
|
||||
}
|
||||
|
@ -1998,9 +1990,10 @@ rjh_post_message( int Channel, char *buffer )
|
|||
int main( int argc, char **argv )
|
||||
{
|
||||
int ch;
|
||||
int LoopPeriod;
|
||||
int LoopPeriod, MSPerLoop;
|
||||
int Channel;
|
||||
pthread_t SSDVThread, FTPThread, NetworkThread, HabitatThread, ServerThread;
|
||||
struct TServerInfo JSONInfo;
|
||||
|
||||
atexit(bye);
|
||||
|
||||
|
@ -2064,6 +2057,7 @@ int main( int argc, char **argv )
|
|||
|
||||
|
||||
LoopPeriod = 0;
|
||||
MSPerLoop = 10;
|
||||
|
||||
// Initialise the vars
|
||||
stsv.parent_status = RUNNING;
|
||||
|
@ -2101,15 +2095,18 @@ int main( int argc, char **argv )
|
|||
|
||||
// RJH close (telem_pipe_fd[0]); // Close the read side of the pipe as we are writing here
|
||||
|
||||
if ( Config.ServerPort > 0 )
|
||||
if (Config.ServerPort > 0)
|
||||
{
|
||||
if ( pthread_create( &ServerThread, NULL, ServerLoop, NULL ) )
|
||||
JSONInfo.Port = Config.ServerPort;
|
||||
JSONInfo.Connected = 0;
|
||||
|
||||
if (pthread_create(&ServerThread, NULL, ServerLoop, (void *)(&JSONInfo)))
|
||||
{
|
||||
fprintf( stderr, "Error creating server thread\n" );
|
||||
fprintf( stderr, "Error creating JSON server thread\n" );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( ( Config.NetworkLED >= 0 ) && ( Config.InternetLED >= 0 ) )
|
||||
{
|
||||
if ( pthread_create( &NetworkThread, NULL, NetworkLoop, NULL ) )
|
||||
|
@ -2139,12 +2136,13 @@ int main( int argc, char **argv )
|
|||
|
||||
while ( run ) // && message_count< 9) // RJH Used for debug
|
||||
{
|
||||
if ( ( ch = getch( ) ) != ERR )
|
||||
// Keypress tests
|
||||
if ((ch = getch()) != ERR )
|
||||
{
|
||||
ProcessKeyPress( ch );
|
||||
}
|
||||
|
||||
/* RJH TEST */
|
||||
// RJH Test mode
|
||||
if ( message_count % 10 == 9 )
|
||||
{
|
||||
if ( file_telem )
|
||||
|
@ -2169,9 +2167,8 @@ int main( int argc, char **argv )
|
|||
message_count++; // We need to increment this here or we will lock
|
||||
}
|
||||
|
||||
|
||||
/* RJH TEST */
|
||||
if ( LoopPeriod > 1000 )
|
||||
|
||||
if (LoopPeriod > 1000)
|
||||
{
|
||||
// Every 1 second
|
||||
time_t now;
|
||||
|
@ -2182,8 +2179,7 @@ int main( int argc, char **argv )
|
|||
|
||||
LoopPeriod = 0;
|
||||
|
||||
|
||||
for ( Channel = 0; Channel <= 1; Channel++ )
|
||||
for (Channel=0; Channel<=1; Channel++)
|
||||
{
|
||||
if ( Config.LoRaDevices[Channel].InUse )
|
||||
{
|
||||
|
@ -2191,11 +2187,7 @@ int main( int argc, char **argv )
|
|||
|
||||
ChannelPrintf( Channel, 12, 1, "Current RSSI = %4d ", CurrentRSSI(Channel));
|
||||
|
||||
// if (Config.LoRaDevices[Channel].LastPacketAt > 0)
|
||||
// {
|
||||
// ChannelPrintf(Channel, 6, 1, "%us since last packet ", (unsigned int)(time(NULL) - Config.LoRaDevices[Channel].LastPacketAt));
|
||||
// }
|
||||
|
||||
// Calling mode timeout?
|
||||
if ( Config.LoRaDevices[Channel].InCallingMode
|
||||
&& ( Config.CallingTimeout > 0 )
|
||||
&& ( Config.LoRaDevices[Channel].ReturnToCallingModeAt > 0 )
|
||||
|
@ -2211,45 +2203,52 @@ int main( int argc, char **argv )
|
|||
SetDefaultLoRaParameters( Channel );
|
||||
|
||||
setMode( Channel, RF98_MODE_RX_CONTINUOUS );
|
||||
|
||||
ChannelPrintf( Channel, 1, 1, "Channel %d %.3lfMHz %s mode", Channel, Config.LoRaDevices[Channel].Frequency, Modes[Config.LoRaDevices[Channel].SpeedMode]);
|
||||
}
|
||||
|
||||
// AFC Timeout ?
|
||||
if (!Config.LoRaDevices[Channel].InCallingMode &&
|
||||
(Config.LoRaDevices[Channel].AFCTimeout > 0) &&
|
||||
(Config.LoRaDevices[Channel].ReturnToOriginalFrequencyAt > 0) &&
|
||||
(time(NULL) > Config.LoRaDevices[Channel].ReturnToOriginalFrequencyAt))
|
||||
{
|
||||
Config.LoRaDevices[Channel].ReturnToOriginalFrequencyAt = 0;
|
||||
|
||||
if ( ( Config.LoRaDevices[Channel].UplinkTime > 0 )
|
||||
&& ( Config.LoRaDevices[Channel].UplinkCycle > 0 ) )
|
||||
LogMessage("AFC timeout - return to original frequency\n");
|
||||
|
||||
setMode(Channel, RF98_MODE_SLEEP);
|
||||
setFrequency(Channel, Config.LoRaDevices[Channel].Frequency);
|
||||
startReceiving(Channel);
|
||||
}
|
||||
|
||||
// Uplink cycle time ?
|
||||
if ((Config.LoRaDevices[Channel].UplinkTime > 0) && (Config.LoRaDevices[Channel].UplinkCycle > 0))
|
||||
{
|
||||
long CycleSeconds;
|
||||
|
||||
CycleSeconds = (tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec ) % Config.LoRaDevices[Channel].UplinkCycle;
|
||||
|
||||
CycleSeconds =
|
||||
( tm->tm_hour * 3600 + tm->tm_min * 60 +
|
||||
tm->tm_sec ) %
|
||||
Config.LoRaDevices[Channel].UplinkCycle;
|
||||
|
||||
if ( CycleSeconds ==
|
||||
Config.LoRaDevices[Channel].UplinkTime )
|
||||
if ( CycleSeconds == Config.LoRaDevices[Channel].UplinkTime )
|
||||
{
|
||||
// LogMessage("%02d:%02d:%02d - Time to send uplink message\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
LogMessage("%02d:%02d:%02d - Time to send uplink message\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
|
||||
SendUplinkMessage( Channel );
|
||||
}
|
||||
}
|
||||
|
||||
if ( LEDCounts[Channel]
|
||||
&& ( Config.LoRaDevices[Channel].ActivityLED >= 0 ) )
|
||||
// LEDs
|
||||
if (LEDCounts[Channel] && ( Config.LoRaDevices[Channel].ActivityLED >= 0))
|
||||
{
|
||||
if ( --LEDCounts[Channel] == 0 )
|
||||
{
|
||||
digitalWrite( Config.LoRaDevices[Channel].
|
||||
ActivityLED, 0 );
|
||||
digitalWrite(Config.LoRaDevices[Channel].ActivityLED, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delay( 10 );
|
||||
LoopPeriod += 10;
|
||||
delay(MSPerLoop);
|
||||
LoopPeriod += MSPerLoop;
|
||||
}
|
||||
|
||||
LogMessage("Disabling DIO0 ISRs\n");
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
tracker=LCARS
|
||||
EnableHabitat=N
|
||||
EnableSSDV=N
|
||||
LogTelemetry=Y
|
||||
LogPackets=Y
|
||||
CallingTimeout=60
|
||||
ServerPort=6004
|
||||
Latitude=51.950230
|
||||
Longitude=-2.544500
|
||||
Antenna=MagMount
|
||||
JPGFolder=SSDV
|
||||
EnableDev=N
|
||||
|
||||
#NetworkLED=21
|
||||
#InternetLED=22
|
||||
#ActivityLED_0=23
|
||||
#ActivityLED_1=24
|
||||
|
||||
frequency_0=434.450000
|
||||
mode_0=0
|
||||
#frequency_0=434.447
|
||||
#mode_0=1
|
||||
DIO0_0=6
|
||||
DIO5_0=5
|
||||
AFC_0=N
|
||||
|
||||
frequency_1=869.850000
|
||||
mode_1=3
|
||||
#bandwidth_1=125K
|
||||
#implicit_1=n
|
||||
#coding_1=5
|
||||
DIO0_1=27
|
||||
DIO5_1=26
|
||||
AFC_1=N
|
134
global.h
134
global.h
|
@ -2,83 +2,70 @@
|
|||
|
||||
#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
{
|
||||
double Frequency;
|
||||
double Bandwidth;
|
||||
double CurrentBandwidth;
|
||||
int InUse;
|
||||
int DIO0;
|
||||
int DIO5;
|
||||
double activeFreq;
|
||||
int AFC;
|
||||
int SpeedMode;
|
||||
int Power;
|
||||
int PayloadLength;
|
||||
int ImplicitOrExplicit;
|
||||
int ErrorCoding;
|
||||
int SpreadingFactor;
|
||||
int LowDataRateOptimize;
|
||||
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 InUse;
int DIO0;
int DIO5;
double activeFreq;
|
||||
|
||||
int AFC; // Enable Automatic Frequency Control
|
||||
double MaxAFCStep; // Maximum adjustment, in kHz, per packet
|
||||
int AFCTimeout; // Revert to original frequency if no packets for this period (in seconds)
|
||||
|
||||
int SpeedMode;
|
||||
int Power;
|
||||
int PayloadLength;
|
||||
int ImplicitOrExplicit;
|
||||
int ErrorCoding;
|
||||
int SpreadingFactor;
|
||||
int LowDataRateOptimize;
|
||||
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;
|
||||
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;
|
||||
|
||||
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;
|
||||
int UplinkCycle;
|
||||
|
||||
// SSDV Packet Log
|
||||
struct TSSDVPackets SSDVPackets[3];
|
||||
};
|
||||
// Normal (non TDM) uplink
|
||||
int UplinkTime;
|
||||
int UplinkCycle;
|
||||
};
|
||||
struct TConfig
{
char Tracker[16]; // Callsign or name of receiver
|
||||
double latitude, longitude; // Receiver's location
|
||||
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;
|
||||
char SMSFolder[64];
|
||||
char antenna[64];
|
||||
int EnableDev;
|
||||
};
|
||||
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; // JSON port for telemetry, settings
|
||||
char SMSFolder[64];
|
||||
char antenna[64];
|
||||
int EnableDev;
|
||||
};
|
||||
typedef struct {
|
||||
int parent_status;
|
||||
unsigned long packet_count;
|
||||
|
@ -95,6 +82,13 @@ typedef struct {
|
|||
char SSDV_Packet[257];
|
||||
int Packet_Number;
|
||||
} ssdv_t;
|
||||
|
||||
struct TServerInfo
|
||||
{
|
||||
int Port;
|
||||
int Connected;
|
||||
int sockfd;
|
||||
};
|
||||
|
||||
extern struct TConfig Config;
|
||||
extern int SSDVSendArrayIndex;
|
||||
|
|
222
server.c
222
server.c
|
@ -23,13 +23,12 @@
|
|||
#include "global.h"
|
||||
|
||||
extern bool run;
|
||||
extern bool server_closed;
|
||||
|
||||
void ProcessClientLine(int connfd, char *line)
|
||||
void ProcessJSONClientLine(int connfd, char *line)
|
||||
{
|
||||
line[strcspn(line, "\r\n")] = '\0'; // Get rid of CR LF
|
||||
|
||||
LogMessage("Received %s from client\n", line);
|
||||
LogMessage("Received %s from JSON client\n", line);
|
||||
|
||||
if (strchr(line, '=') == NULL)
|
||||
{
|
||||
|
@ -79,140 +78,165 @@ void ProcessClientLine(int connfd, char *line)
|
|||
}
|
||||
}
|
||||
|
||||
int SendJSON(int connfd)
|
||||
{
|
||||
int Channel, port_closed;
|
||||
char sendBuff[1025];
|
||||
|
||||
port_closed = 0;
|
||||
memset( sendBuff, '0', sizeof( sendBuff ) );
|
||||
|
||||
for (Channel=0; Channel<=1; Channel++)
|
||||
{
|
||||
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\",\"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);
|
||||
}
|
||||
|
||||
if ( !run )
|
||||
{
|
||||
port_closed = 1;
|
||||
}
|
||||
else if ( send(connfd, sendBuff, strlen(sendBuff), MSG_NOSIGNAL ) <= 0 )
|
||||
{
|
||||
LogMessage( "Disconnected from client\n" );
|
||||
port_closed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return port_closed;
|
||||
}
|
||||
void *ServerLoop( void *some_void_ptr )
|
||||
{
|
||||
int sockfd = 0;
|
||||
struct sockaddr_in serv_addr;
|
||||
struct TServerInfo *ServerInfo;
|
||||
|
||||
ServerInfo = (struct TServerInfo *)some_void_ptr;
|
||||
|
||||
char sendBuff[1025];
|
||||
|
||||
sockfd = socket( AF_INET, SOCK_STREAM, 0 );
|
||||
ServerInfo->sockfd = 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 );
|
||||
serv_addr.sin_port = htons(ServerInfo->Port);
|
||||
|
||||
LogMessage( "Listening on port %d\n", Config.ServerPort );
|
||||
LogMessage( "Listening on JSON port %d\n", ServerInfo->Port);
|
||||
|
||||
if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &( int )
|
||||
{
|
||||
1}, sizeof( int ) ) < 0 )
|
||||
{
|
||||
if (setsockopt(ServerInfo->sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0)
|
||||
{
|
||||
LogMessage( "setsockopt(SO_REUSEADDR) failed" );
|
||||
}
|
||||
|
||||
if ( bind
|
||||
( sockfd, ( struct sockaddr * ) &serv_addr,
|
||||
sizeof( serv_addr ) ) < 0 )
|
||||
if (bind(ServerInfo->sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
|
||||
{
|
||||
LogMessage( "Server failed errno %d\n", errno );
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
listen( sockfd, 10 );
|
||||
listen(ServerInfo->sockfd, 10);
|
||||
|
||||
while ( run )
|
||||
while (run)
|
||||
{
|
||||
int SendEveryMS = 1000;
|
||||
int MSPerLoop=100;
|
||||
int ms, port_closed, connfd;
|
||||
int ms=0;
|
||||
int connfd;
|
||||
|
||||
Config.EnableDev=1;
|
||||
|
||||
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) & ~O_NONBLOCK); // Blocking mode so we wait for a connection
|
||||
fcntl(ServerInfo->sockfd, F_SETFL, fcntl(ServerInfo->sockfd, F_GETFL) & ~O_NONBLOCK); // Blocking mode so we wait for a connection
|
||||
|
||||
connfd = accept( sockfd, ( struct sockaddr * ) NULL, NULL ); // Wait for connection
|
||||
connfd = accept(ServerInfo->sockfd, ( struct sockaddr * ) NULL, NULL ); // Wait for connection
|
||||
|
||||
LogMessage( "Connected to client\n" );
|
||||
LogMessage( "Connected to client\n");
|
||||
ServerInfo->Connected = 1;
|
||||
|
||||
fcntl(connfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK); // Non-blocking, so we don't block on receiving any commands from client
|
||||
fcntl(connfd, F_SETFL, fcntl(ServerInfo->sockfd, F_GETFL) | O_NONBLOCK); // Non-blocking, so we don't block on receiving any commands from client
|
||||
|
||||
for ( port_closed = 0; !port_closed; )
|
||||
while (ServerInfo->Connected)
|
||||
{
|
||||
int Channel;
|
||||
char packet[4096];
|
||||
int bytecount;
|
||||
|
||||
// Listen loop
|
||||
for (ms=0; ms<SendEveryMS; ms+=MSPerLoop)
|
||||
{
|
||||
int bytecount;
|
||||
ms += MSPerLoop;
|
||||
|
||||
// Listen part
|
||||
bytecount = -1;
|
||||
|
||||
while ((bytecount = recv(connfd, packet, sizeof(packet), 0)) > 0)
|
||||
while ((bytecount = recv(connfd, packet, sizeof(packet), 0)) > 0)
|
||||
{
|
||||
char *line, *saveptr;
|
||||
|
||||
packet[bytecount] = 0;
|
||||
|
||||
// JSON server
|
||||
line = strtok_r(packet, "\n", &saveptr);
|
||||
while (line)
|
||||
{
|
||||
char *line, *saveptr;
|
||||
|
||||
packet[bytecount] = 0;
|
||||
|
||||
line = strtok_r(packet, "\n", &saveptr);
|
||||
while (line)
|
||||
ProcessJSONClientLine(connfd, line);
|
||||
line = strtok_r( NULL, "\n", &saveptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (bytecount == 0)
|
||||
{
|
||||
// -1 is no more data, 0 means port closed
|
||||
LogMessage("Disconnected from client\n");
|
||||
ServerInfo->Connected = 0;
|
||||
}
|
||||
|
||||
if (ServerInfo->Connected)
|
||||
{
|
||||
// Send to JSON client
|
||||
if (ms >= SendEveryMS)
|
||||
{
|
||||
if (SendJSON(connfd))
|
||||
{
|
||||
ProcessClientLine(connfd, line);
|
||||
line = strtok_r( NULL, "\n", &saveptr);
|
||||
ServerInfo->Connected = 0;
|
||||
}
|
||||
}
|
||||
|
||||
delay(MSPerLoop);
|
||||
}
|
||||
|
||||
// Send part
|
||||
// Build json
|
||||
|
||||
for (Channel=0; Channel<=1; Channel++)
|
||||
{
|
||||
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\",\"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);
|
||||
}
|
||||
|
||||
if ( !run )
|
||||
{
|
||||
port_closed = 1;
|
||||
}
|
||||
else if ( send(connfd, sendBuff, strlen(sendBuff), MSG_NOSIGNAL ) <= 0 )
|
||||
{
|
||||
LogMessage( "Disconnected from client\n" );
|
||||
port_closed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
delay(MSPerLoop);
|
||||
}
|
||||
|
||||
close( connfd );
|
||||
close(connfd);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
32
ssdv.c
32
ssdv.c
|
@ -66,7 +66,6 @@ UploadImagePacket( ssdv_t * s, unsigned int packets )
|
|||
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 );
|
||||
|
||||
|
@ -90,25 +89,22 @@ UploadImagePacket( ssdv_t * s, unsigned int packets )
|
|||
// 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++ )
|
||||
for (PacketIndex = 0; PacketIndex < packets; PacketIndex++)
|
||||
{
|
||||
base64_encode( s[PacketIndex].SSDV_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 == ( packets - 1 ) ? "" : "," );
|
||||
strcat( json, packet_json );
|
||||
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, "]}" );
|
||||
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;
|
||||
|
@ -144,10 +140,8 @@ UploadImagePacket( ssdv_t * s, unsigned int packets )
|
|||
}
|
||||
}
|
||||
|
||||
void *
|
||||
SSDVLoop( void *vars )
|
||||
void *SSDVLoop( void *vars )
|
||||
{
|
||||
|
||||
if ( Config.EnableSSDV )
|
||||
{
|
||||
const int max_packets = 51;
|
||||
|
@ -185,11 +179,11 @@ SSDVLoop( void *vars )
|
|||
|
||||
if ( j == 50 || ( ( packets == 0 ) && ( j > 0 ) ) )
|
||||
{
|
||||
ChannelPrintf( s[0].Channel, 6, 1, "Habitat" );
|
||||
|
||||
ChannelPrintf(s[0].Channel, 6, 16, "SSDV");
|
||||
|
||||
UploadImagePacket( s, j );
|
||||
|
||||
ChannelPrintf( s[0].Channel, 6, 1, " " );
|
||||
|
||||
ChannelPrintf(s[0].Channel, 6, 16, " ");
|
||||
|
||||
j = 0;
|
||||
|
||||
|
|
204
ssdv_resend.py
204
ssdv_resend.py
|
@ -1,103 +1,101 @@
|
|||
import urllib.parse
|
||||
import urllib.request
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
import sys
|
||||
import os.path
|
||||
import time
|
||||
|
||||
def get_list_of_missing_packets(PayloadID, Minutes):
|
||||
result = ''
|
||||
|
||||
# url = 'http://ssdv.habhub.org/api/v0/images?callsign=PI868&from=2016-01-22T11:00:00Z&missing_packets'
|
||||
time_limit = datetime.utcnow() - timedelta(0,Minutes*60) # n minutes ago
|
||||
url = 'http://ssdv.habhub.org/api/v0/images?callsign=' + PayloadID + '&from=' + time_limit.strftime('%Y-%m-%dT%H:%M:%SZ') + '&missing_packets'
|
||||
|
||||
print("url", url)
|
||||
|
||||
req = urllib.request.Request(url)
|
||||
with urllib.request.urlopen(req) as response:
|
||||
the_page = response.read() # content = urllib.request.urlopen(url=url, data=data).read()
|
||||
# print(the_page)
|
||||
|
||||
temp = the_page.decode('utf-8')
|
||||
j = json.loads(temp)
|
||||
# print(j)
|
||||
|
||||
line = ""
|
||||
for index, item in enumerate(j):
|
||||
# only interested in latest 2 images
|
||||
if index >= (len(j) - 2):
|
||||
# only interested in images that have missing packets
|
||||
if len(item['missing_packets']) > 0:
|
||||
print(item['id'], item['image_id'], len(item['missing_packets']))
|
||||
print(item['missing_packets'])
|
||||
pl = item['packets']
|
||||
# print("highest_packet_id = ", item['last_packet'])
|
||||
first_missing_packet = -1
|
||||
last_missing_packet = -1
|
||||
missing_packets = item['missing_packets'] + [9999]
|
||||
|
||||
# Header for this image
|
||||
if line != "":
|
||||
line = line + ","
|
||||
line = line + str(item['image_id']) + ":" + str(item['last_packet']) + "="
|
||||
image_line = ""
|
||||
|
||||
for mp_index, mp in enumerate(missing_packets):
|
||||
if mp_index == 0:
|
||||
first_missing_packet = mp
|
||||
last_missing_packet = mp
|
||||
|
||||
if (mp > (last_missing_packet+1)): # or (mp_index == len(item['missing_packets'])-1):
|
||||
# emit section
|
||||
if image_line != "":
|
||||
image_line = image_line + ","
|
||||
if last_missing_packet == first_missing_packet:
|
||||
image_line = image_line + str(last_missing_packet)
|
||||
else:
|
||||
image_line = image_line + str(first_missing_packet) + "-" + str(last_missing_packet)
|
||||
first_missing_packet = mp
|
||||
|
||||
last_missing_packet = mp
|
||||
line = line + image_line
|
||||
|
||||
if line != '':
|
||||
result = "!" + line + "\n"
|
||||
|
||||
return result
|
||||
|
||||
|
||||
if len(sys.argv) <= 1:
|
||||
print ("Usage: ssdv_resend <payload_id> [folder]\n")
|
||||
quit()
|
||||
|
||||
payload_id = sys.argv[1]
|
||||
|
||||
if len(sys.argv) >= 3:
|
||||
folder = sys.argv[2]
|
||||
else:
|
||||
folder = './'
|
||||
|
||||
print('Payload = ' + payload_id)
|
||||
print('Folder = ' + folder)
|
||||
|
||||
while True:
|
||||
# if os.path.isfile(folder + 'get_list.txt'):
|
||||
if (datetime.utcnow().second < 0) or (datetime.utcnow().second > 50):
|
||||
print("Checking ...")
|
||||
# os.remove(folder + 'get_list.txt')
|
||||
line = get_list_of_missing_packets(payload_id, 5)
|
||||
if line == '':
|
||||
print("No missing packets")
|
||||
line = "Nothing"
|
||||
else:
|
||||
print("Missing Packets:", line)
|
||||
with open(folder + 'uplink.txt', "w") as text_file:
|
||||
if line != '':
|
||||
print(line, file=text_file)
|
||||
time.sleep(1)
|
||||
else:
|
||||
print('.',end="",flush=True)
|
||||
time.sleep(1)
|
||||
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
import sys
|
||||
import os.path
|
||||
import time
|
||||
|
||||
def get_list_of_missing_packets(PayloadID, Minutes):
|
||||
result = ''
|
||||
|
||||
time_limit = datetime.utcnow() - timedelta(0,Minutes*60) # n minutes ago
|
||||
url = 'http://ssdv.habhub.org/api/v0/images?callsign=' + PayloadID + '&from=' + time_limit.strftime('%Y-%m-%dT%H:%M:%SZ') + '&missing_packets'
|
||||
|
||||
print("url", url)
|
||||
|
||||
req = urllib.request.Request(url)
|
||||
with urllib.request.urlopen(req) as response:
|
||||
the_page = response.read() # content = urllib.request.urlopen(url=url, data=data).read()
|
||||
# print(the_page)
|
||||
|
||||
temp = the_page.decode('utf-8')
|
||||
j = json.loads(temp)
|
||||
# print(j)
|
||||
|
||||
line = ""
|
||||
for index, item in enumerate(j):
|
||||
# only interested in latest 2 images
|
||||
if index >= (len(j) - 2):
|
||||
# only interested in images that have missing packets
|
||||
if len(item['missing_packets']) > 0:
|
||||
print(item['id'], item['image_id'], len(item['missing_packets']))
|
||||
print(item['missing_packets'])
|
||||
pl = item['packets']
|
||||
# print("highest_packet_id = ", item['last_packet'])
|
||||
first_missing_packet = -1
|
||||
last_missing_packet = -1
|
||||
missing_packets = item['missing_packets'] + [9999]
|
||||
|
||||
# Header for this image
|
||||
if line != "":
|
||||
line = line + ","
|
||||
line = line + str(item['image_id']) + ":" + str(item['last_packet']) + "="
|
||||
image_line = ""
|
||||
|
||||
for mp_index, mp in enumerate(missing_packets):
|
||||
if mp_index == 0:
|
||||
first_missing_packet = mp
|
||||
last_missing_packet = mp
|
||||
|
||||
if (mp > (last_missing_packet+1)): # or (mp_index == len(item['missing_packets'])-1):
|
||||
# emit section
|
||||
if image_line != "":
|
||||
image_line = image_line + ","
|
||||
if last_missing_packet == first_missing_packet:
|
||||
image_line = image_line + str(last_missing_packet)
|
||||
else:
|
||||
image_line = image_line + str(first_missing_packet) + "-" + str(last_missing_packet)
|
||||
first_missing_packet = mp
|
||||
|
||||
last_missing_packet = mp
|
||||
line = line + image_line
|
||||
|
||||
result = "!" + line + "\n"
|
||||
|
||||
return result
|
||||
|
||||
|
||||
if len(sys.argv) <= 1:
|
||||
print ("Usage: ssdv_resend <payload_id> [folder]\n")
|
||||
quit()
|
||||
|
||||
payload_id = sys.argv[1]
|
||||
|
||||
if len(sys.argv) >= 3:
|
||||
folder = sys.argv[2]
|
||||
else:
|
||||
folder = './'
|
||||
|
||||
print('Payload = ' + payload_id)
|
||||
print('Folder = ' + folder)
|
||||
|
||||
while True:
|
||||
# if os.path.isfile(folder + 'get_list.txt'):
|
||||
if (datetime.utcnow().second < 0) or (datetime.utcnow().second > 50):
|
||||
print("Checking ...")
|
||||
# os.remove(folder + 'get_list.txt')
|
||||
line = get_list_of_missing_packets(payload_id, 5)
|
||||
if len(line) <= 2:
|
||||
print("No missing packets")
|
||||
else:
|
||||
print("Missing Packets:", line)
|
||||
with open(folder + 'uplink.txt', "w") as text_file:
|
||||
if line != '':
|
||||
print(line, file=text_file)
|
||||
time.sleep(1)
|
||||
else:
|
||||
print('.',end="")
|
||||
sys.stdout.flush()
|
||||
time.sleep(1)
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue