void ProcessKeyPress(int ch) { int Channel = 0; /* shifted keys act on channel 1 */ if (ch >= 'A' && ch <= 'Z') { Channel = 1; /* change from upper to lower case */ ch += ('a' - 'A'); } if (ch == 'q') { run = FALSE; return; } /* ignore if channel is not in use */ if (!Config.LoRaDevices[Channel].InUse) { return; } switch(ch) { case 'f': Config.LoRaDevices[Channel].AFC = !Config.LoRaDevices[Channel].AFC; ChannelPrintf(Channel, 11, 24, "%s", Config.LoRaDevices[Channel].AFC?"AFC":" "); break; case 'a': ReTune(Channel, 0.1); break; case 'z': ReTune(Channel, -0.1); break; case 's': ReTune(Channel, 0.01); break; case 'x': ReTune(Channel, -0.01); break; case 'd': ReTune(Channel, 0.001); break; case 'c': ReTune(Channel, -0.001); break; default: //LogMessage("KeyPress %d\n", ch); return; } }
void setFrequency(int Channel, double Frequency) { unsigned long FrequencyValue; FrequencyValue = (unsigned long)(Frequency * 7110656 / 434); writeRegister(Channel, 0x06, (FrequencyValue >> 16) & 0xFF); // Set frequency writeRegister(Channel, 0x07, (FrequencyValue >> 8) & 0xFF); writeRegister(Channel, 0x08, FrequencyValue & 0xFF); Config.LoRaDevices[Channel].activeFreq = Frequency; // LogMessage("Set Frequency to %lf\n", Frequency); ChannelPrintf(Channel, 1, 1, "Channel %d %8.4lfMHz ", Channel, Frequency); // ChannelPrintf(Channel, 1, 1, "Channel %d %8.4lfMHz %s mode", Channel, Frequency, Modes[Config.LoRaDevices[Channel].SpeedMode]); // ChannelPrintf(Channel, 1, 11, "%8.4fMHz", Frequency); }
void ProcessCallingMessage(int Channel, char *Message) { char Payload[16]; double Frequency; int ImplicitOrExplicit, ErrorCoding, Bandwidth, SpreadingFactor, LowDataRateOptimize; ChannelPrintf(Channel, 4, 1, "Calling message %d bytes ", strlen(Message)); if (sscanf(Message+2, "%15[^,],%lf,%d,%d,%d,%d,%d,%*d", Payload, &Frequency, &ImplicitOrExplicit, &ErrorCoding, &Bandwidth, &SpreadingFactor, &LowDataRateOptimize) == 7) { if (Config.LoRaDevices[Channel].AFC) { double MasterFrequency; sscanf(Config.LoRaDevices[Channel].Frequency, "%lf", &MasterFrequency); Frequency += Config.LoRaDevices[Channel].activeFreq - MasterFrequency; } LogMessage("Ch %d: Calling message, new frequency %7.3lf\n", Channel, Frequency); // Decoded OK setMode(Channel, RF96_MODE_SLEEP); // setFrequency(Channel, Config.LoRaDevices[Channel].activeFreq + ); setFrequency(Channel, Frequency); SetLoRaParameters(Channel, ImplicitOrExplicit, ErrorCoding, Bandwidth, SpreadingFactor, LowDataRateOptimize); setMode(Channel, RF96_MODE_RX_CONTINUOUS); Config.LoRaDevices[Channel].InCallingMode = 1; // ChannelPrintf(Channel, 1, 1, "Channel %d %7.3lfMHz ", Channel, Frequency); } }
void ProcessTelemetryMessage(int Channel, char *Message) { if (strlen(Message+1) < 150) { char *startmessage, *endmessage; ChannelPrintf(Channel, 4, 1, "Telemetry %d bytes ", strlen(Message+1)); endmessage = Message; startmessage = endmessage; endmessage = strchr(startmessage, '\n'); if (endmessage != NULL) { time_t now; struct tm *tm; *endmessage = '\0'; LogTelemetryPacket(startmessage); UploadTelemetryPacket(startmessage); ProcessLine(Channel, startmessage); now = time(0); tm = localtime(&now); LogMessage("%02d:%02d:%02d Ch%d: %s\n", tm->tm_hour, tm->tm_min, tm->tm_sec, Channel, startmessage); } // DoPositionCalcs(Channel); Config.LoRaDevices[Channel].TelemetryCount++; } }
void * SSDVLoop( void *vars ) { if ( Config.EnableSSDV ) { const int max_packets = 51; thread_shared_vars_t *stsv; stsv = vars; ssdv_t s[max_packets]; unsigned int j = 0; unsigned int packets = 0; unsigned long total_packets = 0; // Keep looping until the parent quits and there are no more packets to // send to ssdv. while ( ( stsv->parent_status == RUNNING ) || ( packets > 0 ) ) { if ( stsv->packet_count > total_packets ) { packets = read( ssdv_pipe_fd[0], &s[j], sizeof( ssdv_t ) ); } else { packets = 0; // If we have have a rollover after processing 4294967295 packets if ( stsv->packet_count < total_packets ) total_packets = 0; } if ( packets ) { j++; total_packets++; } if ( j == 50 || ( ( packets == 0 ) && ( j > 0 ) ) ) { ChannelPrintf( s[0].Channel, 6, 16, "SSDV" ); UploadImagePacket( s, j ); ChannelPrintf( s[0].Channel, 6, 16, " " ); j = 0; packets = 0; } delay( 100 ); // Don't eat too much CPU } } close( ssdv_pipe_fd[0] ); close( ssdv_pipe_fd[1] ); LogMessage( "SSDV thread closing\n" ); return NULL; }
void LoadConfigFile() { FILE *fp; char *filename = "gateway.txt"; char Keyword[32]; int Channel, Temp; char TempString[16]; Config.EnableHabitat = 1; Config.EnableSSDV = 1; Config.EnableTelemetryLogging = 0; Config.ftpServer[0] = '\0'; Config.ftpUser[0] = '\0'; Config.ftpPassword[0] = '\0'; Config.ftpFolder[0] = '\0'; if ((fp = fopen(filename, "r")) == NULL) { printf("\nFailed to open config file %s (error %d - %s).\nPlease check that it exists and has read permission.\n", filename, errno, strerror(errno)); exit(1); } // Receiver config ReadString(fp, "tracker", Config.Tracker, sizeof(Config.Tracker), 1); LogMessage("Tracker = '%s'\n", Config.Tracker); // Enable uploads ReadBoolean(fp, "EnableHabitat", 0, &Config.EnableHabitat); ReadBoolean(fp, "EnableSSDV", 0, &Config.EnableSSDV); // Enable logging ReadBoolean(fp, "LogTelemetry", 0, &Config.EnableTelemetryLogging); // Calling mode Config.CallingTimeout = ReadInteger(fp, "CallingTimeout", 0, 300); // LED allocations Config.NetworkLED = ReadInteger(fp, "NetworkLED", 0, -1); Config.InternetLED = ReadInteger(fp, "InternetLED", 0, -1); Config.LoRaDevices[0].ActivityLED = ReadInteger(fp, "ActivityLED_0", 0, -1); Config.LoRaDevices[1].ActivityLED = ReadInteger(fp, "ActivityLED_1", 0, -1); // Server Port Config.ServerPort = ReadInteger(fp, "ServerPort", 0, -1); ReadString(fp, "ftpserver", Config.ftpServer, sizeof(Config.ftpServer), 0); ReadString(fp, "ftpUser", Config.ftpUser, sizeof(Config.ftpUser), 0); ReadString(fp, "ftpPassword", Config.ftpPassword, sizeof(Config.ftpPassword), 0); ReadString(fp, "ftpFolder", Config.ftpFolder, sizeof(Config.ftpFolder), 0); for (Channel=0; Channel<=1; Channel++) { // Defaults Config.LoRaDevices[Channel].Frequency[0] = '\0'; sprintf(Keyword, "frequency_%d", Channel); ReadString(fp, Keyword, Config.LoRaDevices[Channel].Frequency, sizeof(Config.LoRaDevices[Channel].Frequency), 0); if (Config.LoRaDevices[Channel].Frequency[0]) { Config.LoRaDevices[Channel].ImplicitOrExplicit = EXPLICIT_MODE; Config.LoRaDevices[Channel].ErrorCoding = ERROR_CODING_4_8; Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_20K8; Config.LoRaDevices[Channel].SpreadingFactor = SPREADING_11; Config.LoRaDevices[Channel].LowDataRateOptimize = 0x00; Config.LoRaDevices[Channel].AFC = FALSE; LogMessage("Channel %d frequency set to %s\n", Channel, Config.LoRaDevices[Channel].Frequency); Config.LoRaDevices[Channel].InUse = 1; // DIO0 / DIO5 overrides sprintf(Keyword, "DIO0_%d", Channel); Config.LoRaDevices[Channel].DIO0 = ReadInteger(fp, Keyword, 0, Config.LoRaDevices[Channel].DIO0); sprintf(Keyword, "DIO5_%d", Channel); Config.LoRaDevices[Channel].DIO5 = ReadInteger(fp, Keyword, 0, Config.LoRaDevices[Channel].DIO5); LogMessage("LoRa Channel %d DIO0=%d DIO5=%d\n", Channel, Config.LoRaDevices[Channel].DIO0, Config.LoRaDevices[Channel].DIO5); Config.LoRaDevices[Channel].SpeedMode = 0; sprintf(Keyword, "mode_%d", Channel); Config.LoRaDevices[Channel].SpeedMode = ReadInteger(fp, Keyword, 0, 0); if (Config.LoRaDevices[Channel].SpeedMode == 5) { // Calling channel Config.LoRaDevices[Channel].ImplicitOrExplicit = EXPLICIT_MODE; Config.LoRaDevices[Channel].ErrorCoding = ERROR_CODING_4_8; Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_41K7; Config.LoRaDevices[Channel].SpreadingFactor = SPREADING_11; Config.LoRaDevices[Channel].LowDataRateOptimize = 0; } else if (Config.LoRaDevices[Channel].SpeedMode == 4) { // Testing Config.LoRaDevices[Channel].ImplicitOrExplicit = IMPLICIT_MODE; Config.LoRaDevices[Channel].ErrorCoding = ERROR_CODING_4_5; Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_250K; Config.LoRaDevices[Channel].SpreadingFactor = SPREADING_6; Config.LoRaDevices[Channel].LowDataRateOptimize = 0; } else if (Config.LoRaDevices[Channel].SpeedMode == 3) { // Normal mode for high speed images in 868MHz band Config.LoRaDevices[Channel].ImplicitOrExplicit = EXPLICIT_MODE; Config.LoRaDevices[Channel].ErrorCoding = ERROR_CODING_4_6; Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_250K; Config.LoRaDevices[Channel].SpreadingFactor = SPREADING_7; Config.LoRaDevices[Channel].LowDataRateOptimize = 0; } else if (Config.LoRaDevices[Channel].SpeedMode == 2) { // Normal mode for repeater network Config.LoRaDevices[Channel].ImplicitOrExplicit = EXPLICIT_MODE; Config.LoRaDevices[Channel].ErrorCoding = ERROR_CODING_4_8; Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_62K5; Config.LoRaDevices[Channel].SpreadingFactor = SPREADING_8; Config.LoRaDevices[Channel].LowDataRateOptimize = 0x00; } else if (Config.LoRaDevices[Channel].SpeedMode == 1) { // Normal mode for SSDV Config.LoRaDevices[Channel].ImplicitOrExplicit = IMPLICIT_MODE; Config.LoRaDevices[Channel].ErrorCoding = ERROR_CODING_4_5; Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_20K8; Config.LoRaDevices[Channel].SpreadingFactor = SPREADING_6; Config.LoRaDevices[Channel].LowDataRateOptimize = 0; } else { Config.LoRaDevices[Channel].ImplicitOrExplicit = EXPLICIT_MODE; Config.LoRaDevices[Channel].ErrorCoding = ERROR_CODING_4_8; Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_20K8; Config.LoRaDevices[Channel].SpreadingFactor = SPREADING_11; Config.LoRaDevices[Channel].LowDataRateOptimize = 0x08; } sprintf(Keyword, "sf_%d", Channel); Temp = ReadInteger(fp, Keyword, 0, 0); if ((Temp >= 6) && (Temp <= 12)) { Config.LoRaDevices[Channel].SpreadingFactor = Temp << 4; LogMessage("Setting SF=%d\n", Temp); } sprintf(Keyword, "bandwidth_%d", Channel); ReadString(fp, Keyword, TempString, sizeof(TempString), 0); if (*TempString) { LogMessage("Setting BW=%s\n", TempString); } if (strcmp(TempString, "7K8") == 0) { Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_7K8; } else if (strcmp(TempString, "10K4") == 0) { Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_10K4; } else if (strcmp(TempString, "15K6") == 0) { Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_15K6; } else if (strcmp(TempString, "20K8") == 0) { Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_20K8; } else if (strcmp(TempString, "31K25") == 0) { Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_31K25; } else if (strcmp(TempString, "41K7") == 0) { Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_41K7; } else if (strcmp(TempString, "62K5") == 0) { Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_62K5; } else if (strcmp(TempString, "125K") == 0) { Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_125K; } else if (strcmp(TempString, "250K") == 0) { Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_250K; } else if (strcmp(TempString, "500K") == 0) { Config.LoRaDevices[Channel].Bandwidth = BANDWIDTH_500K; } sprintf(Keyword, "implicit_%d", Channel); if (ReadBoolean(fp, Keyword, 0, &Temp)) { if (Temp) { Config.LoRaDevices[Channel].ImplicitOrExplicit = IMPLICIT_MODE; } } sprintf(Keyword, "coding_%d", Channel); Temp = ReadInteger(fp, Keyword, 0, 0); if ((Temp >= 5) && (Temp <= 8)) { Config.LoRaDevices[Channel].ErrorCoding = (Temp-4) << 1; LogMessage("Setting Error Coding=%d\n", Temp); } sprintf(Keyword, "lowopt_%d", Channel); if (ReadBoolean(fp, Keyword, 0, &Temp)) { if (Temp) { Config.LoRaDevices[Channel].LowDataRateOptimize = 0x08; } } sprintf(Keyword, "AFC_%d", Channel); if (ReadBoolean(fp, Keyword, 0, &Temp)) { if (Temp) { Config.LoRaDevices[Channel].AFC = TRUE; ChannelPrintf(Channel, 11, 24, "AFC"); } } } } fclose(fp); }
int main(int argc, char **argv) { unsigned char Message[257]; int Bytes, ch; uint32_t LoopCount[2]; pthread_t SSDVThread, FTPThread, NetworkThread, HabitatThread, ServerThread; WINDOW * mainwin; int LEDCounts[2]; if (prog_count("gateway") > 1) { printf("\nThe gateway program is already running!\n\n"); exit(1); } mainwin = InitDisplay(); // Settings for character input noecho(); cbreak(); nodelay(stdscr, TRUE); keypad(stdscr, TRUE); Config.LoRaDevices[0].InUse = 0; Config.LoRaDevices[1].InUse = 0; LEDCounts[0] = 0; LEDCounts[1] = 0; // Remove any old SSDV files // system("rm -f /tmp/*.bin"); // Default pin allocations Config.LoRaDevices[0].DIO0 = 6; Config.LoRaDevices[0].DIO5 = 5; Config.LoRaDevices[1].DIO0 = 27; Config.LoRaDevices[1].DIO5 = 26; LoadConfigFile(); LoadPayloadFiles(); if (wiringPiSetup() < 0) { fprintf(stderr, "Failed to open wiringPi\n"); exit(1); } if (Config.LoRaDevices[0].ActivityLED >= 0) pinMode(Config.LoRaDevices[0].ActivityLED, OUTPUT); if (Config.LoRaDevices[1].ActivityLED >= 0) pinMode(Config.LoRaDevices[1].ActivityLED, OUTPUT); if (Config.InternetLED >= 0) pinMode(Config.InternetLED, OUTPUT); if (Config.NetworkLED >= 0) pinMode(Config.NetworkLED, OUTPUT); setupRFM98(0); setupRFM98(1); ShowPacketCounts(0); ShowPacketCounts(1); LoopCount[0] = 0; LoopCount[1] = 0; if (pthread_create(&SSDVThread, NULL, SSDVLoop, NULL)) { fprintf(stderr, "Error creating SSDV thread\n"); return 1; } if (pthread_create(&FTPThread, NULL, FTPLoop, NULL)) { fprintf(stderr, "Error creating FTP thread\n"); return 1; } if (pthread_create(&HabitatThread, NULL, HabitatLoop, NULL)) { fprintf(stderr, "Error creating Habitat thread\n"); return 1; } if (Config.ServerPort > 0) { if (pthread_create(&ServerThread, NULL, ServerLoop, NULL)) { fprintf(stderr, "Error creating server thread\n"); return 1; } } if ((Config.NetworkLED >= 0) && (Config.InternetLED >= 0)) { if (pthread_create(&NetworkThread, NULL, NetworkLoop, NULL)) { fprintf(stderr, "Error creating Network thread\n"); return 1; } } while (run) { int Channel; for (Channel=0; Channel<=1; Channel++) { if (Config.LoRaDevices[Channel].InUse) { if (digitalRead(Config.LoRaDevices[Channel].DIO0)) { Bytes = receiveMessage(Channel, Message+1); if (Bytes > 0) { if (Config.LoRaDevices[Channel].ActivityLED >= 0) { digitalWrite(Config.LoRaDevices[Channel].ActivityLED, 1); LEDCounts[Channel] = 5; } // LogMessage("Channel %d data available - %d bytes\n", Channel, Bytes); // LogMessage("Line = '%s'\n", Message); if (Message[1] == '!') { ProcessUploadMessage(Channel, (char *) Message+1); } else if (Message[1] == '^') { ProcessCallingMessage(Channel, (char *) Message+1); } else if (Message[1] == '$') { ProcessTelemetryMessage(Channel, (char *) Message+1); } else if (Message[1] == 0x66) { ProcessSSDVMessage(Channel, Message); } else { LogMessage("Unknown packet type is %02Xh, RSSI %d\n", Message[1], readRegister(Channel, REG_PACKET_RSSI) - 157); ChannelPrintf(Channel, 4, 1, "Unknown Packet %d, %d bytes", Message[0], Bytes); Config.LoRaDevices[Channel].UnknownCount++; } Config.LoRaDevices[Channel].LastPacketAt = time(NULL); if (Config.LoRaDevices[Channel].InCallingMode && (Config.CallingTimeout > 0)) { Config.LoRaDevices[Channel].ReturnToCallingModeAt = time(NULL) + Config.CallingTimeout; } ShowPacketCounts(Channel); } } if (++LoopCount[Channel] > 1000000) { LoopCount[Channel] = 0; ShowPacketCounts(Channel); ChannelPrintf(Channel, 12, 1, "Current RSSI = %4d ", readRegister(Channel, REG_CURRENT_RSSI) - 157); if (Config.LoRaDevices[Channel].LastPacketAt > 0) { ChannelPrintf(Channel, 6, 1, "%us since last packet ", (unsigned int)(time(NULL) - Config.LoRaDevices[Channel].LastPacketAt)); } if (Config.LoRaDevices[Channel].InCallingMode && (Config.CallingTimeout > 0) && (Config.LoRaDevices[Channel].ReturnToCallingModeAt > 0) && (time(NULL) > Config.LoRaDevices[Channel].ReturnToCallingModeAt)) { Config.LoRaDevices[Channel].InCallingMode = 0; Config.LoRaDevices[Channel].ReturnToCallingModeAt = 0; LogMessage("Return to calling mode\n"); // setMode(Channel, RF96_MODE_SLEEP); // setFrequency(Channel, Frequency); // SetLoRaParameters(Channel, ImplicitOrExplicit, ErrorCoding, Bandwidth, SpreadingFactor, LowDataRateOptimize); // setMode(Channel, RF96_MODE_RX_CONTINUOUS); setLoRaMode(Channel); SetDefaultLoRaParameters(Channel); setMode(Channel, RF96_MODE_RX_CONTINUOUS); ChannelPrintf(Channel, 1, 1, "Channel %d %sMHz %s mode", Channel, Config.LoRaDevices[Channel].Frequency, Modes[Config.LoRaDevices[Channel].SpeedMode]); } if ((ch = getch()) != ERR) { ProcessKeyPress(ch); } if (LEDCounts[Channel] && (Config.LoRaDevices[Channel].ActivityLED >= 0)) { if (--LEDCounts[Channel] == 0) { digitalWrite(Config.LoRaDevices[Channel].ActivityLED, 0); } } } } } // delay(5); } CloseDisplay(mainwin); if (Config.NetworkLED >= 0) digitalWrite(Config.NetworkLED, 0); if (Config.InternetLED >= 0) digitalWrite(Config.InternetLED, 0); if (Config.LoRaDevices[0].ActivityLED >= 0) digitalWrite(Config.LoRaDevices[0].ActivityLED, 0); if (Config.LoRaDevices[1].ActivityLED >= 0) digitalWrite(Config.LoRaDevices[1].ActivityLED, 0); return 0; }
void ProcessSSDVMessage(int Channel, unsigned char *Message) { // SSDV packet static uint32_t PreviousCallsignCode=0; static int PreviousImageNumber=-1, PreviousPacketNumber=0; uint32_t CallsignCode; char Callsign[7], *FileMode, *EncodedCallsign, *EncodedEncoding, *EncodedData, HexString[513]; int ImageNumber, PacketNumber; char filename[100]; FILE *fp; Message[0] = 0x55; CallsignCode = Message[2]; CallsignCode <<= 8; CallsignCode |= Message[3]; CallsignCode <<= 8; CallsignCode |= Message[4]; CallsignCode <<= 8; CallsignCode |= Message[5]; decode_callsign(Callsign, CallsignCode); ImageNumber = Message[6]; PacketNumber = Message[8]; // Create new file ? if ((ImageNumber != PreviousImageNumber) || (PacketNumber <= PreviousPacketNumber) || (CallsignCode != PreviousCallsignCode)) { // New image so new file // FileMode = "wb"; FileMode = "ab"; Config.LoRaDevices[Channel].SSDVMissing = PacketNumber; } else { FileMode = "ab"; if (PacketNumber > (PreviousPacketNumber+1)) { Config.LoRaDevices[Channel].SSDVMissing += PacketNumber - PreviousPacketNumber - 1; } } LogMessage("Ch%d: SSDV Packet, Callsign %s, Image %d, Packet %d, %d Missing\n", Channel, Callsign, Message[6], Message[7] * 256 + Message[8], Config.LoRaDevices[Channel].SSDVMissing); ChannelPrintf(Channel, 4, 1, "SSDV Packet "); PreviousImageNumber = ImageNumber; PreviousPacketNumber = PacketNumber; PreviousCallsignCode = CallsignCode; // Save to file sprintf(filename, "/tmp/%s_%d.bin", Callsign, ImageNumber); if ((fp = fopen(filename, FileMode))) { fwrite(Message, 1, 256, fp); fclose(fp); } // Upload to server if (Config.EnableSSDV) { EncodedCallsign = url_encode(Callsign); EncodedEncoding = url_encode("hex"); // Base64Data = base64_encode(Message, 256, &output_length); // printf("output_length=%d, byte=%02Xh\n", output_length, Base64Data[output_length]); // Base64Data[output_length] = '\0'; // printf ("Base64Data '%s'\n", Base64Data); ConvertStringToHex(HexString, Message, 256); EncodedData = url_encode(HexString); UploadImagePacket(EncodedCallsign, EncodedEncoding, EncodedData); free(EncodedCallsign); free(EncodedEncoding); // free(Base64Data); free(EncodedData); } Config.LoRaDevices[Channel].SSDVCount++; }