From ae12a2126a032cb7aadeb884528f4ea49d378f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Izzo?= Date: Mon, 4 Apr 2022 19:43:21 +0200 Subject: [PATCH] Implement codeplug read and write functions Implemented remaining codeplug functions to read, write and insert codeplug entries. Fix bugs in ui code. Add unit tests. TG-428 --- openrtx/include/core/cps.h | 32 +- openrtx/include/interfaces/cps_io.h | 119 ++++++- openrtx/src/core/cps_io_libc.c | 351 ++++++++++++++++++- openrtx/src/ui/ui.c | 10 +- openrtx/src/ui/ui_main.c | 1 + openrtx/src/ui/ui_menu.c | 6 +- platform/drivers/CPS/cps_io_native_GDx.c | 6 +- platform/drivers/CPS/cps_io_native_MD3x0.c | 6 +- platform/drivers/CPS/cps_io_native_MD9600.c | 6 +- platform/drivers/CPS/cps_io_native_MDUV3x0.c | 6 +- platform/drivers/CPS/cps_io_native_Mod17.c | 4 +- tests/platform/codeplug_demo.c | 4 +- tests/platform/printContacts_MDx.c | 2 +- tests/unit/cps.c | 190 +++++++++- 14 files changed, 668 insertions(+), 75 deletions(-) diff --git a/openrtx/include/core/cps.h b/openrtx/include/core/cps.h index eba6ace6..0ab34a92 100644 --- a/openrtx/include/core/cps.h +++ b/openrtx/include/core/cps.h @@ -80,7 +80,7 @@ typedef struct txColorCode : 4; //< Color code sent during transmission uint8_t dmr_timeslot; //< DMR timeslot, either 1 or 2 - uint16_t contactName_index; //< Index to retrieve contact from list + uint16_t contact_index; //< Index to retrieve contact from list } __attribute__((packed)) dmrInfo_t; // 4B @@ -152,7 +152,7 @@ typedef struct 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 + uint16_t contact_index; //< Index to retrieve data from contact list } __attribute__((packed)) m17Info_t; // 5B @@ -203,8 +203,8 @@ typedef struct uint8_t scanList_index; //< Scan List: None, ScanList1...250 uint8_t groupList_index; //< Group List: None, GroupList1...128 - char name[CPS_STR_SIZE]; //< Channel name - char descr[CPS_STR_SIZE]; //< Description of the channel + char name[CPS_STR_SIZE]; //< Channel name + char descr[CPS_STR_SIZE]; //< Description of the channel geo_t ch_location; //< Transmitter geolocation union @@ -221,7 +221,7 @@ __attribute__((packed)) channel_t; // 59B */ typedef struct { - char name[CPS_STR_SIZE]; //< Display name of the contact + char name[CPS_STR_SIZE]; //< Display name of the contact uint8_t mode; //< Operating mode union @@ -231,7 +231,7 @@ typedef struct } info; // 6B } -__attribute__((packed)) contact_t; // 23B +__attribute__((packed)) contact_t; // 39B /** * Data structure describing a bank header. @@ -241,7 +241,7 @@ __attribute__((packed)) contact_t; // 23B typedef struct { char name[CPS_STR_SIZE]; - uint16_t ch_count; //< Count of all the channels in this bank + uint16_t ch_count; //< Count of all the channels in this bank } __attribute__((packed)) bankHdr_t; // 18B + 2 * ch_count @@ -255,17 +255,17 @@ __attribute__((packed)) bankHdr_t; // 18B + 2 * ch_count */ typedef struct { - uint64_t magic; //< Magic number "RTXC" - uint16_t version_number; //< Version number for the cps structure - char author[CPS_STR_SIZE]; //< Author of the codeplug - char descr[CPS_STR_SIZE]; //< Description of the codeplug - uint64_t timestamp; //< unix timestamp of the codeplug + uint64_t magic; //< Magic number "RTXC" + uint16_t version_number; //< Version number for the cps structure + char author[CPS_STR_SIZE]; //< Author of the codeplug + char descr[CPS_STR_SIZE]; //< 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 + 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 +__attribute__((packed)) cps_header_t; // 88B /** * Create and return a viable channel for this radio. diff --git a/openrtx/include/interfaces/cps_io.h b/openrtx/include/interfaces/cps_io.h index eeedc091..3f392268 100644 --- a/openrtx/include/interfaces/cps_io.h +++ b/openrtx/include/interfaces/cps_io.h @@ -60,7 +60,7 @@ int cps_create(char *cps_name); * @param pos: position, inside the bank table, from which read data. * @return 0 on success, -1 on failure */ -int cps_readContactData(contact_t *contact, uint16_t pos); +int cps_readContact(contact_t *contact, uint16_t pos); /** * Read one channel entry from table stored in nonvolatile memory. @@ -69,7 +69,7 @@ int cps_readContactData(contact_t *contact, uint16_t pos); * @param pos: position, inside the channel table, from which read data. * @return 0 on success, -1 on failure */ -int cps_readChannelData(channel_t *channel, uint16_t pos); +int cps_readChannel(channel_t *channel, uint16_t pos); /** * Read one bank header from the codeplug stored in the radio's filesystem. @@ -84,10 +84,121 @@ int cps_readBankHeader(bankHdr_t *b_header, uint16_t pos); * Read one channel index from a bank of the codeplug stored in NVM. * * @param bank_pos: position of the bank inside the cps. - * @param ch_pos: position of the channel index inside the bank. + * @param pos: position of the channel index inside the bank. * @return the retrieved channel index on success, -1 on failure */ -int32_t cps_readBankData(uint16_t bank_pos, uint16_t ch_pos); +int32_t cps_readBankData(uint16_t bank_pos, uint16_t pos); + +/** + * Overwrite one contact to the codeplug stored in nonvolatile memory. + * + * @param contact: data structure to be written. + * @param pos: position, inside the contact table, in which to insert data. + * @return 0 on success, -1 on failure + */ +int cps_writeContact(contact_t contact, uint16_t pos); + +/** + * Overwrite one channel to the codeplug stored in nonvolatile memory. + * + * @param channel: data structure to be written. + * @param pos: position, inside the channel table, in which to insert data. + * @return 0 on success, -1 on failure + */ +int cps_writeChannel(channel_t channel, uint16_t pos); + +/** + * Overwrite one bank header to the codeplug stored in nonvolatile memory. + * + * @param b_header: data structure to be written. + * @param pos: position, inside the bank table, in which to insert data. + * @return 0 on success, -1 on failure + */ +int cps_writeBankHeader(bankHdr_t b_header, uint16_t pos); + +/** + * Write one channel index in a bank entry stored in the codeplug. + * + * @param ch: index of the new channel to be written + * @param bank_pos: index of the bank to be written. + * @param pos: position, inside the bank table, in which to write data. + * @return 0 on success, -1 on failure + */ +int cps_writeBankData(uint32_t ch, uint16_t bank_pos, uint16_t pos); + +/** + * Insert one contact to the codeplug stored in nonvolatile memory, + * updating channels accordingly. + * + * @param contact: data structure to be written. + * @param pos: position, inside the contact table, in which to insert data. + * @return 0 on success, -1 on failure + */ +int cps_insertContact(contact_t contact, uint16_t pos); + +/** + * Insert one channel to the codeplug stored in nonvolatile memory, + * updating banks accordingly. + * + * @param channel: data structure to be written. + * @param pos: position, inside the channel table, in which to insert data. + * @return 0 on success, -1 on failure + */ +int cps_insertChannel(channel_t channel, uint16_t pos); + +/** + * Insert one bank header to the codeplug stored in nonvolatile memory. + * + * @param bank: data structure to be written. + * @param pos: position, inside the bank table, in which to insert data. + * @return 0 on success, -1 on failure + */ +int cps_insertBankHeader(bankHdr_t b_header, uint16_t pos); + +/** + * Insert one channel index in a bank entry stored in the codeplug. + * + * @param ch: index of the new channel to be written + * @param bank_pos: index of the bank to be written. + * @param pos: position, inside the bank table, in which to insert data. + * @return 0 on success, -1 on failure + */ +int cps_insertBankData(uint32_t ch, uint16_t bank_pos, uint16_t pos); + +/** + * Delete one contact to the codeplug stored in nonvolatile memory, + * updating channels accordingly. + * + * @param pos: position, inside the contact table, to delete + * @return 0 on success, -1 on failure + */ +int cps_deleteContact(uint16_t pos); + +/** + * Delete one channel to the codeplug stored in nonvolatile memory, + * updating banks accordingly. + * + * @param pos: position, inside the channel table, to delete + * @return 0 on success, -1 on failure + */ +int cps_deleteChannel(channel_t channel, uint16_t pos); + +/** + * Delete one bank header to the codeplug stored in nonvolatile memory. + * + * @param pos: position, inside the bank table, to delete + * @return 0 on success, -1 on failure + */ +int cps_deleteBankHeader(uint16_t pos); + +/** + * Delete one bank entry to the codeplug stored in nonvolatile memory. + * + * @param bank_pos: index of the bank to be deleted + * @param pos: position, inside the bank table, to delete + * @return 0 on success, -1 on failure + */ +int cps_deleteBankData(uint16_t bank_pos, uint16_t pos); #ifdef __cplusplus } diff --git a/openrtx/src/core/cps_io_libc.c b/openrtx/src/core/cps_io_libc.c index a073511f..7db6080c 100644 --- a/openrtx/src/core/cps_io_libc.c +++ b/openrtx/src/core/cps_io_libc.c @@ -3,6 +3,8 @@ #include #include +#define CPS_CHUNK_SIZE 1024 + static FILE *cps_file = NULL; const char *default_author = "Codeplug author."; const char *default_descr = "Codeplug description."; @@ -13,7 +15,8 @@ const char *default_descr = "Codeplug description."; * @param header: pointer to the header struct to be populated * @return 0 on success, -1 on failure */ -bool _readHeader(cps_header_t *header) { +int _readHeader(cps_header_t *header) +{ fseek(cps_file, 0L, SEEK_SET); fread(header, sizeof(cps_header_t), 1, cps_file); // Validate magic number @@ -26,6 +29,19 @@ bool _readHeader(cps_header_t *header) { return 0; } +/** + * Internal: write codeplug header + * + * @param header: header struct to be written + * @return 0 on success, -1 on failure + */ +int _writeHeader(cps_header_t header) +{ + fseek(cps_file, 0L, SEEK_SET); + fwrite(&header, sizeof(cps_header_t), 1, cps_file); + return 0; +} + /** * Internal: push down data at a given offset by a given amount * @@ -33,12 +49,122 @@ bool _readHeader(cps_header_t *header) { * @param amount: amount of free space to be created * @return 0 on success, -1 on failure */ -int _pushDown(uint32_t offset, uint32_t amount) { - +int _pushDown(uint32_t offset, uint32_t amount) +{ + // Start from the end of the codeplug + cps_header_t header = { 0 }; + if (_readHeader(&header)) + return -1; + fseek(cps_file, + header.ct_count * sizeof(contact_t) + + header.ch_count * sizeof(channel_t), + SEEK_CUR); + // If banks are present skip those + if (header.b_count != 0) { + fseek(cps_file, + (header.b_count - 1) * sizeof(uint32_t), + SEEK_CUR); + uint32_t b_offset = 0; + bankHdr_t b_header = { 0 }; + fread(&b_offset, sizeof(uint32_t), 1, cps_file); + fseek(cps_file, b_offset, SEEK_CUR); + fread(&b_header, sizeof(bankHdr_t), 1, cps_file); + fseek(cps_file, b_header.ch_count * sizeof(uint32_t), SEEK_CUR); + } + // Move data downwards in chunks of fixed size + long end = ftell(cps_file); + // If offset equals end, just return + if (offset == end) + return 0; + char buffer[CPS_CHUNK_SIZE] = { 0 }; + for(int i = 1; i <= ((end - offset) / CPS_CHUNK_SIZE); i++) + { + fseek(cps_file, end - i * CPS_CHUNK_SIZE, SEEK_SET); + fread(buffer, CPS_CHUNK_SIZE, 1, cps_file); + fseek(cps_file, end - i * CPS_CHUNK_SIZE + amount, SEEK_SET); + fwrite(buffer, CPS_CHUNK_SIZE, 1, cps_file); + } + // Once initial offset is reached, move the last incomplete block + fseek(cps_file, offset, SEEK_SET); + fread(buffer, (end - offset) % CPS_CHUNK_SIZE, 1, cps_file); + fseek(cps_file, offset + amount, SEEK_SET); + fwrite(buffer, (end - offset) % CPS_CHUNK_SIZE, 1, cps_file); + fseek(cps_file, offset, SEEK_SET); + return 0; } -int cps_open(char *cps_name) { +/** + * Internal: updates the contact numbering after a contact addition or removal + * + * @param pos: position at which the new contact was inserted or removed + * @param add: if true a contact was inserted, otherwise it was removed + * @return 0 on success, -1 on failure + */ +int _updateCtNumbering(uint16_t pos, bool add) +{ + cps_header_t header = { 0 }; + if (_readHeader(&header)) + return -1; + for(int i = 0; i < header.ch_count; i++) + { + channel_t c = { 0 }; + cps_readChannel(&c, i); + if (c.mode == OPMODE_M17 && c.m17.contact_index >= pos) + { + if (add) + c.m17.contact_index++; + else + c.m17.contact_index--; + cps_writeChannel(c, i); + } + if (c.mode == OPMODE_DMR && c.dmr.contact_index >= pos) + { + if (add) + c.dmr.contact_index++; + else + c.dmr.contact_index--; + cps_writeChannel(c, i); + } + } + return 0; +} + +/** + * Internal: updates the channel numbering after a channel addition or removal + * + * @param pos: position at which the new channel was inserted or removed + * @param add: if true a channel was inserted, otherwise it was removed + * @return 0 on success, -1 on failure + */ +int _updateChNumbering(uint16_t pos, bool add) +{ + cps_header_t header = { 0 }; + if (_readHeader(&header)) + return -1; + for(int i = 0; i < header.b_count; i++) + { + bankHdr_t b_header = { 0 }; + cps_readBankHeader(&b_header, i); + for(int j = 0; j < b_header.ch_count; j++) + { + int32_t ch = cps_readBankData(i, j); + if (ch >= pos) + { + if (add) + ch++; + else + ch--; + cps_writeBankData(ch, i, j); + } + } + } + return 0; +} + + +int cps_open(char *cps_name) +{ if (!cps_name) cps_name = "default.rtxc"; cps_file = fopen(cps_name, "r+"); @@ -47,11 +173,13 @@ int cps_open(char *cps_name) { return 0; } -void cps_close() { +void cps_close() +{ fclose(cps_file); } -int cps_create(char *cps_name) { +int cps_create(char *cps_name) +{ // Clear or create cps file FILE *new_cps = NULL; if (!cps_name) @@ -75,9 +203,10 @@ int cps_create(char *cps_name) { return 0; } -int cps_readContactData(contact_t *contact, uint16_t pos) { +int cps_readContact(contact_t *contact, uint16_t pos) +{ cps_header_t header = { 0 }; - if (!_readHeader(&header)) + if (_readHeader(&header)) return -1; if (pos >= header.ct_count) return -1; @@ -86,9 +215,10 @@ int cps_readContactData(contact_t *contact, uint16_t pos) { return 0; } -int cps_readChannelData(channel_t *channel, uint16_t pos) { +int cps_readChannel(channel_t *channel, uint16_t pos) +{ cps_header_t header = { 0 }; - if (!_readHeader(&header)) + if (_readHeader(&header)) return -1; if (pos >= header.ch_count) return -1; @@ -100,9 +230,10 @@ int cps_readChannelData(channel_t *channel, uint16_t pos) { return 0; } -int cps_readBankHeader(bankHdr_t *b_header, uint16_t pos) { +int cps_readBankHeader(bankHdr_t *b_header, uint16_t pos) +{ cps_header_t header = { 0 }; - if (!_readHeader(&header)) + if (_readHeader(&header)) return -1; if (pos >= header.b_count) return -1; @@ -113,14 +244,15 @@ int cps_readBankHeader(bankHdr_t *b_header, uint16_t pos) { SEEK_CUR); uint32_t offset = 0; fread(&offset, sizeof(uint32_t), 1, cps_file); - fseek(cps_file, header.b_count - pos * sizeof(uint32_t) + offset, SEEK_CUR); + fseek(cps_file, (header.b_count - pos) * sizeof(uint32_t) + offset, SEEK_CUR); fread(b_header, sizeof(bankHdr_t), 1, cps_file); return 0; } -uint32_t cps_readBankData(uint16_t bank_pos, uint16_t ch_pos) { +int32_t cps_readBankData(uint16_t bank_pos, uint16_t pos) +{ cps_header_t header = { 0 }; - if (!_readHeader(&header)) + if (_readHeader(&header)) return -1; if (bank_pos >= header.b_count) return -1; @@ -134,14 +266,195 @@ uint32_t cps_readBankData(uint16_t bank_pos, uint16_t ch_pos) { fseek(cps_file, header.b_count - bank_pos * sizeof(uint32_t) + offset, SEEK_CUR); bankHdr_t b_header = { 0 }; fread(&b_header, sizeof(bankHdr_t), 1, cps_file); - if (ch_pos >= b_header.ch_count) + if (pos >= b_header.ch_count) return -1; - fseek(cps_file, ch_pos * sizeof(uint32_t), SEEK_CUR); + fseek(cps_file, pos * sizeof(uint32_t), SEEK_CUR); uint32_t ch_index = 0; fread(&ch_index, sizeof(uint32_t), 1, cps_file); return ch_index; } -int cps_writeContactData(contact_t contact, uint16_t pos) { - +int cps_writeContact(contact_t contact, uint16_t pos) +{ + cps_header_t header = { 0 }; + if (_readHeader(&header)) + return -1; + if (pos >= header.ct_count) + return -1; + fseek(cps_file, pos * sizeof(contact_t), SEEK_CUR); + fwrite(&contact, sizeof(contact_t), 1, cps_file); + return 0; +} + +int cps_writeChannel(channel_t channel, uint16_t pos) +{ + cps_header_t header = { 0 }; + if (_readHeader(&header)) + return -1; + if (pos >= header.ch_count) + return -1; + fseek(cps_file, + header.ct_count * sizeof(contact_t) + + pos * sizeof(channel_t), + SEEK_CUR); + fwrite(&channel, sizeof(channel_t), 1, cps_file); + return 0; +} + +int cps_writeBankHeader(bankHdr_t b_header, uint16_t pos) +{ + cps_header_t header = { 0 }; + if (_readHeader(&header)) + return -1; + if (pos >= header.b_count) + return -1; + fseek(cps_file, + header.ct_count * sizeof(contact_t) + + header.ch_count * sizeof(channel_t) + + pos * sizeof(uint32_t), + SEEK_CUR); + uint32_t offset = 0; + fread(&offset, sizeof(uint32_t), 1, cps_file); + fseek(cps_file, header.b_count - pos * sizeof(uint32_t) + offset, SEEK_CUR); + fwrite(&b_header, sizeof(bankHdr_t), 1, cps_file); + return 0; +} + +int cps_writeBankData(uint32_t ch, uint16_t bank_pos, uint16_t pos) +{ + cps_header_t header = { 0 }; + if (_readHeader(&header)) + return -1; + if (pos >= header.b_count + 1) + return -1; + fseek(cps_file, + header.ct_count * sizeof(contact_t) + + header.ch_count * sizeof(channel_t) + + bank_pos * sizeof(uint32_t), + SEEK_CUR); + uint32_t offset = 0; + fread(&offset, sizeof(uint32_t), 1, cps_file); + fseek(cps_file, header.b_count - bank_pos * sizeof(uint32_t) + offset, SEEK_CUR); + bankHdr_t b_header = { 0 }; + fread(&b_header, sizeof(bankHdr_t), 1, cps_file); + if (pos >= b_header.ch_count) + return -1; + fseek(cps_file, pos * sizeof(uint32_t), SEEK_CUR); + fwrite(&ch, sizeof(uint32_t), 1, cps_file); + return 0; +} + +int cps_insertContact(contact_t contact, uint16_t pos) +{ + cps_header_t header = { 0 }; + if (_readHeader(&header)) + return -1; + if (pos >= header.ct_count + 1) + return -1; + long ct_pos = ftell(cps_file) + pos * sizeof(contact_t); + _pushDown(ct_pos, sizeof(contact_t)); + fwrite(&contact, sizeof(contact_t), 1, cps_file); + header.ct_count++; + _writeHeader(header); + if (_updateCtNumbering(pos, true)) + return -1; + return 0; +} + +int cps_insertChannel(channel_t channel, uint16_t pos) +{ + cps_header_t header = { 0 }; + if (_readHeader(&header)) + return -1; + if (pos >= header.ch_count + 1) + return -1; + long ch_pos = ftell(cps_file) + + header.ct_count * sizeof(contact_t) + + pos * sizeof(channel_t); + _pushDown(ch_pos, sizeof(channel_t)); + fwrite(&channel, sizeof(channel_t), 1, cps_file); + header.ch_count++; + _writeHeader(header); + _updateChNumbering(pos, true); + return 0; +} + +int cps_insertBankHeader(bankHdr_t b_header, uint16_t pos) +{ + cps_header_t header = { 0 }; + if (_readHeader(&header)) + return -1; + if (pos >= header.b_count + 1) + return -1; + // Read old offset + uint32_t b_offset = 0; + fseek(cps_file, + header.ct_count * sizeof(contact_t) + + header.ch_count * sizeof(channel_t) + + pos * sizeof(uint32_t), + SEEK_CUR); + long b_offset_pos = ftell(cps_file); + fread(&b_offset, sizeof(uint32_t), 1, cps_file); + // Write new offset + _pushDown(b_offset_pos, sizeof(uint32_t)); + fwrite(&b_offset, sizeof(uint32_t), 1, cps_file); + // Update all the offsets following the moved bank + for(int i = 0; i < header.b_count - pos; i++) + { + long p = ftell(cps_file); + uint32_t o = 0; + fread(&o, sizeof(uint32_t), 1, cps_file); + fseek(cps_file, p, SEEK_SET); + o += sizeof(bankHdr_t); + fwrite(&o, sizeof(uint32_t), 1, cps_file); + } + // Write new bank + fseek(cps_file, b_offset, SEEK_CUR); + long h_pos = ftell(cps_file); + _pushDown(h_pos, sizeof(bankHdr_t)); + fwrite(&b_header, sizeof(bankHdr_t), 1, cps_file); + header.b_count++; + _writeHeader(header); + return 0; +} + +int cps_insertBankData(uint32_t ch, uint16_t bank_pos, uint16_t pos) +{ + cps_header_t header = { 0 }; + if (_readHeader(&header)) + return -1; + if (bank_pos >= header.b_count + 1) + return -1; + fseek(cps_file, + header.ct_count * sizeof(contact_t) + + header.ch_count * sizeof(channel_t) + + bank_pos * sizeof(uint32_t), + SEEK_CUR); + uint32_t offset = 0; + fread(&offset, sizeof(uint32_t), 1, cps_file); + // Update all the offsets following the moved bank + for(int i = 0; i < header.b_count - bank_pos - 1; i++) + { + long p = ftell(cps_file); + uint32_t o = 0; + fread(&o, sizeof(uint32_t), 1, cps_file); + fseek(cps_file, p, SEEK_SET); + o += sizeof(uint32_t); + fwrite(&o, sizeof(uint32_t), 1, cps_file); + } + // Update bank header + fseek(cps_file, offset, SEEK_CUR); + bankHdr_t b_header = { 0 }; + long h_pos = ftell(cps_file); + fread(&b_header, sizeof(bankHdr_t), 1, cps_file); + if (pos >= b_header.ch_count + 1) + return -1; + b_header.ch_count++; + fseek(cps_file, h_pos, SEEK_SET); + fwrite(&b_header, sizeof(bankHdr_t), 1, cps_file); + fseek(cps_file, pos * sizeof(uint32_t), SEEK_CUR); + long p = ftell(cps_file); + _pushDown(p, sizeof(uint32_t)); + fwrite(&ch, sizeof(uint32_t), 1, cps_file); + return 0; } diff --git a/openrtx/src/ui/ui.c b/openrtx/src/ui/ui.c index e746bb26..fe00b69b 100644 --- a/openrtx/src/ui/ui.c +++ b/openrtx/src/ui/ui.c @@ -551,7 +551,7 @@ int _ui_fsm_loadChannel(uint16_t channel_index, bool *sync_rtx) { // Channel index is 1-based while bank array access is 0-based channel_index = cps_readBankData(state.bank, channel_index); } - int result = cps_readChannelData(&channel, channel_index); + int result = cps_readChannel(&channel, channel_index); // Read successful and channel is valid if(result != -1 && _ui_channel_valid(&channel)) { @@ -1312,19 +1312,19 @@ void ui_updateFSM(event_t event, bool *sync_rtx) // manu_selected is 0-based // bank 0 means "All Channel" mode // banks (1, n) are mapped to banks (0, n-1) - if(cps_readBankHeader(&bank, ui_state.menu_selected + 1) != -1) + if(cps_readBankHeader(&bank, ui_state.menu_selected) != -1) ui_state.menu_selected += 1; } else if(state.ui_screen == MENU_CHANNEL) { channel_t channel; - if(cps_readChannelData(&channel, ui_state.menu_selected + 1) != -1) + if(cps_readChannel(&channel, ui_state.menu_selected + 1) != -1) ui_state.menu_selected += 1; } else if(state.ui_screen == MENU_CONTACTS) { contact_t contact; - if(cps_readContactData(&contact, ui_state.menu_selected + 1) != -1) + if(cps_readContact(&contact, ui_state.menu_selected + 1) != -1) ui_state.menu_selected += 1; } } @@ -1359,7 +1359,7 @@ void ui_updateFSM(event_t event, bool *sync_rtx) // If we were in VFO mode, save VFO channel if(ui_state.last_main_state == MAIN_VFO) state.vfo_channel = state.channel; - _ui_fsm_loadChannel(ui_state.menu_selected + 1, sync_rtx); + _ui_fsm_loadChannel(ui_state.menu_selected, sync_rtx); // Switch to MEM screen state.ui_screen = MAIN_MEM; } diff --git a/openrtx/src/ui/ui_main.c b/openrtx/src/ui/ui_main.c index 5e31c141..6230bba8 100644 --- a/openrtx/src/ui/ui_main.c +++ b/openrtx/src/ui/ui_main.c @@ -19,6 +19,7 @@ ***************************************************************************/ #include +#include #include #include #include diff --git a/openrtx/src/ui/ui_menu.c b/openrtx/src/ui/ui_menu.c index 8df19c4b..0cac4db4 100644 --- a/openrtx/src/ui/ui_menu.c +++ b/openrtx/src/ui/ui_menu.c @@ -269,7 +269,7 @@ int _ui_getBankName(char *buf, uint8_t max_len, uint8_t index) else { bankHdr_t bank; - result = cps_readBankHeader(&bank, index); + result = cps_readBankHeader(&bank, index - 1); if(result != -1) snprintf(buf, max_len, "%s", bank.name); } @@ -279,7 +279,7 @@ int _ui_getBankName(char *buf, uint8_t max_len, uint8_t index) int _ui_getChannelName(char *buf, uint8_t max_len, uint8_t index) { channel_t channel; - int result = cps_readChannelData(&channel, index + 1); + int result = cps_readChannel(&channel, index); if(result != -1) snprintf(buf, max_len, "%s", channel.name); return result; @@ -288,7 +288,7 @@ int _ui_getChannelName(char *buf, uint8_t max_len, uint8_t index) int _ui_getContactName(char *buf, uint8_t max_len, uint8_t index) { contact_t contact; - int result = cps_readContactData(&contact, index + 1); + int result = cps_readContact(&contact, index); if(result != -1) snprintf(buf, max_len, "%s", contact.name); return result; diff --git a/platform/drivers/CPS/cps_io_native_GDx.c b/platform/drivers/CPS/cps_io_native_GDx.c index 3e28c974..762c04a3 100644 --- a/platform/drivers/CPS/cps_io_native_GDx.c +++ b/platform/drivers/CPS/cps_io_native_GDx.c @@ -78,7 +78,7 @@ int cps_create(char *cps_name) return 0; } -int cps_readChannelData(channel_t *channel, uint16_t pos) +int cps_readChannel(channel_t *channel, uint16_t pos) { if(pos >= maxNumChannels) return -1; @@ -185,7 +185,7 @@ int cps_readChannelData(channel_t *channel, uint16_t pos) } else if(channel->mode == OPMODE_DMR) { - channel->dmr.contactName_index = chData.contact_name_index; + channel->dmr.contact_index = chData.contact_name_index; channel->dmr.dmr_timeslot = chData.repeater_slot; channel->dmr.rxColorCode = chData.colorcode_rx; channel->dmr.txColorCode = chData.colorcode_tx; @@ -241,7 +241,7 @@ int32_t cps_readBankData(uint16_t bank_pos, uint16_t ch_pos) return zoneData.member[ch_pos]; } -int cps_readContactData(contact_t *contact, uint16_t pos) +int cps_readContact(contact_t *contact, uint16_t pos) { if(pos >= maxNumContacts) return -1; diff --git a/platform/drivers/CPS/cps_io_native_MD3x0.c b/platform/drivers/CPS/cps_io_native_MD3x0.c index da1636fe..820f0448 100644 --- a/platform/drivers/CPS/cps_io_native_MD3x0.c +++ b/platform/drivers/CPS/cps_io_native_MD3x0.c @@ -60,7 +60,7 @@ int cps_create(char *cps_name) return 0; } -int cps_readChannelData(channel_t *channel, uint16_t pos) +int cps_readChannel(channel_t *channel, uint16_t pos) { if(pos >= maxNumChannels) return -1; @@ -131,7 +131,7 @@ int cps_readChannelData(channel_t *channel, uint16_t pos) } else if(channel->mode == OPMODE_DMR) { - channel->dmr.contactName_index = chData.contact_name_index; + channel->dmr.contact_index = chData.contact_name_index; channel->dmr.dmr_timeslot = chData.repeater_slot; channel->dmr.rxColorCode = chData.colorcode; channel->dmr.txColorCode = chData.colorcode; @@ -189,7 +189,7 @@ int32_t cps_readBankData(uint16_t bank_pos, uint16_t ch_pos) return zoneData.member[ch_pos] - 1; } -int cps_readContactData(contact_t *contact, uint16_t pos) +int cps_readContact(contact_t *contact, uint16_t pos) { if(pos >= maxNumContacts) return -1; diff --git a/platform/drivers/CPS/cps_io_native_MD9600.c b/platform/drivers/CPS/cps_io_native_MD9600.c index 903d9114..30f4d581 100644 --- a/platform/drivers/CPS/cps_io_native_MD9600.c +++ b/platform/drivers/CPS/cps_io_native_MD9600.c @@ -121,7 +121,7 @@ static int _readChannelAtAddress(channel_t *channel, uint32_t addr) } else if(channel->mode == OPMODE_DMR) { - channel->dmr.contactName_index = chData.contact_name_index; + channel->dmr.contact_index = chData.contact_name_index; channel->dmr.dmr_timeslot = chData.repeater_slot; channel->dmr.rxColorCode = chData.colorcode; channel->dmr.txColorCode = chData.colorcode; @@ -157,7 +157,7 @@ int cps_create(char *cps_name) return 0; } -int cps_readChannelData(channel_t *channel, uint16_t pos) +int cps_readChannel(channel_t *channel, uint16_t pos) { if(pos >= maxNumChannels) return -1; @@ -222,7 +222,7 @@ int32_t cps_readBankData(uint16_t bank_pos, uint16_t ch_pos) return zoneExtData.ext_a[ch_pos - 16] - 1; } -int cps_readContactData(contact_t *contact, uint16_t pos) +int cps_readContact(contact_t *contact, uint16_t pos) { if(pos >= maxNumContacts) return -1; diff --git a/platform/drivers/CPS/cps_io_native_MDUV3x0.c b/platform/drivers/CPS/cps_io_native_MDUV3x0.c index f5514117..dc9e2d7f 100644 --- a/platform/drivers/CPS/cps_io_native_MDUV3x0.c +++ b/platform/drivers/CPS/cps_io_native_MDUV3x0.c @@ -120,7 +120,7 @@ static int _readChannelAtAddress(channel_t *channel, uint32_t addr) } else if(channel->mode == OPMODE_DMR) { - channel->dmr.contactName_index = chData.contact_name_index; + channel->dmr.contact_index = chData.contact_name_index; channel->dmr.dmr_timeslot = chData.repeater_slot; channel->dmr.rxColorCode = chData.colorcode; channel->dmr.txColorCode = chData.colorcode; @@ -155,7 +155,7 @@ int cps_create(char *cps_name) return 0; } -int cps_readChannelData(channel_t *channel, uint16_t pos) +int cps_readChannel(channel_t *channel, uint16_t pos) { if(pos >= maxNumChannels) return -1; @@ -223,7 +223,7 @@ int32_t cps_readBankData(uint16_t bank_pos, uint16_t ch_pos) return zoneExtData.ext_a[ch_pos - 16] - 1; } -int cps_readContactData(contact_t *contact, uint16_t pos) +int cps_readContact(contact_t *contact, uint16_t pos) { if(pos >= maxNumContacts) return -1; diff --git a/platform/drivers/CPS/cps_io_native_Mod17.c b/platform/drivers/CPS/cps_io_native_Mod17.c index 0c6bbb9b..412c8356 100644 --- a/platform/drivers/CPS/cps_io_native_Mod17.c +++ b/platform/drivers/CPS/cps_io_native_Mod17.c @@ -46,7 +46,7 @@ int cps_create(char *cps_name) return 0; } -int cps_readChannelData(channel_t *channel, uint16_t pos) +int cps_readChannel(channel_t *channel, uint16_t pos) { (void) channel; (void) pos; @@ -67,7 +67,7 @@ int32_t cps_readBankData(uint16_t bank_pos, uint16_t ch_pos) return -1; } -int cps_readContactData(contact_t *contact, uint16_t pos) +int cps_readContact(contact_t *contact, uint16_t pos) { (void) contact; (void) pos; diff --git a/tests/platform/codeplug_demo.c b/tests/platform/codeplug_demo.c index 9c0383c5..0636488c 100644 --- a/tests/platform/codeplug_demo.c +++ b/tests/platform/codeplug_demo.c @@ -34,7 +34,7 @@ int main() for(int pos=0,result=0; result != -1; pos++) { channel_t ch; - result = cps_readChannelData(&ch, pos); + result = cps_readChannel(&ch, pos); if(result != -1) { printf("Channel n.%d:\r\n", pos+1); @@ -71,7 +71,7 @@ int main() for(int pos=0,result=0; result != -1; pos++) { contact_t contact; - result = cps_readContactData(&contact, pos); + result = cps_readContact(&contact, pos); if(result != -1) { printf("Contact n.%d:\r\n", pos+1); diff --git a/tests/platform/printContacts_MDx.c b/tests/platform/printContacts_MDx.c index 27cb9a25..89fb8158 100644 --- a/tests/platform/printContacts_MDx.c +++ b/tests/platform/printContacts_MDx.c @@ -35,7 +35,7 @@ int main() getchar(); channel_t ch; - cps_readChannelData(&ch, pos); + cps_readChannel(&ch, pos); printf("Contact entry %d:\r\n", pos+1); printf(" %s\r\n TX: %ld\r\n RX: %ld\r\n Mode: %s\r\n Bandwidth: %s\r\n", ch.name, diff --git a/tests/unit/cps.c b/tests/unit/cps.c index 4aa8af80..29098905 100644 --- a/tests/unit/cps.c +++ b/tests/unit/cps.c @@ -1,19 +1,187 @@ #include +#include +#include + +int test_initCPS() { + // Initialize a new cps + int err = cps_create("/tmp/test1.rtxc"); + if (err) + return -1; + // Re-open it + err = cps_open("/tmp/test1.rtxc"); + if (err) + return -1; + return 0; +} + +int test_insertContact() { + cps_create("/tmp/test2.rtxc"); + + cps_open("/tmp/test2.rtxc"); + contact_t c1 = { "Test contact 1", 0, {{0}} }; + contact_t c2 = { "Test contact 2", 0, {{0}} }; + contact_t c3 = { "Test contact 3", 0, {{0}} }; + contact_t c4 = { "Test contact 4", 0, {{0}} }; + cps_insertContact(c1, 0); + cps_insertContact(c2, 0); + cps_insertContact(c3, 0); + cps_insertContact(c4, 1); + contact_t c = { 0 }; + cps_readContact(&c, 0); + if(strncmp(c3.name, c.name, 32L)) + return -1; + cps_readContact(&c, 1); + if(strncmp(c4.name, c.name, 32L)) + return -1; + cps_readContact(&c, 2); + if(strncmp(c2.name, c.name, 32L)) + return -1; + cps_readContact(&c, 3); + if(strncmp(c1.name, c.name, 32L)) + return -1; + cps_close(); + return 0; +} + +int test_insertChannel() { + cps_create("/tmp/test3.rtxc"); + + cps_open("/tmp/test3.rtxc"); + channel_t c1 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, "Test channel 1", "", {0}, {{0}} }; + channel_t c2 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, "Test channel 2", "", {0}, {{0}} }; + channel_t c3 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, "Test channel 3", "", {0}, {{0}} }; + channel_t c4 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, "Test channel 4", "", {0}, {{0}} }; + cps_insertChannel(c1, 0); + cps_insertChannel(c2, 0); + cps_insertChannel(c3, 0); + cps_insertChannel(c4, 1); + channel_t c = { 0 }; + cps_readChannel(&c, 0); + if(strncmp(c3.name, c.name, 32L)) + return -1; + cps_readChannel(&c, 1); + if(strncmp(c4.name, c.name, 32L)) + return -1; + cps_readChannel(&c, 2); + if(strncmp(c2.name, c.name, 32L)) + return -1; + cps_readChannel(&c, 3); + if(strncmp(c1.name, c.name, 32L)) + return -1; + cps_close(); + return 0; +} + +int test_contactIndexFix() { + cps_create("/tmp/test4.rtxc"); + + cps_open("/tmp/test4.rtxc"); + contact_t ct1 = { "Test contact 1", 0, {{0}} }; + contact_t ct2 = { "Test contact 2", 0, {{0}} }; + channel_t ch1 = { M17, 0, 0, 0, 0, 0, 0, 0, 0, "Test channel 1", "", {0}, {{0}} }; + cps_insertContact(ct1, 0); + cps_insertChannel(ch1, 0); + cps_insertContact(ct2, 0); + channel_t c = { 0 }; + cps_readChannel(&c, 0); + if(c.m17.contact_index != 1) + return -1; + cps_close(); + return 0; +} + +int test_createComplexCPS() { + cps_create("/tmp/test5.rtxc"); + + cps_open("/tmp/test5.rtxc"); + contact_t ct1 = { "Test contact 1", 0, {{0}} }; + contact_t ct2 = { "Test contact 2", 0, {{0}} }; + channel_t ch1 = { M17, 0, 0, 0, 0, 0, 0, 0, 0, "Test channel 1", "", {0}, {{0}} }; + channel_t ch2 = { M17, 0, 0, 0, 0, 0, 0, 0, 0, "Test channel 2", "", {0}, {{0}} }; + channel_t ch3 = { M17, 0, 0, 0, 0, 0, 0, 0, 0, "Test channel 3", "", {0}, {{0}} }; + channel_t ch4 = { M17, 0, 0, 0, 0, 0, 0, 0, 0, "Test channel 4", "", {0}, {{0}} }; + channel_t ch5 = { M17, 0, 0, 0, 0, 0, 0, 0, 0, "Test channel 5", "", {0}, {{0}} }; + bankHdr_t b1 = { "Test Bank 1", 0 }; + bankHdr_t b2 = { "Test Bank 2", 0 }; + cps_insertContact(ct2, 0); + cps_insertContact(ct1, 0); + cps_insertChannel(ch1, 0); + cps_insertChannel(ch2, 1); + cps_insertChannel(ch3, 2); + cps_insertChannel(ch4, 3); + cps_insertChannel(ch5, 4); + cps_insertBankHeader(b2, 0); + cps_insertBankHeader(b1, 0); + cps_insertBankData(0, 0, 0); + cps_insertBankData(1, 0, 1); + cps_insertBankData(2, 1, 0); + cps_insertBankData(3, 1, 1); + cps_insertBankData(4, 1, 2); + cps_insertBankData(5, 1, 3); + cps_close(); + return 0; +} + +int test_createOOOCPS() { + cps_create("/tmp/test6.rtxc"); + + cps_open("/tmp/test6.rtxc"); + contact_t ct1 = { "Test contact 1", 0, {{0}} }; + contact_t ct2 = { "Test contact 2", 0, {{0}} }; + channel_t ch1 = { M17, 0, 0, 0, 0, 0, 0, 0, 0, "Test channel 1", "", {0}, {{0}} }; + channel_t ch2 = { M17, 0, 0, 0, 0, 0, 0, 0, 0, "Test channel 2", "", {0}, {{0}} }; + channel_t ch3 = { M17, 0, 0, 0, 0, 0, 0, 0, 0, "Test channel 3", "", {0}, {{0}} }; + channel_t ch4 = { M17, 0, 0, 0, 0, 0, 0, 0, 0, "Test channel 4", "", {0}, {{0}} }; + channel_t ch5 = { M17, 0, 0, 0, 0, 0, 0, 0, 0, "Test channel 5", "", {0}, {{0}} }; + bankHdr_t b1 = { "Test Bank 1", 0 }; + bankHdr_t b2 = { "Test Bank 2", 0 }; + cps_insertContact(ct2, 0); + cps_insertContact(ct1, 0); + cps_insertBankHeader(b2, 0); + cps_insertBankHeader(b1, 0); + cps_insertChannel(ch5, 0); + cps_insertBankData(0, 0, 0); + cps_insertChannel(ch4, 0); + cps_insertBankData(0, 0, 1); + cps_insertChannel(ch3, 0); + cps_insertBankData(0, 1, 0); + cps_insertChannel(ch2, 0); + cps_insertBankData(0, 1, 1); + cps_insertChannel(ch1, 0); + cps_insertBankData(0, 1, 2); + cps_close(); + return 0; +} int main() { - // Initialize a new cps - int err = cps_create("test.rtxc"); - if (err) { - printf("Error in codeplug initialization!\n"); + if (test_initCPS()) + { + printf("Error in codeplug initialization and read back!\n"); return -1; } - // Write data - // Close it - // Re-open it - err = cps_open("test.rtxc"); - if (err) { - printf("Error in codeplug reading!\n"); + if (test_insertContact()) + { + printf("Error in contact insertion!\n"); + return -1; + } + if (test_insertChannel()) + { + printf("Error in channel insertion!\n"); + return -1; + } + if (test_contactIndexFix()) + { + printf("Error in contact index fix!\n"); + return -1; + } + if (test_createComplexCPS()) + { + printf("Error in creation of complex CPS!\n"); + return -1; + } + if (test_createOOOCPS()) + { + printf("Error in creation of Out-Of-Order CPS!\n"); return -1; } - // Read data and compare }