diff --git a/meson.build b/meson.build
index 48b44034..8f8ac86e 100644
--- a/meson.build
+++ b/meson.build
@@ -511,6 +511,30 @@ cs7000_src += openrtx_src + stm32f405_src + ui_src_default
cs7000_inc += openrtx_inc + stm32f405_inc
cs7000_def += openrtx_def + stm32f405_def
+##
+## Connect Systems CS70000-PLUS
+##
+cs7000p_src = ['platform/drivers/stubs/nvmem_stub.c',
+ 'platform/drivers/stubs/cps_io_stub.c',
+ 'platform/drivers/stubs/radio_stub.c',
+ 'platform/drivers/stubs/audio_stub.c',
+ 'platform/drivers/stubs/radio_stub.c',
+ 'platform/drivers/display/ST7735R_CS7000.c',
+ 'platform/drivers/keyboard/keyboard_CS7000.c',
+ 'platform/drivers/backlight/backlight_CS7000.c',
+ 'platform/drivers/GPIO/gpio_shiftReg.c',
+ 'platform/drivers/SPI/spi_custom.c',
+ 'platform/drivers/SPI/spi_bitbang.c',
+ 'platform/targets/CS7000-PLUS/hwconfig.c',
+ 'platform/targets/CS7000-PLUS/platform.c']
+
+cs7000p_inc = ['platform/targets/CS7000-PLUS']
+cs7000p_def = {'PLATFORM_CS7000P': '', 'timegm': 'mktime'}
+
+cs7000p_src += openrtx_src + stm32h743_src + miosix_cm7_src + ui_src_default
+cs7000p_inc += openrtx_inc + stm32h743_inc + miosix_cm7_inc
+cs7000p_def += openrtx_def + stm32h743_def + miosix_cm7_def
+
##
## -------------------------- Compilation arguments ----------------------------
##
@@ -615,6 +639,15 @@ foreach k, v : cs7000_def
endif
endforeach
+cs7000p_args = []
+foreach k, v : cs7000p_def
+ if v == ''
+ cs7000p_args += '-D@0@'.format(k)
+ else
+ cs7000p_args += '-D@0@=@1@'.format(k, v)
+ endif
+endforeach
+
linux_opts = {
'sources' : linux_default_src,
'include_directories': linux_inc,
@@ -714,6 +747,16 @@ cs7000_opts = {
'link_args' : ['-Wl,-T../platform/mcu/STM32F4xx/stm32_1m+192k_rom.ld']
}
+cs7000p_opts = {
+ 'sources' : cs7000p_src,
+ 'include_directories': cs7000p_inc,
+ 'dependencies' : [codec2_dep],
+ 'c_args' : cs7000p_args,
+ 'cpp_args' : cs7000p_args,
+ 'link_args' : ['-Wl,-T../platform/mcu/STM32H7xx/linker_script_cs7000p.ld',
+ '-Wl,--print-memory-usage']
+}
+
##
## ---------------------------- Compilation targets ----------------------------
##
@@ -790,6 +833,13 @@ targets = [
'wrap' : ' ',
'load_addr': '0x08000000'
},
+ {
+ 'name' : 'cs7000p',
+ 'opts' : cs7000p_opts,
+ 'flashable': true,
+ 'wrap' : ' ',
+ 'load_addr': '0x08100000'
+ },
]
if build_machine.system() == 'linux'
@@ -919,7 +969,7 @@ foreach t : targets
'-s', '0x08000000'])
# For CS7000 'wrap' target prepares a .dfu file
- elif name == 'openrtx_cs7000'
+ elif name == 'openrtx_cs7000' or name == 'openrtx_cs7000p'
custom_target(name+'_wrap',
output : name+'.dfu',
diff --git a/platform/mcu/STM32H7xx/linker_script_cs7000p.ld b/platform/mcu/STM32H7xx/linker_script_cs7000p.ld
new file mode 100644
index 00000000..7f686978
--- /dev/null
+++ b/platform/mcu/STM32H7xx/linker_script_cs7000p.ld
@@ -0,0 +1,167 @@
+/*
+ * C++ enabled linker script for stm32 (2M FLASH, 512K RAM)
+ * Developed by TFT: Terraneo Federico Technologies
+ * Optimized for use with the Miosix kernel
+ */
+
+/*
+ * This linker script puts:
+ * - read only data and code (.text, .rodata, .eh_*) in flash
+ * - stacks, heap and sections .data and .bss in the internal ram
+ * - the external ram (if available) is not used.
+ */
+
+/*
+ * The main stack is used for interrupt handling by the kernel.
+ *
+ * *** Readme ***
+ * This linker script places the main stack (used by the kernel for interrupts)
+ * at the bottom of the ram, instead of the top. This is done for two reasons:
+ *
+ * - as an optimization for microcontrollers with little ram memory. In fact
+ * the implementation of malloc from newlib requests memory to the OS in 4KB
+ * block (except the first block that can be smaller). This is probably done
+ * for compatibility with OSes with an MMU and paged memory. To see why this
+ * is bad, consider a microcontroller with 8KB of ram: when malloc finishes
+ * up the first 4KB it will call _sbrk_r asking for a 4KB block, but this will
+ * fail because the top part of the ram is used by the main stack. As a
+ * result, the top part of the memory will not be used by malloc, even if
+ * available (and it is nearly *half* the ram on an 8KB mcu). By placing the
+ * main stack at the bottom of the ram, the upper 4KB block will be entirely
+ * free and available as heap space.
+ *
+ * - In case of main stack overflow the cpu will fault because access to memory
+ * before the beginning of the ram faults. Instead with the default stack
+ * placement the main stack will silently collide with the heap.
+ * Note: if increasing the main stack size also increase the ORIGIN value in
+ * the MEMORY definitions below accordingly.
+ */
+_main_stack_size = 0x00000200; /* main stack = 512Bytes */
+_main_stack_top = 0x24000000 + _main_stack_size;
+ASSERT(_main_stack_size % 8 == 0, "MAIN stack size error");
+
+/* end of the heap */
+_heap_end = 0x24080000; /* end of available ram */
+
+/* identify the Entry Point */
+ENTRY(_Z13Reset_Handlerv)
+
+/* specify the memory areas */
+MEMORY
+{
+ flash(rx) : ORIGIN = 0x08100000, LENGTH = 1M
+
+ /* NOTE: for now wer support only the AXI SRAM */
+ ram(wx) : ORIGIN = 0x24000200, LENGTH = 512K-0x200
+}
+
+/* now define the output sections */
+SECTIONS
+{
+ . = 0;
+
+ /* .text section: code goes to flash */
+ .text :
+ {
+ /* Startup code must go at address 0 */
+ KEEP(*(.isr_vector))
+
+ *(.text)
+ *(.text.*)
+ *(.gnu.linkonce.t.*)
+ /* these sections for thumb interwork? */
+ *(.glue_7)
+ *(.glue_7t)
+ /* these sections for C++? */
+ *(.gcc_except_table)
+ *(.gcc_except_table.*)
+ *(.ARM.extab*)
+ *(.gnu.linkonce.armextab.*)
+
+ . = ALIGN(4);
+ /* .rodata: constant data */
+ *(.rodata)
+ *(.rodata.*)
+ *(.gnu.linkonce.r.*)
+
+ /* C++ Static constructors/destructors (eabi) */
+ . = ALIGN(4);
+ KEEP(*(.init))
+
+ . = ALIGN(4);
+ __miosix_init_array_start = .;
+ KEEP (*(SORT(.miosix_init_array.*)))
+ KEEP (*(.miosix_init_array))
+ __miosix_init_array_end = .;
+
+ . = ALIGN(4);
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+
+ . = ALIGN(4);
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+
+ . = ALIGN(4);
+ KEEP(*(.fini))
+
+ . = ALIGN(4);
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+
+ /* C++ Static constructors/destructors (elf) */
+ . = ALIGN(4);
+ _ctor_start = .;
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*crtend.o(.ctors))
+ _ctor_end = .;
+
+ . = ALIGN(4);
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*crtend.o(.dtors))
+ } > flash
+
+ /* .ARM.exidx is sorted, so has to go in its own output section. */
+ __exidx_start = .;
+ .ARM.exidx :
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ } > flash
+ __exidx_end = .;
+
+ /* .data section: global variables go to ram, but also store a copy to
+ flash to initialize them */
+ .data : ALIGN(8)
+ {
+ _data = .;
+ *(.data)
+ *(.data.*)
+ *(.gnu.linkonce.d.*)
+ . = ALIGN(8);
+ _edata = .;
+ } > ram AT > flash
+ _etext = LOADADDR(.data);
+
+ /* .bss section: uninitialized global variables go to ram */
+ _bss_start = .;
+ .bss :
+ {
+ *(.bss)
+ *(.bss.*)
+ *(.gnu.linkonce.b.*)
+ . = ALIGN(8);
+ } > ram
+ _bss_end = .;
+
+ _end = .;
+ PROVIDE(end = .);
+}
diff --git a/platform/targets/CS7000-PLUS/hwconfig.c b/platform/targets/CS7000-PLUS/hwconfig.c
new file mode 100644
index 00000000..051b369e
--- /dev/null
+++ b/platform/targets/CS7000-PLUS/hwconfig.c
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * Copyright (C) 2024 by 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
+#include
+#include
+
+/**
+ * SPI bitbang function for SN74HC595 gpio extender.
+ *
+ * Hand-tuned to be as fast as possible, gives the following clock performance
+ * when compiled with -Os and run on STM32H743 at 400MHz:
+ *
+ * - Freq 7MHz
+ * - Pos. width 70ns
+ * - Neg. with 70ns
+ */
+static uint8_t spiSr_func(const void *priv, uint8_t value)
+{
+ (void) priv;
+
+ for(uint8_t cnt = 0; cnt < 8; cnt++)
+ {
+ GPIOE->BSRR = (1 << 23); // Clear PE7 (CLK)
+
+ if(value & (0x80 >> cnt))
+ GPIOE->BSRR = 1 << 9; // Set PE9 (MOSI)
+ else
+ GPIOE->BSRR = 1 << 25; // Clear PE9 (MOSI)
+
+ // ~70ns delay
+ asm volatile(" mov r1, #5 \n"
+ "___loop_2: cmp r1, #0 \n"
+ " itt ne \n"
+ " subne r1, r1, #1 \n"
+ " bne ___loop_2 \n":::"r1");
+
+ GPIOE->BSRR = (1 << 7); // Set PE7 (CLK)
+
+ // ~70ns delay
+ asm volatile(" mov r1, #6 \n"
+ "___loop_3: cmp r1, #0 \n"
+ " itt ne \n"
+ " subne r1, r1, #1 \n"
+ " bne ___loop_3 \n":::"r1");
+ }
+
+ return 0;
+}
+
+static const struct gpioPin shiftRegStrobe = { GPIOEXT_STR };
+static pthread_mutex_t adc1Mutex;
+
+SPI_CUSTOM_DEVICE_DEFINE(spiSr, spiSr_func, NULL, NULL)
+GPIO_SHIFTREG_DEVICE_DEFINE(extGpio, (const struct spiDevice *) &spiSr, shiftRegStrobe, 24)
+ADC_STM32_DEVICE_DEFINE(adc1, ADC1, &adc1Mutex, ADC_COUNTS_TO_UV(3300000, 16))
diff --git a/platform/targets/CS7000-PLUS/hwconfig.h b/platform/targets/CS7000-PLUS/hwconfig.h
new file mode 100644
index 00000000..b8d03177
--- /dev/null
+++ b/platform/targets/CS7000-PLUS/hwconfig.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+ * Copyright (C) 2024 by 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 *
+ ***************************************************************************/
+
+#ifndef HWCONFIG_H
+#define HWCONFIG_H
+
+#include
+#include "pinmap.h"
+
+#ifdef __cplusplus
+
+// Export the HR_C6000 driver only for C++ sources
+#include
+
+extern HR_C6000 C6000;
+
+extern "C" {
+#endif
+
+enum AdcChannels
+{
+ ADC_VOL_CH = 8, /* PC5 */
+ ADC_VBAT_CH = 3, /* PA6 */
+ ADC_RTX_CH = 15, /* PA3 */
+ ADC_RSSI_CH = 9, /* PB0 */
+ ADC_MIC_CH = 7, /* PA7 */
+ ADC_CTCSS_CH = 2, /* PA2 */
+};
+
+extern const struct Adc adc1;
+extern const struct spiCustomDevice spiSr;
+extern const struct gpioDev extGpio;
+extern const struct ak2365a detector;
+extern const struct sky73210 pll;
+
+/* Screen dimensions */
+#define CONFIG_SCREEN_WIDTH 160
+#define CONFIG_SCREEN_HEIGHT 128
+
+/* Screen pixel format */
+#define CONFIG_PIX_FMT_RGB565
+
+/* Screen has adjustable brightness */
+#define CONFIG_SCREEN_BRIGHTNESS
+
+/* Battery type */
+#define CONFIG_BAT_LIPO_2S
+
+/* Device supports M17 mode */
+#define CONFIG_M17
+
+/* Device has a GPS chip */
+// #define CONFIG_GPS
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HWCONFIG_H */
diff --git a/platform/targets/CS7000-PLUS/pinmap.h b/platform/targets/CS7000-PLUS/pinmap.h
new file mode 100644
index 00000000..7459938b
--- /dev/null
+++ b/platform/targets/CS7000-PLUS/pinmap.h
@@ -0,0 +1,173 @@
+/***************************************************************************
+ * Copyright (C) 2024 by 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 *
+ ***************************************************************************/
+
+#ifndef PINMAP_H
+#define PINMAP_H
+
+#include
+
+/* Power control */
+#define BAT_DETECT GPIOB,2
+#define MAIN_PWR_DET GPIOA,6
+#define MAIN_PWR_SW &extGpio,20
+
+/* Display */
+#define LCD_D0 GPIOD,0
+#define LCD_D1 GPIOD,1
+#define LCD_D2 GPIOD,2
+#define LCD_D3 GPIOD,3
+#define LCD_D4 GPIOD,4
+#define LCD_D5 GPIOD,5
+#define LCD_D6 GPIOD,6
+#define LCD_D7 GPIOD,7
+#define LCD_WR GPIOD,13
+#define LCD_RD GPIOD,14
+#define LCD_DC GPIOD,12
+#define LCD_RST GPIOE,0
+#define LCD_CS GPIOE,1
+#define LCD_BKLIGHT GPIOC,9
+
+/*
+ * Keyboard. Rows and columns, except for column 5, are shared with the LCD
+ * data lines. Commens reports the resistor number in the schematic for reference.
+ */
+#define KB_ROW1 LCD_D0 // R905
+#define KB_ROW2 LCD_D1 // R906
+#define KB_ROW3 LCD_D2 // R907
+#define KB_ROW4 LCD_D3 // R908
+#define KB_COL1 LCD_D7 // R902
+#define KB_COL2 LCD_D6 // R903
+#define KB_COL3 LCD_D5 // R904
+#define KB_COL4 LCD_D4 // R909
+#define KB_COL5 GPIOB,7 // R926
+#define KBD_BKLIGHT &extGpio,16
+
+/* Push-to-talk and side keys */
+#define PTT_SW GPIOA,8
+#define PTT_EXT GPIOE,11
+#define SIDE_KEY1 GPIOD,15
+#define SIDE_KEY2 GPIOE,12
+#define SIDE_KEY3 GPIOE,13
+#define ALARM_KEY GPIOE,10
+
+/* Channel selection rotary encoder */
+#define CH_SELECTOR_0 GPIOE,14
+#define CH_SELECTOR_1 GPIOE,15
+#define CH_SELECTOR_2 GPIOB,10
+#define CH_SELECTOR_3 GPIOB,11
+
+/* LEDs */
+#define GREEN_LED &extGpio,12
+#define RED_LED &extGpio,13
+
+/* Analog inputs */
+#define AIN_VOLUME GPIOC,5
+#define AIN_VBAT GPIOC,4 // BATT
+#define AIN_MIC GPIOA,7
+#define AIN_RSSI GPIOB,0
+#define AIN_NOISE GPIOB,1
+#define AIN_RTX GPIOA,3
+#define AIN_CTCSS GPIOA,2 // QT_DQT_IN
+#define AIN_TEMP GPIOA,7 // Batt. temp.
+
+/* Tone generator */
+#define CTCSS_OUT GPIOC,8 // CTCSS tone
+#define BEEP_OUT GPIOA,5 // System "beep"
+
+/* External flash */
+#define FLASH_CS &GpioE,4
+#define FLASH_CLK GPIOE,2
+#define FLASH_SDO GPIOE,5
+#define FLASH_SDI GPIOE,6
+
+/* PLL */
+#define PLL_CS &GpioD,9
+#define PLL_CLK GPIOD,10
+#define PLL_DAT GPIOD,8
+#define PLL_LD GPIOD,11
+
+/* HR_C6000 */
+#define C6K_CS &GpioB,12
+#define C6K_CLK GPIOB,13
+#define C6K_MISO GPIOB,14
+#define C6K_MOSI GPIOB,15
+#define C6K_SLEEP &extGpio,7
+
+#define VOC_CS GPIOB,6
+#define VOC_CLK GPIOB,3
+#define VOC_MOSI GPIOB,4
+#define VOC_MISO GPIOB,5
+
+#define I2S_FS GPIOA,15
+#define I2S_CLK GPIOC,10
+#define I2S_RX GPIOC,11
+#define I2S_TX GPIOC,12
+
+#define DMR_TS_INT GPIOC,0
+#define DMR_SYS_INT GPIOC,1
+#define DMR_TX_INT GPIOC,2
+
+/* AK2365 */
+#define DET_PDN &extGpio,6
+#define DET_CS &extGpio,0
+#define DET_CLK GPIOE,3
+#define DET_DAT GPIOC,13
+#define DET_RST &GpioC,14
+
+/* RTX control */
+#define RF_APC_SW &extGpio,3
+#define VCOVCC_SW &extGpio,8
+#define TX_PWR_EN &extGpio,9
+#define RX_PWR_EN &extGpio,15
+#define VCO_PWR_EN &extGpio,11
+#define CTCSS_AMP_EN &extGpio,22
+#define APC_TV GPIOA,4
+
+/* Audio control */
+#define AUDIO_AMP_EN &extGpio,14
+#define INT_SPK_MUTE &extGpio,17
+#define EXT_SPK_MUTE &extGpio,19
+#define MIC_PWR_EN &extGpio,18
+#define INT_MIC_SEL &extGpio,10
+#define EXT_MIC_SEL &extGpio,5
+#define AF_MUTE &extGpio,23
+#define PHONE_DETECT GPIOA,13
+
+/* GPS */
+#define GPS_TXD GPIOC,6
+#define GPS_RXD GPIOC,7
+
+/* Accessory connector */
+#define PHONE_TXD GPIOA,0
+#define PHONE_RXD GPIOA,1
+
+/* SN74HC595 gpio extenders */
+#define GPIOEXT_CLK GPIOE,7
+#define GPIOEXT_DAT GPIOE,9
+#define GPIOEXT_STR &GpioE,8
+
+/* Bluetooth module */
+#define BLTH_DETECT GPIOA,14
+#define BLTH_PWR_EN &extGpio,4
+#define BLTH_RXD GPIOA,9
+#define BLTH_TXD GPIOA,10
+
+/* ALPU-MP */
+#define ALPU_SDA GPIOB,9
+#define ALPU_SCL GPIOB,8
+
+#endif /* PINMAP_H */
diff --git a/platform/targets/CS7000-PLUS/platform.c b/platform/targets/CS7000-PLUS/platform.c
new file mode 100644
index 00000000..3f51ad6c
--- /dev/null
+++ b/platform/targets/CS7000-PLUS/platform.c
@@ -0,0 +1,207 @@
+/***************************************************************************
+ * Copyright (C) 2024 by 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
+#include
+#include
+#include
+#include
+
+static const hwInfo_t hwInfo =
+{
+ .name = "CS7000P",
+ .hw_version = 0,
+ .vhf_band = 0,
+ .uhf_band = 1,
+ .vhf_minFreq = 0,
+ .vhf_maxFreq = 0,
+ .uhf_minFreq = 400,
+ .uhf_maxFreq = 527
+};
+
+
+void platform_init()
+{
+ gpio_setMode(PTT_SW, INPUT);
+ gpio_setMode(PTT_EXT, INPUT);
+
+ gpio_setMode(MAIN_PWR_DET, ANALOG);
+ gpio_setMode(AIN_MIC, ANALOG);
+ gpio_setMode(AIN_VOLUME, ANALOG);
+
+ gpio_setMode(GPIOEXT_CLK, OUTPUT);
+ gpio_setMode(GPIOEXT_DAT, OUTPUT);
+
+ spi_init((const struct spiDevice *) &spiSr);
+ gpioShiftReg_init(&extGpio);
+ adcStm32_init(&adc1);
+ nvm_init();
+ audio_init();
+
+ #ifndef RUNNING_TESTSUITE
+ gpioDev_set(MAIN_PWR_SW);
+ #endif
+}
+
+void platform_terminate()
+{
+ adcStm32_terminate(&adc1);
+
+ #ifndef RUNNING_TESTSUITE
+ gpioDev_clear(MAIN_PWR_SW);
+ #endif
+
+ gpioShiftReg_terminate(&extGpio);
+}
+
+uint16_t platform_getVbat()
+{
+ /*
+ * Battery voltage is measured through an 1:3.95 voltage divider and
+ * adc1_getMeasurement returns a value in uV.
+ */
+ uint32_t vbat = adc_getVoltage(&adc1, ADC_VBAT_CH) * 395;
+ return vbat / 100000;
+}
+
+uint8_t platform_getMicLevel()
+{
+ // ADC1 returns a 16-bit value: shift right by eight to get 0 - 255
+ return adc_getRawSample(&adc1, ADC_MIC_CH) >> 8;
+}
+
+uint8_t platform_getVolumeLevel()
+{
+ /*
+ * Volume level corresponds to an analog signal in the range 20 - 2520mV.
+ * Potentiometer has pseudo-logarithmic law, well described with two straight
+ * lines with a breakpoint around 410mV.
+ * Output value has range 0 - 255 with breakpoint at 139.
+ */
+ uint16_t value = adc_getRawSample(&adc1, ADC_VOL_CH) >> 4;
+ uint32_t output;
+
+ if(value <= 512)
+ {
+ // First line: offset zero, slope 0.271
+ output = value;
+ output = (output * 271) / 1000;
+ }
+ else
+ {
+ // Second line: offset 512, slope 0.044
+ output = value - 512;
+ output = (output * 44) / 1000;
+ output += 139;
+ }
+
+ if(output > 255)
+ output = 255;
+
+ return output;
+}
+
+// int8_t platform_getChSelector()
+// {
+// return 0; // TODO
+// }
+
+bool platform_getPttStatus()
+{
+ /* PTT line has a pullup resistor with PTT switch closing to ground */
+ uint8_t intPttStatus = gpio_readPin(PTT_SW);
+ uint8_t extPttStatus = gpio_readPin(PTT_EXT);
+ return ((intPttStatus == 0) || (extPttStatus == 0)) ? true : false;
+}
+
+bool platform_pwrButtonStatus()
+{
+ /*
+ * When power knob is set to off, battery voltage measurement returns 0V.
+ * Here we set the threshold to 1V since, with knob in off position, there
+ * is always a bit of noise in the ADC measurement making the returned
+ * voltage not to be exactly zero.
+ */
+ uint16_t vbat = platform_getVbat();
+ if(vbat < 1000)
+ return false;
+
+ return true;
+}
+
+void platform_ledOn(led_t led)
+{
+ switch(led)
+ {
+ case GREEN:
+ gpioDev_set(GREEN_LED);
+ break;
+
+ case RED:
+ gpioDev_set(RED_LED);
+ break;
+
+ case YELLOW:
+ gpioDev_set(GREEN_LED);
+ gpioDev_set(RED_LED);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void platform_ledOff(led_t led)
+{
+ switch(led)
+ {
+ case GREEN:
+ gpioDev_clear(GREEN_LED);
+ break;
+
+ case RED:
+ gpioDev_clear(RED_LED);
+ break;
+
+ case YELLOW:
+ gpioDev_clear(GREEN_LED);
+ gpioDev_clear(RED_LED);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void platform_beepStart(uint16_t freq)
+{
+ (void) freq;
+}
+
+void platform_beepStop()
+{
+
+}
+
+const hwInfo_t *platform_getHwInfo()
+{
+ return &hwInfo;
+}