int main(void) { int fd, ReturnCode, i; unsigned long Sentence_Counter = 0; int ImagePacketCount, MaxImagePackets; char Sentence[100], Command[100]; struct stat st = {0}; struct TGPS GPS; pthread_t PredictionThread, LoRaThread, APRSThread, GPSThread, DS18B20Thread, ADCThread, CameraThread, BMP085Thread, BME280Thread, LEDThread, LogThread; if (prog_count("tracker") > 1) { printf("\nThe tracker program is already running!\n"); printf("It is started automatically, with the camera script, when the Pi boots.\n\n"); printf("If you just want the tracker software to run, it already is,\n"); printf("and its output can be viewed on a monitor attached to a Pi video socket.\n\n"); printf("If instead you want to view the tracker output via ssh,\n"); printf("then you should first stop it by typing the following command:\n"); printf(" sudo killall tracker\n\n"); printf("and then restart manually with\n"); printf(" sudo ./tracker\n\n"); exit(1); } printf("\n\nRASPBERRY PI-IN-THE-SKY FLIGHT COMPUTER\n"); printf( "=======================================\n\n"); Config.BoardType = GetBoardType(); if (Config.BoardType) { if (Config.BoardType == 3) { printf("RPi Zero\n"); printf("PITS Zero Board\n"); } else { if (Config.BoardType == 2) { printf("RPi 2 B\n"); } else { printf("RPi Model A+ or B+\n"); } printf("PITS+ Board\n"); } Config.LED_OK = 25; Config.LED_Warn = 24; Config.SDA = 2; Config.SCL = 3; } else { printf("RPi Model A or B\n"); printf("PITS Board\n"); Config.LED_OK = 11; Config.LED_Warn = 4; Config.SDA = 5; Config.SCL = 6; } printf("Device Tree is %s\n\n", devicetree() ? "enabled" : "disabled"); LoadConfigFile(&Config); if (Config.DisableMonitor) { system("/opt/vc/bin/tvservice -off"); } if (FileExists("/boot/clear.txt")) { // remove SSDV and other camera images, plus log files printf("Removing existing photo files\n"); remove("gps.txt"); remove("telemetry.txt"); remove("/boot/clear.txt"); system("rm -rf /home/pi/pits/tracker/images/*"); } // Remove any old SSDV files system("rm -f ssdv*.bin"); GPS.SecondsInDay = 0; GPS.Hours = 0; GPS.Minutes = 0; GPS.Seconds = 0; GPS.Longitude = 0.0; GPS.Latitude = 0.0; GPS.Altitude = 0; GPS.Satellites = 0; GPS.Speed = 0.0; GPS.Direction = 0.0; GPS.DS18B20Temperature[0] = 0.0; GPS.DS18B20Temperature[1] = 0.0; GPS.BatteryVoltage = 0.0; GPS.BMP180Temperature = 0.0; GPS.Pressure = 0.0; GPS.MaximumAltitude = 0.0; GPS.DS18B20Count = 0; // Set up I/O if (wiringPiSetup() == -1) { exit (1); } // Switch off the radio till it's configured pinMode (NTX2B_ENABLE, OUTPUT); digitalWrite (NTX2B_ENABLE, 0); // Switch on the GPS if (Config.BoardType == 0) { // Only PITS board had this, not PITS+ pinMode (UBLOX_ENABLE, OUTPUT); digitalWrite (UBLOX_ENABLE, 0); } if (!Config.DisableRTTY) { if (*Config.Frequency) { SetFrequency(Config.Frequency); } fd = OpenSerialPort(); digitalWrite (NTX2B_ENABLE, 1); } // Set up DS18B20 system("sudo modprobe w1-gpio"); system("sudo modprobe w1-therm"); if (!devicetree()) { // SPI for ADC (older boards), LoRa add-on board system("gpio load spi"); } // SSDV Folders sprintf(Config.Channels[0].SSDVFolder, "%s/RTTY", SSDVFolder); *Config.Channels[1].SSDVFolder = '\0'; // No folder for APRS images sprintf(Config.Channels[2].SSDVFolder, "%s/LORA0", SSDVFolder); sprintf(Config.Channels[3].SSDVFolder, "%s/LORA1", SSDVFolder); sprintf(Config.Channels[4].SSDVFolder, "%s/FULL", SSDVFolder); if (Config.Camera) { // Create SSDV Folders if (stat(SSDVFolder, &st) == -1) { mkdir(SSDVFolder, 0777); } for (i=0; i<5; i++) { if (*Config.Channels[i].SSDVFolder) { if (stat(Config.Channels[i].SSDVFolder, &st) == -1) { mkdir(Config.Channels[i].SSDVFolder, 0777); } } } // Filenames for SSDV for (i=0; i<5; i++) { sprintf(Config.Channels[i].take_pic, "take_pic_%d", i); // sprintf(Config.Channels[i].current_ssdv, "ssdv_%d.bin", i); // sprintf(Config.Channels[i].next_ssdv, "ssdv_%d.nxt", i); sprintf(Config.Channels[i].convert_file, "convert_%d", i); sprintf(Config.Channels[i].ssdv_done, "ssdv_done_%d", i); Config.Channels[i].SSDVImageNumber = -1; Config.Channels[i].SSDVPacketNumber = -1; Config.Channels[i].ImageFP = NULL; } } if (pthread_create(&GPSThread, NULL, GPSLoop, &GPS)) { fprintf(stderr, "Error creating GPS thread\n"); return 1; } if (*(Config.APRS_Callsign) && Config.APRS_ID && Config.APRS_Period) { if (pthread_create(&APRSThread, NULL, APRSLoop, &GPS)) { fprintf(stderr, "Error creating APRS thread\n"); return 1; } } if (Config.LoRaDevices[0].InUse || Config.LoRaDevices[1].InUse) { if (pthread_create(&LoRaThread, NULL, LoRaLoop, &GPS)) { fprintf(stderr, "Error creating LoRa thread\n"); } } if (pthread_create(&DS18B20Thread, NULL, DS18B20Loop, &GPS)) { fprintf(stderr, "Error creating DS18B20s thread\n"); return 1; } if (Config.BoardType != 3) { // Not a zero, so should have ADC on it if (I2CADCExists()) { printf ("V2.4 or later board with I2C ADC\n"); if (pthread_create(&ADCThread, NULL, I2CADCLoop, &GPS)) { fprintf(stderr, "Error creating ADC thread\n"); return 1; } } else { printf ("Older board with SPI ADC\n"); if (pthread_create(&ADCThread, NULL, ADCLoop, &GPS)) { fprintf(stderr, "Error creating ADC thread\n"); return 1; } } } if (Config.Camera) { if (pthread_create(&CameraThread, NULL, CameraLoop, &GPS)) { fprintf(stderr, "Error creating camera thread\n"); return 1; } } if (pthread_create(&LEDThread, NULL, LEDLoop, &GPS)) { fprintf(stderr, "Error creating LED thread\n"); return 1; } if (Config.TelemetryFileUpdate > 0) { if (pthread_create(&LogThread, NULL, LogLoop, &GPS)) { fprintf(stderr, "Error creating Log thread\n"); return 1; } } if (Config.EnableBMP085) { if (pthread_create(&BMP085Thread, NULL, BMP085Loop, &GPS)) { fprintf(stderr, "Error creating BMP085 thread\n"); return 1; } } if (Config.EnableBME280) { if (pthread_create(&BME280Thread, NULL, BME280Loop, &GPS)) { fprintf(stderr, "Error creating BME280 thread\n"); return 1; } } if (Config.EnableLandingPrediction) { if (pthread_create(&PredictionThread, NULL, PredictionLoop, &GPS)) { fprintf(stderr, "Error creating prediction thread\n"); } } if (!Config.DisableRTTY) { if (Config.InfoMessageCount < 0) { // Default number depends on baud rate Config.InfoMessageCount = (Config.TxSpeed < B300) ? 2 : 4; } for (i=0; i<Config.InfoMessageCount; i++) { SendIPAddress(fd); SendFreeSpace(fd); } } ImagePacketCount = 0; while (1) { static int CarrierOn=1; if (Config.DisableRTTY) { delayMilliseconds (200); } else if (LoRaUploadNow(&GPS, 10)) { if (CarrierOn) { digitalWrite (NTX2B_ENABLE, 0); CarrierOn = 0; printf("Switching RTTY carrier off\n"); } delayMilliseconds (200); } else { if (!CarrierOn) { digitalWrite (NTX2B_ENABLE, 1); printf("Switching RTTY carrier on\n"); CarrierOn = 1; } MaxImagePackets = (GPS.Altitude > Config.SSDVHigh) ? Config.Channels[RTTY_CHANNEL].ImagePackets : 1; if (ImagePacketCount++ < MaxImagePackets) { SendRTTYImage(fd); } else { ImagePacketCount = 0; BuildSentence(Sentence, ++Sentence_Counter, &GPS); SendSentence(fd, Sentence); } } } }
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; }