From 47d6313ba1d9c177814651c656afceddde73fab0 Mon Sep 17 00:00:00 2001 From: Winfred LIN Date: Fri, 3 Apr 2020 18:21:16 +1100 Subject: [PATCH 1/2] added reading flash functions for stm32l0xx series 1. implemented HAL_StatusTypeDef HAL_FLASH_ReadWord(uint32_t Address, uint32_t* Data); and HAL_StatusTypeDef HAL_FLASH_ReadHalfWord(uint32_t Address, uint16_t* Data); which allows user to read the internal FLASH (with out read protection) 2. implemeted device_config struct to store device configurations, e.g. magnetometer fullscale, report period, etc. 3. added demonstration code of using flash reading apis in lora_demo.c, in which the configuration sent from the cloud is stored into the internal Data EEPROM bank1, and each time when the device is booted, the configurations would be loaded from the Data EEPROM and used to initialize the application. --- .../BSP/HardWare/Common/bsp.c | 5 +- .../BSP/HardWare/Common/bsp.h | 54 +++---- board/NUCLEO_STM32L073RZ/BSP/Src/lora_demo.c | 149 ++++++++++++++++-- .../IAR/lorawan/TencentOS_tiny.ewp | 15 +- .../IAR/lorawan/TencentOS_tiny.ewt | 15 +- examples/LoRaWAN/lora_demo.h | 7 +- .../Inc/stm32l0xx_hal_flash_ex2.h | 43 +++++ .../Src/stm32l0xx_hal_flash_ex2.c | 89 +++++++++++ 8 files changed, 313 insertions(+), 64 deletions(-) create mode 100644 platform/vendor_bsp/st/STM32L0xx_HAL_Driver/Inc/stm32l0xx_hal_flash_ex2.h create mode 100644 platform/vendor_bsp/st/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_flash_ex2.c diff --git a/board/NUCLEO_STM32L073RZ/BSP/HardWare/Common/bsp.c b/board/NUCLEO_STM32L073RZ/BSP/HardWare/Common/bsp.c index 57f6df9c..facb7837 100644 --- a/board/NUCLEO_STM32L073RZ/BSP/HardWare/Common/bsp.c +++ b/board/NUCLEO_STM32L073RZ/BSP/HardWare/Common/bsp.c @@ -3,19 +3,20 @@ * @file bsp.c * @author jieranzhi * @brief provide high level interfaces to manage the sensors on the - * application, this is a modified version of the official api + * application ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "bsp.h" -void BSP_Sensor_Init(void) +void BSP_Sensor_Init(DeviceConfig_TypeDef config) { /* Initialize sensors */ HTS221_Init(); LPS22HB_Init(); LIS3MDL_Init(); + LIS3MDL_Set_FullScale((LIS3MDL_FullScaleTypeDef)config.magn_fullscale); } void BSP_Sensor_Read(sensor_data_t *sensor_data) diff --git a/board/NUCLEO_STM32L073RZ/BSP/HardWare/Common/bsp.h b/board/NUCLEO_STM32L073RZ/BSP/HardWare/Common/bsp.h index c9f515ae..6ed73014 100644 --- a/board/NUCLEO_STM32L073RZ/BSP/HardWare/Common/bsp.h +++ b/board/NUCLEO_STM32L073RZ/BSP/HardWare/Common/bsp.h @@ -1,33 +1,9 @@ -/* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2013 Semtech - -Description: contains all hardware driver - -License: Revised BSD License, see LICENSE.TXT file include in the project - -Maintainer: Miguel Luis and Gregory Cristian -*/ /** ****************************************************************************** - * @file bsp.h - * @author MCD Application Team - * @brief contains all hardware driver - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2018 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * + * @file bsp.c + * @author jieranzhi + * @brief provide high level interfaces to manage the sensors on the + * application, this is a modified version of the official api ****************************************************************************** */ @@ -40,6 +16,7 @@ extern "C" { #endif /* Includes ------------------------------------------------------------------*/ #include +#include #include "HTS221.h" #include "LPS22HB.h" #include "LIS3MDL.h" @@ -61,6 +38,25 @@ typedef struct } sensor_data_t; + // application configuration types + typedef enum{ + DCT_IS_CONFIRM = 0x00U, + DCT_REPORT_PERIOD = 0x01U, + DCT_REPEAT_TIME = 0x02U, + DCT_MAGN_FULLSCALE = 0x03U, + DCT_DEFAULT = 0xFFU, + }DeviceConfigType_TypeDef; + +// application configuration +typedef struct +{ + uint32_t config_address; + uint16_t report_period; + uint8_t repeat_time; + LIS3MDL_FullScaleTypeDef magn_fullscale; + bool is_confirmed; +}DeviceConfig_TypeDef; + /* Exported constants --------------------------------------------------------*/ /* External variables --------------------------------------------------------*/ /* Exported macros -----------------------------------------------------------*/ @@ -71,7 +67,7 @@ typedef struct * @note * @retval None */ -void BSP_Sensor_Init(void); +void BSP_Sensor_Init(DeviceConfig_TypeDef config); /** * @brief sensor read. diff --git a/board/NUCLEO_STM32L073RZ/BSP/Src/lora_demo.c b/board/NUCLEO_STM32L073RZ/BSP/Src/lora_demo.c index 35583663..76d00d1a 100644 --- a/board/NUCLEO_STM32L073RZ/BSP/Src/lora_demo.c +++ b/board/NUCLEO_STM32L073RZ/BSP/Src/lora_demo.c @@ -1,7 +1,7 @@ #include "lora_demo.h" +#include "stm32l0xx_hal_flash_ex2.h" #include "RHF76.h" #include "bsp.h" -#include #include /* @@ -118,9 +118,6 @@ */ -uint16_t report_period = 10; -bool is_confirmed = true; - typedef struct device_data_st { uint8_t magn_fullscale; // fullscale of magnetometer(RW) uint8_t temp_sensitivity; // temperature sensitivity (R) @@ -145,6 +142,118 @@ typedef struct device_data_wrapper_st { dev_data_wrapper_t dev_data_wrapper; +DeviceConfig_TypeDef device_config; + +void set_config_to_default(DeviceConfig_TypeDef* config) +{ + config->config_address = 0x08080000U; + config->is_confirmed = true; + config->report_period = 10; + config->magn_fullscale = FULLSCALE_4; +} + +/** + * @brief Write the configuration to the internal EEPROM bank 1 + * @note a single config frame is of 32-bit(a word, 4bytes), and the config + * block starts with a frame whose value is 0x464E4F43U ('CONF' from + * low to high) and ends with a frame with a value of 0xFFFFFFFFU; a + * single data frame has a following structure£º + * ---------------------------------------------------------------- + * | byte | 0 | 1 | 2 | 3 | + * ---------------------------------------------------------------- + * | value| Device Config Type | value-L | value-H | reserve | + * ---------------------------------------------------------------- + * the reserve byte could be used as an extra byte for the config + * value, i.e. a 24-bit value. + * + * @param config system configurations + * + * @retval HAL_StatusTypeDef HAL Status + */ +HAL_StatusTypeDef write_config_to_Flash(DeviceConfig_TypeDef config) +{ + uint32_t frame[5] = {0}; + frame[0] = 0x464E4F43U; // <'C'><'O'><'N'><'F'> from low to high + frame[1] = (uint32_t)config.is_confirmed<<8 | (uint32_t)DCT_IS_CONFIRM; + frame[2] = (uint32_t)config.report_period<<8 | (uint32_t)DCT_REPORT_PERIOD; + frame[3] = (uint32_t)config.repeat_time<<8 | (uint32_t)DCT_REPEAT_TIME; + frame[4] = 0xFFFFFFFFU; + + HAL_FLASH_Unlock(); + uint8_t retry = 10; + + HAL_StatusTypeDef status = HAL_OK; + for(int i=0; i<5; i++) + { + status = HAL_OK; + do{ + status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, config.config_address+4*i, frame[i]); + }while(retry--!=0 && status != HAL_OK); + } + HAL_FLASH_Lock(); + + return status; +} + +HAL_StatusTypeDef read_config_from_Flash(DeviceConfig_TypeDef* config) +{ + uint32_t data = 0; + HAL_StatusTypeDef status = HAL_FLASH_ReadWord(config->config_address, &data); + if(status == HAL_OK) + { + // a valid config starts with <'C'><'O'><'N'><'F'> and ended with a word of 0xFFFFFFFF + if((char)(data&0xFF) == 'C' + &&(char)(data>>8&0xFF) == 'O' + &&(char)(data>>16&0xFF) == 'N' + &&(char)(data>>24&0xFF) == 'F') + { + int i = 0; + int retry = 10; + DeviceConfigType_TypeDef config_type = DCT_DEFAULT; + while(data!=0xFFFFFFFF) + { + i+=4; + status = HAL_FLASH_ReadWord(config->config_address+i, &data); + if(status != HAL_OK){ + retry--; + i-=4; + if(retry == 0) break; + }else{ + config_type = (DeviceConfigType_TypeDef)(data&0xFF); + switch(config_type) + { + case DCT_IS_CONFIRM: + { + config->is_confirmed = (bool)(data>>8&0xFF); + break; + } + case DCT_REPORT_PERIOD: + { + config->report_period = (uint16_t)(data>>8&0xFFFF); + break; + } + case DCT_REPEAT_TIME: + { + config->repeat_time = (uint8_t)(data>>8&0xFF); + break; + } + case DCT_MAGN_FULLSCALE: + { + config->magn_fullscale = (LIS3MDL_FullScaleTypeDef)(data>>8&0xFF); + break; + } + default: + { + break; + } + } + } + } + } + } + return status; +} + void recv_callback(uint8_t *data, uint8_t len) { printf("len: %d\n", len); @@ -154,11 +263,13 @@ void recv_callback(uint8_t *data, uint8_t len) } if (len == 1) { - report_period = data[0]; + device_config.report_period = data[0]; } else if (len >= 2) { - report_period = data[0] | (data[1] << 8); - LIS3MDL_Set_FullScale((LIS3MDL_FullScaleTypeDef)data[2]); - is_confirmed = (bool)data[3]; + device_config.is_confirmed = (bool)data[3]; + device_config.report_period = data[0] | (data[1] << 8); + device_config.magn_fullscale = (LIS3MDL_FullScaleTypeDef)data[2]; + LIS3MDL_Set_FullScale(device_config.magn_fullscale); + write_config_to_Flash(device_config); } } @@ -181,15 +292,22 @@ void print_to_screen(sensor_data_t sensor_data) */ void application_entry(void *arg) { + // retrieve configuration from the EEPROM (if any) + set_config_to_default(&device_config); + HAL_StatusTypeDef status = read_config_from_Flash(&device_config); + if(status != HAL_OK) + { + printf("retrieve configuration FAILED!\r\n"); + } + + // initialization sensor_data_t sensor_data; - - // initialization of sensors - BSP_Sensor_Init(); - + BSP_Sensor_Init(device_config); rhf76_lora_init(HAL_UART_PORT_1); tos_lora_module_recvcb_register(recv_callback); tos_lora_module_join_otaa("8cf957200000f52c", "8cf957200000f52c6d09aaaaad204a72"); + // do the job while (1) { BSP_Sensor_Read(&sensor_data); print_to_screen(sensor_data); @@ -205,15 +323,14 @@ void application_entry(void *arg) dev_data_wrapper.u.dev_data.magn_y = (int16_t)(sensor_data.sensor_magn.magn_y); dev_data_wrapper.u.dev_data.magn_z = (int16_t)(sensor_data.sensor_magn.magn_z); dev_data_wrapper.u.dev_data.pressure = (uint32_t)(sensor_data.sensor_press.pressure); - dev_data_wrapper.u.dev_data.period = report_period; + dev_data_wrapper.u.dev_data.period = device_config.report_period; // send data to the server (via gateway) - if(is_confirmed){ + if(device_config.is_confirmed){ tos_lora_module_send(dev_data_wrapper.u.serialize, sizeof(dev_data_t)); }else{ tos_lora_module_send_unconfirmed(dev_data_wrapper.u.serialize, sizeof(dev_data_t)); } - - tos_task_delay(report_period * 1000); + tos_task_delay(device_config.report_period * 1000); } } diff --git a/board/NUCLEO_STM32L073RZ/IAR/lorawan/TencentOS_tiny.ewp b/board/NUCLEO_STM32L073RZ/IAR/lorawan/TencentOS_tiny.ewp index ce06297d..84a1b288 100644 --- a/board/NUCLEO_STM32L073RZ/IAR/lorawan/TencentOS_tiny.ewp +++ b/board/NUCLEO_STM32L073RZ/IAR/lorawan/TencentOS_tiny.ewp @@ -1123,14 +1123,14 @@ $PROJ_DIR$\..\..\..\..\devices\rhf76_lora\RHF76.c - - Drivers/CMSIS - - $PROJ_DIR$\..\..\BSP\Src\system_stm32l0xx.c - - Drivers/STM32L0xx_HAL_Driver + + Drivers/CMSIS + + $PROJ_DIR$\..\..\BSP\Src\system_stm32l0xx.c + + $PROJ_DIR$\..\..\..\..\platform\vendor_bsp\st\STM32L0xx_HAL_Driver\Src\stm32l0xx_hal.c @@ -1146,6 +1146,9 @@ $PROJ_DIR$\..\..\..\..\platform\vendor_bsp\st\STM32L0xx_HAL_Driver\Src\stm32l0xx_hal_flash_ex.c + + $PROJ_DIR$\..\..\..\..\platform\vendor_bsp\st\STM32L0xx_HAL_Driver\Src\stm32l0xx_hal_flash_ex2.c + $PROJ_DIR$\..\..\..\..\platform\vendor_bsp\st\STM32L0xx_HAL_Driver\Src\stm32l0xx_hal_flash_ramfunc.c diff --git a/board/NUCLEO_STM32L073RZ/IAR/lorawan/TencentOS_tiny.ewt b/board/NUCLEO_STM32L073RZ/IAR/lorawan/TencentOS_tiny.ewt index 4267415e..b3317fc0 100644 --- a/board/NUCLEO_STM32L073RZ/IAR/lorawan/TencentOS_tiny.ewt +++ b/board/NUCLEO_STM32L073RZ/IAR/lorawan/TencentOS_tiny.ewt @@ -1257,14 +1257,14 @@ $PROJ_DIR$\..\..\..\..\devices\rhf76_lora\RHF76.c - - Drivers/CMSIS - - $PROJ_DIR$\..\..\BSP\Src\system_stm32l0xx.c - - Drivers/STM32L0xx_HAL_Driver + + Drivers/CMSIS + + $PROJ_DIR$\..\..\BSP\Src\system_stm32l0xx.c + + $PROJ_DIR$\..\..\..\..\platform\vendor_bsp\st\STM32L0xx_HAL_Driver\Src\stm32l0xx_hal.c @@ -1280,6 +1280,9 @@ $PROJ_DIR$\..\..\..\..\platform\vendor_bsp\st\STM32L0xx_HAL_Driver\Src\stm32l0xx_hal_flash_ex.c + + $PROJ_DIR$\..\..\..\..\platform\vendor_bsp\st\STM32L0xx_HAL_Driver\Src\stm32l0xx_hal_flash_ex2.c + $PROJ_DIR$\..\..\..\..\platform\vendor_bsp\st\STM32L0xx_HAL_Driver\Src\stm32l0xx_hal_flash_ramfunc.c diff --git a/examples/LoRaWAN/lora_demo.h b/examples/LoRaWAN/lora_demo.h index f6222c8e..9455bd6a 100644 --- a/examples/LoRaWAN/lora_demo.h +++ b/examples/LoRaWAN/lora_demo.h @@ -1,20 +1,17 @@ #ifndef __APP_DEMO_H__ #define __APP_DEMO_H__ +#include #include "mcu_init.h" #include "tos_at.h" #include "string.h" #include "cmsis_os.h" #include "lora_module_wrapper.h" + #ifdef __cplusplus extern "C" { #endif -typedef struct -{ - char data[32]; -}ReportData_TypeDef; - void application_entry(void *arg); #ifdef __cplusplus } diff --git a/platform/vendor_bsp/st/STM32L0xx_HAL_Driver/Inc/stm32l0xx_hal_flash_ex2.h b/platform/vendor_bsp/st/STM32L0xx_HAL_Driver/Inc/stm32l0xx_hal_flash_ex2.h new file mode 100644 index 00000000..9641f2a8 --- /dev/null +++ b/platform/vendor_bsp/st/STM32L0xx_HAL_Driver/Inc/stm32l0xx_hal_flash_ex2.h @@ -0,0 +1,43 @@ +/** + ****************************************************************************** + * @file stm32l0xx_hal_flash_ex2.h + * @author jieranzhi + * @date 2020/04/02 14:59 CST + * @brief Header file of Flash EEPROM. + ****************************************************************************** + * @attention + * + * this file implementes FLASH read operations for stm32l0xx series(category 5 + * devices), to implement a morefunctions, please refer to RM0367, which could + * be downloaded from: + * https://www.st.com/resource/en/reference_manual/dm00095744-ultra-low-power- + * stm32l0x3-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32L0xx_HAL_FLASH_EX2_H +#define __STM32L0xx_HAL_FLASH_EX2_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32l0xx_hal.h" + +/* Include FLASH HAL Extended module */ +#include "stm32l0xx_hal_flash_ex.h" +#include "stm32l0xx_hal_flash_ramfunc.h" + +/* Exported functions --------------------------------------------------------*/ +void HAL_FLASH_Prepare_Reading(uint8_t WaitState); +HAL_StatusTypeDef HAL_FLASH_ReadWord(uint32_t Address, uint32_t* Data); +HAL_StatusTypeDef HAL_FLASH_ReadHalfWord(uint32_t Address, uint16_t* Data); + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32L0xx_HAL_FLASH_EX2_H */ \ No newline at end of file diff --git a/platform/vendor_bsp/st/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_flash_ex2.c b/platform/vendor_bsp/st/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_flash_ex2.c new file mode 100644 index 00000000..2a341d3d --- /dev/null +++ b/platform/vendor_bsp/st/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_flash_ex2.c @@ -0,0 +1,89 @@ +/** + ****************************************************************************** + * @file stm32l0xx_hal_flash_eeprom.c + * @author jieranzhi + * @date 2020/04/02 14:59 CST + * @brief implementation of Flash EEPROM operations. + ****************************************************************************** + * @attention + * + * this file implementes FLASH read operations for stm32l0xx series(category 5 + * devices), to implement a morefunctions, please refer to RM0367, which could + * be downloaded from: + * https://www.st.com/resource/en/reference_manual/dm00095744-ultra-low-power- + * stm32l0x3-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf + ****************************************************************************** + */ + +#include "stm32l0xx_hal_flash_ex2.h" + +/** + * @brief set the correct number of wait states, and set the clock of the memory + interface + * @note The user must set the correct number of wait states (LATENCY bit in + * the FLASH_ACR register). No control is done to verify if the frequency + * or the power used is correct, with respect to the number of wait + * states. A wrong number of wait states can generate wrong read values + * (high frequency and 0 wait states) or a long time to execute a code + * (low frequency with 1 wait state). + * @param correct number of wait states + */ +void HAL_FLASH_Prepare_Reading(uint8_t WaitState) +{ + __HAL_RCC_MIF_CLK_ENABLE(); + __HAL_FLASH_SET_LATENCY(WaitState); +} + +/** + * @brief Read word (4 bytes) from a specified address + * @note To correctly run this function, the HAL_FLASH_Prepare_Reading(...) + * function must be called before. + * + * @param Address Specifie the address to be read from. + * @param Data Specifie the data to store the + * + * @retval HAL_StatusTypeDef HAL Status + */ +HAL_StatusTypeDef HAL_FLASH_ReadWord(uint32_t Address, uint32_t* Data) +{ + HAL_StatusTypeDef status = HAL_ERROR; + + /* Check the parameters */ + assert_param(IS_FLASH_PROGRAM_ADDRESS(Address)||IS_FLASH_DATA_ADDRESS(Address)); + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE); + + if(status == HAL_OK) + { + *Data = *(__IO uint32_t*)Address; + } + return status; +} + +/** + * @brief Read half-word (2 bytes) from a specified address + * @note To correctly run this function, the HAL_FLASH_Prepare_Reading(...) + * function must be called before. + * + * @param Address Specifie the address to be read from. + * @param Data Specifie the data to store the + * + * @retval HAL_StatusTypeDef HAL Status + */ +HAL_StatusTypeDef HAL_FLASH_ReadHalfWord(uint32_t Address, uint16_t* Data) +{ + HAL_StatusTypeDef status = HAL_ERROR; + + /* Check the parameters */ + assert_param(IS_FLASH_PROGRAM_ADDRESS(Address)||IS_FLASH_DATA_ADDRESS(Address)); + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE); + + if(status == HAL_OK) + { + *Data = *(__IO uint16_t*)Address; + } + return status; +} \ No newline at end of file From b6cb7147ccc8bc7062b0c5837a3b3691d64427ab Mon Sep 17 00:00:00 2001 From: Winfred LIN Date: Mon, 6 Apr 2020 23:11:48 +1000 Subject: [PATCH 2/2] added fuzzy matching feature to at_echo; added set some AT+ commands for RHF76; added support for LSM6DS3; 1. in tos_at.h, added int fuzzy_matching; field into at_echo_st struct, if this field is set to K_TRUE, then if echo message contains the string in "echo_expect" field. 2. added __API__ int tos_at_echo_fuzzy_matching_create(at_echo_t *echo, char *buffer, size_t buffer_size, char *echo_expect_contains) api to tos_at.c, which will create an at_echo_t with fuzzy_matching = K_TRUE; 3. added RHF76_ATCMD_SET_DELAY and rhf76_set_delay to RHF76.h to allow set/query RX delay config 4. added RHF76_ATCMD_SET_DATA_RATE and rhf76_set_data_rate to RHF76.h to allow set/query date rate config 5. added rhf76_at_cmd_exe for DEBUG purpose, so that user can execute any AT+ commands they want 6. added code in lora_demo.c to demonstrate package segmentation. --- .../BSP/HardWare/Common/bsp.c | 3 + .../BSP/HardWare/Common/bsp.h | 37 +- .../BSP/HardWare/LIS3MDL/LIS3MDL.c | 8 +- .../BSP/HardWare/LIS3MDL/LIS3MDL.h | 8 +- .../BSP/HardWare/LPS22HB/LPS22HB.h | 2 +- .../BSP/HardWare/LSM6DS3/LSM6DS3.c | 359 +++++++ .../BSP/HardWare/LSM6DS3/LSM6DS3.h | 130 +++ board/NUCLEO_STM32L073RZ/BSP/Src/lora_demo.c | 111 ++- .../IAR/lorawan/TencentOS_tiny.ewp | 7 + .../IAR/lorawan/TencentOS_tiny.ewt | 6 + devices/rhf76_lora/RHF76.c | 79 +- devices/rhf76_lora/RHF76.h | 63 ++ net/at/include/tos_at.h | 936 +++++++++--------- net/at/src/tos_at.c | 31 + 14 files changed, 1258 insertions(+), 522 deletions(-) create mode 100644 board/NUCLEO_STM32L073RZ/BSP/HardWare/LSM6DS3/LSM6DS3.c create mode 100644 board/NUCLEO_STM32L073RZ/BSP/HardWare/LSM6DS3/LSM6DS3.h diff --git a/board/NUCLEO_STM32L073RZ/BSP/HardWare/Common/bsp.c b/board/NUCLEO_STM32L073RZ/BSP/HardWare/Common/bsp.c index facb7837..46840cbf 100644 --- a/board/NUCLEO_STM32L073RZ/BSP/HardWare/Common/bsp.c +++ b/board/NUCLEO_STM32L073RZ/BSP/HardWare/Common/bsp.c @@ -17,6 +17,9 @@ void BSP_Sensor_Init(DeviceConfig_TypeDef config) LPS22HB_Init(); LIS3MDL_Init(); LIS3MDL_Set_FullScale((LIS3MDL_FullScaleTypeDef)config.magn_fullscale); + LSM6DS3_Init(); + LSM6DS3_Set_Accel_FullScale((LSM6DS3_AccelFullscaleTypeDef)config.accel_fullscale); + LSM6DS3_Set_Gyro_FullScale((LSM6DS3_GyroFullscaleTypeDef)config.gyro_fullscale); } void BSP_Sensor_Read(sensor_data_t *sensor_data) diff --git a/board/NUCLEO_STM32L073RZ/BSP/HardWare/Common/bsp.h b/board/NUCLEO_STM32L073RZ/BSP/HardWare/Common/bsp.h index 6ed73014..b9c61029 100644 --- a/board/NUCLEO_STM32L073RZ/BSP/HardWare/Common/bsp.h +++ b/board/NUCLEO_STM32L073RZ/BSP/HardWare/Common/bsp.h @@ -20,6 +20,7 @@ extern "C" { #include "HTS221.h" #include "LPS22HB.h" #include "LIS3MDL.h" +#include "LSM6DS3.h" /* Exported types ------------------------------------------------------------*/ typedef struct @@ -27,35 +28,31 @@ typedef struct sensor_press_t sensor_press; /* pressure sensor */ sensor_tempnhumi_t sensor_tempnhumi; /* temperature and humidity */ sensor_magn_t sensor_magn; /* magnetometer */ - - //--------------------------- accelerator and gyroscope -------------------// - int16_t accel_x; /* in g */ - int16_t accel_y; /* in g */ - int16_t accel_z; /* in g */ - int16_t gyro_x; /* in degree/s */ - int16_t gyro_y; /* in degree/s */ - int16_t gyro_z; /* in degree/s */ - + sensor_motion_t sensor_motion; /* accelerometer, gyroscope */ } sensor_data_t; // application configuration types typedef enum{ - DCT_IS_CONFIRM = 0x00U, - DCT_REPORT_PERIOD = 0x01U, - DCT_REPEAT_TIME = 0x02U, - DCT_MAGN_FULLSCALE = 0x03U, - DCT_DEFAULT = 0xFFU, + DCT_IS_CONFIRM = 0x00U, + DCT_REPORT_PERIOD = 0x01U, + DCT_REPEAT_TIME = 0x02U, + DCT_MAGN_FULLSCALE = 0x03U, + DCT_ACCEL_FULLSCALE = 0x04U, + DCT_GYRO_FULLSCALE = 0x05U, + DCT_DEFAULT = 0xFFU, }DeviceConfigType_TypeDef; // application configuration typedef struct { - uint32_t config_address; - uint16_t report_period; - uint8_t repeat_time; - LIS3MDL_FullScaleTypeDef magn_fullscale; - bool is_confirmed; -}DeviceConfig_TypeDef; + uint32_t config_address; + uint16_t report_period; + uint8_t repeat_time; + LIS3MDL_FullScaleTypeDef magn_fullscale; + LSM6DS3_AccelFullscaleTypeDef accel_fullscale; + LSM6DS3_GyroFullscaleTypeDef gyro_fullscale; + bool is_confirmed; +}DeviceConfig_TypeDef; /* Exported constants --------------------------------------------------------*/ /* External variables --------------------------------------------------------*/ diff --git a/board/NUCLEO_STM32L073RZ/BSP/HardWare/LIS3MDL/LIS3MDL.c b/board/NUCLEO_STM32L073RZ/BSP/HardWare/LIS3MDL/LIS3MDL.c index adffac7b..f825b29e 100644 --- a/board/NUCLEO_STM32L073RZ/BSP/HardWare/LIS3MDL/LIS3MDL.c +++ b/board/NUCLEO_STM32L073RZ/BSP/HardWare/LIS3MDL/LIS3MDL.c @@ -75,19 +75,19 @@ uint16_t LIS3MDL_Get_Sensitivity(LIS3MDL_FullScaleTypeDef fullscale) uint16_t sensitivity = 1; switch(fullscale) { - case FULLSCALE_4:{ + case MAGN_FULLSCALE_4:{ sensitivity = 6842; break; } - case FULLSCALE_8:{ + case MAGN_FULLSCALE_8:{ sensitivity = 3421; break; } - case FULLSCALE_12:{ + case MAGN_FULLSCALE_12:{ sensitivity = 2281; break; } - case FULLSCALE_16:{ + case MAGN_FULLSCALE_16:{ sensitivity = 1711; break; } diff --git a/board/NUCLEO_STM32L073RZ/BSP/HardWare/LIS3MDL/LIS3MDL.h b/board/NUCLEO_STM32L073RZ/BSP/HardWare/LIS3MDL/LIS3MDL.h index f61302c6..64efcd17 100644 --- a/board/NUCLEO_STM32L073RZ/BSP/HardWare/LIS3MDL/LIS3MDL.h +++ b/board/NUCLEO_STM32L073RZ/BSP/HardWare/LIS3MDL/LIS3MDL.h @@ -65,10 +65,10 @@ typedef enum */ typedef enum { - FULLSCALE_4 = 0x00U, - FULLSCALE_8 = 0x01U, - FULLSCALE_12 = 0x02U, - FULLSCALE_16 = 0x03U + MAGN_FULLSCALE_4 = 0x00U, + MAGN_FULLSCALE_8 = 0x01U, + MAGN_FULLSCALE_12 = 0x02U, + MAGN_FULLSCALE_16 = 0x03U }LIS3MDL_FullScaleTypeDef; /** diff --git a/board/NUCLEO_STM32L073RZ/BSP/HardWare/LPS22HB/LPS22HB.h b/board/NUCLEO_STM32L073RZ/BSP/HardWare/LPS22HB/LPS22HB.h index fbb2d265..3a997295 100644 --- a/board/NUCLEO_STM32L073RZ/BSP/HardWare/LPS22HB/LPS22HB.h +++ b/board/NUCLEO_STM32L073RZ/BSP/HardWare/LPS22HB/LPS22HB.h @@ -58,7 +58,7 @@ typedef enum typedef struct { uint16_t sensitivity; // sensitivity per fullscale - uint32_t pressure; // X-magnetic value in LSB + uint32_t pressure; // pressure }sensor_press_t; /* Functions -----------------------------------------------------------------*/ diff --git a/board/NUCLEO_STM32L073RZ/BSP/HardWare/LSM6DS3/LSM6DS3.c b/board/NUCLEO_STM32L073RZ/BSP/HardWare/LSM6DS3/LSM6DS3.c new file mode 100644 index 00000000..4070363f --- /dev/null +++ b/board/NUCLEO_STM32L073RZ/BSP/HardWare/LSM6DS3/LSM6DS3.c @@ -0,0 +1,359 @@ +/** + ****************************************************************************** + * @file LSM6DS3.c + * @author jieranzhi + * @update 2020/03/23 19:00 CST + * @brief This file provides code for the LSM6DS3 Initialization + * and data output codes. + ****************************************************************************** + * @attention + * + * 1. this code is used as one of the examples in TencentOS_tiny project, it's + * just a simple implementation of the sensor functionalities, to implement + * more functions, please refer to the datasheet or the official software + * package provided by ST (STM32CubeExpansion_LRWAN_V1.3.1) + * + * 2. in this file the host MCU need to read the output persistently, which is + * not of power efficient, to achieve better power consumption performance, + * it is recommended to use FIFO. + * + ****************************************************************************** + */ + +#include +#include + +// initialization of LSM6DS3 +void LSM6DS3_Init() +{ + uint8_t cmd = 0; + + // ODR: 12.5Hz, fs: 4g, BWZ: 50Hz + cmd = 0x1B; + HAL_I2C_Mem_Write(&hi2c1, LSM6DS3_ADDR_WR, LSM6DS3_CTRL1_XL, I2C_MEMADD_SIZE_8BIT, &cmd, 1, 0xFFFF); + + // ODR: 12.5Hz, fs: 250dps + cmd = 0x10; + HAL_I2C_Mem_Write(&hi2c1, LSM6DS3_ADDR_WR, LSM6DS3_CTRL2_G, I2C_MEMADD_SIZE_8BIT, &cmd, 1, 0xFFFF); + + // High performance: disabled to save power + cmd = 0x10; + HAL_I2C_Mem_Write(&hi2c1, LSM6DS3_ADDR_WR, LSM6DS3_CTRL6_C, I2C_MEMADD_SIZE_8BIT, &cmd, 1, 0xFFFF); + + // High performance: disabled to save power + cmd = 0x80; + HAL_I2C_Mem_Write(&hi2c1, LSM6DS3_ADDR_WR, LSM6DS3_CTRL7_G, I2C_MEMADD_SIZE_8BIT, &cmd, 1, 0xFFFF); + + // timestamp output: enable, pedometer algorithm: enabled + cmd = 0xC0; + HAL_I2C_Mem_Write(&hi2c1, LSM6DS3_ADDR_WR, LSM6DS3_TAP_CFG, I2C_MEMADD_SIZE_8BIT, &cmd, 1, 0xFFFF); +} + +void LSM6DS3_Set_Accel_FullScale(LSM6DS3_AccelFullscaleTypeDef fullscale) +{ + uint8_t ctrl_reg1_value; + uint8_t fullscale_config = (uint8_t)fullscale; + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_CTRL1_XL, I2C_MEMADD_SIZE_8BIT, &ctrl_reg1_value, 1, 0xFFFF); + fullscale_config = (ctrl_reg1_value&0xF1)|(fullscale_config&0x0E); + HAL_I2C_Mem_Write(&hi2c1, LSM6DS3_ADDR_WR, LSM6DS3_CTRL1_XL, I2C_MEMADD_SIZE_8BIT, &fullscale_config, 1, 0xFFFF); +} + +void LSM6DS3_Set_Gyro_FullScale(LSM6DS3_GyroFullscaleTypeDef fullscale) +{ + uint8_t ctrl_reg2_value; + uint8_t fullscale_config = (uint8_t)fullscale; + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_CTRL2_G, I2C_MEMADD_SIZE_8BIT, &ctrl_reg2_value, 1, 0xFFFF); + fullscale_config = (ctrl_reg2_value&0xF1)|(fullscale_config&0x0E); + HAL_I2C_Mem_Write(&hi2c1, LSM6DS3_ADDR_WR, LSM6DS3_CTRL2_G, I2C_MEMADD_SIZE_8BIT, &fullscale_config, 1, 0xFFFF); +} + +void LSM6DS3_Set_Accel_FullScale_Num(uint8_t fullscale_num) +{ + LSM6DS3_AccelFullscaleTypeDef fullscale = ACCEL_FULLSCALE_2; + switch(fullscale_num) + { + case 2: + { + fullscale = ACCEL_FULLSCALE_2; + break; + } + case 16: + { + fullscale = ACCEL_FULLSCALE_16; + break; + } + case 4: + { + fullscale = ACCEL_FULLSCALE_4; + break; + } + case 8: + { + fullscale = ACCEL_FULLSCALE_8; + break; + } + default: + { + break; + } + } + LSM6DS3_Set_Accel_FullScale(fullscale); +} + +void LSM6DS3_Set_Gyro_FullScale_Num(uint8_t fullscale_num) +{ + LSM6DS3_GyroFullscaleTypeDef fullscale = GYRO_FULLSCALE_250; + switch(fullscale_num) + { + case 125: + { + fullscale = GYRO_FULLSCALE_125; + break; + } + case 250: + { + fullscale = GYRO_FULLSCALE_250; + break; + } + case 500: + { + fullscale = GYRO_FULLSCALE_500; + break; + } + case 1000: + { + fullscale = GYRO_FULLSCALE_1000; + break; + } + case 2000: + { + fullscale = GYRO_FULLSCALE_2000; + break; + } + default: + { + break; + } + } + LSM6DS3_Set_Gyro_FullScale(fullscale); +} + +uint8_t LSM6DS3_Get_Accel_FullScale_Num(LSM6DS3_AccelFullscaleTypeDef fullscale) +{ + uint8_t fullscale_num = 1; + switch(fullscale) + { + case ACCEL_FULLSCALE_2: + { + fullscale_num = 2; + break; + } + case ACCEL_FULLSCALE_16: + { + fullscale_num = 16; + break; + } + case ACCEL_FULLSCALE_4: + { + fullscale_num = 4; + break; + } + case ACCEL_FULLSCALE_8: + { + fullscale_num = 8; + break; + } + default: + { + break; + } + } + return fullscale_num; +} + +uint16_t LSM6DS3_Get_Gyro_FullScale_Num(LSM6DS3_GyroFullscaleTypeDef fullscale) +{ + uint16_t fullscale_num = 1; + switch(fullscale) + { + case GYRO_FULLSCALE_125: + { + fullscale_num = 125; + break; + } + case GYRO_FULLSCALE_250: + { + fullscale_num = 250; + break; + } + case GYRO_FULLSCALE_500: + { + fullscale_num = 500; + break; + } + case GYRO_FULLSCALE_1000: + { + fullscale_num = 1000; + break; + } + case GYRO_FULLSCALE_2000: + { + fullscale_num = 2000; + break; + } + default: + { + break; + } + } + return fullscale_num; +} + +LSM6DS3_AccelFullscaleTypeDef LSM6DS3_Get_Accel_FullScale() +{ + uint8_t fullscale; + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_CTRL1_XL, I2C_MEMADD_SIZE_8BIT, &fullscale, 1, 0xFFFF); + fullscale = (fullscale<<1)>>6; + return (LSM6DS3_AccelFullscaleTypeDef)fullscale; +} + +LSM6DS3_GyroFullscaleTypeDef LSM6DS3_Get_Gyro_FullScale() +{ + uint8_t fullscale; + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_CTRL2_G, I2C_MEMADD_SIZE_8BIT, &fullscale, 1, 0xFFFF); + fullscale = fullscale&0x02; + if(fullscale == 0x00) fullscale = fullscale&0x0C; + return (LSM6DS3_GyroFullscaleTypeDef)fullscale; +} + +uint16_t LSM6DS3_Get_Accel_Sensitivity(LSM6DS3_AccelFullscaleTypeDef fullscale) +{ + uint16_t sensitivity = 1; + switch(fullscale) + { + case ACCEL_FULLSCALE_2:{ + sensitivity = 61; + break; + } + case ACCEL_FULLSCALE_4:{ + sensitivity = 122; + break; + } + case ACCEL_FULLSCALE_8:{ + sensitivity = 244; + break; + } + case ACCEL_FULLSCALE_16:{ + sensitivity = 488; + break; + } + default:{ + sensitivity = 1; + } + } + return sensitivity; +} + +uint32_t LSM6DS3_Get_Gyro_Sensitivity(LSM6DS3_GyroFullscaleTypeDef fullscale) +{ + uint32_t sensitivity = 1; + switch(fullscale) + { + case GYRO_FULLSCALE_125:{ + sensitivity = 4375; + break; + } + case GYRO_FULLSCALE_250:{ + sensitivity = 8750; + break; + } + case GYRO_FULLSCALE_500:{ + sensitivity = 17500; + break; + } + case GYRO_FULLSCALE_1000:{ + sensitivity = 35000; + break; + } + case GYRO_FULLSCALE_2000:{ + sensitivity = 70000; + break; + } + default:{ + sensitivity = 1; + } + } + return sensitivity; +} + +uint8_t LSM6DS3_Get_Sensor_Config(sensor_motion_t* sensor_motion) +{ + LSM6DS3_AccelFullscaleTypeDef accel_fullscale = LSM6DS3_Get_Accel_FullScale(); + sensor_motion->accelFullscale = LSM6DS3_Get_Accel_FullScale_Num(accel_fullscale); + sensor_motion->accelSensitivity = LSM6DS3_Get_Accel_Sensitivity(accel_fullscale); + + LSM6DS3_GyroFullscaleTypeDef gyro_fullscale = LSM6DS3_Get_Gyro_FullScale(); + sensor_motion->gyroFullscale = LSM6DS3_Get_Gyro_FullScale_Num(gyro_fullscale); + sensor_motion->gyroSensitivity = LSM6DS3_Get_Gyro_Sensitivity(gyro_fullscale); + + return 0; +} + +uint8_t LSM6DS3_Get_Accel(sensor_motion_t* sensor_motion) +{ + uint8_t accelx_h, accelx_l, accely_h, accely_l, accelz_h, accelz_l; + uint8_t status_dat = 0; + + while((status_dat&LSM6DS3_XL_DA) != LSM6DS3_XL_DA) + { + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_STATUS_REG, I2C_MEMADD_SIZE_8BIT, &status_dat, 1, 0xFFFF); + } + + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_OUTX_H_XL, I2C_MEMADD_SIZE_8BIT, &accelx_h, 1, 0xFFFF); + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_OUTX_L_XL, I2C_MEMADD_SIZE_8BIT, &accelx_l, 1, 0xFFFF); + sensor_motion->accelX = (uint16_t)accelx_h<<8|accelx_l; + + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_OUTY_H_XL, I2C_MEMADD_SIZE_8BIT, &accely_h, 1, 0xFFFF); + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_OUTY_L_XL, I2C_MEMADD_SIZE_8BIT, &accely_l, 1, 0xFFFF); + sensor_motion->accelY = (uint16_t)accely_h<<8|accely_l; + + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_OUTZ_H_XL, I2C_MEMADD_SIZE_8BIT, &accelz_h, 1, 0xFFFF); + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_OUTZ_L_XL, I2C_MEMADD_SIZE_8BIT, &accelz_l, 1, 0xFFFF); + sensor_motion->accelZ = (uint16_t)accelz_h<<8|accelz_l; + + return 0; +} + +uint8_t LSM6DS3_Get_Gyro(sensor_motion_t* sensor_motion) +{ + uint8_t gyrox_h, gyrox_l, gyroy_h, gyroy_l, gyroz_h, gyroz_l; + uint8_t status_dat = 0; + + while((status_dat&LSM6DS3_G_DA) != LSM6DS3_G_DA) + { + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_STATUS_REG, I2C_MEMADD_SIZE_8BIT, &status_dat, 1, 0xFFFF); + } + + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_OUTX_H_G, I2C_MEMADD_SIZE_8BIT, &gyrox_h, 1, 0xFFFF); + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_OUTX_L_G, I2C_MEMADD_SIZE_8BIT, &gyrox_l, 1, 0xFFFF); + sensor_motion->gyroX = (uint16_t)gyrox_h<<8|gyrox_l; + + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_OUTY_H_G, I2C_MEMADD_SIZE_8BIT, &gyroy_h, 1, 0xFFFF); + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_OUTY_L_G, I2C_MEMADD_SIZE_8BIT, &gyroy_l, 1, 0xFFFF); + sensor_motion->gyroY = (uint16_t)gyroy_h<<8|gyroy_l; + + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_OUTZ_H_G, I2C_MEMADD_SIZE_8BIT, &gyroz_h, 1, 0xFFFF); + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_OUTZ_L_G, I2C_MEMADD_SIZE_8BIT, &gyroz_l, 1, 0xFFFF); + sensor_motion->gyroZ = (uint16_t)gyroz_h<<8|gyroz_l; + + return 0; +} + +uint8_t LSM6DS3_Get_Step(sensor_motion_t* sensor_motion) +{ + uint8_t step_h, step_l; + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_STEP_COUNTER_H, I2C_MEMADD_SIZE_8BIT, &step_h, 1, 0xFFFF); + HAL_I2C_Mem_Read(&hi2c1, LSM6DS3_ADDR_RD, LSM6DS3_STEP_COUNTER_L, I2C_MEMADD_SIZE_8BIT, &step_l, 1, 0xFFFF); + sensor_motion->stepCount = (uint16_t)step_h<<8|step_l; + return 0; +} \ No newline at end of file diff --git a/board/NUCLEO_STM32L073RZ/BSP/HardWare/LSM6DS3/LSM6DS3.h b/board/NUCLEO_STM32L073RZ/BSP/HardWare/LSM6DS3/LSM6DS3.h new file mode 100644 index 00000000..bd842dea --- /dev/null +++ b/board/NUCLEO_STM32L073RZ/BSP/HardWare/LSM6DS3/LSM6DS3.h @@ -0,0 +1,130 @@ +/** + ****************************************************************************** + * @file LSM6DS3.h + * @author jieranzhi (the developer) + * @update 2020/03/23 19:00 CST + * @brief This file contains basic functions prototypes and pre-definitions + * of the register addresses + ****************************************************************************** + * @attention + * + * 1. the temperature sensor embedded in the LSM6DS3 is intended to be embedded + * temperature compensation. Therefore, in this file we DO NOT include the + * temperature output + * + * 2. on the P-NUCLEO-LRWAN3, the SDO/SA0 pad is connected to voltage supply( + * via a resistor), LSb is ¡®1¡¯ (address 1011101b), and the sensor uses + * connection mode 1 + * + * 3. for more information, please refer to the datasheet + * (https://www.st.com/resource/en/datasheet/lsm6ds3.pdf) + * + ****************************************************************************** + */ +#ifndef _LSM6DS3_H_ +#define _LSM6DS3_H_ + +#include + +/* Registers -----------------------------------------------------------------*/ +#define LSM6DS3_ADDR_WR 0xD6 +#define LSM6DS3_ADDR_RD 0xD7 + +#define LSM6DS3_CTRL1_XL 0x10 +#define LSM6DS3_CTRL2_G 0x11 +#define LSM6DS3_CTRL3_C 0x12 +#define LSM6DS3_CTRL4_C 0x13 +#define LSM6DS3_CTRL5_C 0x14 +#define LSM6DS3_CTRL6_C 0x15 +#define LSM6DS3_CTRL7_G 0x16 +#define LSM6DS3_CTRL8_XL 0x17 +#define LSM6DS3_CTRL9_XL 0x18 +#define LSM6DS3_CTRL10_C 0x19 + +#define LSM6DS3_STATUS_REG 0x1E + +#define LSM6DS3_OUTX_L_G 0x22 +#define LSM6DS3_OUTX_H_G 0x23 +#define LSM6DS3_OUTY_L_G 0x24 +#define LSM6DS3_OUTY_H_G 0x25 +#define LSM6DS3_OUTZ_L_G 0x26 +#define LSM6DS3_OUTZ_H_G 0x27 + +#define LSM6DS3_OUTX_L_XL 0x28 +#define LSM6DS3_OUTX_H_XL 0x29 +#define LSM6DS3_OUTY_L_XL 0x30 +#define LSM6DS3_OUTY_H_XL 0x31 +#define LSM6DS3_OUTZ_L_XL 0x32 +#define LSM6DS3_OUTZ_H_XL 0x33 + +#define LSM6DS3_STEP_COUNTER_L 0x4B +#define LSM6DS3_STEP_COUNTER_H 0x4C + +#define LSM6DS3_TAP_CFG 0x58 + + + +/* Enumeration ---------------------------------------------------------------*/ +/** + * @brief STATUS structures definition + */ +typedef enum +{ + LSM6DS3_T_DA = 0x04, /*!< temperature data available */ + LSM6DS3_G_DA = 0x02, /*!< gyro data available */ + LSM6DS3_XL_DA = 0x01, /*!< acceleration data available */ +}LSM6DS3_StatusTypeDef; + +typedef enum +{ + ACCEL_FULLSCALE_2 = 0x00U, + ACCEL_FULLSCALE_16 = 0x04U, + ACCEL_FULLSCALE_4 = 0x08U, + ACCEL_FULLSCALE_8 = 0x0CU, +}LSM6DS3_AccelFullscaleTypeDef; + +typedef enum +{ + GYRO_FULLSCALE_125 = 0x02U, + GYRO_FULLSCALE_250 = 0x00U, + GYRO_FULLSCALE_500 = 0x04U, + GYRO_FULLSCALE_1000 = 0x08U, + GYRO_FULLSCALE_2000 = 0x0CU, +}LSM6DS3_GyroFullscaleTypeDef; + +/** + * @brief motion sensor structures definition + */ +typedef struct +{ + uint8_t accelFullscale; + uint8_t gyroFullscale; + uint16_t accelSensitivity; /*!< the sensitivity is 1000x its actual value */ + uint16_t gyroSensitivity; /*!< the sensitivity is 1000x its actual value */ + uint16_t gyroX; + uint16_t gyroY; + uint16_t gyroZ; + uint16_t accelX; + uint16_t accelY; + uint16_t accelZ; + uint16_t stepCount; +}sensor_motion_t; + +/* Functions -----------------------------------------------------------------*/ +void LSM6DS3_Init(void); +void LSM6DS3_Set_Accel_FullScale(LSM6DS3_AccelFullscaleTypeDef fullscale); +void LSM6DS3_Set_Gyro_FullScale(LSM6DS3_GyroFullscaleTypeDef fullscale); +void LSM6DS3_Set_Accel_FullScale_Num(uint8_t fullscale_num); +void LSM6DS3_Set_Gyro_FullScale_Num(uint8_t fullscale_num); +uint8_t LSM6DS3_Get_Accel_FullScale_Num(LSM6DS3_AccelFullscaleTypeDef fullscale); +uint16_t LSM6DS3_Get_Gyro_FullScale_Num(LSM6DS3_GyroFullscaleTypeDef fullscale); +LSM6DS3_AccelFullscaleTypeDef LSM6DS3_Get_Accel_FullScale(void); +LSM6DS3_GyroFullscaleTypeDef LSM6DS3_Get_Gyro_FullScale(void); +uint16_t LSM6DS3_Get_Accel_Sensitivity(LSM6DS3_AccelFullscaleTypeDef fullscale); +uint32_t LSM6DS3_Get_Gyro_Sensitivity(LSM6DS3_GyroFullscaleTypeDef fullscale); +uint8_t LSM6DS3_Get_Sensor_Config(sensor_motion_t* sensor_motion); +uint8_t LSM6DS3_Get_Accel(sensor_motion_t* sensor_motion); +uint8_t LSM6DS3_Get_Gyro(sensor_motion_t* sensor_motion); +uint8_t LSM6DS3_Get_Step(sensor_motion_t* sensor_motion); + +#endif /* _LSM6DS3_H_ */ diff --git a/board/NUCLEO_STM32L073RZ/BSP/Src/lora_demo.c b/board/NUCLEO_STM32L073RZ/BSP/Src/lora_demo.c index 76d00d1a..84c0339a 100644 --- a/board/NUCLEO_STM32L073RZ/BSP/Src/lora_demo.c +++ b/board/NUCLEO_STM32L073RZ/BSP/Src/lora_demo.c @@ -119,18 +119,31 @@ */ typedef struct device_data_st { - uint8_t magn_fullscale; // fullscale of magnetometer(RW) - uint8_t temp_sensitivity; // temperature sensitivity (R) - uint16_t humi_sensitivity; // humidity sensitivity (R) - uint16_t press_sensitivity; // pressure sensitivity (R) - uint16_t magn_sensitivity; // magnetic sensitivity (R) - int16_t temperature; // temperature (R) - int16_t humidity; // humidity (R) - int16_t magn_x; // X-magnetic value in LSB (R) - int16_t magn_y; // Y-magnetic value in LSB (R) - int16_t magn_z; // Z-magnetic value in LSB (R) - uint16_t period; // report period (R) - uint32_t pressure; // pressure (R) + // -- data set 1 + uint8_t magn_fullscale; // fullscale of magnetometer (RW) + uint8_t temp_sensitivity; // temperature sensitivity (R) + uint16_t humi_sensitivity; // humidity sensitivity (R) + uint16_t press_sensitivity; // pressure sensitivity (R) + uint16_t magn_sensitivity; // magnetic sensitivity (R) + int16_t temperature; // temperature (R) + int16_t humidity; // humidity (R) + int16_t magn_x; // X-magnetic value in LSB (R) + int16_t magn_y; // Y-magnetic value in LSB (R) + int16_t magn_z; // Z-magnetic value in LSB (R) + uint16_t period; // report period (R) + uint32_t pressure; // pressure (R) + + // --- data set 2 + uint16_t accel_fullscale; // fullscale of accelerometer(RW) + uint16_t gyro_fullscale; // fullscale of magnetometer (RW) + int16_t accel_x; // X-accel value in LSB (R) + int16_t accel_y; // Y-accel value in LSB (R) + int16_t accel_z; // Z-accel value in LSB (R) + int16_t gyro_x; // X-gyro value in LSB (R) + int16_t gyro_y; // Y-gyro value in LSB (R) + int16_t gyro_z; // Z-gyro value in LSB (R) + uint32_t accel_sensitivity; // accel sensitivity (R) + uint32_t gyro_sensitivity; // gyro sensitivity (R) } __PACKED__ dev_data_t; typedef struct device_data_wrapper_st { @@ -146,10 +159,12 @@ DeviceConfig_TypeDef device_config; void set_config_to_default(DeviceConfig_TypeDef* config) { - config->config_address = 0x08080000U; - config->is_confirmed = true; - config->report_period = 10; - config->magn_fullscale = FULLSCALE_4; + config->config_address = 0x08080000U; + config->is_confirmed = true; + config->report_period = 10; + config->magn_fullscale = MAGN_FULLSCALE_4; + config->accel_fullscale = ACCEL_FULLSCALE_4; + config->gyro_fullscale = GYRO_FULLSCALE_250; } /** @@ -177,6 +192,9 @@ HAL_StatusTypeDef write_config_to_Flash(DeviceConfig_TypeDef config) frame[1] = (uint32_t)config.is_confirmed<<8 | (uint32_t)DCT_IS_CONFIRM; frame[2] = (uint32_t)config.report_period<<8 | (uint32_t)DCT_REPORT_PERIOD; frame[3] = (uint32_t)config.repeat_time<<8 | (uint32_t)DCT_REPEAT_TIME; + frame[3] = (uint32_t)config.magn_fullscale<<8 | (uint32_t)DCT_MAGN_FULLSCALE; + frame[3] = (uint32_t)config.accel_fullscale<<8 | (uint32_t)DCT_ACCEL_FULLSCALE; + frame[3] = (uint32_t)config.gyro_fullscale<<8 | (uint32_t)DCT_GYRO_FULLSCALE; frame[4] = 0xFFFFFFFFU; HAL_FLASH_Unlock(); @@ -242,6 +260,16 @@ HAL_StatusTypeDef read_config_from_Flash(DeviceConfig_TypeDef* config) config->magn_fullscale = (LIS3MDL_FullScaleTypeDef)(data>>8&0xFF); break; } + case DCT_ACCEL_FULLSCALE: + { + config->accel_fullscale = (LSM6DS3_AccelFullscaleTypeDef)(data>>8&0xFF); + break; + } + case DCT_GYRO_FULLSCALE: + { + config->gyro_fullscale = (LSM6DS3_GyroFullscaleTypeDef)(data>>8&0xFF); + break; + } default: { break; @@ -311,24 +339,45 @@ void application_entry(void *arg) while (1) { BSP_Sensor_Read(&sensor_data); print_to_screen(sensor_data); - // generate data frame - dev_data_wrapper.u.dev_data.magn_fullscale = (uint8_t)(sensor_data.sensor_magn.fullscale); - dev_data_wrapper.u.dev_data.temp_sensitivity = (uint8_t)(sensor_data.sensor_tempnhumi.temp_sensitivity); - dev_data_wrapper.u.dev_data.humi_sensitivity = (uint16_t)(sensor_data.sensor_tempnhumi.humi_sensitivity); - dev_data_wrapper.u.dev_data.press_sensitivity = (uint16_t)(sensor_data.sensor_press.sensitivity); - dev_data_wrapper.u.dev_data.magn_sensitivity = (uint16_t)(sensor_data.sensor_magn.sensitivity); - dev_data_wrapper.u.dev_data.temperature = (int16_t)(sensor_data.sensor_tempnhumi.temperature); - dev_data_wrapper.u.dev_data.humidity = (int16_t)(sensor_data.sensor_tempnhumi.humidity); - dev_data_wrapper.u.dev_data.magn_x = (int16_t)(sensor_data.sensor_magn.magn_x); - dev_data_wrapper.u.dev_data.magn_y = (int16_t)(sensor_data.sensor_magn.magn_y); - dev_data_wrapper.u.dev_data.magn_z = (int16_t)(sensor_data.sensor_magn.magn_z); - dev_data_wrapper.u.dev_data.pressure = (uint32_t)(sensor_data.sensor_press.pressure); - dev_data_wrapper.u.dev_data.period = device_config.report_period; + // generate data frame for data set 1 + dev_data_wrapper.u.dev_data.magn_fullscale = (uint8_t)(sensor_data.sensor_magn.fullscale); + dev_data_wrapper.u.dev_data.temp_sensitivity = (uint8_t)(sensor_data.sensor_tempnhumi.temp_sensitivity); + dev_data_wrapper.u.dev_data.humi_sensitivity = (uint16_t)(sensor_data.sensor_tempnhumi.humi_sensitivity); + dev_data_wrapper.u.dev_data.press_sensitivity = (uint16_t)(sensor_data.sensor_press.sensitivity); + dev_data_wrapper.u.dev_data.magn_sensitivity = (uint16_t)(sensor_data.sensor_magn.sensitivity); + dev_data_wrapper.u.dev_data.temperature = (int16_t)(sensor_data.sensor_tempnhumi.temperature); + dev_data_wrapper.u.dev_data.humidity = (int16_t)(sensor_data.sensor_tempnhumi.humidity); + dev_data_wrapper.u.dev_data.magn_x = (int16_t)(sensor_data.sensor_magn.magn_x); + dev_data_wrapper.u.dev_data.magn_y = (int16_t)(sensor_data.sensor_magn.magn_y); + dev_data_wrapper.u.dev_data.magn_z = (int16_t)(sensor_data.sensor_magn.magn_z); + dev_data_wrapper.u.dev_data.period = device_config.report_period; + dev_data_wrapper.u.dev_data.pressure = (uint32_t)(sensor_data.sensor_press.pressure); + + // generate data frame for data set 2 + dev_data_wrapper.u.dev_data.accel_fullscale = (uint16_t)(sensor_data.sensor_motion.accelFullscale); + dev_data_wrapper.u.dev_data.gyro_fullscale = (uint16_t)(sensor_data.sensor_motion.gyroFullscale); + dev_data_wrapper.u.dev_data.accel_sensitivity = (uint32_t)(sensor_data.sensor_motion.accelSensitivity); + dev_data_wrapper.u.dev_data.gyro_sensitivity = (uint32_t)(sensor_data.sensor_motion.gyroSensitivity); + dev_data_wrapper.u.dev_data.accel_x = (int16_t)(sensor_data.sensor_motion.accelX); + dev_data_wrapper.u.dev_data.accel_y = (int16_t)(sensor_data.sensor_motion.accelY); + dev_data_wrapper.u.dev_data.accel_z = (int16_t)(sensor_data.sensor_motion.accelZ); + dev_data_wrapper.u.dev_data.gyro_x = (int16_t)(sensor_data.sensor_motion.gyroX); + dev_data_wrapper.u.dev_data.gyro_y = (int16_t)(sensor_data.sensor_motion.gyroY); + dev_data_wrapper.u.dev_data.gyro_z = (int16_t)(sensor_data.sensor_motion.gyroZ); + + // package segmentation + uint8_t data_frame1[25]={0}; // idx = 0 + uint8_t data_frame2[25]={1}; // idx = 1 + memcpy(data_frame1+1, dev_data_wrapper.u.serialize, sizeof(uint8_t)*24); + memcpy(data_frame2+1, dev_data_wrapper.u.serialize+24, sizeof(uint8_t)*24); + // send data to the server (via gateway) if(device_config.is_confirmed){ - tos_lora_module_send(dev_data_wrapper.u.serialize, sizeof(dev_data_t)); + tos_lora_module_send(data_frame1, sizeof(data_frame1)); + tos_lora_module_send(data_frame2, sizeof(data_frame2)); }else{ - tos_lora_module_send_unconfirmed(dev_data_wrapper.u.serialize, sizeof(dev_data_t)); + tos_lora_module_send_unconfirmed(data_frame1, sizeof(data_frame1)); + tos_lora_module_send_unconfirmed(data_frame2, sizeof(data_frame2)); } tos_task_delay(device_config.report_period * 1000); } diff --git a/board/NUCLEO_STM32L073RZ/IAR/lorawan/TencentOS_tiny.ewp b/board/NUCLEO_STM32L073RZ/IAR/lorawan/TencentOS_tiny.ewp index 84a1b288..1dcdb000 100644 --- a/board/NUCLEO_STM32L073RZ/IAR/lorawan/TencentOS_tiny.ewp +++ b/board/NUCLEO_STM32L073RZ/IAR/lorawan/TencentOS_tiny.ewp @@ -369,6 +369,7 @@ $PROJ_DIR$\..\..\BSP\HardWare\LPS22HB $PROJ_DIR$\..\..\BSP\HardWare\Common $PROJ_DIR$\..\..\BSP\HardWare\LIS3MDL + $PROJ_DIR$\..\..\BSP\HardWare\LSM6DS3 + + LSM6DS3 + + $PROJ_DIR$\..\..\BSP\HardWare\LSM6DS3\LSM6DS3.c + + $PROJ_DIR$\..\..\BSP\HardWare\Common\bsp.c diff --git a/board/NUCLEO_STM32L073RZ/IAR/lorawan/TencentOS_tiny.ewt b/board/NUCLEO_STM32L073RZ/IAR/lorawan/TencentOS_tiny.ewt index b3317fc0..5df1eeef 100644 --- a/board/NUCLEO_STM32L073RZ/IAR/lorawan/TencentOS_tiny.ewt +++ b/board/NUCLEO_STM32L073RZ/IAR/lorawan/TencentOS_tiny.ewt @@ -1213,6 +1213,12 @@ $PROJ_DIR$\..\..\BSP\HardWare\LPS22HB\LPS22HB.c + + LSM6DS3 + + $PROJ_DIR$\..\..\BSP\HardWare\LSM6DS3\LSM6DS3.c + + $PROJ_DIR$\..\..\BSP\HardWare\Common\bsp.c diff --git a/devices/rhf76_lora/RHF76.c b/devices/rhf76_lora/RHF76.c index a9a956a0..24190882 100644 --- a/devices/rhf76_lora/RHF76.c +++ b/devices/rhf76_lora/RHF76.c @@ -154,7 +154,7 @@ static int rhf76_set_chanel(void) return -1; } -static int rhf76_set_repeat(uint8_t num) +int rhf76_set_repeat(uint8_t num) { int try = 0; at_echo_t echo; @@ -174,6 +174,56 @@ static int rhf76_set_repeat(uint8_t num) return -1; } +int rhf76_set_data_rate(uint8_t num) +{ + if(num>15) return -1; // num should between [0, 15] + int try = 0; + at_echo_t echo; + char cmd[14] = {0}; + char expect[10] = {'\0'}; + snprintf(cmd, sizeof(cmd), RHF76_ATCMD_SET_DATA_RATE, num); + snprintf(expect, sizeof(expect), " DR%d", num); + + tos_at_echo_fuzzy_matching_create(&echo, NULL, 0, expect); + + while (try++ < 10) { + tos_at_cmd_exec(&echo, 3000, cmd); + if (echo.status == AT_ECHO_STATUS_OK || echo.status == AT_ECHO_STATUS_EXPECT) { + return 0; + } + } + return -1; +} + +int rhf76_set_delay(char *param) +{ + int try = 0; + at_echo_t echo; + char cmd[20] = {0}; + char expect[20] = {'\0'}; + snprintf(cmd, sizeof(cmd), RHF76_ATCMD_SET_DELAY, param); + snprintf(expect, sizeof(expect), "+DELAY %s", param); + + tos_at_echo_create(&echo, NULL, 0, expect); + + while (try++ < 10) { + tos_at_cmd_exec(&echo, 3000, cmd); + if(strstr(param,"?")!=NULL) return 0; + if (echo.status == AT_ECHO_STATUS_OK || echo.status == AT_ECHO_STATUS_EXPECT) { + return 0; + } + } + return -1; +} + +int rhf76_at_cmd_exe(char *cmd) +{ + at_echo_t echo; + tos_at_echo_create(&echo, NULL, 0, NULL); + tos_at_cmd_exec(&echo, 8000, cmd); + return 0; +} + static int rhf76_set_adr_off(void) { int try = 0; @@ -329,10 +379,34 @@ static int rhf76_init(void) printf("rhf76 set repeat times for unconfirmed message FAILED\n"); return -1; } - at_delay_ms(2000); printf("Init RHF76 LoRa done\n"); + /*----------------------------------------------------*/ + /*--- the following code is only used for debuging ---*/ + /*----------------------------------------------------*/ + + /*<-- query/set UART Timeout (~TX timeout) -->*/ + // rhf76_at_cmd_exe("AT+UART=TIMEOUT, 300\r\n"); + // rhf76_at_cmd_exe("AT+UART=TIMEOUT\r\n"); + + /*<-- query current band config -->*/ + // rhf76_at_cmd_exe("AT+DR=SCHEME\r\n"); + // rhf76_at_cmd_exe("AT+LW=CDR\r\n"); + + /*<-- query current data rate and the corresponding max payload size -->*/ + rhf76_set_data_rate(0); + // rhf76_at_cmd_exe("at+dr=0\r\n"); + // rhf76_at_cmd_exe("AT+DR\r\n"); + // rhf76_at_cmd_exe("AT+LW=LEN\r\n"); + + /*<-- query RX1\RX2\JRX1\JRX2 delay config -->*/ + // rhf76_set_delay("?"); + + /*<-- query RF config -->*/ + // rhf76_at_cmd_exe("AT+MODE=TEST\r\n"); + // rhf76_at_cmd_exe("AT+TEST=?\r\n"); + return 0; } @@ -454,7 +528,6 @@ static int rhf76_send(const void *buf, size_t len) static int rhf76_send_unconfirmed(const void *buf, size_t len) { - char *str_buf = NULL; at_echo_t echo; diff --git a/devices/rhf76_lora/RHF76.h b/devices/rhf76_lora/RHF76.h index f5a2ec34..f4d88be5 100644 --- a/devices/rhf76_lora/RHF76.h +++ b/devices/rhf76_lora/RHF76.h @@ -69,9 +69,11 @@ typedef enum lora_key_type { #define RHF76_ATCMD_FMT_SEND_MSGHEX "AT+MSGHEX=\"%s\"\r\n" #define RHF76_ATCMD_SET_REPT "AT+REPT=%d\r\n" +#define RHF76_ATCMD_SET_DELAY "AT+DELAY=%s\r\n" #define RHF76_ATCMD_SET_BAND_CN470 "AT+DR=CN470\r\n" #define RHF76_ATCMD_REPLY_BAND_CN470 "+DR: CN470" +#define RHF76_ATCMD_SET_DATA_RATE "AT+DR=%d\r\n" #define RHF76_ATCMD_SET_CHANNEL "at+ch=num,80-87\r\n" #define RHF76_ATCMD_SET_ADR_OFF "at+adr=off\r\n" @@ -84,5 +86,66 @@ typedef enum lora_key_type { int rhf76_lora_init(hal_uart_port_t uart_port); +/** + * @brief set the delay for RX1,RX2,JRX1,JRX2 OR query current delay config + * @note Examples: + * to set the delay(ms): + * rhf76_set_delay("RX1,2000"); + * + * to query current delay config: + * rhf76_set_delay("?"); + * + * @param params operation string + * + * @retval int Status + */ +int rhf76_set_delay(char *param); + +/** + * @brief set repeat times when sending unconfirmed message + * @note it is equal to sending + * AT+REPT=2 + * +REPT: 2 + * + * @param num repeat times + * + * @retval int Status + */ +int rhf76_set_repeat(uint8_t num); + + +/** + * @brief set date rate, which would affect the maximum payload size + * @note this function is for DEBUG purpose only, it allows user to execute + * AT+ commands by passing the AT+ command to the function as an arg- + * ument. + * For example,users can query the RF configuration by following code: + * + * rhf76_at_cmd_exe("AT+MODE=TEST\r\n"); + * rhf76_at_cmd_exe("AT+TEST=?\r\n"); + * + * @param num data rate + * + * @retval int Status + */ +int rhf76_set_data_rate(uint8_t num); + + +/** + * @brief execute AT+ commands + * @note this function is for DEBUG purpose only, it allows user to execute + * AT+ commands by passing the AT+ command to the function as an arg- + * ument. + * For example,users can query the RF configuration by following code: + * + * rhf76_at_cmd_exe("AT+MODE=TEST\r\n"); + * rhf76_at_cmd_exe("AT+TEST=?\r\n"); + * + * @param cmd AT+ commands + * + * @retval int Status + */ +int rhf76_at_cmd_exe(char *cmd); + #endif /* __RHF76_H__ */ diff --git a/net/at/include/tos_at.h b/net/at/include/tos_at.h index 665b2cb5..36040eb8 100644 --- a/net/at/include/tos_at.h +++ b/net/at/include/tos_at.h @@ -1,459 +1,477 @@ -/*---------------------------------------------------------------------------- - * Tencent is pleased to support the open source community by making TencentOS - * available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * If you have downloaded a copy of the TencentOS binary from Tencent, please - * note that the TencentOS binary is licensed under the BSD 3-Clause License. - * - * If you have downloaded a copy of the TencentOS source code from Tencent, - * please note that TencentOS source code is licensed under the BSD 3-Clause - * License, except for the third-party components listed below which are - * subject to different license terms. Your integration of TencentOS into your - * own projects may require compliance with the BSD 3-Clause License, as well - * as the other licenses applicable to the third-party components included - * within TencentOS. - *---------------------------------------------------------------------------*/ - -#ifndef _TOS_AT_H_ -#define _TOS_AT_H_ - -#include "tos_k.h" -#include "tos_at_utils.h" -#include "tos_hal.h" - -#define AT_AGENT_ECHO_OK "OK" -#define AT_AGENT_ECHO_FAIL "FAIL" -#define AT_AGENT_ECHO_ERROR "ERROR" - -#define AT_DATA_CHANNEL_NUM 6 -#define AT_DATA_CHANNEL_FIFO_BUFFER_SIZE (2048 + 1024) - -#define AT_UART_RX_FIFO_BUFFER_SIZE (2048 + 1024) -#define AT_RECV_CACHE_SIZE 2048 - -#define AT_CMD_BUFFER_SIZE 512 - -#define AT_PARSER_TASK_STACK_SIZE 2048 -#define AT_PARSER_TASK_PRIO 2 - -typedef enum at_status_en { - AT_STATUS_OK, - AT_STATUS_ERROR, - AT_STATUS_INVALID_ARGS, -} at_status_t; - -typedef struct at_cache_st { - uint8_t *buffer; - size_t buffer_size; - size_t recv_len; -} at_cache_t; - -typedef enum at_parse_status_en { - AT_PARSE_STATUS_NONE, - AT_PARSE_STATUS_NEWLINE, - AT_PARSE_STATUS_EVENT, - AT_PARSE_STATUS_EXPECT, - AT_PARSE_STATUS_OVERFLOW, -} at_parse_status_t; - -typedef enum at_echo_status_en { - AT_ECHO_STATUS_NONE, - AT_ECHO_STATUS_OK, - AT_ECHO_STATUS_FAIL, - AT_ECHO_STATUS_ERROR, - AT_ECHO_STATUS_EXPECT, -} at_echo_status_t; - -typedef enum at_channel_status_en { - AT_CHANNEL_STATUS_NONE, /*< usually means we are try to get a channel status with invalid id */ - AT_CHANNEL_STATUS_HANGING, /*< channel is not used */ - AT_CHANNEL_STATUS_WORKING, /*< channel is being using */ - AT_CHANNEL_STATUS_BROKEN, /*< channel is broken(module link to remote server is broken) */ -} at_channel_status_t; - -typedef struct at_data_channel_st { - uint8_t is_free; - k_chr_fifo_t rx_fifo; - uint8_t *rx_fifo_buffer; - k_mutex_t rx_lock; - - at_channel_status_t status; - - const char *remote_ip; - const char *remote_port; -} at_data_channel_t; - -typedef struct at_echo_st { - char *buffer; - size_t buffer_size; - char *echo_expect; - int line_num; - at_echo_status_t status; - size_t __w_idx; - int __is_expecting; - k_sem_t __expect_notify; -} at_echo_t; - -typedef void (*at_event_callback_t)(void); - -typedef struct at_event_st { - const char *event_header; - at_event_callback_t event_callback; -} at_event_t; - -typedef struct at_agent_st { - at_data_channel_t data_channel[AT_DATA_CHANNEL_NUM]; - - at_event_t *event_table; - size_t event_table_size; - - at_echo_t *echo; - - k_task_t parser; - at_cache_t recv_cache; - - at_timer_t timer; - - k_mutex_t global_lock; - - char *cmd_buf; - k_mutex_t cmd_buf_lock; - - hal_uart_t uart; - k_mutex_t uart_tx_lock; - k_mutex_t uart_rx_lock; - k_sem_t uart_rx_sem; - k_chr_fifo_t uart_rx_fifo; - uint8_t *uart_rx_fifo_buffer; -} at_agent_t; - -#define AT_AGENT ((at_agent_t *)(&at_agent)) - -/** - * @brief Write data to a channel. - * Write data to a channel with certain id. - * - * @attention None - * - * @param[in] channel_id id of the channel. - * @param[in] buffer data buffer to write. - * @param[in] buffer_len length of the buffer. - * - * @return errcode - * @retval -1 write failed(error). - * @retval none -1 the number of bytes written. - */ -__API__ int tos_at_channel_write(int channel_id, uint8_t *buffer, size_t buffer_len); - -/** - * @brief Read data from a channel. - * Read data from a channel with a timeout. - * - * @attention None - * - * @param[in] channel_id id of the channel. - * @param[out] buffer buffer to hold the data read. - * @param[in] buffer_len length of the buffer. - * @param[in] timeout timeout. - * - * @return errcode - * @retval -1 read failed(error). - * @retval none -1 the number of bytes read. - */ -__API__ int tos_at_channel_read_timed(int channel_id, uint8_t *buffer, size_t buffer_len, uint32_t timeout); - -/** - * @brief Read data from a channel. - * Read data from a channel. - * - * @attention None - * - * @param[in] channel_id id of the channel. - * @param[out] buffer buffer to hold the data read. - * @param[in] buffer_len length of the buffer. - * - * @return errcode - * @retval -1 read failed(error). - * @retval none -1 the number of bytes read. - */ -__API__ int tos_at_channel_read(int channel_id, uint8_t *buffer, size_t buffer_len); - -/** - * @brief Allocate a channel. - * Allocate a channel with certain id. - * - * @attention None - * - * @param[in] channel_id id of the channel. - * @param[in] ip remote ip of the channel. - * @param[in] port remote port of the channel. - * - * @return errcode - * @retval -1 allocate failed(error). - * @retval none -1 the id of the channel. - */ -__API__ int tos_at_channel_alloc_id(int channel_id, const char *ip, const char *port); - -/** - * @brief Allocate a channel. - * Allocate a channel. - * - * @attention None - * - * @param[in] ip remote ip of the channel. - * @param[in] port remote port of the channel. - * - * @return errcode - * @retval -1 allocate failed(error). - * @retval none -1 the id of the channel. - */ -__API__ int tos_at_channel_alloc(const char *ip, const char *port); - -/** - * @brief Free a channel. - * Free a channel with certain id. - * - * @attention None - * - * @param[in] channel_id id of the channel. - * - * @return errcode - * @retval -1 free failed(error). - * @retval 0 free successfully. - */ -__API__ int tos_at_channel_free(int channel_id); - -/** - * @brief Set channel broken. - * - * @attention None - * - * @param[in] channel_id id of the channel. - * - * @return errcode - * @retval -1 set failed(error). - * @retval 0 set successfully. - */ -__API__ int tos_at_channel_set_broken(int channel_id); - -/** - * @brief Judge whether channel is working. - * - * @attention None - * - * @param[in] channel_id id of the channel. - * - * @return at channel status(type of at_channel_status_t) - */ -__API__ int tos_at_channel_is_working(int channel_id); - -/** - * @brief Initialize the at framework. - * - * @attention None - * - * @param[in] uart_port port number of the uart thougth which the module connect to the MCU. - * @param[in] event_table the listened event table. - * @param[in] event_table_size the size of the listened event table. - * - * @return errcode - * @retval -1 initialize failed(error). - * @retval 0 initialize successfully. - */ -__API__ int tos_at_init(hal_uart_port_t uart_port, at_event_t *event_table, size_t event_table_size); - -/** - * @brief De-initialize the at framework. - * - * @attention None - * - * @return None - */ -__API__ void tos_at_deinit(void); - -/** - * @brief Create a echo struct. - * - * @attention None - * - * @param[in] echo pointer to the echo struct. - * @param[out] buffer buffer to hold the received message from the module. - * @param[in] buffer_size size of the buffer. - * @param[in] echo_expect the expected echo message. - * - * @return errcode - * @retval -1 create failed(error). - * @retval 0 create successfully. - */ -__API__ int tos_at_echo_create(at_echo_t *echo, char *buffer, size_t buffer_size, char *echo_expect); - -/** - * @brief Execute an at command. - * - * @attention None - * - * @param[in] echo pointer to the echo struct. - * @param[in] timeout command wait timeout . - * @param[in] cmd at command. - * - * @return errcode - * @retval -1 execute failed(error). - * @retval 0 execute successfully. - */ -__API__ int tos_at_cmd_exec(at_echo_t *echo, uint32_t timeout, const char *cmd, ...); - -/** - * @brief Execute an at command. - * Execute an at command and wait until the expected echo message received or timeout. - * - * @attention None - * - * @param[in] echo pointer to the echo struct. - * @param[in] timeout command wait timeout . - * @param[in] cmd at command. - * - * @return errcode - * @retval -1 execute failed(error). - * @retval 0 execute successfully. - */ -__API__ int tos_at_cmd_exec_until(at_echo_t *echo, uint32_t timeout, const char *cmd, ...); - -/** - * @brief Send raw data througth uart. - * - * @attention None - * - * @param[in] echo pointer to the echo struct. - * @param[in] timeout command wait timeout . - * @param[in] buf data to send. - * @param[in] size size of the buf. - * - * @return errcode - * @retval -1 execute failed(error). - * @retval 0 execute successfully. - */ -__API__ int tos_at_raw_data_send(at_echo_t *echo, uint32_t timeout, const uint8_t *buf, size_t size); - -/** - * @brief Send raw data througth uart. - * Send raw data througth uart and wait until the expected echo message received or timeout. - * - * @attention None - * - * @param[in] echo pointer to the echo struct. - * @param[in] timeout command wait timeout . - * @param[in] buf data to send. - * @param[in] size size of the buf. - * - * @return errcode - * @retval -1 execute failed(error). - * @retval 0 execute successfully. - */ -__API__ int tos_at_raw_data_send_until(at_echo_t *echo, uint32_t timeout, const uint8_t *buf, size_t size); - -/** - * @brief Write byte to the at uart. - * The function called by the uart interrupt, to put the data from the uart to the at framework. - * - * @attention None - * - * @param[in] data uart received data. - * - * @return None - */ -__API__ void tos_at_uart_input_byte(uint8_t data); - -/** - * @brief A global lock provided by at framework. - * The lock usually used to make a atomic function. - * - * @attention None - * - * @param None. - * - * @return errcode - * @retval -1 pend failed(error). - * @retval 0 pend successfully. - */ -__API__ int tos_at_global_lock_pend(void); - -/** - * @brief A global lock provided by at framework. - * The lock usually used to make a atomic function. - * - * @attention None - * - * @param None. - * - * @return errcode - * @retval -1 post failed(error). - * @retval 0 post successfully. - */ -__API__ int tos_at_global_lock_post(void); - -/** - * @brief Read data from the uart. - * Read data from the uart, usually called in listened event callback. - * - * @attention None - * - * @param[out] buffer buffer to hold the data read from the uart. - * @param[in] buffer_len length of the buffer. - * - * @return length of the data read from the uart. - */ -__API__ int tos_at_uart_read(uint8_t *buffer, size_t buffer_len); - -/** - * @brief Read data from the uart. - * Read data from the uart until meet a '\n', usually called in listened event callback. - * - * @attention None - * - * @param[out] buffer buffer to hold the data read from the uart. - * @param[in] buffer_len length of the buffer. - * - * @return length of the data read from the uart. - */ -__API__ int tos_at_uart_readline(uint8_t *buffer, size_t buffer_len); - -/** - * @brief Read data from the uart. - * Read data from the uart until no more incoming data, usually called in listened event callback. - * - * @attention None - * - * @param[out] buffer buffer to hold the data read from the uart. - * @param[in] buffer_len length of the buffer. - * - * @return length of the data read from the uart. - */ -__API__ int tos_at_uart_drain(uint8_t *buffer, size_t buffer_len); - -/** - * @brief Get the remote ip of a channel. - * Get the remote ip of a channel with certain id. - * - * @attention None - * - * @param[in] channel_id id of the channel. - * - * @return remote ip of the channel. - */ -__API__ const char *tos_at_agent_channel_ip_get(int channel_id); - -/** - * @brief Get the remote port of a channel. - * Get the remote port of a channel with certain id. - * - * @attention None - * - * @param[in] channel_id id of the channel. - * - * @return remote port of the channel. - */ -__API__ const char *tos_at_agent_channel_port_get(int channel_id); - -#endif /* __AT_AGENT_H_ */ - +/*---------------------------------------------------------------------------- + * Tencent is pleased to support the open source community by making TencentOS + * available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * If you have downloaded a copy of the TencentOS binary from Tencent, please + * note that the TencentOS binary is licensed under the BSD 3-Clause License. + * + * If you have downloaded a copy of the TencentOS source code from Tencent, + * please note that TencentOS source code is licensed under the BSD 3-Clause + * License, except for the third-party components listed below which are + * subject to different license terms. Your integration of TencentOS into your + * own projects may require compliance with the BSD 3-Clause License, as well + * as the other licenses applicable to the third-party components included + * within TencentOS. + *---------------------------------------------------------------------------*/ + +#ifndef _TOS_AT_H_ +#define _TOS_AT_H_ + +#include "tos_k.h" +#include "tos_at_utils.h" +#include "tos_hal.h" + +#define AT_AGENT_ECHO_OK "OK" +#define AT_AGENT_ECHO_FAIL "FAIL" +#define AT_AGENT_ECHO_ERROR "ERROR" + +#define AT_DATA_CHANNEL_NUM 6 +#define AT_DATA_CHANNEL_FIFO_BUFFER_SIZE (2048 + 1024) + +#define AT_UART_RX_FIFO_BUFFER_SIZE (2048 + 1024) +#define AT_RECV_CACHE_SIZE 2048 + +#define AT_CMD_BUFFER_SIZE 512 + +#define AT_PARSER_TASK_STACK_SIZE 2048 +#define AT_PARSER_TASK_PRIO 2 + +typedef enum at_status_en { + AT_STATUS_OK, + AT_STATUS_ERROR, + AT_STATUS_INVALID_ARGS, +} at_status_t; + +typedef struct at_cache_st { + uint8_t *buffer; + size_t buffer_size; + size_t recv_len; +} at_cache_t; + +typedef enum at_parse_status_en { + AT_PARSE_STATUS_NONE, + AT_PARSE_STATUS_NEWLINE, + AT_PARSE_STATUS_EVENT, + AT_PARSE_STATUS_EXPECT, + AT_PARSE_STATUS_OVERFLOW, +} at_parse_status_t; + +typedef enum at_echo_status_en { + AT_ECHO_STATUS_NONE, + AT_ECHO_STATUS_OK, + AT_ECHO_STATUS_FAIL, + AT_ECHO_STATUS_ERROR, + AT_ECHO_STATUS_EXPECT, +} at_echo_status_t; + +typedef enum at_channel_status_en { + AT_CHANNEL_STATUS_NONE, /*< usually means we are try to get a channel status with invalid id */ + AT_CHANNEL_STATUS_HANGING, /*< channel is not used */ + AT_CHANNEL_STATUS_WORKING, /*< channel is being using */ + AT_CHANNEL_STATUS_BROKEN, /*< channel is broken(module link to remote server is broken) */ +} at_channel_status_t; + +typedef struct at_data_channel_st { + uint8_t is_free; + k_chr_fifo_t rx_fifo; + uint8_t *rx_fifo_buffer; + k_mutex_t rx_lock; + + at_channel_status_t status; + + const char *remote_ip; + const char *remote_port; +} at_data_channel_t; + +typedef struct at_echo_st { + char *buffer; + size_t buffer_size; + char *echo_expect; + int line_num; + at_echo_status_t status; + size_t __w_idx; + int __is_expecting; + k_sem_t __expect_notify; + int fuzzy_matching; +} at_echo_t; + +typedef void (*at_event_callback_t)(void); + +typedef struct at_event_st { + const char *event_header; + at_event_callback_t event_callback; +} at_event_t; + +typedef struct at_agent_st { + at_data_channel_t data_channel[AT_DATA_CHANNEL_NUM]; + + at_event_t *event_table; + size_t event_table_size; + + at_echo_t *echo; + + k_task_t parser; + at_cache_t recv_cache; + + at_timer_t timer; + + k_mutex_t global_lock; + + char *cmd_buf; + k_mutex_t cmd_buf_lock; + + hal_uart_t uart; + k_mutex_t uart_tx_lock; + k_mutex_t uart_rx_lock; + k_sem_t uart_rx_sem; + k_chr_fifo_t uart_rx_fifo; + uint8_t *uart_rx_fifo_buffer; +} at_agent_t; + +#define AT_AGENT ((at_agent_t *)(&at_agent)) + +/** + * @brief Write data to a channel. + * Write data to a channel with certain id. + * + * @attention None + * + * @param[in] channel_id id of the channel. + * @param[in] buffer data buffer to write. + * @param[in] buffer_len length of the buffer. + * + * @return errcode + * @retval -1 write failed(error). + * @retval none -1 the number of bytes written. + */ +__API__ int tos_at_channel_write(int channel_id, uint8_t *buffer, size_t buffer_len); + +/** + * @brief Read data from a channel. + * Read data from a channel with a timeout. + * + * @attention None + * + * @param[in] channel_id id of the channel. + * @param[out] buffer buffer to hold the data read. + * @param[in] buffer_len length of the buffer. + * @param[in] timeout timeout. + * + * @return errcode + * @retval -1 read failed(error). + * @retval none -1 the number of bytes read. + */ +__API__ int tos_at_channel_read_timed(int channel_id, uint8_t *buffer, size_t buffer_len, uint32_t timeout); + +/** + * @brief Read data from a channel. + * Read data from a channel. + * + * @attention None + * + * @param[in] channel_id id of the channel. + * @param[out] buffer buffer to hold the data read. + * @param[in] buffer_len length of the buffer. + * + * @return errcode + * @retval -1 read failed(error). + * @retval none -1 the number of bytes read. + */ +__API__ int tos_at_channel_read(int channel_id, uint8_t *buffer, size_t buffer_len); + +/** + * @brief Allocate a channel. + * Allocate a channel with certain id. + * + * @attention None + * + * @param[in] channel_id id of the channel. + * @param[in] ip remote ip of the channel. + * @param[in] port remote port of the channel. + * + * @return errcode + * @retval -1 allocate failed(error). + * @retval none -1 the id of the channel. + */ +__API__ int tos_at_channel_alloc_id(int channel_id, const char *ip, const char *port); + +/** + * @brief Allocate a channel. + * Allocate a channel. + * + * @attention None + * + * @param[in] ip remote ip of the channel. + * @param[in] port remote port of the channel. + * + * @return errcode + * @retval -1 allocate failed(error). + * @retval none -1 the id of the channel. + */ +__API__ int tos_at_channel_alloc(const char *ip, const char *port); + +/** + * @brief Free a channel. + * Free a channel with certain id. + * + * @attention None + * + * @param[in] channel_id id of the channel. + * + * @return errcode + * @retval -1 free failed(error). + * @retval 0 free successfully. + */ +__API__ int tos_at_channel_free(int channel_id); + +/** + * @brief Set channel broken. + * + * @attention None + * + * @param[in] channel_id id of the channel. + * + * @return errcode + * @retval -1 set failed(error). + * @retval 0 set successfully. + */ +__API__ int tos_at_channel_set_broken(int channel_id); + +/** + * @brief Judge whether channel is working. + * + * @attention None + * + * @param[in] channel_id id of the channel. + * + * @return at channel status(type of at_channel_status_t) + */ +__API__ int tos_at_channel_is_working(int channel_id); + +/** + * @brief Initialize the at framework. + * + * @attention None + * + * @param[in] uart_port port number of the uart thougth which the module connect to the MCU. + * @param[in] event_table the listened event table. + * @param[in] event_table_size the size of the listened event table. + * + * @return errcode + * @retval -1 initialize failed(error). + * @retval 0 initialize successfully. + */ +__API__ int tos_at_init(hal_uart_port_t uart_port, at_event_t *event_table, size_t event_table_size); + +/** + * @brief De-initialize the at framework. + * + * @attention None + * + * @return +None + */ +__API__ void tos_at_deinit(void); + +/** + * @brief Create a echo struct. + * + * @attention None + * + * @param[in] echo pointer to the echo struct. + * @param[out] buffer buffer to hold the received message from the module. + * @param[in] buffer_size size of the buffer. + * @param[in] echo_expect the expected echo message. + * + * @return errcode + * @retval -1 create failed(error). + * @retval 0 create successfully. + */ +__API__ int tos_at_echo_create(at_echo_t *echo, char *buffer, size_t buffer_size, char *echo_expect); + +/** + * @brief Create a echo struct with fuzzy matching for expected echo. + * + * @attention None + * + * @param[in] echo pointer to the echo struct. + * @param[out] buffer buffer to hold the received message from the module. + * @param[in] buffer_size size of the buffer. + * @param[in] echo_expect_contains if the echo message contains echo_expect_contains, it is a matching. + * + * @return errcode + * @retval -1 create failed(error). + * @retval 0 create successfully. + */ +__API__ int tos_at_echo_fuzzy_matching_create(at_echo_t *echo, char *buffer, size_t buffer_size, char *echo_expect_contains); + +/** + * @brief Execute an at command. + * + * @attention None + * + * @param[in] echo pointer to the echo struct. + * @param[in] timeout command wait timeout . + * @param[in] cmd at command. + * + * @return errcode + * @retval -1 execute failed(error). + * @retval 0 execute successfully. + */ +__API__ int tos_at_cmd_exec(at_echo_t *echo, uint32_t timeout, const char *cmd, ...); + +/** + * @brief Execute an at command. + * Execute an at command and wait until the expected echo message received or timeout. + * + * @attention None + * + * @param[in] echo pointer to the echo struct. + * @param[in] timeout command wait timeout . + * @param[in] cmd at command. + * + * @return errcode + * @retval -1 execute failed(error). + * @retval 0 execute successfully. + */ +__API__ int tos_at_cmd_exec_until(at_echo_t *echo, uint32_t timeout, const char *cmd, ...); + +/** + * @brief Send raw data througth uart. + * + * @attention None + * + * @param[in] echo pointer to the echo struct. + * @param[in] timeout command wait timeout . + * @param[in] buf data to send. + * @param[in] size size of the buf. + * + * @return errcode + * @retval -1 execute failed(error). + * @retval 0 execute successfully. + */ +__API__ int tos_at_raw_data_send(at_echo_t *echo, uint32_t timeout, const uint8_t *buf, size_t size); + +/** + * @brief Send raw data througth uart. + * Send raw data througth uart and wait until the expected echo message received or timeout. + * + * @attention None + * + * @param[in] echo pointer to the echo struct. + * @param[in] timeout command wait timeout . + * @param[in] buf data to send. + * @param[in] size size of the buf. + * + * @return errcode + * @retval -1 execute failed(error). + * @retval 0 execute successfully. + */ +__API__ int tos_at_raw_data_send_until(at_echo_t *echo, uint32_t timeout, const uint8_t *buf, size_t size); + +/** + * @brief Write byte to the at uart. + * The function called by the uart interrupt, to put the data from the uart to the at framework. + * + * @attention None + * + * @param[in] data uart received data. + * + * @return None + */ +__API__ void tos_at_uart_input_byte(uint8_t data); + +/** + * @brief A global lock provided by at framework. + * The lock usually used to make a atomic function. + * + * @attention None + * + * @param None. + * + * @return errcode + * @retval -1 pend failed(error). + * @retval 0 pend successfully. + */ +__API__ int tos_at_global_lock_pend(void); + +/** + * @brief A global lock provided by at framework. + * The lock usually used to make a atomic function. + * + * @attention None + * + * @param None. + * + * @return errcode + * @retval -1 post failed(error). + * @retval 0 post successfully. + */ +__API__ int tos_at_global_lock_post(void); + +/** + * @brief Read data from the uart. + * Read data from the uart, usually called in listened event callback. + * + * @attention None + * + * @param[out] buffer buffer to hold the data read from the uart. + * @param[in] buffer_len length of the buffer. + * + * @return length of the data read from the uart. + */ +__API__ int tos_at_uart_read(uint8_t *buffer, size_t buffer_len); + +/** + * @brief Read data from the uart. + * Read data from the uart until meet a '\n', usually called in listened event callback. + * + * @attention None + * + * @param[out] buffer buffer to hold the data read from the uart. + * @param[in] buffer_len length of the buffer. + * + * @return length of the data read from the uart. + */ +__API__ int tos_at_uart_readline(uint8_t *buffer, size_t buffer_len); + +/** + * @brief Read data from the uart. + * Read data from the uart until no more incoming data, usually called in listened event callback. + * + * @attention None + * + * @param[out] buffer buffer to hold the data read from the uart. + * @param[in] buffer_len length of the buffer. + * + * @return length of the data read from the uart. + */ +__API__ int tos_at_uart_drain(uint8_t *buffer, size_t buffer_len); + +/** + * @brief Get the remote ip of a channel. + * Get the remote ip of a channel with certain id. + * + * @attention None + * + * @param[in] channel_id id of the channel. + * + * @return remote ip of the channel. + */ +__API__ const char *tos_at_agent_channel_ip_get(int channel_id); + +/** + * @brief Get the remote port of a channel. + * Get the remote port of a channel with certain id. + * + * @attention None + * + * @param[in] channel_id id of the channel. + * + * @return remote port of the channel. + */ +__API__ const char *tos_at_agent_channel_port_get(int channel_id); + +#endif /* __AT_AGENT_H_ */ + diff --git a/net/at/src/tos_at.c b/net/at/src/tos_at.c index f632cbef..a9cd6cde 100644 --- a/net/at/src/tos_at.c +++ b/net/at/src/tos_at.c @@ -161,9 +161,18 @@ __STATIC__ int at_is_echo_expect(void) return 0; } + if(at_echo->fuzzy_matching){ + if(strstr(recv_buffer, expect)!=NULL){ + return 0; + } + return -1; + } + if (strncmp(expect, recv_buffer, expect_len) == 0) { return 1; } + + return 0; } @@ -337,6 +346,28 @@ __API__ int tos_at_echo_create(at_echo_t *echo, char *buffer, size_t buffer_size echo->status = AT_ECHO_STATUS_NONE; echo->__w_idx = 0; echo->__is_expecting = K_FALSE; + echo->fuzzy_matching = K_FALSE; + return 0; +} + +__API__ int tos_at_echo_fuzzy_matching_create(at_echo_t *echo, char *buffer, size_t buffer_size, char *echo_expect_contains) +{ + if (!echo) { + return -1; + } + + if (buffer) { + memset(buffer, 0, buffer_size); + } + + echo->buffer = buffer; + echo->buffer_size = buffer_size; + echo->echo_expect = echo_expect_contains; + echo->line_num = 0; + echo->status = AT_ECHO_STATUS_NONE; + echo->__w_idx = 0; + echo->__is_expecting = K_FALSE; + echo->fuzzy_matching = K_TRUE; return 0; }