diff --git a/openrtx/include/cps.h b/openrtx/include/cps.h
index b912669b..ecd1b6ed 100644
--- a/openrtx/include/cps.h
+++ b/openrtx/include/cps.h
@@ -102,4 +102,13 @@ typedef struct
};
} channel_t;
+/**
+ * Data structure containing all the information of a zone.
+ */
+typedef struct
+{
+ char name[16]; /**< Zone name */
+ uint16_t member[64]; /**< Channels 1...64, 0=empty zone */
+} zone_t;
+
#endif
diff --git a/openrtx/include/interfaces/nvmem.h b/openrtx/include/interfaces/nvmem.h
index 67a81996..692e82e9 100644
--- a/openrtx/include/interfaces/nvmem.h
+++ b/openrtx/include/interfaces/nvmem.h
@@ -55,4 +55,13 @@ void nvm_readCalibData(void *buf);
*/
int nvm_readChannelData(channel_t *channel, uint16_t pos);
+/**
+ * Read one zone from table stored in nonvolatile memory.
+ *
+ * @param zone: pointer to the zone_t data structure to be populated.
+ * @param pos: position, inside the zone table, from which read data.
+ * @return 0 on success, -1 on failure
+ */
+int nvm_readZoneData(zone_t *zone, uint16_t pos);
+
#endif /* NVMEM_H */
diff --git a/platform/drivers/NVM/nvmem_MDUV3x0.c b/platform/drivers/NVM/nvmem_MDUV3x0.c
index bb3d9fec..04adac5c 100644
--- a/platform/drivers/NVM/nvmem_MDUV3x0.c
+++ b/platform/drivers/NVM/nvmem_MDUV3x0.c
@@ -18,6 +18,7 @@
* along with this program; if not, see *
***************************************************************************/
+#include
#include
#include
#include
@@ -25,7 +26,7 @@
/**
* \internal Data structure matching the one used by original MD3x0 firmware to
- * manage channel data inside nonvolatile flash memory.
+ * manage codeplug data inside nonvolatile flash memory.
*
* Taken by dmrconfig repository: https://github.com/sergev/dmrconfig/blob/master/uv380.c
*/
@@ -116,8 +117,27 @@ typedef struct
}
mduv3x0Channel_t;
+typedef struct {
+ // Bytes 0-31
+ uint16_t name[16]; // Zone Name (Unicode)
+
+ // Bytes 32-63
+ uint16_t member_a[16]; // Member A: channels 1...16
+} mduv3x0Zone_t;
+
+typedef struct {
+ // Bytes 0-95
+ uint16_t ext_a[48]; // Member A: channels 17...64
+
+ // Bytes 96-223
+ uint16_t member_b[64]; // Member B: channels 1...64
+} mduv3x0ZoneExt_t;
+
const uint32_t chDataBaseAddr = 0x110000; /**< Base address of channel data */
+const uint32_t zoneBaseAddr = 0x149e0; /**< Base address of zones */
+const uint32_t zoneExtBaseAddr = 0x31000; /**< Base address of zone extensions */
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 */
/**
* \internal Utility function to convert 4 byte BCD values into a 32-bit
@@ -301,3 +321,34 @@ int nvm_readChannelData(channel_t *channel, uint16_t pos)
return 0;
}
+
+int nvm_readZoneData(zone_t *zone, uint16_t pos)
+{
+ if(pos > maxNumZones) return -1;
+
+ W25Qx_wakeup();
+ delayUs(5);
+
+ mduv3x0Zone_t zoneData;
+ mduv3x0ZoneExt_t zoneExtData;
+ uint32_t zoneAddr = zoneBaseAddr + pos * sizeof(mduv3x0Zone_t);
+ uint32_t zoneExtAddr = zoneBaseAddr + pos * sizeof(mduv3x0Zone_t);
+ W25Qx_readData(zoneAddr, ((uint8_t *) &zoneData), sizeof(mduv3x0Zone_t));
+ W25Qx_readData(zoneExtAddr, ((uint8_t *) &zoneExtData), sizeof(mduv3x0ZoneExt_t));
+ W25Qx_sleep();
+
+ /*
+ * Brutally convert channel name from unicode to char by truncating the most
+ * significant byte
+ */
+ for(uint16_t i = 0; i < 16; i++)
+ {
+ zone->name[i] = ((char) (zoneData.name[i] & 0x00FF));
+ }
+ // Copy zone channel indexes
+ memcpy(zone->member, zoneData.member_a, sizeof(uint16_t) * 16);
+ // Copy zone extension channel indexes
+ memcpy(zone->member + 16, zoneExtData.ext_a, sizeof(uint16_t) * 48);
+
+ return 0;
+}
diff --git a/tests/platform/codeplug_demo.c b/tests/platform/codeplug_demo.c
new file mode 100644
index 00000000..8a315a70
--- /dev/null
+++ b/tests/platform/codeplug_demo.c
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * Copyright (C) 2020 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 *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+
+int main()
+{
+ nvm_init();
+
+ getchar();
+ printf("Codeplug Demo!\r\n\r\n");
+ printf("Contacts:\r\n");
+ for(uint16_t pos=0,result=0; result != -1 && pos < 20; pos++)
+ {
+ channel_t ch;
+ result = nvm_readChannelData(&ch, pos);
+ printf("Contact n.%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,
+ ch.tx_frequency,
+ ch.rx_frequency,
+ (ch.mode == 1) ? "DMR" : "FM",
+ (ch.bandwidth == BW_12_5) ? "12.5kHz" : ((ch.bandwidth == BW_20)
+ ? "20kHz" : "25kHz"));
+ puts("\r");
+ }
+ printf("Zones:\r\n");
+ for(uint16_t pos=0,result=0; result != -1 && pos < 5; pos++)
+ {
+ zone_t zone;
+ result = nvm_readZoneData(&zone, pos);
+ printf("Zone n.%d:\r\n", pos+1);
+ printf(" %s\r\n", zone.name);
+ for(int x=0; x < 64; x++)
+ {
+ if(zone.member[x] != 0)
+ {
+ printf(" - Channel %d\r\n", zone.member[x]);
+ }
+ }
+ puts("\r");
+ }
+ return 0;
+}