Implemented load/save of settings and VFO configuration for MDx devices
This commit is contained in:
parent
756812ca31
commit
691b388228
|
|
@ -169,6 +169,7 @@ stm32f405_src = ['platform/mcu/STM32F4xx/boot/startup.cpp',
|
||||||
'platform/mcu/STM32F4xx/drivers/rtc.c',
|
'platform/mcu/STM32F4xx/drivers/rtc.c',
|
||||||
'platform/mcu/STM32F4xx/drivers/SPI2.c',
|
'platform/mcu/STM32F4xx/drivers/SPI2.c',
|
||||||
'platform/mcu/STM32F4xx/drivers/USART3.cpp',
|
'platform/mcu/STM32F4xx/drivers/USART3.cpp',
|
||||||
|
'platform/mcu/STM32F4xx/drivers/flash.c',
|
||||||
'platform/mcu/CMSIS/Device/ST/STM32F4xx/Source/system_stm32f4xx.c']
|
'platform/mcu/CMSIS/Device/ST/STM32F4xx/Source/system_stm32f4xx.c']
|
||||||
|
|
||||||
stm32f405_inc = ['platform/mcu/CMSIS/Include',
|
stm32f405_inc = ['platform/mcu/CMSIS/Include',
|
||||||
|
|
|
||||||
|
|
@ -48,11 +48,14 @@ int main(void)
|
||||||
// Initialize platform drivers
|
// Initialize platform drivers
|
||||||
platform_init();
|
platform_init();
|
||||||
|
|
||||||
|
// Initialize radio state
|
||||||
|
state_init();
|
||||||
|
|
||||||
// Initialize display and graphics driver
|
// Initialize display and graphics driver
|
||||||
gfx_init();
|
gfx_init();
|
||||||
|
|
||||||
// Set default contrast
|
// Set default contrast
|
||||||
display_setContrast(default_settings.contrast);
|
display_setContrast(state.settings.contrast);
|
||||||
|
|
||||||
// Initialize user interface
|
// Initialize user interface
|
||||||
ui_init();
|
ui_init();
|
||||||
|
|
@ -63,7 +66,7 @@ int main(void)
|
||||||
|
|
||||||
// Wait 30ms before turning on backlight to hide random pixels on screen
|
// Wait 30ms before turning on backlight to hide random pixels on screen
|
||||||
sleepFor(0u, 30u);
|
sleepFor(0u, 30u);
|
||||||
platform_setBacklightLevel(255);
|
platform_setBacklightLevel(state.settings.brightness);
|
||||||
|
|
||||||
// Keep the splash screen for 1 second
|
// Keep the splash screen for 1 second
|
||||||
sleepFor(1u, 0u);
|
sleepFor(1u, 0u);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ void state_init()
|
||||||
* Try loading settings from nonvolatile memory and default to sane values
|
* Try loading settings from nonvolatile memory and default to sane values
|
||||||
* in case of failure.
|
* in case of failure.
|
||||||
*/
|
*/
|
||||||
if(nvm_readSettings(&state.settings) != 0)
|
if(nvm_readSettings(&state.settings) < 0)
|
||||||
{
|
{
|
||||||
state.settings = default_settings;
|
state.settings = default_settings;
|
||||||
strncpy(state.settings.callsign, "OPNRTX", 10);
|
strncpy(state.settings.callsign, "OPNRTX", 10);
|
||||||
|
|
@ -44,7 +44,7 @@ void state_init()
|
||||||
* Try loading VFO configuration from nonvolatile memory and default to sane
|
* Try loading VFO configuration from nonvolatile memory and default to sane
|
||||||
* values in case of failure.
|
* values in case of failure.
|
||||||
*/
|
*/
|
||||||
if(nvm_readVFOChannelData(&state.channel) != 0)
|
if(nvm_readVFOChannelData(&state.channel) < 0)
|
||||||
{
|
{
|
||||||
state.channel.mode = FM;
|
state.channel.mode = FM;
|
||||||
state.channel.bandwidth = BW_25;
|
state.channel.bandwidth = BW_25;
|
||||||
|
|
|
||||||
|
|
@ -327,9 +327,6 @@ void create_threads()
|
||||||
// Create UI event queue
|
// Create UI event queue
|
||||||
queue_init(&ui_queue);
|
queue_init(&ui_queue);
|
||||||
|
|
||||||
// State initialization, execute before starting all tasks
|
|
||||||
state_init();
|
|
||||||
|
|
||||||
// Create rtx radio thread
|
// Create rtx radio thread
|
||||||
pthread_t rtx_thread;
|
pthread_t rtx_thread;
|
||||||
pthread_attr_t rtx_attr;
|
pthread_attr_t rtx_attr;
|
||||||
|
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2021 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 <http://www.gnu.org/licenses/> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#include "mcuFlash.h"
|
|
||||||
|
|
||||||
inline bool unlock()
|
|
||||||
{
|
|
||||||
// Flash already unlocked
|
|
||||||
if((FLASH->CR & FLASH_CR_LOCK) == 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
FLASH->KEYR = 0x45670123;
|
|
||||||
FLASH->KEYR = 0xCDEF89AB;
|
|
||||||
|
|
||||||
// Succesful unlock
|
|
||||||
if((FLASH->CR & FLASH_CR_LOCK) == 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mcuFlash_eraseSector(const uint8_t secNum)
|
|
||||||
{
|
|
||||||
if(secNum > 11) return false;
|
|
||||||
if(unlock() == false) return false;
|
|
||||||
|
|
||||||
// Flash busy, wait until previous operation finishes
|
|
||||||
while((FLASH->SR & FLASH_SR_BSY) != 0) ;
|
|
||||||
|
|
||||||
FLASH->CR |= FLASH_CR_PSIZE_1 // 32-bit program parallelism
|
|
||||||
| (secNum << 3) // Sector number
|
|
||||||
| FLASH_CR_SER // Sector erase
|
|
||||||
| FLASH_CR_STRT; // Start erase
|
|
||||||
|
|
||||||
// Wait until erase ends
|
|
||||||
while((FLASH->SR & FLASH_SR_BSY) != 0) ;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mcuFlash_write(const uint32_t address, const void *data, const size_t len)
|
|
||||||
{
|
|
||||||
if((data == NULL) || (len == 0)) return;
|
|
||||||
|
|
||||||
// Flash busy, wait until previous operation finishes
|
|
||||||
while((FLASH->SR & FLASH_SR_BSY) != 0) ;
|
|
||||||
|
|
||||||
// Request programming with 8-bit parallelism
|
|
||||||
FLASH->CR = FLASH_CR_PG;
|
|
||||||
|
|
||||||
const uint8_t *buf = ((uint8_t *) data);
|
|
||||||
const uint8_t *mem = ((uint8_t *) address);
|
|
||||||
for(size_t i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
*mem = buf[i];
|
|
||||||
mem++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait until the end of the write operation
|
|
||||||
while((FLASH->SR & FLASH_SR_BSY) != 0) ;
|
|
||||||
}
|
|
||||||
|
|
@ -21,18 +21,112 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <interfaces/nvmem.h>
|
#include <interfaces/nvmem.h>
|
||||||
#include <cps.h>
|
#include <cps.h>
|
||||||
|
#include "flash.h"
|
||||||
|
|
||||||
int nvm_readSettings(settings_t *settings)
|
|
||||||
|
typedef struct
|
||||||
{
|
{
|
||||||
return -1;
|
uint32_t magic;
|
||||||
|
uint32_t flags[64];
|
||||||
|
struct dataBlock
|
||||||
|
{
|
||||||
|
settings_t settings;
|
||||||
|
channel_t vfoData;
|
||||||
|
}
|
||||||
|
data[2048];
|
||||||
}
|
}
|
||||||
|
__attribute__((packed)) memory_t;
|
||||||
|
|
||||||
|
static const uint32_t validMagic = 0x5854524F; // "ORTX"
|
||||||
|
static const uint32_t baseAddress = 0x080E0000;
|
||||||
|
memory_t *memory = ((memory_t *) baseAddress);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \internal
|
||||||
|
* Utility function to find the currently active data block inside memory, that
|
||||||
|
* is the one containing the last saved settings.
|
||||||
|
*
|
||||||
|
* @return number currently active data block or -1 if memory data is invalid.
|
||||||
|
*/
|
||||||
|
int findActiveBlock()
|
||||||
|
{
|
||||||
|
if(memory->magic != validMagic) return -1;
|
||||||
|
|
||||||
|
uint16_t block = 0;
|
||||||
|
for(; block < 64; block++)
|
||||||
|
{
|
||||||
|
if(memory->flags[block] != 0x00000000)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t bit = 0;
|
||||||
|
for(; bit < 32; bit++)
|
||||||
|
{
|
||||||
|
if((memory->flags[block] & (1 << bit)) != 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
block = (block * 32) + bit;
|
||||||
|
return block - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int nvm_readVFOChannelData(channel_t *channel)
|
int nvm_readVFOChannelData(channel_t *channel)
|
||||||
{
|
{
|
||||||
return -1;
|
int block = findActiveBlock();
|
||||||
|
if(block < 0) return -1;
|
||||||
|
memcpy(channel, &(memory->data[block].vfoData), sizeof(channel_t));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nvm_readSettings(settings_t *settings)
|
||||||
|
{
|
||||||
|
int block = findActiveBlock();
|
||||||
|
if(block < 0) return -1;
|
||||||
|
memcpy(settings, &(memory->data[block].settings), sizeof(settings_t));
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nvm_writeSettingsAndVfo(const settings_t *settings, const channel_t *vfo)
|
int nvm_writeSettingsAndVfo(const settings_t *settings, const channel_t *vfo)
|
||||||
{
|
{
|
||||||
return -1;
|
uint32_t addr = 0;
|
||||||
|
int block = findActiveBlock();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Memory never initialised or save space finished: erase all the sector.
|
||||||
|
* On STM32F405 the settings are saved in sector 11, starting at address
|
||||||
|
* 0x08060000.
|
||||||
|
*/
|
||||||
|
if((block < 0) || (block >= 2047))
|
||||||
|
{
|
||||||
|
flash_eraseSector(11);
|
||||||
|
addr = ((uint32_t) &(memory->magic));
|
||||||
|
flash_write(addr, &validMagic, sizeof(validMagic));
|
||||||
|
block = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
block += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save settings
|
||||||
|
addr = ((uint32_t) &(memory->data[block].settings));
|
||||||
|
flash_write(addr, settings, sizeof(settings_t));
|
||||||
|
|
||||||
|
// Save VFO configuration
|
||||||
|
addr = ((uint32_t) &(memory->data[block].vfoData));
|
||||||
|
flash_write(addr, vfo, sizeof(channel_t));
|
||||||
|
|
||||||
|
// Update the flags marking used data blocks
|
||||||
|
uint32_t flag = ~(1 << (block % 32));
|
||||||
|
addr = ((uint32_t) &(memory->flags[block / 32]));
|
||||||
|
flash_write(addr, &flag, sizeof(uint32_t));
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2021 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 <http://www.gnu.org/licenses/> *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <stm32f4xx.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "flash.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \internal
|
||||||
|
* Utility function performing unlock of flash erase and write access.
|
||||||
|
*
|
||||||
|
* @true on success, false on failure.
|
||||||
|
*/
|
||||||
|
static inline bool unlock()
|
||||||
|
{
|
||||||
|
// Flash already unlocked
|
||||||
|
if((FLASH->CR & FLASH_CR_LOCK) == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLASH->KEYR = 0x45670123;
|
||||||
|
FLASH->KEYR = 0xCDEF89AB;
|
||||||
|
|
||||||
|
// Succesful unlock
|
||||||
|
if((FLASH->CR & FLASH_CR_LOCK) == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool flash_eraseSector(const uint8_t secNum)
|
||||||
|
{
|
||||||
|
if(secNum > 11) return false;
|
||||||
|
if(unlock() == false) return false;
|
||||||
|
|
||||||
|
// Flash busy, wait until previous operation finishes
|
||||||
|
while((FLASH->SR & FLASH_SR_BSY) != 0) ;
|
||||||
|
|
||||||
|
FLASH->CR |= FLASH_CR_PSIZE_1 // 32-bit program parallelism
|
||||||
|
| (secNum << 3) // Sector number
|
||||||
|
| FLASH_CR_SER // Sector erase
|
||||||
|
| FLASH_CR_STRT; // Start erase
|
||||||
|
|
||||||
|
// Wait until erase ends
|
||||||
|
while((FLASH->SR & FLASH_SR_BSY) != 0) ;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void flash_write(const uint32_t address, const void *data, const size_t len)
|
||||||
|
{
|
||||||
|
if(unlock() == false) return;
|
||||||
|
if((data == NULL) || (len == 0)) return;
|
||||||
|
|
||||||
|
// Flash busy, wait until previous operation finishes
|
||||||
|
while((FLASH->SR & FLASH_SR_BSY) != 0) ;
|
||||||
|
|
||||||
|
// Request programming with 8-bit parallelism
|
||||||
|
FLASH->CR = FLASH_CR_PG;
|
||||||
|
|
||||||
|
// Write data to memory
|
||||||
|
const uint8_t *buf = ((uint8_t *) data);
|
||||||
|
uint8_t *mem = ((uint8_t *) address);
|
||||||
|
for(size_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
*mem = buf[i];
|
||||||
|
mem++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until the end of the write operation
|
||||||
|
while((FLASH->SR & FLASH_SR_BSY) != 0) ;
|
||||||
|
}
|
||||||
|
|
@ -18,12 +18,16 @@
|
||||||
* along with this program; if not, see <http://www.gnu.org/licenses/> *
|
* along with this program; if not, see <http://www.gnu.org/licenses/> *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#ifndef MCUFLASH_H
|
#ifndef FLASH_H
|
||||||
#define MCUFLASH_H
|
#define FLASH_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Driver for MCU's internal flash management, allowing for sector erase and data
|
* Driver for MCU's internal flash management, allowing for sector erase and data
|
||||||
* writing.
|
* writing.
|
||||||
|
|
@ -35,7 +39,7 @@
|
||||||
* @param secNum: sector number.
|
* @param secNum: sector number.
|
||||||
* @return true for successful erase, false otherwise.
|
* @return true for successful erase, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool mcuFlash_eraseSector(const uint8_t secNum);
|
bool flash_eraseSector(const uint8_t secNum);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write data to the MCU flash memory.
|
* Write data to the MCU flash memory.
|
||||||
|
|
@ -44,6 +48,10 @@ bool mcuFlash_eraseSector(const uint8_t secNum);
|
||||||
* @param data: data to be written.
|
* @param data: data to be written.
|
||||||
* @param len: data length.
|
* @param len: data length.
|
||||||
*/
|
*/
|
||||||
void mcuFlash_write(const uint32_t address, const void *data, const size_t len);
|
void flash_write(const uint32_t address, const void *data, const size_t len);
|
||||||
|
|
||||||
#endif /* MCUFLASH_H */
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* FLASH_H */
|
||||||
|
|
@ -59,7 +59,8 @@ ENTRY(_Z13Reset_Handlerv)
|
||||||
/* specify the memory areas */
|
/* specify the memory areas */
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
flash(rx) : ORIGIN = 0x0800C000, LENGTH = 1M - 48K
|
/* Reserve space for bootloader and settings */
|
||||||
|
flash(rx) : ORIGIN = 0x0800C000, LENGTH = 1M - 48K - 128K
|
||||||
/*
|
/*
|
||||||
* Note, the small ram starts at 0x10000000 but it is necessary to add the
|
* Note, the small ram starts at 0x10000000 but it is necessary to add the
|
||||||
* size of the main stack, so it is 0x10000200.
|
* size of the main stack, so it is 0x10000200.
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,6 @@ void platform_init()
|
||||||
gpio_setMode(GREEN_LED, OUTPUT);
|
gpio_setMode(GREEN_LED, OUTPUT);
|
||||||
gpio_setMode(RED_LED, OUTPUT);
|
gpio_setMode(RED_LED, OUTPUT);
|
||||||
|
|
||||||
gpio_setMode(LCD_BKLIGHT, ALTERNATE);
|
|
||||||
gpio_setAlternateFunction(LCD_BKLIGHT, 3);
|
|
||||||
|
|
||||||
gpio_setMode(CH_SELECTOR_0, INPUT);
|
gpio_setMode(CH_SELECTOR_0, INPUT);
|
||||||
gpio_setMode(CH_SELECTOR_1, INPUT);
|
gpio_setMode(CH_SELECTOR_1, INPUT);
|
||||||
gpio_setMode(CH_SELECTOR_2, INPUT);
|
gpio_setMode(CH_SELECTOR_2, INPUT);
|
||||||
|
|
@ -50,6 +47,7 @@ void platform_init()
|
||||||
gpio_setMode(PTT_EXT, INPUT);
|
gpio_setMode(PTT_EXT, INPUT);
|
||||||
|
|
||||||
gpio_setMode(PWR_SW, OUTPUT);
|
gpio_setMode(PWR_SW, OUTPUT);
|
||||||
|
gpio_setPin(PWR_SW);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialise ADC1, for vbat, RSSI, ...
|
* Initialise ADC1, for vbat, RSSI, ...
|
||||||
|
|
@ -146,7 +144,7 @@ bool platform_pwrButtonStatus()
|
||||||
* is always a bit of noise in the ADC measurement making the returned
|
* is always a bit of noise in the ADC measurement making the returned
|
||||||
* voltage not to be exactly zero.
|
* voltage not to be exactly zero.
|
||||||
*/
|
*/
|
||||||
return (platform_getVbat() > 1.0f) ? true : false;
|
return (platform_getVbat() > 1000) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void platform_ledOn(led_t led)
|
void platform_ledOn(led_t led)
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,9 @@ void platform_init()
|
||||||
gpio_setMode(PTT_SW, INPUT_PULL_UP);
|
gpio_setMode(PTT_SW, INPUT_PULL_UP);
|
||||||
gpio_setMode(PTT_EXT, INPUT_PULL_UP);
|
gpio_setMode(PTT_EXT, INPUT_PULL_UP);
|
||||||
|
|
||||||
|
gpio_setMode(PWR_SW, OUTPUT);
|
||||||
|
gpio_setPin(PWR_SW);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialise ADC1, for vbat, RSSI, ...
|
* Initialise ADC1, for vbat, RSSI, ...
|
||||||
* Configuration of corresponding GPIOs in analog input mode is done inside
|
* Configuration of corresponding GPIOs in analog input mode is done inside
|
||||||
|
|
@ -141,7 +144,7 @@ bool platform_pwrButtonStatus()
|
||||||
* is always a bit of noise in the ADC measurement making the returned
|
* is always a bit of noise in the ADC measurement making the returned
|
||||||
* voltage not to be exactly zero.
|
* voltage not to be exactly zero.
|
||||||
*/
|
*/
|
||||||
return (platform_getVbat() > 1.0f) ? true : false;
|
return (platform_getVbat() > 1000) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void platform_ledOn(led_t led)
|
void platform_ledOn(led_t led)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue