DMR - UDT Fixes and NMEA Support; #177

This commit is contained in:
lwvmobile 2023-12-16 20:06:10 -05:00
parent 67b7272b05
commit 7193bca136
1 changed files with 132 additions and 8 deletions

View File

@ -121,6 +121,13 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
//ETSI TS 102 361-4 V1.12.1 (2023-07) p281
udt_uab += 1; //add 1 internally, up to 4 appended blocks are carried, min is 1
//NMEA Specific Fix for unspecified MFID format w/ 2 appended blocks (UAB 2) p291
if (udt_uab == 0x5 && udt_uab == 3)
udt_uab = 2; //set to two if long unspecified format
//Note: NMEA Reserved value UAB 3 is not referenced in ETSI, so unknown number of
//appended blocks but we will assume it is supposed to be 4 appended blocks
//p_head
uint8_t p_sap = (uint8_t)ConvertBitIntoBytes(&dheader_bits[0], 4);
uint8_t p_mfid = (uint8_t)ConvertBitIntoBytes(&dheader_bits[8], 8);
@ -373,15 +380,112 @@ void dmr_dheader (dsd_opts * opts, dsd_state * state, uint8_t dheader[], uint8_t
}
void nmea_iec_61162_1 (dsd_opts * opts, dsd_state * state, uint8_t * input, uint32_t src, int type)
{
int slot = state->currentslot;
//NOTE: The Only difference between Short (type == 1) and Long Format (type == 2)
//is the utc_ss3 on short vs utc_ss6 and inclusion of COG value on long
//NOTE: MFID Specific Formats are not handled here, unknown, could be added if worked out
//they could share most of the same elements and use the large spare bits in block 2 for extra
// uint8_t mfid = (uint8_t)ConvertBitIntoBytes(&input[88], 8); //on type 3, last octet of first block carries MFID
// uint8_t nmea_c = input[0]; //encrypted -- checked before we get here
uint8_t nmea_ns = input[1]; //north/south (lat sign)
uint8_t nmea_ew = input[2]; //east/west (lon sign)
uint8_t nmea_q = input[3]; //Quality Indicator (no fix or fix valid)
uint8_t nmea_speed = (uint8_t)ConvertBitIntoBytes(&input[4], 7); //speed in knots (127 = greater than 126 knots)
//Latitude Bits
uint8_t nmea_ndeg = (uint8_t)ConvertBitIntoBytes(&input[11], 7); //Latitude Degrees
uint8_t nmea_nmin = (uint8_t)ConvertBitIntoBytes(&input[18], 6); //Latitude Minutes
uint16_t nmea_nminf = (uint16_t)ConvertBitIntoBytes(&input[24], 14); //Latitude Fractions of Minutes
//Longitude Bits
uint8_t nmea_edeg = (uint8_t)ConvertBitIntoBytes(&input[38], 8); //Longitude Degrees
uint8_t nmea_emin = (uint8_t)ConvertBitIntoBytes(&input[46], 6); //Longitude Minutes
uint16_t nmea_eminf = (uint16_t)ConvertBitIntoBytes(&input[52], 14); //Longitude Fractions of Minutes
//UTC Time and COG
uint8_t nmea_utc_hh = (uint8_t)ConvertBitIntoBytes(&input[66], 5);
uint8_t nmea_utc_mm = (uint8_t)ConvertBitIntoBytes(&input[71], 6);
//seconds and the addition of COG is the difference between short and long formats
uint8_t nmea_utc_ss3 = (uint8_t)ConvertBitIntoBytes(&input[77], 3); //seconds in 10s
uint8_t nmea_utc_ss6 = (uint8_t)ConvertBitIntoBytes(&input[77], 6); //seconds in 1s
uint16_t nmea_cog = (uint16_t)ConvertBitIntoBytes(&input[103], 9); //course over ground in degrees
//lat and lon conversion
char deg_glyph[4];
sprintf (deg_glyph, "%s", "°");
float latitude = 0.0f;
float longitude = 0.0f;
float m_unit = 1.0f / 60.0f; //unit to convert min into decimal value - (1/60)*60 minutes = 1 degree
float mm_unit = 1.0f / 1000.0f; //unit to convert minf into decimal value - (0000 - 9999) 0.0001×9999 = .9999 minutes, so its sub 1 minute decimal
//speed conversion
float fmps, fmph, fkph = 0.0f; //conversion of knots to mps, kph, and mph values
fmps = (float)nmea_speed * 0.514444; UNUSED(fmps);
fmph = (float)nmea_speed * 1.15078f; UNUSED(fmph);
fkph = (float)nmea_speed * 1.852f;
//calculate decimal representation of latidude and longitude (need some samples to test)
latitude = ( (float)nmea_ndeg + ((float)nmea_nmin*m_unit) + ((float)nmea_nminf*mm_unit) );
longitude = ( (float)nmea_edeg + ((float)nmea_emin*m_unit) + ((float)nmea_eminf*mm_unit) );
if (!nmea_ns) latitude *= -1.0f; //0 is South, 1 is North
if (nmea_ew) longitude *= -1.0f; //0 is West, 1 is East
fprintf (stderr, " GPS: %f%s, %f%s;", latitude, deg_glyph, longitude, deg_glyph);
//Speed in Knots
if (nmea_speed > 126)
fprintf (stderr, " SPD > 126 knots or %f kph;", fkph);
else
fprintf (stderr, " SPD: %d knots; %f kph;", nmea_speed, fkph);
//Print UTC Time and COG according to Format Type
if (type == 1)
fprintf (stderr, " FIX: %d; %02d:%02d:%02d UTC; Short Format;", nmea_q, nmea_utc_hh, nmea_utc_mm, nmea_utc_ss3);
if (type == 2)
fprintf (stderr, " FIX: %d; %02d:%02d:%02d UTC; COG: %d%s; Long Format;", nmea_q, nmea_utc_hh, nmea_utc_mm, nmea_utc_ss6, nmea_cog, deg_glyph);
//save to ncurses string
sprintf (state->dmr_embedded_gps[slot], "GPS: (%f%s, %f%s)", latitude, deg_glyph, longitude, deg_glyph);
//save to LRRP report for mapping/logging
FILE * pFile; //file pointer
if (opts->lrrp_file_output == 1)
{
int s = (int)fkph; //rounded interger format for the log report
int a = 0;
if (type == 2)
a = nmea_cog; //long format only
//open file by name that is supplied in the ncurses terminal, or cli
pFile = fopen (opts->lrrp_out_file, "a");
fprintf (pFile, "%s\t", getDateL() );
fprintf (pFile, "%s\t", getTimeL() ); //could switch to UTC time if desired, but would require local user offset
fprintf (pFile, "%08d\t", src);
fprintf (pFile, "%.6lf\t", latitude);
fprintf (pFile, "%.6lf\t", longitude);
fprintf (pFile, "%d\t ", s);
fprintf (pFile, "%d\t ", a);
fprintf (pFile, "\n");
fclose (pFile);
}
}
void dmr_udt_decoder (dsd_opts * opts, dsd_state * state, uint8_t * block_bytes, uint32_t CRCCorrect)
{
//TODO: double check end rep values to Text Format Modes vs padnibs/uab values
//TODO: Make Text Format Modes seperate function to be used more generically by other things
//TODO: NMEA/LIP Format (make seperate functions, LIP also used by USBD)
//TODO: LIP Format (make seperate functions, LIP also used by USBD)
int i, j;
UNUSED(CRCCorrect);
UNUSED(opts);
UNUSED(state);
int slot = state->currentslot;
uint8_t cs_bits[8*12*5]; //maximum of 1 header and 4 blocks at 96 bits
UNUSED(cs_bits);
@ -435,9 +539,18 @@ void dmr_udt_decoder (dsd_opts * opts, dsd_state * state, uint8_t * block_bytes,
//BCD Format (Dialer Digits) -- max is 92 digits
uint8_t bcd_digits[93]; memset (bcd_digits, 0, sizeof(bcd_digits)); UNUSED(bcd_digits);
//NMEA Debug Testing (need real world samples)
// udt_format2 = 0x5;
// for (int i = 0; i < 8; i++) cs_bits[184+i] = 0; //spare bits to zero
// cs_bits[96] = 0; //enc bit to zero
// uint8_t test[96*4]; memset (test, 1, sizeof(test)); // all ones test vector
// nmea_iec_61162_1 (opts, state, test, udt_source, 1);
// nmea_iec_61162_1 (opts, state, cs_bits+96, udt_source, 2);
//initial linebreak
fprintf (stderr, "%s", KCYN);
fprintf (stderr, "\n ");
fprintf (stderr, "Slot %d - SRC: %d; TGT: %d; UDT ", slot+1, udt_source, udt_target);
if (udt_format2 == 0x00) ; //do we really want to do anything with this?
else if (udt_format2 == 0x01) //appended addresses
@ -502,7 +615,7 @@ void dmr_udt_decoder (dsd_opts * opts, dsd_state * state, uint8_t * block_bytes,
else fprintf (stderr, " ");
}
}
else if (udt_format2 == 0x07) //UTF16 format
else if (udt_format2 == 0x07) //UTF-16BE format
{
if (udt_uab == 1) end = 5;
if (udt_uab == 2) end = 11;
@ -530,7 +643,6 @@ void dmr_udt_decoder (dsd_opts * opts, dsd_state * state, uint8_t * block_bytes,
}
else //IP6
{
//TODO: 8 by 4 hex seperated by colons
fprintf (stderr, "IP6: ");
fprintf (stderr, "%04X:",(uint16_t)ConvertBitIntoBytes(&cs_bits[96+0], 16));
fprintf (stderr, "%04X:",(uint16_t)ConvertBitIntoBytes(&cs_bits[96+16], 16));
@ -542,7 +654,7 @@ void dmr_udt_decoder (dsd_opts * opts, dsd_state * state, uint8_t * block_bytes,
fprintf (stderr, "%04X", (uint16_t)ConvertBitIntoBytes(&cs_bits[96+104], 16));
}
}
else if (udt_format2 == 0x0A) //Mixed Address/UTF16
else if (udt_format2 == 0x0A) //Mixed Address/UTF-16BE
{
if (udt_uab == 1) end = 3;
if (udt_uab == 2) end = 9;
@ -559,9 +671,21 @@ void dmr_udt_decoder (dsd_opts * opts, dsd_state * state, uint8_t * block_bytes,
else fprintf (stderr, " ");
}
}
else if (udt_format2 == 0x0A)
else if (udt_format2 == 0x05)
{
fprintf (stderr, "NMEA LOCN: " ); //TODO: Add function to decode NMEA formats
//Would be nice to be able to test these all out to make sure the conditions are okay, etc
fprintf (stderr, "NMEA" );
if (cs_bits[96] == 1) //check if its encrypted first
fprintf (stderr, " Encrypted Format :(" ); //sad face
else if (udt_uab == 1)
nmea_iec_61162_1 (opts, state, cs_bits+96, udt_source, 1); //short format w/ 1 appended block
else if (udt_uab == 2)
nmea_iec_61162_1 (opts, state, cs_bits+96, udt_source, 2); //standard long format w/ 2 appended blocks
//check the 'spare' bits from 184 to 192 to see if this is a manufacturer specific nmea format
else if (udt_uab == 3) //mfid format w/ 2 appended blocks -- format unspecified -- this may fail to trigger due to block assembler
fprintf (stderr, " Unspecified MFID Format: %02X;", (uint8_t)ConvertBitIntoBytes(&cs_bits[184], 8));
else //this may fail to trigger due to block assembler also
fprintf (stderr, " Reserved Format; ");
}
else if (udt_format2 == 0x0B)
{
@ -569,7 +693,7 @@ void dmr_udt_decoder (dsd_opts * opts, dsd_state * state, uint8_t * block_bytes,
}
else if (udt_format2 == 0x08 || udt_format2 == 0x09)
{
fprintf (stderr, "MANUFACTURER SPEC %02X: ", udt_format2);
fprintf (stderr, "MFID SPEC %02X: ", udt_format2);
//use -Z to expose this
}
else