kopia lustrzana https://github.com/PiInTheSky/lora-gateway
Merge branch 'master' of https://github.com/PiInTheSky/lora-gateway
commit
3c8a3a7f39
|
@ -0,0 +1,30 @@
|
||||||
|
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
|
21
README.md
21
README.md
|
@ -226,6 +226,27 @@ Many thanks to David Brooke for coding this feature and the AFC.
|
||||||
Change History
|
Change History
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
14/09/2016 - V1.8.3
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Save boolean settings sent by client
|
||||||
|
Use of atexit() so ncurses is always closed properly on exit
|
||||||
|
Added an exit-with-message function
|
||||||
|
Fixed errors where threads were closed on exit even if they hadn't been created (i.e. their functions disabled in the config)
|
||||||
|
Consistent RSSI calculations that take HF/LF port into account
|
||||||
|
|
||||||
|
|
||||||
|
14/09/2016 - V1.8.2
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Configuration all in a generic array
|
||||||
|
Generic code to read/write config array/file
|
||||||
|
Send configuration values to JSON client
|
||||||
|
Accept commands and new config settings from client
|
||||||
|
Fixed SMS folder error
|
||||||
|
Fixed LDRO setting
|
||||||
|
|
||||||
|
|
||||||
03/09/2016 - V1.8
|
03/09/2016 - V1.8
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,394 @@
|
||||||
|
//// Generalised configuration manager
|
||||||
|
// Generalised configuration manager
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#define MAX_SECTIONS 16
|
||||||
|
#define SECTION_LENGTH 21
|
||||||
|
#define MAX_SETTINGS 256
|
||||||
|
|
||||||
|
char *ConfigFilename;
|
||||||
|
|
||||||
|
int SectionCount=0;
|
||||||
|
char Sections[MAX_SECTIONS][32];
|
||||||
|
|
||||||
|
int SettingsCount=0;
|
||||||
|
struct TSetting Settings[MAX_SETTINGS];
|
||||||
|
|
||||||
|
void RegisterConfigFile(char *Filename)
|
||||||
|
{
|
||||||
|
ConfigFilename = Filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RegisterConfigSection(char *Section)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<SectionCount; i++)
|
||||||
|
{
|
||||||
|
if (strcmp(Section, Sections[i]) == 0)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SectionCount < MAX_SECTIONS)
|
||||||
|
{
|
||||||
|
strcpy(Sections[SectionCount], Section);
|
||||||
|
return SectionCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FindSettingIndex(int SectionIndex, int Index, char *Name)
|
||||||
|
{
|
||||||
|
// Return existing position for this setting, if it's there, or allocate a new one
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<SettingsCount; i++)
|
||||||
|
{
|
||||||
|
if ((Settings[i].SectionIndex == SectionIndex) &&
|
||||||
|
(Settings[i].Index == Index) &&
|
||||||
|
(strcmp(Settings[i].ValueName, Name) == 0))
|
||||||
|
{
|
||||||
|
// Found
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Room for one more on top ?
|
||||||
|
if (SettingsCount < MAX_SETTINGS)
|
||||||
|
{
|
||||||
|
Settings[SettingsCount].SectionIndex = SectionIndex;
|
||||||
|
Settings[SettingsCount].Index = Index;
|
||||||
|
strcpy(Settings[SettingsCount].ValueName, Name);
|
||||||
|
|
||||||
|
return SettingsCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full or can't add, and not found, so return "fail"
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RegisterConfigDouble(int SectionIndex, int Index, char *Name, double *DoubleValuePtr, void (Callback)(int))
|
||||||
|
{
|
||||||
|
if ((SectionIndex >= 0) && (SectionIndex < SectionCount))
|
||||||
|
{
|
||||||
|
int SettingIndex;
|
||||||
|
|
||||||
|
if ((SettingIndex = FindSettingIndex(SectionIndex, Index, Name)) >= 0)
|
||||||
|
{
|
||||||
|
Settings[SettingIndex].SectionIndex = SectionIndex;
|
||||||
|
Settings[SettingIndex].Index = Index;
|
||||||
|
strcpy(Settings[SettingIndex].ValueName, Name);
|
||||||
|
Settings[SettingIndex].SettingType = stDouble;
|
||||||
|
Settings[SettingIndex].DoubleValuePtr = DoubleValuePtr;
|
||||||
|
// Settings[SettingIndex].Callback = Callback;
|
||||||
|
|
||||||
|
ReadConfigValue(SettingIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RegisterConfigInteger(int SectionIndex, int Index, char *Name, int *IntValuePtr, void (Callback)(int))
|
||||||
|
{
|
||||||
|
if ((SectionIndex >= 0) && (SectionIndex < SectionCount))
|
||||||
|
{
|
||||||
|
int SettingIndex;
|
||||||
|
|
||||||
|
if ((SettingIndex = FindSettingIndex(SectionIndex, Index, Name)) >= 0)
|
||||||
|
{
|
||||||
|
Settings[SettingIndex].SectionIndex = SectionIndex;
|
||||||
|
Settings[SettingIndex].Index = Index;
|
||||||
|
strcpy(Settings[SettingIndex].ValueName, Name);
|
||||||
|
Settings[SettingIndex].SettingType = stInteger;
|
||||||
|
Settings[SettingIndex].IntValuePtr = IntValuePtr;
|
||||||
|
// Settings[SettingIndex].Callback = Callback;
|
||||||
|
|
||||||
|
return ReadConfigValue(SettingIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RegisterConfigBoolean(int SectionIndex, int Index, char *Name, int *BoolValuePtr, void (Callback)(int))
|
||||||
|
{
|
||||||
|
if ((SectionIndex >= 0) && (SectionIndex < SectionCount))
|
||||||
|
{
|
||||||
|
int SettingIndex;
|
||||||
|
|
||||||
|
if ((SettingIndex = FindSettingIndex(SectionIndex, Index, Name)) >= 0)
|
||||||
|
{
|
||||||
|
Settings[SettingIndex].SectionIndex = SectionIndex;
|
||||||
|
Settings[SettingIndex].Index = Index;
|
||||||
|
strcpy(Settings[SettingIndex].ValueName, Name);
|
||||||
|
Settings[SettingIndex].SettingType = stBoolean;
|
||||||
|
Settings[SettingIndex].IntValuePtr = BoolValuePtr;
|
||||||
|
// Settings[SettingIndex].Callback = Callback;
|
||||||
|
|
||||||
|
return ReadConfigValue(SettingIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RegisterConfigString(int SectionIndex, int Index, char *Name, char *StringValuePtr, int MaxValueLength, void (Callback)(int))
|
||||||
|
{
|
||||||
|
if ((SectionIndex >= 0) && (SectionIndex < SectionCount))
|
||||||
|
{
|
||||||
|
int SettingIndex;
|
||||||
|
|
||||||
|
if ((SettingIndex = FindSettingIndex(SectionIndex, Index, Name)) >= 0)
|
||||||
|
{
|
||||||
|
Settings[SettingIndex].SectionIndex = SectionIndex;
|
||||||
|
Settings[SettingIndex].Index = Index;
|
||||||
|
strcpy(Settings[SettingIndex].ValueName, Name);
|
||||||
|
Settings[SettingIndex].SettingType = stString;
|
||||||
|
Settings[SettingIndex].StringValuePtr = StringValuePtr;
|
||||||
|
Settings[SettingIndex].MaxValueLength = MaxValueLength;
|
||||||
|
// Settings[SettingIndex].Callback = Callback;
|
||||||
|
|
||||||
|
return ReadConfigValue(SettingIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetLongName(int SettingIndex, char *ValueName, int Length)
|
||||||
|
{
|
||||||
|
struct TSetting *Setting;
|
||||||
|
|
||||||
|
Setting = &(Settings[SettingIndex]);
|
||||||
|
|
||||||
|
// Build string to look for in file
|
||||||
|
if (Setting->Index >= 0)
|
||||||
|
{
|
||||||
|
sprintf(ValueName, "%s%s_%d", Sections[Setting->SectionIndex], Setting->ValueName, Setting->Index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprintf(ValueName, "%s%s", Sections[Setting->SectionIndex], Setting->ValueName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ReadConfigValue(int SettingIndex)
|
||||||
|
{
|
||||||
|
char line[100], ValueName[64], *token, *temp;
|
||||||
|
struct TSetting *Setting;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
GetLongName(SettingIndex, ValueName, sizeof(ValueName));
|
||||||
|
|
||||||
|
Setting = &(Settings[SettingIndex]);
|
||||||
|
|
||||||
|
if ((fp = fopen(ConfigFilename, "r" ) ) != NULL)
|
||||||
|
{
|
||||||
|
while (fgets(line, sizeof(line), fp) != NULL)
|
||||||
|
{
|
||||||
|
line[strcspn(line, "\r")] = '\0'; // Get rid of CR if there is one
|
||||||
|
|
||||||
|
token = strtok(line, "=" );
|
||||||
|
if (strcasecmp(ValueName, token ) == 0)
|
||||||
|
{
|
||||||
|
temp = strtok( NULL, "\n");
|
||||||
|
|
||||||
|
switch (Setting->SettingType)
|
||||||
|
{
|
||||||
|
case stString:
|
||||||
|
strncpy(Setting->StringValuePtr, temp, Setting->MaxValueLength-1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case stInteger:
|
||||||
|
*(Setting->IntValuePtr) = atoi(temp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case stDouble:
|
||||||
|
// So we can handle bandwidths such as "20K8", convert "K" to decimal point
|
||||||
|
if (strchr(temp, 'K') != NULL)
|
||||||
|
{
|
||||||
|
*strchr(temp, 'K') = '.';
|
||||||
|
}
|
||||||
|
*(Setting->DoubleValuePtr) = atof(temp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case stBoolean:
|
||||||
|
*(Setting->IntValuePtr) = (*temp == '1') || (*temp == 'Y') || (*temp == 'y') || (*temp == 't') || (*temp == 'T');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case stNone:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FindSettingByName(char *ValueNameToFind)
|
||||||
|
{
|
||||||
|
char ValueName[64];
|
||||||
|
int SettingIndex;
|
||||||
|
|
||||||
|
for (SettingIndex=0; SettingIndex<SettingsCount; SettingIndex++)
|
||||||
|
{
|
||||||
|
GetLongName(SettingIndex, ValueName, sizeof(ValueName));
|
||||||
|
|
||||||
|
if (strcasecmp(ValueNameToFind, ValueName) == 0)
|
||||||
|
{
|
||||||
|
// Found
|
||||||
|
return SettingIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SaveConfigFile(void)
|
||||||
|
{
|
||||||
|
char line[100], original[100], *token;
|
||||||
|
FILE *src, *dest;
|
||||||
|
struct TSetting *Setting;
|
||||||
|
char *TempFileName="gateway.txt.tmp";
|
||||||
|
char *SavedFileName="gateway.txt.old";
|
||||||
|
int SettingIndex;
|
||||||
|
|
||||||
|
if ((src = fopen(ConfigFilename, "r" ) ) != NULL)
|
||||||
|
{
|
||||||
|
if ((dest = fopen(TempFileName, "w" ) ) != NULL)
|
||||||
|
{
|
||||||
|
while (fgets(line, sizeof(line), src) != NULL)
|
||||||
|
{
|
||||||
|
line[strcspn(line, "\r")] = '\0'; // Get rid of CR if there is one
|
||||||
|
strcpy(original, line);
|
||||||
|
|
||||||
|
token = strtok(line, "=" ); // Name of setting
|
||||||
|
|
||||||
|
if (token == NULL)
|
||||||
|
{
|
||||||
|
// Write old line
|
||||||
|
fputs(original, dest);
|
||||||
|
}
|
||||||
|
else if ((SettingIndex = FindSettingByName(token)) >= 0)
|
||||||
|
{
|
||||||
|
// Found, so write new value instead of old one
|
||||||
|
// tracker=M0RPI/5
|
||||||
|
Setting = &(Settings[SettingIndex]);
|
||||||
|
switch (Setting->SettingType)
|
||||||
|
{
|
||||||
|
case stString:
|
||||||
|
fprintf(dest, "%s=%s\n", token, Setting->StringValuePtr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case stInteger:
|
||||||
|
fprintf(dest, "%s=%d\n", token, *(Setting->IntValuePtr));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case stDouble:
|
||||||
|
fprintf(dest, "%s=%lf\n", token, *(Setting->DoubleValuePtr));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case stBoolean:
|
||||||
|
fprintf(dest, "%s=%c\n", token, *(Setting->IntValuePtr) ? 'Y' : 'N');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case stNone:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Just write old line
|
||||||
|
fputs(original, dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(dest);
|
||||||
|
|
||||||
|
// Now save original file and replace with new one
|
||||||
|
remove(SavedFileName);
|
||||||
|
rename(ConfigFilename, SavedFileName);
|
||||||
|
rename(TempFileName, ConfigFilename);
|
||||||
|
}
|
||||||
|
fclose(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetConfigValue(char *Setting, char *Value)
|
||||||
|
{
|
||||||
|
int SettingIndex;
|
||||||
|
|
||||||
|
if ((SettingIndex = FindSettingByName(Setting)) >= 0)
|
||||||
|
{
|
||||||
|
switch (Settings[SettingIndex].SettingType)
|
||||||
|
{
|
||||||
|
case stString:
|
||||||
|
strncpy(Settings[SettingIndex].StringValuePtr, Value, Settings[SettingIndex].MaxValueLength-1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case stInteger:
|
||||||
|
*Settings[SettingIndex].IntValuePtr = atoi(Value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case stDouble:
|
||||||
|
*Settings[SettingIndex].DoubleValuePtr = atof(Value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case stBoolean:
|
||||||
|
*Settings[SettingIndex].IntValuePtr = Value[strcspn(Value, "1YyTt")];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case stNone:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int SettingAsString(int SettingIndex, char *SettingName, int SettingNameSize, char *SettingValue, int SettingValueSize)
|
||||||
|
{
|
||||||
|
if ((SettingIndex >= 0) && (SettingIndex < SettingsCount))
|
||||||
|
{
|
||||||
|
// strncpy(SettingName, Settings[Index].ValueName, SettingNameSize);
|
||||||
|
|
||||||
|
GetLongName(SettingIndex, SettingName, sizeof(SettingNameSize));
|
||||||
|
|
||||||
|
switch (Settings[SettingIndex].SettingType)
|
||||||
|
{
|
||||||
|
case stString:
|
||||||
|
snprintf(SettingValue, SettingValueSize-1, "\"%s\"", Settings[SettingIndex].StringValuePtr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case stInteger:
|
||||||
|
snprintf(SettingValue, SettingValueSize-1, "%d", *Settings[SettingIndex].IntValuePtr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case stDouble:
|
||||||
|
snprintf(SettingValue, SettingValueSize-1, "%lf", *Settings[SettingIndex].DoubleValuePtr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case stBoolean:
|
||||||
|
snprintf(SettingValue, SettingValueSize-1, "%d", *Settings[SettingIndex].IntValuePtr ? 1 : 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case stNone:
|
||||||
|
strncpy(SettingValue, "\"?\"", SettingValueSize);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
typedef enum {stNone, stString, stInteger, stDouble, stBoolean} TSettingType;
|
||||||
|
|
||||||
|
struct TSetting
|
||||||
|
{
|
||||||
|
int SectionIndex;
|
||||||
|
int Index;
|
||||||
|
char ValueName[32];
|
||||||
|
TSettingType SettingType;
|
||||||
|
char *StringValuePtr;
|
||||||
|
int *IntValuePtr;
|
||||||
|
double *DoubleValuePtr;
|
||||||
|
int MaxValueLength;
|
||||||
|
// void (Callback)(int);
|
||||||
|
};
|
||||||
|
|
||||||
|
void RegisterConfigFile(char *Filename);
|
||||||
|
int RegisterConfigSection(char *Section);
|
||||||
|
int RegisterConfigString(int SectionIndex, int Index, char *Name, char *StringValuePtr, int MaxValueLength, void (Callback)(int));
|
||||||
|
int RegisterConfigInteger(int SectionIndex, int Index, char *Name, int *IntValuePtr, void (Callback)(int));
|
||||||
|
int RegisterConfigDouble(int SectionIndex, int Index, char *Name, double *DoubleValuePtr, void (Callback)(int));
|
||||||
|
int RegisterConfigBoolean(int SectionIndex, int Index, char *Name, int *BoolValuePtr, void (Callback)(int));
|
||||||
|
int ReadConfigValue(int SettingIndex);
|
||||||
|
void SetConfigValue(char *Setting, char *Value);
|
||||||
|
int SettingAsString(int SettingIndex, char *SettingName, int SettingNameSize, char *SettingValue, int SettingValueSize);
|
||||||
|
void SaveConfigFile(void);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
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
|
21
global.h
21
global.h
|
@ -11,23 +11,23 @@
|
||||||
int HighestPacket;
|
int HighestPacket;
|
||||||
bool Packets[1024];
|
bool Packets[1024];
|
||||||
};
|
};
|
||||||
struct TLoRaDevice
{
|
struct TLoRaDevice
{
|
||||||
int InUse;
|
double Frequency;
|
||||||
|
double Bandwidth;
|
||||||
|
double CurrentBandwidth;
|
||||||
|
int InUse;
|
||||||
int DIO0;
|
int DIO0;
|
||||||
int DIO5;
|
int DIO5;
|
||||||
char Frequency[16];
|
|
||||||
double activeFreq;
|
double activeFreq;
|
||||||
bool AFC;
|
int AFC;
|
||||||
int SpeedMode;
|
int SpeedMode;
|
||||||
int Power;
|
int Power;
|
||||||
int PayloadLength;
|
int PayloadLength;
|
||||||
int ImplicitOrExplicit;
|
int ImplicitOrExplicit;
|
||||||
int ErrorCoding;
|
int ErrorCoding;
|
||||||
int Bandwidth;
|
|
||||||
int SpreadingFactor;
|
int SpreadingFactor;
|
||||||
int LowDataRateOptimize;
|
int LowDataRateOptimize;
|
||||||
int CurrentBandwidth;
|
WINDOW * Window;
|
||||||
WINDOW * Window;
|
|
||||||
unsigned int TelemetryCount, SSDVCount, BadCRCCount, UnknownCount;
|
unsigned int TelemetryCount, SSDVCount, BadCRCCount, UnknownCount;
|
||||||
int Sending;
|
int Sending;
|
||||||
char Telemetry[256];
|
char Telemetry[256];
|
||||||
|
@ -59,8 +59,8 @@ int UplinkMode;
|
||||||
// SSDV Packet Log
|
// SSDV Packet Log
|
||||||
struct TSSDVPackets SSDVPackets[3];
|
struct TSSDVPackets SSDVPackets[3];
|
||||||
};
|
};
|
||||||
struct TConfig
{
|
struct TConfig
{
char Tracker[16]; // Callsign or name of receiver
|
||||||
char Tracker[16];
|
double latitude, longitude; // Receiver's location
|
||||||
int EnableHabitat;
|
int EnableHabitat;
|
||||||
int EnableSSDV;
|
int EnableSSDV;
|
||||||
int EnableTelemetryLogging;
|
int EnableTelemetryLogging;
|
||||||
|
@ -75,8 +75,7 @@ int UplinkMode;
|
||||||
int NetworkLED;
|
int NetworkLED;
|
||||||
int InternetLED;
|
int InternetLED;
|
||||||
int ServerPort;
|
int ServerPort;
|
||||||
float latitude, longitude;
|
char SMSFolder[64];
|
||||||
char SMSFolder[64];
|
|
||||||
char antenna[64];
|
char antenna[64];
|
||||||
int EnableDev;
|
int EnableDev;
|
||||||
};
|
};
|
||||||
|
|
|
@ -232,6 +232,7 @@ HabitatLoop( void *vars )
|
||||||
total_packets++;
|
total_packets++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
delay(100); // Don't eat too much CPU
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
112
server.c
112
server.c
|
@ -4,8 +4,8 @@
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdio.h> // Standard input/output definitions
|
#include <stdio.h> // Standard input/output definitions
|
||||||
#include <string.h> // String function definitions
|
#include <string.h> // String function definitions
|
||||||
#include <unistd.h> // UNIX standard function definitions
|
|
||||||
#include <fcntl.h> // File control definitions
|
#include <fcntl.h> // File control definitions
|
||||||
|
#include <unistd.h> // UNIX standard function definitions
|
||||||
#include <errno.h> // Error number definitions
|
#include <errno.h> // Error number definitions
|
||||||
#include <termios.h> // POSIX terminal control definitions
|
#include <termios.h> // POSIX terminal control definitions
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -13,24 +13,80 @@
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <wiringPi.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
#include "config.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
extern bool run;
|
extern bool run;
|
||||||
extern bool server_closed;
|
extern bool server_closed;
|
||||||
|
|
||||||
|
void ProcessClientLine(int connfd, char *line)
|
||||||
|
{
|
||||||
|
line[strcspn(line, "\r\n")] = '\0'; // Get rid of CR LF
|
||||||
|
|
||||||
|
LogMessage("Received %s from client\n", line);
|
||||||
|
|
||||||
|
if (strchr(line, '=') == NULL)
|
||||||
|
{
|
||||||
|
// Request or command
|
||||||
|
|
||||||
|
if (strcasecmp(line, "settings") == 0)
|
||||||
|
{
|
||||||
|
int Index;
|
||||||
|
char SettingName[64], SettingValue[256], packet[4096];
|
||||||
|
|
||||||
|
LogMessage("Responding to settings request\n");
|
||||||
|
|
||||||
|
Index = 0;
|
||||||
|
packet[0] = '\0';
|
||||||
|
|
||||||
|
while (SettingAsString(Index, SettingName, sizeof(SettingName), SettingValue, sizeof(SettingValue)))
|
||||||
|
{
|
||||||
|
char temp[300];
|
||||||
|
|
||||||
|
sprintf(temp, "{\"class\":\"SET\",\"set\":\"%s\",\"val\":%s}\r\n", SettingName, SettingValue);
|
||||||
|
|
||||||
|
if ((strlen(temp) + strlen(packet)) < sizeof(packet))
|
||||||
|
{
|
||||||
|
strcat(packet, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
Index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
send(connfd, packet, strlen(packet), MSG_NOSIGNAL);
|
||||||
|
}
|
||||||
|
else if (strcasecmp(line, "save") == 0)
|
||||||
|
{
|
||||||
|
LogMessage("Saving Settings\n");
|
||||||
|
SaveConfigFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Setting
|
||||||
|
char *setting, *value, *saveptr;
|
||||||
|
|
||||||
|
setting = strtok_r(line, "=", &saveptr);
|
||||||
|
value = strtok_r( NULL, "\n", &saveptr);
|
||||||
|
|
||||||
|
SetConfigValue(setting, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void *ServerLoop( void *some_void_ptr )
|
void *ServerLoop( void *some_void_ptr )
|
||||||
{
|
{
|
||||||
int listenfd = 0, connfd = 0;
|
int sockfd = 0;
|
||||||
struct sockaddr_in serv_addr;
|
struct sockaddr_in serv_addr;
|
||||||
|
|
||||||
char sendBuff[1025];
|
char sendBuff[1025];
|
||||||
|
|
||||||
listenfd = socket( AF_INET, SOCK_STREAM, 0 );
|
sockfd = socket( AF_INET, SOCK_STREAM, 0 );
|
||||||
memset( &serv_addr, '0', sizeof( serv_addr ) );
|
memset( &serv_addr, '0', sizeof( serv_addr ) );
|
||||||
memset( sendBuff, '0', sizeof( sendBuff ) );
|
memset( sendBuff, '0', sizeof( sendBuff ) );
|
||||||
|
|
||||||
|
@ -40,7 +96,7 @@ void *ServerLoop( void *some_void_ptr )
|
||||||
|
|
||||||
LogMessage( "Listening on port %d\n", Config.ServerPort );
|
LogMessage( "Listening on port %d\n", Config.ServerPort );
|
||||||
|
|
||||||
if ( setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR, &( int )
|
if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &( int )
|
||||||
{
|
{
|
||||||
1}, sizeof( int ) ) < 0 )
|
1}, sizeof( int ) ) < 0 )
|
||||||
{
|
{
|
||||||
|
@ -48,28 +104,58 @@ void *ServerLoop( void *some_void_ptr )
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( bind
|
if ( bind
|
||||||
( listenfd, ( struct sockaddr * ) &serv_addr,
|
( sockfd, ( struct sockaddr * ) &serv_addr,
|
||||||
sizeof( serv_addr ) ) < 0 )
|
sizeof( serv_addr ) ) < 0 )
|
||||||
{
|
{
|
||||||
LogMessage( "Server failed errno %d\n", errno );
|
LogMessage( "Server failed errno %d\n", errno );
|
||||||
exit( -1 );
|
exit( -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
listen( listenfd, 10 );
|
listen( sockfd, 10 );
|
||||||
|
|
||||||
while ( run )
|
while ( run )
|
||||||
{
|
{
|
||||||
int port_closed;
|
int SendEveryMS = 1000;
|
||||||
|
int MSPerLoop=100;
|
||||||
|
int ms, port_closed, connfd;
|
||||||
|
|
||||||
connfd = accept( listenfd, ( struct sockaddr * ) NULL, NULL );
|
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) & ~O_NONBLOCK); // Blocking mode so we wait for a connection
|
||||||
|
|
||||||
|
connfd = accept( sockfd, ( struct sockaddr * ) NULL, NULL ); // Wait for connection
|
||||||
|
|
||||||
LogMessage( "Connected to client\n" );
|
LogMessage( "Connected to client\n" );
|
||||||
|
|
||||||
|
fcntl(connfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK); // Non-blocking, so we don't block on receiving any commands from client
|
||||||
|
|
||||||
for ( port_closed = 0; !port_closed; )
|
for ( port_closed = 0; !port_closed; )
|
||||||
{
|
{
|
||||||
int Channel;
|
int Channel;
|
||||||
// Build json
|
char packet[4096];
|
||||||
// sprintf(sendBuff, "{\"class\":\"POSN\",\"time\":\"12:34:56\",\"lat\":54.12345,\"lon\":-2.12345,\"alt\":169}\r\n");
|
|
||||||
|
// Listen loop
|
||||||
|
for (ms=0; ms<SendEveryMS; ms+=MSPerLoop)
|
||||||
|
{
|
||||||
|
int bytecount;
|
||||||
|
|
||||||
|
while ((bytecount = recv(connfd, packet, sizeof(packet), 0)) > 0)
|
||||||
|
{
|
||||||
|
char *line, *saveptr;
|
||||||
|
|
||||||
|
packet[bytecount] = 0;
|
||||||
|
|
||||||
|
line = strtok_r(packet, "\n", &saveptr);
|
||||||
|
while (line)
|
||||||
|
{
|
||||||
|
ProcessClientLine(connfd, line);
|
||||||
|
line = strtok_r( NULL, "\n", &saveptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(MSPerLoop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send part
|
||||||
|
// Build json
|
||||||
|
|
||||||
for (Channel=0; Channel<=1; Channel++)
|
for (Channel=0; Channel<=1; Channel++)
|
||||||
{
|
{
|
||||||
|
@ -123,10 +209,6 @@ void *ServerLoop( void *some_void_ptr )
|
||||||
LogMessage( "Disconnected from client\n" );
|
LogMessage( "Disconnected from client\n" );
|
||||||
port_closed = 1;
|
port_closed = 1;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
sleep(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
ssdv.c
2
ssdv.c
|
@ -195,7 +195,7 @@ SSDVLoop( void *vars )
|
||||||
|
|
||||||
packets = 0;
|
packets = 0;
|
||||||
}
|
}
|
||||||
|
delay(100); // Don't eat too much CPU
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue