diff --git a/meson.build b/meson.build index b297aad5..7eeefd95 100644 --- a/meson.build +++ b/meson.build @@ -24,7 +24,7 @@ openrtx_src = ['openrtx/src/core/state.c', 'openrtx/src/core/battery.c', 'openrtx/src/core/graphics.cpp', 'openrtx/src/core/input.c', - 'openrtx/src/core/calibUtils.c', + 'openrtx/src/core/utils.c', 'openrtx/src/core/queue.c', 'openrtx/src/core/chan.c', 'openrtx/src/core/gps.c', diff --git a/openrtx/include/core/cps.h b/openrtx/include/core/cps.h index 8bff58fa..66377870 100644 --- a/openrtx/include/core/cps.h +++ b/openrtx/include/core/cps.h @@ -1,8 +1,8 @@ /*************************************************************************** - * Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, * - * Niccolò Izzo IU2KIN, * - * Frederik Saraci IU2NRO, * - * Silvano Seva IU2KWO * + * Copyright (C) 2020 - 2022 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN, * + * Frederik Saraci IU2NRO, * + * Silvano Seva IU2KWO * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -26,129 +26,262 @@ #include #include -/** - * \enum admit_t Enumeration type defining the admission criteria to a the - * channel. - */ -enum admit_t -{ - ALWAYS = 0, /**< Always transmit when PTT is pressed */ - FREE = 1, /**< Transmit only if channel si free */ - TONE = 2, /**< Transmit on matching tone */ - COLOR = 3 /**< Transmit only if color code is not used yet */ -}; +// Magic number to identify the binary file +#define CPS_MAGIC 0x52545843 +// Codeplug version v0.1 +#define CPS_VERSION_MAJOR 0 +#define CPS_VERSION_MINOR 1 +#define CPS_VERSION_NUMBER (CPS_VERSION_MAJOR << 8) | CPS_VERSION_MINOR + + +/****************************************************************************** + * FM MODE * + ******************************************************************************/ /** - * Data structure containing all and only the information for analog FM channels, - * like CTC/DCS tones. + * Data structure containing the tone information for analog FM channels. + * This is just a lookup table for the CTCSS frequencies and is not actually + * present in the codeplug binary data. */ #define MAX_TONE_INDEX 50 -static const uint16_t ctcss_tone[MAX_TONE_INDEX] = { +static const uint16_t ctcss_tone[MAX_TONE_INDEX] = +{ 670, 693, 719, 744, 770, 797, 825, 854, 885, 915, 948, 974, 1000, 1034, 1072, 1109, 1148, 1188, 1230, 1273, 1318, 1365, 1413, 1462, 1514, 1567, 1598, 1622, 1655, 1679, 1713, 1738, 1773, 1799, 1835, 1862, 1899, 1928, 1966, 1995, 2035, 2065, 2107, 2181, 2257, 2291, 2336, 2418, 2503, 2541 }; +/** + * Data structure defining an analog-specific channel information such as tones. + */ typedef struct { - uint8_t rxToneEn : 1, /**< RX CTC/DCS tone enable */ - rxTone : 7; /**< RX CTC/DCS tone index, squelch opens on match */ - uint8_t txToneEn : 1, /**< TX CTC/DCS tone enable */ - txTone : 7; /**< TX CTC/DCS tone index, sent alongside voice */ + uint8_t rxToneEn : 1, //< RX CTC/DCS tone enable + rxTone : 7; //< RX CTC/DCS tone index + uint8_t txToneEn : 1, //< TX CTC/DCS tone enable + txTone : 7; //< TX CTC/DCS tone index } -__attribute__((packed)) fmInfo_t; +__attribute__((packed)) fmInfo_t; // 2B + + + +/****************************************************************************** + * DMR MODE * + ******************************************************************************/ /** * Data structure containing all and only the information for DMR channels. */ typedef struct { - uint8_t rxColorCode : 4, /**< Color code for RX squelch opening */ - txColorCode : 4; /**< Color code sent during transmission */ + uint8_t rxColorCode : 4, //< Color code for RX squelch opening + txColorCode : 4; //< Color code sent during transmission - uint8_t dmr_timeslot; /**< DMR timeslot, either 1 or 2 */ - uint16_t contactName_index; /**< Index to retrieve data from contact list */ + uint8_t dmr_timeslot; //< DMR timeslot, either 1 or 2 + uint16_t contactName_index; //< Index to retrieve contact from list } -__attribute__((packed)) dmrInfo_t; +__attribute__((packed)) dmrInfo_t; // 4B + +/** + * Enumeration type defining the types of a DMR contact. + */ +enum dmrContactType_t +{ + GROUP = 0, //< Group contact (Talkgroup) + PRIVATE = 1, //< Private contact + ALL = 2 //< Broadcast call +}; + +/** + * Data structure describing a DMR contact entry. + */ +typedef struct +{ + uint32_t id; //< DMR id + + uint8_t contactType : 2, //< Call type + rx_tone : 1, //< Call receive tone + _unused : 5; //< Padding +} +__attribute__((packed)) dmrContact_t; // 5B + + + +/****************************************************************************** + * M17 MODE * + ******************************************************************************/ + +/** + * M17 channel modes. + */ +enum m17mode_t +{ + DIGITAL_VOICE = 1, //< Digital Voice + DIGITAL_DATA = 2, //< Digital Data + DIGITAL_VOICE_DATA = 3 //< Digital Voice and Data +}; + +/** + * M17 channel encryption. + */ +enum m17crypto_t +{ + PLAIN = 0, //< No encryption, plaintext data is sent + AES256 = 1, //< AES-256 Encryption + SCRAMBLER = 2 //< Scrambler +}; + +/** + * M17 gps operation. + */ +enum m17gps_t +{ + NO_GPS = 0, //< No GPS information is sent + GPS_META = 1 //< GPS position is sent along with payload +}; /** * Data structure containing all and only the information for M17 channels. */ typedef struct { - uint8_t rxCan : 4, /**< Channel Access Number for RX squelch */ - txCan : 4; /**< Channel Access Number for TX squelch */ - - uint16_t contactName_index; /**< Index to retrieve data from contact list */ + uint8_t rxCan : 4, //< Channel Access Number for RX + txCan : 4; //< Channel Access Number for TX + uint8_t mode : 4, //< Channel operation mode + encr : 4; //< Encryption mode + uint8_t gps_mode; //< Channel GPS mode + uint16_t contactName_index; //< Index to retrieve data from contact list } -__attribute__((packed)) m17Info_t; +__attribute__((packed)) m17Info_t; // 5B /** - * Data structure containing all the information of a channel, either FM or DMR. + * Data structure describing M17-specific contact fields. */ typedef struct { - uint8_t mode; /**< Operating mode */ + uint8_t address[6]; //< M17 encoded address +} +__attribute__((packed)) m17Contact_t; // 6B - uint8_t bandwidth : 2, /**< Bandwidth */ - admit_criteria : 2, /**< Admit criterion */ - squelch : 1, /**< Squelch type: 0 = tight, 1 = normal */ - rx_only : 1, /**< 1 means RX-only channel */ - vox : 1, /**< VOX enable */ - _padding : 1; /**< Padding to 8 bits */ - float power; /**< Transmission power, in watt */ - freq_t rx_frequency; /**< RX Frequency, in Hz */ - freq_t tx_frequency; /**< TX Frequency, in Hz */ +/****************************************************************************** + * COMMON DATA STRUCTURES * + ******************************************************************************/ - uint8_t tot; /**< TOT x 15sec: 0-Infinite, 1=15s...33=495s */ - uint8_t tot_rekey_delay; /**< TOT Rekey Delay: 0...255s */ +/** + * Data structure for geolocation data + */ +typedef struct +{ + int8_t ch_lat_int; //< Latitude integer part + uint16_t ch_lat_dec; //< Latitude decimal part + int16_t ch_lon_int; //< Longitude integer part + uint16_t ch_lon_dec; //< Longitude decimal part + uint16_t ch_altitude; //< Meters MSL. Stored +500 +} +__attribute__((packed)) geo_t; // 9B - uint8_t emSys_index; /**< Emergency System: None, System1...32 */ - uint8_t scanList_index; /**< Scan List: None, ScanList1...250 */ - uint8_t groupList_index; /**< Group List: None, GroupList1...128 */ +/** + * Data structure containing all the information of a channel. + */ +typedef struct +{ + uint8_t mode; //< Operating mode - char name[16]; /**< Channel name */ + uint8_t bandwidth : 2, //< Bandwidth + rx_only : 1, //< 1 means RX-only channel + _unused : 5; //< Padding to 8 bits + + uint8_t power; //< P = 10dBm + n*0.2dBm, we store n + + freq_t rx_frequency; //< RX Frequency, in Hz + freq_t tx_frequency; //< TX Frequency, in Hz + + uint8_t scanList_index; //< Scan List: None, ScanList1...250 + uint8_t groupList_index; //< Group List: None, GroupList1...128 + + char name[16]; //< Channel name + char descr[16]; //< Description of the channel + geo_t ch_location; //< Transmitter geolocation union { - fmInfo_t fm; /**< Information block for FM channels */ - dmrInfo_t dmr; /**< Information block for DMR channels */ - m17Info_t m17; /**< Information block for M17 channels */ + fmInfo_t fm; //< Information block for FM channels + dmrInfo_t dmr; //< Information block for DMR channels + m17Info_t m17; //< Information block for M17 channels }; } -__attribute__((packed)) channel_t; - +__attribute__((packed)) channel_t; // 59B /** - * Data structure containing all the information of a bank. + * Data structure describing a codeplug contact. */ typedef struct { - char name[16]; /**< Bank name */ - uint16_t member[64]; /**< Channel indexes */ + char name[16]; //< Display name of the contact + uint8_t mode; //< Operating mode + + union + { + dmrContact_t dmr; //< DMR specific contact info + m17Contact_t m17; //< M17 specific contact info + } + info; // 6B +} +__attribute__((packed)) contact_t; // 23B + +/** + * Data structure containing all the information of a bank. + * Legacy data structure for brackwards compatibility. + */ +typedef struct +{ + char name[16]; //< Bank name + uint16_t member[64]; //< Channel indexes } __attribute__((packed)) bank_t; /** - * Data structure containing all the information of a contact. + * Data structure describing a bank header. */ typedef struct { - char name[16]; /**< Contact name */ - uint32_t id; /**< DMR ID: 24bit number, 1...16777215 */ - uint8_t type; /**< Call Type: Group Call, Private Call or All Call */ - bool receive_tone; /**< Call Receive Tone: No or yes */ + char name[16]; + uint16_t ch_count; //< Count of all the channels in this bank } -__attribute__((packed)) contact_t; +__attribute__((packed)) bankHdr_t; // 18B + 2 * ch_count -/* + +/** + * The codeplug binary structure is composed by: + * - A header struct + * - A variable length array of all the contacts + * - A variable length array of all the channels + * - A variable length array of the offsets to reach each bank + * - A binary dense structure of all the banks + */ +typedef struct +{ + uint64_t magic; //< Magic number "RTXC" + uint16_t version_number; //< Version number for the cps structure + char author[16]; //< Author of the codeplug + char descr[16]; //< Description of the codeplug + uint64_t timestamp; //< unix timestamp of the codeplug + + uint16_t ct_count; //< Number of stored contacts + uint16_t ch_count; //< Number of stored channels + uint16_t b_count; //< Number of stored banks +} +__attribute__((packed)) cps_header_t; // 52B + +/** * Create and return a viable channel for this radio. * Suitable for default VFO settings or the creation of a new channel. - * Needs to be generated by a function frequency settings require details from the running hardware on limitations + * Needs to be generated by a function frequency settings require details from + * the running hardware on limitations. */ -channel_t get_default_channel(); +channel_t cps_getDefaultChannel(); -#endif +#endif // CPS_H diff --git a/openrtx/include/core/gps.h b/openrtx/include/core/gps.h index 46598f8a..214834a8 100644 --- a/openrtx/include/core/gps.h +++ b/openrtx/include/core/gps.h @@ -20,13 +20,47 @@ #ifndef GPS_H #define GPS_H -#include +#include +#include + +/** + * Data structure representing a single satellite as part of a GPS fix. + */ +typedef struct +{ + uint8_t id; // ID of the satellite + uint8_t elevation; // Elevation in degrees + uint16_t azimuth; // Azimuth in degrees + uint8_t snr; // Quality of the signal in range 0-99 +} +sat_t; + +/** + * Data structure representing the last state received from the GPS module. + */ +typedef struct +{ + curTime_t timestamp; // Timestamp of the latest GPS update + uint8_t fix_quality; // 0: no fix, 1: GPS, 2: GPS SPS, 3: GPS PPS + uint8_t fix_type; // 0: no fix, 1: 2D, 2: 3D + uint8_t satellites_tracked; // Number of tracked satellites + uint8_t satellites_in_view; // Satellites in view + sat_t satellites[12]; // Details about satellites in view + uint32_t active_sats; // Bitmap representing which sats are part of the fix + float latitude; // Latitude coordinates + float longitude; // Longitude coordinates + float altitude; // Antenna altitude above mean sea level (geoid) in m + float speed; // Ground speed in km/h + float tmg_mag; // Course over ground, degrees, magnetic + float tmg_true; // Course over ground, degrees, true +} +gps_t; /** * This function perfoms the task of reading data from the GPS module, * if available, enabled and ready, decode NMEA sentences and update * the radio state with the retrieved data. */ -void gps_taskFunc(char *line, int len, state_t *state); +void gps_taskFunc(char *line, int len); #endif /* GPS_H */ diff --git a/openrtx/include/core/state.h b/openrtx/include/core/state.h index eb820c2d..691c642a 100644 --- a/openrtx/include/core/state.h +++ b/openrtx/include/core/state.h @@ -26,50 +26,18 @@ #include #include #include - -/** - * Data structure representing a single satellite as part of a GPS fix. - */ -typedef struct -{ - uint8_t id; // ID of the satellite - uint8_t elevation; // Elevation in degrees - uint16_t azimuth; // Azimuth in degrees - uint8_t snr; // Quality of the signal in range 0-99 -} -sat_t; - -/** - * Data structure representing the last state received from the GPS module. - */ -typedef struct -{ - curTime_t timestamp; // Timestamp of the latest GPS update - uint8_t fix_quality; // 0: no fix, 1: GPS, 2: GPS SPS, 3: GPS PPS - uint8_t fix_type; // 0: no fix, 1: 2D, 2: 3D - uint8_t satellites_tracked; // Number of tracked satellites - uint8_t satellites_in_view; // Satellites in view - sat_t satellites[12]; // Details about satellites in view - uint32_t active_sats; // Bitmap representing which sats are part of the fix - float latitude; // Latitude coordinates - float longitude; // Longitude coordinates - float altitude; // Antenna altitude above mean sea level (geoid) in m - float speed; // Ground speed in km/h - float tmg_mag; // Course over ground, degrees, magnetic - float tmg_true; // Course over ground, degrees, true -} -gps_t; +#include /** * Data structure representing the settings of the M17 mode. */ typedef struct { -// char callsign[10]; char dst_addr[10]; } m17_t; + /** * Part of this structure has been commented because the corresponding * functionality is not yet implemented. @@ -85,12 +53,6 @@ typedef struct uint8_t ui_screen; uint8_t tuner_mode; - //time_t rx_status_tv; - //bool rx_status; - - //time_t tx_status_tv; - //bool tx_status; - uint16_t channel_index; channel_t channel; channel_t vfo_channel; @@ -130,12 +92,6 @@ extern state_t state; */ void state_init(); -/** - * Write default values to OpenRTX settings and VFO Channel configuration. - * Writes out to flash and calls state_init again to reload it immediately. - */ -void defaultSettingsAndVfo(); - /** * This function terminates the radio state saving persistent settings to flash. */ @@ -146,6 +102,11 @@ void state_terminate(); */ void state_update(); +/** + * Reset the fields of radio state containing user settings and VFO channel. + */ +void state_resetSettingsAndVfo(); + /** * The RTC and state.time are set to UTC time * Use this function to get local time from UTC time based on timezone setting diff --git a/openrtx/include/calibration/calibUtils.h b/openrtx/include/core/utils.h similarity index 84% rename from openrtx/include/calibration/calibUtils.h rename to openrtx/include/core/utils.h index dda68ac7..5075177f 100644 --- a/openrtx/include/calibration/calibUtils.h +++ b/openrtx/include/core/utils.h @@ -1,7 +1,7 @@ /*************************************************************************** - * Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, * - * Niccolò Izzo IU2KIN, * - * Silvano Seva IU2KWO * + * Copyright (C) 2020 - 2022 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN, * + * Silvano Seva IU2KWO * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -32,6 +32,7 @@ extern "C" { * frequencies outside the calibration points. It works by searching the two * calibration points containing the target frequency and then by linearly * interpolating the calibration parameter among these two points. + * * @param freq: target frequency for which a calibration value has to be * computed. * @param calPoints: pointer to the vector containing the frequencies of the @@ -46,6 +47,15 @@ extern "C" { uint8_t interpCalParameter(const freq_t freq, const freq_t *calPoints, const uint8_t *param, const uint8_t elems); +/** + * Convert from "OpenRTX dBm" to watt. + * In OpenRTX cps power is stored as the coefficient n of the equation + * P(dBm) = 10 + 2*0.2. + * + * @param n: coefficient of the dBm equation. + * @return power in watt. + */ +float dBmToWatt(const uint8_t n); #ifdef __cplusplus } diff --git a/openrtx/src/core/cps.c b/openrtx/src/core/cps.c index d4b4aaeb..053dd81e 100644 --- a/openrtx/src/core/cps.c +++ b/openrtx/src/core/cps.c @@ -1,8 +1,7 @@ #include #include - -channel_t get_default_channel() +channel_t cps_getDefaultChannel() { channel_t channel; channel.mode = OPMODE_FM; diff --git a/openrtx/src/core/gps.c b/openrtx/src/core/gps.c index 4894db18..7312e69f 100644 --- a/openrtx/src/core/gps.c +++ b/openrtx/src/core/gps.c @@ -30,13 +30,15 @@ /** * This function parses a GPS NMEA sentence and updates radio state */ -void gps_taskFunc(char *line, __attribute__((unused)) int len, state_t *state) +void gps_taskFunc(char *line, int len) { + (void) len; + char nmea_id[3] = { 0 }; // Little mechanism to ensure that RTC is synced with GPS time only once. static bool isRtcSyncronised = false; - if(!state->gps_set_time) + if(!state.gps_set_time) { isRtcSyncronised = false; } @@ -55,27 +57,27 @@ void gps_taskFunc(char *line, __attribute__((unused)) int len, state_t *state) struct minmea_sentence_rmc frame; if (minmea_parse_rmc(&frame, line)) { - state->gps_data.latitude = minmea_tocoord(&frame.latitude); - state->gps_data.longitude = minmea_tocoord(&frame.longitude); - state->gps_data.timestamp.hour = frame.time.hours; - state->gps_data.timestamp.minute = frame.time.minutes; - state->gps_data.timestamp.second = frame.time.seconds; - state->gps_data.timestamp.day = 0; - state->gps_data.timestamp.date = frame.date.day; - state->gps_data.timestamp.month = frame.date.month; - state->gps_data.timestamp.year = frame.date.year; + state.gps_data.latitude = minmea_tocoord(&frame.latitude); + state.gps_data.longitude = minmea_tocoord(&frame.longitude); + state.gps_data.timestamp.hour = frame.time.hours; + state.gps_data.timestamp.minute = frame.time.minutes; + state.gps_data.timestamp.second = frame.time.seconds; + state.gps_data.timestamp.day = 0; + state.gps_data.timestamp.date = frame.date.day; + state.gps_data.timestamp.month = frame.date.month; + state.gps_data.timestamp.year = frame.date.year; } // Synchronize RTC with GPS UTC clock, only when fix is done - if((state->gps_set_time) && - (state->gps_data.fix_quality > 0) && (!isRtcSyncronised)) + if((state.gps_set_time) && + (state.gps_data.fix_quality > 0) && (!isRtcSyncronised)) { - rtc_setTime(state->gps_data.timestamp); + rtc_setTime(state.gps_data.timestamp); isRtcSyncronised = true; } - state->gps_data.tmg_true = minmea_tofloat(&frame.course); - state->gps_data.speed = minmea_tofloat(&frame.speed) * KNOTS2KMH; + state.gps_data.tmg_true = minmea_tofloat(&frame.course); + state.gps_data.speed = minmea_tofloat(&frame.speed) * KNOTS2KMH; } break; case MINMEA_SENTENCE_GGA: @@ -83,24 +85,24 @@ void gps_taskFunc(char *line, __attribute__((unused)) int len, state_t *state) struct minmea_sentence_gga frame; if (minmea_parse_gga(&frame, line)) { - state->gps_data.fix_quality = frame.fix_quality; - state->gps_data.satellites_tracked = frame.satellites_tracked; - state->gps_data.altitude = minmea_tofloat(&frame.altitude); + state.gps_data.fix_quality = frame.fix_quality; + state.gps_data.satellites_tracked = frame.satellites_tracked; + state.gps_data.altitude = minmea_tofloat(&frame.altitude); } } break; case MINMEA_SENTENCE_GSA: { - state->gps_data.active_sats = 0; + state.gps_data.active_sats = 0; struct minmea_sentence_gsa frame; if (minmea_parse_gsa(&frame, line)) { - state->gps_data.fix_type = frame.fix_type; + state.gps_data.fix_type = frame.fix_type; for (int i = 0; i < 12; i++) { if (frame.sats[i] != 0) { - state->gps_data.active_sats |= 1 << (frame.sats[i] - 1); + state.gps_data.active_sats |= 1 << (frame.sats[i] - 1); } } } @@ -115,17 +117,17 @@ void gps_taskFunc(char *line, __attribute__((unused)) int len, state_t *state) // When the first sentence arrives, clear all the old data if (frame.msg_nr == 1) { - bzero(&state->gps_data.satellites[0], 12 * sizeof(sat_t)); + bzero(&state.gps_data.satellites[0], 12 * sizeof(sat_t)); } - state->gps_data.satellites_in_view = frame.total_sats; + state.gps_data.satellites_in_view = frame.total_sats; for (int i = 0; i < 4; i++) { int index = 4 * (frame.msg_nr - 1) + i; - state->gps_data.satellites[index].id = frame.sats[i].nr; - state->gps_data.satellites[index].elevation = frame.sats[i].elevation; - state->gps_data.satellites[index].azimuth = frame.sats[i].azimuth; - state->gps_data.satellites[index].snr = frame.sats[i].snr; + state.gps_data.satellites[index].id = frame.sats[i].nr; + state.gps_data.satellites[index].elevation = frame.sats[i].elevation; + state.gps_data.satellites[index].azimuth = frame.sats[i].azimuth; + state.gps_data.satellites[index].snr = frame.sats[i].snr; } } } break; @@ -135,9 +137,9 @@ void gps_taskFunc(char *line, __attribute__((unused)) int len, state_t *state) struct minmea_sentence_vtg frame; if (minmea_parse_vtg(&frame, line)) { - state->gps_data.speed = minmea_tofloat(&frame.speed_kph); - state->gps_data.tmg_mag = minmea_tofloat(&frame.magnetic_track_degrees); - state->gps_data.tmg_true = minmea_tofloat(&frame.true_track_degrees); + state.gps_data.speed = minmea_tofloat(&frame.speed_kph); + state.gps_data.tmg_mag = minmea_tofloat(&frame.magnetic_track_degrees); + state.gps_data.tmg_true = minmea_tofloat(&frame.true_track_degrees); } } break; diff --git a/openrtx/src/core/state.c b/openrtx/src/core/state.c index 50e4a098..4df987ae 100644 --- a/openrtx/src/core/state.c +++ b/openrtx/src/core/state.c @@ -25,22 +25,10 @@ #include #include #include - #include state_t state; -void defaultSettingsAndVfo() -{ - - //don't need to lock state mutex because this is called from a section - //that already does that - ui_updatefsm runs in a critical section in - //the ui thread - channel_t default_vfo = get_default_channel(); - nvm_writeSettingsAndVfo( &default_settings, &default_vfo ); - state_init(); -} - void state_init() { /* @@ -59,7 +47,7 @@ void state_init() */ if(nvm_readVFOChannelData(&state.channel) < 0) { - state.channel = get_default_channel(); + state.channel = cps_getDefaultChannel(); } /* @@ -114,6 +102,12 @@ void state_update() #endif } +void state_resetSettingsAndVfo() +{ + state.settings = default_settings; + state.channel = cps_getDefaultChannel(); +} + curTime_t state_getLocalTime(curTime_t utc_time) { curTime_t local_time = utc_time; diff --git a/openrtx/src/core/threads.c b/openrtx/src/core/threads.c index be1d4b11..e36d7167 100644 --- a/openrtx/src/core/threads.c +++ b/openrtx/src/core/threads.c @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef HAS_GPS #include #include @@ -92,20 +93,22 @@ void *ui_task(void *arg) // If synchronization needed take mutex and update RTX configuration if(sync_rtx) { + float power = dBmToWatt(state.channel.power); + pthread_mutex_lock(&rtx_mutex); - rtx_cfg.opMode = state.channel.mode; - rtx_cfg.bandwidth = state.channel.bandwidth; + rtx_cfg.opMode = state.channel.mode; + rtx_cfg.bandwidth = state.channel.bandwidth; rtx_cfg.rxFrequency = state.channel.rx_frequency; rtx_cfg.txFrequency = state.channel.tx_frequency; - rtx_cfg.txPower = state.channel.power; - rtx_cfg.sqlLevel = state.settings.sqlLevel; - rtx_cfg.rxToneEn = state.channel.fm.rxToneEn; - rtx_cfg.rxTone = ctcss_tone[state.channel.fm.rxTone]; - rtx_cfg.txToneEn = state.channel.fm.txToneEn; - rtx_cfg.txTone = ctcss_tone[state.channel.fm.txTone]; + rtx_cfg.txPower = power; + rtx_cfg.sqlLevel = state.settings.sqlLevel; + rtx_cfg.rxToneEn = state.channel.fm.rxToneEn; + rtx_cfg.rxTone = ctcss_tone[state.channel.fm.rxTone]; + rtx_cfg.txToneEn = state.channel.fm.txToneEn; + rtx_cfg.txTone = ctcss_tone[state.channel.fm.txTone]; // Copy new M17 source and destination addresses - strncpy(rtx_cfg.source_address, state.settings.callsign, 10); + strncpy(rtx_cfg.source_address, state.settings.callsign, 10); strncpy(rtx_cfg.destination_address, state.m17_data.dst_addr, 10); pthread_mutex_unlock(&rtx_mutex); @@ -298,7 +301,7 @@ void *gps_task(void *arg) pthread_mutex_lock(&state_mutex); // GPS readout is blocking, no need to delay here - gps_taskFunc(line, len, &state); + gps_taskFunc(line, len); // Unlock state mutex pthread_mutex_unlock(&state_mutex); diff --git a/openrtx/src/core/calibUtils.c b/openrtx/src/core/utils.c similarity index 84% rename from openrtx/src/core/calibUtils.c rename to openrtx/src/core/utils.c index 7cf29dff..3fb79fb3 100644 --- a/openrtx/src/core/calibUtils.c +++ b/openrtx/src/core/utils.c @@ -1,7 +1,7 @@ /*************************************************************************** - * Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, * - * Niccolò Izzo IU2KIN, * - * Silvano Seva IU2KWO * + * Copyright (C) 2020 - 2022 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN, * + * Silvano Seva IU2KWO * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -17,7 +17,8 @@ * along with this program; if not, see * ***************************************************************************/ -#include +#include +#include uint8_t interpCalParameter(const freq_t freq, const freq_t *calPoints, const uint8_t *param, const uint8_t elems) @@ -49,3 +50,11 @@ uint8_t interpCalParameter(const freq_t freq, const freq_t *calPoints, return interpValue; } + +float dBmToWatt(const uint8_t n) +{ + float dBm = 10.0f + ((float) n) * 0.2f; + float power = pow(10.0f, (dBm - 30.0f)/10.0f); + + return power; +} diff --git a/openrtx/src/ui/ui.c b/openrtx/src/ui/ui.c index ff1a1379..49377752 100644 --- a/openrtx/src/ui/ui.c +++ b/openrtx/src/ui/ui.c @@ -764,10 +764,10 @@ void _ui_fsm_menuMacro(kbd_msg_t msg, bool *sync_rtx) } break; case 3: - if (state.channel.power == 1.0f) - state.channel.power = 5.0f; + if (state.channel.power == 100) + state.channel.power = 135; else - state.channel.power = 1.0f; + state.channel.power = 100; *sync_rtx = true; break; case 4: @@ -1644,7 +1644,7 @@ void ui_updateFSM(event_t event, bool *sync_rtx) if(msg.keys & KEY_ENTER) { ui_state.edit_mode = false; - defaultSettingsAndVfo(); + state_resetSettingsAndVfo(); _ui_menuBack(MENU_SETTINGS); } else if(msg.keys & KEY_ESC) diff --git a/openrtx/src/ui/ui_menu.c b/openrtx/src/ui/ui_menu.c index 44a6e687..62c0dd51 100644 --- a/openrtx/src/ui/ui_menu.c +++ b/openrtx/src/ui/ui_menu.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -718,7 +719,7 @@ bool _ui_drawMacroMenu() gfx_print(layout.line1_pos, layout.top_font, TEXT_ALIGN_RIGHT, yellow_fab413, "3 "); gfx_print(layout.line1_pos, layout.top_font, TEXT_ALIGN_RIGHT, - color_white, "%.1gW", last_state.channel.power); + color_white, "%.1gW", dBmToWatt(last_state.channel.power)); // Second row // Calculate symmetric second row position, line2_pos is asymmetric like main screen point_t pos_2 = {layout.line1_pos.x, layout.line1_pos.y + diff --git a/platform/drivers/NVM/nvmem_GDx.c b/platform/drivers/NVM/nvmem_GDx.c index 4a51ec69..ada04904 100644 --- a/platform/drivers/NVM/nvmem_GDx.c +++ b/platform/drivers/NVM/nvmem_GDx.c @@ -183,6 +183,8 @@ void nvm_loadHwInfo(hwInfo_t *info) int nvm_readVFOChannelData(channel_t *channel) { + memset(channel, 0x00, sizeof(channel_t)); + gdxChannel_t chData; AT24Cx_readData(vfoChannelBaseAddr, ((uint8_t *) &chData), sizeof(gdxChannel_t)); @@ -190,17 +192,10 @@ int nvm_readVFOChannelData(channel_t *channel) // Copy data to OpenRTX channel_t channel->mode = chData.channel_mode + 1; channel->bandwidth = chData.bandwidth; - channel->admit_criteria = chData.admit_criteria; - channel->squelch = chData.squelch; channel->rx_only = chData.rx_only; - channel->vox = chData.vox; - channel->power = ((chData.power == 1) ? 5.0f : 1.0f); + channel->power = ((chData.power == 1) ? 135 : 100); channel->rx_frequency = _bcd2bin(chData.rx_frequency) * 10; channel->tx_frequency = _bcd2bin(chData.tx_frequency) * 10; - channel->tot = chData.tot; - channel->tot_rekey_delay = chData.tot_rekey_delay; - channel->emSys_index = chData.emergency_system_index; - channel->scanList_index = chData.scan_list_index; channel->groupList_index = chData.group_list_index; memcpy(channel->name, chData.name, sizeof(chData.name)); // Terminate string with 0x00 instead of 0xFF @@ -258,6 +253,8 @@ int cps_readChannelData(channel_t *channel, uint16_t pos) if((pos <= 0) || (pos > maxNumChannels)) return -1; + memset(channel, 0x00, sizeof(channel_t)); + // Channels are organized in 128-channel banks uint8_t bank_num = (pos - 1) / 128; // Note: pos is 1-based because an empty slot in a bank contains index 0 @@ -310,16 +307,10 @@ int cps_readChannelData(channel_t *channel, uint16_t pos) // Copy data to OpenRTX channel_t channel->mode = chData.channel_mode + 1; channel->bandwidth = chData.bandwidth; - channel->admit_criteria = chData.admit_criteria; - channel->squelch = chData.squelch; channel->rx_only = chData.rx_only; - channel->vox = chData.vox; - channel->power = ((chData.power == 1) ? 5.0f : 1.0f); + channel->power = ((chData.power == 1) ? 135 : 100); channel->rx_frequency = _bcd2bin(chData.rx_frequency) * 10; channel->tx_frequency = _bcd2bin(chData.tx_frequency) * 10; - channel->tot = chData.tot; - channel->tot_rekey_delay = chData.tot_rekey_delay; - channel->emSys_index = chData.emergency_system_index; channel->scanList_index = chData.scan_list_index; channel->groupList_index = chData.group_list_index; memcpy(channel->name, chData.name, sizeof(chData.name)); @@ -427,11 +418,17 @@ int cps_readContactData(contact_t *contact, uint16_t pos) memcpy(contact->name, contactData.name, sizeof(contactData.name)); // Terminate string with 0x00 instead of 0xFF _addStringTerminator(contact->name, sizeof(contactData.name)); + + contact->mode = DMR; + // Copy contact DMR ID - contact->id = (contactData.id[0] | contactData.id[1] << 8 | contactData.id[2] << 16); + contact->info.dmr.id = contactData.id[0] + | (contactData.id[1] << 8) + | (contactData.id[2] << 16); + // Copy contact details - contact->type = contactData.type; - contact->receive_tone = contactData.receive_tone ? true : false; + contact->info.dmr.contactType = contactData.type; + contact->info.dmr.rx_tone = contactData.receive_tone ? true : false; return 0; } diff --git a/platform/drivers/NVM/nvmem_MD3x0.c b/platform/drivers/NVM/nvmem_MD3x0.c index eaddc684..36e9a729 100644 --- a/platform/drivers/NVM/nvmem_MD3x0.c +++ b/platform/drivers/NVM/nvmem_MD3x0.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "nvmData_MD3x0.h" #include "W25Qx.h" @@ -171,6 +172,8 @@ int cps_readChannelData(channel_t *channel, uint16_t pos) { if((pos <= 0) || (pos > maxNumChannels)) return -1; + memset(channel, 0x00, sizeof(channel_t)); + W25Qx_wakeup(); delayUs(5); @@ -182,16 +185,10 @@ int cps_readChannelData(channel_t *channel, uint16_t pos) channel->mode = chData.channel_mode; channel->bandwidth = chData.bandwidth; - channel->admit_criteria = chData.admit_criteria; - channel->squelch = chData.squelch; channel->rx_only = chData.rx_only; - channel->vox = chData.vox; - channel->power = ((chData.power == 1) ? 5.0f : 1.0f); + channel->power = ((chData.power == 1) ? 135 : 100); channel->rx_frequency = _bcd2bin(chData.rx_frequency) * 10; channel->tx_frequency = _bcd2bin(chData.tx_frequency) * 10; - channel->tot = chData.tot; - channel->tot_rekey_delay = chData.tot_rekey_delay; - channel->emSys_index = chData.emergency_system_index; channel->scanList_index = chData.scan_list_index; channel->groupList_index = chData.group_list_index; @@ -309,11 +306,17 @@ int cps_readContactData(contact_t *contact, uint16_t pos) { contact->name[i] = ((char) (contactData.name[i] & 0x00FF)); } + + contact->mode = DMR; + // Copy contact DMR ID - contact->id = (contactData.id[0] | contactData.id[1] << 8 | contactData.id[2] << 16); + contact->info.dmr.id = contactData.id[0] + | (contactData.id[1] << 8) + | (contactData.id[2] << 16); + // Copy contact details - contact->type = contactData.type; - contact->receive_tone = contactData.receive_tone ? true : false; + contact->info.dmr.contactType = contactData.type; + contact->info.dmr.rx_tone = contactData.receive_tone ? true : false; return 0; } diff --git a/platform/drivers/NVM/nvmem_MD9600.c b/platform/drivers/NVM/nvmem_MD9600.c index 1e7e0b47..6b35af0e 100644 --- a/platform/drivers/NVM/nvmem_MD9600.c +++ b/platform/drivers/NVM/nvmem_MD9600.c @@ -26,14 +26,14 @@ #include "nvmData_MDUV3x0.h" #include "W25Qx.h" -const uint32_t zoneBaseAddr = 0x149E0; /**< Base address of zones */ -const uint32_t zoneExtBaseAddr = 0x31000; /**< Base address of zone extensions */ -const uint32_t vfoChannelBaseAddr = 0x2EF00; /**< Base address of VFO channel */ -const uint32_t chDataBaseAddr = 0x110000; /**< Base address of channel data */ -const uint32_t contactBaseAddr = 0x140000; /**< Base address of contacts */ -const uint32_t maxNumChannels = 3000; /**< Maximum number of channels in memory */ -const uint32_t maxNumZones = 250; /**< Maximum number of zones and zone extensions in memory */ -const uint32_t maxNumContacts = 10000; /**< Maximum number of contacts in memory */ +const uint32_t zoneBaseAddr = 0x149E0; /**< Base address of zones */ +const uint32_t zoneExtBaseAddr = 0x31000; /**< Base address of zone extensions */ +const uint32_t vfoChannelBaseAddr = 0x2EF00; /**< Base address of VFO channel */ +const uint32_t chDataBaseAddr = 0x110000; /**< Base address of channel data */ +const uint32_t contactBaseAddr = 0x140000; /**< Base address of contacts */ +const uint32_t maxNumChannels = 3000; /**< Maximum number of channels in memory */ +const uint32_t maxNumZones = 250; /**< Maximum number of zones and zone extensions in memory */ +const uint32_t maxNumContacts = 10000; /**< Maximum number of contacts in memory */ /* This address has been chosen by OpenRTX to store the settings * because it is empty (0xFF) and has enough free space */ const uint32_t settingsAddr = 0x6000; @@ -71,29 +71,23 @@ int _cps_readChannelAtAddress(channel_t *channel, uint32_t addr) channel->mode = chData.channel_mode; channel->bandwidth = chData.bandwidth; - channel->admit_criteria = chData.admit_criteria; - channel->squelch = chData.squelch; channel->rx_only = chData.rx_only; - channel->vox = chData.vox; channel->rx_frequency = _bcd2bin(chData.rx_frequency) * 10; channel->tx_frequency = _bcd2bin(chData.tx_frequency) * 10; - channel->tot = chData.tot; - channel->tot_rekey_delay = chData.tot_rekey_delay; - channel->emSys_index = chData.emergency_system_index; channel->scanList_index = chData.scan_list_index; channel->groupList_index = chData.group_list_index; if(chData.power == 3) { - channel->power = 5.0f; /* High power -> 5W */ + channel->power = 135; /* High power -> 5W = 37dBm */ } else if(chData.power == 2) { - channel->power = 2.5f; /* Mid power -> 2.5W */ + channel->power = 120; /* Mid power -> 2.5W = 34dBm */ } else { - channel->power = 1.0f; /* Low power -> 1W */ + channel->power = 100; /* Low power -> 1W = 30dBm */ } /* @@ -181,6 +175,8 @@ int cps_readChannelData(channel_t *channel, uint16_t pos) { if((pos <= 0) || (pos > maxNumChannels)) return -1; + memset(channel, 0x00, sizeof(channel_t)); + // Note: pos is 1-based because an empty slot in a zone contains index 0 uint32_t readAddr = chDataBaseAddr + (pos - 1) * sizeof(mduv3x0Channel_t); return _cps_readChannelAtAddress(channel, readAddr); @@ -250,11 +246,17 @@ int cps_readContactData(contact_t *contact, uint16_t pos) { contact->name[i] = ((char) (contactData.name[i] & 0x00FF)); } + + contact->mode = DMR; + // Copy contact DMR ID - contact->id = (contactData.id[0] | contactData.id[1] << 8 | contactData.id[2] << 16); + contact->info.dmr.id = contactData.id[0] + | (contactData.id[1] << 8) + | (contactData.id[2] << 16); + // Copy contact details - contact->type = contactData.type; - contact->receive_tone = contactData.receive_tone ? true : false; + contact->info.dmr.contactType = contactData.type; + contact->info.dmr.rx_tone = contactData.receive_tone ? true : false; return 0; } diff --git a/platform/drivers/NVM/nvmem_MDUV3x0.c b/platform/drivers/NVM/nvmem_MDUV3x0.c index b027e44e..029257bc 100644 --- a/platform/drivers/NVM/nvmem_MDUV3x0.c +++ b/platform/drivers/NVM/nvmem_MDUV3x0.c @@ -26,14 +26,14 @@ #include "nvmData_MDUV3x0.h" #include "W25Qx.h" -const uint32_t zoneBaseAddr = 0x149E0; /**< Base address of zones */ -const uint32_t zoneExtBaseAddr = 0x31000; /**< Base address of zone extensions */ -const uint32_t vfoChannelBaseAddr = 0x2EF00; /**< Base address of VFO channel */ -const uint32_t chDataBaseAddr = 0x110000; /**< Base address of channel data */ -const uint32_t contactBaseAddr = 0x140000; /**< Base address of contacts */ -const uint32_t maxNumChannels = 3000; /**< Maximum number of channels in memory */ -const uint32_t maxNumZones = 250; /**< Maximum number of zones and zone extensions in memory */ -const uint32_t maxNumContacts = 10000; /**< Maximum number of contacts in memory */ +const uint32_t zoneBaseAddr = 0x149E0; /**< Base address of zones */ +const uint32_t zoneExtBaseAddr = 0x31000; /**< Base address of zone extensions */ +const uint32_t vfoChannelBaseAddr = 0x2EF00; /**< Base address of VFO channel */ +const uint32_t chDataBaseAddr = 0x110000; /**< Base address of channel data */ +const uint32_t contactBaseAddr = 0x140000; /**< Base address of contacts */ +const uint32_t maxNumChannels = 3000; /**< Maximum number of channels in memory */ +const uint32_t maxNumZones = 250; /**< Maximum number of zones and zone extensions in memory */ +const uint32_t maxNumContacts = 10000; /**< Maximum number of contacts in memory */ /* This address has been chosen by OpenRTX to store the settings * because it is empty (0xFF) and has enough free space */ const uint32_t settingsAddr = 0x6000; @@ -42,7 +42,7 @@ const uint32_t settingsAddr = 0x6000; * \internal Utility function to convert 4 byte BCD values into a 32-bit * unsigned integer ones. */ -uint32_t _bcd2bin(uint32_t bcd) +static uint32_t _bcd2bin(uint32_t bcd) { return ((bcd >> 28) & 0x0F) * 10000000 + ((bcd >> 24) & 0x0F) * 1000000 + @@ -57,7 +57,7 @@ uint32_t _bcd2bin(uint32_t bcd) /** * Used to read channel data from SPI flash into a channel_t struct */ -int _cps_readChannelAtAddress(channel_t *channel, uint32_t addr) +static int _cps_readChannelAtAddress(channel_t *channel, uint32_t addr) { W25Qx_wakeup(); delayUs(5); @@ -71,29 +71,23 @@ int _cps_readChannelAtAddress(channel_t *channel, uint32_t addr) channel->mode = chData.channel_mode; channel->bandwidth = chData.bandwidth; - channel->admit_criteria = chData.admit_criteria; - channel->squelch = chData.squelch; channel->rx_only = chData.rx_only; - channel->vox = chData.vox; channel->rx_frequency = _bcd2bin(chData.rx_frequency) * 10; channel->tx_frequency = _bcd2bin(chData.tx_frequency) * 10; - channel->tot = chData.tot; - channel->tot_rekey_delay = chData.tot_rekey_delay; - channel->emSys_index = chData.emergency_system_index; channel->scanList_index = chData.scan_list_index; channel->groupList_index = chData.group_list_index; if(chData.power == 3) { - channel->power = 5.0f; /* High power -> 5W */ + channel->power = 135; /* High power -> 5W = 37dBm */ } else if(chData.power == 2) { - channel->power = 2.5f; /* Mid power -> 2.5W */ + channel->power = 120; /* Mid power -> 2.5W = 34dBm */ } else { - channel->power = 1.0f; /* Low power -> 1W */ + channel->power = 100; /* Low power -> 1W = 30dBm */ } /* @@ -281,6 +275,8 @@ int cps_readChannelData(channel_t *channel, uint16_t pos) { if((pos <= 0) || (pos > maxNumChannels)) return -1; + memset(channel, 0x00, sizeof(channel_t)); + // Note: pos is 1-based because an empty slot in a zone contains index 0 uint32_t readAddr = chDataBaseAddr + (pos - 1) * sizeof(mduv3x0Channel_t); return _cps_readChannelAtAddress(channel, readAddr); @@ -350,11 +346,17 @@ int cps_readContactData(contact_t *contact, uint16_t pos) { contact->name[i] = ((char) (contactData.name[i] & 0x00FF)); } + + contact->mode = DMR; + // Copy contact DMR ID - contact->id = (contactData.id[0] | contactData.id[1] << 8 | contactData.id[2] << 16); + contact->info.dmr.id = contactData.id[0] + | (contactData.id[1] << 8) + | (contactData.id[2] << 16); + // Copy contact details - contact->type = contactData.type; - contact->receive_tone = contactData.receive_tone ? true : false; + contact->info.dmr.contactType = contactData.type; + contact->info.dmr.rx_tone = contactData.receive_tone ? true : false; return 0; } diff --git a/platform/drivers/NVM/nvmem_settings_MDx.c b/platform/drivers/NVM/nvmem_settings_MDx.c index a96e4ee6..1403a69a 100644 --- a/platform/drivers/NVM/nvmem_settings_MDx.c +++ b/platform/drivers/NVM/nvmem_settings_MDx.c @@ -40,7 +40,7 @@ typedef struct } __attribute__((packed)) memory_t; -static const uint32_t validMagic = 0x5854504F; // "OPTX" +static const uint32_t validMagic = 0x584E504F; // "OPNX" static const uint32_t baseAddress = 0x080E0000; memory_t *memory = ((memory_t *) baseAddress); diff --git a/platform/drivers/baseband/radio_GDx.cpp b/platform/drivers/baseband/radio_GDx.cpp index fb8c199b..7402b2a9 100644 --- a/platform/drivers/baseband/radio_GDx.cpp +++ b/platform/drivers/baseband/radio_GDx.cpp @@ -22,9 +22,9 @@ #include #include #include -#include #include #include +#include #include "radioUtils.h" #include "HR_C6000.h" #include "AT1846S.h" diff --git a/platform/drivers/baseband/radio_MD3x0.cpp b/platform/drivers/baseband/radio_MD3x0.cpp index 2289286e..40490afe 100644 --- a/platform/drivers/baseband/radio_MD3x0.cpp +++ b/platform/drivers/baseband/radio_MD3x0.cpp @@ -23,10 +23,10 @@ #include #include #include -#include #include #include #include +#include #include "HR_C5000.h" #include "SKY72310.h" diff --git a/platform/drivers/baseband/radio_UV3x0.cpp b/platform/drivers/baseband/radio_UV3x0.cpp index 42b14665..8f3875ea 100644 --- a/platform/drivers/baseband/radio_UV3x0.cpp +++ b/platform/drivers/baseband/radio_UV3x0.cpp @@ -22,9 +22,9 @@ #include #include #include -#include #include #include +#include #include "radioUtils.h" #include "HR_C6000.h" #include "AT1846S.h"