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:
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(¤t_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;
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
FatFs License
|
||||
|
||||
FatFs has being developped as a personal project of the author, ChaN. It is free from the code anyone else wrote at current release. Following code block shows a copy of the FatFs license document that heading the source files.
|
||||
|
||||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT Filesystem Module Rx.xx /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 20xx, ChaN, all right reserved.
|
||||
/
|
||||
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||
/ source and binary forms, with or without modification, are permitted provided
|
||||
/ that the following condition is met:
|
||||
/
|
||||
/ 1. Redistributions of source code must retain the above copyright notice,
|
||||
/ this condition and the following disclaimer.
|
||||
/
|
||||
/ This software is provided by the copyright holder and contributors "AS IS"
|
||||
/ and any warranties related to this software are DISCLAIMED.
|
||||
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
||||
/ by use of this software.
|
||||
/----------------------------------------------------------------------------*/
|
||||
|
||||
Therefore FatFs license is one of the BSD-style licenses but there is a significant feature. FatFs is mainly intended for embedded systems. In order to extend the usability for commercial products, the redistributions of FatFs in binary form, such as embedded code, binary library and any forms without source code, does not need to include about FatFs in the documentations. This is equivalent to the 1-clause BSD license. Of course FatFs is compatible with the most of open source software licenses including GNU GPL. When you redistribute the FatFs source code with any changes or create a fork, the license can also be changed to GNU GPL, BSD-style license or any open source software license that not conflict with FatFs license.
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2023 */
|
||||
/* */
|
||||
/* Portions COPYRIGHT 2017-2023 STMicroelectronics */
|
||||
/* Portions Copyright (C) 2013, ChaN, all right reserved */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* If a working storage control module is available, it should be */
|
||||
/* attached to the FatFs via a glue function rather than modifying it. */
|
||||
/* This is an example of glue functions to attach various existing */
|
||||
/* storage control modules to the FatFs module with a defined API. */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "diskio.h"
|
||||
#include "ff_gen_drv.h"
|
||||
|
||||
#if defined ( __GNUC__ )
|
||||
#ifndef __weak
|
||||
#define __weak __attribute__((weak))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
extern Disk_drvTypeDef disk;
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Gets Disk Status
|
||||
* @param pdrv: Physical drive number (0..)
|
||||
* @retval DSTATUS: Operation status
|
||||
*/
|
||||
DSTATUS disk_status (
|
||||
BYTE pdrv /* Physical drive number to identify the drive */
|
||||
)
|
||||
{
|
||||
DSTATUS stat;
|
||||
|
||||
stat = disk.drv[pdrv]->disk_status(disk.lun[pdrv]);
|
||||
return stat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes a Drive
|
||||
* @param pdrv: Physical drive number (0..)
|
||||
* @retval DSTATUS: Operation status
|
||||
*/
|
||||
DSTATUS disk_initialize (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
DSTATUS stat = RES_OK;
|
||||
|
||||
if(disk.is_initialized[pdrv] == 0)
|
||||
{
|
||||
stat = disk.drv[pdrv]->disk_initialize(disk.lun[pdrv]);
|
||||
if(stat == RES_OK)
|
||||
{
|
||||
disk.is_initialized[pdrv] = 1;
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads Sector(s)
|
||||
* @param pdrv: Physical drive number (0..)
|
||||
* @param *buff: Data buffer to store read data
|
||||
* @param sector: Sector address (LBA)
|
||||
* @param count: Number of sectors to read (1..128)
|
||||
* @retval DRESULT: Operation result
|
||||
*/
|
||||
DRESULT disk_read (
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
BYTE *buff, /* Data buffer to store read data */
|
||||
LBA_t sector, /* Sector address in LBA */
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
|
||||
{
|
||||
DRESULT res;
|
||||
|
||||
res = disk.drv[pdrv]->disk_read(disk.lun[pdrv], buff, sector, count);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes Sector(s)
|
||||
* @param pdrv: Physical drive number (0..)
|
||||
* @param *buff: Data to be written
|
||||
* @param sector: Sector address (LBA)
|
||||
* @param count: Number of sectors to write (1..128)
|
||||
* @retval DRESULT: Operation result
|
||||
*/
|
||||
|
||||
DRESULT disk_write (
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
const BYTE *buff, /* Data to be written */
|
||||
LBA_t sector, /* Sector address in LBA */
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
DRESULT res;
|
||||
|
||||
res = disk.drv[pdrv]->disk_write(disk.lun[pdrv], buff, sector, count);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief I/O control operation
|
||||
* @param pdrv: Physical drive number (0..)
|
||||
* @param cmd: Control code
|
||||
* @param *buff: Buffer to send/receive control data
|
||||
* @retval DRESULT: Operation result
|
||||
*/
|
||||
|
||||
DRESULT disk_ioctl (
|
||||
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||
BYTE cmd, /* Control code */
|
||||
void *buff /* Buffer to send/receive control data */
|
||||
)
|
||||
{
|
||||
DRESULT res;
|
||||
|
||||
res = disk.drv[pdrv]->disk_ioctl(disk.lun[pdrv], cmd, buff);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets Time from RTC
|
||||
* @param None
|
||||
* @retval Time in DWORD
|
||||
*/
|
||||
__weak DWORD get_fattime (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*-----------------------------------------------------------------------/
|
||||
/ Low level disk interface modlue include file (C)ChaN, 2019 /
|
||||
/-----------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _DISKIO_DEFINED
|
||||
#define _DISKIO_DEFINED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ff.h"
|
||||
|
||||
/* Status of Disk Functions */
|
||||
typedef BYTE DSTATUS;
|
||||
|
||||
/* Results of Disk Functions */
|
||||
typedef enum {
|
||||
RES_OK = 0, /* 0: Successful */
|
||||
RES_ERROR, /* 1: R/W Error */
|
||||
RES_WRPRT, /* 2: Write Protected */
|
||||
RES_NOTRDY, /* 3: Not Ready */
|
||||
RES_PARERR /* 4: Invalid Parameter */
|
||||
} DRESULT;
|
||||
|
||||
|
||||
/*---------------------------------------*/
|
||||
/* Prototypes for disk control functions */
|
||||
|
||||
|
||||
DSTATUS disk_initialize (BYTE pdrv);
|
||||
DSTATUS disk_status (BYTE pdrv);
|
||||
DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count);
|
||||
DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count);
|
||||
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
||||
|
||||
|
||||
/* Disk Status Bits (DSTATUS) */
|
||||
|
||||
#define STA_NOINIT 0x01 /* Drive not initialized */
|
||||
#define STA_NODISK 0x02 /* No medium in the drive */
|
||||
#define STA_PROTECT 0x04 /* Write protected */
|
||||
|
||||
|
||||
/* Command code for disk_ioctrl fucntion */
|
||||
|
||||
/* Generic command (Used by FatFs) */
|
||||
#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
|
||||
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
|
||||
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
|
||||
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
|
||||
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
|
||||
|
||||
/* Generic command (Not used by FatFs) */
|
||||
#define CTRL_POWER 5 /* Get/Set power status */
|
||||
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
|
||||
#define CTRL_EJECT 7 /* Eject media */
|
||||
#define CTRL_FORMAT 8 /* Create physical format on the media */
|
||||
|
||||
/* MMC/SDC specific ioctl command */
|
||||
#define MMC_GET_TYPE 10 /* Get card type */
|
||||
#define MMC_GET_CSD 11 /* Get CSD */
|
||||
#define MMC_GET_CID 12 /* Get CID */
|
||||
#define MMC_GET_OCR 13 /* Get OCR */
|
||||
#define MMC_GET_SDSTAT 14 /* Get SD status */
|
||||
#define ISDIO_READ 55 /* Read data form SD iSDIO register */
|
||||
#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */
|
||||
#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */
|
||||
|
||||
/* ATA/CF specific ioctl command */
|
||||
#define ATA_GET_REV 20 /* Get F/W revision */
|
||||
#define ATA_GET_MODEL 21 /* Get model name */
|
||||
#define ATA_GET_SN 22 /* Get serial number */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,416 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file sd_diskio_dma_rtos.c
|
||||
* @author MCD Application Team
|
||||
* @brief SD Disk I/O DMA with RTOS driver
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2023 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the st_license.txt
|
||||
* file in the root directory of this software component.
|
||||
* If no st_license.txt file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "sd_diskio_dma_rtos.h"
|
||||
#include <string.h>
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
#define QUEUE_SIZE (uint32_t) 10
|
||||
#define READ_CPLT_MSG (uint32_t) 1
|
||||
#define WRITE_CPLT_MSG (uint32_t) 2
|
||||
#define RW_ABORT_MSG (uint32_t) 3
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
#ifndef BLOCKSIZE
|
||||
#define BLOCKSIZE 512
|
||||
#endif
|
||||
|
||||
#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
|
||||
static uint8_t scratch[BLOCKSIZE]__attribute__ ((aligned (32))); // 32-Byte aligned for cache maintenance
|
||||
#else
|
||||
__ALIGN_BEGIN static uint8_t scratch[BLOCKSIZE] __ALIGN_END;
|
||||
#endif
|
||||
|
||||
/* Disk status */
|
||||
static volatile DSTATUS Stat = STA_NOINIT;
|
||||
static osMessageQueueId_t SDQueueID = NULL;
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
static int SD_check_status_with_timeout (uint32_t);
|
||||
static DSTATUS SD_check_status (BYTE);
|
||||
static DSTATUS SD_DMA_initialize (BYTE);
|
||||
static DSTATUS SD_DMA_status (BYTE);
|
||||
static DRESULT SD_DMA_read (BYTE, BYTE*, LBA_t, UINT);
|
||||
static DRESULT SD_DMA_write (BYTE, const BYTE*, LBA_t, UINT);
|
||||
static DRESULT SD_DMA_ioctl (BYTE, BYTE, void*);
|
||||
|
||||
const Diskio_drvTypeDef SD_DMA_Driver =
|
||||
{
|
||||
SD_DMA_initialize,
|
||||
SD_DMA_status,
|
||||
SD_DMA_read,
|
||||
SD_DMA_write,
|
||||
SD_DMA_ioctl
|
||||
};
|
||||
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Check the status of the sd card
|
||||
* @param lun : not used
|
||||
* @retval DSTATUS: return 0 if the sd card is ready and -1 otherwise
|
||||
*/
|
||||
static int SD_check_status_with_timeout(uint32_t timeout)
|
||||
{
|
||||
uint32_t timer;
|
||||
|
||||
timer = osKernelGetTickCount();
|
||||
/* block until SDIO IP is ready or a timeout occur */
|
||||
while(osKernelGetTickCount() - timer < timeout)
|
||||
{
|
||||
if (HAL_SD_GetCardState(&sdmmc_handle) == HAL_SD_CARD_TRANSFER)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check the status of the sd card
|
||||
* @param lun : not used
|
||||
* @retval DSTATUS: return 0 if the sd card is ready and 1 otherwise
|
||||
*/
|
||||
static DSTATUS SD_check_status(BYTE lun)
|
||||
{
|
||||
Stat = STA_NOINIT;
|
||||
|
||||
if (HAL_SD_GetCardState(&sdmmc_handle) == HAL_SD_CARD_TRANSFER)
|
||||
{
|
||||
Stat &= ~STA_NOINIT;
|
||||
}
|
||||
|
||||
return Stat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the SD Diskio lowlevel driver
|
||||
* @param lun : not used
|
||||
* @retval DSTATUS: return 0 on Success STA_NOINIT otherwise
|
||||
*/
|
||||
static DSTATUS SD_DMA_initialize(BYTE lun)
|
||||
{
|
||||
Stat = STA_NOINIT;
|
||||
|
||||
if(osKernelGetState() == osKernelRunning)
|
||||
{
|
||||
#if (ENABLE_SD_INIT == 1)
|
||||
|
||||
sdmmc_sd_init();
|
||||
#endif
|
||||
|
||||
Stat = SD_check_status(lun);
|
||||
|
||||
/*
|
||||
* if the SD is correctly initialized, create the operation queue
|
||||
*/
|
||||
|
||||
if (Stat != STA_NOINIT)
|
||||
{
|
||||
if (SDQueueID == NULL)
|
||||
{
|
||||
SDQueueID = osMessageQueueNew(QUEUE_SIZE, 2, NULL);
|
||||
}
|
||||
|
||||
if (SDQueueID == NULL)
|
||||
{
|
||||
Stat |= STA_NOINIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Stat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the Disk Status
|
||||
* @param lun : not used
|
||||
* @retval DSTATUS: return 0 if the sd card is ready and 1 otherwise status
|
||||
*/
|
||||
static DSTATUS SD_DMA_status(BYTE lun)
|
||||
{
|
||||
return SD_check_status(lun);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read data from sd card into a buffer
|
||||
* @param lun : not used
|
||||
* @param *buff: Data buffer to store read data
|
||||
* @param sector: Sector address (LBA)
|
||||
* @param count: Number of sectors to read (1..128)
|
||||
* @retval DRESULT: return RES_OK otherwise
|
||||
*/
|
||||
static DRESULT SD_DMA_read(BYTE lun, BYTE *buff, LBA_t sector, UINT count)
|
||||
{
|
||||
DRESULT res = RES_ERROR;
|
||||
uint32_t timer;
|
||||
uint16_t event;
|
||||
osStatus_t status;
|
||||
uint8_t ret;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* ensure the SDCard is ready for a new operation
|
||||
*/
|
||||
|
||||
if (SD_check_status_with_timeout(SD_TIMEOUT) < 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
/* Check if buffer currently used is aligned on 32 bytes address */
|
||||
if (!((uint32_t)buff & 0x1F))
|
||||
{
|
||||
if(HAL_SD_ReadBlocks_DMA(&sdmmc_handle, (uint8_t*)buff, sector, count) == HAL_OK)
|
||||
{
|
||||
status = osMessageQueueGet(SDQueueID, (void *)&event, NULL, SD_TIMEOUT);
|
||||
if ((status == osOK) && (event == READ_CPLT_MSG))
|
||||
{
|
||||
timer = osKernelGetTickCount();
|
||||
/* block until SDIO IP is ready or a timeout occur */
|
||||
while(osKernelGetTickCount() - timer < SD_TIMEOUT)
|
||||
{
|
||||
if (HAL_SD_GetCardState(&sdmmc_handle) == HAL_SD_CARD_TRANSFER)
|
||||
{
|
||||
res = RES_OK;
|
||||
#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
|
||||
/*
|
||||
the SCB_InvalidateDCache_by_Addr() requires a 32-Byte aligned address,
|
||||
adjust the address and the D-Cache size to invalidate accordingly.
|
||||
*/
|
||||
SCB_InvalidateDCache_by_Addr((uint32_t*)buff, count*BLOCKSIZE);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Slow path, fetch each sector a part and memcpy to destination buffer */
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
ret = HAL_SD_ReadBlocks_DMA(&sdmmc_handle, (uint8_t*)scratch, (uint32_t)sector++, 1);
|
||||
if (ret == HAL_OK)
|
||||
{
|
||||
/* wait until the read is successful or a timeout occurs */
|
||||
status = osMessageQueueGet(SDQueueID, (void *)&event, NULL, SD_TIMEOUT);
|
||||
if ((status == osOK) && (event == READ_CPLT_MSG))
|
||||
{
|
||||
timer = osKernelGetTickCount();
|
||||
/* block until SDIO IP is ready or a timeout occur */
|
||||
while(osKernelGetTickCount() - timer < SD_TIMEOUT)
|
||||
{
|
||||
if ( HAL_SD_GetCardState(&sdmmc_handle) == HAL_SD_CARD_TRANSFER)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
|
||||
/*
|
||||
*
|
||||
* invalidate the scratch buffer before the next read to get the actual data instead of the cached one
|
||||
*/
|
||||
SCB_InvalidateDCache_by_Addr((uint32_t*)scratch, BLOCKSIZE);
|
||||
#endif
|
||||
memcpy(buff, scratch, BLOCKSIZE);
|
||||
buff += BLOCKSIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((i == count) && (ret == HAL_OK))
|
||||
res = RES_OK;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write data from sd card into a buffer
|
||||
* @param lun : not used
|
||||
* @param *buff: Data to be written
|
||||
* @param sector: Sector address (LBA)
|
||||
* @param count: Number of sectors to write (1..128)
|
||||
* @retval DRESULT: return RES_OK otherwise
|
||||
*/
|
||||
static DRESULT SD_DMA_write(BYTE lun, const BYTE *buff, LBA_t sector, UINT count)
|
||||
{
|
||||
DRESULT res = RES_ERROR;
|
||||
uint32_t timer;
|
||||
uint16_t event;
|
||||
osStatus_t status;
|
||||
uint8_t ret;
|
||||
int i;
|
||||
/*
|
||||
* ensure the SDCard is ready for a new operation
|
||||
*/
|
||||
|
||||
if (SD_check_status_with_timeout(SD_TIMEOUT) < 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
/* Check if buffer currently used is aligned on 32 bytes address */
|
||||
if (!((uint32_t)buff & 0x1F))
|
||||
{
|
||||
#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
|
||||
/*
|
||||
the SCB_CleanDCache_by_Addr() requires a 32-Byte aligned address
|
||||
adjust the address and the D-Cache size to clean accordingly.
|
||||
*/
|
||||
SCB_CleanDCache_by_Addr((uint32_t*)buff, count*BLOCKSIZE);
|
||||
#endif
|
||||
|
||||
if(HAL_SD_WriteBlocks_DMA(&sdmmc_handle, (uint8_t*)buff, sector, count) == HAL_OK)
|
||||
{
|
||||
status = osMessageQueueGet(SDQueueID, (void *)&event, NULL, SD_TIMEOUT);
|
||||
if ((status == osOK) && (event == WRITE_CPLT_MSG))
|
||||
{
|
||||
timer = osKernelGetTickCount();
|
||||
/* block until SDIO IP is ready or a timeout occur */
|
||||
while(osKernelGetTickCount() - timer < SD_TIMEOUT)
|
||||
{
|
||||
if (HAL_SD_GetCardState(&sdmmc_handle) == HAL_SD_CARD_TRANSFER)
|
||||
{
|
||||
res = RES_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Slow path, fetch each sector a part and memcpy to destination buffer */
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
memcpy((void *)scratch, buff, BLOCKSIZE);
|
||||
buff += BLOCKSIZE;
|
||||
|
||||
/* Clean the cache to move the scratch buffer content from the CPU cache to the memory to let the SD DMA copy updated data. */
|
||||
SCB_CleanDCache_by_Addr(scratch, BLOCKSIZE);
|
||||
|
||||
ret = HAL_SD_WriteBlocks_DMA(&sdmmc_handle, (uint8_t*)scratch, (uint32_t)sector++, 1);
|
||||
if (ret == HAL_OK )
|
||||
{
|
||||
/* wait until the read is successful or a timeout occurs */
|
||||
status = osMessageQueueGet(SDQueueID, (void *)&event, NULL, SD_TIMEOUT);
|
||||
if ((status == osOK) && (event == WRITE_CPLT_MSG))
|
||||
{
|
||||
timer = osKernelGetTickCount();
|
||||
/* block until SDIO IP is ready or a timeout occur */
|
||||
while(osKernelGetTickCount() - timer < SD_TIMEOUT)
|
||||
{
|
||||
if (HAL_SD_GetCardState(&sdmmc_handle) == HAL_SD_CARD_TRANSFER)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((i == count) && (ret == HAL_OK))
|
||||
res = RES_OK;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I/O control operation
|
||||
* @param lun : not used
|
||||
* @param cmd: Control code
|
||||
* @param *buff: Buffer to send/receive control data
|
||||
* @retval DRESULT: return RES_OK otherwise
|
||||
*/
|
||||
static DRESULT SD_DMA_ioctl(BYTE lun, BYTE cmd, void *buff)
|
||||
{
|
||||
DRESULT res = RES_ERROR;
|
||||
HAL_SD_CardInfoTypeDef CardInfo;
|
||||
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
/* Make sure that no pending write process */
|
||||
case CTRL_SYNC:
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
/* Get number of sectors on the disk (DWORD) */
|
||||
case GET_SECTOR_COUNT:
|
||||
HAL_SD_GetCardInfo(&sdmmc_handle, &CardInfo);
|
||||
*(DWORD*)buff = CardInfo.LogBlockNbr;
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
/* Get R/W sector size (WORD) */
|
||||
case GET_SECTOR_SIZE:
|
||||
HAL_SD_GetCardInfo(&sdmmc_handle, &CardInfo);
|
||||
*(WORD*)buff = CardInfo.LogBlockSize;
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
/* Get erase block size in unit of sector (DWORD) */
|
||||
case GET_BLOCK_SIZE:
|
||||
HAL_SD_GetCardInfo(&sdmmc_handle, &CardInfo);
|
||||
*(DWORD*)buff = CardInfo.LogBlockSize / BLOCKSIZE;
|
||||
res = RES_OK;
|
||||
break;
|
||||
|
||||
default:
|
||||
res = RES_PARERR;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tx Transfer completed callbacks
|
||||
* @param hsd: SD handle
|
||||
* @retval None
|
||||
*/
|
||||
|
||||
void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
|
||||
{
|
||||
/*
|
||||
* No need to add an "osKernelRunning()" check here, as the SD_initialize()
|
||||
* is always called before any SD_Read()/SD_Write() call
|
||||
*/
|
||||
const uint16_t msg = WRITE_CPLT_MSG;
|
||||
osMessageQueuePut(SDQueueID, (const void *)&msg, 0, 0);
|
||||
}
|
||||
|
||||
void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
|
||||
{
|
||||
/*
|
||||
* No need to add an "osKernelRunning()" check here, as the SD_initialize()
|
||||
* is always called before any SD_Read()/SD_Write() call
|
||||
*/
|
||||
const uint16_t msg = READ_CPLT_MSG;
|
||||
osMessageQueuePut(SDQueueID, (const void *)&msg, 0, 0);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file sd_diskio_dma_rtos.h
|
||||
* @author MCD Application Team
|
||||
* @brief Header for sd_diskio_dma_rtos.c module
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2023 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the st_license.txt
|
||||
* file in the root directory of this software component.
|
||||
* If no st_license.txt file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __SD_DISKIO_DMA_RTOS_H
|
||||
#define __SD_DISKIO_DMA_RTOS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
/*
|
||||
* The sd_diskio_config.h is under application project
|
||||
* and contain the config parameters for SD diskio
|
||||
*
|
||||
*/
|
||||
#include "sd_diskio_config.h"
|
||||
#include "cmsis_os2.h"
|
||||
#include "ff_gen_drv.h"
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
extern const Diskio_drvTypeDef SD_DMA_Driver;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SD_DISKIO_DMA_RTOS_H */
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file sd_diskio_config.h
|
||||
* @author MCD Application Team
|
||||
* @brief Template for the sd_diskio_config.h. This file should be copied and
|
||||
under project.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2023 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the st_license.txt
|
||||
* file in the root directory of this software component.
|
||||
* If no st_license.txt file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef SD_DISKIO_CONFIG_H
|
||||
#define SD_DISKIO_CONFIG_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
|
||||
#include "stm32{family}xx_hal.h"
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
|
||||
/* Maximum waiting time to do an operation in the HAL_SD_ReadBlocks() and HAL_SD_WriteBlocks() */
|
||||
#define SD_TIMEOUT 30 * 1000
|
||||
|
||||
/*
|
||||
* Depending on the usecase, the SD card initialization could be done at the
|
||||
* application level, if it is the case define the flag below to enable
|
||||
* the MX_SD_Init().
|
||||
*/
|
||||
#define ENABLE_SD_INIT 0
|
||||
|
||||
/*
|
||||
* when using cacheable memory region, it may be needed to maintain the cache
|
||||
* validity. Enable the define below to activate a cache maintenance at each
|
||||
* read and write operation.
|
||||
* Notice: This is applicable only for cortex M7 based platform.
|
||||
*/
|
||||
|
||||
#define ENABLE_SD_DMA_CACHE_MAINTENANCE 1
|
||||
|
||||
|
||||
extern SD_HandleTypeDef hsd_sdmmc1;
|
||||
|
||||
/* Default handle used in sd_diskio.c file */
|
||||
#define sdmmc_handle hsd_sdmmc1
|
||||
|
||||
/* Default Init function of sdmmc IP used in sd_diskio.c file */
|
||||
#if (ENABLE_SD_INIT == 1)
|
||||
extern void MX_SDMMC1_SD_Init(void);
|
||||
#define sdmmc_sd_init MX_SDMMC1_SD_Init
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SD_DISKIO_CONFIG_H */
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file sram_diskio_config.h
|
||||
* @author MCD Application Team
|
||||
* @brief Template for the sram_diskio_config.h. This file should be copied and
|
||||
under project.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2023 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the st_license.txt
|
||||
* file in the root directory of this software component.
|
||||
* If no st_license.txt file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef SRAM_DISKIO_CONFIG_H
|
||||
#define SRAM_DISKIO_CONFIG_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
|
||||
#include "stm32{family}xx_hal.h"
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Block size */
|
||||
#define BLOCK_SIZE 512
|
||||
|
||||
/* Base Address */
|
||||
#define SRAM_DISK_BASE_ADDR 0x24000000
|
||||
|
||||
/* SRAM Disk size in bytes */
|
||||
#define SRAM_DISK_SIZE (32 * 1024)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SRAM_DISKIO_CONFIG_H */
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file usbh_diskio_config.h
|
||||
* @author MCD Application Team
|
||||
* @brief Template for the usbh_diskio_config.h. This file should be copied and
|
||||
under project.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2023 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the st_license.txt
|
||||
* file in the root directory of this software component.
|
||||
* If no st_license.txt file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef USBH_DISKIO_CONFIG_H
|
||||
#define USBH_DISKIO_CONFIG_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
|
||||
#include "usbh_msc.h"
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Block size */
|
||||
#define USB_BLOCK_SIZE 512
|
||||
|
||||
extern USBH_HandleTypeDef hUsbHost;
|
||||
/* Default handle used in usbh_diskio.c file */
|
||||
#define hUsb_Host hUsbHost
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBH_DISKIO_CONFIG_H */
|
||||
+7086
File diff suppressed because it is too large.
Load diff
+429
@@ -0,0 +1,429 @@
|
||||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT Filesystem module R0.15 /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2022, ChaN, all right reserved.
|
||||
/
|
||||
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||
/ source and binary forms, with or without modification, are permitted provided
|
||||
/ that the following condition is met:
|
||||
|
||||
/ 1. Redistributions of source code must retain the above copyright notice,
|
||||
/ this condition and the following disclaimer.
|
||||
/
|
||||
/ This software is provided by the copyright holder and contributors "AS IS"
|
||||
/ and any warranties related to this software are DISCLAIMED.
|
||||
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
||||
/ by use of this software.
|
||||
/
|
||||
/----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifndef FF_DEFINED
|
||||
#define FF_DEFINED 80286 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ffconf.h" /* FatFs configuration options */
|
||||
|
||||
#if FF_DEFINED != FFCONF_DEF
|
||||
#error Wrong configuration file (ffconf.h).
|
||||
#endif
|
||||
|
||||
|
||||
/* Integer types used for FatFs API */
|
||||
|
||||
#if defined(_WIN32) /* Windows VC++ (for development only) */
|
||||
#define FF_INTDEF 2
|
||||
#include <windows.h>
|
||||
typedef unsigned __int64 QWORD;
|
||||
#include <float.h>
|
||||
#define isnan(v) _isnan(v)
|
||||
#define isinf(v) (!_finite(v))
|
||||
|
||||
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */
|
||||
#define FF_INTDEF 2
|
||||
#include <stdint.h>
|
||||
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
|
||||
typedef unsigned char BYTE; /* char must be 8-bit */
|
||||
typedef uint16_t WORD; /* 16-bit unsigned integer */
|
||||
typedef uint32_t DWORD; /* 32-bit unsigned integer */
|
||||
typedef uint64_t QWORD; /* 64-bit unsigned integer */
|
||||
typedef WORD WCHAR; /* UTF-16 character type */
|
||||
|
||||
#else /* Earlier than C99 */
|
||||
#define FF_INTDEF 1
|
||||
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
|
||||
typedef unsigned char BYTE; /* char must be 8-bit */
|
||||
typedef unsigned short WORD; /* 16-bit unsigned integer */
|
||||
typedef unsigned long DWORD; /* 32-bit unsigned integer */
|
||||
typedef WORD WCHAR; /* UTF-16 character type */
|
||||
#endif
|
||||
|
||||
|
||||
/* Type of file size and LBA variables */
|
||||
|
||||
#if FF_FS_EXFAT
|
||||
#if FF_INTDEF != 2
|
||||
#error exFAT feature wants C99 or later
|
||||
#endif
|
||||
typedef QWORD FSIZE_t;
|
||||
#if FF_LBA64
|
||||
typedef QWORD LBA_t;
|
||||
#else
|
||||
typedef DWORD LBA_t;
|
||||
#endif
|
||||
#else
|
||||
#if FF_LBA64
|
||||
#error exFAT needs to be enabled when enable 64-bit LBA
|
||||
#endif
|
||||
typedef DWORD FSIZE_t;
|
||||
typedef DWORD LBA_t;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Type of path name strings on FatFs API (TCHAR) */
|
||||
|
||||
#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */
|
||||
typedef WCHAR TCHAR;
|
||||
#define _T(x) L ## x
|
||||
#define _TEXT(x) L ## x
|
||||
#elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */
|
||||
typedef char TCHAR;
|
||||
#define _T(x) u8 ## x
|
||||
#define _TEXT(x) u8 ## x
|
||||
#elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */
|
||||
typedef DWORD TCHAR;
|
||||
#define _T(x) U ## x
|
||||
#define _TEXT(x) U ## x
|
||||
#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3)
|
||||
#error Wrong FF_LFN_UNICODE setting
|
||||
#else /* ANSI/OEM code in SBCS/DBCS */
|
||||
typedef char TCHAR;
|
||||
#define _T(x) x
|
||||
#define _TEXT(x) x
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Definitions of volume management */
|
||||
|
||||
#if FF_MULTI_PARTITION /* Multiple partition configuration */
|
||||
typedef struct {
|
||||
BYTE pd; /* Physical drive number */
|
||||
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
|
||||
} PARTITION;
|
||||
extern PARTITION VolToPart[]; /* Volume - Partition mapping table */
|
||||
#endif
|
||||
|
||||
#if FF_STR_VOLUME_ID
|
||||
#ifndef FF_VOLUME_STRS
|
||||
extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Filesystem object structure (FATFS) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fs_type; /* Filesystem type (0:not mounted) */
|
||||
BYTE pdrv; /* Volume hosting physical drive */
|
||||
BYTE ldrv; /* Logical drive number (used only when FF_FS_REENTRANT) */
|
||||
BYTE n_fats; /* Number of FATs (1 or 2) */
|
||||
BYTE wflag; /* win[] status (b0:dirty) */
|
||||
BYTE fsi_flag; /* FSINFO status (b7:disabled, b0:dirty) */
|
||||
WORD id; /* Volume mount ID */
|
||||
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
|
||||
WORD csize; /* Cluster size [sectors] */
|
||||
#if FF_MAX_SS != FF_MIN_SS
|
||||
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
|
||||
#endif
|
||||
#if FF_USE_LFN
|
||||
WCHAR* lfnbuf; /* LFN working buffer */
|
||||
#endif
|
||||
#if FF_FS_EXFAT
|
||||
BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */
|
||||
#endif
|
||||
#if !FF_FS_READONLY
|
||||
DWORD last_clst; /* Last allocated cluster */
|
||||
DWORD free_clst; /* Number of free clusters */
|
||||
#endif
|
||||
#if FF_FS_RPATH
|
||||
DWORD cdir; /* Current directory start cluster (0:root) */
|
||||
#if FF_FS_EXFAT
|
||||
DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
|
||||
DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
|
||||
DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
|
||||
#endif
|
||||
#endif
|
||||
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
|
||||
DWORD fsize; /* Number of sectors per FAT */
|
||||
LBA_t volbase; /* Volume base sector */
|
||||
LBA_t fatbase; /* FAT base sector */
|
||||
LBA_t dirbase; /* Root directory base sector (FAT12/16) or cluster (FAT32/exFAT) */
|
||||
LBA_t database; /* Data base sector */
|
||||
#if FF_FS_EXFAT
|
||||
LBA_t bitbase; /* Allocation bitmap base sector */
|
||||
#endif
|
||||
LBA_t winsect; /* Current sector appearing in the win[] */
|
||||
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
} FATFS;
|
||||
|
||||
|
||||
|
||||
/* Object ID and allocation information (FFOBJID) */
|
||||
|
||||
typedef struct {
|
||||
FATFS* fs; /* Pointer to the hosting volume of this object */
|
||||
WORD id; /* Hosting volume's mount ID */
|
||||
BYTE attr; /* Object attribute */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
|
||||
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
|
||||
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
||||
#if FF_FS_EXFAT
|
||||
DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */
|
||||
DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */
|
||||
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
|
||||
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
|
||||
DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */
|
||||
#endif
|
||||
#if FF_FS_LOCK
|
||||
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
||||
#endif
|
||||
} FFOBJID;
|
||||
|
||||
|
||||
|
||||
/* File object structure (FIL) */
|
||||
|
||||
typedef struct {
|
||||
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
|
||||
BYTE flag; /* File status flags */
|
||||
BYTE err; /* Abort flag (error code) */
|
||||
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
||||
DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */
|
||||
LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */
|
||||
#if !FF_FS_READONLY
|
||||
LBA_t dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
|
||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
|
||||
#endif
|
||||
#if FF_USE_FASTSEEK
|
||||
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||
#endif
|
||||
#if !FF_FS_TINY
|
||||
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
} FIL;
|
||||
|
||||
|
||||
|
||||
/* Directory object structure (DIR) */
|
||||
|
||||
typedef struct {
|
||||
FFOBJID obj; /* Object identifier */
|
||||
DWORD dptr; /* Current read/write offset */
|
||||
DWORD clust; /* Current cluster */
|
||||
LBA_t sect; /* Current sector (0:Read operation has terminated) */
|
||||
BYTE* dir; /* Pointer to the directory item in the win[] */
|
||||
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
|
||||
#if FF_USE_LFN
|
||||
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
|
||||
#endif
|
||||
#if FF_USE_FIND
|
||||
const TCHAR* pat; /* Pointer to the name matching pattern */
|
||||
#endif
|
||||
} DIR;
|
||||
|
||||
|
||||
|
||||
/* File information structure (FILINFO) */
|
||||
|
||||
typedef struct {
|
||||
FSIZE_t fsize; /* File size */
|
||||
WORD fdate; /* Modified date */
|
||||
WORD ftime; /* Modified time */
|
||||
BYTE fattrib; /* File attribute */
|
||||
#if FF_USE_LFN
|
||||
TCHAR altname[FF_SFN_BUF + 1];/* Alternative file name */
|
||||
TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */
|
||||
#else
|
||||
TCHAR fname[12 + 1]; /* File name */
|
||||
#endif
|
||||
} FILINFO;
|
||||
|
||||
|
||||
|
||||
/* Format parameter structure (MKFS_PARM) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fmt; /* Format option (FM_FAT, FM_FAT32, FM_EXFAT and FM_SFD) */
|
||||
BYTE n_fat; /* Number of FATs */
|
||||
UINT align; /* Data area alignment (sector) */
|
||||
UINT n_root; /* Number of root directory entries */
|
||||
DWORD au_size; /* Cluster size (byte) */
|
||||
} MKFS_PARM;
|
||||
|
||||
|
||||
|
||||
/* File function return code (FRESULT) */
|
||||
|
||||
typedef enum {
|
||||
FR_OK = 0, /* (0) Succeeded */
|
||||
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
|
||||
FR_INT_ERR, /* (2) Assertion failed */
|
||||
FR_NOT_READY, /* (3) The physical drive cannot work */
|
||||
FR_NO_FILE, /* (4) Could not find the file */
|
||||
FR_NO_PATH, /* (5) Could not find the path */
|
||||
FR_INVALID_NAME, /* (6) The path name format is invalid */
|
||||
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
|
||||
FR_EXIST, /* (8) Access denied due to prohibited access */
|
||||
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
|
||||
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
|
||||
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
||||
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
||||
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
||||
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
|
||||
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
|
||||
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
||||
} FRESULT;
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* FatFs Module Application Interface */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
||||
FRESULT f_close (FIL* fp); /* Close an open file object */
|
||||
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
|
||||
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
|
||||
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
|
||||
FRESULT f_truncate (FIL* fp); /* Truncate the file */
|
||||
FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
|
||||
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
||||
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
||||
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
||||
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
|
||||
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
|
||||
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
|
||||
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
||||
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
||||
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
||||
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
|
||||
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
|
||||
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
||||
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
||||
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
||||
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
|
||||
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
||||
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||
FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */
|
||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||
FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len); /* Create a FAT volume */
|
||||
FRESULT f_fdisk (BYTE pdrv, const LBA_t ptbl[], void* work); /* Divide a physical drive into some partitions */
|
||||
FRESULT f_setcp (WORD cp); /* Set current code page */
|
||||
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
||||
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
||||
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
||||
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
|
||||
|
||||
/* Some API fucntions are implemented as macro */
|
||||
|
||||
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
|
||||
#define f_error(fp) ((fp)->err)
|
||||
#define f_tell(fp) ((fp)->fptr)
|
||||
#define f_size(fp) ((fp)->obj.objsize)
|
||||
#define f_rewind(fp) f_lseek((fp), 0)
|
||||
#define f_rewinddir(dp) f_readdir((dp), 0)
|
||||
#define f_rmdir(path) f_unlink(path)
|
||||
#define f_unmount(path) f_mount(0, path, 0)
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Additional Functions */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
/* RTC function (provided by user) */
|
||||
#if !FF_FS_READONLY && !FF_FS_NORTC
|
||||
DWORD get_fattime (void); /* Get current time */
|
||||
#endif
|
||||
|
||||
|
||||
/* LFN support functions (defined in ffunicode.c) */
|
||||
|
||||
#if FF_USE_LFN >= 1
|
||||
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
|
||||
WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */
|
||||
DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
|
||||
#endif
|
||||
|
||||
|
||||
/* O/S dependent functions (samples available in ffsystem.c) */
|
||||
|
||||
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
|
||||
void* ff_memalloc (UINT msize); /* Allocate memory block */
|
||||
void ff_memfree (void* mblock); /* Free memory block */
|
||||
#endif
|
||||
#if FF_FS_REENTRANT /* Sync functions */
|
||||
int ff_mutex_create (int vol); /* Create a sync object */
|
||||
void ff_mutex_delete (int vol); /* Delete a sync object */
|
||||
int ff_mutex_take (int vol); /* Lock sync object */
|
||||
void ff_mutex_give (int vol); /* Unlock sync object */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Flags and Offset Address */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
/* File access mode and open method flags (3rd argument of f_open) */
|
||||
#define FA_READ 0x01
|
||||
#define FA_WRITE 0x02
|
||||
#define FA_OPEN_EXISTING 0x00
|
||||
#define FA_CREATE_NEW 0x04
|
||||
#define FA_CREATE_ALWAYS 0x08
|
||||
#define FA_OPEN_ALWAYS 0x10
|
||||
#define FA_OPEN_APPEND 0x30
|
||||
|
||||
/* Fast seek controls (2nd argument of f_lseek) */
|
||||
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
|
||||
|
||||
/* Format options (2nd argument of f_mkfs) */
|
||||
#define FM_FAT 0x01
|
||||
#define FM_FAT32 0x02
|
||||
#define FM_EXFAT 0x04
|
||||
#define FM_ANY 0x07
|
||||
#define FM_SFD 0x08
|
||||
|
||||
/* Filesystem type (FATFS.fs_type) */
|
||||
#define FS_FAT12 1
|
||||
#define FS_FAT16 2
|
||||
#define FS_FAT32 3
|
||||
#define FS_EXFAT 4
|
||||
|
||||
/* File attribute bits for directory entry (FILINFO.fattrib) */
|
||||
#define AM_RDO 0x01 /* Read only */
|
||||
#define AM_HID 0x02 /* Hidden */
|
||||
#define AM_SYS 0x04 /* System */
|
||||
#define AM_DIR 0x10 /* Directory */
|
||||
#define AM_ARC 0x20 /* Archive */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FF_DEFINED */
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file ff_gen_drv.c
|
||||
* @author MCD Application Team
|
||||
* @brief FatFs generic low level driver.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2023 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the st_license.txt
|
||||
* file in the root directory of this software component.
|
||||
* If no st_license.txt file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "ff_gen_drv.h"
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
Disk_drvTypeDef disk = {{0},{0},{0},0};
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Links a compatible diskio driver/lun id and increments the number of active
|
||||
* linked drivers.
|
||||
* @note The number of linked drivers (volumes) is up to 10 due to FatFs limits.
|
||||
* @param drv: pointer to the disk IO Driver structure
|
||||
* @param path: pointer to the logical drive path
|
||||
* @param lun : only used for USB Key Disk to add multi-lun management
|
||||
else the parameter must be equal to 0
|
||||
* @retval Returns 0 in case of success, otherwise 1.
|
||||
*/
|
||||
uint8_t FATFS_LinkDriverEx(const Diskio_drvTypeDef *drv, char *path, uint8_t lun)
|
||||
{
|
||||
uint8_t ret = 1;
|
||||
uint8_t DiskNum = 0;
|
||||
|
||||
if(disk.nbr < FF_VOLUMES)
|
||||
{
|
||||
disk.is_initialized[disk.nbr] = 0;
|
||||
disk.drv[disk.nbr] = drv;
|
||||
disk.lun[disk.nbr] = lun;
|
||||
DiskNum = disk.nbr++;
|
||||
path[0] = DiskNum + '0';
|
||||
path[1] = ':';
|
||||
path[2] = '/';
|
||||
path[3] = 0;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Links a compatible diskio driver and increments the number of active
|
||||
* linked drivers.
|
||||
* @note The number of linked drivers (volumes) is up to 10 due to FatFs limits
|
||||
* @param drv: pointer to the disk IO Driver structure
|
||||
* @param path: pointer to the logical drive path
|
||||
* @retval Returns 0 in case of success, otherwise 1.
|
||||
*/
|
||||
uint8_t FATFS_LinkDriver(const Diskio_drvTypeDef *drv, char *path)
|
||||
{
|
||||
return FATFS_LinkDriverEx(drv, path, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unlinks a diskio driver and decrements the number of active linked
|
||||
* drivers.
|
||||
* @param path: pointer to the logical drive path
|
||||
* @param lun : not used
|
||||
* @retval Returns 0 in case of success, otherwise 1.
|
||||
*/
|
||||
uint8_t FATFS_UnLinkDriverEx(char *path, uint8_t lun)
|
||||
{
|
||||
uint8_t DiskNum = 0;
|
||||
uint8_t ret = 1;
|
||||
|
||||
if(disk.nbr >= 1)
|
||||
{
|
||||
DiskNum = path[0] - '0';
|
||||
if(disk.drv[DiskNum] != 0)
|
||||
{
|
||||
disk.drv[DiskNum] = 0;
|
||||
disk.lun[DiskNum] = 0;
|
||||
disk.nbr--;
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unlinks a diskio driver and decrements the number of active linked
|
||||
* drivers.
|
||||
* @param path: pointer to the logical drive path
|
||||
* @retval Returns 0 in case of success, otherwise 1.
|
||||
*/
|
||||
uint8_t FATFS_UnLinkDriver(char *path)
|
||||
{
|
||||
return FATFS_UnLinkDriverEx(path, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets number of linked drivers to the FatFs module.
|
||||
* @param None
|
||||
* @retval Number of attached drivers.
|
||||
*/
|
||||
uint8_t FATFS_GetAttachedDriversNbr(void)
|
||||
{
|
||||
return disk.nbr;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file ff_gen_drv.h
|
||||
* @author MCD Application Team
|
||||
* @brief Header for ff_gen_drv.c module.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2023 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the st_license.txt
|
||||
* file in the root directory of this software component.
|
||||
* If no st_license.txt file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __FF_GEN_DRV_H
|
||||
#define __FF_GEN_DRV_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "diskio.h"
|
||||
#include "ff.h"
|
||||
#include "stdint.h"
|
||||
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Disk IO Driver structure definition
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
DSTATUS (*disk_initialize) (BYTE); /*!< Initialize Disk Drive*/
|
||||
DSTATUS (*disk_status) (BYTE); /*!< Get Disk Status*/
|
||||
DRESULT (*disk_read) (BYTE, BYTE*, DWORD, UINT); /*!< Read Sector(s)*/
|
||||
DRESULT (*disk_write) (BYTE, const BYTE*, DWORD, UINT); /*!< Write Sector(s)*/
|
||||
DRESULT (*disk_ioctl) (BYTE, BYTE, void*); /*!< I/O control operation*/
|
||||
}Diskio_drvTypeDef;
|
||||
|
||||
/**
|
||||
* @brief Global Disk IO Drivers structure definition
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t is_initialized[FF_VOLUMES];
|
||||
const Diskio_drvTypeDef *drv[FF_VOLUMES];
|
||||
uint8_t lun[FF_VOLUMES];
|
||||
volatile uint8_t nbr;
|
||||
|
||||
}Disk_drvTypeDef;
|
||||
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
uint8_t FATFS_LinkDriver(const Diskio_drvTypeDef *drv, char *path);
|
||||
uint8_t FATFS_UnLinkDriver(char *path);
|
||||
uint8_t FATFS_LinkDriverEx(const Diskio_drvTypeDef *drv, char *path, BYTE lun);
|
||||
uint8_t FATFS_UnLinkDriverEx(char *path, BYTE lun);
|
||||
uint8_t FATFS_GetAttachedDriversNbr(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __FF_GEN_DRV_H */
|
||||
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file ffsystem_cmsis_os.c
|
||||
* @author MCD Application Team
|
||||
* @brief ffsystem cmsis_os functions implementation
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (C) 2018, ChaN, all right reserved
|
||||
* Copyright (c) 2023 STMicroelectronics
|
||||
*
|
||||
* 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 "ff.h"
|
||||
|
||||
#if FF_USE_LFN == 3
|
||||
#include "FreeRTOS.h"
|
||||
#endif
|
||||
|
||||
#if FF_FS_REENTRANT
|
||||
#include "cmsis_os2.h"
|
||||
#endif
|
||||
|
||||
/* Dynamic memory allocation */
|
||||
#if FF_USE_LFN == 3
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Allocate/Free a Memory Block */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
|
||||
UINT msize /* Number of bytes to allocate */
|
||||
)
|
||||
{
|
||||
return (void *) pvPortMalloc((size_t)msize); /* Allocate a new memory block */
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Free a memory block */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void ff_memfree (
|
||||
void* mblock /* Pointer to the memory block to free (no effect if null) */
|
||||
)
|
||||
{
|
||||
vPortFree(mblock); /* Free the memory block */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Mutal exclusion */
|
||||
#if FF_FS_REENTRANT
|
||||
|
||||
/* Definition table of Mutex */
|
||||
static osMutexId_t Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Create a Mutex */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called in f_mount function to create a new mutex
|
||||
/ or semaphore for the volume. When a 0 is returned, the f_mount function
|
||||
/ fails with FR_INT_ERR.
|
||||
*/
|
||||
|
||||
int ff_mutex_create ( /* Returns 1:Function succeeded or 0:Could not create the mutex */
|
||||
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
|
||||
)
|
||||
{
|
||||
int ret;
|
||||
const osMutexAttr_t attr = {
|
||||
"FatFsMutex",
|
||||
osMutexRecursive,
|
||||
NULL,
|
||||
0U
|
||||
};
|
||||
|
||||
Mutex[vol] = osMutexNew(&attr);
|
||||
if (Mutex[vol] != NULL)
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Delete a Mutex */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called in f_mount function to delete a mutex or
|
||||
/ semaphore of the volume created with ff_mutex_create function.
|
||||
*/
|
||||
|
||||
void ff_mutex_delete ( /* Returns 1:Function succeeded or 0:Could not delete due to an error */
|
||||
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
|
||||
)
|
||||
{
|
||||
osMutexDelete(Mutex[vol]);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Request a Grant to Access the Volume */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called on enter file functions to lock the volume.
|
||||
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
|
||||
*/
|
||||
|
||||
int ff_mutex_take ( /* Returns 1:Succeeded or 0:Timeout */
|
||||
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
|
||||
)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if(osMutexAcquire(Mutex[vol], FF_FS_TIMEOUT) == osOK)
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Release a Grant to Access the Volume */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called on leave file functions to unlock the volume.
|
||||
*/
|
||||
|
||||
void ff_mutex_give (
|
||||
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
|
||||
)
|
||||
{
|
||||
osMutexRelease(Mutex[vol]);
|
||||
}
|
||||
#endif
|
||||
+15593
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user