Basic Framework
This commit is contained in:
158
FreeRTOSConfig.h
Normal file
158
FreeRTOSConfig.h
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
/* USER CODE BEGIN Header */
|
||||||
|
/*
|
||||||
|
* FreeRTOS Kernel V10.2.1
|
||||||
|
* Portion Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Portion Copyright (C) 2019 StMicroelectronics, Inc. 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.
|
||||||
|
*
|
||||||
|
* http://www.FreeRTOS.org
|
||||||
|
* http://aws.amazon.com/freertos
|
||||||
|
*
|
||||||
|
* 1 tab == 4 spaces!
|
||||||
|
*/
|
||||||
|
/* USER CODE END Header */
|
||||||
|
|
||||||
|
#ifndef FREERTOS_CONFIG_H
|
||||||
|
#define FREERTOS_CONFIG_H
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------
|
||||||
|
* Application specific definitions.
|
||||||
|
*
|
||||||
|
* These definitions should be adjusted for your particular hardware and
|
||||||
|
* application requirements.
|
||||||
|
*
|
||||||
|
* These parameters and more are described within the 'configuration' section of the
|
||||||
|
* FreeRTOS API documentation available on the FreeRTOS.org web site.
|
||||||
|
*
|
||||||
|
* See http://www.freertos.org/a00110.html
|
||||||
|
*----------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* USER CODE BEGIN Includes */
|
||||||
|
/* Section where include file can be added */
|
||||||
|
/* USER CODE END Includes */
|
||||||
|
|
||||||
|
/* Ensure definitions are only used by the compiler, and not by the assembler. */
|
||||||
|
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
|
||||||
|
#include <stdint.h>
|
||||||
|
extern uint32_t SystemCoreClock;
|
||||||
|
#endif
|
||||||
|
#define configENABLE_FPU 0
|
||||||
|
#define configENABLE_MPU 0
|
||||||
|
|
||||||
|
#define configUSE_PREEMPTION 1
|
||||||
|
#define configSUPPORT_STATIC_ALLOCATION 1
|
||||||
|
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||||
|
#define configUSE_IDLE_HOOK 0
|
||||||
|
#define configUSE_TICK_HOOK 0
|
||||||
|
#define configCPU_CLOCK_HZ ( SystemCoreClock )
|
||||||
|
#define configTICK_RATE_HZ ((TickType_t)1000)
|
||||||
|
#define configMAX_PRIORITIES ( 56 )
|
||||||
|
#define configMINIMAL_STACK_SIZE ((uint16_t)256)
|
||||||
|
#define configTOTAL_HEAP_SIZE ((size_t)15360)
|
||||||
|
#define configMAX_TASK_NAME_LEN ( 16 )
|
||||||
|
#define configUSE_TRACE_FACILITY 1
|
||||||
|
#define configUSE_16_BIT_TICKS 0
|
||||||
|
#define configUSE_MUTEXES 1
|
||||||
|
#define configQUEUE_REGISTRY_SIZE 8
|
||||||
|
#define configUSE_RECURSIVE_MUTEXES 1
|
||||||
|
#define configUSE_COUNTING_SEMAPHORES 1
|
||||||
|
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||||
|
/* USER CODE BEGIN MESSAGE_BUFFER_LENGTH_TYPE */
|
||||||
|
/* Defaults to size_t for backward compatibility, but can be changed
|
||||||
|
if lengths will always be less than the number of bytes in a size_t. */
|
||||||
|
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
|
||||||
|
/* USER CODE END MESSAGE_BUFFER_LENGTH_TYPE */
|
||||||
|
|
||||||
|
/* Co-routine definitions. */
|
||||||
|
#define configUSE_CO_ROUTINES 0
|
||||||
|
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
|
||||||
|
|
||||||
|
/* Software timer definitions. */
|
||||||
|
#define configUSE_TIMERS 1
|
||||||
|
#define configTIMER_TASK_PRIORITY ( 2 )
|
||||||
|
#define configTIMER_QUEUE_LENGTH 10
|
||||||
|
#define configTIMER_TASK_STACK_DEPTH 512
|
||||||
|
|
||||||
|
/* Set the following definitions to 1 to include the API function, or zero
|
||||||
|
to exclude the API function. */
|
||||||
|
#define INCLUDE_vTaskPrioritySet 1
|
||||||
|
#define INCLUDE_uxTaskPriorityGet 1
|
||||||
|
#define INCLUDE_vTaskDelete 1
|
||||||
|
#define INCLUDE_vTaskCleanUpResources 0
|
||||||
|
#define INCLUDE_vTaskSuspend 1
|
||||||
|
#define INCLUDE_vTaskDelayUntil 1
|
||||||
|
#define INCLUDE_vTaskDelay 1
|
||||||
|
#define INCLUDE_xTaskGetSchedulerState 1
|
||||||
|
#define INCLUDE_xTimerPendFunctionCall 1
|
||||||
|
#define INCLUDE_xQueueGetMutexHolder 1
|
||||||
|
#define INCLUDE_uxTaskGetStackHighWaterMark 1
|
||||||
|
#define INCLUDE_eTaskGetState 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used
|
||||||
|
* by the application thus the correct define need to be enabled below
|
||||||
|
*/
|
||||||
|
#define USE_FreeRTOS_HEAP_4
|
||||||
|
|
||||||
|
/* Cortex-M specific definitions. */
|
||||||
|
#ifdef __NVIC_PRIO_BITS
|
||||||
|
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
|
||||||
|
#define configPRIO_BITS __NVIC_PRIO_BITS
|
||||||
|
#else
|
||||||
|
#define configPRIO_BITS 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The lowest interrupt priority that can be used in a call to a "set priority"
|
||||||
|
function. */
|
||||||
|
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
|
||||||
|
|
||||||
|
/* The highest interrupt priority that can be used by any interrupt service
|
||||||
|
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
|
||||||
|
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
|
||||||
|
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
|
||||||
|
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
|
||||||
|
|
||||||
|
/* Interrupt priorities used by the kernel port layer itself. These are generic
|
||||||
|
to all Cortex-M ports, and do not rely on any particular library functions. */
|
||||||
|
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
|
||||||
|
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
|
||||||
|
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
|
||||||
|
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
|
||||||
|
|
||||||
|
/* Normal assert() semantics without relying on the provision of an assert.h
|
||||||
|
header file. */
|
||||||
|
/* USER CODE BEGIN 1 */
|
||||||
|
#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}
|
||||||
|
/* USER CODE END 1 */
|
||||||
|
|
||||||
|
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
|
||||||
|
standard names. */
|
||||||
|
#define vPortSVCHandler SVC_Handler
|
||||||
|
#define xPortPendSVHandler PendSV_Handler
|
||||||
|
|
||||||
|
/* IMPORTANT: This define is commented when used with STM32Cube firmware, when the timebase source is SysTick,
|
||||||
|
to prevent overwriting SysTick_Handler defined within STM32Cube HAL */
|
||||||
|
|
||||||
|
#define xPortSysTickHandler SysTick_Handler
|
||||||
|
|
||||||
|
/* USER CODE BEGIN Defines */
|
||||||
|
/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */
|
||||||
|
/* USER CODE END Defines */
|
||||||
|
|
||||||
|
#endif /* FREERTOS_CONFIG_H */
|
||||||
201
app_tasks.c
Normal file
201
app_tasks.c
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
/* USER CODE BEGIN Header */
|
||||||
|
/**
|
||||||
|
* Begin Comments
|
||||||
|
* @brief Lightweight Modbus RTU slave driver for STM32 + FreeRTOS
|
||||||
|
*
|
||||||
|
* This module implements a simple, real-time friendly Modbus RTU slave
|
||||||
|
* using UART idle-line detection and RS485 GPIO control. It supports
|
||||||
|
* function codes 0x03 and 0x10 and is designed to run as a cooperative
|
||||||
|
* background task in embedded systems using STM32 HAL and FreeRTOS.
|
||||||
|
*
|
||||||
|
* Author: Scott Leonard
|
||||||
|
* License: Unlicense
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* USER CODE END Header */
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
#include "app_tasks.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "cmsis_os.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define RX_FRAME_LENGTH 256
|
||||||
|
#define TX_FRAME_LENGTH 256
|
||||||
|
#define TABLE_SIZE 128
|
||||||
|
#define SLAVE_ID 0x01
|
||||||
|
|
||||||
|
enum {
|
||||||
|
READ_HOLDING_REGISTERS = 0x03,
|
||||||
|
WRITE_HOLDING_REGISTERS = 0x10
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ILLEGAL_FUNCTION 0x01
|
||||||
|
#define ILLEGAL_DATA_ADDRESS 0x02
|
||||||
|
#define ILLEGAL_DATA_VALUE 0x03
|
||||||
|
|
||||||
|
|
||||||
|
extern UART_HandleTypeDef huart2;
|
||||||
|
|
||||||
|
uint8_t request_frame[RX_FRAME_LENGTH];
|
||||||
|
uint8_t response_frame[TX_FRAME_LENGTH];
|
||||||
|
uint16_t modbus_table[TABLE_SIZE] = {0};
|
||||||
|
|
||||||
|
void rs485_dir_tx(void) {
|
||||||
|
HAL_GPIO_WritePin(GPIOF, PF0_DE_NRE_Pin, GPIO_PIN_SET); // HIGH = TX
|
||||||
|
__NOP(); __NOP(); __NOP(); __NOP(); // Delay for direction switch
|
||||||
|
}
|
||||||
|
|
||||||
|
void rs485_dir_rx(void) {
|
||||||
|
HAL_GPIO_WritePin(GPIOF, PF0_DE_NRE_Pin, GPIO_PIN_RESET); // LOW = RX
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_task_Modbus(void)
|
||||||
|
{
|
||||||
|
static uint8_t modbus_initialized = 0;
|
||||||
|
if (!modbus_initialized) {
|
||||||
|
init_modbus_system();
|
||||||
|
HAL_UARTEx_ReceiveToIdle_IT(&huart2, request_frame, RX_FRAME_LENGTH);
|
||||||
|
modbus_initialized = 1;
|
||||||
|
}
|
||||||
|
osDelay(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t calculate_modbus_crc(uint8_t *data, uint16_t length) {
|
||||||
|
uint16_t crc = 0xFFFF;
|
||||||
|
for (uint16_t pos = 0; pos < length; pos++) {
|
||||||
|
crc ^= (uint16_t)data[pos];
|
||||||
|
for (uint8_t i = 8; i != 0; i--) {
|
||||||
|
if ((crc & 0x0001) != 0) {
|
||||||
|
crc >>= 1;
|
||||||
|
crc ^= 0xA001;
|
||||||
|
} else {
|
||||||
|
crc >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_modbus_data(uint8_t *data, int size) {
|
||||||
|
uint16_t crc = calculate_modbus_crc(data, size);
|
||||||
|
data[size] = crc & 0xFF;
|
||||||
|
data[size+1] = (crc>>8) & 0xFF;
|
||||||
|
rs485_dir_tx();
|
||||||
|
HAL_UART_Transmit(&huart2, data, size+2, 100);
|
||||||
|
rs485_dir_rx();
|
||||||
|
}
|
||||||
|
|
||||||
|
void modbus_exception(uint8_t exceptionCode) {
|
||||||
|
response_frame[0] = request_frame[0];
|
||||||
|
response_frame[1] = request_frame[1] | 0x80;
|
||||||
|
response_frame[2] = exceptionCode;
|
||||||
|
send_modbus_data(response_frame, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t table_read(void) {
|
||||||
|
uint16_t startAddr = ((request_frame[2]<<8) | request_frame[3]);
|
||||||
|
uint16_t numRegs = ((request_frame[4]<<8) | request_frame[5]);
|
||||||
|
|
||||||
|
if ((numRegs < 1) || (numRegs > 125)) {
|
||||||
|
modbus_exception(ILLEGAL_DATA_VALUE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t endAddr = startAddr + numRegs - 1;
|
||||||
|
if (endAddr > TABLE_SIZE - 1) {
|
||||||
|
modbus_exception(ILLEGAL_DATA_ADDRESS);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
response_frame[0] = request_frame[0];
|
||||||
|
response_frame[1] = request_frame[1];
|
||||||
|
response_frame[2] = numRegs * 2;
|
||||||
|
int indx = 3;
|
||||||
|
|
||||||
|
for (int i = 0; i < numRegs; i++) {
|
||||||
|
response_frame[indx++] = (modbus_table[startAddr] >> 8) & 0xFF;
|
||||||
|
response_frame[indx++] = modbus_table[startAddr] & 0xFF;
|
||||||
|
startAddr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_modbus_data(response_frame, indx);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t table_write(void) {
|
||||||
|
uint16_t startAddr = ((request_frame[2]<<8) | request_frame[3]);
|
||||||
|
uint16_t numRegs = ((request_frame[4]<<8) | request_frame[5]);
|
||||||
|
uint8_t byteCount = request_frame[6];
|
||||||
|
|
||||||
|
if ((numRegs < 1) || (numRegs > 123)) {
|
||||||
|
modbus_exception(ILLEGAL_DATA_VALUE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byteCount != (numRegs * 2)) {
|
||||||
|
modbus_exception(ILLEGAL_DATA_VALUE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t endAddr = startAddr + numRegs - 1;
|
||||||
|
if (endAddr > TABLE_SIZE - 1) {
|
||||||
|
modbus_exception(ILLEGAL_DATA_ADDRESS);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int indx = 7;
|
||||||
|
for (int i = 0; i < numRegs; i++) {
|
||||||
|
uint8_t high_byte = request_frame[indx++];
|
||||||
|
uint8_t low_byte = request_frame[indx++];
|
||||||
|
modbus_table[startAddr++] = (high_byte << 8) | low_byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
response_frame[0] = request_frame[0];
|
||||||
|
memcpy(&response_frame[1], &request_frame[1], 5);
|
||||||
|
|
||||||
|
|
||||||
|
send_modbus_data(response_frame, 6);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_modbus_message(uint16_t Size) {
|
||||||
|
if (Size < 8) return;
|
||||||
|
if (request_frame[0] != SLAVE_ID) return;
|
||||||
|
|
||||||
|
uint16_t receivedCRC = request_frame[Size-2] | (request_frame[Size-1] << 8);
|
||||||
|
uint16_t calculatedCRC = calculate_modbus_crc(request_frame, Size-2);
|
||||||
|
if (receivedCRC != calculatedCRC) return;
|
||||||
|
|
||||||
|
switch (request_frame[1]) {
|
||||||
|
case READ_HOLDING_REGISTERS:
|
||||||
|
table_read();
|
||||||
|
break;
|
||||||
|
case WRITE_HOLDING_REGISTERS:
|
||||||
|
table_write();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
modbus_exception(ILLEGAL_FUNCTION);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_modbus_system(void) {
|
||||||
|
|
||||||
|
memset(request_frame, 0, sizeof(request_frame));
|
||||||
|
memset(response_frame, 0, sizeof(response_frame));
|
||||||
|
rs485_dir_rx(); // Start in RX mode
|
||||||
|
}
|
||||||
|
|
||||||
|
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
|
||||||
|
{
|
||||||
|
if (huart->Instance == USART2) {
|
||||||
|
__HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_PEF | UART_CLEAR_FEF | UART_CLEAR_NEF | UART_CLEAR_OREF);
|
||||||
|
HAL_UARTEx_ReceiveToIdle_IT(&huart2, request_frame, RX_FRAME_LENGTH);
|
||||||
|
}
|
||||||
|
}
|
||||||
48
app_tasks.h
Normal file
48
app_tasks.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/* USER CODE BEGIN Header */
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @file : app_tasks.h
|
||||||
|
* @brief : Header for ModTOS (Modbus RTU slave task).
|
||||||
|
*
|
||||||
|
* Declares core symbols for the Modbus driver running in FreeRTOS context.
|
||||||
|
* Author: Scott Leonard
|
||||||
|
* License: Unlicense
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
/* USER CODE END Header */
|
||||||
|
|
||||||
|
#ifndef __APP_TASKS_H
|
||||||
|
#define __APP_TASKS_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
#include "cmsis_os.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Shared buffers and register table */
|
||||||
|
extern uint8_t request_frame[];
|
||||||
|
extern uint8_t response_frame[];
|
||||||
|
extern uint16_t modbus_table[];
|
||||||
|
|
||||||
|
/* Task entry point */
|
||||||
|
void app_task_Modbus(void);
|
||||||
|
|
||||||
|
/* Core Modbus driver functions */
|
||||||
|
void rs485_dir_tx(void);
|
||||||
|
void rs485_dir_rx(void);
|
||||||
|
uint16_t calculate_modbus_crc(uint8_t *data, uint16_t length);
|
||||||
|
void send_modbus_data(uint8_t *data, int size);
|
||||||
|
void modbus_exception(uint8_t exception_code);
|
||||||
|
uint8_t table_read(void);
|
||||||
|
uint8_t table_write(void);
|
||||||
|
void process_modbus_message(uint16_t size);
|
||||||
|
void init_modbus_system(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __APP_TASKS_H */
|
||||||
59
freertos.c
Normal file
59
freertos.c
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/* USER CODE BEGIN Header */
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* File Name : freertos.c
|
||||||
|
* Description : Code for freertos applications
|
||||||
|
******************************************************************************
|
||||||
|
* @attention
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 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.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
/* USER CODE END Header */
|
||||||
|
|
||||||
|
/* Includes ------------------------------------------------------------------*/
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
/* Private includes ----------------------------------------------------------*/
|
||||||
|
/* USER CODE BEGIN Includes */
|
||||||
|
|
||||||
|
/* USER CODE END Includes */
|
||||||
|
|
||||||
|
/* Private typedef -----------------------------------------------------------*/
|
||||||
|
/* USER CODE BEGIN PTD */
|
||||||
|
|
||||||
|
/* USER CODE END PTD */
|
||||||
|
|
||||||
|
/* Private define ------------------------------------------------------------*/
|
||||||
|
/* USER CODE BEGIN PD */
|
||||||
|
|
||||||
|
/* USER CODE END PD */
|
||||||
|
|
||||||
|
/* Private macro -------------------------------------------------------------*/
|
||||||
|
/* USER CODE BEGIN PM */
|
||||||
|
|
||||||
|
/* USER CODE END PM */
|
||||||
|
|
||||||
|
/* Private variables ---------------------------------------------------------*/
|
||||||
|
/* USER CODE BEGIN Variables */
|
||||||
|
|
||||||
|
/* USER CODE END Variables */
|
||||||
|
|
||||||
|
/* Private function prototypes -----------------------------------------------*/
|
||||||
|
/* USER CODE BEGIN FunctionPrototypes */
|
||||||
|
|
||||||
|
/* USER CODE END FunctionPrototypes */
|
||||||
|
|
||||||
|
/* Private application code --------------------------------------------------*/
|
||||||
|
/* USER CODE BEGIN Application */
|
||||||
|
|
||||||
|
/* USER CODE END Application */
|
||||||
|
|
||||||
Reference in New Issue
Block a user