CubeMX: SPI4 + SDMMC1/FatFs + I2S6, audio BSP et debug VS Code (Linux)

Regeneration CubeMX (Appli) preparant le driver ST67W611M1 et la carte SD :
- SPI4 (PE12/13/14, CS PF8) + DMA GPDMA1 canaux 4/5, SPI_RDY (PD12/EXTI12),
  CHIP_EN (PD13) et BOOT (PD15) pour la X-NUCLEO-67W61M1 sur l'Arduino
- SDMMC1 + FatFs (appels d'init non generes dans main, IRQ SDMMC1 prio 14),
  PM14 en open-drain ; I2S6_CK sur PA5 pour liberer PC12 (SDMMC1_CK)
- HAL UART retire ; USE_BSP_COM_FEATURE=0
- Audio preserve : ADF 4/16/24, prio IRQ 2, DMA canal 0 en priorite haute,
  GPDMA1_Channel2_IRQHandler deplace dans audio_irq.c (hors fichiers generes),
  BSP_MX_I2S6_Init (renommage dans le BSP pour eviter le conflit avec CubeMX)
- Middlewares/ST/ST67W6X_Network_Driver, FatFs et sources HAL SPI/SD ajoutes
  (driver ST67 pas encore integre au build)

Build et debug sous Linux :
- gcc/toolchain-env.sh, gdbserver.sh, arm-gdb.sh : outils de STM32CubeIDE par
  glob ; flash.sh les retrouve ; ruby_compat.rb pour Ruby >= 3.2 (TouchGFX)
- makefile_appli : sources SD/SPI/FatFs/audio_irq ; chmod +x des .out TouchGFX
- Objets de build (*.o, *.d, *.su) retires de l'index (deja dans .gitignore)
- AGENTS.md : toolchain Linux, configs VS Code (cppdbg et ST stlinkgdbtarget),
  pieges de l'extension ST (.settings/ide.store.json, preRunCommands reset)

Verifie sur carte : audio OK, debug Appli/Boot OK.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
thomasandClaude Sonnet 5.5 committed 2026-10-23 22:49:06 +02:00
1 parent b119a6abd7
commit 66bb319423
1092 files changed
+172728 -133236

No files matched your search

@@ -0,0 +1,126 @@
/**
******************************************************************************
* @file common_parser.h
* @author ST67 Application Team
* @brief This file provides the W6x common parser definitions
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef COMMON_PARSER_H
#define COMMON_PARSER_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include <inttypes.h>
#include <stdlib.h>
#include <stdint.h>
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/** @defgroup ST67W6X_Utilities_Common_Macros ST67W6X Utility Common Macros
* @ingroup ST67W6X_Utilities_Common
* @{
*/
#ifndef MAC2STR
/** MAC buffer to string macros */
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
/** MAC string format */
#define MACSTR "%02" PRIx16 ":%02" PRIx16 ":%02" PRIx16 ":%02" PRIx16 ":%02" PRIx16 ":%02" PRIx16
#endif /* MAC2STR */
#ifndef IP2STR
/** IP buffer to string macros */
#define IP2STR(a) (a)[0], (a)[1], (a)[2], (a)[3]
/** IP string format */
#define IPSTR "%" PRIu16 ".%" PRIu16 ".%" PRIu16 ".%" PRIu16
#endif /* IP2STR */
#ifndef NIP2STR
/** Macro to convert a uint32_t IP address to a string */
#define NIP2STR(ip) \
(uint8_t)(((ip) >> 24U) & 0xFFU), \
(uint8_t)(((ip) >> 16U) & 0xFFU), \
(uint8_t)(((ip) >> 8U) & 0xFFU), \
(uint8_t)((ip) & 0xFFU)
/** Macro to format the IP address as a string, same as IPSTR */
#define NIP2STR_FMT "%" PRIu16 ".%" PRIu16 ".%" PRIu16 ".%" PRIu16
#endif /* NIP2STR */
/** @} */
/* Exported functions ------------------------------------------------------- */
/** @defgroup ST67W6X_Utilities_Common_Functions ST67W6X Utility Common Functions
* @ingroup ST67W6X_Utilities_Common
* @{
*/
/**
* @brief Extract a hex number from a string
* @param ptr: pointer to string
* @param cnt: pointer to the number of parsed digit
* @retval Hex value or -1 on error
*/
int32_t Parser_StrToHex(char *ptr, uint8_t *cnt);
/**
* @brief Parses and returns number from string
* @param ptr: pointer to string
* @param cnt: pointer to the number of parsed digit
* @param value: pointer to the parsed value
* @retval integer value
*/
int32_t Parser_StrToInt(char *ptr, uint8_t *cnt, int32_t *value);
/**
* @brief Parses and returns IP address
* @param ptr: pointer to string
* @param ip: IP buffer
*/
void Parser_StrToIP(char *ptr, uint8_t ip[4]);
/**
* @brief Parses and returns MAC address
* @param ptr: pointer to string
* @param mac: MAC buffer
*/
void Parser_StrToMAC(char *ptr, uint8_t mac[6]);
/**
* @brief Convert char in Hex format to integer
* @param a: character to convert
* @retval integer value
*/
uint8_t Parser_Hex2Num(char a);
/**
* @brief Checks if the given IP or MAC address is valid
* @param buff: pointer to the address buffer (4 bytes for IP, 6 bytes for MAC)
* @param len: length of the address buffer (4 for IP, 6 for MAC)
* @return Operation status
*/
int32_t Parser_CheckValidAddress(uint8_t *buff, uint32_t len);
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* COMMON_PARSER_H */
@@ -0,0 +1,224 @@
/**
******************************************************************************
* @file logging.h
* @author ST67 Application Team
* @brief This file is part of the FreeRTOS logging interface
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/**
* Portions of this file are based on FreeRTOS, which is licensed under the MIT license as indicated below.
* See https://www.FreeRTOS.org/logging.html for more information.
*
* Reference source:
* https://github.com/FreeRTOS/FreeRTOS/blob/main/FreeRTOS-Plus/Source/Utilities/logging/logging.h
*/
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef LOGGING_H
#define LOGGING_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include "logging_config.h"
#include "logging_levels.h"
/* Exported macros -----------------------------------------------------------*/
/** @defgroup ST67W6X_Utilities_Logging_Macros ST67W6X Utility Logging Macros
* @ingroup ST67W6X_Utilities_Logging
* @{
*/
/**
* \def LogError( ... )
* Send a message to the log with level ::LOG_ERROR.
*/
/**
* \def LogErrorEx( line, file, ... )
* Send a message with line number and file name to the log with level ::LOG_ERROR.
*/
/**
* \def LogInfo( ... )
* Send a message to the log with level ::LOG_INFO.
*/
/**
* \def LogWarn( ... )
* Send a message to the log with level ::LOG_WARN.
*/
/**
* \def LogDebug( ... )
* Send a message to the log with level ::LOG_DEBUG.
*/
#ifndef LOG_LEVEL
/** Global verbosity level (LOG_NONE, LOG_ERROR, LOG_WARNING, LOG_INFO, LOG_DEBUG) */
#define LOG_LEVEL LOG_INFO
#endif /* LOG_LEVEL */
/* Get rid of extra C89 style parentheses generated by core FreeRTOS libraries */
/** Macro to remove the extra parentheses. */
#define REMOVE
/** Convert a macro parameter to a string. */
#define STR_( ... ) REM ## __VA_ARGS__
/** Convert a macro parameter to a string. */
#define STR( ... ) STR_( __VA_ARGS__ )
/** Removes at most one outer set of parentheses from its arguments. */
#define OVE( ... ) OVE __VA_ARGS__
/** Removes at most one outer set of parentheses from its arguments. */
#define REMOVE_PARENS( ... ) STR( OVE __VA_ARGS__ )
#if defined(__ICCARM__) || defined(__ICCRX__) /* For IAR Compiler */
#ifndef __FILE_NAME__
/* coverity[misra_c_2012_rule_21_1_violation : FALSE] */
/* coverity[misra_c_2012_rule_21_2_violation : FALSE] */
#define __FILE_NAME__ __FILE__
#endif /* ! __FILE_NAME__ */
#endif /* __ICCARM__ */
/**
* Disable definition of logging interface macros when generating doxygen output,
* to avoid conflict with documentation of macros at the end of the file.
*/
/* Check that LOG_LEVEL is defined and has a valid value. */
#if !defined( LOG_LEVEL ) || \
( ( LOG_LEVEL != LOG_NONE ) && \
( LOG_LEVEL != LOG_ERROR ) && \
( LOG_LEVEL != LOG_WARN ) && \
( LOG_LEVEL != LOG_INFO ) && \
( LOG_LEVEL != LOG_DEBUG ) )
#error "Please define LOG_LEVEL as either LOG_NONE, LOG_ERROR, LOG_WARN, LOG_INFO, or LOG_DEBUG."
#else
#if ( LOG_LEVEL >= LOG_ERROR )
#define LogError( ... ) vLoggingPrintf( LOG_ERROR, 1U, __LINE__, __FILE_NAME__, REMOVE_PARENS( __VA_ARGS__ ) )
#define LogErrorEx(line, file, ... ) vLoggingPrintf( LOG_ERROR, 1U, line, file, REMOVE_PARENS( __VA_ARGS__ ) )
#else
#define LogError( ... )
#define LogErrorEx(line, file, ... )
#endif /* ( LOG_LEVEL >= LOG_ERROR ) */
#if ( LOG_LEVEL >= LOG_WARN )
#define LogWarn( ... ) vLoggingPrintf( LOG_WARN, 1U, __LINE__, __FILE_NAME__, REMOVE_PARENS( __VA_ARGS__ ) )
#else
#define LogWarn( ... )
#endif /* ( LOG_LEVEL >= LOG_WARN ) */
#if ( LOG_LEVEL >= LOG_INFO )
#define LogInfo( ... ) vLoggingPrintf( LOG_INFO, 0U, 0U, (void *)0, REMOVE_PARENS( __VA_ARGS__ ) )
#else
#define LogInfo( ... )
#endif /* ( LOG_LEVEL >= LOG_INFO ) */
#if ( LOG_LEVEL >= LOG_DEBUG )
#define LogDebug( ... ) vLoggingPrintf( LOG_DEBUG, 0U, 0U, (void *)0, REMOVE_PARENS( __VA_ARGS__ ) )
#else
#define LogDebug( ... )
#endif /* ( LOG_LEVEL >= LOG_DEBUG ) */
#endif /* LOG_LEVEL */
/** @} */
/* Exported functions ------------------------------------------------------- */
/** @defgroup ST67W6X_Utilities_Logging_Functions ST67W6X Utility Logging Functions
* @ingroup ST67W6X_Utilities_Logging
* @{
*/
/**
* @brief Printf like function to print a message in the log. The application should not use it directly,
* but it must uses the log macros:
* - LogError
* - LogWarn
* - LogInfo
* - LogDebug
* @param log_level specifies the type of log entry
* @param metadata_print specifies if the metadata should be printed
* @param line_number specifies the line number in the compilation unit generating the log message. \
* is automatically generated by the log macros.
* @param p_file_name specifies the name of the file generating the log message. \
* is automatically generated by the log macros.
* @param p_format printf like format string
*/
void vLoggingPrintf(uint32_t log_level,
const uint8_t metadata_print,
const uint32_t line_number,
const char *const p_file_name,
const char *const p_format,
...);
/**
* @brief Initialize the logging service
* @param LogOutput_cb [IN] specifies the callback to output the message. \
* The callback shall not return until it is completed
* @return NULL in case of error, a pointer to the logging service otherwise
*/
void *vLoggingInit(void (*LogOutput_cb)(const char *message));
/**
* @brief Reset the logging service
*/
void vLoggingDeInit(void);
/**
* @brief Set the verbose level
* @param level [IN] the maximum log level to be printed
*/
void vLoggingSetVerbosity(uint32_t level);
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* LOGGING_H */
@@ -0,0 +1,136 @@
/**
******************************************************************************
* @file logging_levels.h
* @author ST67 Application Team
* @brief Defines the configuration constants for all logging verbosity levels
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/**
* Portions of this file are based on FreeRTOS, which is licensed under the MIT license as indicated below.
* See https://www.FreeRTOS.org/logging.html for more information.
*
* Reference source:
* https://github.com/FreeRTOS/FreeRTOS/blob/main/FreeRTOS-Plus/Source/Utilities/logging/logging_levels.h
*/
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef LOGGING_LEVELS_H
#define LOGGING_LEVELS_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Exported macros -----------------------------------------------------------*/
/** @addtogroup ST67W6X_Utilities_Logging_Macros
* @{
*/
/**
* Each part using the logging should specify a log level by setting LOG_LEVEL.
* If a LOG_LEVEL is not defined locally by the part, then it is used the global LOG_LEVEL.
* All log messages with a level at or below the specified level will be printed
* for that part.
* Currently, there are 4 log levels. In the order of lowest to highest, they are:
* - #LOG_NONE <br>
* @copybrief LOG_NONE
* - #LOG_ERROR <br>
* @copybrief LOG_ERROR
* - #LOG_WARN <br>
* @copybrief LOG_WARN
* - #LOG_INFO <br>
* @copybrief LOG_INFO
* - #LOG_DEBUG <br>
* @copybrief LOG_DEBUG
*/
/**
* @brief No log messages
* When LOG_LEVEL is #LOG_NONE, logging is disabled and no
* logging messages are printed.
*/
#define LOG_NONE 0
/**
* @brief Represents erroneous application state or event
* These messages describe the situations when a library encounters an error from
* which it cannot recover.
* @note These messages are printed when LOG_LEVEL is defined as either
* of #LOG_ERROR, #LOG_WARN, #LOG_INFO or #LOG_DEBUG.
*/
#define LOG_ERROR 1
/**
* @brief Message about an abnormal event
* These messages describe the situations when a library encounters
* abnormal event that may be indicative of an error. Libraries continue
* execution after logging a warning.
* @note These messages are printed when LOG_LEVEL is defined as either
* of #LOG_WARN, #LOG_INFO or #LOG_DEBUG.
*/
#define LOG_WARN 2
/**
* @brief A helpful, informational message
* These messages describe normal execution of a library. They provide
* the progress of the program at a coarse-grained level.
* @note These messages are printed when LOG_LEVEL is defined as either
* of #LOG_INFO or #LOG_DEBUG.
*/
#define LOG_INFO 3
/**
* @brief Detailed and excessive debug information
* Debug log messages are used to provide the
* progress of the program at a fine-grained level. These are mostly used
* for debugging and may contain excessive information such as internal
* variables, buffers, or other specific information.
* @note These messages are only printed when LOG_LEVEL is defined as
* #LOG_DEBUG.
*/
#define LOG_DEBUG 4
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* LOGGING_LEVELS_H */
@@ -0,0 +1,322 @@
/**
******************************************************************************
* @file shell.h
* @author ST67 Application Team
* @brief This file provides the definition of the Shell API
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/**
* Portions of this file are based on RT-Thread Development Team,
* which is licensed under the Apache-2.0 license as indicated below.
* See https://github.com/RT-Thread/rt-thread for more information.
*
* Reference source:
* https://github.com/RT-Thread/rt-thread/blob/master/components/finsh/shell.h
*/
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-06-02 Bernard Add finsh_get_prompt function declaration
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef SHELL_H
#define SHELL_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <stdbool.h>
#include "shell_default_config.h"
/* Exported constants --------------------------------------------------------*/
/** @defgroup ST67W6X_Utilities_Shell_Constants ST67W6X Utility Shell Constants
* @ingroup ST67W6X_Utilities_Shell
* @{
*/
/** @brief Shell no command found */
#define SHELL_STATUS_NO_COMMAND -255
/** @brief Shell unknown arguments */
#define SHELL_STATUS_UNKNOWN_ARGS -254
/** @brief Shell error code */
#define SHELL_STATUS_ERROR -1
/** @brief Shell success code */
#define SHELL_STATUS_OK 0
/** @brief Interrupt signal */
#define SHELL_SIGINT 1
/** @brief Default action */
#define SHELL_SIG_DFL ((shell_sig_func_ptr)0)
/** @brief Ignore action */
#define SHELL_SIG_IGN ((shell_sig_func_ptr)1)
/** @} */
/* Exported types ------------------------------------------------------------*/
/** @defgroup ST67W6X_Utilities_Shell_Types ST67W6X Utility Shell Types
* @ingroup ST67W6X_Utilities_Shell
* @{
*/
/** shell input status */
enum input_stat
{
WAIT_NORMAL, /*!< normal status */
WAIT_SPEC_KEY, /*!< wait special key */
WAIT_FUNC_KEY, /*!< wait function key */
WAIT_EXT_KEY, /*!< wait extended key */
};
/** shell command function typedef */
typedef int32_t (*cmd_function_t)(int32_t argc, char **argv);
/**
* @brief System call table
*/
typedef struct shell_syscall
{
const char *name; /*!< the name of system call */
#if (SHELL_USING_DESCRIPTION == 1)
const char *desc; /*!< description of system call */
#endif /* SHELL_USING_DESCRIPTION */
cmd_function_t func; /*!< the function address of system call */
} shell_syscall_t;
/**
* @brief Shell structure
*/
struct shell
{
/** shell status */
enum input_stat stat;
/** shell overwrite mode flag */
uint8_t overwrite_mode;
/** shell control mode flag */
uint8_t control_mode;
/** shell history command position */
uint16_t current_history;
/** shell history command count */
uint16_t history_count;
/** shell history command buffer */
char cmd_history[SHELL_HISTORY_LINES][SHELL_CMD_SIZE];
/** shell command buffer */
char line[SHELL_CMD_SIZE + 1];
/** shell cursor position on the line */
uint16_t line_position;
/** shell current position on the line */
uint16_t line_curpos;
/** shell prompt */
char *prompt_custom;
/** shell printf function */
void (*shell_printf_fn)(char *fmt, ...);
/** shell start of system call table */
shell_syscall_t *syscall_table_begin;
/** shell end of system call table */
shell_syscall_t *syscall_table_end;
};
/**
* @brief Shell queue internal typedef
*/
typedef struct QueueDefinition shell_queue_def_t;
/**
* @brief Shell queue handle typedef
*/
typedef shell_queue_def_t *shell_queue_handle_t;
/** @} */
/* Exported variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/** @defgroup ST67W6X_Utilities_Shell_Macros ST67W6X Utility Shell Macros
* @ingroup ST67W6X_Utilities_Shell
* @{
*/
/**
* \def SHELL_PRINTF( ... )
* Print standard output without color.
*/
/**
* \def SHELL_PROMPT( ... )
* Print prompt message with cyan color or without color according to the SHELL_USING_COLOR configuration.
*/
/**
* \def SHELL_DBG( ... )
* Print debug message with green color or without color according to the SHELL_USING_COLOR configuration.
*/
/**
* \def SHELL_CMD( ... )
* Print command with yellow color or without color according to the SHELL_USING_COLOR configuration.
*/
/**
* \def SHELL_E( ... )
* Print error message with red color or without color according to the SHELL_USING_COLOR configuration.
*/
/** Print output without color */
#define SHELL_PRINT_NOCOLOR(fmt, ...) \
do { \
struct shell *shell_hdl = shell_get_instance(); \
(void)shell_hdl->shell_printf_fn(fmt, ##__VA_ARGS__); \
SHELL_FLUSH_OUT; \
} while(false)
#ifndef SHELL_PRINTF
#define SHELL_PRINTF(fmt, ...) SHELL_PRINT_NOCOLOR(fmt, ##__VA_ARGS__)
#endif /* SHELL_PRINTF */
#if (SHELL_USING_COLOR == 1)
/*
* The color for terminal (foreground)
* BLACK 30
* RED 31
* GREEN 32
* YELLOW 33
* BLUE 34
* PURPLE 35
* CYAN 36
* WHITE 37
*/
/** Start colorized output */
#define SHELL_COLOR_HDR(n) shell_hdl->shell_printf_fn("\033[" #n "m")
/** End colorized output */
#define SHELL_COLOR_END shell_hdl->shell_printf_fn("\033[0m")
/** Print output with color */
#define SHELL_PRINT(color_n, fmt, ...) \
do { \
struct shell *shell_hdl = shell_get_instance(); \
SHELL_COLOR_HDR(color_n); \
(void)shell_hdl->shell_printf_fn(fmt, ##__VA_ARGS__); \
SHELL_FLUSH_OUT; \
SHELL_COLOR_END; \
} while(false)
#define SHELL_PROMPT(fmt, ...) SHELL_PRINT(36, fmt, ##__VA_ARGS__)
#define SHELL_DBG(fmt, ...) SHELL_PRINT(32, fmt, ##__VA_ARGS__)
#define SHELL_CMD(fmt, ...) SHELL_PRINT(33, fmt, ##__VA_ARGS__)
#define SHELL_E(fmt, ...) SHELL_PRINT(31, fmt, ##__VA_ARGS__)
#else /* SHELL_USING_COLOR */
#define SHELL_PROMPT(fmt, ...) SHELL_PRINT_NOCOLOR(fmt, ##__VA_ARGS__)
#define SHELL_DBG(fmt, ...) SHELL_PRINT_NOCOLOR(fmt, ##__VA_ARGS__)
#define SHELL_CMD(fmt, ...) SHELL_PRINT_NOCOLOR(fmt, ##__VA_ARGS__)
#define SHELL_E(fmt, ...) SHELL_PRINT_NOCOLOR(fmt, ##__VA_ARGS__)
#endif /* SHELL_USING_COLOR */
/**
* \def SHELL_CMD_EXPORT_ALIAS( ... )
* @brief This macro exports a command to module shell
* @param name the name of command
* @param cmd the alias of command
* @param desc the description of command, which will show in help
*/
#if (SHELL_ENABLE == 1)
/**
* \def SHELL_CMD_EXPORT_ALIAS_WITH_DESC( ... )
* @brief This macro exports a command to module shell with description
* @param name the name of command
* @param cmd the alias of command
* @param desc_str the description of command, which will show in help
*/
#if (SHELL_USING_DESCRIPTION == 1)
#define SHELL_CMD_EXPORT_ALIAS_WITH_DESC(name, cmd, desc_str) \
const char fsym_##cmd##_name[] __attribute__((section(".rodata.name"))) = #cmd; \
const char fsym_##cmd##_desc[] __attribute__((section(".rodata.name"))) = desc_str; \
__attribute__((used)) const struct shell_syscall fsym_##cmd __attribute__((section("FSymTab"))) = \
{ \
(fsym_##cmd##_name), \
fsym_##cmd##_desc, \
(cmd_function_t)&(name) \
};
#define SHELL_CMD_EXPORT_ALIAS(name, cmd, desc) SHELL_CMD_EXPORT_ALIAS_WITH_DESC(name, cmd, #desc)
#else
#define SHELL_CMD_EXPORT_ALIAS_WITH_DESC(name, cmd, desc_str) \
const char fsym_##cmd##_name[] __attribute__((section(".rodata.name"))) = #cmd; \
__attribute__((used)) const struct shell_syscall fsym_##cmd __attribute__((section("FSymTab"))) = \
{ \
(fsym_##cmd##_name), \
(cmd_function_t)&(name) \
};
#define SHELL_CMD_EXPORT_ALIAS(name, cmd, desc) SHELL_CMD_EXPORT_ALIAS_WITH_DESC(name, cmd, "")
#endif /* SHELL_USING_DESCRIPTION */
#else /* SHELL_ENABLE */
#define SHELL_CMD_EXPORT_ALIAS(name, cmd, desc)
#endif /* SHELL_ENABLE */
/** @} */
/* Exported functions ------------------------------------------------------- */
/** @addtogroup ST67W6X_Utilities_Shell_Functions
* @{
*/
/**
* @brief Initialize the shell based on FreeRTOS. It creates a task that read the input chars from the uart and parse
* the input using the upper layer shell API. The output of the shell is sent to the stream buffer ::tx_stream.
* @param shell_queue [IN] specifies the queue where to send all the output produced by the shell
*/
void shell_freertos_init(shell_queue_handle_t shell_queue);
/**
* @brief Deinitialize the shell. It stops the shell task and release all the resources used by the shell
*/
void shell_freertos_deinit(void);
/**
* @brief Callback called by the uart ISR when a new byte is received
* @param uart_rxbyte [IN] specifies the byte received.
*/
void shell_freertos_on_new_data(uint8_t uart_rxbyte);
/**
* @brief Get the shell instance
* @return shell instance
*/
struct shell *shell_get_instance(void);
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SHELL_H */
@@ -0,0 +1,152 @@
/**
******************************************************************************
* @file shell_default_config.h
* @author ST67 Application Team
* @brief This file provides default configuration for the Shell component
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef SHELL_DEFAULT_CONFIG_H
#define SHELL_DEFAULT_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include "shell_config.h"
/* Exported constants --------------------------------------------------------*/
/** @addtogroup ST67W6X_Utilities_Shell_Constants
* @{
*/
#ifndef SHELL_ENABLE
/** Enable the shell component */
#define SHELL_ENABLE 1
#endif /* SHELL_ENABLE */
#ifndef SHELL_CMD_LEVEL
/** Default shell commands list level (0: Minimal, 1: Full) */
#define SHELL_CMD_LEVEL 0
#endif /* SHELL_CMD_LEVEL */
#ifndef SHELL_DEFAULT_NAME
/** Default shell prompt string */
#define SHELL_DEFAULT_NAME "w61"
#endif /* SHELL_DEFAULT_NAME */
#ifndef SHELL_CONSOLEBUF_SIZE
/** Console buffer size */
#define SHELL_CONSOLEBUF_SIZE 128U
#endif /* SHELL_CONSOLEBUF_SIZE */
#ifndef SHELL_HISTORY_LINES
/** Shell history maximum lines */
#define SHELL_HISTORY_LINES 5U
#endif /* SHELL_HISTORY_LINES */
#ifndef SHELL_CMD_SIZE
/** Shell command maximum size */
#define SHELL_CMD_SIZE 120U
#endif /* SHELL_CMD_SIZE */
#ifndef SHELL_ARG_NUM
/** Shell argument maximum number */
#define SHELL_ARG_NUM 24U
#endif /* SHELL_ARG_NUM */
#ifndef SHELL_USING_WORD_OPERATION
/** Enable word operation support */
#define SHELL_USING_WORD_OPERATION 1
#endif /* SHELL_USING_WORD_OPERATION */
#ifndef SHELL_USING_FUNC_EXT
/** Enable function extension support */
#define SHELL_USING_FUNC_EXT 1
#endif /* SHELL_USING_FUNC_EXT */
#ifndef SHELL_USING_COLOR
/** Shell using color */
#define SHELL_USING_COLOR 1
#endif /* SHELL_USING_COLOR */
#ifndef SHELL_PRINT_STATUS
/** Print an additional status message at the end of the command execution */
#define SHELL_PRINT_STATUS 0
#endif /* SHELL_PRINT_STATUS */
#ifndef SHELL_FREERTOS_MAX_PRINT_STRING_LENGTH
/** Maximum length of the string to be printed */
#define SHELL_FREERTOS_MAX_PRINT_STRING_LENGTH 2000U
#endif /* SHELL_FREERTOS_MAX_PRINT_STRING_LENGTH */
#ifndef SHELL_FREERTOS_RX_BUFF_SIZE
/** Shell receive buffer size */
#define SHELL_FREERTOS_RX_BUFF_SIZE 128U
#endif /* SHELL_FREERTOS_RX_BUFF_SIZE */
#ifndef SHELL_FREERTOS_RX_THREAD_STACK_SIZE
/** Shell receive thread stack size */
#define SHELL_FREERTOS_RX_THREAD_STACK_SIZE 2048U
#endif /* SHELL_FREERTOS_RX_THREAD_STACK_SIZE */
#ifndef SHELL_FREERTOS_RX_THREAD_PRIO
/** Shell receive thread priority */
#define SHELL_FREERTOS_RX_THREAD_PRIO 5
#endif /* SHELL_FREERTOS_RX_THREAD_PRIO */
#ifndef SHELL_FLUSH_OUT
/** Flush the output */
#define SHELL_FLUSH_OUT do { (void)fflush(stdout); } while(false)
#endif /* SHELL_FLUSH_OUT */
#ifndef SHELL_USING_DESCRIPTION
/** Enable the shell command description */
#define SHELL_USING_DESCRIPTION 1
#endif /* SHELL_USING_DESCRIPTION */
#ifndef SHELL_HELP_MAX_COMPARED_NB_CHAR
/** Maximum number of characters to compare in the help command */
#define SHELL_HELP_MAX_COMPARED_NB_CHAR 10U
#endif /* SHELL_HELP_MAX_COMPARED_NB_CHAR */
#ifndef SHELL_HELP_DESC_SIZE
/** Shell help command description size */
#define SHELL_HELP_DESC_SIZE 110U
#endif /* SHELL_HELP_DESC_SIZE */
#ifndef SHELL_LOG
/** Print log message */
#define SHELL_LOG SHELL_DBG
#endif /* SHELL_LOG */
/* Memory allocator */
#ifndef SHELL_MALLOC
/** Shell memory allocator */
#define SHELL_MALLOC pvPortMalloc
#endif /* SHELL_MALLOC */
#ifndef SHELL_FREE
/** Shell memory deallocator */
#define SHELL_FREE vPortFree
#endif /* SHELL_FREE */
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SHELL_DEFAULT_CONFIG_H */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,489 @@
/**
******************************************************************************
* @file w6x_legacy.h
* @author ST67 Application Team
* @brief This file provides the legacy W6x core resources definitions
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef W6X_LEGACY_H
#define W6X_LEGACY_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/**
* @brief Write a file from the Host file system to the NCP file system
* @param filename: File name
* @return Operation status
*/
static inline W6X_Status_t W6X_FS_WriteFile(char *filename)
{
return W6X_FS_WriteFileByName(filename);
}
/**
* @brief Restore module default configuration
* @note If the ::W6X_WIFI_AUTOCONNECT is enabled, the Wi-Fi station credentials must be reconfigured
* through the ::W6X_WiFi_Connect function
* @return Operation status
*/
static inline W6X_Status_t W6X_RestoreDefaultConfig(void)
{
return W6X_Reset(1);
}
/**
* @brief Starts the NCP FWU process
* @param enable: 0 Terminate the FWU transmission. 1 Start the FWU transmission
* @return Operation status
*/
static inline W6X_Status_t W6X_OTA_Starts(uint32_t enable)
{
return W6X_FWU_Starts(enable);
}
/**
* @brief Finish the NCP FWU process which reboot the module to apply the new firmware
* @return Operation status
*/
static inline W6X_Status_t W6X_OTA_Finish(void)
{
return W6X_FWU_Finish();
}
/**
* @brief Send the firmware binary to the module
* @param buff: Buffer containing the firmware binary chunk
* @param len: Length of the firmware binary chunk
* @return Operation status
*/
static inline W6X_Status_t W6X_OTA_Send(uint8_t *buff, uint32_t len)
{
return W6X_FWU_Send(buff, len);
}
/**
* @brief Set the module in station mode
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_StartSta(void)
{
return W6X_WiFi_Station_Start();
}
#if (ST67_ARCH == W6X_ARCH_T01)
/**
* @brief This function set the Wi-Fi STA host name
* @param Hostname: Hostname to set
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_SetHostname(uint8_t Hostname[33])
{
return W6X_Net_SetHostname(Hostname);
}
/**
* @brief This function retrieves the Wi-Fi STA host name
* @param Hostname: Hostname to get
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_GetHostname(uint8_t Hostname[33])
{
return W6X_Net_GetHostname(Hostname);
}
/**
* @brief This function retrieves the Wi-Fi interface's IP address
* @param Ip_addr: IP address of the interface
* @param Gateway_addr: Gateway address of the interface
* @param Netmask_addr: Netmask address of the interface
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_GetStaIpAddress(uint8_t Ip_addr[4], uint8_t Gateway_addr[4],
uint8_t Netmask_addr[4])
{
return W6X_Net_Station_GetIPAddress(Ip_addr, Gateway_addr, Netmask_addr);
}
#endif /* (ST67_ARCH == W6X_ARCH_T01) */
/**
* @brief This function retrieves the Wi-Fi station MAC address
* @param mac: MAC address of the interface
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_GetStaMacAddress(uint8_t mac[6])
{
return W6X_WiFi_Station_GetMACAddress(mac);
}
#if (ST67_ARCH == W6X_ARCH_T01)
/**
* @brief This function set the Wi-Fi interface's IP address
* @param Ipaddr: IP address to set
* @param Gateway_addr: Gateway address to set
* @param Netmask_addr: Netmask address to set
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_SetStaIpAddress(uint8_t Ipaddr[4], uint8_t Gateway_addr[4],
uint8_t Netmask_addr[4])
{
return W6X_Net_Station_SetIPAddress(Ipaddr, Gateway_addr, Netmask_addr);
}
/**
* @brief This function retrieves the Wi-Fi DNS addresses
* @param Dns_enable: DNS enable status. Unused
* @param Dns1_addr: DNS1 address
* @param Dns2_addr: DNS2 address
* @param Dns3_addr: DNS3 address
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_GetDnsAddress(uint32_t *Dns_enable, uint8_t Dns1_addr[4], uint8_t Dns2_addr[4],
uint8_t Dns3_addr[4])
{
(void)Dns_enable; /* unused */
return W6X_Net_GetDnsAddress(Dns1_addr, Dns2_addr, Dns3_addr);
}
/**
* @brief This function set the Wi-Fi DNS addresses
* @param Dns_enable: DNS enable manually. Unused
* @param Dns1_addr: DNS1 address
* @param Dns2_addr: DNS2 address
* @param Dns3_addr: DNS3 address
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_SetDnsAddress(uint32_t *Dns_enable, uint8_t Dns1_addr[4], uint8_t Dns2_addr[4],
uint8_t Dns3_addr[4])
{
(void)Dns_enable; /* unused */
return W6X_Net_SetDnsAddress(Dns1_addr, Dns2_addr, Dns3_addr);
}
#endif /* (ST67_ARCH == W6X_ARCH_T01) */
/**
* @brief This function retrieves the Wi-Fi station state
* @param state: Station state
* @param connect_data: Connection data
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_GetStaState(W6X_WiFi_StaStateType_e *state, W6X_WiFi_Connect_t *connect_data)
{
return W6X_WiFi_Station_GetState(state, connect_data);
}
/**
* @brief Configure a Soft-AP
* @param ap_config: Soft-AP configuration
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_StartAp(W6X_WiFi_ApConfig_t *ap_config)
{
return W6X_WiFi_AP_Start(ap_config);
}
/**
* @brief Stop the Soft-AP
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_StopAp(void)
{
return W6X_WiFi_AP_Stop();
}
/**
* @brief Get the Soft-AP configuration
* @param ap_config: Soft-AP configuration
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_GetApConfig(W6X_WiFi_ApConfig_t *ap_config)
{
return W6X_WiFi_AP_GetConfig(ap_config);
}
/**
* @brief List the connected stations
* @param connected_sta: Connected stations structure
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_ListConnectedSta(W6X_WiFi_Connected_Sta_t *connected_sta)
{
return W6X_WiFi_AP_ListConnectedStations(connected_sta);
}
/**
* @brief Disconnect station from the Soft-AP
* @param mac: MAC address of the station to disconnect
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_DisconnectSta(uint8_t mac[6])
{
return W6X_WiFi_AP_DisconnectStation(mac);
}
/**
* @brief This function retrieves the Wi-Fi Soft-AP MAC address
* @param mac: MAC address of the interface
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_GetApMacAddress(uint8_t mac[6])
{
return W6X_WiFi_AP_GetMACAddress(mac);
}
#if (ST67_ARCH == W6X_ARCH_T01)
/**
* @brief Get the Soft-AP IP addresses
* @param Ipaddr: IP address of the Soft-AP
* @param Netmask_addr: Netmask address of the Soft-AP
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_GetApIpAddress(uint8_t Ipaddr[4], uint8_t Netmask_addr[4])
{
return W6X_Net_AP_GetIPAddress(Ipaddr, Netmask_addr);
}
/**
* @brief DHCP Client type enumeration
*/
typedef W6X_Net_DhcpType_e W6X_WiFi_DhcpType_e;
/**
* @brief Get the DHCP configuration
* @param State: pointer to the DHCP state
* @param lease_time: lease time
* @param start_ip: pointer to the start IP address
* @param end_ip: pointer to the end IP address
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_GetDhcp(W6X_WiFi_DhcpType_e *State, uint32_t *lease_time,
uint8_t start_ip[4], uint8_t end_ip[4])
{
return W6X_Net_GetDhcp(State, lease_time, start_ip, end_ip);
}
/**
* @brief Set the DHCP configuration
* @param State: DHCP state
* @param Operate: pointer to enable / disable DHCP
* @param lease_time: lease time
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_SetDhcp(W6X_WiFi_DhcpType_e *State, uint32_t *Operate, uint32_t lease_time)
{
return W6X_Net_SetDhcp(State, Operate, lease_time);
}
#endif /* (ST67_ARCH == W6X_ARCH_T01) */
/**
* @brief Setup Target Wake Time (TWT) for the Wi-Fi station
* @param twt_params: TWT parameters
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_SetupTWT(W6X_WiFi_TWT_Setup_Params_t *twt_params)
{
return W6X_WiFi_TWT_Setup(twt_params);
}
/**
* @brief Get Target Wake Time (TWT) status for the Wi-Fi station
* @param twt_status: Pointer to TWT flow status
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_GetTWTStatus(W6X_WiFi_TWT_Status_t *twt_status)
{
return W6X_WiFi_TWT_GetStatus(twt_status);
}
/**
* @brief Teardown Target Wake Time (TWT) for the Wi-Fi station
* @param twt_params: TWT parameters
* @return Operation status
*/
static inline W6X_Status_t W6X_WiFi_TeardownTWT(W6X_WiFi_TWT_Teardown_Params_t *twt_params)
{
return W6X_WiFi_TWT_Teardown(twt_params);
}
#if (ST67_ARCH == W6X_ARCH_T01)
/**
* @brief Get IP address from URL using DNS
* @param location: Host URL
* @param ipaddr: array of the IP address
* @return Operation status
*/
static inline W6X_Status_t W6X_Net_GetHostAddress(const char *location, uint8_t *ipaddr)
{
return W6X_Net_ResolveHostAddress(location, ipaddr);
}
/**
* @brief Query date string from SNTP, the used format is asctime style time
* @param Time: Buffer to store time
* @return Operation status
*/
static inline W6X_Status_t W6X_Net_GetTime(uint8_t *Time)
{
W6X_Status_t ret;
W6X_Net_Time_t time_s;
ret = W6X_Net_SNTP_GetTime(&time_s);
if (ret != W6X_STATUS_OK)
{
return ret;
}
for (uint32_t i = 0; i < sizeof(time_s.raw); i++)
{
Time[i] = time_s.raw[i];
}
return W6X_STATUS_OK;
}
/**
* @brief Get current SNTP status, timezone and servers
* @param Enable: SNTP usage status
* @param Timezone: Configured Timezone
* @param SntpServer1: Configured Primary SNTP Server URL
* @param SntpServer2: Configured Secondary SNTP Server URL
* @param SntpServer3: Configured Third SNTP Server URL
* @return Operation status
*/
static inline W6X_Status_t W6X_Net_GetSNTPConfiguration(uint8_t *Enable, int16_t *Timezone, uint8_t *SntpServer1,
uint8_t *SntpServer2, uint8_t *SntpServer3)
{
return W6X_Net_SNTP_GetConfiguration(Enable, Timezone, SntpServer1, SntpServer2, SntpServer3);
}
/**
* @brief Set SNTP status, timezone and servers
* @param Enable: Enable/Disable SNTP usage
* @param Timezone: Timezone to set in one of the 2 following formats:
* - range [-12,14]: marks most of the time zones by offset from UTC in whole hours
* - HHmm with HH in range[-12,+14] and mm in range [00,59]
* @param SntpServer1: Primary SNTP Server URL to use
* @param SntpServer2: Secondary SNTP Server URL to use
* @param SntpServer3: Third SNTP Server URL to use
* @return Operation status
*/
static inline W6X_Status_t W6X_Net_SetSNTPConfiguration(uint8_t Enable, int16_t Timezone, uint8_t *SntpServer1,
uint8_t *SntpServer2, uint8_t *SntpServer3)
{
return W6X_Net_SNTP_SetConfiguration(Enable, Timezone, SntpServer1, SntpServer2, SntpServer3);
}
/**
* @brief Get SNTP Synchronization interval
* @param Interval: Configured SNTP time synchronization interval, in seconds
* @return Operation status
*/
static inline W6X_Status_t W6X_Net_GetSNTPInterval(uint16_t *Interval)
{
return W6X_Net_SNTP_GetInterval(Interval);
}
/**
* @brief Set SNTP Synchronization interval
* @param Interval: SNTP time synchronization interval, in seconds (range:[15,4294967])
* @return Operation status
*/
static inline W6X_Status_t W6X_Net_SetSNTPInterval(uint16_t Interval)
{
return W6X_Net_SNTP_SetInterval(Interval);
}
/**
* @brief Add the credential to the TLS context
* @param tag: Tag of the TLS context (must be unique by credential file)
* @param type: Type of the credential
* @param cred: Credential to add
* @param credlen: Length of the credential
* @return Operation status
*/
static inline int32_t W6X_Net_Tls_Credential_Add(uint32_t tag, W6X_Net_Tls_Credential_e type,
const void *cred, size_t credlen)
{
return W6X_Net_TLS_Credential_AddByName(tag, type, (const char *)cred);
}
/**
* @brief Delete the credential from the TLS context
* @param tag: Tag of the TLS context
* @param type: Type of the credential
* @return Operation status
*/
static inline int32_t W6X_Net_Tls_Credential_Delete(uint32_t tag, W6X_Net_Tls_Credential_e type)
{
return W6X_Net_TLS_Credential_Delete(tag, type);
}
#endif /* (ST67_ARCH == W6X_ARCH_T01) */
/**
* @brief Indicate the Characteristic Value from the Server to a Client
* @param service_index: index of the service containing characteristic to indicate
* @param char_index: index of the characteristic to indicate
* @param data: pointer to the data to indicate
* @param req_len: length of the data to indicate
* @param sent_data_len: length of the data sent
* @param timeout: timeout in ms
* @return Operation status
*/
static inline W6X_Status_t W6X_Ble_ServerSendIndication(uint8_t service_index, uint8_t char_index,
void *data, uint32_t req_len, uint32_t *sent_data_len,
uint32_t timeout)
{
uint8_t conn_handle = 0;
return W6X_Ble_ServerIndicate(conn_handle, service_index, char_index,
data, req_len, sent_data_len, timeout);
}
/**
* @brief Notify the Characteristic Value from the Server to a Client
* @param service_index: index of the service containing characteristic to notify
* @param char_index: index of the characteristic to notify
* @param data: pointer to the data to notify
* @param req_len: length of the data to notify
* @param sent_data_len: length of the data sent
* @param timeout: timeout in ms
* @return Operation status
*/
static inline W6X_Status_t W6X_Ble_ServerSendNotification(uint8_t service_index, uint8_t char_index,
void *data, uint32_t req_len, uint32_t *sent_data_len,
uint32_t timeout)
{
uint8_t conn_handle = 0;
return W6X_Ble_ServerNotify(conn_handle, service_index, char_index,
data, req_len, sent_data_len, timeout);
}
/**
* @brief BLE enter remote passkey
* @param conn_handle: BLE connection handle
* @param passkey: BLE security passkey
* @return Operation status
*/
static inline W6X_Status_t W6X_Ble_SecuritySetPassKey(uint8_t conn_handle, uint32_t passkey)
{
return W6X_Ble_SecurityEnterRemotePassKey(conn_handle, passkey);
}
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* W6X_LEGACY_H */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,67 @@
/**
******************************************************************************
* @file w6x_version.h
* @author ST67 Application Team
* @brief This file provides the version of W6x_Network_Driver
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef W6X_VERSION_H
#define W6X_VERSION_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Exported constants --------------------------------------------------------*/
/** @addtogroup ST67W6X_API_System_Public_Constants
* @{
*/
#define W6X_VERSION_MAIN 1 /*!< [31:24] main version */
#define W6X_VERSION_SUB1 3 /*!< [23:16] sub1 version */
#define W6X_VERSION_SUB2 0 /*!< [15:8] sub2 version */
#define W6X_MAIN_SHIFT 24 /*!< main version shift */
#define W6X_SUB1_SHIFT 16 /*!< sub1 version shift */
#define W6X_SUB2_SHIFT 8 /*!< sub2 version shift */
/** ST67W61_Network_Driver version */
#define W6X_VERSION ((W6X_VERSION_MAIN << W6X_MAIN_SHIFT)\
|(W6X_VERSION_SUB1 << W6X_SUB1_SHIFT)\
|(W6X_VERSION_SUB2 << W6X_SUB2_SHIFT))
/** @} */
/* Exported macros -----------------------------------------------------------*/
/** @defgroup ST67W6X_API_System_Public_Macros ST67W6X System Macros
* @ingroup ST67W6X_API_System
* @{
*/
/** ST67W61_Network_Driver version preprocessor macro */
#define XSTR(x) #x
/** ST67W61_Network_Driver version preprocessor macro */
#define MSTR(x) XSTR(x)
/** ST67W61_Network_Driver version string */
#define W6X_VERSION_STR MSTR(W6X_VERSION_MAIN) "." MSTR(W6X_VERSION_SUB1) "." MSTR(W6X_VERSION_SUB2)
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* W6X_VERSION_H */
@@ -0,0 +1,925 @@
/**
******************************************************************************
* @file w6x_ble.c
* @author ST67 Application Team
* @brief This file provides code for W6x BLE API
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <inttypes.h>
#include <string.h>
#include "w6x_api.h" /* Prototypes of the functions implemented in this file */
#include "w61_at_api.h" /* Prototypes of the functions called by this file */
#include "w6x_internal.h"
#include "w61_io.h" /* Prototypes of the BUS functions to be registered */
/* Global variables ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup ST67W6X_Private_BLE_Macros ST67W6X BLE Macros
* @ingroup ST67W6X_Private_BLE
* @{
*/
#ifndef BDADDR2STR
/** BD Address buffer to string macros */
#define BDADDR2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#endif /* BDADDR2STR */
#ifndef BDADDRSTR
/** BD address string format */
#define BDADDRSTR "%02" PRIx16 ":%02" PRIx16 ":%02" PRIx16 ":%02" PRIx16 ":%02" PRIx16 ":%02" PRIx16
#endif /* BDADDRSTR */
#ifndef UUID128TOSTR
/** 128-bit UUID buffer to string macros */
#define UUID128TOSTR(a) \
(a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5], (a)[6], (a)[7], \
(a)[8], (a)[9], (a)[10], (a)[11], (a)[12], (a)[13], (a)[14], (a)[15]
#endif /* UUID128TOSTR */
#ifndef UUID128STR
/** 128-bit UUID string format */
#define UUID128STR \
"%02" PRIx16 "%02" PRIx16 "%02" PRIx16 "%02" PRIx16 "%02" PRIx16 "%02" PRIx16 "%02" PRIx16 "%02" PRIx16 \
"%02" PRIx16 "%02" PRIx16 "%02" PRIx16 "%02" PRIx16 "%02" PRIx16 "%02" PRIx16 "%02" PRIx16 "%02" PRIx16
#endif /* UUID128STR */
/** @} */
/* Private variables ---------------------------------------------------------*/
/** @defgroup ST67W6X_Private_BLE_Variables ST67W6X BLE Variables
* @ingroup ST67W6X_Private_BLE
* @{
*/
static W61_Object_t *W6X_Ble_drv_obj = NULL; /*!< Global W61 context pointer */
#if (W6X_ASSERT_ENABLE == 1)
/** W6X BLE init error string */
static const char W6X_Ble_Uninit_str[] = "W6X BLE module not initialized";
#endif /* W6X_ASSERT_ENABLE */
/** BLE Connection Role string */
static const char *const W6X_Ble_Role_str[] =
{
"Central", "Peripheral", "Unknown"
};
/** @} */
/* Private function prototypes -----------------------------------------------*/
/** @defgroup ST67W6X_Private_BLE_Functions ST67W6X BLE Functions
* @ingroup ST67W6X_Private_BLE
* @{
*/
/**
* @brief BLE callback function
* @param event_id: event ID
* @param event_args: event arguments
*/
static void W6X_Ble_cb(W61_event_id_t event_id, void *event_args);
/**
* @brief Print Services and Characteristics information
* @param ServicesTable: Table of services and Characteristics to display
*/
static void W6X_Ble_PrintServicesAndCharacteristics(W6X_Ble_Service_t ServicesTable[]);
/** @} */
/* Functions Definition ------------------------------------------------------*/
/** @addtogroup ST67W6X_API_BLE_Public_Functions
* @{
*/
W6X_Status_t W6X_Ble_GetInitMode(W6X_Ble_Mode_e *mode)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Get the BLE initialization mode */
return TranslateErrorStatus(W61_Ble_GetInitMode(W6X_Ble_drv_obj, (W61_Ble_Mode_e *) mode));
}
W6X_Status_t W6X_Ble_Init(W6X_Ble_Mode_e mode, uint8_t *recv_data, size_t max_len)
{
W6X_Status_t ret = W6X_STATUS_ERROR;
W6X_App_Cb_t *p_cb_handler;
W6X_Ble_Mode_e current_mode;
uint32_t ps_mode = 0;
uint32_t clock_source = 0;
char device_name[W6X_BLE_DEVICE_NAME_SIZE + 1] = {0};
/* Get the global W61 context pointer */
W6X_Ble_drv_obj = W61_ObjGet();
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Obj_Null_str);
p_cb_handler = W6X_GetCbHandler(); /* Check that application callback is registered */
if ((p_cb_handler == NULL) || (p_cb_handler->APP_ble_cb == NULL))
{
BLE_LOG_ERROR("Please register the APP callback before initializing the module\n");
return ret;
}
ret = W6X_GetPowerMode(&ps_mode);
if (ret != W6X_STATUS_OK)
{
BLE_LOG_ERROR("Get Power Mode failed\n");
return ret;
}
if (ps_mode == 1U)
{
/* Low Power Mode is enabled */
/* Ensure current W61 clock is correctly setup to support BLE in low power */
ret = TranslateErrorStatus(W61_GetClockSource(W6X_Ble_drv_obj, &clock_source));
if (ret != W6X_STATUS_OK)
{
BLE_LOG_ERROR("Get W61 clock source failed\n");
return ret;
}
/* External oscillator must be used to support BLE in Low Power */
if (clock_source == 1U)
{
BLE_LOG_WARN("External Clock oscillator must be used to support BLE in power save mode\n");
ret = W6X_SetPowerMode(0); /* Disable low power */
if (ret != W6X_STATUS_OK)
{
BLE_LOG_ERROR("Disable power save mode failed\n");
return ret;
}
BLE_LOG_WARN("Power save disabled!\n");
}
}
/* Register W61 driver callbacks */
(void)W61_RegisterULcb(W6X_Ble_drv_obj,
NULL,
NULL,
NULL,
NULL,
W6X_Ble_cb);
/* Initialize BLE Data buffer */
ret = TranslateErrorStatus(W61_Ble_Init(W6X_Ble_drv_obj, (uint8_t) mode, recv_data, (uint32_t)max_len));
if (W6X_STATUS_OK != ret)
{
goto _err;
}
ret = W6X_Ble_GetInitMode(&current_mode); /* Check if the BLE mode is correctly set */
if ((W6X_STATUS_OK == ret) && (current_mode != mode))
{
ret = W6X_STATUS_ERROR; /* Error: BLE mode not correctly set */
goto _err;
}
/* Save the BLE mode */
W6X_Ble_drv_obj->BleCtx.NetSettings.Mode = (W61_Ble_Mode_e)mode;
/* Set device name */
(void)strncpy(device_name, W6X_BLE_HOSTNAME, W6X_BLE_DEVICE_NAME_SIZE);
device_name[W6X_BLE_DEVICE_NAME_SIZE] = '\0'; /* Ensure null termination */
if (W6X_Ble_SetDeviceName(device_name) != W6X_STATUS_OK)
{
BLE_LOG_ERROR("Failed to set device name\n");
ret = W6X_STATUS_ERROR;
goto _err;
}
/* Update BLE state */
W6X_Ble_drv_obj->ResetCfg.Ble_status = W61_MODULE_STATE_INIT;
return W6X_STATUS_OK;
_err:
W6X_Ble_DeInit(); /* Deinitialize BLE in case of failure */
return ret;
}
void W6X_Ble_DeInit(void)
{
if (W6X_Ble_drv_obj == NULL)
{
return; /* Nothing to do */
}
(void)W61_Ble_DeInit(W6X_Ble_drv_obj); /* Deinitialize BLE */
W6X_Ble_drv_obj->ResetCfg.Ble_status = W61_MODULE_STATE_NOT_INIT; /* Update BLE state */
W6X_Ble_drv_obj = NULL; /* Reset the global pointer */
}
W6X_Status_t W6X_Ble_SetRecvDataPtr(uint8_t *recv_data, uint32_t recv_data_buf_size)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Update the BLE Data buffer */
return TranslateErrorStatus(W61_Ble_SetRecvDataPtr(W6X_Ble_drv_obj, recv_data, recv_data_buf_size));
}
W6X_Status_t W6X_Ble_SetTxPower(uint32_t power)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Set BLE Tx Power */
return TranslateErrorStatus(W61_Ble_SetTxPower(W6X_Ble_drv_obj, power));
}
W6X_Status_t W6X_Ble_GetTxPower(uint32_t *power)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Get BLE Tx Power */
return TranslateErrorStatus(W61_Ble_GetTxPower(W6X_Ble_drv_obj, power));
}
W6X_Status_t W6X_Ble_AdvStart(void)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Start BLE advertising */
return TranslateErrorStatus(W61_Ble_AdvStart(W6X_Ble_drv_obj));
}
W6X_Status_t W6X_Ble_AdvStop(void)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Stop BLE advertising */
return TranslateErrorStatus(W61_Ble_AdvStop(W6X_Ble_drv_obj));
}
W6X_Status_t W6X_Ble_GetBDAddress(uint8_t bd_addr[6])
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Get the BD address */
return TranslateErrorStatus(W61_Ble_GetBDAddress(W6X_Ble_drv_obj, bd_addr));
}
W6X_Status_t W6X_Ble_Disconnect(uint32_t conn_handle)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Disconnect BLE */
return TranslateErrorStatus(W61_Ble_Disconnect(W6X_Ble_drv_obj, conn_handle));
}
W6X_Status_t W6X_Ble_ExchangeMTU(uint32_t conn_handle)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Exchange BLE MTU length */
return TranslateErrorStatus(W61_Ble_ExchangeMTU(W6X_Ble_drv_obj, conn_handle));
}
W6X_Status_t W6X_Ble_SetBdAddress(const uint8_t bd_addr[6])
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Set the BD address */
return TranslateErrorStatus(W61_Ble_SetBDAddress(W6X_Ble_drv_obj, bd_addr));
}
W6X_Status_t W6X_Ble_SetDeviceName(char name[W6X_BLE_DEVICE_NAME_SIZE])
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Set the host name */
return TranslateErrorStatus(W61_Ble_SetDeviceName(W6X_Ble_drv_obj, name));
}
W6X_Status_t W6X_Ble_GetDeviceName(char device_name[W6X_BLE_DEVICE_NAME_SIZE])
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Get the host name */
return TranslateErrorStatus(W61_Ble_GetDeviceName(W6X_Ble_drv_obj, device_name));
}
W6X_Status_t W6X_Ble_SetAdvData(const char *adv_data)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Set the advertising data */
return TranslateErrorStatus(W61_Ble_SetAdvData(W6X_Ble_drv_obj, adv_data));
}
W6X_Status_t W6X_Ble_SetScanRespData(const char *scan_resp_data)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Set the scan response data */
return TranslateErrorStatus(W61_Ble_SetScanRespData(W6X_Ble_drv_obj, scan_resp_data));
}
W6X_Status_t W6X_Ble_SetAdvParam(uint32_t adv_int_min, uint32_t adv_int_max,
W6X_Ble_AdvType_e adv_type, W6X_Ble_AdvChannel_e adv_channel)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Set advertising parameters */
return TranslateErrorStatus(W61_Ble_SetAdvParam(W6X_Ble_drv_obj, adv_int_min, adv_int_max,
(uint8_t)adv_type, (uint8_t)adv_channel));
}
W6X_Status_t W6X_Ble_GetAdvParam(uint32_t *adv_int_min, uint32_t *adv_int_max,
W6X_Ble_AdvType_e *adv_type, W6X_Ble_AdvChannel_e *channel_map)
{
W6X_Status_t ret;
uint32_t AdvType_tmp;
uint32_t ChannelMap_tmp;
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Get advertising parameters */
ret = TranslateErrorStatus(W61_Ble_GetAdvParam(W6X_Ble_drv_obj, adv_int_min, adv_int_max, &AdvType_tmp,
&ChannelMap_tmp));
if (ret == W6X_STATUS_OK)
{
/* Return the advertising parameters */
*adv_type = (W6X_Ble_AdvType_e)AdvType_tmp;
*channel_map = (W6X_Ble_AdvChannel_e)ChannelMap_tmp;
}
return ret;
}
W6X_Status_t W6X_Ble_SetConnParam(uint32_t conn_handle, uint32_t conn_int_min,
uint32_t conn_int_max, uint32_t latency, uint32_t timeout)
{
W6X_Status_t ret = W6X_STATUS_ERROR;
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Check the connection interval range */
if ((conn_int_min < 0x6U) || (conn_int_min > 0xC80U) || (conn_int_max < 0x6U) || (conn_int_max > 0xC80U) ||
(conn_int_max < conn_int_min))
{
BLE_LOG_ERROR("Invalid connection interval values\n");
return ret;
}
/* Check the latency */
if (latency > 0x1F3U) /* 499 */
{
BLE_LOG_ERROR("Invalid Latency value\n");
return ret;
}
/* Check the timeout */
if ((timeout < 0xAU) || (timeout > 0xC80U)) /* 10ms to 32s */
{
BLE_LOG_ERROR("Invalid timeout value\n");
return ret;
}
/* Set Connection parameters */
return TranslateErrorStatus(W61_Ble_SetConnParam(W6X_Ble_drv_obj, conn_handle, conn_int_min, conn_int_max,
latency, timeout));
}
W6X_Status_t W6X_Ble_GetConnParam(uint32_t *conn_handle, uint32_t *conn_int_min,
uint32_t *conn_int_max, uint32_t *conn_int_current,
uint32_t *latency, uint32_t *timeout)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Get Connection parameters */
return TranslateErrorStatus(W61_Ble_GetConnParam(W6X_Ble_drv_obj, conn_handle, conn_int_min, conn_int_max,
conn_int_current, latency, timeout));
}
W6X_Status_t W6X_Ble_GetConn(uint32_t *conn_handle, uint8_t remote_bd_addr[6])
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Get Connection information */
return TranslateErrorStatus(W61_Ble_GetConn(W6X_Ble_drv_obj, conn_handle, remote_bd_addr));
}
W6X_Status_t W6X_Ble_Connect(uint32_t conn_handle, uint8_t remote_bd_addr[6])
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Connect to a remote device */
return TranslateErrorStatus(W61_Ble_Connect(W6X_Ble_drv_obj, conn_handle, remote_bd_addr));
}
W6X_Status_t W6X_Ble_StartScan(W6X_Ble_Scan_Result_cb_t scan_result_cb)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
NULL_ASSERT(scan_result_cb, "Invalid callback");
/* Set the scan callback */
W6X_Ble_drv_obj->BleCtx.scan_done_cb = (W61_Ble_Scan_Result_cb_t)scan_result_cb;
/* Start the scan */
return TranslateErrorStatus(W61_Ble_Scan(W6X_Ble_drv_obj, 1));
}
void W6X_Ble_Print_Scan(W6X_Ble_Scan_Result_t *scan_results)
{
NULL_ASSERT_VOID(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
if ((scan_results == NULL) || (scan_results->Detected_Peripheral == NULL))
{
return;
}
/* Print the scan results */
for (uint32_t count = 0; count < scan_results->Count; count++)
{
/* Print the mandatory fields from the scan results */
BLE_LOG_INFO("Scanned device: Addr : " BDADDRSTR ", RSSI : %" PRIi16 " %s\n",
BDADDR2STR(scan_results->Detected_Peripheral[count].BDAddr),
scan_results->Detected_Peripheral[count].RSSI, scan_results->Detected_Peripheral[count].DeviceName);
vTaskDelay(pdMS_TO_TICKS(15)); /* Wait few ms to avoid logging buffer overflow */
}
}
W6X_Status_t W6X_Ble_StopScan(void)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Stop the scan */
return TranslateErrorStatus(W61_Ble_Scan(W6X_Ble_drv_obj, 0));
}
W6X_Status_t W6X_Ble_SetScanParam(W6X_Ble_ScanType_e scan_type, W6X_Ble_AddrType_e own_addr_type,
W6X_Ble_FilterPolicy_e filter_policy, uint32_t scan_interval, uint32_t scan_window)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Set scan parameters */
return TranslateErrorStatus(W61_Ble_SetScanParam(W6X_Ble_drv_obj, (uint8_t) scan_type, (uint8_t) own_addr_type,
(uint8_t) filter_policy, scan_interval, scan_window));
}
W6X_Status_t W6X_Ble_GetScanParam(W6X_Ble_ScanType_e *scan_type, W6X_Ble_AddrType_e *addr_type,
W6X_Ble_FilterPolicy_e *scan_filter, uint32_t *scan_interval, uint32_t *scan_window)
{
W6X_Status_t ret;
uint32_t ScanType_tmp = 0;
uint32_t AddrType_tmp = 0;
uint32_t ScanFilter_tmp = 0;
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Get scan parameters */
ret = TranslateErrorStatus(W61_Ble_GetScanParam(W6X_Ble_drv_obj, &ScanType_tmp, &AddrType_tmp,
&ScanFilter_tmp, scan_interval, scan_window));
if (ret == W6X_STATUS_OK)
{
/* Return the scan parameters */
*scan_type = (W6X_Ble_ScanType_e)ScanType_tmp;
*addr_type = (W6X_Ble_AddrType_e)AddrType_tmp;
*scan_filter = (W6X_Ble_FilterPolicy_e)ScanFilter_tmp;
}
return ret;
}
W6X_Status_t W6X_Ble_SetDataLength(uint32_t conn_handle, uint32_t tx_bytes, uint32_t tx_trans_time)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Set the data length */
return TranslateErrorStatus(W61_Ble_SetDataLength(W6X_Ble_drv_obj, conn_handle, tx_bytes, tx_trans_time));
}
/* GATT Server APIs */
W6X_Status_t W6X_Ble_CreateService(uint8_t service_index, const char *service_uuid, uint8_t uuid_type)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
if (service_index > (W6X_BLE_MAX_CREATED_SERVICE_NBR - 1U))
{
BLE_LOG_ERROR("Invalid service index, must be less than %" PRIi32 "\n", W6X_BLE_MAX_CREATED_SERVICE_NBR - 1U);
return W6X_STATUS_ERROR;
}
/* Create a service */
return TranslateErrorStatus(W61_Ble_CreateService(W6X_Ble_drv_obj, service_index, service_uuid, uuid_type));
}
W6X_Status_t W6X_Ble_DeleteService(uint8_t service_index)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Delete a service */
return TranslateErrorStatus(W61_Ble_DeleteService(W6X_Ble_drv_obj, service_index));
}
W6X_Status_t W6X_Ble_CreateCharacteristic(uint8_t service_index, uint8_t char_index, const char *char_uuid,
uint8_t uuid_type, uint8_t char_property, uint8_t char_permission)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
if (char_index > (W6X_BLE_MAX_CHAR_NBR - 1U))
{
BLE_LOG_ERROR("Invalid characteristic index, must be less than %" PRIi32 "\n", W6X_BLE_MAX_CHAR_NBR - 1U);
return W6X_STATUS_ERROR;
}
/* Create a characteristic */
return TranslateErrorStatus(W61_Ble_CreateCharacteristic(W6X_Ble_drv_obj, service_index, char_index, char_uuid,
uuid_type, char_property, char_permission));
}
W6X_Status_t W6X_Ble_GetServicesAndCharacteristics(W6X_Ble_Service_t services_table[])
{
W6X_Status_t ret = W6X_STATUS_ERROR;
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Get services */
for (uint8_t srv_idx = 0; srv_idx < W61_BLE_MAX_CREATED_SERVICE_NBR; srv_idx++)
{
/* Get the service information */
ret = TranslateErrorStatus(W61_Ble_GetService(W6X_Ble_drv_obj,
(W61_Ble_Service_t *)(&services_table[srv_idx]),
srv_idx));
if ((ret != W6X_STATUS_OK) || (services_table[srv_idx].service_idx == (W61_BLE_MAX_CREATED_SERVICE_NBR + 1U)))
{
/* No more services */
break;
}
/* Get characteristics for each service */
for (uint8_t char_idx = 0; char_idx < W6X_BLE_MAX_CHAR_NBR; char_idx++)
{
ret = TranslateErrorStatus(
W61_Ble_GetCharacteristic(W6X_Ble_drv_obj,
(W61_Ble_Characteristic_t *)(&services_table[srv_idx].charac[char_idx]),
srv_idx, char_idx));
if ((ret != W6X_STATUS_OK) || (services_table[srv_idx].charac[char_idx].char_idx == (W6X_BLE_MAX_CHAR_NBR + 1U)))
{
/* No more characteristics for this service */
break;
}
}
}
if (ret == W6X_STATUS_OK)
{
W6X_Ble_PrintServicesAndCharacteristics(services_table);
}
return ret;
}
W6X_Status_t W6X_Ble_RegisterCharacteristics(void)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Register characteristics */
return TranslateErrorStatus(W61_Ble_RegisterCharacteristics(W6X_Ble_drv_obj));
}
W6X_Status_t W6X_Ble_ServerNotify(uint8_t conn_handle, uint8_t service_index, uint8_t char_index,
void *data, uint32_t req_len, uint32_t *sent_data_len, uint32_t timeout)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Send a notification */
return TranslateErrorStatus(W61_Ble_ServerSendNotification(W6X_Ble_drv_obj, conn_handle, service_index, char_index,
(uint8_t *)data, req_len, sent_data_len, timeout));
}
W6X_Status_t W6X_Ble_ServerIndicate(uint8_t conn_handle, uint8_t service_index, uint8_t char_index,
void *data, uint32_t req_len, uint32_t *sent_data_len, uint32_t timeout)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Send an indication */
return TranslateErrorStatus(W61_Ble_ServerSendIndication(W6X_Ble_drv_obj, conn_handle, service_index, char_index,
(uint8_t *)data, req_len, sent_data_len, timeout));
}
W6X_Status_t W6X_Ble_ServerSetReadData(uint8_t service_index, uint8_t char_index, void *data, uint32_t req_len,
uint32_t *sent_data_len, uint32_t timeout)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Set the data to read */
return TranslateErrorStatus(W61_Ble_ServerSetReadData(W6X_Ble_drv_obj, service_index, char_index, (uint8_t *)data,
req_len, sent_data_len, timeout));
}
/* GATT Client APIs */
W6X_Status_t W6X_Ble_RemoteServiceDiscovery(uint8_t conn_handle)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Discover services of a remote device */
return TranslateErrorStatus(W61_Ble_RemoteServiceDiscovery(W6X_Ble_drv_obj, conn_handle));
}
W6X_Status_t W6X_Ble_RemoteCharDiscovery(uint8_t conn_handle, uint8_t service_index)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Discover characteristics of a remote device */
return TranslateErrorStatus(W61_Ble_RemoteCharDiscovery(W6X_Ble_drv_obj, conn_handle, service_index));
}
W6X_Status_t W6X_Ble_ClientWriteData(uint8_t conn_handle, uint8_t service_index, uint8_t char_index,
void *data, uint32_t req_len, uint32_t *sent_data_len, uint32_t timeout)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Write data to a characteristic */
return TranslateErrorStatus(W61_Ble_ClientWriteData(W6X_Ble_drv_obj, conn_handle, service_index, char_index,
(uint8_t *)data, req_len, sent_data_len, timeout));
}
W6X_Status_t W6X_Ble_ClientReadData(uint8_t conn_handle, uint8_t service_index, uint8_t char_index)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Read data from a characteristic */
return TranslateErrorStatus(W61_Ble_ClientReadData(W6X_Ble_drv_obj, conn_handle, service_index, char_index));
}
W6X_Status_t W6X_Ble_ClientSubscribeChar(uint8_t conn_handle, uint8_t char_value_handle, uint8_t char_prop)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Subscribe to a characteristic */
return TranslateErrorStatus(W61_Ble_ClientSubscribeChar(W6X_Ble_drv_obj, conn_handle, char_value_handle, char_prop));
}
W6X_Status_t W6X_Ble_ClientUnsubscribeChar(uint8_t conn_handle, uint8_t char_value_handle)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Unsubscribe from a characteristic */
return TranslateErrorStatus(W61_Ble_ClientUnsubscribeChar(W6X_Ble_drv_obj, conn_handle, char_value_handle));
}
/* Security APIs */
W6X_Status_t W6X_Ble_SetSecurityParam(W6X_Ble_SecurityParameter_e security_parameter)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Set security parameters */
return TranslateErrorStatus(W61_Ble_SetSecurityParam(W6X_Ble_drv_obj, (uint8_t) security_parameter));
}
W6X_Status_t W6X_Ble_GetSecurityParam(W6X_Ble_SecurityParameter_e *security_parameter)
{
W6X_Status_t ret;
uint32_t SecurityParam_tmp = 0;
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Get security parameters */
ret = TranslateErrorStatus(W61_Ble_GetSecurityParam(W6X_Ble_drv_obj, &SecurityParam_tmp));
if (ret == W6X_STATUS_OK)
{
*security_parameter = (W6X_Ble_SecurityParameter_e) SecurityParam_tmp;
}
return ret;
}
W6X_Status_t W6X_Ble_SecurityStart(uint8_t conn_handle, uint8_t security_level)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Start BLE security */
return TranslateErrorStatus(W61_Ble_SecurityStart(W6X_Ble_drv_obj, conn_handle, security_level));
}
W6X_Status_t W6X_Ble_SecurityPassKeyConfirm(uint8_t conn_handle)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Confirm the passkey */
return TranslateErrorStatus(W61_Ble_SecurityPassKeyConfirm(W6X_Ble_drv_obj, conn_handle));
}
W6X_Status_t W6X_Ble_SecurityPairingConfirm(uint8_t conn_handle)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Confirm the pairing */
return TranslateErrorStatus(W61_Ble_SecurityPairingConfirm(W6X_Ble_drv_obj, conn_handle));
}
W6X_Status_t W6X_Ble_SecurityEnterRemotePassKey(uint8_t conn_handle, uint32_t passkey)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Enter remote passkey */
return TranslateErrorStatus(W61_Ble_SecurityEnterRemotePassKey(W6X_Ble_drv_obj, conn_handle, passkey));
}
W6X_Status_t W6X_Ble_SecurityPairingCancel(uint8_t conn_handle)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Cancel the pairing */
return TranslateErrorStatus(W61_Ble_SecurityPairingCancel(W6X_Ble_drv_obj, conn_handle));
}
W6X_Status_t W6X_Ble_SecurityUnpair(uint8_t remote_bd_addr[6], W6X_Ble_AddrType_e remote_addr_type)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Unpair a device */
return TranslateErrorStatus(W61_Ble_SecurityUnpair(W6X_Ble_drv_obj, remote_bd_addr, (uint32_t) remote_addr_type));
}
W6X_Status_t W6X_Ble_SecurityGetBondedDeviceList(W6X_Ble_Bonded_Devices_Result_t *remote_bonded_devices)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Get the list of bonded devices */
return TranslateErrorStatus(W61_Ble_SecurityGetBondedDeviceList(
W6X_Ble_drv_obj, (W61_Ble_Bonded_Devices_Result_t *)remote_bonded_devices));
}
W6X_Status_t W6X_Ble_SetGapAppearance(uint16_t appearance_value)
{
NULL_ASSERT(W6X_Ble_drv_obj, W6X_Ble_Uninit_str);
/* Set GAP appearance */
return TranslateErrorStatus(W61_Ble_SetGapAppearance(W6X_Ble_drv_obj, appearance_value));
}
const char *W6X_Ble_RoleToStr(W6X_Ble_Conn_Role_e role)
{
/* Check if the protocol is unknown */
if (role > W6X_BLE_CONN_ROLE_PERIPH)
{
return "Unknown";
}
/* Return the protocol string */
return W6X_Ble_Role_str[role];
}
/** @} */
/* Private Functions Definition ----------------------------------------------*/
/** @addtogroup ST67W6X_Private_BLE_Functions
* @{
*/
static void W6X_Ble_cb(W61_event_id_t event_id, void *event_args)
{
W61_Ble_CbParamData_t *p_param_ble_data = (W61_Ble_CbParamData_t *) event_args;
W6X_App_Cb_t *p_cb_handler = W6X_GetCbHandler();
/* Check if the application callback is registered */
if ((p_cb_handler == NULL) || (p_cb_handler->APP_ble_cb == NULL))
{
BLE_LOG_ERROR("Please register the APP callback before initializing the module\n");
return;
}
switch (event_id) /* Check the event ID and call the appropriate callback */
{
case W61_BLE_EVT_CONNECTED_ID:
BLE_LOG_DEBUG("BLE connected\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_CONNECTED_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_CONNECTION_PARAM_ID:
BLE_LOG_DEBUG("BLE connection param update\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_CONNECTION_PARAM_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_DISCONNECTED_ID:
BLE_LOG_DEBUG("BLE disconnected\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_DISCONNECTED_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_INDICATION_STATUS_ENABLED_ID:
BLE_LOG_DEBUG("BLE indication enabled\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_INDICATION_STATUS_ENABLED_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_INDICATION_STATUS_DISABLED_ID:
BLE_LOG_DEBUG("BLE indication disabled\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_INDICATION_STATUS_DISABLED_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_INDICATION_ACK_ID:
BLE_LOG_DEBUG("BLE indication complete\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_INDICATION_ACK_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_INDICATION_NACK_ID:
BLE_LOG_DEBUG("BLE indication not complete\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_INDICATION_NACK_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_NOTIFICATION_STATUS_ENABLED_ID:
BLE_LOG_DEBUG("BLE notification enabled\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_NOTIFICATION_STATUS_ENABLED_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_NOTIFICATION_STATUS_DISABLED_ID:
BLE_LOG_DEBUG("BLE notification disabled\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_NOTIFICATION_STATUS_DISABLED_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_NOTIFICATION_DATA_ID:
BLE_LOG_DEBUG("BLE notification data\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_NOTIFICATION_DATA_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_WRITE_ID:
BLE_LOG_DEBUG("BLE write\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_WRITE_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_READ_ID:
BLE_LOG_DEBUG("BLE read\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_READ_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_SCAN_DONE_ID:
BLE_LOG_DEBUG("BLE scan done\n"); /* Call the scan done callback */
W6X_Ble_drv_obj->BleCtx.scan_done_cb(&W6X_Ble_drv_obj->BleCtx.ScanResults);
break;
case W61_BLE_EVT_SERVICE_FOUND_ID:
BLE_LOG_DEBUG("BLE service discovered\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_SERVICE_FOUND_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_CHAR_FOUND_ID:
BLE_LOG_DEBUG("BLE characteristic discovered\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_CHAR_FOUND_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_MTU_SIZE_ID:
BLE_LOG_DEBUG("BLE MTU exchange\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_MTU_SIZE_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_PAIRING_COMPLETED_ID:
BLE_LOG_DEBUG("BLE pairing completed\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_PAIRING_COMPLETED_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_PAIRING_FAILED_ID:
BLE_LOG_DEBUG("BLE pairing failed\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_PAIRING_FAILED_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_PAIRING_CONFIRM_ID:
BLE_LOG_DEBUG("BLE pairing confirm\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_PAIRING_CONFIRM_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_PAIRING_CANCELED_ID:
BLE_LOG_DEBUG("BLE pairing canceled\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_PAIRING_CANCELED_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_PASSKEY_CONFIRM_ID:
BLE_LOG_DEBUG("BLE passkey confirm\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_PASSKEY_CONFIRM_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_PASSKEY_ENTRY_ID:
BLE_LOG_DEBUG("BLE passkey entry\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_PASSKEY_ENTRY_ID, (void *) p_param_ble_data);
break;
case W61_BLE_EVT_PASSKEY_DISPLAY_ID:
BLE_LOG_DEBUG("BLE passkey display\n");
p_cb_handler->APP_ble_cb(W6X_BLE_EVT_PASSKEY_DISPLAY_ID, (void *) p_param_ble_data);
break;
default:
/* BLE events unmanaged */
break;
}
}
static void W6X_Ble_PrintServicesAndCharacteristics(W6X_Ble_Service_t ServicesTable[])
{
for (uint8_t i = 0; i < W61_BLE_MAX_CREATED_SERVICE_NBR; i++) /* Loop through the services */
{
if (i == ServicesTable[i].service_idx) /* Check if the service is valid */
{
/* Print the service information */
BLE_LOG_INFO("Service: %" PRIu16 ", UUID: " UUID128STR "\n", ServicesTable[i].service_idx,
UUID128TOSTR(ServicesTable[i].service_uuid));
for (uint8_t k = 0; k < W6X_BLE_MAX_CHAR_NBR; k++) /* Loop through the characteristics */
{
if (k == ServicesTable[i].charac[k].char_idx) /* Check if the characteristic is valid */
{
/* Print the characteristics of the service */
BLE_LOG_INFO("Characteristic: %" PRIu16 ", UUID: " UUID128STR ", Property: %" PRIu16 "\n",
ServicesTable[i].charac[k].char_idx,
UUID128TOSTR(ServicesTable[i].charac[k].char_uuid),
ServicesTable[i].charac[k].char_property);
}
}
BLE_LOG_INFO("\n");
}
}
}
/** @} */
@@ -0,0 +1,189 @@
/**
******************************************************************************
* @file w6x_default_config.h
* @author ST67 Application Team
* @brief Header file for the W6X configuration module
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef W6X_DEFAULT_CONFIG_H
#define W6X_DEFAULT_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include "w6x_config.h"
/* Exported constants --------------------------------------------------------*/
/** @defgroup ST67W6X_API_System_Public_Constants ST67W6X System Constants
* @ingroup ST67W6X_API_System
* @{
*/
#ifndef W6X_POWER_SAVE_AUTO
/** NCP will go by default in low power mode when NCP is in idle mode */
#define W6X_POWER_SAVE_AUTO 1
#endif /* W6X_POWER_SAVE_AUTO */
#ifndef W6X_CLOCK_MODE
/** NCP clock mode : 1: Internal RC oscillator, 2: External passive crystal, 3: External active crystal */
#define W6X_CLOCK_MODE 1U
#endif /* W6X_CLOCK_MODE */
#ifndef W6X_ASSERT_ENABLE
/** Enable/Disable NULL pointer check in the API functions.
* 0: Disabled, 1: Enabled */
#define W6X_ASSERT_ENABLE 0
#endif /* W6X_ASSERT_ENABLE */
/** @} */
/** @addtogroup ST67W6X_API_WiFi_Public_Constants
* @{
*/
#ifndef W6X_WIFI_AUTOCONNECT
/** Boolean to enable/disable autoconnect functionality */
#define W6X_WIFI_AUTOCONNECT 0
#endif /* W6X_WIFI_AUTOCONNECT */
#ifndef W6X_WIFI_SAP_MAX_CONNECTED_STATIONS
/** Define the max number of stations that can connect to the Soft-AP */
#define W6X_WIFI_SAP_MAX_CONNECTED_STATIONS 4
#endif /* W6X_WIFI_SAP_MAX_CONNECTED_STATIONS */
#ifndef W6X_WIFI_COUNTRY_CODE
/** Define the region code, supported values : [CN, JP, US, EU, 00] */
#define W6X_WIFI_COUNTRY_CODE "00"
#endif /* W6X_WIFI_COUNTRY_CODE */
#ifndef W6X_WIFI_ADAPTIVE_COUNTRY_CODE
/** Define if the country code will match AP's one.
* 0: match AP's country code,
* 1: static country code */
#define W6X_WIFI_ADAPTIVE_COUNTRY_CODE 0
#endif /* W6X_WIFI_ADAPTIVE_COUNTRY_CODE */
/** @} */
/** @addtogroup ST67W6X_API_BLE_Public_Constants
* @{
*/
#ifndef W6X_BLE_HOSTNAME
/** String defining BLE hostname */
#define W6X_BLE_HOSTNAME "ST67W61_BLE"
#endif /* W6X_BLE_HOSTNAME */
/** @} */
/** @addtogroup ST67W6X_API_Net_Public_Constants
* @{
*/
#ifndef W6X_NET_DHCP
/** Define the DHCP configuration : 0: NO DHCP, 1: DHCP CLIENT STA, 2:DHCP SERVER AP, 3: DHCP STA+AP */
#define W6X_NET_DHCP 1U
#endif /* W6X_NET_DHCP */
#ifndef W6X_NET_SAP_IP_SUBNET
/** String defining Soft-AP subnet to use.
* Last digit of IP address automatically set to 1 */
#define W6X_NET_SAP_IP_SUBNET {10, 19, 96}
#endif /* W6X_NET_SAP_IP_SUBNET */
#ifndef W6X_NET_HOSTNAME
/** String defining Wi-Fi hostname */
#define W6X_NET_HOSTNAME "ST67W61_WiFi"
#endif /* W6X_NET_HOSTNAME */
#ifndef W6X_NET_RECV_TIMEOUT
/** Timeout in ticks when calling W6X_Net_Recv() */
#define W6X_NET_RECV_TIMEOUT 5000U
#endif /* W6X_NET_RECV_TIMEOUT */
#ifndef W6X_NET_SEND_TIMEOUT
/** Timeout in ticks when calling W6X_Net_Send() */
#define W6X_NET_SEND_TIMEOUT 5000U
#endif /* W6X_NET_SEND_TIMEOUT */
#ifndef W6X_NET_RECV_BUFFER_SIZE
/** Default Net socket receive buffer size
* @note In the NCP, the LWIP recv function is used with a static buffer with
* a fixed length of 4608 (3 * 1536). The data is read in chunks of 4608 bytes
* So in order to get optimal performances, the buffer on NCP side should be twice as big */
#define W6X_NET_RECV_BUFFER_SIZE 9216U
#endif /* W6X_NET_RECV_BUFFER_SIZE */
/** @} */
/** @addtogroup ST67W6X_API_HTTP_Public_Constants
* @{
*/
#ifndef W6X_HTTP_CLIENT_TCP_SOCK_RECV_TIMEOUT
/** Timeout value in millisecond for receiving data via TCP socket used by the HTTP client.
* This value is set to compensate for when the NCP get stuck for a long time (1 second or more)
* when retrieving data from an HTTP server for example */
#define W6X_HTTP_CLIENT_TCP_SOCK_RECV_TIMEOUT 1000
#endif /* W6X_HTTP_CLIENT_TCP_SOCK_RECV_TIMEOUT */
#ifndef W6X_HTTP_CLIENT_TCP_SOCKET_SIZE
/** Size of the TCP socket used by the HTTP client, recommended to be at least 0x2000 when fetching lots of data.
* 0x2000 is the value used in the SPI host project for Firmware updates,
* which retrieves around 1 mega bytes of data. */
#define W6X_HTTP_CLIENT_TCP_SOCKET_SIZE 0x3000
#endif /* W6X_HTTP_CLIENT_TCP_SOCKET_SIZE */
/** @} */
/** @defgroup ST67W6X_API_Netif_Public_Constants ST67W6X Network Interface Constants
* @ingroup ST67W6X_API_Netif
* @{
*/
#ifndef W6X_NETIF_STA_RXQ_DEPTH
/** RX queue depth (number of pending frames) for Network STA traffic */
#define W6X_NETIF_STA_RXQ_DEPTH 16
#endif /* W6X_NETIF_STA_RXQ_DEPTH */
#ifndef W6X_NETIF_AP_RXQ_DEPTH
/** RX queue depth (number of pending frames) for Network AP traffic */
#define W6X_NETIF_AP_RXQ_DEPTH 8
#endif /* W6X_NETIF_AP_RXQ_DEPTH */
/** @} */
#ifndef MEM_PERF_ENABLE
/** Enable memory performance measurement */
#define MEM_PERF_ENABLE 0
#endif /* MEM_PERF_ENABLE */
#ifndef TASK_PERF_ENABLE
/** Enable task performance measurement */
#define TASK_PERF_ENABLE 0
#endif /* TASK_PERF_ENABLE */
#ifndef LFS_ENABLE
/** Enable LittleFS */
#define LFS_ENABLE 0
#endif /* LFS_ENABLE */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* W6X_DEFAULT_CONFIG_H */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,137 @@
/**
******************************************************************************
* @file w6x_internal.h
* @author ST67 Application Team
* @brief This file contains the internal definitions of the API
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef W6X_INTERNAL_H
#define W6X_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include "w6x_default_config.h"
/** @defgroup ST67W6X_Private ST67W6X Internal
*/
/** @defgroup ST67W6X_Private_Common ST67W6X Common
* @ingroup ST67W6X_Private
*/
/** @defgroup ST67W6X_Private_System ST67W6X System
* @ingroup ST67W6X_Private
*/
/** @defgroup ST67W6X_Private_WiFi ST67W6X Wi-Fi
* @ingroup ST67W6X_Private
*/
/** @defgroup ST67W6X_Private_Net ST67W6X Net
* @ingroup ST67W6X_Private
*/
/** @defgroup ST67W6X_Private_HTTP ST67W6X HTTP
* @ingroup ST67W6X_Private
*/
/** @defgroup ST67W6X_Private_MQTT ST67W6X MQTT
* @ingroup ST67W6X_Private
*/
/** @defgroup ST67W6X_Private_BLE ST67W6X BLE
* @ingroup ST67W6X_Private
*/
/** @defgroup ST67W6X_Private_FWU ST67W6X Firmware updates
* @ingroup ST67W6X_Private
*/
/** @defgroup ST67W6X_Private_Netif ST67W6X Network Interface
* @ingroup ST67W6X_Private
*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup ST67W6X_Private_Common_Constants ST67W6X Common Constants
* @ingroup ST67W6X_Private_Common
* @{
*/
#if (W6X_ASSERT_ENABLE == 1)
/** W61 context pointer error string */
static const char W6X_Obj_Null_str[] = "W61 Object pointer not initialized";
#endif /* W6X_ASSERT_ENABLE */
/** @} */
/* Exported variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/** @defgroup ST67W6X_Private_Common_Macros ST67W6X Common Macros
* @ingroup ST67W6X_Private_Common
* @{
*/
/**
* \def NULL_ASSERT(p, s)
* Pointer NULL check and return error
*/
/**
* \def NULL_ASSERT_VOID(p, s)
* Pointer NULL check and no return
*/
#if (W6X_ASSERT_ENABLE == 1)
#define NULL_ASSERT(p, s) if ((p) == NULL) { LogError("%s\n", (s)); return W6X_STATUS_ERROR; }
#define NULL_ASSERT_VOID(p, s) if ((p) == NULL) { LogError("%s\n", (s)); return; }
#else
#define NULL_ASSERT(p, s)
#define NULL_ASSERT_VOID(p, s)
#endif /* W6X_ASSERT_ENABLE */
/** Translate W61 to W6X status */
#define TranslateErrorStatus(ret_w61) TranslateErrorStatus_W61_W6X((ret_w61), __func__)
/** Translate W61 to W6X status and return error */
#define RETURN_ERROR_STATUS(err61, str) \
if ((ret = TranslateErrorStatus((err61))) == W6X_STATUS_ERROR) { LogError("%s\n", (str)); } return ret;
/** @} */
/* Exported functions ------------------------------------------------------- */
/** @defgroup ST67W6X_Private_Common_Functions ST67W6X Common Functions
* @ingroup ST67W6X_Private_Common
* @{
*/
/**
* @brief Translate W61 status to W6X status
* @param ret_w61: W61 status
* @param func_name: Function name
* @retval W6X status
*/
W6X_Status_t TranslateErrorStatus_W61_W6X(W61_Status_t ret_w61, char const *func_name);
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* W6X_INTERNAL_H */
@@ -0,0 +1,388 @@
/**
******************************************************************************
* @file w6x_mqtt.c
* @author ST67 Application Team
* @brief This file provides code for W6x MQTT API
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "w6x_types.h" /* W6X_ARCH_** */
#if (ST67_ARCH == W6X_ARCH_T01)
#include <string.h>
#include "w6x_api.h" /* Prototypes of the functions implemented in this file */
#include "w61_at_api.h" /* Prototypes of the functions called by this file */
#include "w6x_internal.h"
#include "w61_io.h" /* Prototypes of the BUS functions to be registered */
/* Global variables ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup ST67W6X_Private_MQTT_Variables ST67W6X MQTT Variables
* @ingroup ST67W6X_Private_MQTT
* @{
*/
static W61_Object_t *W6X_MQTT_drv_obj = NULL; /*!< Global W61 context pointer */
#if (W6X_ASSERT_ENABLE == 1)
/** W6X MQTT init error string */
static const char W6X_MQTT_Uninit_str[] = "W6X MQTT module not initialized";
#endif /* W6X_ASSERT_ENABLE */
/** MQTT state string */
static const char *const W6X_MQTT_State_str[] =
{
"Not initialized",
"", /* Unused "User configuration done" */
"Configured", /* "Connection configuration done" */
"Disconnected",
"Connected",
"", /* Unused "Connected, no subscription" */
"", /* Unused "Connected, and subscribed to MQTT topics" */
};
/** @} */
/* Private function prototypes -----------------------------------------------*/
/** @defgroup ST67W6X_Private_MQTT_Functions ST67W6X MQTT Functions
* @ingroup ST67W6X_Private_MQTT
* @{
*/
/**
* @brief MQTT callback function
* @param event_id: event ID
* @param event_args: event arguments
*/
static void W6X_MQTT_cb(W61_event_id_t event_id, void *event_args);
/** @} */
/* Functions Definition ------------------------------------------------------*/
/** @addtogroup ST67W6X_API_MQTT_Public_Functions
* @{
*/
W6X_Status_t W6X_MQTT_Init(W6X_MQTT_Data_t *mqtt_data)
{
W6X_Status_t ret = W6X_STATUS_ERROR;
W6X_App_Cb_t *p_cb_handler;
NULL_ASSERT(mqtt_data, "MQTT configuration pointer is NULL");
W6X_MQTT_drv_obj = W61_ObjGet();
NULL_ASSERT(W6X_MQTT_drv_obj, W6X_Obj_Null_str);
/* Check that application callback is registered */
p_cb_handler = W6X_GetCbHandler();
if ((p_cb_handler == NULL) || (p_cb_handler->APP_mqtt_cb == NULL))
{
MQTT_LOG_ERROR("Please register the APP callback before initializing the module\n");
return ret;
}
/* Register W61 driver callbacks */
(void)W61_RegisterULcb(W6X_MQTT_drv_obj,
NULL,
NULL,
NULL,
W6X_MQTT_cb,
NULL);
return TranslateErrorStatus(W61_MQTT_Init(W6X_MQTT_drv_obj, mqtt_data->p_recv_data,
mqtt_data->recv_data_buf_size));
}
void W6X_MQTT_DeInit(void)
{
if (W6X_MQTT_drv_obj == NULL)
{
return; /* Nothing to do */
}
(void)W61_MQTT_DeInit(W6X_MQTT_drv_obj); /* Deinitialize MQTT */
W6X_MQTT_drv_obj = NULL; /* Reset the global pointer */
}
W6X_Status_t W6X_MQTT_SetRecvDataPtr(W6X_MQTT_Data_t *mqtt_data)
{
NULL_ASSERT(mqtt_data, "MQTT configuration pointer is NULL");
W6X_MQTT_drv_obj = W61_ObjGet();
NULL_ASSERT(W6X_MQTT_drv_obj, W6X_Obj_Null_str);
return TranslateErrorStatus(W61_MQTT_Init(W6X_MQTT_drv_obj, mqtt_data->p_recv_data,
mqtt_data->recv_data_buf_size));
}
W6X_Status_t W6X_MQTT_Configure(W6X_MQTT_Connect_t *config)
{
W6X_Status_t ret = W6X_STATUS_ERROR;
NULL_ASSERT(W6X_MQTT_drv_obj, W6X_MQTT_Uninit_str);
if ((config->Scheme == 2U) || (config->Scheme == 4U)) /* Server certificate */
{
if (config->CACertificateName[0] == '\0')
{
MQTT_LOG_ERROR("CA certificate is mandatory for scheme 2 or 4\n");
goto _err;
}
if (config->CACertificateContent != NULL)
{
/* Write the file into the NCP */
if (W6X_FS_WriteFileByContent((char *)config->CACertificateName, config->CACertificateContent,
strlen(config->CACertificateContent)) != W6X_STATUS_OK)
{
MQTT_LOG_ERROR("Writing file %s into the NCP failed\n", config->CACertificateName);
goto _err;
}
}
else
{
/* Write the file into the NCP */
if (W6X_FS_WriteFileByName((char *)config->CACertificateName) != W6X_STATUS_OK)
{
MQTT_LOG_ERROR("Writing file %s into the NCP failed\n", config->CACertificateName);
goto _err;
}
}
}
if ((config->Scheme == 3U) || (config->Scheme == 4U)) /* Client certificate */
{
if ((config->CertificateName[0] == '\0') || (config->PrivateKeyName[0] == '\0'))
{
MQTT_LOG_ERROR("Client certificate and private key are mandatory for scheme 3 or 4\n");
goto _err;
}
if (config->CertificateContent != NULL)
{
/* Write the file into the NCP */
if (W6X_FS_WriteFileByContent((char *)config->CertificateName, config->CertificateContent,
strlen(config->CertificateContent)) != W6X_STATUS_OK)
{
MQTT_LOG_ERROR("Writing file %s into the NCP failed\n", config->CertificateName);
goto _err;
}
}
else
{
/* Write the file into the NCP */
if (W6X_FS_WriteFileByName((char *)config->CertificateName) != W6X_STATUS_OK)
{
MQTT_LOG_ERROR("Writing file %s into the NCP failed\n", config->CertificateName);
goto _err;
}
}
if (config->PrivateKeyContent != NULL)
{
/* Write the file into the NCP */
if (W6X_FS_WriteFileByContent((char *)config->PrivateKeyName, config->PrivateKeyContent,
strlen(config->PrivateKeyContent)) != W6X_STATUS_OK)
{
MQTT_LOG_ERROR("Writing file %s into the NCP failed\n", config->PrivateKeyName);
goto _err;
}
}
else
{
/* Write the file into the NCP */
if (W6X_FS_WriteFileByName((char *)config->PrivateKeyName) != W6X_STATUS_OK)
{
MQTT_LOG_ERROR("Writing file %s into the NCP failed\n", config->PrivateKeyName);
goto _err;
}
}
}
/* Set the MQTT User configuration */
ret = TranslateErrorStatus(W61_MQTT_SetUserConfiguration(W6X_MQTT_drv_obj, config->Scheme, config->MQClientId,
config->MQUserName, config->MQUserPwd,
config->CertificateName, config->PrivateKeyName,
config->CACertificateName));
if (ret != W6X_STATUS_OK)
{
goto _err;
}
if (config->SNI[0] != 0U)
{
/* Set the SNI */
ret = TranslateErrorStatus(W61_MQTT_SetSNI(W6X_MQTT_drv_obj, config->SNI));
if (ret != W6X_STATUS_OK)
{
goto _err;
}
}
/* Set the MQTT Connection configuration */
ret = TranslateErrorStatus(W61_MQTT_SetConfiguration(W6X_MQTT_drv_obj, config->KeepAlive, config->DisableCleanSession,
config->WillTopic, config->WillMessage, config->WillQos,
config->WillRetain));
_err:
return ret;
}
W6X_Status_t W6X_MQTT_Connect(W6X_MQTT_Connect_t *config)
{
NULL_ASSERT(W6X_MQTT_drv_obj, W6X_MQTT_Uninit_str);
/* Connect to the MQTT broker */
return TranslateErrorStatus(W61_MQTT_Connect(W6X_MQTT_drv_obj, config->HostName, config->HostPort));
}
W6X_Status_t W6X_MQTT_GetConnectionStatus(W6X_MQTT_Connect_t *config)
{
W6X_Status_t ret;
NULL_ASSERT(W6X_MQTT_drv_obj, W6X_MQTT_Uninit_str);
/* Get the connection status */
ret = TranslateErrorStatus(W61_MQTT_GetConnectionStatus(W6X_MQTT_drv_obj, config->HostName,
&config->HostPort, &config->Scheme,
&config->State));
if (ret != W6X_STATUS_OK)
{
goto _err;
}
/* Get the MQTT user configuration */
ret = TranslateErrorStatus(W61_MQTT_GetUserConfiguration(W6X_MQTT_drv_obj, config->MQClientId,
config->MQUserName, config->MQUserPwd,
config->CertificateName, config->PrivateKeyName,
config->CACertificateName));
_err:
return ret;
}
W6X_Status_t W6X_MQTT_Disconnect(void)
{
uint8_t HostName[64];
uint32_t HostPort;
uint32_t Scheme;
uint32_t State = W6X_MQTT_STATE_UNINIT;
W6X_Status_t ret;
NULL_ASSERT(W6X_MQTT_drv_obj, W6X_MQTT_Uninit_str);
/* Get the connection status */
ret = TranslateErrorStatus(W61_MQTT_GetConnectionStatus(W6X_MQTT_drv_obj, HostName, &HostPort, &Scheme, &State));
if (ret != W6X_STATUS_OK)
{
goto _err;
}
if ((State == W6X_MQTT_STATE_CONNECTED) || (State == W6X_MQTT_STATE_CONNECTED_SUBSCRIBED) ||
(State == W6X_MQTT_STATE_CONNECTED_NO_SUB))
{
/* Disconnect from the MQTT broker */
return TranslateErrorStatus(W61_MQTT_Disconnect(W6X_MQTT_drv_obj));
}
return W6X_STATUS_OK;
_err:
return ret;
}
W6X_Status_t W6X_MQTT_Subscribe(uint8_t *topic)
{
NULL_ASSERT(W6X_MQTT_drv_obj, W6X_MQTT_Uninit_str);
/* Subscribe to the topic */
return TranslateErrorStatus(W61_MQTT_Subscribe(W6X_MQTT_drv_obj, topic));
}
W6X_Status_t W6X_MQTT_GetSubscribedTopics(void)
{
NULL_ASSERT(W6X_MQTT_drv_obj, W6X_MQTT_Uninit_str);
/* Get the list of subscribed topics */
return TranslateErrorStatus(W61_MQTT_GetSubscribedTopics(W6X_MQTT_drv_obj));
}
W6X_Status_t W6X_MQTT_Unsubscribe(uint8_t *topic)
{
NULL_ASSERT(W6X_MQTT_drv_obj, W6X_MQTT_Uninit_str);
/* Unsubscribe from the topic */
return TranslateErrorStatus(W61_MQTT_Unsubscribe(W6X_MQTT_drv_obj, topic));
}
W6X_Status_t W6X_MQTT_Publish(uint8_t *topic, uint8_t *message, uint32_t message_len, uint32_t qos,
uint32_t retain)
{
NULL_ASSERT(W6X_MQTT_drv_obj, W6X_MQTT_Uninit_str);
/* Publish the message to the topic */
return TranslateErrorStatus(W61_MQTT_Publish(W6X_MQTT_drv_obj, topic, message, message_len, qos, retain));
}
const char *W6X_MQTT_StateToStr(uint32_t state)
{
if (state > W6X_MQTT_STATE_CONNECTED_SUBSCRIBED)
{
return "Unknown";
}
else if ((state == W6X_MQTT_STATE_CONNECTED_NO_SUB) || (state == W6X_MQTT_STATE_CONNECTED_SUBSCRIBED))
{
/* Return simplified connected status */
return W6X_MQTT_State_str[W6X_MQTT_STATE_CONNECTED];
}
else
{
/* Return the MQTT state string */
return W6X_MQTT_State_str[state];
}
}
/** @} */
/* Private Functions Definition ----------------------------------------------*/
/* =================== Callbacks ===================================*/
/** @addtogroup ST67W6X_Private_MQTT_Functions
* @{
*/
static void W6X_MQTT_cb(W61_event_id_t event_id, void *event_args)
{
W6X_MQTT_CbParamData_t *cb_param_mqtt_data;
W6X_App_Cb_t *p_cb_handler = W6X_GetCbHandler();
if ((p_cb_handler == NULL) || (p_cb_handler->APP_mqtt_cb == NULL))
{
MQTT_LOG_ERROR("Please register the APP callback before initializing the module\n");
return;
}
switch (event_id)
{
case W61_MQTT_EVT_CONNECTED_ID:
p_cb_handler->APP_mqtt_cb(W6X_MQTT_EVT_CONNECTED_ID, NULL);
break;
case W61_MQTT_EVT_DISCONNECTED_ID:
p_cb_handler->APP_mqtt_cb(W6X_MQTT_EVT_DISCONNECTED_ID, NULL);
break;
case W61_MQTT_EVT_SUBSCRIPTION_RECEIVED_ID:
cb_param_mqtt_data = (W6X_MQTT_CbParamData_t *)event_args;
p_cb_handler->APP_mqtt_cb(W6X_MQTT_EVT_SUBSCRIPTION_RECEIVED_ID, (void *) cb_param_mqtt_data);
break;
default:
/* MQTT events unmanaged */
break;
}
}
/** @} */
#endif /* ST67_ARCH */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,143 @@
/**
******************************************************************************
* @file w6x_netif.c
* @author ST67 Application Team
* @brief This file provides code for W6x Net interface API
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "w6x_types.h" /* W6X_ARCH_** */
#if (ST67_ARCH == W6X_ARCH_T02)
#include <string.h>
#include "w6x_api.h" /* Prototypes of the functions implemented in this file */
#include "w61_at_api.h" /* Prototypes of the functions called by this file */
#include "w6x_internal.h"
#include "w61_io.h" /* Prototypes of the BUS functions to be registered */
#include "common_parser.h" /* Common Parser functions */
#include "event_groups.h"
/* Global variables ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup ST67W6X_Private_Netif_Variables ST67W6X Network Interface Variables
* @ingroup ST67W6X_Private_Netif
* @{
*/
static W61_Object_t *W6X_Netif_drv_obj = NULL; /*!< Global W61 context pointer */
/** @} */
/* Private function prototypes -----------------------------------------------*/
/* Functions Definition ------------------------------------------------------*/
/** @addtogroup ST67W6X_API_Netif_Public_Functions
* @{
*/
W6X_Status_t W6X_Netif_Init(W6X_Net_if_cb_t *net_if_cb)
{
/* Get the global W61 context pointer */
W6X_Netif_drv_obj = W61_ObjGet();
NULL_ASSERT(W6X_Netif_drv_obj, W6X_Obj_Null_str);
if (W6X_Netif_drv_obj->NetCtx.Supported != 0U)
{
NET_LOG_ERROR("Netif module not supported\n");
return W6X_STATUS_ERROR;
}
if (BusIo_SPI_Bind(SPI_MSG_CTRL_TRAFFIC_NETWORK_STA, (int32_t)W6X_NETIF_STA_RXQ_DEPTH,
net_if_cb->rxd_sta_notify_fn) != 0)
{
SYS_LOG_ERROR("Bind Network Traffic Station failed\n");
return W6X_STATUS_ERROR;
}
if (BusIo_SPI_Bind(SPI_MSG_CTRL_TRAFFIC_NETWORK_AP, (int32_t)W6X_NETIF_AP_RXQ_DEPTH,
net_if_cb->rxd_ap_notify_fn) != 0)
{
SYS_LOG_ERROR("Bind Network Traffic AP failed\n");
return W6X_STATUS_ERROR;
}
W6X_Netif_drv_obj->Callbacks.Netif_cb.link_sta_up_fn = net_if_cb->link_sta_up_fn;
W6X_Netif_drv_obj->Callbacks.Netif_cb.link_sta_down_fn = net_if_cb->link_sta_down_fn;
W6X_Netif_drv_obj->Callbacks.Netif_cb.link_ap_up_fn = net_if_cb->link_ap_up_fn;
W6X_Netif_drv_obj->Callbacks.Netif_cb.link_ap_down_fn = net_if_cb->link_ap_down_fn;
return W6X_STATUS_OK;
}
void W6X_Netif_DeInit(void)
{
if (W6X_Netif_drv_obj == NULL)
{
return; /* Nothing to do */
}
W6X_Netif_drv_obj->Callbacks.Netif_cb.link_sta_up_fn = NULL;
W6X_Netif_drv_obj->Callbacks.Netif_cb.link_sta_down_fn = NULL;
W6X_Netif_drv_obj->Callbacks.Netif_cb.link_ap_up_fn = NULL;
W6X_Netif_drv_obj->Callbacks.Netif_cb.link_ap_down_fn = NULL;
}
int32_t W6X_Netif_output(uint32_t link_id, uint8_t *buf, uint32_t len)
{
uint8_t type;
if (link_id == W6X_NET_IF_STA)
{
type = SPI_MSG_CTRL_TRAFFIC_NETWORK_STA;
}
else if (link_id == W6X_NET_IF_AP)
{
type = SPI_MSG_CTRL_TRAFFIC_NETWORK_AP;
}
else
{
return -1;
}
return BusIo_SPI_SendData(type, buf, len, pdMS_TO_TICKS(10000));
}
int32_t W6X_Netif_input(uint32_t link_id, void **buffer, uint8_t **data)
{
uint8_t type;
if (link_id == W6X_NET_IF_STA)
{
type = SPI_MSG_CTRL_TRAFFIC_NETWORK_STA;
}
else if (link_id == W6X_NET_IF_AP)
{
type = SPI_MSG_CTRL_TRAFFIC_NETWORK_AP;
}
else
{
return -1;
}
return BusIo_SPI_ReceivePtr(type, buffer, data, 0);
}
int32_t W6X_Netif_free(void *buffer)
{
return BusIo_SPI_Free(buffer);
}
/** @} */
#endif /* ST67_ARCH */
@@ -0,0 +1,899 @@
/**
******************************************************************************
* @file w6x_sys.c
* @author ST67 Application Team
* @brief This file provides code for W6x System API
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <inttypes.h>
#include <string.h>
#include <stdbool.h>
#include "w6x_api.h" /* Prototypes of the functions implemented in this file */
#include "w6x_version.h"
#include "w61_at_api.h" /* Prototypes of the functions called by this file */
#include "w6x_internal.h"
#include "w61_io.h" /* Prototypes of the BUS functions to be registered */
#include "common_parser.h" /* Common Parser functions */
#if (!defined(ST67_ARCH) || ((ST67_ARCH != W6X_ARCH_T02) && (ST67_ARCH != W6X_ARCH_T01)))
#error "ST67_ARCH not defined or invalid. Supported values are: W6X_ARCH_T01 or W6X_ARCH_T02"
#error "Please define ST67_ARCH in the compiler preprocessor macros"
#endif /* ST67_ARCH */
/* Private defines -----------------------------------------------------------*/
/** @defgroup ST67W6X_Private_System_Constants ST67W6X System Constants
* @ingroup ST67W6X_Private_System
* @{
*/
#define W6X_FS_READ_BLOCK_SIZE 256U /*!< File system read block size */
#define ANT_DIVERSITY_PIN 0U /*!< Antenna diversity GPIO pin number */
#ifndef HAL_SYS_RESET
/** HAL System software reset function */
/* coverity[misra_c_2012_rule_8_5_violation : FALSE] */
/* coverity[misra_c_2012_rule_8_6_violation : FALSE] */
extern void HAL_NVIC_SystemReset(void);
/** HAL System software reset macro */
#define HAL_SYS_RESET() do{ HAL_NVIC_SystemReset(); } while(false);
#endif /* HAL_SYS_RESET */
/** @} */
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup ST67W6X_Private_System_Variables ST67W6X System Variables
* @ingroup ST67W6X_Private_System
* @{
*/
static W61_Object_t *p_DrvObj = NULL; /*!< Global W61 context pointer */
#if (W6X_ASSERT_ENABLE == 1)
/** W6X System init error string */
static const char W6X_Sys_Uninit_str[] = "W6X System module not initialized";
#endif /* W6X_ASSERT_ENABLE */
static W6X_App_Cb_t W6X_CbHandler; /*!< W6X Applicative Callbacks handler */
static W6X_FS_FilesListFull_t *W6X_FilesList = NULL; /*!< List of files */
static W6X_ModuleInfo_t *p_module_info = NULL; /*!< W61 module info */
/** Status string table for W6X_StatusToStr */
static const char *const W6X_status_strings[] =
{
"OK",
"BUSY",
"ERROR",
"TIMEOUT",
"UNEXPECTED RESPONSE",
"NOT SUPPORTED",
"UNKNOWN"
};
/** Module ID string table for W6X_ModuleIDToStr */
static const char *const W6X_module_strings[] =
{
"Undefined",
"-B",
"-U",
"-P"
};
/** @} */
/** @defgroup ST67W6X_Private_FWU_Variables ST67W6X Firmware updates Variables
* @ingroup ST67W6X_Private_FWU
* @{
*/
#if (W6X_ASSERT_ENABLE == 1)
/** W6X FWU init error string */
static const char W6X_FWU_Uninit_str[] = "W6X FWU module not initialized";
#endif /* W6X_ASSERT_ENABLE */
/** @} */
/* Private function prototypes -----------------------------------------------*/
/** @defgroup ST67W6X_Private_System_Functions ST67W6X System Functions
* @ingroup ST67W6X_Private_System
*/
/* Functions Definition ------------------------------------------------------*/
/** @addtogroup ST67W6X_API_System_Public_Functions
* @{
*/
W6X_Status_t W6X_Init(void)
{
W6X_Status_t ret;
uint32_t clock_source = 0U;
int32_t Netmode = -1;
p_DrvObj = W61_ObjGet();
NULL_ASSERT(p_DrvObj, W6X_Obj_Null_str);
/* Configure the default power save mode and WakeUp pin */
(void)W61_LowPowerConfig(p_DrvObj, 28, 2);
/* Initialize the W61 module */
ret = TranslateErrorStatus(W61_Init(p_DrvObj));
if (ret != W6X_STATUS_OK)
{
SYS_LOG_ERROR("W61 Init failed\n");
goto _err;
}
/* Get the current Network mode (0: on host, 1: on NCP) */
ret = TranslateErrorStatus(W61_GetNetMode(p_DrvObj, &Netmode));
if (ret != W6X_STATUS_OK)
{
SYS_LOG_ERROR("Get Net mode failed\n");
goto _err;
}
if (Netmode == 1)
{
p_DrvObj->NetCtx.Supported = 1; /* AT Network module supported */
#if (ST67_ARCH == W6X_ARCH_T02)
LogError("SDK T02 variant is required for the ST67_ARCH selected\n");
ret = W6X_STATUS_ERROR;
goto _err;
#endif /* ST67_ARCH */
}
else if (Netmode == 0)
{
/* AT Network module not supported. The network interface must be linked to the IP stack on host */
p_DrvObj->NetCtx.Supported = 0;
#if (ST67_ARCH == W6X_ARCH_T01)
LogError("SDK T01 variant is required for the ST67_ARCH selected\n");
ret = W6X_STATUS_ERROR;
goto _err;
#endif /* ST67_ARCH */
}
else
{
SYS_LOG_ERROR("Invalid Net mode %d\n", Netmode);
ret = W6X_STATUS_ERROR;
goto _err;
}
/* Configure the current W61 clock used */
ret = TranslateErrorStatus(W61_GetClockSource(p_DrvObj, &clock_source));
if (ret != W6X_STATUS_OK)
{
SYS_LOG_ERROR("Get W61 clock source failed\n");
goto _err;
}
if (clock_source != W6X_CLOCK_MODE)
{
/* Set the chosen clock source depending of the hardware configuration */
ret = TranslateErrorStatus(W61_SetClockSource(p_DrvObj, W6X_CLOCK_MODE));
if (ret != W6X_STATUS_OK)
{
SYS_LOG_ERROR("Set W61 clock failed\n");
goto _err;
}
HAL_SYS_RESET(); /* Reboot the host to apply the clock change */
}
/* Get the W61 info */
ret = TranslateErrorStatus(W61_GetModuleInfo(p_DrvObj));
if (ret != W6X_STATUS_OK)
{
SYS_LOG_ERROR("Get W61 Info failed\n");
goto _err;
}
/* Store the W61 information */
p_module_info = (W6X_ModuleInfo_t *)&p_DrvObj->ModuleInfo;
(void)W6X_ModuleInfoDisplay(); /* Display the W61 information in banner */
#if (LFS_ENABLE == 1)
(void)easyflash_init(); /* Initialize the File system with user certificates */
#endif /* LFS_ENABLE */
if (p_DrvObj->ModuleInfo.ModuleID.ModuleID == W61_MODULE_ID_B)
{
/* Restore the antenna diversity pin to floating input */
(void)W61_RestoreGPIO(p_DrvObj, ANT_DIVERSITY_PIN);
}
/* Set the wake-up pin to the ST67W611M */
(void)W61_SetWakeUpPin(p_DrvObj, p_DrvObj->LowPowerCfg.WakeUpPinIn);
#if (W6X_POWER_SAVE_AUTO == 1)
(void)W6X_SetPowerMode(1U); /* Enable the power save mode */
#else
(void)W6X_SetPowerMode(0U); /* Disable the power save mode */
#endif /* W6X_POWER_SAVE_AUTO */
ret = W6X_STATUS_OK;
_err:
return ret;
}
void W6X_DeInit(void)
{
if (p_DrvObj == NULL)
{
return; /* Nothing to do */
}
/* Set to hibernate */
(void)W61_SetPowerMode(p_DrvObj, 1U, 0U);
/* DeInit and power-off the ST67 by resetting the CHIP_EN pin */
(void)W61_DeInit(p_DrvObj);
if (W6X_FilesList != NULL)
{
/* Free the files list */
vPortFree(W6X_FilesList);
W6X_FilesList = NULL;
}
p_module_info = NULL; /* Reset the module info */
p_DrvObj = NULL; /* Reset the global pointer */
}
W6X_Status_t W6X_ModuleInfoDisplay(void)
{
NULL_ASSERT(p_DrvObj, W6X_Sys_Uninit_str);
NULL_ASSERT(p_module_info, "Module info not available");
/* Display the W61 information */
SYS_LOG_INFO("--------------- ST67W6X info ------------\n");
SYS_LOG_INFO("ST67W6X MW Version: " W6X_VERSION_STR "\n");
SYS_LOG_INFO("AT Version: %" PRIi16 ".%" PRIi16 ".%" PRIi16 "\n",
p_module_info->AT_Version.Major, p_module_info->AT_Version.Sub1, p_module_info->AT_Version.Sub2);
SYS_LOG_INFO("SDK Version: %" PRIi16 ".%" PRIi16 ".%" PRIi16,
p_module_info->SDK_Version.Major, p_module_info->SDK_Version.Sub1, p_module_info->SDK_Version.Sub2);
if (p_module_info->SDK_Version.Patch != 0U)
{
SYS_LOG_INFO(".%" PRIi16, p_module_info->SDK_Version.Patch);
}
SYS_LOG_INFO("\n");
SYS_LOG_INFO("Wi-Fi MAC Version: %" PRIi16 ".%" PRIi16 ".%" PRIi16 "\n",
p_module_info->WiFi_MAC_Version.Major, p_module_info->WiFi_MAC_Version.Sub1,
p_module_info->WiFi_MAC_Version.Sub2);
SYS_LOG_INFO("BT Controller Version: %" PRIi16 ".%" PRIi16 ".%" PRIi16 "\n",
p_module_info->BT_Controller_Version.Major, p_module_info->BT_Controller_Version.Sub1,
p_module_info->BT_Controller_Version.Sub2);
SYS_LOG_INFO("BT Stack Version: %" PRIi16 ".%" PRIi16 ".%" PRIi16 "\n",
p_module_info->BT_Stack_Version.Major, p_module_info->BT_Stack_Version.Sub1,
p_module_info->BT_Stack_Version.Sub2);
SYS_LOG_INFO("Build Date: %s\n", p_module_info->Build_Date);
SYS_LOG_INFO("Module ID: ");
if (p_module_info->ModuleID.ModuleName[0] == '\0')
{
SYS_LOG_INFO("Undefined");
}
else
{
SYS_LOG_INFO("%s (%s)", p_module_info->ModuleID.ModuleName, W6X_ModelToStr(p_module_info->ModuleID.ModuleID));
}
SYS_LOG_INFO("\n");
SYS_LOG_INFO("BOM ID: %" PRIu16 "\n", p_module_info->BomID);
SYS_LOG_INFO("Manufacturing Year: 20%02" PRIu16 "\n", p_module_info->Manufacturing_Year);
SYS_LOG_INFO("Manufacturing Week: %02" PRIu16 "\n", p_module_info->Manufacturing_Week);
SYS_LOG_INFO("Battery Voltage: %" PRIu32 ".%" PRIu32 " V\n", p_module_info->BatteryVoltage / 1000U,
p_module_info->BatteryVoltage % 1000U);
SYS_LOG_INFO("Trim Wi-Fi hp: %" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%"
PRIi16
",%" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%" PRIi16 "\n",
p_module_info->trim_wifi_hp[0], p_module_info->trim_wifi_hp[1],
p_module_info->trim_wifi_hp[2], p_module_info->trim_wifi_hp[3],
p_module_info->trim_wifi_hp[4], p_module_info->trim_wifi_hp[5],
p_module_info->trim_wifi_hp[6], p_module_info->trim_wifi_hp[7],
p_module_info->trim_wifi_hp[8], p_module_info->trim_wifi_hp[9],
p_module_info->trim_wifi_hp[10], p_module_info->trim_wifi_hp[11],
p_module_info->trim_wifi_hp[12], p_module_info->trim_wifi_hp[13]);
SYS_LOG_INFO("Trim Wi-Fi lp: %" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%"
PRIi16
",%" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%" PRIi16 "\n",
p_module_info->trim_wifi_lp[0], p_module_info->trim_wifi_lp[1],
p_module_info->trim_wifi_lp[2], p_module_info->trim_wifi_lp[3],
p_module_info->trim_wifi_lp[4], p_module_info->trim_wifi_lp[5],
p_module_info->trim_wifi_lp[6], p_module_info->trim_wifi_lp[7],
p_module_info->trim_wifi_lp[8], p_module_info->trim_wifi_lp[9],
p_module_info->trim_wifi_lp[10], p_module_info->trim_wifi_lp[11],
p_module_info->trim_wifi_lp[12], p_module_info->trim_wifi_lp[13]);
SYS_LOG_INFO("Trim BLE: %" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%" PRIi16 ",%" PRIi16 "\n",
p_module_info->trim_ble[0], p_module_info->trim_ble[1], p_module_info->trim_ble[2],
p_module_info->trim_ble[3], p_module_info->trim_ble[4]);
SYS_LOG_INFO("Trim XTAL: %" PRIi16 "\n", p_module_info->trim_xtal);
SYS_LOG_INFO("MAC Address: " MACSTR "\n", MAC2STR(p_module_info->Mac_Address));
SYS_LOG_INFO("Anti-rollback Bootloader: %" PRIu16 "\n", p_module_info->AntiRollbackBootloader);
SYS_LOG_INFO("Anti-rollback App: %" PRIu16 "\n", p_module_info->AntiRollbackApp);
SYS_LOG_INFO("-----------------------------------------\n");
return W6X_STATUS_OK;
}
W6X_App_Cb_t *W6X_GetCbHandler(void)
{
/* Return the W6X callback handler */
return &W6X_CbHandler;
}
W6X_ModuleInfo_t *W6X_GetModuleInfo(void)
{
/* Return the W6X module info */
return p_module_info;
}
W6X_Status_t W6X_RegisterAppCb(W6X_App_Cb_t *app_cb)
{
NULL_ASSERT(app_cb, W6X_Sys_Uninit_str);
/* Register the application callback */
W6X_CbHandler = *app_cb;
return W6X_STATUS_OK;
}
W6X_Status_t W6X_FS_WriteFileByName(char filename[W6X_SYS_FS_FILENAME_SIZE])
{
/* Write the file to the NCP. Requires the file to be present in the host filesystem */
return W6X_FS_WriteFileByContent(filename, NULL, 0);
}
W6X_Status_t W6X_FS_WriteFileByContent(char filename[W6X_SYS_FS_FILENAME_SIZE], const char *file, uint32_t len)
{
W6X_FS_FilesListFull_t *files_list = NULL;
uint32_t file_ncp_index = 0;
uint32_t read_offset = 0;
uint32_t part_len;
uint32_t file_lfs_size = 0;
#if (LFS_ENABLE == 1)
uint8_t *buf = NULL;
uint32_t file_lfs_index = 0;
int32_t read_len = 0;
#endif /* LFS_ENABLE */
W6X_Status_t ret = W6X_STATUS_ERROR;
NULL_ASSERT(p_DrvObj, W6X_Sys_Uninit_str);
/* Allocate a buffer to read a block of the NCP file */
uint8_t *ncp_buf = pvPortMalloc(W6X_FS_READ_BLOCK_SIZE + 1U);
if (ncp_buf == NULL)
{
goto _err;
}
(void)memset(ncp_buf, 0, W6X_FS_READ_BLOCK_SIZE + 1U);
#if (LFS_ENABLE == 1)
/* Allocate a buffer to read a block of the Host lfs file */
buf = pvPortMalloc(W6X_FS_READ_BLOCK_SIZE + 1U);
if (buf == NULL)
{
goto _err;
}
(void)memset(buf, 0, W6X_FS_READ_BLOCK_SIZE + 1U);
#else
if (file == NULL)
{
SYS_LOG_ERROR("File content not available\n");
ret = W6X_STATUS_ERROR;
goto _err;
}
#endif /* LFS_ENABLE */
ret = W6X_FS_ListFiles(&files_list); /* Get the files list available in the NCP */
if (ret != W6X_STATUS_OK)
{
if (ret == W6X_STATUS_ERROR)
{
SYS_LOG_ERROR("Unable to list files\n");
}
goto _err;
}
#if (LFS_ENABLE == 1)
/* Check if the file exists in the lfs_files_list to be copied in NCP */
for (; file_lfs_index < files_list->nb_files; file_lfs_index++)
{
if (strncmp(files_list->lfs_files_list[file_lfs_index].name, filename, strlen(filename)) == 0)
{
/* File found in the lfs_files_list */
file_lfs_size = files_list->lfs_files_list[file_lfs_index].size;
break;
}
}
if ((file == NULL) && (file_lfs_index == files_list->nb_files))
{
/* File not found in the lfs_files_list */
SYS_LOG_ERROR("File not found in the Host LFS. Verify the filename and littlefs.bin generation");
ret = W6X_STATUS_ERROR;
goto _err;
}
#endif /* LFS_ENABLE */
/* Check if the file exists in the NCP */
for (; file_ncp_index < files_list->ncp_files_list.nb_files; file_ncp_index++)
{
if (strncmp(files_list->ncp_files_list.filename[file_ncp_index], filename, strlen(filename)) == 0)
{
/* File found in the NCP. Must to check if the content is the same */
uint32_t size = 0U;
/* Get the NCP file size */
ret = TranslateErrorStatus(W61_FS_GetSizeFile(p_DrvObj, filename, &size));
if (ret != W6X_STATUS_OK)
{
goto _err;
}
/* File found. Must to check if the size of Host lfs file and NCP file are equal */
#if (LFS_ENABLE == 1)
if (((file != NULL) && (len == size)) || (files_list->lfs_files_list[file_lfs_index].size == size))
#else
if (len == size)
#endif /* LFS_ENABLE */
{
read_offset = 0;
while (read_offset < size) /* Size of files are equal. Read and compare the files by block */
{
part_len = ((size - read_offset) < W6X_FS_READ_BLOCK_SIZE) ? (size - read_offset) : W6X_FS_READ_BLOCK_SIZE;
/* Read a part of the NCP file */
ret = W6X_FS_ReadFile(filename, read_offset, ncp_buf, part_len);
if (ret != W6X_STATUS_OK)
{
goto _err;
}
#if (LFS_ENABLE == 1)
/* Read a part of the Host file */
read_len = ef_get_env_blob_offset(filename, buf, part_len, NULL, read_offset);
if ((read_len <= 0) || (read_len != part_len))
{
ret = W6X_STATUS_ERROR;
goto _err;
}
/* Compare the two buffers */
if (memcmp(ncp_buf, buf, part_len) != 0)
{
/* File content is different: Delete operation requested */
SYS_LOG_DEBUG("File content is different: Delete operation requested\n");
(void)W61_FS_DeleteFile(p_DrvObj, filename);
break;
}
#else
/* Compare the two buffers */
if (memcmp(ncp_buf, &file[read_offset], part_len) != 0)
{
/* File content is different: Delete operation requested */
SYS_LOG_DEBUG("File content is different: Delete operation requested\n");
(void)W61_FS_DeleteFile(p_DrvObj, filename);
break;
}
#endif /* LFS_ENABLE */
if (size == (read_offset + part_len))
{
/* File already exists in the NCP and the content is the same */
SYS_LOG_DEBUG("File already exists in the NCP and the content is the same\n");
ret = W6X_STATUS_OK;
goto _err;
}
read_offset += part_len;
}
}
else
{
/* File already exists in the NCP but the size is different: Delete operation requested */
SYS_LOG_DEBUG("File size is different: Delete operation requested\n");
(void)W61_FS_DeleteFile(p_DrvObj, filename);
}
break;
}
}
/* Create the file entry */
ret = TranslateErrorStatus(W61_FS_CreateFile(p_DrvObj, filename));
if (ret != W6X_STATUS_OK)
{
if (ret == W6X_STATUS_ERROR)
{
SYS_LOG_ERROR("Unable to create file in NCP\n");
}
goto _err;
}
/* Copy the file content */
read_offset = 0;
#if (LFS_ENABLE == 0)
file_lfs_size = len;
#endif /* LFS_ENABLE */
do
{
#if (LFS_ENABLE == 1)
/* Read data in Host lfs */
read_len = ef_get_env_blob_offset(filename, buf, W6X_FS_READ_BLOCK_SIZE, NULL, read_offset);
if (read_len <= 0)
{
SYS_LOG_ERROR("Unable to read file in Host LFS\n");
goto _err;
}
/* Write data to the file */
ret = TranslateErrorStatus(W61_FS_WriteFile(p_DrvObj, filename, read_offset, buf, read_len));
read_offset += read_len;
#else
part_len = ((len - read_offset) < W6X_FS_READ_BLOCK_SIZE) ? (len - read_offset) : W6X_FS_READ_BLOCK_SIZE;
ret = TranslateErrorStatus(W61_FS_WriteFile(p_DrvObj, filename, read_offset,
(uint8_t *)&file[read_offset], part_len));
read_offset += part_len;
#endif /* LFS_ENABLE */
if (ret != W6X_STATUS_OK)
{
if (ret == W6X_STATUS_ERROR)
{
SYS_LOG_ERROR("Unable to write file in NCP\n");
}
goto _err;
}
} while (read_offset < file_lfs_size);
SYS_LOG_DEBUG("File copied to NCP\n");
_err:
if (ncp_buf != NULL)
{
vPortFree(ncp_buf);
}
#if (LFS_ENABLE == 1)
if (buf != NULL)
{
vPortFree(buf);
}
#endif /* LFS_ENABLE */
return ret;
}
W6X_Status_t W6X_FS_ReadFile(char filename[W6X_SYS_FS_FILENAME_SIZE], uint32_t offset, uint8_t *data, uint32_t len)
{
NULL_ASSERT(p_DrvObj, W6X_Sys_Uninit_str);
/* Read data from the file */
return TranslateErrorStatus(W61_FS_ReadFile(p_DrvObj, filename, offset, data, len));
}
W6X_Status_t W6X_FS_DeleteFile(char filename[W6X_SYS_FS_FILENAME_SIZE])
{
NULL_ASSERT(p_DrvObj, W6X_Sys_Uninit_str);
/* Delete the file */
return TranslateErrorStatus(W61_FS_DeleteFile(p_DrvObj, filename));
}
W6X_Status_t W6X_FS_GetSizeFile(char filename[W6X_SYS_FS_FILENAME_SIZE], uint32_t *size)
{
NULL_ASSERT(p_DrvObj, W6X_Sys_Uninit_str);
/* Get the size of the file */
return TranslateErrorStatus(W61_FS_GetSizeFile(p_DrvObj, filename, size));
}
W6X_Status_t W6X_FS_ListFiles(W6X_FS_FilesListFull_t **files_list)
{
W6X_Status_t ret = W6X_STATUS_ERROR;
NULL_ASSERT(p_DrvObj, W6X_Sys_Uninit_str);
if (W6X_FilesList == NULL)
{
/* Allocate the files list to store all filenames */
W6X_FilesList = pvPortMalloc(sizeof(W6X_FS_FilesListFull_t));
if (W6X_FilesList == NULL)
{
SYS_LOG_ERROR("Unable to allocate memory for files list\n");
goto _err;
}
}
/* Clear the list */
(void)memset(W6X_FilesList, 0, sizeof(W6X_FS_FilesListFull_t));
#if (LFS_ENABLE == 1)
/* List the host files */
(void)ef_print_env(W6X_FilesList->lfs_files_list, &W6X_FilesList->nb_files);
#endif /* LFS_ENABLE */
/* List the NCP files */
ret = TranslateErrorStatus(W61_FS_ListFiles(p_DrvObj, (W61_FS_FilesList_t *)&W6X_FilesList->ncp_files_list));
if (ret != W6X_STATUS_OK)
{
goto _err;
}
*files_list = W6X_FilesList;
_err:
return ret;
}
W6X_Status_t W6X_SetPowerMode(uint32_t ps_mode)
{
NULL_ASSERT(p_DrvObj, W6X_Sys_Uninit_str);
/* Set the power save mode */
return TranslateErrorStatus(W61_SetPowerMode(p_DrvObj, (ps_mode == 0U) ? 0U : 2U, 0U));
}
W6X_Status_t W6X_GetPowerMode(uint32_t *ps_mode)
{
W6X_Status_t ret;
uint32_t mode = 0;
NULL_ASSERT(p_DrvObj, W6X_Sys_Uninit_str);
/* Get the power save mode */
ret = TranslateErrorStatus(W61_GetPowerMode(p_DrvObj, &mode));
*ps_mode = (mode == 0U) ? 0U : 1U;
return ret;
}
W6X_Status_t W6X_Reset(uint8_t restore)
{
NULL_ASSERT(p_DrvObj, W6X_Sys_Uninit_str);
if (p_DrvObj->ResetCfg.PS_mode < 0) /* Power save mode not saved yet */
{
/* Save the current power save mode */
if (W6X_GetPowerMode((uint32_t *)&p_DrvObj->ResetCfg.PS_mode) != W6X_STATUS_OK)
{
goto _err;
}
}
/* Disable the power save mode */
if (W6X_SetPowerMode(0) != W6X_STATUS_OK)
{
goto _err;
}
/* DeInit the modules */
if (p_DrvObj->ResetCfg.WiFi_status == W61_MODULE_STATE_INIT)
{
W6X_WiFi_DeInit();
/* Backup the Wi-Fi state to restore it after reset */
p_DrvObj->ResetCfg.WiFi_status = W61_MODULE_STATE_INIT_PENDING;
}
#if (ST67_ARCH == W6X_ARCH_T01)
if (p_DrvObj->ResetCfg.Net_status == W61_MODULE_STATE_INIT)
{
W6X_Net_DeInit();
/* Backup the Network state to restore it after reset */
p_DrvObj->ResetCfg.Net_status = W61_MODULE_STATE_INIT_PENDING;
}
#endif /* ST67_ARCH */
if (p_DrvObj->ResetCfg.Ble_status == W61_MODULE_STATE_INIT)
{
/* Save BLE buffer and mode information */
p_DrvObj->ResetCfg.Ble_mode = p_DrvObj->BleCtx.NetSettings.Mode;
p_DrvObj->ResetCfg.Ble_BuffRecvData = p_DrvObj->BleCtx.AppBuffRecvData;
p_DrvObj->ResetCfg.Ble_BuffRecvDataSize = p_DrvObj->BleCtx.AppBuffRecvDataSize;
W6X_Ble_DeInit();
/* Backup the BLE state to restore it after reset */
p_DrvObj->ResetCfg.Ble_status = W61_MODULE_STATE_INIT_PENDING;
}
if (p_DrvObj->ResetCfg.FWU_requested == 1U)
{
/* Finish the firmware update and reboot the ST67W611M on the new firmware version if integrity check passes */
if (W61_Reset(p_DrvObj, W61_RESET_MODE_FWU) != W61_STATUS_OK)
{
goto _err;
}
}
else if (restore == 1U)
{
/* Reset the W61 module to factory default. This will erase all user data and reboot the ST67W611M */
if (W61_Reset(p_DrvObj, W61_RESET_MODE_RESTORE) != W61_STATUS_OK)
{
goto _err;
}
}
else
{
/* Reset the W61 module */
if (W61_Reset(p_DrvObj, W61_RESET_MODE_SOFT) != W61_STATUS_OK)
{
goto _err;
}
}
/* Set the wake-up pin to the ST67W611M */
if (W61_SetWakeUpPin(p_DrvObj, p_DrvObj->LowPowerCfg.WakeUpPinIn) != W61_STATUS_OK)
{
goto _err;
}
/* Restore the power save mode */
if (W6X_SetPowerMode((uint32_t)p_DrvObj->ResetCfg.PS_mode) != W6X_STATUS_OK)
{
goto _err;
}
p_DrvObj->ResetCfg.PS_mode = -1; /* Reset the backup variable */
/* If Wi-Fi was started, initialize the Wi-Fi module */
if (p_DrvObj->ResetCfg.WiFi_status == W61_MODULE_STATE_INIT_PENDING)
{
if (W6X_WiFi_Init() != W6X_STATUS_OK)
{
goto _err;
}
}
#if (ST67_ARCH == W6X_ARCH_T01)
/* If Network was started, initialize the Network module */
if (p_DrvObj->ResetCfg.Net_status == W61_MODULE_STATE_INIT_PENDING)
{
if (W6X_Net_Init() != W6X_STATUS_OK)
{
goto _err;
}
}
#endif /* ST67_ARCH */
/* If BLE was started, initialize the BLE module with previous configuration */
if (p_DrvObj->ResetCfg.Ble_status == W61_MODULE_STATE_INIT_PENDING)
{
if (W6X_Ble_Init((W6X_Ble_Mode_e)p_DrvObj->ResetCfg.Ble_mode,
p_DrvObj->ResetCfg.Ble_BuffRecvData,
p_DrvObj->ResetCfg.Ble_BuffRecvDataSize) != W6X_STATUS_OK)
{
goto _err;
}
}
return W6X_STATUS_OK;
_err:
SYS_LOG_ERROR("Restore default config failed.\n");
return W6X_STATUS_ERROR;
}
W6X_Status_t W6X_ExeATCommand(char *at_cmd)
{
return TranslateErrorStatus(W61_ExeATCommand(p_DrvObj, at_cmd));
}
const char *W6X_StatusToStr(W6X_Status_t status)
{
if (status > W6X_STATUS_UNKNOWN)
{
status = W6X_STATUS_UNKNOWN;
}
return W6X_status_strings[(uint8_t)status];
}
const char *W6X_ModelToStr(W6X_ModuleID_e module_id)
{
if (module_id > W6X_MODULE_ID_P)
{
module_id = W6X_MODULE_ID_UNDEF;
}
return W6X_module_strings[(uint8_t)module_id];
}
W6X_Status_t W6X_SdkMinVersion(uint8_t major, uint8_t sub1, uint8_t sub2)
{
NULL_ASSERT(p_DrvObj, W6X_Obj_Null_str);
if (W61_SdkMinVersion(p_DrvObj, major, sub1, sub2) != W61_STATUS_OK)
{
return W6X_STATUS_ERROR;
}
return W6X_STATUS_OK;
}
/** @} */
/** @addtogroup ST67W6X_API_FWU_Public_Functions
* @{
*/
W6X_Status_t W6X_FWU_Starts(uint32_t enable)
{
NULL_ASSERT(p_DrvObj, W6X_Obj_Null_str);
/* Start of firmware update on W61 currently supports only value 1 or 0 as parameters,
all other value will raise an error */
if ((enable != 0U) && (enable != 1U))
{
return W6X_STATUS_ERROR;
}
return TranslateErrorStatus(W61_FWU_starts(p_DrvObj, enable));
}
W6X_Status_t W6X_FWU_Finish(void)
{
W6X_Status_t ret;
NULL_ASSERT(p_DrvObj, W6X_FWU_Uninit_str);
/* Set the firmware update requested flag to avoid any operation
* on the module until the end of the firmware update process */
p_DrvObj->ResetCfg.FWU_requested = 1U;
/* Finish the firmware update and reboot the ST67W611M on the new firmware version if integrity check passes
* Perform a module reset to reinitialize all contexts to their initial state */
ret = W6X_Reset(0U);
/* Reset the firmware update requested flag to allow normal operation of the module */
p_DrvObj->ResetCfg.FWU_requested = 0U;
return ret;
}
W6X_Status_t W6X_FWU_Send(uint8_t *buff, uint32_t len)
{
NULL_ASSERT(p_DrvObj, W6X_FWU_Uninit_str);
NULL_ASSERT(buff, "buff not defined");
if (len == 0U)
{
return W6X_STATUS_OK;
}
return TranslateErrorStatus(W61_FWU_Send(p_DrvObj, buff, len));
}
/** @} */
/** @addtogroup ST67W6X_Private_Common_Functions
* @{
*/
W6X_Status_t TranslateErrorStatus_W61_W6X(W61_Status_t ret_w61, char const *func_name)
{
W6X_Status_t ret_w6x;
/* Translate the W61 status to the W6X status */
switch (ret_w61)
{
case W61_STATUS_OK:
ret_w6x = W6X_STATUS_OK;
break;
case W61_STATUS_BUSY:
ret_w6x = W6X_STATUS_BUSY;
break;
case W61_STATUS_TIMEOUT:
ret_w6x = W6X_STATUS_TIMEOUT;
break;
case W61_STATUS_UNEXPECTED_RESPONSE:
ret_w6x = W6X_STATUS_UNEXPECTED_RESPONSE;
break;
default:
ret_w6x = W6X_STATUS_ERROR;
break;
}
if ((ret_w6x != W6X_STATUS_OK) && (W6X_CbHandler.APP_error_cb != NULL))
{
/* Call the error callback */
W6X_CbHandler.APP_error_cb(ret_w6x, func_name);
}
return ret_w6x;
}
/** @} */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,957 @@
/**
******************************************************************************
* @file modem_cmd_handler.c
* @author ST67 Application Team
* @brief Modem command handler for modem context driver
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/**
* Portions of this file are based on Zephyr Project,
* which is licensed under the Apache-2.0 license as indicated below.
* See https://github.com/zephyrproject-rtos/zephyr for more information.
*
* Reference source:
* https://github.com/zephyrproject-rtos/zephyr/blob/main/drivers/modem/modem_cmd_handler.c
*/
/*
* Copyright (c) 2019-2020 Foundries.io
*
* SPDX-License-Identifier: Apache-2.0
*/
/* Includes ------------------------------------------------------------------*/
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "FreeRTOS.h"
#include "semphr.h"
#include "modem_cmd_handler.h"
#include "w61_default_config.h"
#include "logging.h"
/* Private macros ------------------------------------------------------------*/
/** @addtogroup ST67W61_AT_Modem_Cmd_Handler_Macros
* @{
*/
/**
* \def LOG_ERR( ... )
* Send a message to the log with level ::LOG_ERR.
*/
/**
* \def LOG_DBG( ... )
* Send a message to the log with level ::LOG_DEBUG.
*/
/**
* \def LOG_HEXDUMP_DBG( ... )
* Send a hex dump message to the log with level ::LOG_DEBUG.
*/
#if (MDM_CMD_LOG_ENABLE == 1)
#define LOG_ERR(...) LogError(__VA_ARGS__)
#define LOG_DBG(...) LogDebug(__VA_ARGS__)
#define LOG_HEXDUMP_DBG(...)
#else
#define LOG_ERR(...)
#define LOG_DBG(...)
#define LOG_HEXDUMP_DBG(...)
#endif /* MDM_CMD_LOG_ENABLE */
/** @} */
/* Private function prototypes -----------------------------------------------*/
/** @addtogroup ST67W61_AT_Modem_Cmd_Handler_Functions
* @{
*/
/**
* @brief Checks if the given character is a carriage return (CR) or line feed (LF)
* @param c: The character to check
* @return true if the character is either (CR) or (LF), false otherwise
*/
static bool is_crlf(uint8_t c);
/**
* @brief Skips carriage return and line feed characters in the modem command handler data
* @details This function advances the internal pointer or index within the provided
* modem_cmd_handler_data structure to bypass any CR or LF characters.
* It is typically used to ignore line endings when parsing modem responses or commands.
* @param data: Pointer to the modem_cmd_handler_data structure containing the buffer
* and current parsing position
*/
static void skipcrlf(struct modem_cmd_handler_data *data);
/**
* @brief Finds the position of the next carriage return (CR) or line feed (LF) character
* @details This function scans the modem command handler data buffer for the next occurrence
* of a CR or LF character and returns its position.
* @param data: Pointer to the modem_cmd_handler_data structure containing the buffer
* and current parsing position
* @param offset: Pointer to a variable to store the offset of the found character
* @return uint16_t: The position of the found character, or 0 if not found
*/
static uint16_t findcrlf(struct modem_cmd_handler_data *data, uint16_t *offset);
/**
* @brief Checks if the given buffer starts with the specified string
* @details This function compares the beginning of the buffer with the provided
* null-terminated string and returns true if the buffer starts with the string.
*
* @param buf: Pointer to the buffer to check
* @param buf_len: Length of the buffer in bytes
* @param str: Null-terminated string to compare with the start of the buffer
* @return true if the buffer starts with the specified string, false otherwise
*/
static bool starts_with(const uint8_t *buf, size_t buf_len, const char *str);
/**
* @brief Skips the first n bytes in the given linear buffer
* @details This function advances the buffer pointer by n bytes and decreases the buffer length accordingly.
* @param rx_buf: Pointer to the buffer to be modified
* @param rx_buf_len: Pointer to the length of the buffer; will be updated after skipping
* @param n: Number of bytes to skip from the beginning of the buffer
*/
static void linear_buf_skip(uint8_t *rx_buf, size_t *rx_buf_len, size_t n);
/**
* @brief Parses parameters from the matched command in the modem command handler data
* @details This function extracts parameters from the matched command string in the
* modem_cmd_handler_data structure, based on the specified command definition.
* It populates the argv array with pointers to the parsed parameters and updates
* the argc count. The function handles quoted parameters and ensures that the
* number of parsed parameters falls within the defined minimum and maximum limits.
* @param data: Pointer to the modem_cmd_handler_data structure containing the matched command
* @param match_len: Length of the matched command string
* @param cmd: Pointer to the modem_cmd structure defining the command and its parameters
* @param argv: Array of pointers to store the addresses of parsed parameters
* @param argv_len: Length of the argv array (maximum number of parameters it can hold)
* @param argc: Pointer to a variable to store the count of parsed parameters
* @return On success, returns the number of bytes parsed for parameters;
* On error, returns a negative error code (e.g., -EINVAL for invalid arguments)
*/
static int32_t parse_params(struct modem_cmd_handler_data *data, size_t match_len,
const struct modem_cmd *cmd, uint8_t **argv, size_t argv_len, uint16_t *argc);
/**
* @brief Processes a matched command in the modem command handler
* @details This function is responsible for executing the matched command
* and handling its parameters. It validates the command and
* invokes the appropriate command handler function.
* @param cmd: Pointer to the modem_cmd structure defining the command
* @param match_len: Length of the matched command string
* @param data: Pointer to the modem_cmd_handler_data structure containing
* the current state and data for command processing
* @return On success, returns 0; on error, returns a negative error code
*/
static int32_t process_cmd(const struct modem_cmd *cmd, size_t match_len, struct modem_cmd_handler_data *data);
/**
* @brief Finds a matching command in the modem command handler data
* @details This function searches through the command lists in the modem_cmd_handler_data
* structure to find a command that matches the current input buffer (match_buf).
* It checks the response handlers, unsolicited handlers, and currently assigned handlers.
* @param data: Pointer to the modem_cmd_handler_data structure containing the command lists
* @return Pointer to the matched modem_cmd structure if a match is found; NULL otherwise
*/
static const struct modem_cmd *find_cmd_match(struct modem_cmd_handler_data *data);
/**
* @brief Finds a direct match command in the modem command handler data
* @details This function searches through the command lists in the modem_cmd_handler_data
* structure to find a command that directly matches the start of the current
* input buffer (rx_buf). It checks for commands marked with the 'direct' flag.
* @param data: Pointer to the modem_cmd_handler_data structure containing the command lists
* @return Pointer to the matched modem_cmd structure if a direct match is found; NULL otherwise
*/
static const struct modem_cmd *find_cmd_direct_match(struct modem_cmd_handler_data *data);
/**
* @brief Process incoming data from the modem interface
* @details This function reads data from the modem interface and appends it to the
* receive buffer in the modem_cmd_handler_data structure. It handles reading
* as much data as possible without exceeding the buffer size.
* @param data: Pointer to the modem_cmd_handler_data structure containing the receive buffer
* @param iface: Pointer to the modem_iface structure representing the modem interface
* @return On success, returns 0; on error, returns a negative error code
*/
static int32_t cmd_handler_process_iface_data(struct modem_cmd_handler_data *data, struct modem_iface *iface);
/**
* @brief Process the received data in the modem command handler
* @details This function processes the data in the receive buffer of the
* modem_cmd_handler_data structure. It looks for complete commands
* terminated by CR/LF, matches them against known commands, and
* invokes the corresponding command handlers.
* @param data: Pointer to the modem_cmd_handler_data structure containing the receive buffer
*/
static void cmd_handler_process_rx_buf(struct modem_cmd_handler_data *data);
/**
* @brief Process the modem command handler
* @details This function processes the modem command handler by invoking the
* appropriate command handler functions based on the current state
* and received data.
* @param cmd_handler: Pointer to the modem_cmd_handler structure representing the command handler
* @param iface: Pointer to the modem_iface structure representing the modem interface
*/
static void cmd_handler_process(struct modem_cmd_handler *cmd_handler, struct modem_iface *iface);
/* Private Functions Definition ----------------------------------------------*/
static bool is_crlf(uint8_t c)
{
if ((c == 0x0AU) || (c == 0x0DU))
{
return true;
}
else
{
return false;
}
}
static void skipcrlf(struct modem_cmd_handler_data *data)
{
size_t skip_count = 0;
if ((data == NULL) || (data->rx_buf == NULL) || (data->rx_buf_len == 0U))
{
return;
}
while ((skip_count < data->rx_buf_len) && is_crlf(data->rx_buf[skip_count]))
{
skip_count++;
}
if (skip_count > 0U)
{
linear_buf_skip(data->rx_buf, &data->rx_buf_len, skip_count);
}
}
static uint16_t findcrlf(struct modem_cmd_handler_data *data, uint16_t *offset)
{
if ((data == NULL) || (data->rx_buf == NULL) || (data->rx_buf_len == 0U) || (offset == NULL))
{
return 0;
}
for (size_t i = 0; i < data->rx_buf_len; ++i)
{
if (is_crlf(data->rx_buf[i]))
{
*offset = (uint16_t)i;
return (uint16_t)i;
}
}
return 0;
}
static bool starts_with(const uint8_t *buf, size_t buf_len, const char *str)
{
size_t i = 0;
while ((i < buf_len) && (*str != '\0'))
{
if (buf[i] != (uint8_t)*str)
{
return false;
}
i++;
str++;
}
return *str == '\0';
}
static void linear_buf_skip(uint8_t *rx_buf, size_t *rx_buf_len, size_t n)
{
if (n >= *rx_buf_len)
{
*rx_buf_len = 0;
}
else
{
for (size_t i = 0; i < (*rx_buf_len - n); ++i)
{
rx_buf[i] = rx_buf[i + n];
}
*rx_buf_len -= n;
}
}
static int32_t parse_params(struct modem_cmd_handler_data *data, size_t match_len,
const struct modem_cmd *cmd, uint8_t **argv, size_t argv_len, uint16_t *argc)
{
uint32_t count = 0;
size_t delim_len, begin, end, i;
bool quoted = false;
if ((data == NULL) || (data->match_buf == NULL) || (match_len == 0U) || (cmd == NULL) ||
(argv == NULL) || (argc == NULL))
{
return -EINVAL;
}
begin = cmd->cmd_len;
end = cmd->cmd_len;
delim_len = strlen(cmd->delim);
while (end < match_len)
{
/* Don't look for delimiters in the middle of a quoted parameter */
if (data->match_buf[end] == '"')
{
quoted = !quoted;
}
if (quoted)
{
end++;
continue;
}
/* Look for delimiter characters */
for (i = 0; i < delim_len; i++)
{
if (data->match_buf[end] == cmd->delim[i])
{
/* Mark a parameter beginning */
argv[*argc] = (uint8_t *)&data->match_buf[begin];
/* End parameter with NUL char */
data->match_buf[end] = '\0';
/* Bump begin */
begin = end + 1U;
count += 1U;
(*argc)++;
break;
}
}
if (count >= cmd->arg_count_max)
{
break;
}
if (*argc == argv_len)
{
break;
}
end++;
}
/* Consider the ending portion a param if end > begin */
if (end > begin)
{
/* Mark a parameter beginning */
argv[*argc] = (uint8_t *)&data->match_buf[begin];
/* End parameter with NUL char
* NOTE: if this is at the end of match_len will probably
* be overwriting a NUL that's already there
*/
data->match_buf[end] = '\0';
(*argc)++;
}
/* Missing arguments */
if (*argc < cmd->arg_count_min)
{
/* Do not return -EAGAIN here as there is no way new argument
* can be parsed later because match_len is computed to be
* the minimum of the distance to the first CRLF and the size
* of the buffer.
* Therefore, waiting more data on the interface won't change
* match_len value, which mean there is no point in waiting
* for more arguments, this will just end in a infinite loop
* parsing data and finding that some arguments are missing.
*/
return -EINVAL;
}
/*
* Return the beginning of the next unfinished param so don't
* "skip" any data that could be parsed later.
*/
return begin - cmd->cmd_len;
}
static int32_t process_cmd(const struct modem_cmd *cmd, size_t match_len, struct modem_cmd_handler_data *data)
{
int32_t parsed_len = 0;
int32_t ret = 0;
uint8_t *argv[CONFIG_MODEM_CMD_HANDLER_MAX_PARAM_COUNT];
uint16_t argc = 0U;
/* Reset params */
(void)memset(argv, 0, sizeof(argv[0]) * ARRAY_SIZE(argv));
/* Needed to parse arguments? */
if (cmd->arg_count_max > 0U)
{
/* Returns < 0 on error and > 0 for parsed len */
parsed_len = parse_params(data, match_len, cmd,
argv, ARRAY_SIZE(argv), &argc);
if (parsed_len < 0)
{
return parsed_len;
}
}
/* Skip cmd_len + parsed len */
size_t skip_len = cmd->cmd_len + parsed_len;
/* Store original rx_buf */
uint8_t *orig_rx_buf = data->rx_buf;
size_t orig_rx_buf_len = data->rx_buf_len;
if ((skip_len > 0U) && (skip_len <= data->rx_buf_len))
{
data->rx_buf += skip_len;
data->rx_buf_len -= skip_len;
}
/* Call handler */
if (cmd->func != NULL)
{
ret = cmd->func(data, match_len - cmd->cmd_len - parsed_len,
argv, argc);
}
/* Restore rx_buf */
data->rx_buf = orig_rx_buf;
data->rx_buf_len = orig_rx_buf_len;
if ((ret != -EAGAIN) && (data->rx_buf != NULL))
{
/* Skip in case consumed */
linear_buf_skip(data->rx_buf, &data->rx_buf_len, skip_len);
}
return ret;
}
static const struct modem_cmd *find_cmd_match(struct modem_cmd_handler_data *data)
{
for (uint32_t j = 0; j < ARRAY_SIZE(data->cmds); j++)
{
if ((data->cmds[j] == NULL) || (data->cmds_len[j] == 0U))
{
continue;
}
for (size_t i = 0; i < data->cmds_len[j]; i++)
{
/* Match on "empty" cmd */
if (((data->cmds[j][i].cmd != NULL) && (data->match_buf != NULL)) &&
((strlen(data->cmds[j][i].cmd) == 0U) ||
(strncmp(data->match_buf, data->cmds[j][i].cmd, data->cmds[j][i].cmd_len) == 0)))
{
return &data->cmds[j][i];
}
}
}
return NULL;
}
static const struct modem_cmd *find_cmd_direct_match(struct modem_cmd_handler_data *data)
{
if (data->rx_buf == NULL)
{
return NULL;
}
for (size_t j = 0; j < ARRAY_SIZE(data->cmds); j++)
{
if ((data->cmds[j] == NULL) || (data->cmds_len[j] == 0U))
{
continue;
}
for (size_t i = 0; i < data->cmds_len[j]; i++)
{
/* Match start of cmd */
if ((data->cmds[j][i].cmd != NULL) &&
data->cmds[j][i].direct &&
((data->cmds[j][i].cmd[0] == '\0') ||
starts_with(data->rx_buf, data->rx_buf_len, data->cmds[j][i].cmd)))
{
return &data->cmds[j][i];
}
}
}
return NULL;
}
static int32_t cmd_handler_process_iface_data(struct modem_cmd_handler_data *data, struct modem_iface *iface)
{
size_t bytes_read = 0;
int32_t ret;
if ((data->rx_buf == NULL) || (iface == NULL) || (iface->mdm_read == NULL))
{
return -EINVAL;
}
/* Read as much as possible into the linear buffer */
size_t room = RX_BUF_SIZE - data->rx_buf_len;
if (room == 0U)
{
return -ENOMEM;
}
ret = iface->mdm_read(iface, data->rx_buf + data->rx_buf_len, room, &bytes_read);
if ((ret < 0) || (bytes_read == 0U))
{
return 0;
}
data->rx_buf_len += bytes_read;
return 0;
}
static void cmd_handler_process_rx_buf(struct modem_cmd_handler_data *data)
{
const struct modem_cmd *cmd;
size_t match_len;
int32_t ret;
uint16_t offset;
uint16_t len;
if ((data->rx_buf == NULL) || (data->match_buf == NULL))
{
return;
}
while (data->rx_buf_len > 0U)
{
skipcrlf(data);
if (data->rx_buf_len == 0U)
{
break;
}
/* Direct match */
cmd = find_cmd_direct_match(data);
if ((cmd != NULL) && (cmd->func != NULL))
{
ret = cmd->func(data, cmd->cmd_len, NULL, 0);
if (ret == -EAGAIN)
{
break;
}
else if (ret > 0)
{
LOG_DBG("match direct cmd [%s] (ret:%" PRIi32 ")\n", cmd->cmd, ret);
linear_buf_skip(data->rx_buf, &data->rx_buf_len, ret);
}
else
{
/* Unhandled case */
}
continue;
}
/* Find CRLF */
len = findcrlf(data, &offset);
if (len == 0U)
{
break;
}
/* Copy up to CRLF into match_buf */
match_len = (len < data->match_buf_len - 1) ? len : data->match_buf_len - 1;
(void)memcpy(data->match_buf, data->rx_buf, match_len);
data->match_buf[match_len] = '\0';
#if defined(CONFIG_MODEM_CONTEXT_VERBOSE_DEBUG)
LOG_HEXDUMP_DBG(data->match_buf, match_len, "RECV");
#endif /* CONFIG_MODEM_CONTEXT_VERBOSE_DEBUG */
(void)xSemaphoreTake(data->sem_parse_lock, portMAX_DELAY);
cmd = find_cmd_match(data);
if (cmd != NULL)
{
LOG_DBG("match cmd [%s] (len:%" PRIu32 ")\n", cmd->cmd, match_len);
ret = process_cmd(cmd, match_len, data);
if (ret == -EAGAIN)
{
(void)xSemaphoreGive(data->sem_parse_lock);
break;
}
else if (ret < 0)
{
LOG_ERR("process cmd [%s] (len:%" PRIu32 ", ret:%" PRIi32 ")\n", cmd->cmd, match_len, ret);
}
else
{
/* Unhandled case */
}
if (data->rx_buf_len == 0U)
{
(void)xSemaphoreGive(data->sem_parse_lock);
break;
}
/* Find CRLF again to skip processed line */
(void)findcrlf(data, &offset);
}
(void)xSemaphoreGive(data->sem_parse_lock);
if ((data->rx_buf != NULL) && (data->rx_buf_len != 0U))
{
linear_buf_skip(data->rx_buf, &data->rx_buf_len, offset + 1U);
}
}
}
static void cmd_handler_process(struct modem_cmd_handler *cmd_handler, struct modem_iface *iface)
{
struct modem_cmd_handler_data *data;
int32_t err;
if ((cmd_handler == NULL) || (cmd_handler->cmd_handler_data == NULL) ||
(iface == NULL) || (iface->mdm_read == NULL))
{
return;
}
data = (struct modem_cmd_handler_data *)(cmd_handler->cmd_handler_data);
do
{
err = cmd_handler_process_iface_data(data, iface);
cmd_handler_process_rx_buf(data);
} while (err == 0);
}
/* Functions Definition ------------------------------------------------------*/
int32_t modem_cmd_handler_get_error(struct modem_cmd_handler_data *data)
{
if (data == NULL)
{
return -EINVAL;
}
return data->last_error;
}
int32_t modem_cmd_handler_set_error(struct modem_cmd_handler_data *data, int32_t error_code)
{
if (data == NULL)
{
return -EINVAL;
}
data->last_error = error_code;
return 0;
}
int32_t modem_cmd_handler_update_cmds(struct modem_cmd_handler_data *data,
const struct modem_cmd *handler_cmds,
size_t handler_cmds_len,
bool reset_error_flag)
{
if (data == NULL)
{
return -EINVAL;
}
data->cmds[CMD_HANDLER] = handler_cmds;
data->cmds_len[CMD_HANDLER] = handler_cmds_len;
if (reset_error_flag)
{
data->last_error = 0;
}
return 0;
}
int32_t modem_cmd_handler_await(struct modem_cmd_handler_data *data,
SemaphoreHandle_t sem, TickType_t timeout)
{
int32_t ret = xSemaphoreTake(sem, timeout);
if (ret == pdTRUE)
{
ret = modem_cmd_handler_get_error(data);
}
else
{
ret = -ETIMEDOUT;
}
return ret;
}
int32_t modem_cmd_send_data_nolock(struct modem_iface *iface,
const uint8_t *buf, size_t len)
{
if ((iface == NULL) || (iface->mdm_write == NULL) || (buf == NULL))
{
return -EINVAL;
}
#if defined(CONFIG_MODEM_CONTEXT_VERBOSE_DEBUG)
if (len > 256)
{
/* Truncate the message, since too long log messages gets dropped somewhere. */
LOG_HEXDUMP_DBG(buf, 256, "SENT DIRECT DATA (truncated)");
}
else
{
LOG_HEXDUMP_DBG(buf, len, "SENT DIRECT DATA");
}
#endif /* CONFIG_MODEM_CONTEXT_VERBOSE_DEBUG */
return iface->mdm_write(iface, buf, len);
}
int32_t modem_cmd_send_ext(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct modem_cmd *handler_cmds,
size_t handler_cmds_len, const uint8_t *buf,
SemaphoreHandle_t sem, TickType_t timeout, uint32_t flags)
{
struct modem_cmd_handler_data *data;
int32_t ret = 0;
if ((iface == NULL) || (iface->mdm_write == NULL) ||
(handler == NULL) || (handler->cmd_handler_data == NULL) ||
(buf == NULL))
{
return -EINVAL;
}
if (timeout == 0U)
{
/* Semaphore is not needed if there is no timeout */
sem = NULL;
}
else
{
if (sem == NULL)
{
/* Cannot respect timeout without semaphore */
return -EINVAL;
}
}
data = (struct modem_cmd_handler_data *)(handler->cmd_handler_data);
if ((flags & MODEM_NO_TX_LOCK) == 0U)
{
(void)xSemaphoreTake(data->sem_tx_lock, portMAX_DELAY);
}
if ((flags & MODEM_NO_SET_CMDS) == 0U)
{
ret = modem_cmd_handler_update_cmds(data, handler_cmds,
handler_cmds_len, true);
if (ret < 0)
{
goto unlock_tx_lock;
}
}
#if defined(CONFIG_MODEM_CONTEXT_VERBOSE_DEBUG)
LOG_HEXDUMP_DBG(buf, strlen(buf), "SENT DATA");
if (data->eol_len > 0)
{
if (data->eol[0] != '\r')
{
LOG_HEXDUMP_DBG(data->eol, data->eol_len, "SENT EOL");
}
}
else
{
LOG_DBG("EOL not set!!!");
}
#endif /* CONFIG_MODEM_CONTEXT_VERBOSE_DEBUG */
if (sem != NULL)
{
(void)xSemaphoreTake(sem, 0); /* Reset semaphore (binary) */
}
(void)iface->mdm_write(iface, buf, strlen((char *)buf));
(void)iface->mdm_write(iface, (uint8_t const *)data->eol, data->eol_len);
if (sem != NULL)
{
ret = modem_cmd_handler_await(data, sem, timeout);
}
if ((flags & MODEM_NO_UNSET_CMDS) == 0U)
{
(void)modem_cmd_handler_update_cmds(data, NULL, 0U, false);
}
unlock_tx_lock:
if ((flags & MODEM_NO_TX_LOCK) == 0U)
{
(void)xSemaphoreGive(data->sem_tx_lock);
}
return ret;
}
/* Run a set of AT commands */
int32_t modem_cmd_handler_setup_cmds(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct setup_cmd *cmds, size_t cmds_len,
SemaphoreHandle_t sem, TickType_t timeout)
{
int32_t ret = 0;
size_t i;
for (i = 0; i < cmds_len; i++)
{
if ((cmds[i].handle_cmd.cmd != NULL) && (cmds[i].handle_cmd.func != NULL))
{
ret = modem_cmd_send(iface, handler,
&cmds[i].handle_cmd, 1U,
(uint8_t const *)cmds[i].send_cmd,
sem, timeout);
}
else
{
ret = modem_cmd_send(iface, handler,
NULL, 0, (uint8_t const *)cmds[i].send_cmd,
sem, timeout);
}
vTaskDelay(pdMS_TO_TICKS(50));
if (ret < 0)
{
LOG_ERR("command %s ret:%" PRIi32 "\n", cmds[i].send_cmd, ret);
break;
}
}
return ret;
}
/* Run a set of AT commands, without lock */
int32_t modem_cmd_handler_setup_cmds_nolock(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct setup_cmd *cmds,
size_t cmds_len, SemaphoreHandle_t sem,
TickType_t timeout)
{
int32_t ret = 0;
size_t i;
for (i = 0; i < cmds_len; i++)
{
if ((cmds[i].handle_cmd.cmd != NULL) && (cmds[i].handle_cmd.func != NULL))
{
ret = modem_cmd_send_nolock(iface, handler,
&cmds[i].handle_cmd, 1U,
(uint8_t const *)cmds[i].send_cmd,
sem, timeout);
}
else
{
ret = modem_cmd_send_nolock(iface, handler,
NULL, 0, (uint8_t const *)cmds[i].send_cmd,
sem, timeout);
}
vTaskDelay(pdMS_TO_TICKS(50));
if (ret < 0)
{
LOG_ERR("command %s ret:%" PRIi32 "\n", cmds[i].send_cmd, ret);
break;
}
}
return ret;
}
int32_t modem_cmd_handler_tx_lock(struct modem_cmd_handler *handler,
TickType_t timeout)
{
struct modem_cmd_handler_data *data;
data = (struct modem_cmd_handler_data *)(handler->cmd_handler_data);
if (data == NULL)
{
return -EINVAL;
}
return xSemaphoreTake(data->sem_tx_lock, timeout) == pdTRUE ? 0 : -ETIMEDOUT;
}
void modem_cmd_handler_tx_unlock(struct modem_cmd_handler *handler)
{
struct modem_cmd_handler_data *data;
data = (struct modem_cmd_handler_data *)(handler->cmd_handler_data);
if (data == NULL)
{
return;
}
(void)xSemaphoreGive(data->sem_tx_lock);
}
int32_t modem_cmd_handler_init(struct modem_cmd_handler *handler,
struct modem_cmd_handler_data *data,
const struct modem_cmd_handler_config *config)
{
/* Verify arguments */
if ((handler == NULL) || (data == NULL) || (config == NULL))
{
return -EINVAL;
}
/* Verify config */
if ((config->match_buf == NULL) || (config->match_buf_len == 0U) ||
((NULL != config->response_cmds) && (0U == config->response_cmds_len)) ||
((NULL != config->unsol_cmds) && (0U == config->unsol_cmds_len)))
{
return -EINVAL;
}
/* Assign data to command handler */
handler->cmd_handler_data = data;
/* Init rx_buf_len */
data->rx_buf_len = 0U;
/* Assign command process implementation to command handler */
handler->process = cmd_handler_process;
/* Store arguments */
data->match_buf = config->match_buf;
data->match_buf_len = config->match_buf_len;
data->eol = config->eol;
data->cmds[CMD_RESP] = config->response_cmds;
data->cmds_len[CMD_RESP] = config->response_cmds_len;
data->cmds[CMD_UNSOL] = config->unsol_cmds;
data->cmds_len[CMD_UNSOL] = config->unsol_cmds_len;
/* Process end of line */
data->eol_len = (data->eol == NULL) ? 0U : strlen(data->eol);
/* Store optional user data */
data->user_data = config->user_data;
/* Initialize command handler data members */
data->sem_tx_lock = xSemaphoreCreateMutex();
data->sem_parse_lock = xSemaphoreCreateMutex();
return 0;
}
/** @} */
@@ -0,0 +1,497 @@
/**
******************************************************************************
* @file modem_cmd_handler.h
* @author ST67 Application Team
* @brief Modem command handler header file
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/**
* Portions of this file are based on Zephyr Project,
* which is licensed under the Apache-2.0 license as indicated below.
* See https://github.com/zephyrproject-rtos/zephyr for more information.
*
* Reference source:
* https://github.com/zephyrproject-rtos/zephyr/blob/main/drivers/modem/modem_cmd_handler.h
*/
/*
* Copyright (c) 2019 Foundries.io
*
* SPDX-License-Identifier: Apache-2.0
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef MODEM_MODEM_CMD_HANDLER_H
#define MODEM_MODEM_CMD_HANDLER_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include "FreeRTOS.h"
#include "semphr.h"
/** @defgroup ST67W61_AT_Modem_Cmd_Handler ST67W61 AT Modem Command Handler
* @ingroup ST67W61_AT
*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup ST67W61_AT_Modem_Cmd_Handler_Constants ST67W61 AT Modem Command Handler Constants
* @ingroup ST67W61_AT_Modem_Cmd_Handler
* @{
*/
#ifndef CONFIG_MODEM_CMD_HANDLER_MAX_PARAM_COUNT
/** Maximum number of parameters for modem commands */
#define CONFIG_MODEM_CMD_HANDLER_MAX_PARAM_COUNT 11
#endif /* CONFIG_MODEM_CMD_HANDLER_MAX_PARAM_COUNT */
/** Size of the receive buffer */
#define RX_BUF_SIZE W61_MAX_SPI_XFER
#define EIO 5 /*!< I/O error */
#define EAGAIN 11 /*!< No more contexts */
#define ENOMEM 12 /*!< Not enough core */
#define EBUSY 16 /*!< Mount device busy */
#define EINVAL 22 /*!< Invalid argument */
#ifndef ETIMEDOUT
#define ETIMEDOUT 116 /*!< Connection timed out */
#endif /* ETIMEDOUT */
#define CMD_RESP 0 /*!< Command response */
#define CMD_UNSOL 1 /*!< Unsolicited command */
#define CMD_HANDLER 2 /*!< Command handler */
#define CMD_MAX 3 /*!< Maximum command types */
/* Flags for modem_send_cmd_ext */
#define MODEM_NO_TX_LOCK (1UL << 0U) /*!< No TX lock flag send */
#define MODEM_NO_SET_CMDS (1UL << 1U) /*!< No set commands flag send */
#define MODEM_NO_UNSET_CMDS (1UL << 2U) /*!< No unset commands flag send */
/** @} */
/* Exported types ------------------------------------------------------------*/
/** @defgroup ST67W61_AT_Modem_Cmd_Handler_Types ST67W61 AT Modem Command Handler Types
* @ingroup ST67W61_AT_Modem_Cmd_Handler
* @{
*/
/**
* @brief Modem interface structure
*/
struct modem_iface
{
/** Callback to read data from the modem interface */
int32_t (*mdm_read)(struct modem_iface *iface, uint8_t *buf, size_t size, size_t *bytes_read);
/** Callback to write data to the modem interface */
int32_t (*mdm_write)(struct modem_iface *iface, const uint8_t *buf, size_t size);
};
/**
* @brief Modem command handler structure
*/
struct modem_cmd_handler
{
/** Callback to process commands */
void (*process)(struct modem_cmd_handler *cmd_handler, struct modem_iface *iface);
/** Data based on modem_cmd_handler_data */
void *cmd_handler_data;
};
/**
* @brief Modem context structure
*/
struct modem_context
{
/** Interface configuration */
struct modem_iface iface;
/** Command handler configuration */
struct modem_cmd_handler cmd_handler;
};
/**
* @brief Modem command handler data
*/
struct modem_cmd_handler_data;
/**
* @brief Modem command structure
*/
struct modem_cmd
{
/** Callback to process commands */
int32_t (*func)(struct modem_cmd_handler_data *data, uint16_t len, uint8_t **argv, uint16_t argc);
/** Command string to match */
const char *cmd;
/** Command delimiter */
const char *delim;
/** Command length */
uint16_t cmd_len;
/** Minimum argument count */
uint16_t arg_count_min;
/** Maximum argument count */
uint16_t arg_count_max;
/** Command direct match flag */
bool direct;
};
/**
* @brief Series of modem setup commands to run
*/
struct setup_cmd
{
/** Command to send */
const char *send_cmd;
/** Handle command */
struct modem_cmd handle_cmd;
};
/**
* @brief Modem command handler data
*/
struct modem_cmd_handler_data
{
/** Command list */
const struct modem_cmd *cmds[CMD_MAX];
/** Command list lengths */
size_t cmds_len[CMD_MAX];
/** Buffer for matching commands */
char *match_buf;
/** Length of buffer for matching commands */
size_t match_buf_len;
/** Last error code */
int32_t last_error;
/** End of line string */
const char *eol;
/** Length of end of line string */
size_t eol_len;
/** RX net buffer */
uint8_t *rx_buf;
/** Length of RX net buffer */
size_t rx_buf_len;
/** TX lock */
SemaphoreHandle_t sem_tx_lock;
/** Parse lock */
SemaphoreHandle_t sem_parse_lock;
/** User data */
void *user_data;
};
/**
* @brief Modem command handler configuration
* @details Contains user configuration which is used to set up
* command handler data context. The struct is initialized and then passed
* to modem_cmd_handler_init().
*/
struct modem_cmd_handler_config
{
/** Buffer used for matching commands */
char *match_buf;
/** Length of buffer used for matching commands */
size_t match_buf_len;
/** End of line represented as string */
const char *eol;
/** Length of end of line string */
size_t eol_len;
/** Free to use data which can be retrieved from within command handlers */
void *user_data;
/** Array of response command handlers */
const struct modem_cmd *response_cmds;
/** Length of response command handlers array */
size_t response_cmds_len;
/** Array of unsolicited command handlers */
const struct modem_cmd *unsol_cmds;
/** Length of unsolicited command handlers array */
size_t unsol_cmds_len;
};
/** @} */
/* Exported macros -----------------------------------------------------------*/
/** @defgroup ST67W61_AT_Modem_Cmd_Handler_Macros ST67W61 AT Modem Command Handler Macros
* @ingroup ST67W61_AT_Modem_Cmd_Handler
* @{
*/
#ifndef ARRAY_SIZE
/** Get the number of elements in an array */
#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
#endif /* ARRAY_SIZE */
/** Macro to declare a modem command handler function */
#define MODEM_CMD_DECLARE(name_) \
static int32_t name_(struct modem_cmd_handler_data *data, uint16_t len, \
uint8_t **argv, uint16_t argc)
/** Macro to declare a direct modem command handler function */
#define MODEM_CMD_DIRECT_DECLARE(name_) MODEM_CMD_DECLARE(name_)
/** Macro to define a modem command handler function */
#define MODEM_CMD_DEFINE(name_) \
static int32_t name_(struct modem_cmd_handler_data *data, uint16_t len, \
uint8_t **argv, uint16_t argc)
/** Macro to define a direct modem command handler function */
#define MODEM_CMD_DIRECT_DEFINE(name_) MODEM_CMD_DEFINE(name_)
/** Macro to call a direct modem command handler function */
#define MODEM_CMD_DIRECT(cmd_, func_cb_) { \
.cmd = cmd_, \
.cmd_len = (uint16_t)sizeof(cmd_)-1, \
.func = func_cb_, \
.arg_count_min = 0, \
.arg_count_max = 0, \
.delim = "", \
.direct = true, \
}
/** Macro to call a modem command handler function with fixed arguments number */
#define MODEM_CMD(cmd_, func_cb_, acount_, adelim_) { \
.cmd = cmd_, \
.cmd_len = (uint16_t)sizeof(cmd_)-1, \
.func = func_cb_, \
.arg_count_min = acount_, \
.arg_count_max = acount_, \
.delim = adelim_, \
.direct = false, \
}
/** Macro to call a modem command handler function with variable arguments range */
#define MODEM_CMD_ARGS_MAX(cmd_, func_cb_, acount_, acountmax_, adelim_) { \
.cmd = cmd_, \
.cmd_len = (uint16_t)sizeof(cmd_)-1, \
.func = func_cb_, \
.arg_count_min = acount_, \
.arg_count_max = acountmax_, \
.delim = adelim_, \
.direct = false, \
}
/** @} */
/* Exported functions ------------------------------------------------------- */
/** @defgroup ST67W61_AT_Modem_Cmd_Handler_Functions ST67W61 AT Modem Command Handler Functions
* @ingroup ST67W61_AT_Modem_Cmd_Handler
* @{
*/
/**
* @brief get the last error code
* @param data: command handler data reference
* @return last handled error
*/
int32_t modem_cmd_handler_get_error(struct modem_cmd_handler_data *data);
/**
* @brief set the last error code
* @param data: command handler data reference
* @param error_code: error
* @return 0 if ok, < 0 if error
*/
int32_t modem_cmd_handler_set_error(struct modem_cmd_handler_data *data, int32_t error_code);
/**
* @brief update the parser's handler commands
* @param data: handler data to use
* @param handler_cmds: commands to attach
* @param handler_cmds_len: size of commands array
* @param reset_error_flag: reset last error code
* @return 0 if ok, < 0 if error
*/
int32_t modem_cmd_handler_update_cmds(struct modem_cmd_handler_data *data,
const struct modem_cmd *handler_cmds,
size_t handler_cmds_len,
bool reset_error_flag);
/**
* @brief Wait until semaphore is given
* @details This function does the same wait behavior as @ref modem_cmd_send_ext, but can wait without sending
* any command first. Useful for waiting for asynchronous responses.
* @param data: handler data to use
* @param sem: wait for semaphore
* @param timeout: wait timeout
* @return 0 if ok, < 0 if error
*/
int32_t modem_cmd_handler_await(struct modem_cmd_handler_data *data,
SemaphoreHandle_t sem, TickType_t timeout);
/**
* @brief send data directly to interface w/o TX lock
* @details This function just writes directly to the modem interface.
* Recommended to use to get verbose logging for all data sent to the interface.
* @param iface: interface to use
* @param buf: send buffer (not NULL terminated)
* @param len: length of send buffer
* @return 0 if ok, < 0 if error
*/
int32_t modem_cmd_send_data_nolock(struct modem_iface *iface,
const uint8_t *buf, size_t len);
/**
* @brief send AT command to interface with behavior defined by flags
* @details This function is similar to @ref modem_cmd_send_ext, but it allows to choose a
* specific behavior regarding acquiring tx_lock, setting and unsetting
* @a handler_cmds.
* @param iface: interface to use
* @param handler: command handler to use
* @param handler_cmds: commands to attach
* @param handler_cmds_len: size of commands array
* @param buf: NULL terminated send buffer
* @param sem: wait for response semaphore
* @param timeout: timeout of command
* @param flags: flags which influence behavior of command sending
* @return 0 if ok, < 0 if error
*/
int32_t modem_cmd_send_ext(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct modem_cmd *handler_cmds,
size_t handler_cmds_len, const uint8_t *buf,
SemaphoreHandle_t sem, TickType_t timeout, uint32_t flags);
/**
* @brief send AT command to interface w/o locking TX
* @param iface: interface to use
* @param handler: command handler to use
* @param handler_cmds: commands to attach
* @param handler_cmds_len: size of commands array
* @param buf: NULL terminated send buffer
* @param sem: wait for response semaphore
* @param timeout: timeout of command
* @return 0 if ok, < 0 if error
*/
static inline int32_t modem_cmd_send_nolock(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct modem_cmd *handler_cmds,
size_t handler_cmds_len,
const uint8_t *buf, SemaphoreHandle_t sem,
TickType_t timeout)
{
return modem_cmd_send_ext(iface, handler, handler_cmds,
handler_cmds_len, buf, sem, timeout,
MODEM_NO_TX_LOCK);
}
/**
* @brief send AT command to interface w/ a TX lock
* @param iface: interface to use
* @param handler: command handler to use
* @param handler_cmds: commands to attach
* @param handler_cmds_len: size of commands array
* @param buf: NULL terminated send buffer
* @param sem: wait for response semaphore
* @param timeout: timeout of command
* @return 0 if ok, < 0 if error
*/
static inline int32_t modem_cmd_send(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct modem_cmd *handler_cmds,
size_t handler_cmds_len, const uint8_t *buf,
SemaphoreHandle_t sem, TickType_t timeout)
{
return modem_cmd_send_ext(iface, handler, handler_cmds,
handler_cmds_len, buf, sem, timeout, 0);
}
/**
* @brief send a series of AT commands w/ a TX lock
* @param iface: interface to use
* @param handler: command handler to use
* @param cmds: array of setup commands to send
* @param cmds_len: size of the setup command array
* @param sem: wait for response semaphore
* @param timeout: timeout of command
* @return 0 if ok, < 0 if error
*/
int32_t modem_cmd_handler_setup_cmds(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct setup_cmd *cmds, size_t cmds_len,
SemaphoreHandle_t sem, TickType_t timeout);
/**
* @brief send a series of AT commands w/o locking TX
* @param iface: interface to use
* @param handler: command handler to use
* @param cmds: array of setup commands to send
* @param cmds_len: size of the setup command array
* @param sem: wait for response semaphore
* @param timeout: timeout of command
* @return 0 if ok, < 0 if error
*/
int32_t modem_cmd_handler_setup_cmds_nolock(struct modem_iface *iface,
struct modem_cmd_handler *handler,
const struct setup_cmd *cmds,
size_t cmds_len, SemaphoreHandle_t sem,
TickType_t timeout);
/**
* @brief Initialize modem command handler
* @details This function is called once for each command handler, before any
* incoming data is processed.
* @note All arguments passed to this function, including the referenced data
* contained in the setup struct, must persist as long as the command handler itself.
* @param handler: Command handler to initialize
* @param data: Command handler data to use
* @param config: Command handler configuration
* @return -EINVAL if any argument is invalid
* @return 0 if successful
*/
int32_t modem_cmd_handler_init(struct modem_cmd_handler *handler,
struct modem_cmd_handler_data *data,
const struct modem_cmd_handler_config *config);
/**
* @brief Lock the modem for sending cmds
* @details This is semaphore-based rather than mutex based, which means there's no
* requirements of thread ownership for the user. This function is useful
* when one needs to prevent threads from sending UART data to the modem for an
* extended period of time (for example during modem reset).
* @param handler: command handler to lock
* @param timeout: give up after timeout
* @return 0 if ok, < 0 if error
*/
int32_t modem_cmd_handler_tx_lock(struct modem_cmd_handler *handler,
TickType_t timeout);
/**
* @brief Unlock the modem for sending cmds
* @param handler: command handler to unlock
*/
void modem_cmd_handler_tx_unlock(struct modem_cmd_handler *handler);
/**
* @brief Process incoming data
* @details This function will process any data available from the interface
* using the command handler. The command handler will invoke any matching modem
* command which has been registered using @ref modem_cmd_handler_update_cmds.
* Once handled, the function will return.
* @note This function should be invoked from a dedicated thread, which only handles
* commands.
* @param handler: The handler which will handle the command when processed
* @param iface: The interface which receives incoming data
*/
static inline void modem_cmd_handler_process(struct modem_cmd_handler *handler,
struct modem_iface *iface)
{
handler->process(handler, iface);
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* MODEM_MODEM_CMD_HANDLER_H */
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,945 @@
/**
******************************************************************************
* @file w61_at_common.c
* @author ST67 Application Team
* @brief This file provides the common implementations of the AT driver
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "w61_at_common.h"
#include "w61_at_internal.h"
#include "w61_io.h"
#include <stdlib.h>
#include "modem_cmd_handler.h"
#include "stdio.h"
#if (defined(SYS_DBG_ENABLE_TA4) && (SYS_DBG_ENABLE_TA4 >= 1))
#include "trcRecorder.h"
#endif /* SYS_DBG_ENABLE_TA4 */
/* Global variables ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/** @defgroup ST67W61_AT_Common_Defines ST67W61 AT Driver Common Defines
* @ingroup ST67W61_AT_Common
* @{
*/
/** Timeout for io send operation */
#define IO_SEND_TIMEOUT 2000U
/** Timeout for io receive operation */
#define IO_RECEIVE_TIMEOUT portMAX_DELAY
#ifndef IO_AT_CMDQ_DEPTH
/** IO queue depth for AT CMD */
#define IO_AT_CMDQ_DEPTH 16
#endif /* IO_AT_CMDQ_DEPTH */
/** @} */
/* Private macros ------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @addtogroup ST67W61_AT_Common_Functions
* @{
*/
/**
* @brief Initialize the IO interface
* @param iface: pointer to the modem interface
* @return 0 on success, negative value on error
*/
static int32_t io_init(struct modem_iface *iface);
/**
* @brief Deinitialize the IO interface
* @param iface: pointer to the modem interface
* @return 0 on success, negative value on error
*/
static int32_t io_deinit(struct modem_iface *iface);
/**
* @brief Modem process task
* @param arg: pointer to the task argument
*/
static void W61_Modem_Process_task(void *arg);
/**
* @brief Write data to the modem interface
* @param iface: pointer to the modem interface
* @param buf: pointer to the data buffer
* @param size: size of the data to write
* @return 0 on success, negative value on error
*/
static int32_t modem_iface_spi_write(struct modem_iface *iface,
const uint8_t *buf, size_t size);
/**
* @brief Read data from the modem interface
* @param iface: pointer to the modem interface
* @param buf: pointer to the buffer to store read data
* @param size: size of the buffer
* @param bytes_read: pointer to store the number of bytes read
* @return 0 on success, negative value on error
*/
static int32_t modem_iface_spi_read(struct modem_iface *iface,
uint8_t *buf, size_t size, size_t *bytes_read);
/**
* @brief Callback function to handle query events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings
* @param argc: number of argument
* @return 0 on success, negative value on error
*/
MODEM_CMD_DECLARE(on_cmd_query);
/**
* @brief Callback function to handle "OK" events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings (unused)
* @param argc: number of arguments (unused)
* @return 0 on success, negative value on error
*/
MODEM_CMD_DECLARE(on_cmd_ok);
/**
* @brief Callback function to handle "ERROR" events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings (unused)
* @param argc: number of arguments (unused)
* @return 0 on success, negative value on error
*/
MODEM_CMD_DECLARE(on_cmd_error);
/**
* @brief Callback function to handle "ready" events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings (unused)
* @param argc: number of arguments (unused)
* @return 0 on success, negative value on error
*/
MODEM_CMD_DECLARE(on_cmd_ready);
/**
* @brief Callback function to handle "+CW" events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings
* @param argc: number of arguments
* @return process length on success, negative value on error
*/
MODEM_CMD_DECLARE(on_cmd_wifi_event);
/**
* @brief Callback function to handle "+BLE" events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings
* @param argc: number of arguments
* @return process length on success, negative value on error
*/
MODEM_CMD_DECLARE(on_cmd_ble_event);
/**
* @brief Callback function to handle "+CIP" events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings (unused)
* @param argc: number of arguments (unused)
* @return process length on success, negative value on error
*/
MODEM_CMD_DECLARE(on_cmd_net_event);
/**
* @brief Callback function to handle "+MQTT" events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings
* @param argc: number of arguments
* @return process length on success, negative value on error
*/
MODEM_CMD_DECLARE(on_cmd_mqtt_event);
/**
* @brief Callback function to handle ">" events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings (unused)
* @param argc: number of arguments (unused)
* @return 0 on success, negative value on error
*/
MODEM_CMD_DIRECT_DECLARE(on_cmd_tx_ready);
/**
* @brief Callback function to handle "RECV " events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings (unused)
* @param argc: number of arguments (unused)
* @return 0 on success, negative value on error
*/
MODEM_CMD_DECLARE(on_cmd_recv);
/**
* @brief Callback function to handle MQTT data events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings (unused)
* @param argc: number of arguments (unused)
* @return process length on success, negative value on error
*/
MODEM_CMD_DIRECT_DECLARE(on_cmd_mqtt_data_event);
/**
* @brief Callback function to handle Net data events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings
* @param argc: number of arguments
* @return process length on success, negative value on error
*/
MODEM_CMD_DECLARE(on_cmd_net_data_event);
/**
* @brief Callback function to handle BLE Write data events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings (unused)
* @param argc: number of arguments (unused)
* @return process length on success, negative value on error
*/
MODEM_CMD_DIRECT_DECLARE(on_cmd_ble_write_data_event);
/**
* @brief Callback function to handle BLE Read data events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings (unused)
* @param argc: number of arguments (unused)
* @return process length on success, negative value on error
*/
MODEM_CMD_DIRECT_DECLARE(on_cmd_ble_read_data_event);
/**
* @brief Callback function to handle BLE Notification data events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings (unused)
* @param argc: number of arguments (unused)
* @return process length on success, negative value on error
*/
MODEM_CMD_DIRECT_DECLARE(on_cmd_ble_noti_data_event);
/**
* @brief Callback function to handle ping events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings (unused)
* @param argc: number of arguments (unused)
* @return process length on success, negative value on error
*/
MODEM_CMD_DECLARE(on_cmd_net_ping_event);
/**
* @brief Callback function to handle Wi-Fi scan events
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings (unused)
* @param argc: number of arguments (unused)
* @return process length on success, negative value on error
*/
MODEM_CMD_DECLARE(on_cmd_wifi_scan_event);
/** @} */
/* Private variables ---------------------------------------------------------*/
/** @defgroup ST67W61_AT_Common_Variables ST67W61 AT Driver Common Variables
* @ingroup ST67W61_AT_Common
* @{
*/
/** List of response commands for the modem */
static const struct modem_cmd response_cmds_list[] =
{
MODEM_CMD("OK", on_cmd_ok, 0U, ""),
MODEM_CMD("ERROR", on_cmd_error, 0U, ""),
};
/** List of unsolicited commands for the modem */
static const struct modem_cmd unsol_cmds_list[] =
{
MODEM_CMD("ready", on_cmd_ready, 0U, ""),
MODEM_CMD("+CWLAP:", on_cmd_wifi_scan_event, 8U, ","),
MODEM_CMD_DIRECT("+BLE:GATTWRITE:", on_cmd_ble_write_data_event),
MODEM_CMD_DIRECT("+BLE:GATTREAD:", on_cmd_ble_read_data_event),
MODEM_CMD_DIRECT("+BLE:NOTIDATA:", on_cmd_ble_noti_data_event),
MODEM_CMD_DIRECT("+MQTT:SUBRECV:", on_cmd_mqtt_data_event),
MODEM_CMD_ARGS_MAX("+IPD:", on_cmd_net_data_event, 1U, 10U, ","),
MODEM_CMD_ARGS_MAX("+CW:", on_cmd_wifi_event, 1U, 10U, ", "),
MODEM_CMD_ARGS_MAX("+BLE:", on_cmd_ble_event, 1U, 11U, ",:()"),
MODEM_CMD_ARGS_MAX("+CIP:", on_cmd_net_event, 1U, 10U, ","),
MODEM_CMD_ARGS_MAX("+MQTT:", on_cmd_mqtt_event, 1U, 10U, ","),
MODEM_CMD("+PING:", on_cmd_net_ping_event, 1U, ""),
};
/** @} */
/* Functions Definition ------------------------------------------------------*/
/** @addtogroup ST67W61_AT_Common_Functions
* @{
*/
int32_t W61_AT_ModemInit(W61_Object_t *Obj)
{
BaseType_t xReturned;
int32_t ret = -1;
struct modem *mdm = (struct modem *) &Obj->Modem;
/* Cmd handler */
const struct modem_cmd_handler_config cmd_handler_config =
{
.match_buf = (char *) &mdm->cmd_match_buf[0],
.match_buf_len = sizeof(mdm->cmd_match_buf),
.eol = "", /* CRLF sent within the command string to avoid 2 successive write */
.user_data = mdm,
.response_cmds = response_cmds_list,
.response_cmds_len = ARRAY_SIZE(response_cmds_list),
.unsol_cmds = unsol_cmds_list,
.unsol_cmds_len = ARRAY_SIZE(unsol_cmds_list),
};
mdm->sem_response = xSemaphoreCreateBinary();
if (mdm->sem_response == NULL)
{
goto __err;
}
mdm->sem_if_ready = xSemaphoreCreateBinary();
if (mdm->sem_if_ready == NULL)
{
goto __err;
}
mdm->sem_tx_ready = xSemaphoreCreateBinary();
if (mdm->sem_tx_ready == NULL)
{
goto __err;
}
/* Assign rx_buff */
/** Linear RX buffer to process */
mdm->handler_data.rx_buf = pvPortMalloc(RX_BUF_SIZE);
if (mdm->handler_data.rx_buf == NULL)
{
goto __err;
}
ret = modem_cmd_handler_init(&mdm->handler, &mdm->handler_data,
&cmd_handler_config);
if (ret < 0)
{
goto __err;
}
ret = io_init(&mdm->iface);
if (ret < 0)
{
goto __err;
}
xReturned = xTaskCreate(W61_Modem_Process_task,
(char *)"Modem_Process",
W61_MDM_RX_TASK_STACK_SIZE_BYTES >> 2U,
mdm,
W61_MDM_RX_TASK_PRIO,
&mdm->modem_task_handle);
if (xReturned != pdPASS)
{
SYS_LOG_ERROR("xTaskCreate failed to create\n");
ret = -1;
goto __err;
}
/* Wait for the module to be ready */
if (W61_WaitForReady(Obj, W61_READY_DEFAULT_TIMEOUT_MS) != W61_STATUS_OK)
{
SYS_LOG_ERROR("sem_if_ready not received\n");
ret = -1;
goto __err;
}
(void)W61_AT_Common_SetExecute(Obj, (uint8_t *)"AT\r\n", W61_NCP_TIMEOUT);
return ret;
__err:
if (mdm->handler_data.rx_buf != NULL)
{
vPortFree(mdm->handler_data.rx_buf);
mdm->handler_data.rx_buf = NULL;
}
if (mdm->sem_response != NULL)
{
vSemaphoreDelete(mdm->sem_response);
mdm->sem_response = NULL;
}
if (mdm->sem_if_ready != NULL)
{
vSemaphoreDelete(mdm->sem_if_ready);
mdm->sem_if_ready = NULL;
}
if (mdm->sem_tx_ready != NULL)
{
vSemaphoreDelete(mdm->sem_tx_ready);
mdm->sem_tx_ready = NULL;
}
if (mdm->modem_task_handle != NULL)
{
vTaskDelete(mdm->modem_task_handle);
mdm->modem_task_handle = NULL;
}
return ret;
}
void W61_AT_ModemDeInit(W61_Object_t *Obj)
{
struct modem *mdm = (struct modem *) &Obj->Modem;
(void)io_deinit(&mdm->iface);
if (mdm->handler_data.rx_buf != NULL)
{
vPortFree(mdm->handler_data.rx_buf);
mdm->handler_data.rx_buf = NULL;
}
if (mdm->sem_response != NULL)
{
vSemaphoreDelete(mdm->sem_response);
mdm->sem_response = NULL;
}
if (mdm->sem_if_ready != NULL)
{
vSemaphoreDelete(mdm->sem_if_ready);
mdm->sem_if_ready = NULL;
}
if (mdm->sem_tx_ready != NULL)
{
vSemaphoreDelete(mdm->sem_tx_ready);
mdm->sem_tx_ready = NULL;
}
if (mdm->modem_task_handle != NULL)
{
vTaskDelete(mdm->modem_task_handle);
mdm->modem_task_handle = NULL;
}
}
W61_Status_t W61_Status(int32_t ret)
{
W61_Status_t status;
switch (ret)
{
case 0:
status = W61_STATUS_OK;
break;
case -ETIMEDOUT:
status = W61_STATUS_TIMEOUT;
break;
case -EIO:
status = W61_STATUS_IO_ERROR;
break;
default:
status = W61_STATUS_ERROR;
break;
}
return status;
}
W61_Status_t W61_AT_Common_SetExecute(W61_Object_t *Obj, uint8_t *p_cmd, uint32_t timeout_ms)
{
struct modem *mdm = &Obj->Modem;
return W61_Status(modem_cmd_send(&mdm->iface,
&mdm->handler,
NULL,
0,
p_cmd,
mdm->sem_response,
timeout_ms));
}
W61_Status_t W61_AT_Common_Query_Parse(W61_Object_t *Obj, char *p_cmd, char *p_resp,
uint16_t *argc, char **argv, uint32_t timeout_ms)
{
struct modem *mdm = (struct modem *) &Obj->Modem;
struct modem_cmd_handler_data *data = (struct modem_cmd_handler_data *)mdm->handler.cmd_handler_data;
W61_Status_t ret;
if (data == NULL)
{
return W61_STATUS_ERROR;
}
(void)xSemaphoreTake(data->sem_tx_lock, portMAX_DELAY);
/* **argv reference p_cmd to ensure re-entrance */
mdm->rx_data = p_cmd;
mdm->argc = argc;
mdm->argv = argv;
struct modem_cmd handlers[] = {{
.cmd = p_resp,
.cmd_len = (uint16_t)strlen(p_resp),
.func = on_cmd_query,
.arg_count_min = 1,
.arg_count_max = CONFIG_MODEM_CMD_HANDLER_MAX_PARAM_COUNT,
.delim = ",:",
.direct = false,
}
};
ret = W61_Status(modem_cmd_send_ext(&mdm->iface,
&mdm->handler,
handlers,
ARRAY_SIZE(handlers),
(const uint8_t *)p_cmd,
mdm->sem_response,
timeout_ms,
MODEM_NO_TX_LOCK));
(void)xSemaphoreGive(data->sem_tx_lock);
return ret;
}
W61_Status_t W61_AT_Common_RequestSendData(W61_Object_t *Obj, uint8_t *p_cmd, uint8_t *pdata, uint32_t len,
uint32_t timeout_ms, bool check_resp)
{
struct modem *mdm = (struct modem *) &Obj->Modem;
int32_t ret;
int32_t bytes_consumed_by_the_bus = 0;
int32_t bytes_to_send;
static const struct modem_cmd cmds[] =
{
MODEM_CMD_DIRECT(">", on_cmd_tx_ready),
MODEM_CMD("Recv ", on_cmd_recv, 1U, " "),
};
(void)xSemaphoreTake(mdm->handler_data.sem_tx_lock, portMAX_DELAY);
/*reset mdm->sem_tx_read */
(void)xSemaphoreTake(mdm->sem_tx_ready, 0);
ret = modem_cmd_send_ext(&mdm->iface, &mdm->handler,
cmds, ARRAY_SIZE(cmds), p_cmd, mdm->sem_response,
check_resp ? pdMS_TO_TICKS(timeout_ms) : 0U, /* If check_resp is false don't wait for OK */
MODEM_NO_TX_LOCK | MODEM_NO_UNSET_CMDS);
if (ret < 0)
{
SYS_LOG_DEBUG("Failed to send command\n");
goto out;
}
/* Reset semaphore that will be released by "Recv " */
/*reset mdm->sem_response */
(void)xSemaphoreTake(mdm->sem_response, 0);
/* Set rx_data_len to be checked during "Recv " event */
mdm->rx_data_len = len;
/* Wait for '>' */
if (xSemaphoreTake(mdm->sem_tx_ready, pdMS_TO_TICKS(5000)) != pdPASS)
{
SYS_LOG_DEBUG("Timeout waiting for tx\n");
ret = -ETIMEDOUT;
goto out;
}
while (bytes_consumed_by_the_bus < len)
{
bytes_to_send = len - bytes_consumed_by_the_bus;
bytes_consumed_by_the_bus += modem_cmd_send_data_nolock(&mdm->iface,
&pdata[bytes_consumed_by_the_bus],
bytes_to_send);
}
/* Wait for "Recv " */
if (xSemaphoreTake(mdm->sem_response, pdMS_TO_TICKS(timeout_ms)) != pdPASS)
{
SYS_LOG_DEBUG("No send response\n");
ret = -ETIMEDOUT;
goto out;
}
ret = modem_cmd_handler_get_error(&mdm->handler_data);
if (ret != 0)
{
SYS_LOG_DEBUG("Failed to send data\n");
}
out:
(void)modem_cmd_handler_update_cmds(&mdm->handler_data,
NULL, 0U, false);
(void)xSemaphoreGive(mdm->handler_data.sem_tx_lock);
return W61_Status(ret);
}
void W61_AT_RemoveStrQuotes(char *inbuf)
{
int32_t len = strlen(inbuf);
if (len < 2U)
{
return; /* Nothing to do */
}
inbuf[len - 1U] = '\0'; /* Ensure the last character is null-terminated */
/* Ensure the first character is not a double quote */
(void)memmove(inbuf, inbuf + 1, len);
}
void W61_AT_Logger(uint8_t *pBuf, uint32_t len, char *inOut)
{
char log_message[W61_MAX_AT_LOG_LENGTH];
uint32_t message_len = W61_MAX_AT_LOG_LENGTH - 1U;
if (len < (W61_MAX_AT_LOG_LENGTH - 1U))
{
message_len = len;
}
(void)memcpy(log_message, pBuf, message_len);
log_message[message_len] = '\0';
if (message_len == (W61_MAX_AT_LOG_LENGTH - 1U))
{
log_message[message_len - 1U] = '.';
log_message[message_len - 2U] = '.';
log_message[message_len - 3U] = '.';
}
SYS_LOG_DEBUG("AT%s %s\n", inOut, log_message);
}
#if defined(__ICCARM__) || defined(__ICCRX__) || defined(__ARMCC_VERSION) /* For IAR/MDK Compiler */
char *strnstr(const char *big, const char *little, size_t len)
{
size_t i;
size_t j;
if (little[0] == '\0')
{
return ((char *)big);
}
j = 0;
while ((j < len) && (big[j] != '\0'))
{
i = 0;
while ((j < len) && (little[i] != '\0') && (big[j] != '\0') && (little[i] == big[j]))
{
++i;
++j;
}
if (little[i] == '\0')
{
return ((char *)&big[j - i]);
}
j = j - i + 1U;
}
return NULL;
}
#endif /* __ICCARM__ || __ARMCC_VERSION */
/* Private Functions Definition ----------------------------------------------*/
static int32_t io_init(struct modem_iface *iface)
{
if (iface == NULL)
{
return -EINVAL;
}
if (BusIo_SPI_Init() != 0)
{
return -1;
}
if (BusIo_SPI_Bind(SPI_MSG_CTRL_TRAFFIC_AT_CMD, (int32_t)IO_AT_CMDQ_DEPTH, NULL) != 0)
{
return -1;
}
iface->mdm_read = modem_iface_spi_read;
iface->mdm_write = modem_iface_spi_write;
return 0;
}
static int32_t io_deinit(struct modem_iface *iface)
{
if (iface == NULL)
{
return -EINVAL;
}
if (BusIo_SPI_DeInit() != 0)
{
return -1;
}
iface->mdm_read = NULL;
iface->mdm_write = NULL;
return 0;
}
static void W61_Modem_Process_task(void *arg)
{
struct modem *mdm = (struct modem *) arg;
while (true)
{
modem_cmd_handler_process(&mdm->handler,
&mdm->iface);
}
}
static int32_t modem_iface_spi_write(struct modem_iface *iface,
const uint8_t *buf, size_t size)
{
if (size == 0U)
{
return 0;
}
AT_LOG_HOST_OUT((uint8_t *)buf, size);
return BusIo_SPI_SendData(SPI_MSG_CTRL_TRAFFIC_AT_CMD, (uint8_t *)buf, size, IO_SEND_TIMEOUT);
}
static int32_t modem_iface_spi_read(struct modem_iface *iface,
uint8_t *buf, size_t size, size_t *bytes_read)
{
int32_t received = BusIo_SPI_ReceiveData(SPI_MSG_CTRL_TRAFFIC_AT_CMD, buf, size, portMAX_DELAY);
AT_LOG_HOST_IN(buf, received);
if (received < 0)
{
*bytes_read = 0;
return received;
}
*bytes_read = received;
return 0;
}
MODEM_CMD_DEFINE(on_cmd_query)
{
struct modem *mdm = (struct modem *) data->user_data;
int32_t offset = ((uint8_t *) mdm->rx_data) - mdm->cmd_match_buf;
/*len of the current mdm->cmd_match_buf + '\0'*/
int32_t mlen = (argv[argc - 1] - mdm->cmd_match_buf) + strlen((char *) argv[argc - 1]) + 1;
(void)memcpy(mdm->rx_data, (char *) mdm->cmd_match_buf, mlen);
/* Record and offset argv to mdm->rx_data */
for (int32_t i = 0; i < argc; i++)
{
mdm->argv[i] = (char *)(argv[i] + offset);
}
*mdm->argc = argc;
return 0;
}
MODEM_CMD_DIRECT_DEFINE(on_cmd_tx_ready)
{
struct modem *mdm = (struct modem *) data->user_data;
(void)xSemaphoreGive(mdm->sem_tx_ready);
return len;
}
MODEM_CMD_DEFINE(on_cmd_recv)
{
struct modem *mdm = (struct modem *) data->user_data;
int32_t recv_len = 0;
if (argc > 0U)
{
recv_len = atoi((char *) argv[0]);
/*check if length received by modem is matching the sent value */
if (recv_len != mdm->rx_data_len)
{
(void)modem_cmd_handler_set_error(data, -EIO);
}
else
{
(void)modem_cmd_handler_set_error(data, 0);
}
}
else
{
(void)modem_cmd_handler_set_error(data, -EIO);
}
(void)xSemaphoreGive(mdm->sem_response);
return 0;
}
/* Handler: OK */
MODEM_CMD_DEFINE(on_cmd_ok)
{
struct modem *mdm = (struct modem *) data->user_data;
(void)modem_cmd_handler_set_error(data, 0);
(void)xSemaphoreGive(mdm->sem_response);
return 0;
}
/* Handler: ERROR */
MODEM_CMD_DEFINE(on_cmd_error)
{
struct modem *mdm = (struct modem *) data->user_data;
(void)modem_cmd_handler_set_error(data, -EIO);
(void)xSemaphoreGive(mdm->sem_response);
return 0;
}
MODEM_CMD_DEFINE(on_cmd_ready)
{
struct modem *mdm = (struct modem *) data->user_data;
(void)xSemaphoreGive(mdm->sem_if_ready);
return 0;
}
MODEM_CMD_DEFINE(on_cmd_wifi_event)
{
struct modem *mdm = (struct modem *) data->user_data;
W61_Object_t *Obj = CONTAINER_OF(mdm, W61_Object_t, Modem);
if (Obj->Callbacks.WiFi_event_cb != NULL)
{
Obj->Callbacks.WiFi_event_cb(Obj, &argc, (char **)argv);
}
return 0;
}
MODEM_CMD_DEFINE(on_cmd_wifi_scan_event)
{
struct modem *mdm = (struct modem *) data->user_data;
W61_Object_t *Obj = CONTAINER_OF(mdm, W61_Object_t, Modem);
if (Obj->Callbacks.WiFi_event_scan_cb != NULL)
{
Obj->Callbacks.WiFi_event_scan_cb(Obj, &argc, (char **)argv);
}
return 0;
}
MODEM_CMD_DEFINE(on_cmd_ble_event)
{
struct modem *mdm = (struct modem *) data->user_data;
W61_Object_t *Obj = CONTAINER_OF(mdm, W61_Object_t, Modem);
if (Obj->Callbacks.Ble_event_cb != NULL)
{
Obj->Callbacks.Ble_event_cb(Obj, &argc, (char **)argv);
}
return 0;
}
MODEM_CMD_DIRECT_DEFINE(on_cmd_ble_write_data_event)
{
struct modem *mdm = (struct modem *) data->user_data;
W61_Object_t *Obj = CONTAINER_OF(mdm, W61_Object_t, Modem);
if (Obj->Callbacks.Ble_event_data_cb != NULL)
{
return Obj->Callbacks.Ble_event_data_cb(W61_BLE_EVT_WRITE_ID, data, len);
}
return 0;
}
MODEM_CMD_DIRECT_DEFINE(on_cmd_ble_read_data_event)
{
struct modem *mdm = (struct modem *) data->user_data;
W61_Object_t *Obj = CONTAINER_OF(mdm, W61_Object_t, Modem);
if (Obj->Callbacks.Ble_event_data_cb != NULL)
{
return Obj->Callbacks.Ble_event_data_cb(W61_BLE_EVT_READ_ID, data, len);
}
return 0;
}
MODEM_CMD_DIRECT_DEFINE(on_cmd_ble_noti_data_event)
{
struct modem *mdm = (struct modem *) data->user_data;
W61_Object_t *Obj = CONTAINER_OF(mdm, W61_Object_t, Modem);
if (Obj->Callbacks.Ble_event_data_cb != NULL)
{
return Obj->Callbacks.Ble_event_data_cb(W61_BLE_EVT_NOTIFICATION_DATA_ID, data, len);
}
return 0;
}
MODEM_CMD_DEFINE(on_cmd_net_event)
{
struct modem *mdm = (struct modem *) data->user_data;
W61_Object_t *Obj = CONTAINER_OF(mdm, W61_Object_t, Modem);
if (Obj->Callbacks.Net_event_cb != NULL)
{
Obj->Callbacks.Net_event_cb(Obj, &argc, (char **)argv);
}
return 0;
}
MODEM_CMD_DEFINE(on_cmd_net_ping_event)
{
struct modem *mdm = (struct modem *) data->user_data;
W61_Object_t *Obj = CONTAINER_OF(mdm, W61_Object_t, Modem);
if (Obj->Callbacks.Net_event_ping_cb != NULL)
{
Obj->Callbacks.Net_event_ping_cb(Obj, &argc, (char **)argv);
}
return 0;
}
MODEM_CMD_DEFINE(on_cmd_net_data_event)
{
struct modem *mdm = (struct modem *) data->user_data;
W61_Object_t *Obj = CONTAINER_OF(mdm, W61_Object_t, Modem);
if (Obj->Callbacks.Net_event_data_cb != NULL)
{
Obj->Callbacks.Net_event_data_cb(Obj, &argc, (char **)argv);
}
return 0;
}
MODEM_CMD_DEFINE(on_cmd_mqtt_event)
{
struct modem *mdm = (struct modem *) data->user_data;
W61_Object_t *Obj = CONTAINER_OF(mdm, W61_Object_t, Modem);
if (Obj->Callbacks.MQTT_event_cb != NULL)
{
Obj->Callbacks.MQTT_event_cb(Obj, &argc, (char **)argv);
}
return 0;
}
MODEM_CMD_DIRECT_DEFINE(on_cmd_mqtt_data_event)
{
struct modem *mdm = (struct modem *) data->user_data;
W61_Object_t *Obj = CONTAINER_OF(mdm, W61_Object_t, Modem);
if (Obj->Callbacks.MQTT_event_data_cb != NULL)
{
return Obj->Callbacks.MQTT_event_data_cb(0, data, len);
}
return 0;
}
/** @} */
@@ -0,0 +1,215 @@
/**
******************************************************************************
* @file w61_at_common.h
* @author ST67 Application Team
* @brief This file provides the common definitions of the AT driver
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef W61_AT_COMMON_H
#define W61_AT_COMMON_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include "w61_at_api.h"
/** @defgroup ST67W61_AT_Common ST67W61 AT Driver Common
* @ingroup ST67W61_AT
*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup ST67W61_AT_Common_Constants ST67W61 AT Driver Common Constants
* @ingroup ST67W61_AT_Common
* @{
*/
#ifndef W61_CMDRSP_STRING_SIZE
/** W61 AT command response string size */
#define W61_CMDRSP_STRING_SIZE 192U
#endif /* W61_CMDRSP_STRING_SIZE */
#ifndef W61_MDM_RX_TASK_STACK_SIZE_BYTES
/** Stack required especially for Log messages */
#define W61_MDM_RX_TASK_STACK_SIZE_BYTES 2048U
#endif /* W61_MDM_RX_TASK_STACK_SIZE_BYTES */
#ifndef W61_MDM_RX_TASK_PRIO
/** W61 W61_Modem_Process task priority, recommended to be higher than application tasks */
#define W61_MDM_RX_TASK_PRIO 54
#endif /* W61_MDM_RX_TASK_PRIO */
#ifndef W61_MAX_AT_LOG_LENGTH
/** Maximum size of AT log */
#define W61_MAX_AT_LOG_LENGTH 300U
#endif /* W61_MAX_AT_LOG_LENGTH */
/** Cmd/query default timeouts */
#ifndef W61_NCP_TIMEOUT
/** Timeout for reply/execute of NCP */
#define W61_NCP_TIMEOUT 2000U
#endif /* W61_NCP_TIMEOUT */
#ifndef W61_SYS_TIMEOUT
/** Timeout for special cases like flash write, firmware updates, etc */
#define W61_SYS_TIMEOUT 2000U
#endif /* W61_SYS_TIMEOUT */
#ifndef W61_WIFI_TIMEOUT
/** Timeout for remote WIFI device operation (e.g. AP) */
#define W61_WIFI_TIMEOUT 6000U
#endif /* W61_WIFI_TIMEOUT */
#ifndef W61_NET_TIMEOUT
/** Timeout for remote network operation (e.g. server) */
#define W61_NET_TIMEOUT 6000U
#endif /* W61_NET_TIMEOUT */
#ifndef W61_BLE_TIMEOUT
/** Timeout for remote BLE device operation */
#define W61_BLE_TIMEOUT 2000U
#endif /* W61_BLE_TIMEOUT */
/** @} */
/* Exported variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/** @defgroup ST67W61_AT_Common_Macros ST67W61 AT Driver Common Macros
* @ingroup ST67W61_AT_Common
* @{
*/
#ifndef CONTAINER_OF
/** Return the pointer to the structure containing the specified member */
#define CONTAINER_OF(ptr, type, field) \
({ \
((type *)(((char *)(ptr)) - offsetof(type, field)));\
})
#endif
/**
* \def AT_LOG_HOST_OUT(pBuf, len)
* AT log trace to announce an AT command sent to the module
*/
/**
* \def AT_LOG_HOST_IN(pBuf, len)
* AT log trace to announce an AT message received from the module
*/
#if (W61_AT_LOG_ENABLE == 1)
#define AT_LOG_HOST_OUT(pBuf, len) W61_AT_Logger( pBuf, len, ">")
#define AT_LOG_HOST_IN(pBuf, len) W61_AT_Logger( pBuf, len, "<")
#else
#define AT_LOG_HOST_OUT(pBuf, len)
#define AT_LOG_HOST_IN(pBuf, len)
#endif /* W61_AT_LOG_ENABLE */
/** @} */
/* Exported functions ------------------------------------------------------- */
/** @defgroup ST67W61_AT_Common_Functions ST67W61 AT Driver Common Functions
* @ingroup ST67W61_AT_Common
* @{
*/
/**
* @brief Initialize the W61 AT modem
* @param Obj: pointer to module handle
* @return Operation status
*/
int32_t W61_AT_ModemInit(W61_Object_t *Obj);
/**
* @brief Deinitialize the W61 AT modem
* @param Obj: pointer to module handle
*/
void W61_AT_ModemDeInit(W61_Object_t *Obj);
/**
* @brief Translate modem_cmd status into W61_Status_t
* @param ret status
* @return Operation status W61_Status_t
*/
W61_Status_t W61_Status(int32_t ret);
/**
* @brief Send the AT command for Set and Execute mode, and check the status response
* @param Obj: pointer to module handle
* @param p_cmd: pointer to pass command string
* @param timeout_ms: timeout for the W61_SetExecute
* @return Operation status
*/
W61_Status_t W61_AT_Common_SetExecute(W61_Object_t *Obj, uint8_t *p_cmd, uint32_t timeout_ms);
/**
* @brief Send the AT command for Queries, wait Query response and check the status response
* @param Obj: pointer to module handle
* @param p_cmd: pointer to pass command string. Reused as rx buffer to store the argv content
* @param p_resp: pointer to pass expected response string. \
* Must be provided as buffer allocated locally to ensure re-entrance
* @param argc: pointer to number of found argument
* @param argv: pointer to argument table
* @param timeout_ms: timeout for the first W61_AT_Common_Query_Parse
* @return Operation status
*/
W61_Status_t W61_AT_Common_Query_Parse(W61_Object_t *Obj, char *p_cmd, char *p_resp,
uint16_t *argc, char **argv, uint32_t timeout_ms);
/**
* @brief Send the AT command for Set and Execute mode and send data
* @param Obj: pointer to module handle
* @param p_cmd: pointer to pass command string
* @param pdata: pointer to data to send
* @param len: binary data length
* @param timeout_ms: timeout
* @param check_resp: if true, check the response status
* @return Operation status
*/
W61_Status_t W61_AT_Common_RequestSendData(W61_Object_t *Obj, uint8_t *p_cmd, uint8_t *pdata, uint32_t len,
uint32_t timeout_ms, bool check_resp);
/**
* @brief Remove the double quotes at the beginning and the end of the string
* @param inbuf: input string
*/
void W61_AT_RemoveStrQuotes(char *inbuf);
/**
* @brief Log AT command
* @param pBuf: pointer to buffer
* @param len: buffer length
* @param inOut: pointer to string
*/
void W61_AT_Logger(uint8_t *pBuf, uint32_t len, char *inOut);
#if defined(__ICCARM__) || defined(__ICCRX__) || defined(__ARMCC_VERSION) /* For IAR/MDK Compiler */
/**
* @brief Function locates the first occurrence of the null-terminated string little in the string big
*/
char *strnstr(const char *big, const char *little, size_t len);
#endif /* __ICCARM__ || __ARMCC_VERSION */
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* W61_AT_COMMON_H */
@@ -0,0 +1,78 @@
/**
******************************************************************************
* @file w61_at_internal.h
* @author ST67 Application Team
* @brief This file provides the internal definitions of the AT driver
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef W61_AT_INTERNAL_H
#define W61_AT_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include "w61_default_config.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/** @addtogroup ST67W61_AT_Common_Macros
* @{
*/
/**
* \def W61_ASSERT(p)
* Macro to check if the expression is true and call the assert function if it is false
*/
/**
* \def W61_NULL_ASSERT(p)
* Macro to check if the pointer is NULL and return the error code
*/
/**
* \def W61_NULL_ASSERT_VOID(p)
* Macro to check if the pointer is NULL does not return the error code
*/
/**
* \def W61_NULL_ASSERT_STR(p, s)
* Macro to check if the pointer is NULL and return the error code with error string log
*/
#if (W61_ASSERT_ENABLE == 1)
/** Macro to check if the pointer is NULL and return the error code with error string log */
#define W61_ASSERT(expr) if (!(expr)) { LogError("Assert failed: file: %s, line: %d", __FILE__, __LINE__); while(1); }
#define W61_NULL_ASSERT(p) if ((p) == NULL) { return W61_STATUS_ERROR; }
#define W61_NULL_ASSERT_VOID(p) if ((p) == NULL) { return; }
#define W61_NULL_ASSERT_STR(p, s) if ((p) == NULL) { LogError("%s\n", (s)); return W61_STATUS_ERROR; }
#else
#define W61_ASSERT(expr)
#define W61_NULL_ASSERT(p)
#define W61_NULL_ASSERT_VOID(p)
#define W61_NULL_ASSERT_STR(p, s)
#endif /* W61_ASSERT_ENABLE */
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /*W61_AT_INTERNAL_H */
@@ -0,0 +1,544 @@
/**
******************************************************************************
* @file w61_at_mqtt.c
* @author ST67 Application Team
* @brief This file provides code for W61 MQTT AT module
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <inttypes.h>
#include <stdio.h>
#include "w61_at_api.h"
#include "w61_at_common.h"
#include "w61_at_internal.h"
#include "common_parser.h" /* Common Parser functions */
#if (defined(SYS_DBG_ENABLE_TA4) && (SYS_DBG_ENABLE_TA4 >= 1))
#include "trcRecorder.h"
#endif /* SYS_DBG_ENABLE_TA4 */
/* Global variables ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/** @addtogroup ST67W61_AT_MQTT_Constants
* @{
*/
#define W61_MQTT_CONNECT_TIMEOUT 10000U /*!< MQTT connect timeout in ms */
/** @} */
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @addtogroup ST67W61_AT_MQTT_Functions
* @{
*/
/**
* @brief Callback function to handle MQTT get subscription responses
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings
* @param argc: number of argument
* @return 0 on success, negative value on error
*/
MODEM_CMD_DECLARE(on_cmd_getsub);
/**
* @brief Callback function to handle MQTT unsubscribe responses
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @param argv: array of argument strings
* @param argc: number of argument
* @return 0 on success, negative value on error
*/
MODEM_CMD_DECLARE(on_cmd_getunsub);
/**
* @brief Parses MQTT event and call related callback
* @param hObj: pointer to module handle
* @param argc: pointer to argument count
* @param argv: pointer to argument values
*/
static void W61_MQTT_AT_Event(void *hObj, uint16_t *argc, char **argv);
/**
* @brief Callback function to handle MQTT data events
* @param event_id: event ID
* @param data: pointer to the modem_cmd_handler_data structure
* @param len: length of the data
* @return data length on success, negative value on error
*/
static int32_t W61_MQTT_Data_Event(uint32_t event_id, struct modem_cmd_handler_data *data, uint16_t len);
/* Functions Definition ------------------------------------------------------*/
W61_Status_t W61_MQTT_Init(W61_Object_t *Obj, uint8_t *p_recv_data, uint32_t recv_data_buf_len)
{
W61_NULL_ASSERT(Obj);
W61_NULL_ASSERT(p_recv_data);
/* Initialize the MQTT data buffer. Used to store received MQTT messages */
Obj->MQTTCtx.AppBuffRecvData = p_recv_data;
Obj->MQTTCtx.AppBuffRecvDataSize = recv_data_buf_len;
/* Register the MQTT event callbacks */
Obj->Callbacks.MQTT_event_cb = W61_MQTT_AT_Event;
Obj->Callbacks.MQTT_event_data_cb = W61_MQTT_Data_Event;
return W61_STATUS_OK;
}
W61_Status_t W61_MQTT_DeInit(W61_Object_t *Obj)
{
W61_NULL_ASSERT(Obj);
Obj->MQTTCtx.AppBuffRecvData = NULL;
Obj->MQTTCtx.AppBuffRecvDataSize = 0;
Obj->Callbacks.MQTT_event_cb = NULL;
Obj->Callbacks.MQTT_event_data_cb = NULL;
return W61_STATUS_OK;
}
W61_Status_t W61_MQTT_SetUserConfiguration(W61_Object_t *Obj, uint32_t Scheme, uint8_t *ClientId, uint8_t *Username,
uint8_t *Password, uint8_t *Certificate, uint8_t *PrivateKey,
uint8_t *CaCertificate)
{
char cmd[W61_CMDRSP_STRING_SIZE];
W61_NULL_ASSERT(Obj);
W61_NULL_ASSERT(ClientId);
W61_NULL_ASSERT(Username);
W61_NULL_ASSERT(Password);
W61_NULL_ASSERT(Certificate);
W61_NULL_ASSERT(PrivateKey);
W61_NULL_ASSERT(CaCertificate);
if (ClientId[0] == '\0')
{
return W61_STATUS_ERROR; /* ClientId must not be empty */
}
(void)snprintf(cmd, W61_CMDRSP_STRING_SIZE,
"AT+MQTTUSERCFG=0,%" PRIu32 ",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\r\n",
Scheme, ClientId, Username, Password, Certificate, PrivateKey, CaCertificate);
return W61_AT_Common_SetExecute(Obj, (uint8_t *)cmd, W61_NET_TIMEOUT);
}
W61_Status_t W61_MQTT_GetUserConfiguration(W61_Object_t *Obj, uint8_t ClientId[32], uint8_t Username[32],
uint8_t Password[32], uint8_t Certificate[32], uint8_t PrivateKey[32],
uint8_t CaCertificate[32])
{
char *argv[CONFIG_MODEM_CMD_HANDLER_MAX_PARAM_COUNT];
char cmd[W61_CMD_MATCH_BUFF_SIZE];
uint16_t argc = 0;
W61_Status_t ret;
W61_NULL_ASSERT(Obj);
W61_NULL_ASSERT(ClientId);
W61_NULL_ASSERT(Username);
W61_NULL_ASSERT(Password);
W61_NULL_ASSERT(Certificate);
W61_NULL_ASSERT(PrivateKey);
W61_NULL_ASSERT(CaCertificate);
/* Initialize the output parameters */
ClientId[0] = '\0';
Username[0] = '\0';
Password[0] = '\0';
Certificate[0] = '\0';
PrivateKey[0] = '\0';
CaCertificate[0] = '\0';
(void)strncpy(cmd, "AT+MQTTUSERCFG?\r\n", sizeof(cmd));
ret = W61_AT_Common_Query_Parse(Obj, cmd, "+MQTTUSERCFG:", &argc, argv, W61_NCP_TIMEOUT);
if (ret != W61_STATUS_OK)
{
return ret;
}
if (argc < 8U)
{
return W61_STATUS_ERROR;
}
W61_AT_RemoveStrQuotes(argv[2]); /* ClientId */
(void)strncpy((char *)ClientId, argv[2], 31);
ClientId[31] = '\0'; /* Ensure null termination */
W61_AT_RemoveStrQuotes(argv[3]); /* Username */
(void)strncpy((char *)Username, argv[3], 31);
Username[31] = '\0'; /* Ensure null termination */
W61_AT_RemoveStrQuotes(argv[4]); /* Password */
(void)strncpy((char *)Password, argv[4], 31);
Password[31] = '\0'; /* Ensure null termination */
W61_AT_RemoveStrQuotes(argv[5]); /* Certificate */
(void)strncpy((char *)Certificate, argv[5], 31);
Certificate[31] = '\0'; /* Ensure null termination */
W61_AT_RemoveStrQuotes(argv[6]); /* Private Key */
(void)strncpy((char *)PrivateKey, argv[6], 31);
PrivateKey[31] = '\0'; /* Ensure null termination */
W61_AT_RemoveStrQuotes(argv[7]); /* CA Certificate */
(void)strncpy((char *)CaCertificate, argv[7], 31);
CaCertificate[31] = '\0'; /* Ensure null termination */
return ret;
}
W61_Status_t W61_MQTT_SetConfiguration(W61_Object_t *Obj, uint32_t KeepAlive, uint32_t DisableCleanSession,
uint8_t *WillTopic, uint8_t *WillMessage, uint32_t WillQos,
uint32_t WillRetain)
{
char cmd[W61_CMDRSP_STRING_SIZE];
W61_NULL_ASSERT(Obj);
(void)snprintf(cmd, W61_CMDRSP_STRING_SIZE,
"AT+MQTTCONNCFG=0,%" PRIu32 ",%" PRIu32 ",\"%s\",\"%s\",%" PRIu32 ",%" PRIu32 "\r\n",
KeepAlive, DisableCleanSession, WillTopic, WillMessage, WillQos, WillRetain);
return W61_AT_Common_SetExecute(Obj, (uint8_t *)cmd, W61_NET_TIMEOUT);
}
W61_Status_t W61_MQTT_GetConfiguration(W61_Object_t *Obj, uint32_t *KeepAlive, uint32_t *DisableCleanSession,
uint8_t WillTopic[64], uint8_t WillMessage[64], uint32_t *WillQos,
uint32_t *WillRetain)
{
char *argv[CONFIG_MODEM_CMD_HANDLER_MAX_PARAM_COUNT];
uint16_t argc = 0;
char cmd[W61_CMD_MATCH_BUFF_SIZE];
W61_Status_t ret;
W61_NULL_ASSERT(Obj);
W61_NULL_ASSERT(KeepAlive);
W61_NULL_ASSERT(DisableCleanSession);
W61_NULL_ASSERT(WillTopic);
W61_NULL_ASSERT(WillMessage);
W61_NULL_ASSERT(WillQos);
W61_NULL_ASSERT(WillRetain);
(void)strncpy(cmd, "AT+MQTTCONNCFG?\r\n", sizeof(cmd));
ret = W61_AT_Common_Query_Parse(Obj, cmd, "+MQTTCONNCFG:", &argc, argv, W61_NET_TIMEOUT);
if (ret != W61_STATUS_OK)
{
return ret;
}
if (argc < 7U)
{
return W61_STATUS_ERROR;
}
*KeepAlive = atoi(argv[1]);
*DisableCleanSession = atoi(argv[2]);
W61_AT_RemoveStrQuotes(argv[3]); /* WillTopic */
(void)strncpy((char *)WillTopic, argv[3], 63);
WillTopic[63] = 0; /* Ensure null termination */
W61_AT_RemoveStrQuotes(argv[4]); /* WillMessage */
(void)strncpy((char *)WillMessage, argv[4], 63);
WillMessage[63] = 0; /* Ensure null termination */
*WillQos = atoi(argv[5]);
*WillRetain = atoi(argv[6]);
return ret;
}
W61_Status_t W61_MQTT_SetSNI(W61_Object_t *Obj, uint8_t *SNI)
{
char cmd[W61_CMDRSP_STRING_SIZE];
W61_NULL_ASSERT(Obj);
W61_NULL_ASSERT(SNI);
(void)snprintf(cmd, W61_CMDRSP_STRING_SIZE, "AT+MQTTSNI=0,\"%s\"\r\n", SNI);
return W61_AT_Common_SetExecute(Obj, (uint8_t *)cmd, W61_NET_TIMEOUT);
}
W61_Status_t W61_MQTT_GetSNI(W61_Object_t *Obj, uint8_t SNI[128])
{
char *argv[CONFIG_MODEM_CMD_HANDLER_MAX_PARAM_COUNT];
char cmd[W61_CMD_MATCH_BUFF_SIZE];
uint16_t argc = 0;
W61_Status_t ret;
W61_NULL_ASSERT(Obj);
W61_NULL_ASSERT(SNI);
(void)strncpy(cmd, "AT+MQTTSNI?\r\n", sizeof(cmd));
ret = W61_AT_Common_Query_Parse(Obj, cmd, "+MQTTSNI:", &argc, argv, W61_NET_TIMEOUT);
if (ret != W61_STATUS_OK)
{
return ret;
}
if (argc < 2U)
{
return W61_STATUS_ERROR;
}
/* Verify the SNI is valid */
if (strncmp(argv[1], "\"", 1) == 0)
{
W61_AT_RemoveStrQuotes(argv[1]); /* Remove quotes from the string */
(void)strncpy((char *)SNI, argv[1], 127);
SNI[127] = '\0'; /* Ensure null termination */
}
else
{
ret = W61_STATUS_ERROR;
}
return ret;
}
W61_Status_t W61_MQTT_Connect(W61_Object_t *Obj, uint8_t *Host, uint16_t Port)
{
uint8_t reconnect = 0;
char cmd[W61_CMDRSP_STRING_SIZE];
W61_NULL_ASSERT(Obj);
W61_NULL_ASSERT(Host);
(void)snprintf(cmd, W61_CMDRSP_STRING_SIZE,
"AT+MQTTCONN=0,\"%s\",%" PRIu16 ",%" PRIu16 "\r\n",
Host, Port, reconnect);
return W61_AT_Common_SetExecute(Obj, (uint8_t *)cmd, W61_MQTT_CONNECT_TIMEOUT);
}
W61_Status_t W61_MQTT_GetConnectionStatus(W61_Object_t *Obj, uint8_t *Host, uint32_t *Port,
uint32_t *Scheme, uint32_t *State)
{
char *argv[CONFIG_MODEM_CMD_HANDLER_MAX_PARAM_COUNT];
char cmd[W61_CMD_MATCH_BUFF_SIZE];
uint16_t argc = 0;
W61_Status_t ret;
W61_NULL_ASSERT(Obj);
W61_NULL_ASSERT(Host);
W61_NULL_ASSERT(Port);
W61_NULL_ASSERT(Scheme);
W61_NULL_ASSERT(State);
(void)strncpy(cmd, "AT+MQTTCONN?\r\n", sizeof(cmd));
ret = W61_AT_Common_Query_Parse(Obj, cmd, "+MQTTCONN:", &argc, argv, W61_NET_TIMEOUT);
if (ret != W61_STATUS_OK)
{
return ret;
}
if (argc < 6U)
{
return W61_STATUS_ERROR;
}
*State = atoi(argv[1]);
*Scheme = atoi(argv[2]);
W61_AT_RemoveStrQuotes(argv[3]);
(void)strncpy((char *)Host, argv[3], 63);
*Port = atoi(argv[4]);
return ret;
}
W61_Status_t W61_MQTT_Disconnect(W61_Object_t *Obj)
{
W61_NULL_ASSERT(Obj);
return W61_AT_Common_SetExecute(Obj, (uint8_t *)"AT+MQTTCLEAN=0\r\n", W61_NET_TIMEOUT);
}
W61_Status_t W61_MQTT_Subscribe(W61_Object_t *Obj, uint8_t *Topic)
{
uint32_t qos = 0;
char cmd[W61_CMDRSP_STRING_SIZE];
W61_NULL_ASSERT(Obj);
W61_NULL_ASSERT(Topic);
(void)snprintf(cmd, W61_CMDRSP_STRING_SIZE, "AT+MQTTSUB=0,\"%s\",%" PRIu32 "\r\n", Topic, qos);
return W61_AT_Common_SetExecute(Obj, (uint8_t *)cmd, W61_NET_TIMEOUT);
}
W61_Status_t W61_MQTT_GetSubscribedTopics(W61_Object_t *Obj)
{
struct modem *mdm = (struct modem *) &Obj->Modem;
W61_NULL_ASSERT(Obj);
struct modem_cmd handlers[] =
{
MODEM_CMD("+MQTTSUB:", on_cmd_getsub, 4U, ","),
};
return W61_Status(modem_cmd_send(&mdm->iface,
&mdm->handler,
handlers,
ARRAY_SIZE(handlers),
(const uint8_t *)"AT+MQTTSUB?\r\n",
mdm->sem_response,
W61_NET_TIMEOUT));
}
W61_Status_t W61_MQTT_Unsubscribe(W61_Object_t *Obj, uint8_t *Topic)
{
struct modem *mdm = (struct modem *) &Obj->Modem;
char cmd[W61_CMDRSP_STRING_SIZE];
W61_NULL_ASSERT(Obj);
W61_NULL_ASSERT(Topic);
struct modem_cmd handlers[] =
{
MODEM_CMD("+MQTTUNSUB:", on_cmd_getunsub, 1U, ""),
};
(void)snprintf(cmd, W61_CMDRSP_STRING_SIZE, "AT+MQTTUNSUB=0,\"%s\"\r\n", Topic);
return W61_Status(modem_cmd_send(&mdm->iface,
&mdm->handler,
handlers,
ARRAY_SIZE(handlers),
(const uint8_t *)cmd,
mdm->sem_response,
W61_NET_TIMEOUT));
}
W61_Status_t W61_MQTT_Publish(W61_Object_t *Obj, uint8_t *Topic, uint8_t *Message, uint32_t Message_len, uint32_t Qos,
uint32_t Retain)
{
char cmd[W61_CMDRSP_STRING_SIZE];
W61_NULL_ASSERT(Obj);
W61_NULL_ASSERT(Topic);
W61_NULL_ASSERT(Message);
if (Message_len > 0U)
{
(void)snprintf(cmd, W61_CMDRSP_STRING_SIZE, "AT+MQTTPUBRAW=0,\"%s\",%" PRIu32 ",%" PRIu32 ",%" PRIu32 "\r\n",
Topic, Message_len, Qos, Retain);
return W61_AT_Common_RequestSendData(Obj, (uint8_t *)cmd, Message, Message_len, W61_NET_TIMEOUT, true);
}
else
{
(void)snprintf(cmd, W61_CMDRSP_STRING_SIZE,
"AT+MQTTPUB=0,\"%s\",\"\",%" PRIu32 ",%" PRIu32 "\r\n",
Topic, Qos, Retain);
return W61_AT_Common_SetExecute(Obj, (uint8_t *)cmd, W61_NET_TIMEOUT);
}
}
/* Private Functions Definition ----------------------------------------------*/
MODEM_CMD_DEFINE(on_cmd_getsub)
{
if (argc >= 4U)
{
MQTT_LOG_DEBUG("LinkID: %" PRIu32 ", state: %" PRIu32 ", topic: %s, qos: %" PRIu32 "\n",
atoi((char *)argv[0]), atoi((char *)argv[1]), argv[2], atoi((char *)argv[3]));
}
return 0;
}
MODEM_CMD_DEFINE(on_cmd_getunsub)
{
if ((argc >= 1U) && (strcmp((char *)argv[0], "NO_UNSUBSCRIBE") == 0))
{
MQTT_LOG_WARN("No topic found\n");
}
return 0;
}
static void W61_MQTT_AT_Event(void *hObj, uint16_t *argc, char **argv)
{
W61_Object_t *Obj = (W61_Object_t *)hObj;
if ((Obj == NULL) || (Obj->ulcbs.UL_mqtt_cb == NULL) || (*argc < 2U))
{
return;
}
/* Argv[0] = link id. not used */
if (strcmp(argv[0], "CONNECTED") == 0)
{
Obj->ulcbs.UL_mqtt_cb(W61_MQTT_EVT_CONNECTED_ID, NULL);
return;
}
if (strcmp(argv[0], "DISCONNECTED") == 0)
{
Obj->ulcbs.UL_mqtt_cb(W61_MQTT_EVT_DISCONNECTED_ID, NULL);
return;
}
}
static int32_t W61_MQTT_Data_Event(uint32_t event_id, struct modem_cmd_handler_data *data, uint16_t len)
{
struct modem *mdm = (struct modem *)data->user_data;
W61_Object_t *Obj = CONTAINER_OF(mdm, W61_Object_t, Modem);
W61_MQTT_CbParamData_t cb_param_mqtt_data;
uint8_t *ptr;
uint8_t *endptr;
uint32_t header_len;
uint32_t topic_len;
uint32_t message_len;
uint16_t rx_data_len;
if ((data->rx_buf == NULL) || (Obj->MQTTCtx.AppBuffRecvData == NULL))
{
return -EINVAL;
}
ptr = &data->rx_buf[len + 2U]; /* Skip the link id and the comma */
data->rx_buf[data->rx_buf_len] = 0;
/* Get the topic length */
topic_len = strtol((char *)ptr, (char **)&endptr, 10);
if ((endptr == ptr) || (*endptr != ','))
{
return -EINVAL;
}
topic_len += 2; /* Include double-quotes */
endptr++; /* Skip the comma */
/* Get the message length */
message_len = strtol((char *)endptr, (char **)&endptr, 10);
if ((endptr == ptr) || (*endptr != ','))
{
return -EINVAL;
}
endptr++; /* Skip the comma */
/* Check if the buffer is large enough to hold the topic and message */
if ((topic_len + message_len + 1) > Obj->MQTTCtx.AppBuffRecvDataSize) /* +1 for the intermediate comma */
{
return -ENOMEM;
}
header_len = endptr - data->rx_buf;
rx_data_len = header_len + topic_len + message_len + 1; /* +1 for the intermediate comma */
if (data->rx_buf_len >= rx_data_len)
{
/* Copy the topic */
(void)memcpy(Obj->MQTTCtx.AppBuffRecvData, endptr, topic_len);
/* Null-terminate the topic */
Obj->MQTTCtx.AppBuffRecvData[topic_len] = 0;
endptr += topic_len + 1; /* Skip the comma after topic */
/* Copy the message */
(void)memcpy(&Obj->MQTTCtx.AppBuffRecvData[topic_len + 1], endptr, message_len);
cb_param_mqtt_data.topic_length = topic_len;
cb_param_mqtt_data.message_length = message_len;
if (Obj->ulcbs.UL_mqtt_cb != NULL)
{
Obj->ulcbs.UL_mqtt_cb(W61_MQTT_EVT_SUBSCRIPTION_RECEIVED_ID, &cb_param_mqtt_data);
}
return rx_data_len;
}
else
{
return -EAGAIN;
}
}
/** @} */
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,155 @@
/**
******************************************************************************
* @file w61_default_config.h
* @author ST67 Application Team
* @brief Header file for the W61 configuration module
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef W61_DEFAULT_CONFIG_H
#define W61_DEFAULT_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include "w61_driver_config.h"
/* Exported constants --------------------------------------------------------*/
/** @addtogroup ST67W61_AT_WiFi_Constants
* @{
*/
#ifndef W61_WIFI_MAX_DETECTED_AP
/** Maximum number of detected AP during the scan. Cannot be greater than 50 */
#define W61_WIFI_MAX_DETECTED_AP 20U
#endif /* W61_WIFI_MAX_DETECTED_AP */
#ifndef WIFI_LOG_ENABLE
/** Enable/Disable Wi-Fi module logging */
#define WIFI_LOG_ENABLE 0
#endif /* WIFI_LOG_ENABLE */
/** @} */
/** @addtogroup ST67W61_AT_BLE_Constants
* @{
*/
#ifndef W61_BLE_MAX_CONN_NBR
/** Maximum number of BLE connections. Must not be greater than 10.
* The maximum connections depend on the mode as follows:
* - Server mode (10 connection max)
* - Client mode (9 connection max)
* - Dual Mode (10 connections max with up to 9 as Client)
*/
#define W61_BLE_MAX_CONN_NBR 2U
#endif /* W61_BLE_MAX_CONN_NBR */
/** Maximum number of BLE application services that can be created */
#define W61_BLE_MAX_CREATED_SERVICE_NBR 3U
/** Maximum number of BLE services supported including Generic access and Generic attributes predefined services */
#define W61_BLE_MAX_SERVICE_NBR (W61_BLE_MAX_CREATED_SERVICE_NBR + 2U)
/** Maximum number of BLE characteristics per service */
#define W61_BLE_MAX_CHAR_NBR 5U
#ifndef W61_BLE_MAX_DETECTED_PERIPHERAL
/** Maximum number of detected peripheral during the scan. Cannot be greater than 50 */
#define W61_BLE_MAX_DETECTED_PERIPHERAL 10U
#endif /* W61_BLE_MAX_DETECTED_PERIPHERAL */
/** BLE Service/Characteristic UUID maximum size size */
#define W61_BLE_MAX_UUID_SIZE 17U
/** Maximum number of bonded devices */
#define W61_BLE_MAX_BONDED_DEVICES 2U
#ifndef BLE_LOG_ENABLE
/** Enable/Disable BLE module logging */
#define BLE_LOG_ENABLE 0
#endif /* BLE_LOG_ENABLE */
/** @} */
/** @addtogroup ST67W61_AT_Net_Constants
* @{
*/
#ifndef W61_NET_IPV6_ENABLE
/** Enable IPv6 support : 0: Disabled, 1: Enabled */
#define W61_NET_IPV6_ENABLE 0
#endif /* W61_NET_IPV6_ENABLE */
#ifndef NET_LOG_ENABLE
/** Enable/Disable Network module logging */
#define NET_LOG_ENABLE 0
#endif /* NET_LOG_ENABLE */
/** @} */
/** @addtogroup ST67W61_AT_MQTT_Constants
* @{
*/
#ifndef MQTT_LOG_ENABLE
/** Enable/Disable MQTT module logging */
#define MQTT_LOG_ENABLE 0
#endif /* MQTT_LOG_ENABLE */
/** @} */
/** @addtogroup ST67W61_AT_Common_Constants
* @{
*/
#ifndef W61_MAX_SPI_XFER
/** Maximum SPI buffer size */
#define W61_MAX_SPI_XFER 1520U
#endif /* W61_MAX_SPI_XFER */
#if ((W61_MAX_SPI_XFER < 1520U) || (W61_MAX_SPI_XFER > (6U * 1024U)))
#error "W6X_MAX_SPI_XFER must be between 1520 and (6*1024)"
#endif /* W61_MAX_SPI_XFER */
#ifndef SYS_LOG_ENABLE
/** Enable/Disable System module logging */
#define SYS_LOG_ENABLE 0
#endif /* SYS_LOG_ENABLE */
#ifndef W61_AT_LOG_ENABLE
/** Debugging only: Enable/Disable AT log, i.e. logs the AT commands incoming/outcoming from/to the NCP */
#define W61_AT_LOG_ENABLE 0
#endif /* W61_AT_LOG_ENABLE */
#ifndef MDM_CMD_LOG_ENABLE
/** Enable/Disable Modem command log */
#define MDM_CMD_LOG_ENABLE W61_AT_LOG_ENABLE
#endif /* MDM_CMD_LOG_ENABLE */
#ifndef W61_ASSERT_ENABLE
/** Enable/Disable NULL pointer check in the AT functions.
* 0: Disabled, 1: Enabled */
#define W61_ASSERT_ENABLE 0
#endif /* W61_ASSERT_ENABLE */
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* W61_DEFAULT_CONFIG_H */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,285 @@
/**
******************************************************************************
* @file spi_iface.h
* @brief SPI bus interface definition
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/**
* This file is based on QCC74xSDK provided by Qualcomm.
* See https://git.codelinaro.org/clo/qcc7xx/QCCSDK-QCC74x for more information.
*
* Reference source: examples/stm32_spi_host/QCC743_SPI_HOST/Core/Inc/spi.h
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef SPI_IFACE_H
#define SPI_IFACE_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/** SPI message control structure */
struct spi_msg_control
{
/** Ref SPI_MSG_CTRL_xxx */
uint8_t type;
/** Length of the following control data */
uint8_t len;
/** Pointer to the control data */
void *val;
};
/** SPI message structure */
struct spi_msg
{
union
{
/** For spi_write and spi_read */
struct
{
/** Data pointer for spi_write and spi_read */
void *data;
/** Data length for spi_write and spi_read */
uint32_t data_len;
};
/** Data buffer for spi_write when type is SPI_MSG_OP_BUFFER */
struct spi_buffer *buffer;
/** Data buffer for spi_read when type is SPI_MSG_OP_BUFFER_PTR */
struct spi_buffer **buffer_ptr;
};
/** Pointer to control information */
struct spi_msg_control *ctrl;
/** Message flags */
uint32_t flags;
/** Operation type: Ref SPI_MSG_OP_xxx */
unsigned char op_type;
};
/** SPI transfer engine structure */
struct spi_stat
{
uint64_t tx_pkts; /*!< Number of transmitted packets */
uint64_t tx_bytes; /*!< Number of transmitted bytes */
uint64_t rx_pkts; /*!< Number of received packets */
uint64_t rx_bytes; /*!< Number of received bytes */
uint64_t rx_drop; /*!< Number of dropped received packets */
uint64_t io_err; /*!< Number of I/O errors */
uint64_t hdr_err; /*!< Number of header errors */
uint64_t wait_txn_timeouts; /*!< Number of wait transaction timeouts */
uint64_t wait_msg_xfer_timeouts; /*!< Number of wait message transfer timeouts */
uint64_t wait_hdr_ack_timeouts; /*!< Number of wait header ack timeouts */
uint64_t mem_err; /*!< Number of memory errors */
uint64_t rx_stall; /*!< Number of RX stalls */
};
/** SPI buffer structure */
struct spi_buffer
{
/** Pointer to the data */
void *data;
/** Length of the data */
uint16_t len;
/** Capacity of the buffer, >= len */
uint32_t cap;
/** Buffer flags */
uint32_t flags;
/** Control block for private data */
unsigned char cb[16];
};
/** Callback function type for received data notification */
typedef void (*spi_rxd_notify_func_t)(void *arg);
/** SPI message control traffic type enumeration */
typedef enum
{
SPI_MSG_CTRL_TRAFFIC_AT_CMD = 0,
SPI_MSG_CTRL_TRAFFIC_NETWORK_STA,
SPI_MSG_CTRL_TRAFFIC_NETWORK_AP,
SPI_MSG_CTRL_TRAFFIC_HCI,
SPI_MSG_CTRL_TRAFFIC_OT,
SPI_MSG_CTRL_TRAFFIC_TYPE_MAX,
} spi_msg_ctrl_t;
/* Exported constants --------------------------------------------------------*/
/** SPI message flags */
#define SPI_MSG_F_TRUNCATED 0x1U
/** SPI message control types */
#define SPI_MSG_CTRL_TRAFFIC_TYPE 0x1U
/** Length of traffic type control info */
#define SPI_MSG_CTRL_TRAFFIC_TYPE_LEN 1U
/** SPI message operation type: data copy */
#define SPI_MSG_OP_DATA 0U
/** SPI message operation type: buffer pointer for write */
#define SPI_MSG_OP_BUFFER 1U
/** SPI message operation type: buffer pointer for read */
#define SPI_MSG_OP_BUFFER_PTR 2U
/** Maximum SPI buffer size */
#define SPI_XFER_MTU_BYTES W61_MAX_SPI_XFER
/* Exported macro ------------------------------------------------------------*/
/**
* @brief Initialize a SPI message control structure
* @param c: spi_msg_control structure to initialize
* @param t: Control type
* @param l: Control data length
* @param v: Pointer to control data
*/
#define SPI_MSG_CONTROL_INIT(c, t, l, v) do { \
struct spi_msg_control *_c = &(c); \
_c->type = t; \
_c->len = l; \
_c->val = v; \
} while (false)
/**
* @brief Initialize a SPI message structure
* @param m: spi_msg structure to initialize
* @param t: Operation type
* @param c: Pointer to control information
* @param f: Message flags
*/
#define SPI_MSG_INIT(m, t, c, f) do { \
struct spi_msg *_m = &(m); \
_m->op_type = t; \
_m->ctrl = c; \
_m->flags = f; \
} while (false)
/* Exported functions ------------------------------------------------------- */
/**
* @brief Initialize SPI transaction context
* @return 0 on success, negative error code on failure
*/
int32_t spi_transaction_init(void);
/**
* @brief Deinitialize SPI transaction context
* @return 0 on success, negative error code on failure
*/
int32_t spi_transaction_deinit(void);
/**
* @brief Allocate a SPI buffer
* @param size: Size of the buffer to allocate
* @return Pointer to the allocated buffer, or NULL on failure
*/
struct spi_buffer *spi_tx_buffer_alloc(uint32_t size);
/**
* @brief Free a SPI buffer
* @param buf: Pointer to the buffer to free
*/
void spi_buffer_free(struct spi_buffer *buf);
/**
* @brief Get data pointer from SPI buffer
* @param buf: Pointer to the SPI buffer
* @return Pointer to the data
*/
static inline void *spi_buffer_data(struct spi_buffer *buf)
{
return buf->data;
}
/**
* @brief Get data length from SPI buffer
* @param buf: Pointer to the SPI buffer
* @return Length of the data
*/
static inline uint32_t spi_buffer_len(struct spi_buffer *buf)
{
return buf->len;
}
/**
* @brief Bind a specific traffic type to a dedicated receive queue
* @param type: Traffic type to bind (must be < SPI_MSG_CTRL_TRAFFIC_TYPE_MAX)
* @param rxq_size: Size of receive queue to create (0 for default)
* @return 0 on success, negative value on error
*
* @note This function should be called during initialization before
* any SPI transfers start, as it's not fully thread-safe. Multiple
* concurrent binds or binding while transfers are in progress could
* lead to race conditions.
*/
int32_t spi_bind(unsigned char type, int32_t rxq_size);
/**
* @brief Read data from the SPI interface
* This function handles both raw data and buffer pointer operations based on the
* message operation type (op_type) field.
*
* @param msg: Message structure for receiving data
* @param timeout_ms: Timeout for queue operations in milliseconds (-1 for infinite)
* @return Number of bytes read or negative error code
*/
int32_t spi_read(struct spi_msg *msg, int32_t timeout_ms);
/**
* @brief Write data to the SPI interface
* This function handles both raw data and pre-allocated buffers based on the
* message operation type (op_type) field.
*
* @param msg: Message containing data or buffer to send
* @param timeout_ms: Timeout for queue operations in milliseconds (-1 for infinite)
* @return Number of bytes written or negative error code
*/
int32_t spi_write(struct spi_msg *msg, int32_t timeout_ms);
/**
* @brief Register a callback for received data of a specific traffic type
* @param type: Traffic type
* @param cb: Callback function
* @param arg: Argument to pass to the callback
* @return 0 on success, negative error code on failure
*/
int32_t spi_rxd_callback_register(spi_msg_ctrl_t type, spi_rxd_notify_func_t cb, void *arg);
/**
* @brief Handle SPI transaction/data ready event
* @return 0 on success, negative error code on failure
*/
int32_t spi_on_txn_data_ready(void);
/**
* @brief Handle SPI header acknowledgment event
* @return 0 on success, negative error code on failure
*/
int32_t spi_on_header_ack(void);
/**
* @brief Dump SPI transaction state and statistics
*/
void spi_dump(void);
/**
* @brief Get SPI transaction statistics
* @param stat: Pointer to the statistics structure to fill
* @return 0 on success, negative error code on failure
*/
int32_t spi_get_stats(struct spi_stat *stat);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SPI_IFACE_H */
@@ -0,0 +1,157 @@
/**
******************************************************************************
* @file spi_port.h
* @brief SPI bus interface porting layer
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/**
* This file is based on QCC74xSDK provided by Qualcomm.
* See https://git.codelinaro.org/clo/qcc7xx/QCCSDK-QCC74x for more information.
*
* Reference source: examples/stm32_spi_host/QCC743_SPI_HOST/Core/Src/spi_iface.c
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef SPI_PORT_H
#define SPI_PORT_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include <inttypes.h>
#include <stdint.h>
#include "logging.h"
/* Exported types ------------------------------------------------------------*/
typedef void (*spi_transaction_complete_t)(void);
/* Exported constants --------------------------------------------------------*/
/** Transfer with size greater than this value should use DMA */
#define SPI_DMA_XFER_SIZE_THRESHOLD 8U
/** SPI wait txn data ready timeout in milliseconds */
#define SPI_WAIT_TXN_TIMEOUT_MS 2000
/** SPI transaction timeout in milliseconds */
#define SPI_WAIT_MSG_XFER_TIMEOUT_MS 500
/** SPI header ack timeout in milliseconds */
#define SPI_WAIT_HDR_ACK_TIMEOUT_MS 100
/** SPI polling transfer timeout in milliseconds */
#define SPI_WAIT_POLL_XFER_TIMEOUT_MS 100
#ifndef SPI_PORT_ERROR_ENABLE
/** Enable/Disable SPI port error logging */
#define SPI_PORT_ERROR_ENABLE 1
#endif /* SPI_PORT_ERROR_ENABLE */
/** SPI event Tx pending */
#define SPI_EVT_TXN_PENDING 0x1U
/** SPI event Tx ready */
#define SPI_EVT_TXN_RDY 0x2U
/** SPI event Header acknowledged */
#define SPI_EVT_HDR_ACKED 0x4U
/** SPI event Hardware transfer done */
#define SPI_EVT_HW_XFER_DONE 0x8U
#ifndef SHORT_FILE
/** Macro to extract short file name from __FILE__ */
#define SHORT_FILE \
(strchr(__FILE__, '\\') \
? ((strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)) \
: ((strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)))
#endif /* SHORT_FILE */
/* Exported macro ------------------------------------------------------------*/
/**
* \def spi_err( ... )
* \brief SPI error logging macro
*/
#if (SPI_PORT_ERROR_ENABLE == 1)
#define spi_err(...) LogError(__VA_ARGS__)
#else
#define spi_err(...)
#endif /* SPI_PORT_ERROR_ENABLE */
/** SPI trace logging. Disabled by default */
#define spi_trace(...)
/* Exported functions ------------------------------------------------------- */
/**
* @brief Initialize SPI port
* @param transaction_complete_cb: Callback function to be called when a DMA transaction is completed
* @retval 0 if successful, -1 otherwise
*/
int32_t spi_port_init(spi_transaction_complete_t transaction_complete_cb);
/**
* @brief De-Initialize SPI port
* @retval 0 if successful, -1 otherwise
*/
int32_t spi_port_deinit(void);
/**
* @brief Execute SPI transaction in blocking mode (polling) with timeout. Can be TxRX or Rx only
* @param tx_buf: Pointer to the transmit buffer
* @param rx_buf: Pointer to the receive buffer
* @param len: Length of the transfer
* @param timeout: Timeout in milliseconds
* @retval 0 if successful, -1 otherwise
*/
int32_t spi_port_transfer(void *tx_buf, void *rx_buf, uint16_t len, uint32_t timeout);
/**
* @brief Execute SPI transaction in non-blocking mode (interrupt). Can be TxRX or Rx only
* @param tx_buf: Pointer to the transmit buffer
* @param rx_buf: Pointer to the receive buffer
* @param len: Length of the transfer
* @retval 0 if successful, -1 otherwise
*/
int32_t spi_port_transfer_dma(void *tx_buf, void *rx_buf, uint16_t len);
/**
* @brief Check if NCP requires to send a new data packet
* @retval 1 if ready, 0 otherwise
*/
int32_t spi_port_is_ready(void);
/**
* @brief Enable or disable the SPI Chip Select (CS) line
* @param state: 1 to set the CS line high, 0 to set it low
* @retval 0 if successful, -1 otherwise
*/
int32_t spi_port_set_cs(int32_t state);
/**
* @brief Copy memory from source to destination
* @note This function can be implemented as 32-bit memcpy
* @param dest: Destination address
* @param src: Source address
* @param len: Length of data to copy in bytes
* @retval Destination address
*/
void *spi_port_memcpy(void *dest, const void *src, unsigned int len);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SPI_PORT_H */
@@ -0,0 +1,138 @@
/**
******************************************************************************
* @file w61_io.c
* @author ST67 Application Team
* @brief This file provides the IO operations to deal with the STM32W61 module.
* It mainly initialize and de-initialize the SPI interface.
* Send and receive data over it.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include "logging.h"
#include "w61_io.h"
#include "FreeRTOS.h"
#include "task.h"
/* Global variables ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/** Initialization flag */
static volatile int32_t BusIo_initialized = 0;
/* Private function prototypes -----------------------------------------------*/
/* Functions Definition ------------------------------------------------------*/
int32_t BusIo_SPI_Init(void)
{
int32_t ret;
if (BusIo_initialized == 1)
{
return -1;
}
ret = spi_transaction_init();
if (ret == 0)
{
BusIo_initialized = 1;
}
return ret;
}
int32_t BusIo_SPI_DeInit(void)
{
BusIo_initialized = 0;
return spi_transaction_deinit();
}
int32_t BusIo_SPI_Bind(uint8_t type, int32_t rxq_size, BusIo_SPI_rxd_notify_func_t cb)
{
int32_t ret = spi_bind(type, rxq_size);
if (ret != 0)
{
return ret;
}
if ((cb != NULL) && ((type == SPI_MSG_CTRL_TRAFFIC_NETWORK_STA) || (type == SPI_MSG_CTRL_TRAFFIC_NETWORK_AP)))
{
ret = spi_rxd_callback_register((spi_msg_ctrl_t)type, cb, NULL);
}
return ret;
}
void BusIo_SPI_Delay(uint32_t Delay)
{
vTaskDelay(pdMS_TO_TICKS(Delay));
}
int32_t BusIo_SPI_SendData(uint8_t type, uint8_t *pBuf, uint16_t length, uint32_t Timeout)
{
struct spi_msg_control ctrl;
struct spi_msg m;
SPI_MSG_CONTROL_INIT(ctrl, SPI_MSG_CTRL_TRAFFIC_TYPE, SPI_MSG_CTRL_TRAFFIC_TYPE_LEN, &type);
SPI_MSG_INIT(m, SPI_MSG_OP_DATA, &ctrl, 0);
m.data = (void *)pBuf;
m.data_len = length;
return spi_write(&m, Timeout);
}
int32_t BusIo_SPI_ReceiveData(uint8_t type, uint8_t *pBuf, uint16_t length, uint32_t Timeout)
{
struct spi_msg_control ctrl;
struct spi_msg m;
SPI_MSG_CONTROL_INIT(ctrl, SPI_MSG_CTRL_TRAFFIC_TYPE, SPI_MSG_CTRL_TRAFFIC_TYPE_LEN, &type);
SPI_MSG_INIT(m, SPI_MSG_OP_DATA, &ctrl, 0);
m.data = pBuf;
m.data_len = length;
return spi_read(&m, Timeout);
}
int32_t BusIo_SPI_ReceivePtr(uint8_t type, void **buffer, uint8_t **data, uint32_t Timeout)
{
struct spi_msg_control ctrl;
struct spi_msg m;
int32_t ret = 0;
struct spi_buffer *spi_buf = NULL;
*buffer = NULL;
*data = NULL;
SPI_MSG_CONTROL_INIT(ctrl, SPI_MSG_CTRL_TRAFFIC_TYPE, SPI_MSG_CTRL_TRAFFIC_TYPE_LEN, &type);
SPI_MSG_INIT(m, SPI_MSG_OP_BUFFER_PTR, &ctrl, 0);
m.buffer_ptr = &spi_buf;
ret = spi_read(&m, Timeout);
if ((ret >= 0) && (spi_buf != NULL))
{
*buffer = (void *)spi_buf;
*data = spi_buf->data;
}
return ret;
}
int32_t BusIo_SPI_Free(void *buffer)
{
if (buffer != NULL)
{
vPortFree(buffer);
}
return 0;
}
@@ -0,0 +1,117 @@
/**
******************************************************************************
* @file w61_io.h
* @author ST67 Application Team
* @brief This file provides the common defines and functions prototypes for
* the ST67W611M IO operations.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef W61_IO_H
#define W61_IO_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <stdint.h>
#include "spi_iface.h" /* Needed for SPI_XFER_MTU_BYTES */
/* Exported types ------------------------------------------------------------*/
/** @brief Callback function prototype called when new data are received */
typedef void (*BusIo_SPI_rxd_notify_func_t)(void *arg);
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/**
* @brief ST67W611M IO Initialization.
* This function initialize the SPI interface to deal with the w61,
* then starts asynchronous listening on the RX port.
* @retval forward spisync_init ret
*/
int32_t BusIo_SPI_Init(void);
/**
* @brief ST67W611M IO Deinitialization.
* This function De-initialize the SPI interface of the ST67W611M module.
* When called the w61 commands can't be executed anymore.
* @retval forward spisync_deinit ret
*/
int32_t BusIo_SPI_DeInit(void);
/**
* @brief ST67W611M IO bind interface.
* This function bind the SPI interface to deal with the w61,
* then starts asynchronous listening on the RX port.
* @param type: Traffic type to bind (must be < SPI_MSG_CTRL_TRAFFIC_TYPE_MAX)
* @param rxq_size: size of the RX queue
* @param cb: callback function to be called when new data are received
* @retval forward spisync_init ret
*/
int32_t BusIo_SPI_Bind(uint8_t type, int32_t rxq_size, BusIo_SPI_rxd_notify_func_t cb);
/**
* @brief Delay
* @param Delay in ticks (often 1 ticks is config to 1 ms)
*/
void BusIo_SPI_Delay(uint32_t Delay);
/**
* @brief Send commands and raw data to the ST67W611M module over the SPI interface.
* This function allows sending bytes to the ST67W611M module, the
* data can be either an AT command or raw data to send over
* a pre-established WiFi connection.
* @param type: Traffic type to use (must be < SPI_MSG_CTRL_TRAFFIC_TYPE_MAX)
* @param pBuf: data to send
* @param length: the data length
* @param Timeout: max time to wait before returning
* @retval forward spisync_deinit ret
*/
int32_t BusIo_SPI_SendData(uint8_t type, uint8_t *pBuf, uint16_t length, uint32_t Timeout);
/**
* @brief Receive data from the ST67W611M module over the SPI interface
* @param type: Traffic type to use (must be < SPI_MSG_CTRL_TRAFFIC_TYPE_MAX)
* @param pBuf: receive buffer
* @param length: max length to be retrieved
* @param Timeout: max time to wait before returning
* @retval size of the buffer actually retrieved (could be smaller the the length param)
*/
int32_t BusIo_SPI_ReceiveData(uint8_t type, uint8_t *pBuf, uint16_t length, uint32_t Timeout);
/**
* @brief Receive pointer of data from the ST67W611M module over the SPI interface
* @param type: Traffic type to use (must be < SPI_MSG_CTRL_TRAFFIC_TYPE_MAX)
* @param buffer: receive spi_buffer
* @param data: receive buffer
* @param Timeout: max time to wait before returning
* @retval size of the buffer actually retrieved (could be smaller the the length param)
*/
int32_t BusIo_SPI_ReceivePtr(uint8_t type, void **buffer, uint8_t **data, uint32_t Timeout);
/**
* @brief Free spi_buffer containing the data
* @param buffer: Pointer to store the spi_buffer
* @return Operation status
*/
int32_t BusIo_SPI_Free(void *buffer);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* W61_IO_H */
@@ -0,0 +1,6 @@
This software component is provided to you as part of a software package and
applicable license terms are in the Package_license file. If you received this
software component outside of a package or without applicable license terms,
the terms of the BSD-3-Clause license shall apply.
You may obtain a copy of the BSD-3-Clause at:
https://opensource.org/licenses/BSD-3-Clause
@@ -0,0 +1,247 @@
/**
******************************************************************************
* @file common_parser.c
* @author ST67 Application Team
* @brief This file provides code for W6x common parser functions
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "common_parser.h"
/* Private macros ------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @addtogroup ST67W6X_Utilities_Common_Functions
* @{
*/
/* Functions Definition ------------------------------------------------------*/
int32_t Parser_StrToHex(char *ptr, uint8_t *cnt)
{
uint32_t sum = 0;
uint8_t i = 0;
if (isxdigit((int32_t)(*ptr)) == 0)
{
return -1;
}
/* Loop on pointer content while it is a hexadecimal character */
while (isxdigit((int32_t)(*ptr)) > 0)
{
sum <<= 4U;
sum += Parser_Hex2Num(*ptr);
ptr++;
i++;
}
/* Save number of characters used for number */
if (cnt != NULL)
{
*cnt = i;
}
/* Return the concatenated number */
return (int32_t)sum;
}
int32_t Parser_StrToInt(char *ptr, uint8_t *cnt, int32_t *value)
{
uint8_t minus = 0U;
uint8_t i = 0;
int32_t sum = 0;
uint8_t len = 0;
if (value == NULL)
{
return 0;
}
len = strlen(ptr);
/* Trim '\r' and '\n' characters */
while (len > i)
{
if ((ptr[i] == '\r') || (ptr[i] == '\n'))
{
len = i;
}
else
{
i++;
}
}
i = 0;
/* Check for minus character */
if (*ptr == '-')
{
minus = 1U;
ptr++;
i++;
}
/* Loop on pointer content while it is a numeric character */
while (isdigit((int32_t)(*ptr)) > 0)
{
sum = (10 * sum) + ((*ptr) - '0');
ptr++;
i++;
}
/* Save number of characters used for number */
if (cnt != NULL)
{
*cnt = i;
}
/* Minus detected */
if (minus == 1U)
{
*value = 0 - sum;
}
else
{
*value = sum;
}
/* Verify the total length of the string equals the number of numeric characters found */
if (len != i)
{
return 0;
}
/* Return the concatenated number */
return 1;
}
void Parser_StrToIP(char *ptr, uint8_t ip[4])
{
uint8_t count_byte = 0;
int32_t tmp_nb = 0;
char *end_ptr = NULL;
while ((*ptr != '\0') && (count_byte < 4U))
{
/* Convert the current segment to an integer */
tmp_nb = strtol(ptr, &end_ptr, 10);
/* Validate the parsed number (must be between 0 and 255) */
if ((tmp_nb < 0) || (tmp_nb > 0xFF) || (end_ptr == ptr))
{
/* If parsing fails or the number is out of range, set IP to 0 and return */
(void)memset(ip, 0, 4);
return;
}
/* Store the parsed number in the IP array */
ip[count_byte++] = (uint8_t)tmp_nb;
/* Move the pointer to the next segment */
ptr = end_ptr;
/* Skip the '.' delimiter if present */
if (*ptr == '.')
{
ptr++;
}
}
/* If exactly 4 bytes are not parsed, the IP is invalid */
if ((count_byte != 4U) || (*ptr != '\0'))
{
(void)memset(ip, 0, 4);
}
}
int32_t Parser_CheckValidAddress(uint8_t *buff, uint32_t len)
{
uint32_t count_full = 0;
uint32_t count_zero = 0;
for (int32_t i = 0; i < len; i++)
{
if (buff[i] == 0xFFU)
{
count_full++; /* Count the number of 255 */
}
if (buff[i] == 0U)
{
count_zero++; /* Count the number of 0 */
}
/* Return invalid address if all bytes contains only 255 or only 0 */
if ((count_full == len) || (count_zero == len))
{
return -1;
}
}
return 0;
}
void Parser_StrToMAC(char *ptr, uint8_t mac[6])
{
uint8_t count_byte = 0;
uint8_t hexcnt;
int32_t mac_string_len = 17; /* Maximum length of a MAC address string */
/* Loop on pointer content while non empty */
while ((*ptr != '\0') && (mac_string_len > 0))
{
hexcnt = 1;
if (*ptr != ':') /* Skip ':' */
{
int32_t hex_value = Parser_StrToHex(ptr, &hexcnt);
if (hex_value < 0)
{
/* If parsing fails, set MAC to 0 and return */
(void)memset(mac, 0, 6);
return;
}
mac[count_byte++] = (uint8_t)hex_value;
}
ptr = ptr + hexcnt;
mac_string_len -= hexcnt; /* Decrement the length of the MAC address string */
}
/* If exactly 6 bytes are not parsed, the MAC Address is invalid */
if ((count_byte != 6U) || (*ptr != '\0'))
{
(void)memset(mac, 0, 6);
}
}
uint8_t Parser_Hex2Num(char a)
{
/* Char is num */
if (((uint8_t)a >= 0x30U) && ((uint8_t)a <= 0x39U))
{
return (uint8_t)a - 0x30U;
}
/* Char is uppercase character A - Z (hex) */
else if (((uint8_t)a >= 0x41U) && ((uint8_t)a <= 0x46U))
{
return (uint8_t)a - 0x41U + 10U;
}
/* Char is lowercase character a - f (hex) */
else if (((uint8_t)a >= 0x61U) && ((uint8_t)a <= 0x66U))
{
return (uint8_t)a - 0x61U + 10U;
}
else
{
return 0U;
}
}
/** @} */