diff --git a/meson.build b/meson.build
index 65fc422c..9df1ed87 100644
--- a/meson.build
+++ b/meson.build
@@ -454,6 +454,28 @@ mod17_src += openrtx_src + stm32f405_src + ui_src_module17
mod17_inc += openrtx_inc + stm32f405_inc
mod17_def += openrtx_def + stm32f405_def
+##
+## Connect Systems CS70000
+##
+cs7000_src = ['platform/drivers/stubs/nvmem_stub.c',
+ 'platform/drivers/stubs/cps_io_stub.c',
+ 'platform/drivers/stubs/radio_stub.c',
+ 'platform/drivers/stubs/keyboard_stub.c',
+ 'platform/drivers/stubs/display_stub.c',
+ 'platform/drivers/stubs/audio_stub.c',
+ 'platform/drivers/GPIO/gpio_shiftReg.c',
+ 'platform/drivers/SPI/spi_custom.c',
+ 'platform/drivers/SPI/spi_bitbang.c',
+ 'platform/targets/CS7000/hwconfig.c',
+ 'platform/targets/CS7000/platform.c']
+
+cs7000_inc = ['platform/targets/CS7000']
+cs7000_def = {'PLATFORM_CS7000': '', 'timegm': 'mktime'}
+
+cs7000_src += openrtx_src + stm32f405_src + ui_src_default
+cs7000_inc += openrtx_inc + stm32f405_inc
+cs7000_def += openrtx_def + stm32f405_def
+
##
## -------------------------- Compilation arguments ----------------------------
##
@@ -549,6 +571,15 @@ foreach k, v : mod17_def
endif
endforeach
+cs7000_args = []
+foreach k, v : cs7000_def
+ if v == ''
+ cs7000_args += '-D@0@'.format(k)
+ else
+ cs7000_args += '-D@0@=@1@'.format(k, v)
+ endif
+endforeach
+
linux_opts = {
'sources' : linux_default_src,
'include_directories': linux_inc,
@@ -639,6 +670,15 @@ ttwrplus_opts = {
'link_args' : [],
}
+cs7000_opts = {
+ 'sources' : cs7000_src,
+ 'include_directories': cs7000_inc,
+ 'dependencies' : [codec2_dep],
+ 'c_args' : cs7000_args,
+ 'cpp_args' : cs7000_args,
+ 'link_args' : ['-Wl,-T../platform/mcu/STM32F4xx/stm32_1m+192k_rom.ld']
+}
+
##
## ---------------------------- Compilation targets ----------------------------
##
@@ -708,6 +748,13 @@ targets = [
'wrap' : ' ',
'load_addr': ' '
},
+ {
+ 'name' : 'cs7000',
+ 'opts' : cs7000_opts,
+ 'flashable': true,
+ 'wrap' : ' ',
+ 'load_addr': '0x08000000'
+ },
]
if build_machine.system() == 'linux'
@@ -724,6 +771,7 @@ gd77_loader = find_program('scripts/gd-77_firmware_loader.py', required:false, d
dfu_util = find_program('dfu-util', required:false, disabler:true)
west = find_program('west', required:false, disabler:true)
uf2conv = find_program('scripts/uf2conv.py', required:false, disabler:true)
+dfu_convert = find_program('scripts/dfu-convert.py', required:false, disabler:true)
foreach t : targets
@@ -816,7 +864,7 @@ foreach t : targets
output : name+'_flash',
command : [gd77_loader, '-f', '@INPUT@', '-m', t['wrap']])
- # Module17 also uses dfu-tool for flashing
+ # Module17 uses dfu-tool for flashing
elif name == 'openrtx_mod17'
# Wrap target for Module17 for consistency, same output as bin target
@@ -835,6 +883,23 @@ foreach t : targets
'-D', '@INPUT@',
'-s', '0x08000000'])
+ # For CS7000 'wrap' target prepares a .dfu file
+ elif name == 'openrtx_cs7000'
+
+ custom_target(name+'_wrap',
+ output : name+'.dfu',
+ input : bin,
+ command : [dfu_convert, '-b', t['load_addr']+':@INPUT@', '@OUTPUT@'])
+
+
+ custom_target(name+'_flash',
+ input : bin,
+ output : name+'_flash',
+ command : [dfu_util,
+ '-d', '0483:df11',
+ '-a', '0',
+ '-D', '@INPUT@',
+ '-s', t['load_addr']])
else
wrap = custom_target(name+'_wrap',
diff --git a/platform/targets/CS7000/hwconfig.c b/platform/targets/CS7000/hwconfig.c
new file mode 100644
index 00000000..dc251b42
--- /dev/null
+++ b/platform/targets/CS7000/hwconfig.c
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * 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
+
+/**
+ * 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 STM32F405 at 168MHz:
+ *
+ * - Freq 8.46MHz
+ * - Pos. width 36ns
+ * - Neg. with 82ns
+ */
+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, #1 \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)
+ }
+
+ return 0;
+}
+
+static const struct gpioPin shiftRegStrobe = { GPIOEXT_STR };
+
+SPI_CUSTOM_DEVICE_DEFINE(spiSr, spiSr_func, NULL, NULL)
+GPIO_SHIFTREG_DEVICE_DEFINE(extGpio, (const struct spiDevice *) &spiSr, shiftRegStrobe, 24)
diff --git a/platform/targets/CS7000/hwconfig.h b/platform/targets/CS7000/hwconfig.h
new file mode 100644
index 00000000..9e7efadf
--- /dev/null
+++ b/platform/targets/CS7000/hwconfig.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ * 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
+extern "C" {
+#endif
+
+extern const struct spiCustomDevice spiSr;
+extern const struct gpioDev extGpio;
+
+/* 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
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HWCONFIG_H */
diff --git a/platform/targets/CS7000/pinmap.h b/platform/targets/CS7000/pinmap.h
new file mode 100644
index 00000000..595d3179
--- /dev/null
+++ b/platform/targets/CS7000/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,3 // VOX
+#define AIN_RSSI GPIOB,0
+#define AIN_NOISE GPIOB,1
+#define AIN_RTX GPIOA,7 // 2T/5T
+#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,2
+#define FLASH_CLK GPIOE,3
+#define FLASH_SDO GPIOE,4
+#define FLASH_SDI GPIOE,5
+
+/* 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,6
+#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_RXD GPIOC,6
+#define GPS_TXD 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/platform.c b/platform/targets/CS7000/platform.c
new file mode 100644
index 00000000..a9938f2f
--- /dev/null
+++ b/platform/targets/CS7000/platform.c
@@ -0,0 +1,160 @@
+/***************************************************************************
+ * 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
+
+static const hwInfo_t hwInfo =
+{
+ .name = "CS7000",
+ .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(GPIOEXT_CLK, OUTPUT);
+ gpio_setMode(GPIOEXT_DAT, OUTPUT);
+
+ spi_init((const struct spiDevice *) &spiSr);
+ gpioShiftReg_init(&extGpio);
+
+ #ifndef RUNNING_TESTSUITE
+ gpioDev_set(MAIN_PWR_SW);
+ #endif
+}
+
+void platform_terminate()
+{
+
+ #ifndef RUNNING_TESTSUITE
+ gpioDev_clear(MAIN_PWR_SW);
+ #endif
+
+ gpioShiftReg_terminate(&extGpio);
+}
+
+uint16_t platform_getVbat()
+{
+ return 7400; // TODO
+}
+
+uint8_t platform_getMicLevel()
+{
+ return 0; // TODO
+}
+
+uint8_t platform_getVolumeLevel()
+{
+ return 0; // TODO
+}
+
+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.
+ */
+ return (platform_getVbat() > 1000) ? true : false;
+}
+
+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;
+}
diff --git a/scripts/dfu-convert.py b/scripts/dfu-convert.py
new file mode 100755
index 00000000..031b82ad
--- /dev/null
+++ b/scripts/dfu-convert.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python3
+
+# Written by Antonio Galea - 2010/11/18
+# Distributed under Gnu LGPL 3.0
+# see http://www.gnu.org/licenses/lgpl-3.0.txt
+
+import sys,struct,zlib,os
+from optparse import OptionParser
+from intelhex import IntelHex
+
+DEFAULT_DEVICE="0x0483:0xdf11"
+
+def named(tuple,names):
+ return dict(zip(names.split(),tuple))
+def consume(fmt,data,names):
+ n = struct.calcsize(fmt)
+ return named(struct.unpack(fmt,data[:n]),names),data[n:]
+def cstring(string):
+ return string.split('\0',1)[0]
+def compute_crc(data):
+ return 0xFFFFFFFF & -zlib.crc32(data) -1
+
+def parse(file, dump_images=False):
+ print ('File: "%s"' % file)
+ data = open(file,'rb').read()
+ crc = compute_crc(data[:-4])
+ prefix, data = consume('<5sBIB',data,'signature version size targets')
+ print ('%(signature)s v%(version)d, image size: %(size)d, targets: %(targets)d' % prefix)
+ for t in range(prefix['targets']):
+ tprefix, data = consume('<6sBI255s2I',data,'signature altsetting named name size elements')
+ tprefix['num'] = t
+ if not tprefix['named']:
+ tprefix['name'] = ''
+ print ('%(signature)s %(num)d, alt setting: %(altsetting)s, name: "%(name)s", size: %(size)d, elements: %(elements)d' % tprefix)
+ tsize = tprefix['size']
+ target, data = data[:tsize], data[tsize:]
+ for e in range(tprefix['elements']):
+ eprefix, target = consume('<2I',target,'address size')
+ eprefix['num'] = e
+ print (' %(num)d, address: 0x%(address)08x, size: %(size)d' % eprefix)
+ esize = eprefix['size']
+ image, target = target[:esize], target[esize:]
+ if dump_images:
+ out = '%s.target%d.image%d.bin' % (file,t,e)
+ open(out,'wb').write(image)
+ print (' DUMPED IMAGE TO "%s"' % out)
+ if len(target):
+ print ("target %d: PARSE ERROR" % t)
+ suffix = named(struct.unpack('<4H3sBI',data[:16]),'device product vendor dfu ufd len crc')
+ print ('usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x' % suffix)
+ if crc != suffix['crc']:
+ print ("CRC ERROR: computed crc32 is 0x%08x" % crc)
+ data = data[16:]
+ if data:
+ print ("PARSE ERROR")
+
+def build(file, targets, device=DEFAULT_DEVICE):
+ data = b''
+ for t,target in enumerate(targets):
+ tdata = b''
+ for image in target:
+ tdata += struct.pack('<2I',image['address'],len(image['data']))+ image['data']
+ tdata = struct.pack('<6sBI255s2I',b'Target',0,1,b'ST...',len(tdata),len(target)) + tdata
+ data += tdata
+ data = struct.pack('<5sBIB',b'DfuSe',1,len(data)+11,len(targets)) + data
+ v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1))
+ data += struct.pack('<4H3sB',0,d,v,0x011a,b'UFD',16)
+ crc = compute_crc(data)
+ data += struct.pack('