kopia lustrzana https://github.com/pjalocha/esp32-ogn-tracker
Add IGC header with HF fields
rodzic
906229814e
commit
8c7108fa56
|
@ -29,7 +29,7 @@ class FlightMonitor
|
|||
// TakeoffCount=0;
|
||||
}
|
||||
|
||||
static char NameCode(int Num) // coding of numbers in IGC file names
|
||||
static char Code36(int Num) // coding of numbers in IGC file names
|
||||
{ if(Num<=0) return '0';
|
||||
if(Num<10) return '0'+Num;
|
||||
if(Num<36) return 'A'+(Num-10);
|
||||
|
@ -41,11 +41,11 @@ class FlightMonitor
|
|||
static int ShortName(char *Name, const GPS_Position &Takeoff, uint8_t TakeoffNum, const char *Serial)
|
||||
{ int Len=0;
|
||||
Name[Len++]='0'+Takeoff.Year%10; // Year (last digit)
|
||||
Name[Len++]=NameCode(Takeoff.Month); // encoded month
|
||||
Name[Len++]=NameCode(Takeoff.Day); // encoded day
|
||||
Name[Len++]=Code36(Takeoff.Month); // encoded month
|
||||
Name[Len++]=Code36(Takeoff.Day); // encoded day
|
||||
Name[Len++]='O'; // OGN
|
||||
Len+=Format_String(Name+Len, Serial); // three-digit serial
|
||||
Name[Len++]=NameCode(TakeoffNum); // flight of the day
|
||||
Len+=Format_String(Name+Len, Serial); // three-letter serial
|
||||
Name[Len++]=Code36(TakeoffNum); // flight of the day
|
||||
Len+=Format_String(Name+Len, ".IGC"); // extension
|
||||
Name[Len]=0;
|
||||
// printf("ShortName[%d]: %s\n", Len, Name);
|
||||
|
|
|
@ -29,7 +29,8 @@ static const char *FlashLog_Ext = ".TLG"; // extension for log files, co
|
|||
static const uint32_t FlashLog_MaxTime = 3600; // 1 hour max. per single log file
|
||||
static const uint32_t FlashLog_MaxSize = 0x10000; // 64KB max. per single log file
|
||||
#ifdef WITH_SPIFFS_FAT
|
||||
static const uint32_t FlashLog_FlushSize = 4096; // 4kB file flush step
|
||||
static const uint32_t FlashLog_SavePeriod = 30; // [sec] reopen the file every 30sec
|
||||
static const uint32_t FlashLog_SaveSize = 4096; // [bytes] reopen the file every 4KB
|
||||
#endif
|
||||
|
||||
bool FlashLog_SaveReq=0; // request to save the log right away, like after landing or before shutdown
|
||||
|
@ -291,7 +292,7 @@ static int FlashLog_Open(uint32_t Time) // open a new
|
|||
if(FlashLog_File==0) FlashLog_Clean(0, 4); // if the file cannot be open clean again
|
||||
return FlashLog_File!=0; } // 1=success, 0=failure: new log file could not be open
|
||||
|
||||
static void FlashLog_Save(void)
|
||||
static void FlashLog_Reopen(void)
|
||||
{ if(FlashLog_File)
|
||||
{ fclose(FlashLog_File);
|
||||
FlashLog_File = fopen(FlashLog_FileName, "ab");
|
||||
|
@ -317,7 +318,7 @@ static int FlashLog_Record(OGN_LogPacket<OGN_Packet> *Packet, int Packets, uint3
|
|||
{ fclose(FlashLog_File); FlashLog_File=0; FlashLog_Clean(0, 4); return -1; } // if failure then close the log file and report error
|
||||
#ifdef WITH_SPIFFS_FAT
|
||||
uint32_t WritePos = ftell(FlashLog_File);
|
||||
if(WritePos-FlashLog_FileFlush>FlashLog_FlushSize) FlashLog_Save();
|
||||
if(WritePos-FlashLog_FileFlush>FlashLog_SaveSize) FlashLog_Reopen();
|
||||
#endif
|
||||
return Packets; } // report success
|
||||
#endif // WITH_SPIFFS
|
||||
|
@ -383,7 +384,7 @@ void vTaskLOG(void* pvParameters)
|
|||
TickType_t PrevTick = 0;
|
||||
for( ; ; )
|
||||
{ // vTaskDelay(200); // wait idle 0.2sec
|
||||
if(FlashLog_SaveReq) FlashLog_Save(); // if requested then save the current log (close + reopen)
|
||||
if(FlashLog_SaveReq) FlashLog_Reopen(); // if requested then save the current log (close + reopen)
|
||||
TickType_t Tick=xTaskGetTickCount(); // system tick count now
|
||||
size_t Packets = FlashLog_FIFO.Full(); // how many packets in the queue ?
|
||||
// #ifdef DEBUG_PRINT
|
||||
|
|
|
@ -139,10 +139,10 @@ class OGN1_Packet // Packet structure for the OGN tracker
|
|||
|
||||
// void recvBytes(const uint8_t *SrcPacket) { memcpy(Byte(), SrcPacket, Bytes); } // load data bytes e.g. from a demodulator
|
||||
|
||||
static const uint8_t InfoParmNum = 14; // [int] number of info-parameters and their names
|
||||
static const uint8_t InfoParmNum = 15; // [int] number of info-parameters and their names
|
||||
static const char *InfoParmName(uint8_t Idx) { static const char *Name[InfoParmNum] =
|
||||
{ "Pilot", "Manuf", "Model", "Type", "SN", "Reg", "ID", "Class",
|
||||
"Task" , "Base" , "ICE" , "PilotID", "Hard", "Soft" } ;
|
||||
"Task" , "Base" , "ICE" , "PilotID", "Hard", "Soft", "Crew" } ;
|
||||
return Idx<InfoParmNum ? Name[Idx]:0; }
|
||||
|
||||
#ifndef __AVR__
|
||||
|
|
|
@ -75,7 +75,7 @@ class FlashParameters
|
|||
uint8_t FreqPlan; // force given frequency hopping plan
|
||||
|
||||
static const uint8_t InfoParmLen = 16; // [char] max. size of an infp-parameter
|
||||
static const uint8_t InfoParmNum = 14; // [int] number of info-parameters
|
||||
static const uint8_t InfoParmNum = 15; // [int] number of info-parameters
|
||||
char *InfoParmValue(uint8_t Idx) { return Idx<InfoParmNum ? Pilot + Idx*InfoParmLen:0; }
|
||||
uint8_t InfoParmValueLen(uint8_t Idx) { return strlen(InfoParmValue(Idx)); }
|
||||
// const char *InfoParmName(uint8_t Idx) const { static const char *Name[InfoParmNum] =
|
||||
|
@ -96,6 +96,7 @@ class FlashParameters
|
|||
char PilotID[InfoParmLen]; // Pilot ID based on his BT or WiFi MAC
|
||||
char Hard[InfoParmLen]; // Hardware
|
||||
char Soft[InfoParmLen]; // Software
|
||||
char Crew[InfoParmLen]; // Crew/2nd pilot name
|
||||
|
||||
// char Copilot[16]
|
||||
// char Category[16]
|
||||
|
|
|
@ -18,7 +18,7 @@ static FILE *LogFile = 0;
|
|||
|
||||
static uint16_t LogDate = 0; // [~days] date = FatTime>>16
|
||||
static TickType_t LogOpenTime; // [msec] when was the log file (re)open
|
||||
static const TickType_t LogReopen = 30000; // [msec] when to close and re-open the log file
|
||||
static const TickType_t LogReopen = 20000; // [msec] when to close and re-open the log file
|
||||
|
||||
const size_t FIFOsize = 16384;
|
||||
static FIFO<char, FIFOsize> Log_FIFO; // 16K buffer for SD-log
|
||||
|
@ -80,11 +80,22 @@ static int WriteLog(size_t MaxBlock=FIFOsize/2) // process th
|
|||
|
||||
const char *IGC_Path = "/sdcard/IGC";
|
||||
const int IGC_PathLen = 11;
|
||||
const uint32_t IGC_SavePeriod = 20;
|
||||
// constexpr int IGC_PathLen = strlen(IGC_Path);
|
||||
const char *IGC_Serial = "XXX";
|
||||
char IGC_Serial[4] = { 0, 0, 0, 0 };
|
||||
char IGC_FileName[32];
|
||||
static FILE *IGC_File=0;
|
||||
uint8_t IGC_FlightNum=0;
|
||||
static uint32_t IGC_SaveTime=0;
|
||||
uint16_t IGC_FlightNum=0;
|
||||
|
||||
static void IGC_TimeStamp(void)
|
||||
{ struct stat FileStat;
|
||||
struct utimbuf FileTime;
|
||||
if(stat(IGC_FileName, &FileStat)>=0) // get file attributes (maybe not needed really ?
|
||||
{ FileTime.actime = IGC_SaveTime; // set access and modification tim$
|
||||
FileTime.modtime = IGC_SaveTime;
|
||||
utime(IGC_FileName, &FileTime); } // write to the FAT
|
||||
}
|
||||
|
||||
static void IGC_Close(void)
|
||||
{ if(IGC_File) // if a file open, then close it and increment the flight number
|
||||
|
@ -93,16 +104,19 @@ static void IGC_Close(void)
|
|||
Format_String(CONS_UART_Write, IGC_FileName);
|
||||
Format_String(CONS_UART_Write, "\n");
|
||||
xSemaphoreGive(CONS_Mutex);
|
||||
fclose(IGC_File); IGC_File=0; IGC_FlightNum++;
|
||||
uint32_t Time = TimeSync_Time();
|
||||
fclose(IGC_File); IGC_File=0; IGC_FlightNum++; }
|
||||
}
|
||||
/*
|
||||
IGC_SaveTime = TimeSync_Time();
|
||||
struct stat FileStat;
|
||||
struct utimbuf FileTime;
|
||||
if(stat(IGC_FileName, &FileStat)>=0) // get file attributes (maybe not needed really ?
|
||||
{ FileTime.actime = Time; // set access and modification tim$
|
||||
FileTime.modtime = Time;
|
||||
{ FileTime.actime = IGC_SaveTime; // set access and modification tim$
|
||||
FileTime.modtime = IGC_SaveTime;
|
||||
utime(IGC_FileName, &FileTime); } // write to the FAT
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static int IGC_Open(void)
|
||||
{ IGC_Close(); // close the previous file, if open
|
||||
|
@ -117,17 +131,58 @@ static int IGC_Open(void)
|
|||
{ if(mkdir(IGC_Path, 0777)<0) return -3; // -3 => can't create sub-dir
|
||||
IGC_File=fopen(IGC_FileName, "wt"); } // retry to open for write
|
||||
if(IGC_File)
|
||||
{ xSemaphoreTake(CONS_Mutex, portMAX_DELAY);
|
||||
{ IGC_SaveTime = TimeSync_Time();
|
||||
xSemaphoreTake(CONS_Mutex, portMAX_DELAY);
|
||||
Format_String(CONS_UART_Write, "IGC_Open: ");
|
||||
Format_String(CONS_UART_Write, IGC_FileName);
|
||||
Format_String(CONS_UART_Write, "\n");
|
||||
xSemaphoreGive(CONS_Mutex); }
|
||||
return IGC_File ? 0:-4; } // -4 => can't open for write
|
||||
|
||||
static void IGC_Reopen(void)
|
||||
{ if(IGC_File)
|
||||
{ fclose(IGC_File);
|
||||
IGC_SaveTime = TimeSync_Time();
|
||||
IGC_TimeStamp();
|
||||
IGC_File=fopen(IGC_FileName, "at"); }
|
||||
}
|
||||
|
||||
static char Line[192];
|
||||
|
||||
static int IGC_Header(void) // write the top of the IGC file
|
||||
{
|
||||
static int IGC_HeadParm(const char *Name, const char *Parm)
|
||||
{ int Len=Format_String(Line, Name);
|
||||
Len+=Format_String(Line+Len, Parm);
|
||||
Line[Len++]='\n'; Line[Len]=0;
|
||||
fputs(Line, IGC_File);
|
||||
return 0; }
|
||||
|
||||
static int IGC_Header(const GPS_Position &Pos) // write the top of the IGC file
|
||||
{ fputs("AGNE001Tracker\n", IGC_File);
|
||||
{ int Len=Format_String(Line, "HFDTEDate:"); // date
|
||||
Len+=Format_UnsDec(Line+Len, (uint16_t)Pos.Day , 2);
|
||||
Len+=Format_UnsDec(Line+Len, (uint16_t)Pos.Month, 2);
|
||||
Len+=Format_UnsDec(Line+Len, (uint16_t)Pos.Year , 2);
|
||||
Line[Len++]=',';
|
||||
Len+=Format_UnsDec(Line+Len, (uint16_t)IGC_FlightNum, 2);
|
||||
Line[Len++]='\n'; Line[Len]=0;
|
||||
fputs(Line, IGC_File); }
|
||||
IGC_HeadParm("HFPLTPilotincharge:", Parameters.Pilot);
|
||||
IGC_HeadParm("HFGTYGliderType:", Parameters.Type);
|
||||
IGC_HeadParm("HFGIDGliderID:", Parameters.Reg);
|
||||
IGC_HeadParm("HFCM2Crew2:", Parameters.Crew);
|
||||
IGC_HeadParm("HFCCLCompetitionClass:", Parameters.Class);
|
||||
IGC_HeadParm("HFCIDCompetitionID:", Parameters.ID);
|
||||
{ int Len=Format_String(Line, "HFGIDGliderid:"); // unique ID
|
||||
uint64_t ID = getUniqueID(); // 48-bit ID
|
||||
Len+=Format_Hex(Line+Len, (uint16_t)(ID>>32));
|
||||
Len+=Format_Hex(Line+Len, (uint32_t)ID);
|
||||
Line[Len++]=',';
|
||||
Len+=Format_Hex(Line+Len, Parameters.AcftID); // stealth, no-track, aircraft-type, address-type, address
|
||||
Line[Len++]='\n'; Line[Len]=0;
|
||||
fputs(Line, IGC_File); }
|
||||
fputs("HFRFWFirmwareVersion:" __DATE__ " " __TIME__ "\n", IGC_File);
|
||||
fputs("HFGPSReceiver:L80\n", IGC_File); // GPS sensor
|
||||
fputs("HFPRSPressAltSensor:BMP280\n", IGC_File); // pressure sensor
|
||||
return 0; }
|
||||
|
||||
static int IGC_Log(const GPS_Position &Pos) // log GPS position as B-record
|
||||
|
@ -161,13 +216,18 @@ static void IGC_Check(void) // check if
|
|||
if(IGC_File) // if IGC file already open
|
||||
{ IGC_Log(GPS_Pos[PosIdx]); // log position
|
||||
if(!inFlight) // if no longer in flight
|
||||
{ IGC_Close(); } // then close the IGC file
|
||||
{ IGC_Close(); IGC_TimeStamp(); } // then close the IGC file
|
||||
else
|
||||
{ uint32_t Time=TimeSync_Time();
|
||||
if(Time-IGC_SaveTime>=IGC_SavePeriod)
|
||||
{ IGC_Reopen(); }
|
||||
}
|
||||
}
|
||||
else // if IGC file is not open
|
||||
{ if(inFlight) // and in-flight
|
||||
{ for(int Try=0; Try<8; Try++)
|
||||
{ int Err=IGC_Open(); if(Err!=(-2)) break; } // try to open a new IGC file but don't overwrite the old ones
|
||||
if(IGC_File) { IGC_Header(); IGC_Log(GPS_Pos[PosIdx]); } // if open succesfully then write header and first B-record
|
||||
if(IGC_File) { IGC_Header(GPS_Pos[PosIdx]); IGC_Log(GPS_Pos[PosIdx]); } // if open succesfully then write header and first B-record
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -178,7 +238,12 @@ static void IGC_Check(void) // check if
|
|||
|
||||
extern "C"
|
||||
void vTaskSDLOG(void* pvParameters)
|
||||
{ Log_FIFO.Clear();
|
||||
{ uint32_t ID = getUniqueAddress();
|
||||
IGC_Serial[2] = Flight.Code36(ID%36); ID/=36;
|
||||
IGC_Serial[1] = Flight.Code36(ID%36); ID/=36;
|
||||
IGC_Serial[0] = Flight.Code36(ID%36);
|
||||
|
||||
Log_FIFO.Clear();
|
||||
|
||||
for( ; ; )
|
||||
{ if(!SD_isMounted()) // if SD ia not mounted:
|
||||
|
|
Ładowanie…
Reference in New Issue