first submission

This commit is contained in:
qiyongshuang
2023-02-01 14:19:13 +08:00
parent d534aad004
commit b79c6ac80d
3711 changed files with 745432 additions and 2 deletions
+93
View File
@@ -0,0 +1,93 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : main.c
* Author : WCH
* Version : V1.0
* Date : 2020/08/06
* Description :
*******************************************************************************/
/******************************************************************************/
/* Header file contains */
#include "CONFIG.h"
#include "HAL.h"
#include "stdlib.h"
#include "lwns_adapter_csma_mac.h"
#include "lwns_adapter_blemesh_mac.h"
#include "lwns_adapter_no_mac.h"
#include "lwns_broadcast_example.h"
#include "lwns_ruc_example.h"
#include "lwns_rucft_example.h"
#include "lwns_unicast_example.h"
#include "lwns_multicast_example.h"
#include "lwns_netflood_example.h"
#include "lwns_uninetflood_example.h"
#include "lwns_multinetflood_example.h"
#include "lwns_mesh_example.h"
//The switch printed by each file separately, and 0 can prohibit the internal printing of this file.
#define DEBUG_PRINT_IN_THIS_FILE 1
#if DEBUG_PRINT_IN_THIS_FILE
#define PRINTF(...) PRINT(__VA_ARGS__)
#else
#define PRINTF(...) do {} while (0)
#endif
/*********************************************************************
* GLOBAL TYPEDEFS
*/
__attribute__((aligned(4))) u32 MEM_BUF[BLE_MEMHEAP_SIZE/4];
#if (defined (BLE_MAC)) && (BLE_MAC == TRUE)
uint8_t const MacAddr[6] = {0x84,0xC2,0xE4,0x03,0x02,0x02};
#endif
/*********************************************************************
* @fn Main_Circulation
*
* @brief Main loop
*
* @return none
*/
__attribute__((section(".highcode")))
__attribute__((noinline))
void Main_Circulation(void)
{
while(1)
{
TMOS_SystemProcess();
}
}
/*********************************************************************
* @fn main
*
* @brief Main function
*
* @return none
*/
int main(void)
{
Delay_Init();
#ifdef DEBUG
USART_Printf_Init( 115200 );
#endif
PRINT("%s\n", VER_LIB);
WCHBLE_Init();
HAL_Init( );
RF_RoleInit( );
RF_Init( );
lwns_init();//初始lwns协议栈
//lwns_broadcast_process_init();//广播
//lwns_multicast_process_init();//组播
//lwns_unicast_process_init();//单播
//lwns_ruc_process_init();//可靠单播
//lwns_rucft_process_init();//可靠单播文件传输
lwns_netflood_process_init();//网络泛洪
//lwns_uninetflood_process_init();//单播网络泛洪
//lwns_multinetflood_process_init();//组播网络泛洪
//lwns_mesh_process_init();//mesh组网
Main_Circulation();
}
/******************************** endfile @ main ******************************/
+74
View File
@@ -0,0 +1,74 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ch32v20x_it.c
* Author : WCH
* Version : V1.0.0
* Date : 2022/06/16
* Description : Main Interrupt Service Routines.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
/*********************************************************************
* INCLUDES
*/
#include "ch32v20x_it.h"
#include "CONFIG.h"
/*********************************************************************
* LOCAL FUNCTIONS
*/
void NMI_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void HardFault_Handler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void BB_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void LLE_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
/*********************************************************************
* @fn NMI_Handler
*
* @brief This function handles NMI exception.
*
* @return None
*/
void NMI_Handler(void)
{
}
/*********************************************************************
* @fn HardFault_Handler
*
* @brief This function handles Hard Fault exception.
*
* @return None
*/
void HardFault_Handler(void)
{
while(1)
{
}
}
/*********************************************************************
* @fn BB_IRQHandler
*
* @brief BB Interrupt for BLE.
*
* @return None
*/
void BB_IRQHandler(void)
{
BB_IRQLibHandler();
}
/*********************************************************************
* @fn LLE_IRQHandler
*
* @brief LLE Interrupt for BLE.
*
* @return None
*/
void LLE_IRQHandler(void)
{
LLE_IRQLibHandler();
}
@@ -0,0 +1,37 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ch32v20x_conf.h
* Author : WCH
* Version : V1.0.0
* Date : 2022/06/16
* Description : Library configuration file.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH32V20x_CONF_H
#define __CH32V20x_CONF_H
#include "ch32v20x_adc.h"
#include "ch32v20x_bkp.h"
#include "ch32v20x_can.h"
#include "ch32v20x_crc.h"
#include "ch32v20x_dbgmcu.h"
#include "ch32v20x_dma.h"
#include "ch32v20x_exti.h"
#include "ch32v20x_flash.h"
#include "ch32v20x_gpio.h"
#include "ch32v20x_i2c.h"
#include "ch32v20x_iwdg.h"
#include "ch32v20x_pwr.h"
#include "ch32v20x_rcc.h"
#include "ch32v20x_rtc.h"
#include "ch32v20x_spi.h"
#include "ch32v20x_tim.h"
#include "ch32v20x_usart.h"
#include "ch32v20x_wwdg.h"
#include "ch32v20x_it.h"
#include "ch32v20x_misc.h"
#endif /* __CH32V20x_CONF_H */
@@ -0,0 +1,18 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ch32v20x_it.h
* Author : WCH
* Version : V1.0.0
* Date : 2022/06/16
* Description : This file contains the headers of the interrupt handlers.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH32V20x_IT_H
#define __CH32V20x_IT_H
#include "debug.h"
#endif /* __CH32V20x_IT_H */
@@ -0,0 +1,72 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_adapter_blemesh_mac.h
* Author : WCH
* Version : V1.0
* Date : 2021/06/20
* Description : lwns适配器,模拟ble sig mesh的mac协议
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef _LWNS_ADAPTER_BLEMESH_MAC_H_
#define _LWNS_ADAPTER_BLEMESH_MAC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "lwns_config.h"
#define LWNS_USE_BLEMESH_MAC 1 //是否使能模仿blemesh的mac协议,注意只能使能一个mac层协议。
#if LWNS_USE_BLEMESH_MAC
struct blemesh_mac_phy_manage_struct
{
struct blemesh_mac_phy_manage_struct *next;
uint8_t *data;
}; //模仿blemesh mac层发送管理结构体
#define LWNS_MAC_TRANSMIT_TIMES 2 //一次发送,调用硬件发送几次
#define LWNS_MAC_PERIOD_MS 10 //mac接收周期,轮流切换
#define LWNS_MAC_SEND_DELAY_MAX_MS 10 //蓝牙mesh就是10ms以内的随机数。
#define LWNS_MAC_SEND_PACKET_MAX_NUM 8 //发送链表最多支持几个数据包等待发送
#define BLE_PHY_ONE_PACKET_MAX_625US 5 //ble mac发送一个包最大可能需要的周期
#define LLE_MODE_ORIGINAL_RX (0x80) //如果配置LLEMODE时加上此宏,则接收第一字节为原始数据(原来为RSSI)
#define LWNS_HTIMER_PERIOD_MS 20 //为(1000/HTIMER_SECOND_NUM)
//RF_TX和RF_RX所用的类型,可以修改,不推荐改
#define USER_RF_RX_TX_TYPE 0xff
#define LWNS_PHY_OUTPUT_TIMEOUT_MS 5
//receive process evt
#define LWNS_PHY_RX_OPEN_EVT 1
#define LWNS_PHY_RX_CHANGE_CHANNEL_EVT 2
//send process evt
#define LWNS_HTIMER_PERIOD_EVT 1
#define LWNS_PHY_OUTPUT_PREPARE_EVT 2
#define LWNS_PHY_OUTPUT_FINISH_EVT 4
extern void RF_Init(void);
extern void lwns_init(void);
extern void lwns_shut(void);
extern void lwns_start(void);
#ifdef __cplusplus
}
#endif
#endif /* LWNS_USE_BLEMESH_MAC */
#endif /* _LWNS_ADAPTER_BLEMESH_MAC_H_ */
@@ -0,0 +1,78 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_adapter_csma_mac.h
* Author : WCH
* Version : V1.0
* Date : 2021/06/20
* Description : lwns适配器,模拟csma的mac协议
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef _LWNS_ADAPTER_CSMA_MAC_H_
#define _LWNS_ADAPTER_CSMA_MAC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "lwns_config.h"
#define LWNS_USE_CSMA_MAC 0 //是否使能模仿csma的mac协议,注意只能使能一个mac层协议。
#if LWNS_USE_CSMA_MAC
struct csma_mac_phy_manage_struct
{
struct csma_mac_phy_manage_struct *next;
uint8_t *data;
}; //模拟csma mac层发送管理结构体
typedef enum
{
BLE_PHY_MANAGE_STATE_FREE = 0,
BLE_PHY_MANAGE_STATE_RECEIVED,
BLE_PHY_MANAGE_STATE_WAIT_SEND,
BLE_PHY_MANAGE_STATE_SENDING,
} BLE_PHY_MANAGE_STATE_t;
#define LWNS_MAC_TRANSMIT_TIMES 2 //一次发送,调用硬件发送几次
#define LWNS_MAC_PERIOD_MS 20 //mac发送接收检测周期,如果有需要发送的数据包,则开始随机延迟检测冲突。//为(1000/HTIMER_SECOND_NUM)
#define LWNS_MAC_SEND_DELAY_MAX_625US LWNS_NEIGHBOR_MAX_NUM //随机延迟,该值越小,越容易出现错误,推荐大一些,8测试概率还可以。
#define BLE_PHY_ONE_PACKET_MAX_625US 5
#define LWNS_MAC_SEND_PACKET_MAX_NUM 8 //发送链表最多支持几个数据包等待发送
#define LWNS_MAC_SEND_DELAY_MAX_TIMES LWNS_NEIGHBOR_MAX_NUM / 2 //在发送被取消,延迟几次后,不再随机等待,立刻发送
#define LLE_MODE_ORIGINAL_RX (0x80) //如果配置LLEMODE时加上此宏,则接收第一字节为原始数据(原来为RSSI)
//RF_TX和RF_RX所用的类型,可以修改,不推荐改
#define USER_RF_RX_TX_TYPE 0xff
#define LWNS_PHY_OUTPUT_TIMEOUT_MS 5
//receive process evt
#define LWNS_PHY_RX_OPEN_EVT 1
//send process evt
#define LWNS_PHY_PERIOD_EVT 1
#define LWNS_PHY_OUTPUT_EVT 2
#define LWNS_PHY_OUTPUT_FINISH_EVT 4
extern void RF_Init(void);
extern void lwns_init(void);
extern void lwns_shut(void);
extern void lwns_start(void);
#endif /* LWNS_USE_CSMA_MAC */
#ifdef __cplusplus
}
#endif
#endif /* _LWNS_ADAPTER_CSMA_MAC_H_ */
@@ -0,0 +1,60 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_adapter_no_mac.h
* Author : WCH
* Version : V1.0
* Date : 2021/06/20
* Description : lwns适配器,不使用mac协议,纯透传
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef _LWNS_ADAPTER_NO_MAC_H_
#define _LWNS_ADAPTER_NO_MAC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "lwns_config.h"
#define LWNS_USE_NO_MAC 0 //是否使能纯透传mac协议,适合不存在并发情况的星型网络,即主机问从机答的星型网络。
#if LWNS_USE_NO_MAC
typedef enum
{
BLE_PHY_MANAGE_STATE_FREE = 0,
BLE_PHY_MANAGE_STATE_SENDING,
} BLE_PHY_MANAGE_STATE_t;
#define LLE_MODE_ORIGINAL_RX (0x80) //如果配置LLEMODE时加上此宏,则接收第一字节为原始数据(原来为RSSI)
#define LWNS_HTIMER_PERIOD_MS 20 //为(1000/HTIMER_SECOND_NUM)
//RF_TX和RF_RX所用的类型,可以修改,不推荐改
#define USER_RF_RX_TX_TYPE 0xff
#define LWNS_PHY_OUTPUT_TIMEOUT_MS 5
//receive process evt
#define LWNS_PHY_RX_OPEN_EVT 1
//send process evt
#define LWNS_HTIMER_PERIOD_EVT 1
#define LWNS_PHY_OUTPUT_FINISH_EVT 2
extern void RF_Init(void);
extern void lwns_init(void);
extern void lwns_shut(void);
extern void lwns_start(void);
#endif /* LWNS_USE_NO_MAC */
#ifdef __cplusplus
}
#endif
#endif /* _LWNS_ADAPTER_NO_MAC_H_ */
@@ -0,0 +1,21 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_broadcast_example.h
* Author : WCH
* Version : V1.0
* Date : 2021/06/20
* Description : broadcast£¬¹ã²¥³ÌÐòÀý×Ó
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef _LWNS_BROADCAST_EXAMPLE_H_
#define _LWNS_BROADCAST_EXAMPLE_H_
#include "lwns_config.h"
#define BROADCAST_EXAMPLE_TX_PERIOD_EVT 1 << (0)
void lwns_broadcast_process_init(void);
#endif /* LWNS_BROADCAST_EXAMPLE_H_ */
@@ -0,0 +1,28 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_config.h
* Author : WCH
* Version : V1.0
* Date : 2021/11/17
* Description : lwns配置选项
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef _LWNS_CONFIG_H_
#define _LWNS_CONFIG_H_
#include "config.h"
#include "WCH_LWNS_LIB.h"
#define LWNS_ADDR_USE_BLE_MAC 1 //是否使用蓝牙硬件的mac地址作为默认lwns地址
#define LWNS_ENCRYPT_ENABLE 1 //是否使能加密
#define QBUF_MANUAL_NUM 4 //qbuf缓存数量配置
#define ROUTE_ENTRY_MANUAL_NUM 32 //路由条目数量配置
#define LWNS_NEIGHBOR_MAX_NUM 8 //最大邻居数量
#endif /* _LWNS_CONFIG_H_ */
@@ -0,0 +1,21 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_mesh_example.h
* Author : WCH
* Version : V1.0
* Date : 2021/06/28
* Description : mesh´«Êä³ÌÐòÀý×Ó
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef _LWNS_MESH_EXAMPLE_H_
#define _LWNS_MESH_EXAMPLE_H_
#include "lwns_config.h"
#define MESH_EXAMPLE_TX_PERIOD_EVT 1 << (0)
#define MESH_EXAMPLE_TX_NODE_EVT 1 << (1)
void lwns_mesh_process_init(void);
#endif /* _LWNS_MESH_EXAMPLE_H_ */
@@ -0,0 +1,21 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_multicast_example.h
* Author : WCH
* Version : V1.0
* Date : 2021/06/20
* Description : single-hop multicast£¬×é²¥´«ÊäÀý×Ó
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef _LWNS_MULTICAST_EXAMPLE_H_
#define _LWNS_MULTICAST_EXAMPLE_H_
#include "lwns_config.h"
#define MULTICAST_EXAMPLE_TX_PERIOD_EVT 1 << (0)
void lwns_multicast_process_init(void);
#endif /* _LWNS_MULTICAST_EXAMPLE_H_ */
@@ -0,0 +1,21 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_multinetflood_example.h
* Author : WCH
* Version : V1.0
* Date : 2021/11/10
* Description : multinetflood,组播网络泛洪传输例子
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef _LWNS_MULTINETFLOOD_EXAMPLE_H_
#define _LWNS_MULTINETFLOOD_EXAMPLE_H_
#include "lwns_config.h"
#define MULTINETFLOOD_EXAMPLE_TX_PERIOD_EVT 1 << (0)
void lwns_multinetflood_process_init(void);
#endif /* _LWNS_MULTINETFLOOD_EXAMPLE_H_ */
@@ -0,0 +1,21 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_netflood_example.h
* Author : WCH
* Version : V1.0
* Date : 2021/07/12
* Description : netflood£¬ÍøÂç·ººé´«ÊäÀý×Ó
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef _LWNS_NETFLOOD_EXAMPLE_H_
#define _LWNS_NETFLOOD_EXAMPLE_H_
#include "lwns_config.h"
#define NETFLOOD_EXAMPLE_TX_PERIOD_EVT 1 << (0)
void lwns_netflood_process_init(void);
#endif /* _LWNS_NETFLOOD_EXAMPLE_H_ */
@@ -0,0 +1,21 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_ruc_example.h
* Author : WCH
* Version : V1.0
* Date : 2021/06/30
* Description : reliable unicast£¬¿É¿¿µ¥²¥´«ÊäÀý×Ó
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef _LWNS_RUC_EXAMPLE_H_
#define _LWNS_RUC_EXAMPLE_H_
#include "lwns_config.h"
#define RUC_EXAMPLE_TX_PERIOD_EVT 1 << (0)
void lwns_ruc_process_init(void);
#endif /* _LWNS_RUC_EXAMPLE_H_ */
@@ -0,0 +1,21 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_rucft_example.h
* Author : WCH
* Version : V1.0
* Date : 2021/06/30
* Description : reliable unicast file transfer,可靠单播文件传输例子
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef _LWNS_RUCFT_EXAMPLE_H_
#define _LWNS_RUCFT_EXAMPLE_H_
#include "lwns_config.h"
#define RUCFT_EXAMPLE_TX_PERIOD_EVT 1 << (0)
void lwns_rucft_process_init(void);
#endif /* _LWNS_RUCFT_EXAMPLE_H_ */
+21
View File
@@ -0,0 +1,21 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_sec.h
* Author : WCH
* Version : V1.0
* Date : 2021/09/17
* Description : lwnsÏûÏ¢¼ÓÃÜ
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef _LWNS_SEC_H_
#define _LWNS_SEC_H_
#include "lwns_config.h"
int lwns_msg_encrypt(uint8_t *src, uint8_t *to, uint8_t mlen);
int lwns_msg_decrypt(uint8_t *src, uint8_t *to, uint8_t mlen);
#endif /* _LWNS_SEC_H_ */
@@ -0,0 +1,21 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_unicast_example.h
* Author : WCH
* Version : V1.0
* Date : 2021/06/19
* Description : lwnsµ¥²¥´«ÊäÀý×Ó
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef _LWNS_UNICAST_EXAMPLE_H_
#define _LWNS_UNICAST_EXAMPLE_H_
#include "lwns_config.h"
#define UNICAST_EXAMPLE_TX_PERIOD_EVT 1 << (0)
void lwns_unicast_process_init(void);
#endif /* _LWNS_UNICAST_EXAMPLE_H_ */
@@ -0,0 +1,21 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_uninetflood_example.h
* Author : WCH
* Version : V1.0
* Date : 2021/10/25
* Description : lwns单播网络泛洪传输例子,将数据网络泛洪发送至指定节点
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef _LWNS_UNINETFLOOD_EXAMPLE_H_
#define _LWNS_UNINETFLOOD_EXAMPLE_H_
#include "lwns_config.h"
#define UNINETFLOOD_EXAMPLE_TX_PERIOD_EVT 1 << (0)
void lwns_uninetflood_process_init(void);
#endif /* _LWNS_UNINETFLOOD_EXAMPLE_H_ */
@@ -0,0 +1,31 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : system_ch32v20x.h
* Author : WCH
* Version : V1.0.0
* Date : 2022/06/16
* Description : CH32V20x Device Peripheral Access Layer System Header File.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __SYSTEM_ch32v20x_H
#define __SYSTEM_ch32v20x_H
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t SystemCoreClock; /* System Clock Frequency (Core Clock) */
/* System_Exported_Functions */
extern void SystemInit(void);
extern void SystemCoreClockUpdate(void);
#ifdef __cplusplus
}
#endif
#endif /*__CH32V20x_SYSTEM_H */
@@ -0,0 +1,528 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_adapter_blemesh_mac.c
* Author : WCH
* Version : V1.0
* Date : 2021/06/20
* Description : lwns适配器,模拟ble sig mesh的mac协议
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "lwns_adapter_blemesh_mac.h"
#include "lwns_sec.h"
//每个文件单独debug打印的开关,置0可以禁止本文件内部打印
#define DEBUG_PRINT_IN_THIS_FILE 1
#if DEBUG_PRINT_IN_THIS_FILE
#define PRINTF(...) PRINT(__VA_ARGS__)
#else
#define PRINTF(...) \
do \
{ \
} while(0)
#endif
/*
* 本文件中ble_phy_channelmap为需要发送和接收的通道列表,用户根据自己需求修改为蓝牙通道中的任意三个通道。
* 蓝牙mesh是在37、38、39三个广播通道的广播accessaddress:0x8E89BED6进行周期性发送。正确符合相应规则的accessaddress接入地址约有23亿个
* 本文件采用的发送通道数量和通道号还有accessaddress可以自定,accessaddress切换通道时不变,通道建议3个,不要太多。
*/
#if LWNS_USE_BLEMESH_MAC //是否使能模仿blemesh的mac协议,注意只能使能一个mac层协议。
//for lwns_packet_buffer save
__attribute__((aligned(4))) static lwns_qbuf_list_t qbuf_memp[QBUF_MANUAL_NUM];
//for lwns_route_entry manage
#if ROUTE_ENTRY_MANUAL_NUM
__attribute__((aligned(4))) static lwns_route_entry_data_t route_entry_memp[ROUTE_ENTRY_MANUAL_NUM];
#endif
//for neighbor manage
__attribute__((aligned(4))) static lwns_neighbor_list_t neighbor_memp[LWNS_NEIGHBOR_MAX_NUM];
static void ble_new_neighbor_callback(lwns_addr_t *n); //发现新邻居回调函数
static BOOL ble_phy_output(uint8_t *dataptr, uint8_t len); //发送接口函数
static void RF_2G4StatusCallBack(uint8_t sta, uint8_t crc, uint8_t *rxBuf);
static uint8_t lwns_adapter_taskid;
static uint16_t lwns_adapter_ProcessEvent(uint8_t task_id, uint16_t events);
static uint8_t lwns_phyoutput_taskid;
static uint16_t lwns_phyoutput_ProcessEvent(uint8_t task_id, uint16_t events);
/**
* lwns必用的函数接口,将指针传递给lwns库内部使用
*/
static lwns_fuc_interface_t ble_lwns_fuc_interface = {
.lwns_phy_output = ble_phy_output,
.lwns_rand = tmos_rand,
.lwns_memcpy = tmos_memcpy,
.lwns_memcmp = tmos_memcmp,
.lwns_memset = tmos_memset,
.new_neighbor_callback = ble_new_neighbor_callback,
};
static const uint8_t ble_phy_channelmap[] = {8, 18, 28}; //所需要用到的通道集合,用户自行更换为想要发送的通道集合。
static uint8_t ble_phy_channelmap_send_seq = 0, ble_phy_channelmap_receive_seq = 0, ble_phy_send_cnt = 0; //发送接收当前通道序号和发送次数管理
static struct blemesh_mac_phy_manage_struct *blemesh_phy_manage_list_head = NULL; //mac管理发送LIST列表指针
static struct blemesh_mac_phy_manage_struct blemesh_phy_manage_list[LWNS_MAC_SEND_PACKET_MAX_NUM]; //mac管理发送列表管理数组
/*********************************************************************
* @fn RF_2G4StatusCallBack
*
* @brief RF 状态回调,注意:不可在此函数中直接调用RF接收或者发送API,需要使用事件的方式调用
*
* @param sta - 状态类型
* @param crc - crc校验结果
* @param rxBuf - 数据buf指针
*
* @return None.
*/
static void RF_2G4StatusCallBack(uint8_t sta, uint8_t crc, uint8_t *rxBuf)
{ //rxBuf[0]为信号强度,rxBuf[1]为本次收到数据的长度
switch(sta)
{
case RX_MODE_RX_DATA:
{
if(crc == 1)
{
PRINTF("crc error\n");
}
else if(crc == 2)
{
PRINTF("match type error\n");
}
else
{
uint8_t *pMsg;
#if LWNS_ENCRYPT_ENABLE //是否启用消息加密
if(((rxBuf[1] % 16) == 1) && (rxBuf[1] >= 17) && (rxBuf[1] > rxBuf[2]))
{ //对齐后数据区最少16个字节,加上真实数据长度一字节
//长度校验通过,所以rxBuf[1] - 1必为16的倍数
pMsg = tmos_msg_allocate(rxBuf[1]); //申请内存空间,真实数据长度不需要解密
if(pMsg != NULL)
{
lwns_msg_decrypt(rxBuf + 3, pMsg + 1, rxBuf[1] - 1); //解密数据
if((rxBuf[2] ^ pMsg[rxBuf[2]]) == pMsg[rxBuf[2] + 1])
{
pMsg[0] = rxBuf[2]; //校验通过,存储真实数据长度
PRINTF("send rx msg\n"); //发送接收到的数据到接收进程中
tmos_msg_send(lwns_adapter_taskid, pMsg);
}
else
{
PRINTF("verify rx msg err\n"); //校验失败
tmos_msg_deallocate(pMsg);
}
}
else
{
PRINTF("send rx msg failed\n"); //申请内存失败,无法发送接收到的数据
}
}
else
{
PRINTF("bad len\n"); //包长度不对
}
#else
if(rxBuf[1] >= LWNS_PHY_OUTPUT_MIN_SIZE)
{ //数据长度符合,才会发送至协议栈内部处理
pMsg = tmos_msg_allocate(rxBuf[1] + 1);
if(pMsg != NULL)
{
PRINTF("send rx msg\n"); //发送接收到的数据到接收进程中
tmos_memcpy(pMsg, rxBuf + 1, rxBuf[1] + 1);
tmos_msg_send(lwns_adapter_taskid, pMsg);
}
else
{
PRINTF("send rx msg failed\n"); //申请内存失败,无法发送接收到的数据
}
}
else
{
PRINTF("bad len\n"); //包长度不对
}
#endif
}
tmos_set_event(lwns_adapter_taskid, LWNS_PHY_RX_OPEN_EVT); //重新打开接收
break;
}
case TX_MODE_TX_FINISH:
case TX_MODE_TX_FAIL:
tmos_stop_task(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_FINISH_EVT); //停止超时计数
tmos_set_event(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_FINISH_EVT); //进入发送完成处理
break;
default:
break;
}
}
/*********************************************************************
* @fn RF_Init
*
* @brief RF 初始化.
*
* @param None.
*
* @return None.
*/
void RF_Init(void)
{
uint8_t state;
rfConfig_t rfConfig;
tmos_memset(&rfConfig, 0, sizeof(rfConfig_t));
rfConfig.accessAddress = 0x17267162; // 禁止使用0x55555555以及0xAAAAAAAA ( 建议不超过24次位反转,且不超过连续的6个0或1 ),正确符合相应规则的accessaddress接入地址约有23亿个
rfConfig.CRCInit = 0x555555;
ble_phy_channelmap_receive_seq = 0;
rfConfig.Channel = ble_phy_channelmap[0];
rfConfig.LLEMode = LLE_MODE_BASIC; //|LLE_MODE_EX_CHANNEL; // 使能 LLE_MODE_EX_CHANNEL 表示 选择 rfConfig.Frequency 作为通信频点
rfConfig.rfStatusCB = RF_2G4StatusCallBack;
state = RF_Config(&rfConfig);
PRINTF("rf 2.4g init: %x\n", state);
}
/*********************************************************************
* @fn lwns_init
*
* @brief lwns初始化.
*
* @param None.
*
* @return None.
*/
void lwns_init(void)
{
uint8_t s;
lwns_config_t cfg;
tmos_memset(&cfg, 0, sizeof(lwns_config_t));
cfg.lwns_lib_name = (uint8_t *)VER_LWNS_FILE; //验证函数库名称,防止版本出错
cfg.qbuf_num = QBUF_MANUAL_NUM; //必须分配,至少1个内存单位,根据你程序中使用的端口数对应模块使用的qbuf单位来定义。
cfg.qbuf_ptr = qbuf_memp; //mesh最多使用3个qbuf单位,(uni/multi)netflood最多使用2个,其他模块都使用1个。
cfg.routetable_num = ROUTE_ENTRY_MANUAL_NUM; //如果需要使用mesh,必须分配路由表内存空间。不然mesh初始化不会成功。
#if ROUTE_ENTRY_MANUAL_NUM
cfg.routetable_ptr = route_entry_memp;
#else
cfg.routetable_ptr = NULL;
#endif
cfg.neighbor_num = LWNS_NEIGHBOR_MAX_NUM; //邻居表数量,必须分配
cfg.neighbor_list_ptr = neighbor_memp; //邻居表内存空间
cfg.neighbor_mod = LWNS_NEIGHBOR_AUTO_ADD_STATE_RECALL_ADDALL; //邻居表初始化默认管理模式为接收所有包,添加所有邻居并且过滤重复包的模式
#if LWNS_ADDR_USE_BLE_MAC
FLASH_GetMACAddress(cfg.addr.v8); //蓝牙硬件的mac地址
#else
//自行定义的地址
uint8_t MacAddr[6] = {0, 0, 0, 0, 0, 1};
tmos_memcpy(cfg.addr.v8, MacAddr, LWNS_ADDR_SIZE);
#endif
s = lwns_lib_init(&ble_lwns_fuc_interface, &cfg); //lwns库底层初始化
if(s)
{
PRINTF("%s init err:%d\n", VER_LWNS_FILE, s);
}
else
{
PRINTF("%s init ok\n", VER_LWNS_FILE);
}
lwns_adapter_taskid = TMOS_ProcessEventRegister(lwns_adapter_ProcessEvent);
lwns_phyoutput_taskid = TMOS_ProcessEventRegister(lwns_phyoutput_ProcessEvent);
tmos_start_task(lwns_phyoutput_taskid, LWNS_HTIMER_PERIOD_EVT, MS1_TO_SYSTEM_TIME(LWNS_HTIMER_PERIOD_MS));
tmos_memset(blemesh_phy_manage_list, 0, sizeof(blemesh_phy_manage_list)); //清除发送管理结构体
ble_phy_send_cnt = 0; //清空发送次数计数
RF_Shut();
RF_Rx(NULL, 0, USER_RF_RX_TX_TYPE, USER_RF_RX_TX_TYPE); //打开RF接收,如果需要低功耗管理,在其他地方打开。
tmos_start_task(lwns_adapter_taskid, LWNS_PHY_RX_CHANGE_CHANNEL_EVT, MS1_TO_SYSTEM_TIME(LWNS_MAC_PERIOD_MS));
}
/*********************************************************************
* @fn ble_new_neighbor_callback
*
* @brief 当发现一个新邻居时的回调函数.
*
* @param n - 新邻居的地址.
*
* @return None.
*/
static void ble_new_neighbor_callback(lwns_addr_t *n)
{
PRINTF("new neighbor: %02x %02x %02x %02x %02x %02x\n", n->v8[0], n->v8[1],
n->v8[2], n->v8[3], n->v8[4], n->v8[5]);
}
/*********************************************************************
* @fn ble_phy_output
*
* @brief lwns发送函数接口
*
* @param dataptr - 待发送的数据缓冲头指针.
* @param len - 待发送的数据缓冲长度.
*
* @return TRUE if success, FLASE is failed.
*/
static BOOL ble_phy_output(uint8_t *dataptr, uint8_t len)
{
uint8_t *pMsg, i;
struct blemesh_mac_phy_manage_struct *p;
for(i = 0; i < LWNS_MAC_SEND_PACKET_MAX_NUM; i++)
{
if(blemesh_phy_manage_list[i].data == NULL)
{
break; //寻找到了一个空的结构体可以使用。
}
else
{
if(i == (LWNS_MAC_SEND_PACKET_MAX_NUM - 1))
{
PRINTF("send failed!\n"); //列表满了,发送失败,直接返回。
return FALSE;
}
}
}
#if LWNS_ENCRYPT_ENABLE
pMsg = tmos_msg_allocate((((len + 1 + 15) & 0xf0) + 1 + 1)); //校验位1位加上后再进行16字节对齐,存储发送长度+1,真实数据长度+1
#else
pMsg = tmos_msg_allocate(len + 1); //申请内存空间存储消息,存储发送长度+1
#endif
if(pMsg != NULL)
{ //成功申请
p = blemesh_phy_manage_list_head;
if(p != NULL)
{
while(p->next != NULL)
{ //寻找发送链表的终点
p = p->next;
}
}
#if LWNS_ENCRYPT_ENABLE
//lwns buffer内部预留有两字节,用户可直接使用dataptr[len]进行赋值两字节内容
dataptr[len] = dataptr[len - 1] ^ len; //校验字节仅取最后一个字节和长度进行异或运算,首字节相同port是一样的,可能有影响。和校验比较浪费时间,所以不采用
pMsg[1] = len; //真实数据长度占一字节,不加密,用来接收做第一步校验
pMsg[0] = lwns_msg_encrypt(dataptr, pMsg + 2, len + 1) + 1; //获取数据加密后的长度,也就是需要发送出去的字节数,真实数据长度不加密
#else
pMsg[0] = len;
tmos_memcpy(pMsg + 1, dataptr, len);
#endif
if(blemesh_phy_manage_list_head != NULL)
{
p->next = &blemesh_phy_manage_list[i]; //链表添加尾结点
}
else
{
blemesh_phy_manage_list_head = &blemesh_phy_manage_list[i]; //链表为空,则节点作为头结点
tmos_set_event(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_PREPARE_EVT); //启动发送,不是头结点不需要启动,因为在发送流程中。
}
blemesh_phy_manage_list[i].data = pMsg; //绑定消息
blemesh_phy_manage_list[i].next = NULL;
return TRUE;
}
else
{
PRINTF("send failed!\n"); //无法申请到内存,则无法发送
}
return FALSE;
}
/*********************************************************************
* @fn lwns_adapter_ProcessEvent
*
* @brief lwns adapter Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed.
*/
static uint16_t lwns_adapter_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & LWNS_PHY_RX_CHANGE_CHANNEL_EVT) //处理更换接收通道事件
{
ble_phy_channelmap_receive_seq++;
if(ble_phy_channelmap_receive_seq >= sizeof(ble_phy_channelmap))
{
ble_phy_channelmap_receive_seq = 0;
}
RF_Shut();
RF_SetChannel(ble_phy_channelmap[ble_phy_channelmap_receive_seq]); //周期性更改发送通道
RF_Rx(NULL, 0, USER_RF_RX_TX_TYPE, USER_RF_RX_TX_TYPE); //重新打开接收
tmos_start_task(lwns_adapter_taskid, LWNS_PHY_RX_CHANGE_CHANNEL_EVT, MS1_TO_SYSTEM_TIME(LWNS_MAC_PERIOD_MS));
return ((events & (~LWNS_PHY_RX_OPEN_EVT)) ^ LWNS_PHY_RX_CHANGE_CHANNEL_EVT ); //停止可能已经置位的、可能会打开接收的任务
}
if(events & LWNS_PHY_RX_OPEN_EVT)
{ //重新打开接收事件
RF_Shut();
RF_Rx(NULL, 0, USER_RF_RX_TX_TYPE, USER_RF_RX_TX_TYPE); //重新打开接收
return (events ^ LWNS_PHY_RX_OPEN_EVT);
}
if(events & SYS_EVENT_MSG)
{ //处理打开接收后,再处理数据
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(lwns_adapter_taskid)) != NULL)
{
// Release the TMOS message,tmos_msg_allocate
lwns_input(pMsg + 1, pMsg[0]); //将数据存入协议栈缓冲区
tmos_msg_deallocate(pMsg); //先释放内存,在数据处理前释放,防止数据处理中需要发送数据,而内存不够。
lwns_dataHandler(); //调用协议栈处理数据函数
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
// Discard unknown events
return 0;
}
/*********************************************************************
* @fn lwns_phyoutput_ProcessEvent
*
* @brief lwns phyoutput Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed.
*/
static uint16_t lwns_phyoutput_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & LWNS_HTIMER_PERIOD_EVT)
{
lwns_htimer_update(); //htimer更新。
tmos_start_task(lwns_phyoutput_taskid, LWNS_HTIMER_PERIOD_EVT, MS1_TO_SYSTEM_TIME(LWNS_HTIMER_PERIOD_MS)); //周期性更新
return (events ^ LWNS_HTIMER_PERIOD_EVT);
}
if(events & LWNS_PHY_OUTPUT_PREPARE_EVT)
{ //准备发送工作
uint8_t rand_delay;
rand_delay = tmos_rand() % MS1_TO_SYSTEM_TIME(LWNS_MAC_SEND_DELAY_MAX_MS) + BLE_PHY_ONE_PACKET_MAX_625US; //随机延迟
ble_phy_channelmap_send_seq = 0; //发送通道序号
PRINTF("rand send:%d\n", rand_delay);
tmos_start_task(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_FINISH_EVT, rand_delay); //随机延迟后立刻发送
return (events ^ LWNS_PHY_OUTPUT_PREPARE_EVT);
}
if(events & LWNS_PHY_OUTPUT_FINISH_EVT)
{ //发送完成任务
if(ble_phy_channelmap_send_seq < sizeof(ble_phy_channelmap))
{
if(ble_phy_channelmap_send_seq == 0)
{ //只需要在开始发送的时候停任务
tmos_stop_task(lwns_adapter_taskid, LWNS_PHY_RX_CHANGE_CHANNEL_EVT); //发送期间,停止继续切换接收通道
tmos_clear_event(lwns_adapter_taskid, LWNS_PHY_RX_CHANGE_CHANNEL_EVT); //停止可能已经置位的、可能会打开接收的任务
tmos_clear_event(lwns_adapter_taskid, LWNS_PHY_RX_OPEN_EVT); //停止可能已经置位的、可能会打开接收的任务
}
RF_Shut();
RF_SetChannel(ble_phy_channelmap[ble_phy_channelmap_send_seq]); //周期性更改发送通道
RF_Tx((uint8_t *)(blemesh_phy_manage_list_head->data + 1),
blemesh_phy_manage_list_head->data[0], USER_RF_RX_TX_TYPE,
USER_RF_RX_TX_TYPE);
tmos_start_task(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_FINISH_EVT, MS1_TO_SYSTEM_TIME(LWNS_PHY_OUTPUT_TIMEOUT_MS)); //开始发送超时计数,防止有意外打断发送,导致无法继续发送
ble_phy_channelmap_send_seq++;
}
else
{
//三个通道一次发送结束完
ble_phy_send_cnt++;
tmos_set_event(lwns_adapter_taskid, LWNS_PHY_RX_CHANGE_CHANNEL_EVT); //间隔期间继续接收
if(ble_phy_send_cnt < LWNS_MAC_TRANSMIT_TIMES)
{ //发送次数不够
tmos_set_event(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_PREPARE_EVT); //启动发送
}
else
{
//指定次数发送结束
ble_phy_send_cnt = 0; //清空发送次数计数
tmos_msg_deallocate(blemesh_phy_manage_list_head->data); //释放内存
blemesh_phy_manage_list_head->data = NULL; //恢复默认参数
blemesh_phy_manage_list_head = blemesh_phy_manage_list_head->next; //链表pop,去除掉首元素
if(blemesh_phy_manage_list_head != NULL)
{
tmos_set_event(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_PREPARE_EVT); //启动发送
}
}
}
return (events ^ LWNS_PHY_OUTPUT_FINISH_EVT);
}
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(lwns_phyoutput_taskid)) != NULL)
{
// Release the TMOS message,tmos_msg_allocate
tmos_msg_deallocate(pMsg); //释放内存
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
/*********************************************************************
* @fn lwns_shut
*
* @brief 停止lwns,不可以在这lwns_phyoutput_taskid和lwns_adapter_taskid的processEvent中调用。
*
* @param None.
*
* @return None.
*/
void lwns_shut()
{
uint8_t *pMsg;
RF_Shut(); //关闭RF接收
while(blemesh_phy_manage_list_head != NULL)
{
/* 清除所有缓存中待发送的消息 */
tmos_msg_deallocate(blemesh_phy_manage_list_head->data);
blemesh_phy_manage_list_head->data = NULL;
blemesh_phy_manage_list_head = blemesh_phy_manage_list_head->next;
}
tmos_stop_task(lwns_phyoutput_taskid, LWNS_HTIMER_PERIOD_EVT); //停止Htimer心跳时钟
tmos_clear_event(lwns_phyoutput_taskid, LWNS_HTIMER_PERIOD_EVT);
/* 超时重发全部清除 */
lwns_htimer_flush_all();
tmos_stop_task(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_PREPARE_EVT);
tmos_clear_event(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_PREPARE_EVT);
tmos_stop_task(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_FINISH_EVT);
tmos_clear_event(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_FINISH_EVT);
while((pMsg = tmos_msg_receive(lwns_adapter_taskid)) != NULL)
{
/* 清除所有缓存的消息 */
tmos_msg_deallocate(pMsg);
}
tmos_stop_task(lwns_adapter_taskid, LWNS_PHY_RX_CHANGE_CHANNEL_EVT); //停止Htimer心跳时钟
tmos_clear_event(lwns_adapter_taskid, LWNS_PHY_RX_CHANGE_CHANNEL_EVT);
tmos_stop_task(lwns_adapter_taskid, LWNS_PHY_RX_OPEN_EVT);
tmos_clear_event(lwns_adapter_taskid, LWNS_PHY_RX_OPEN_EVT);
tmos_clear_event(lwns_adapter_taskid, SYS_EVENT_MSG);
/* 清空发送次数计数 */
ble_phy_send_cnt = 0;
/* 清空发送序号 */
ble_phy_channelmap_send_seq = 0;
/* 清空接收通道序号 */
ble_phy_channelmap_receive_seq = 0;
}
/*********************************************************************
* @fn lwns_start
*
* @brief lwns开始运行,在使用lwns_shut后,重新开始时使用。
*
* @param None.
*
* @return None.
*/
void lwns_start()
{
RF_Shut();
RF_SetChannel(ble_phy_channelmap[ble_phy_channelmap_receive_seq]); //周期性更改发送通道
RF_Rx(NULL, 0, USER_RF_RX_TX_TYPE, USER_RF_RX_TX_TYPE); //打开RF接收,如果需要低功耗管理,在其他地方打开。
tmos_start_task(lwns_adapter_taskid, LWNS_PHY_RX_CHANGE_CHANNEL_EVT, MS1_TO_SYSTEM_TIME(LWNS_MAC_PERIOD_MS));
tmos_start_task(lwns_phyoutput_taskid, LWNS_HTIMER_PERIOD_EVT, MS1_TO_SYSTEM_TIME(LWNS_HTIMER_PERIOD_MS));
}
#endif /* LWNS_USE_BLEMESH_MAC */
@@ -0,0 +1,514 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_adapter_csma_mac.c
* Author : WCH
* Version : V1.0
* Date : 2021/06/20
* Description : lwns适配器,模拟csma的mac协议
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "lwns_adapter_csma_mac.h"
#include "lwns_sec.h"
//每个文件单独debug打印的开关,置0可以禁止本文件内部打印
#define DEBUG_PRINT_IN_THIS_FILE 1
#if DEBUG_PRINT_IN_THIS_FILE
#define PRINTF(...) PRINT(__VA_ARGS__)
#else
#define PRINTF(...) \
do \
{ \
} while(0)
#endif
#if LWNS_USE_CSMA_MAC //是否使能模仿csma的mac协议,注意只能使能一个mac层协议。
//for lwns_packet_buffer save
__attribute__((aligned(4))) static lwns_qbuf_list_t qbuf_memp[QBUF_MANUAL_NUM];
//for lwns_route_entry manage
#if ROUTE_ENTRY_MANUAL_NUM
__attribute__((aligned(4))) static lwns_route_entry_data_t route_entry_memp[ROUTE_ENTRY_MANUAL_NUM];
#endif
//for neighbor manage
__attribute__((aligned(4))) static lwns_neighbor_list_t neighbor_memp[LWNS_NEIGHBOR_MAX_NUM];
static void ble_new_neighbor_callback(lwns_addr_t *n); //发现新邻居回调函数
static BOOL ble_phy_output(uint8_t *dataptr, uint8_t len); //发送接口函数
static void RF_2G4StatusCallBack(uint8_t sta, uint8_t crc, uint8_t *rxBuf);
static uint8_t lwns_adapter_taskid;
static uint16_t lwns_adapter_ProcessEvent(uint8_t task_id, uint16_t events);
static uint8_t lwns_phyoutput_taskid;
static uint16_t lwns_phyoutput_ProcessEvent(uint8_t task_id, uint16_t events);
/**
* lwns必用的函数接口,将指针传递给lwns库内部使用
*/
static lwns_fuc_interface_t ble_lwns_fuc_interface = {
.lwns_phy_output = ble_phy_output,
.lwns_rand = tmos_rand,
.lwns_memcpy = tmos_memcpy,
.lwns_memcmp = tmos_memcmp,
.lwns_memset = tmos_memset,
.new_neighbor_callback = ble_new_neighbor_callback,
};
static uint8_t ble_phy_manage_state, ble_phy_send_cnt = 0, ble_phy_wait_cnt = 0; //ble phy状态管理,发送次数计数,等待次数计数
static struct csma_mac_phy_manage_struct *csma_phy_manage_list_head = NULL; //mac管理发送列表指针
static struct csma_mac_phy_manage_struct csma_phy_manage_list[LWNS_MAC_SEND_PACKET_MAX_NUM]; //mac管理发送列表管理数组
/*********************************************************************
* @fn RF_2G4StatusCallBack
*
* @brief RF 状态回调,注意:不可在此函数中直接调用RF接收或者发送API,需要使用事件的方式调用
*
* @param sta - 状态类型
* @param crc - crc校验结果
* @param rxBuf - 数据buf指针
*
* @return None.
*/
static void RF_2G4StatusCallBack(uint8_t sta, uint8_t crc, uint8_t *rxBuf)
{
switch(sta)
{
case RX_MODE_RX_DATA:
{
if(crc == 1)
{
PRINTF("crc error\n");
}
else if(crc == 2)
{
PRINTF("match type error\n");
}
else
{
uint8_t *pMsg;
#if LWNS_ENCRYPT_ENABLE //是否启用消息加密
if(((rxBuf[1] % 16) == 1) && (rxBuf[1] >= 17) && (rxBuf[1] > rxBuf[2]))
{ //对齐后数据区最少16个字节,加上真实数据长度一字节
//长度校验通过,所以rxBuf[1] - 1必为16的倍数
pMsg = tmos_msg_allocate(rxBuf[1]); //申请内存空间,真实数据长度不需要解密
if(pMsg != NULL)
{
lwns_msg_decrypt(rxBuf + 3, pMsg + 1, rxBuf[1] - 1); //解密数据
if((rxBuf[2] ^ pMsg[rxBuf[2]]) == pMsg[rxBuf[2] + 1])
{
pMsg[0] = rxBuf[2]; //校验通过,存储真实数据长度
PRINTF("send rx msg\n"); //发送接收到的数据到接收进程中
tmos_msg_send(lwns_adapter_taskid, pMsg);
}
else
{
PRINTF("verify rx msg err\n"); //校验失败
tmos_msg_deallocate(pMsg);
}
}
else
{
PRINTF("send rx msg failed\n"); //申请内存失败,无法发送接收到的数据
}
}
else
{
PRINTF("bad len\n"); //包长度不对
}
#else
if(rxBuf[1] >= LWNS_PHY_OUTPUT_MIN_SIZE)
{ //数据长度符合,才会发送至协议栈内部处理
pMsg = tmos_msg_allocate(rxBuf[1] + 1);
if(pMsg != NULL)
{
PRINTF("send rx msg\n"); //发送接收到的数据到接收任务中
tmos_memcpy(pMsg, rxBuf + 1, rxBuf[1] + 1);
tmos_msg_send(lwns_adapter_taskid, pMsg);
}
else
{
PRINTF("rx msg failed\n"); //申请内存失败,无法发送接收到的数据
}
}
else
{
PRINTF("bad len\n"); //包长度不对
}
#endif
//当接收到一个数据包时,将本时间段内的还未开始的发送任务停止,等待下一时间段发送,已经开始的发送任务不暂停,模仿csma/ca,进行防碰撞相关检测。
if(ble_phy_manage_state == BLE_PHY_MANAGE_STATE_WAIT_SEND)
{ //等待发送状态中收到数据包
PRINTF("send delay\n");
ble_phy_manage_state = BLE_PHY_MANAGE_STATE_RECEIVED; //等待发送周期内收到了数据包状态
tmos_stop_task(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_EVT); //竞争发送权限失败,放弃自己的发送任务。
tmos_clear_event(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_EVT); //放弃自己的发送任务
}
}
tmos_set_event(lwns_adapter_taskid, LWNS_PHY_RX_OPEN_EVT); //重新打开接收
break;
}
case TX_MODE_TX_FINISH:
case TX_MODE_TX_FAIL:
tmos_stop_task(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_FINISH_EVT); //停止超时计数
tmos_set_event(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_FINISH_EVT); //进入发送完成处理
break;
default:
break;
}
}
/*********************************************************************
* @fn RF_Init
*
* @brief RF 初始化.
*
* @param None.
*
* @return None.
*/
void RF_Init(void)
{
uint8_t state;
rfConfig_t rfConfig;
tmos_memset(&rfConfig, 0, sizeof(rfConfig_t));
rfConfig.accessAddress = 0x17267162; // 禁止使用0x55555555以及0xAAAAAAAA ( 建议不超过24次位反转,且不超过连续的6个0或1 ),正确符合相应规则的accessaddress接入地址约有23亿个
rfConfig.CRCInit = 0x555555;
rfConfig.Channel = 8;
rfConfig.LLEMode = LLE_MODE_BASIC; //|LLE_MODE_EX_CHANNEL; // 使能 LLE_MODE_EX_CHANNEL 表示 选择 rfConfig.Frequency 作为通信频点
rfConfig.rfStatusCB = RF_2G4StatusCallBack;
state = RF_Config(&rfConfig);
PRINTF("rf 2.4g init: %x\n", state);
}
/*********************************************************************
* @fn lwns_init
*
* @brief lwns初始化.
*
* @param None.
*
* @return None.
*/
void lwns_init(void)
{
uint8_t s;
lwns_config_t cfg;
tmos_memset(&cfg, 0, sizeof(lwns_config_t));
cfg.lwns_lib_name = (uint8_t *)VER_LWNS_FILE; //验证函数库名称,防止版本出错
cfg.qbuf_num = QBUF_MANUAL_NUM; //必须分配,至少1个内存单位,根据你程序中使用的端口数对应模块使用的qbuf单位来定义。
cfg.qbuf_ptr = qbuf_memp; //mesh最多使用3个qbuf单位,(uni/multi)netflood最多使用2个,其他模块都使用1个。
cfg.routetable_num = ROUTE_ENTRY_MANUAL_NUM; //如果需要使用mesh,必须分配路由表内存空间。不然mesh初始化不会成功。
#if ROUTE_ENTRY_MANUAL_NUM
cfg.routetable_ptr = route_entry_memp;
#else
cfg.routetable_ptr = NULL;
#endif
cfg.neighbor_num = LWNS_NEIGHBOR_MAX_NUM; //邻居表数量,必须分配
cfg.neighbor_list_ptr = neighbor_memp; //邻居表内存空间
cfg.neighbor_mod = LWNS_NEIGHBOR_AUTO_ADD_STATE_RECALL_ADDALL; //邻居表初始化默认管理模式为接收所有包,添加所有邻居并且过滤重复包的模式
#if LWNS_ADDR_USE_BLE_MAC
GetMACAddress(cfg.addr.v8); //蓝牙硬件的mac地址
#else
//自行定义的地址
uint8_t MacAddr[6] = {0, 0, 0, 0, 0, 1};
tmos_memcpy(cfg.addr.v8, MacAddr, LWNS_ADDR_SIZE);
#endif
s = lwns_lib_init(&ble_lwns_fuc_interface, &cfg); //lwns库底层初始化
if(s)
{
PRINTF("%s init err:%d\n", VER_LWNS_FILE, s);
}
else
{
PRINTF("%s init ok\n", VER_LWNS_FILE);
}
lwns_adapter_taskid = TMOS_ProcessEventRegister(lwns_adapter_ProcessEvent);
lwns_phyoutput_taskid = TMOS_ProcessEventRegister(lwns_phyoutput_ProcessEvent);
tmos_start_task(lwns_phyoutput_taskid, LWNS_PHY_PERIOD_EVT, MS1_TO_SYSTEM_TIME(LWNS_MAC_PERIOD_MS));
tmos_memset(csma_phy_manage_list, 0, sizeof(csma_phy_manage_list)); //清除发送管理结构体
ble_phy_manage_state = BLE_PHY_MANAGE_STATE_FREE; //清除phy状态
RF_Shut();
RF_Rx(NULL, 0, USER_RF_RX_TX_TYPE, USER_RF_RX_TX_TYPE); //打开RF接收,如果需要低功耗管理,在其他地方打开。
}
/*********************************************************************
* @fn ble_new_neighbor_callback
*
* @brief 当发现一个新邻居时的回调函数.
*
* @param n - 新邻居的地址.
*
* @return None.
*/
static void ble_new_neighbor_callback(lwns_addr_t *n)
{
PRINTF("new neighbor: %02x %02x %02x %02x %02x %02x\n", n->v8[0], n->v8[1],
n->v8[2], n->v8[3], n->v8[4], n->v8[5]);
}
/*********************************************************************
* @fn ble_phy_output
*
* @brief lwns发送函数接口
*
* @param dataptr - 待发送的数据缓冲头指针.
* @param len - 待发送的数据缓冲长度.
*
* @return TRUE if success, FLASE is failed.
*/
static BOOL ble_phy_output(uint8_t *dataptr, uint8_t len)
{
uint8_t *pMsg, i;
struct csma_mac_phy_manage_struct *p;
for(i = 0; i < LWNS_MAC_SEND_PACKET_MAX_NUM; i++)
{
if(csma_phy_manage_list[i].data == NULL)
{
break; //寻找到了一个空的结构体可以使用。
}
else
{
if(i == (LWNS_MAC_SEND_PACKET_MAX_NUM - 1))
{
PRINTF("send failed!\n"); //列表满了,发送失败,直接返回。
return FALSE;
}
}
}
#if LWNS_ENCRYPT_ENABLE
pMsg = tmos_msg_allocate((((len + 1 + 15) & 0xf0) + 1 + 1)); //校验位1位加上后再进行16字节对齐,存储发送长度+1,真实数据长度+1
#else
pMsg = tmos_msg_allocate(len + 1); //申请内存空间存储消息,存储发送长度+1
#endif
if(pMsg != NULL)
{ //成功申请
p = csma_phy_manage_list_head;
if(p != NULL)
{
while(p->next != NULL)
{ //寻找发送链表的终点
p = p->next;
}
}
#if LWNS_ENCRYPT_ENABLE
//lwns buffer内部预留有两字节,用户可直接使用dataptr[len]进行赋值两字节内容
dataptr[len] = dataptr[len - 1] ^ len; //校验字节仅取最后一个字节和长度进行异或运算,首字节相同port是一样的,可能有影响。和校验比较浪费时间,所以不采用
pMsg[1] = len; //真实数据长度占一字节,不加密,用来接收做第一步校验
pMsg[0] = lwns_msg_encrypt(dataptr, pMsg + 2, len + 1) + 1; //获取数据加密后的长度,也就是需要发送出去的字节数,真实数据长度不加密
#else
pMsg[0] = len;
tmos_memcpy(pMsg + 1, dataptr, len);
#endif
if(csma_phy_manage_list_head != NULL)
{
p->next = &csma_phy_manage_list[i]; //链表添加尾结点
}
else
{
csma_phy_manage_list_head = &csma_phy_manage_list[i]; //链表为空,则节点作为头结点
}
csma_phy_manage_list[i].data = pMsg; //绑定消息
csma_phy_manage_list[i].next = NULL;
return TRUE;
}
else
{
PRINTF("send failed!\n"); //无法申请到内存,则无法发送
}
return FALSE;
}
/*********************************************************************
* @fn lwns_adapter_ProcessEvent
*
* @brief lwns adapter Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed.
*/
static uint16_t lwns_adapter_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & LWNS_PHY_RX_OPEN_EVT)
{
RF_Shut();
RF_Rx(NULL, 0, USER_RF_RX_TX_TYPE, USER_RF_RX_TX_TYPE); //重新打开接收
return (events ^ LWNS_PHY_RX_OPEN_EVT);
}
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(lwns_adapter_taskid)) != NULL)
{
// Release the TMOS message,tmos_msg_allocate
lwns_input(pMsg + 1, pMsg[0]); //将数据存入协议栈缓冲区
tmos_msg_deallocate(pMsg); //先释放内存,在数据处理前释放,防止数据处理中需要发送数据,而内存不够。
lwns_dataHandler(); //调用协议栈处理数据函数
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
// Discard unknown events
return 0;
}
/*********************************************************************
* @fn lwns_phyoutput_ProcessEvent
*
* @brief lwns phyoutput Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed.
*/
static uint16_t lwns_phyoutput_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & LWNS_PHY_PERIOD_EVT)
{
lwns_htimer_update(); //htimer的更新需要和mac的phy管理放一起,保持一致。
if((csma_phy_manage_list_head != NULL))
{ //有需要发送的包
if((ble_phy_manage_state == BLE_PHY_MANAGE_STATE_FREE) || (ble_phy_manage_state == BLE_PHY_MANAGE_STATE_RECEIVED))
{ //当前不在发送过程中
if(ble_phy_manage_state == BLE_PHY_MANAGE_STATE_RECEIVED)
{ //当前周期发送碰撞,延迟发送
ble_phy_wait_cnt++; //记录发送延迟次数
}
else
{ //BLE_PHY_MANAGE_STATE_FREE
ble_phy_send_cnt = 0; //清除计数
ble_phy_wait_cnt = 0; //清除计数
}
ble_phy_manage_state = BLE_PHY_MANAGE_STATE_WAIT_SEND; //设置为等待发送状态
if(ble_phy_wait_cnt >= LWNS_MAC_SEND_DELAY_MAX_TIMES)
{ //发送被取消次数,延迟过多,不再随机等待,立刻开始发送
tmos_set_event(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_EVT);
PRINTF("too many delay\n");
}
else
{
uint8_t rand_delay;
rand_delay = tmos_rand() % LWNS_MAC_SEND_DELAY_MAX_625US + BLE_PHY_ONE_PACKET_MAX_625US; //随机延迟,防止冲突,随机延迟等待周期里收到了数据包就下次再发送
tmos_start_task(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_EVT, rand_delay);
PRINTF("rand send:%d\n", rand_delay);
}
}
}
tmos_start_task(lwns_phyoutput_taskid, LWNS_PHY_PERIOD_EVT, MS1_TO_SYSTEM_TIME(LWNS_MAC_PERIOD_MS)); //每个周期毫秒检测一次有误数据要发送,并且更新htimer。
return (events ^ LWNS_PHY_PERIOD_EVT);
}
if(events & LWNS_PHY_OUTPUT_EVT)
{ //发送任务,竞争发送成功
if(ble_phy_manage_state == BLE_PHY_MANAGE_STATE_WAIT_SEND)
{
ble_phy_manage_state = BLE_PHY_MANAGE_STATE_SENDING; //改为发送中状态,竞争包发送完毕,需要等待一下接收方做好准备工作
tmos_clear_event(lwns_adapter_taskid, LWNS_PHY_RX_OPEN_EVT); //停止可能已经置位的、可能会打开接收的任务
}
RF_Shut();
RF_Tx((uint8_t *)(csma_phy_manage_list_head->data + 1),
csma_phy_manage_list_head->data[0], USER_RF_RX_TX_TYPE,
USER_RF_RX_TX_TYPE);
tmos_start_task(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_FINISH_EVT, MS1_TO_SYSTEM_TIME(LWNS_PHY_OUTPUT_TIMEOUT_MS)); //开始发送超时计数
return (events ^ LWNS_PHY_OUTPUT_EVT);
}
if(events & LWNS_PHY_OUTPUT_FINISH_EVT)
{ //发送完成任务
ble_phy_send_cnt++; //发送计数
if(ble_phy_send_cnt < LWNS_MAC_TRANSMIT_TIMES)
{ //发送没结束
tmos_set_event(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_EVT); //发送次数没结束,继续发送
}
else
{ //发送流程结束
ble_phy_manage_state = BLE_PHY_MANAGE_STATE_FREE; //清除状态
RF_Shut();
RF_Rx(NULL, 0, USER_RF_RX_TX_TYPE, USER_RF_RX_TX_TYPE); //重新打开接收
tmos_msg_deallocate(csma_phy_manage_list_head->data); //释放内存
csma_phy_manage_list_head->data = NULL; //恢复默认参数
csma_phy_manage_list_head = csma_phy_manage_list_head->next; //链表pop,去除掉首元素
}
return (events ^ LWNS_PHY_OUTPUT_FINISH_EVT);
}
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(lwns_phyoutput_taskid)) != NULL)
{
// Release the TMOS message,tmos_msg_allocate
tmos_msg_deallocate(pMsg); //释放内存
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
/*********************************************************************
* @fn lwns_shut
*
* @brief 停止lwns,不可以在这lwns_phyoutput_taskid和lwns_adapter_taskid的processEvent中调用。
*
* @param None.
*
* @return None.
*/
void lwns_shut()
{
uint8_t *pMsg;
RF_Shut(); //关闭RF接收
while(csma_phy_manage_list_head != NULL)
{
/* 清除所有缓存中待发送的消息 */
tmos_msg_deallocate(csma_phy_manage_list_head->data);
csma_phy_manage_list_head->data = NULL;
csma_phy_manage_list_head = csma_phy_manage_list_head->next;
}
tmos_stop_task(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_EVT);
tmos_clear_event(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_EVT);
/* 超时重发全部清除 */
lwns_htimer_flush_all();
tmos_stop_task(lwns_phyoutput_taskid, LWNS_PHY_PERIOD_EVT); //停止Htimer心跳时钟和发送列表检测
tmos_clear_event(lwns_phyoutput_taskid, LWNS_PHY_PERIOD_EVT);
tmos_stop_task(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_FINISH_EVT);
tmos_clear_event(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_FINISH_EVT);
while((pMsg = tmos_msg_receive(lwns_adapter_taskid)) != NULL)
{
/* 清除所有缓存的消息 */
tmos_msg_deallocate(pMsg);
}
tmos_stop_task(lwns_adapter_taskid, LWNS_PHY_RX_OPEN_EVT);
tmos_clear_event(lwns_adapter_taskid, LWNS_PHY_RX_OPEN_EVT);
tmos_clear_event(lwns_adapter_taskid, SYS_EVENT_MSG);
}
/*********************************************************************
* @fn lwns_start
*
* @brief lwns开始运行,在使用lwns_shut后,重新开始时使用。
*
* @param None.
*
* @return None.
*/
void lwns_start()
{
RF_Shut();
RF_Rx(NULL, 0, USER_RF_RX_TX_TYPE, USER_RF_RX_TX_TYPE); //打开RF接收,如果需要低功耗管理,在其他地方打开。
tmos_start_task(lwns_phyoutput_taskid, LWNS_PHY_PERIOD_EVT, MS1_TO_SYSTEM_TIME(LWNS_MAC_PERIOD_MS));
}
#endif /* LWNS_USE_CSMA_MAC */
+423
View File
@@ -0,0 +1,423 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_adapter_no_mac.c
* Author : WCH
* Version : V1.0
* Date : 2021/06/20
* Description : lwns适配器,不使用mac协议,纯透传
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "lwns_adapter_no_mac.h"
#include "lwns_sec.h"
//每个文件单独debug打印的开关,置0可以禁止本文件内部打印
#define DEBUG_PRINT_IN_THIS_FILE 1
#if DEBUG_PRINT_IN_THIS_FILE
#define PRINTF(...) PRINT(__VA_ARGS__)
#else
#define PRINTF(...) \
do \
{ \
} while(0)
#endif
#if LWNS_USE_NO_MAC //是否使能纯透传mac协议,即mac层不参与任何动作,注意只能使能一个mac层协议。
//for lwns_packet_buffer save
__attribute__((aligned(4))) static lwns_qbuf_list_t qbuf_memp[QBUF_MANUAL_NUM];
//for lwns_route_entry manage
#if ROUTE_ENTRY_MANUAL_NUM
__attribute__((aligned(4))) static lwns_route_entry_data_t route_entry_memp[ROUTE_ENTRY_MANUAL_NUM];
#endif
//for neighbor manage
__attribute__((aligned(4))) static lwns_neighbor_list_t neighbor_memp[LWNS_NEIGHBOR_MAX_NUM];
static void ble_new_neighbor_callback(lwns_addr_t *n); //发现新邻居回调函数
static BOOL ble_phy_output(uint8_t *dataptr, uint8_t len); //发送接口函数
static void RF_2G4StatusCallBack(uint8_t sta, uint8_t crc, uint8_t *rxBuf);
static uint8_t lwns_adapter_taskid;
static uint16_t lwns_adapter_ProcessEvent(uint8_t task_id, uint16_t events);
static uint8_t lwns_phyoutput_taskid;
static uint16_t lwns_phyoutput_ProcessEvent(uint8_t task_id, uint16_t events);
/**
* lwns必用的函数接口,将指针传递给lwns库内部使用
*/
static lwns_fuc_interface_t ble_lwns_fuc_interface = {
.lwns_phy_output = ble_phy_output,
.lwns_rand = tmos_rand,
.lwns_memcpy = tmos_memcpy,
.lwns_memcmp = tmos_memcmp,
.lwns_memset = tmos_memset,
.new_neighbor_callback = ble_new_neighbor_callback,
};
static uint8_t ble_phy_manage_state; //phy状态管理
/*********************************************************************
* @fn RF_2G4StatusCallBack
*
* @brief RF 状态回调,注意:不可在此函数中直接调用RF接收或者发送API,需要使用事件的方式调用
*
* @param sta - 状态类型
* @param crc - crc校验结果
* @param rxBuf - 数据buf指针
*
* @return None.
*/
static void RF_2G4StatusCallBack(uint8_t sta, uint8_t crc, uint8_t *rxBuf)
{
switch(sta)
{
case RX_MODE_RX_DATA:
{
if(crc == 1)
{
PRINTF("crc error\n");
}
else if(crc == 2)
{
PRINTF("match type error\n");
}
else
{
uint8_t *pMsg;
#if LWNS_ENCRYPT_ENABLE //是否启用消息加密
if(((rxBuf[1] % 16) == 1) && (rxBuf[1] >= 17) && (rxBuf[1] > rxBuf[2]))
{ //对齐后数据区最少16个字节,加上真实数据长度一字节
//长度校验通过,所以rxBuf[1] - 1必为16的倍数
pMsg = tmos_msg_allocate(rxBuf[1]); //申请内存空间,真实数据长度不需要解密
if(pMsg != NULL)
{
lwns_msg_decrypt(rxBuf + 3, pMsg + 1, rxBuf[1] - 1); //解密数据
if((rxBuf[2] ^ pMsg[rxBuf[2]]) == pMsg[rxBuf[2] + 1])
{
pMsg[0] = rxBuf[2]; //校验通过,存储真实数据长度
PRINTF("send rx msg\n"); //发送接收到的数据到接收进程中
tmos_msg_send(lwns_adapter_taskid, pMsg);
}
else
{
PRINTF("verify rx msg err\n"); //校验失败
tmos_msg_deallocate(pMsg);
}
}
else
{
PRINTF("send rx msg failed\n"); //申请内存失败,无法发送接收到的数据
}
}
else
{
PRINTF("bad len\n"); //包长度不对
}
#else
if(rxBuf[1] >= LWNS_PHY_OUTPUT_MIN_SIZE)
{ //数据长度符合,才会发送至协议栈内部处理
pMsg = tmos_msg_allocate(rxBuf[1] + 1);
if(pMsg != NULL)
{
PRINTF("send rx msg\n"); //发送接收到的数据到接收进程中
tmos_memcpy(pMsg, rxBuf + 1, rxBuf[1] + 1);
tmos_msg_send(lwns_adapter_taskid, pMsg);
}
else
{
PRINTF("rx msg failed\n"); //申请内存失败,无法发送接收到的数据
}
}
else
{
PRINTF("bad len\n"); //包长度不对
}
#endif
}
tmos_set_event(lwns_adapter_taskid, LWNS_PHY_RX_OPEN_EVT); //重新打开接收
break;
}
case TX_MODE_TX_FINISH:
case TX_MODE_TX_FAIL:
tmos_stop_task(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_FINISH_EVT); //停止超时计数
tmos_set_event(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_FINISH_EVT); //进入发送完成处理
break;
default:
break;
}
}
/*********************************************************************
* @fn RF_Init
*
* @brief RF 初始化.
*
* @param None.
*
* @return None.
*/
void RF_Init(void)
{
uint8_t state;
rfConfig_t rfConfig;
tmos_memset(&rfConfig, 0, sizeof(rfConfig_t));
rfConfig.accessAddress = 0x17267162; // 禁止使用0x55555555以及0xAAAAAAAA ( 建议不超过24次位反转,且不超过连续的6个0或1 ),正确符合相应规则的accessaddress接入地址约有23亿个
rfConfig.CRCInit = 0x555555;
rfConfig.Channel = 8;
rfConfig.LLEMode = LLE_MODE_BASIC; //|LLE_MODE_EX_CHANNEL; // 使能 LLE_MODE_EX_CHANNEL 表示 选择 rfConfig.Frequency 作为通信频点
rfConfig.rfStatusCB = RF_2G4StatusCallBack;
state = RF_Config(&rfConfig);
PRINTF("rf 2.4g init: %x\n", state);
}
/*********************************************************************
* @fn lwns_init
*
* @brief lwns初始化.
*
* @param None.
*
* @return None.
*/
void lwns_init(void)
{
uint8_t s;
lwns_config_t cfg;
tmos_memset(&cfg, 0, sizeof(lwns_config_t));
cfg.lwns_lib_name = (uint8_t *)VER_LWNS_FILE; //验证函数库名称,防止版本出错
cfg.qbuf_num = QBUF_MANUAL_NUM; //必须分配,至少1个内存单位,根据你程序中使用的端口数对应模块使用的qbuf单位来定义。
cfg.qbuf_ptr = qbuf_memp; //mesh最多使用3个qbuf单位,(uni/multi)netflood最多使用2个,其他模块都使用1个。
cfg.routetable_num = ROUTE_ENTRY_MANUAL_NUM; //如果需要使用mesh,必须分配路由表内存空间。不然mesh初始化不会成功。
#if ROUTE_ENTRY_MANUAL_NUM
cfg.routetable_ptr = route_entry_memp;
#else
cfg.routetable_ptr = NULL;
#endif
cfg.neighbor_num = LWNS_NEIGHBOR_MAX_NUM; //邻居表数量,必须分配
cfg.neighbor_list_ptr = neighbor_memp; //邻居表内存空间
cfg.neighbor_mod = LWNS_NEIGHBOR_AUTO_ADD_STATE_RECALL_NOTADD; //邻居表初始化默认管理模式为接收所有包,不添加邻居的模式
#if LWNS_ADDR_USE_BLE_MAC
GetMACAddress(cfg.addr.v8); //蓝牙硬件的mac地址
#else
//自行定义的地址
uint8_t MacAddr[6] = {0, 0, 0, 0, 0, 1};
tmos_memcpy(cfg.addr.v8, MacAddr, LWNS_ADDR_SIZE);
#endif
s = lwns_lib_init(&ble_lwns_fuc_interface, &cfg); //lwns库底层初始化
if(s)
{
PRINTF("%s init err:%d\n", VER_LWNS_FILE, s);
}
else
{
PRINTF("%s init ok\n", VER_LWNS_FILE);
}
lwns_adapter_taskid = TMOS_ProcessEventRegister(lwns_adapter_ProcessEvent);
lwns_phyoutput_taskid = TMOS_ProcessEventRegister(lwns_phyoutput_ProcessEvent);
tmos_start_task(lwns_phyoutput_taskid, LWNS_HTIMER_PERIOD_EVT, MS1_TO_SYSTEM_TIME(LWNS_HTIMER_PERIOD_MS));
ble_phy_manage_state = BLE_PHY_MANAGE_STATE_FREE;
RF_Shut();
RF_Rx(NULL, 0, USER_RF_RX_TX_TYPE, USER_RF_RX_TX_TYPE); //打开RF接收,如果需要低功耗管理,在其他地方打开。
}
/*********************************************************************
* @fn ble_new_neighbor_callback
*
* @brief 当发现一个新邻居时的回调函数.
*
* @param n - 新邻居的地址.
*
* @return None.
*/
static void ble_new_neighbor_callback(lwns_addr_t *n)
{
PRINTF("new neighbor: %02x %02x %02x %02x %02x %02x\n", n->v8[0], n->v8[1],
n->v8[2], n->v8[3], n->v8[4], n->v8[5]);
}
/*********************************************************************
* @fn ble_phy_output
*
* @brief lwns发送函数接口
*
* @param dataptr - 待发送的数据缓冲头指针.
* @param len - 待发送的数据缓冲长度.
*
* @return TRUE if success, FLASE is failed.
*/
static BOOL ble_phy_output(uint8_t *dataptr, uint8_t len)
{
uint8_t *pMsg;
#if LWNS_ENCRYPT_ENABLE
pMsg = tmos_msg_allocate((((len + 1 + 15) & 0xf0) + 1 + 1)); //校验位1位加上后再进行16字节对齐,存储发送长度+1,真实数据长度+1
#else
pMsg = tmos_msg_allocate(len + 1); //申请内存空间存储消息,存储发送长度+1
#endif
if(pMsg != NULL)
{ //成功申请
#if LWNS_ENCRYPT_ENABLE
//lwns buffer内部预留有两字节,用户可直接使用dataptr[len]进行赋值两字节内容
dataptr[len] = dataptr[len - 1] ^ len; //校验字节仅取最后一个字节和长度进行异或运算,首字节相同port是一样的,可能有影响。和校验比较浪费时间,所以不采用
pMsg[1] = len; //真实数据长度占一字节,不加密,用来接收做第一步校验
pMsg[0] = lwns_msg_encrypt(dataptr, pMsg + 2, len + 1) + 1; //获取数据加密后的长度,也就是需要发送出去的字节数,真实数据长度不加密
#else
pMsg[0] = len;
tmos_memcpy(pMsg + 1, dataptr, len);
#endif
tmos_msg_send(lwns_phyoutput_taskid, pMsg);
return TRUE;
}
else
{
PRINTF("send failed!\n"); //无法申请到内存,则无法发送
}
return FALSE;
}
/*********************************************************************
* @fn lwns_adapter_ProcessEvent
*
* @brief lwns adapter Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed.
*/
static uint16_t lwns_adapter_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & LWNS_PHY_RX_OPEN_EVT)
{ //重新打开接收
RF_Shut();
RF_Rx(NULL, 0, USER_RF_RX_TX_TYPE, USER_RF_RX_TX_TYPE); //重新打开接收
return (events ^ LWNS_PHY_RX_OPEN_EVT);
}
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(task_id)) != NULL)
{
// Release the TMOS message,tmos_msg_allocate
lwns_input(pMsg + 1, pMsg[0]); //将数据存入协议栈缓冲区
tmos_msg_deallocate(pMsg); //先释放内存,在数据处理前释放,防止数据处理中需要发送数据,而内存不够。
lwns_dataHandler(); //调用协议栈处理数据函数
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
// Discard unknown events
return 0;
}
/*********************************************************************
* @fn lwns_phyoutput_ProcessEvent
*
* @brief lwns phyoutput Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed.
*/
static uint16_t lwns_phyoutput_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & LWNS_HTIMER_PERIOD_EVT)
{
lwns_htimer_update(); //htimer更新
tmos_start_task(lwns_phyoutput_taskid, LWNS_HTIMER_PERIOD_EVT, MS1_TO_SYSTEM_TIME(LWNS_HTIMER_PERIOD_MS)); //周期性更新
return (events ^ LWNS_HTIMER_PERIOD_EVT);
}
if(events & LWNS_PHY_OUTPUT_FINISH_EVT)
{ //发送完成任务
RF_Shut();
RF_Rx(NULL, 0, USER_RF_RX_TX_TYPE, USER_RF_RX_TX_TYPE); //重新打开接收
ble_phy_manage_state = BLE_PHY_MANAGE_STATE_FREE; //发送完成,释放phy
return (events ^ LWNS_PHY_OUTPUT_FINISH_EVT);
}
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if(ble_phy_manage_state == BLE_PHY_MANAGE_STATE_SENDING)
{
PRINTF("phy busy\n");
return 0; //发送过程中,不再发送新的数据包,直接返回
}
if((pMsg = tmos_msg_receive(lwns_phyoutput_taskid)) != NULL)
{
// Release the TMOS message,tmos_msg_allocate
tmos_clear_event(lwns_adapter_taskid, LWNS_PHY_RX_OPEN_EVT); //停止可能已经置位的、可能会打开接收的任务
RF_Shut();
RF_Tx((uint8_t *)(pMsg + 1), pMsg[0], USER_RF_RX_TX_TYPE, USER_RF_RX_TX_TYPE);
tmos_start_task(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_FINISH_EVT, MS1_TO_SYSTEM_TIME(LWNS_PHY_OUTPUT_TIMEOUT_MS)); //开始发送超时计数,防止有意外打断发送,导致无法继续发送
tmos_msg_deallocate(pMsg); //释放内存
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
/*********************************************************************
* @fn lwns_shut
*
* @brief 停止lwns,不可以在这lwns_phyoutput_taskid和lwns_adapter_taskid的processEvent中调用。
*
* @param None.
*
* @return None.
*/
void lwns_shut()
{
uint8_t *pMsg;
RF_Shut(); //关闭RF接收
/* 超时重发全部清除 */
lwns_htimer_flush_all();
tmos_stop_task(lwns_phyoutput_taskid, LWNS_HTIMER_PERIOD_EVT);
tmos_clear_event(lwns_phyoutput_taskid, LWNS_HTIMER_PERIOD_EVT);
tmos_stop_task(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_FINISH_EVT); //停止Htimer心跳时钟和发送列表检测
tmos_clear_event(lwns_phyoutput_taskid, LWNS_PHY_OUTPUT_FINISH_EVT);
while((pMsg = tmos_msg_receive(lwns_phyoutput_taskid)) != NULL)
{
/* 清除所有缓存的消息 */
tmos_msg_deallocate(pMsg);
}
tmos_clear_event(lwns_phyoutput_taskid, SYS_EVENT_MSG);
while((pMsg = tmos_msg_receive(lwns_adapter_taskid)) != NULL)
{
/* 清除所有缓存的消息 */
tmos_msg_deallocate(pMsg);
}
tmos_stop_task(lwns_adapter_taskid, LWNS_PHY_RX_OPEN_EVT);
tmos_clear_event(lwns_adapter_taskid, LWNS_PHY_RX_OPEN_EVT);
tmos_clear_event(lwns_adapter_taskid, SYS_EVENT_MSG);
}
/*********************************************************************
* @fn lwns_start
*
* @brief lwns开始运行,在使用lwns_shut后,重新开始时使用。
*
* @param None.
*
* @return None.
*/
void lwns_start()
{
RF_Shut();
RF_Rx(NULL, 0, USER_RF_RX_TX_TYPE, USER_RF_RX_TX_TYPE); //打开RF接收,如果需要低功耗管理,在其他地方打开。
tmos_start_task(lwns_phyoutput_taskid, LWNS_HTIMER_PERIOD_EVT, MS1_TO_SYSTEM_TIME(LWNS_HTIMER_PERIOD_MS));
}
#endif /* LWNS_USE_NO_MAC */
@@ -0,0 +1,154 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_broadcast_example.c
* Author : WCH
* Version : V1.0
* Date : 2021/06/20
* Description : broadcast,广播程序例子
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "lwns_broadcast_example.h"
//每个文件单独debug打印的开关,置0可以禁止本文件内部打印
#define DEBUG_PRINT_IN_THIS_FILE 1
#if DEBUG_PRINT_IN_THIS_FILE
#define PRINTF(...) PRINT(__VA_ARGS__)
#else
#define PRINTF(...) \
do \
{ \
} while(0)
#endif
//用户需要发送的数据缓冲区
static uint8_t TX_DATA[10] =
{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
static uint8_t RX_DATA[10]; //用户接收数据的缓冲区
static uint16_t lwns_broadcast_ProcessEvent(uint8_t task_id, uint16_t events);
static void broadcast_recv(lwns_controller_ptr ptr,
const lwns_addr_t *sender); //接收回调函数声明
static void broadcast_sent(lwns_controller_ptr ptr); //发送回调函数声明
static lwns_broadcast_controller broadcast; //广播控制结构体
static uint8_t broadcast_taskID;
/*********************************************************************
* @fn broadcast_recv
*
* @brief lwns broadcast接收回调函数
*
* @param ptr - 本次接收到的数据所属的广播控制结构体指针.
* @param sender - 本次接收到的数据的发送者地址指针.
*
* @return None.
*/
static void broadcast_recv(lwns_controller_ptr ptr,
const lwns_addr_t *sender)
{
uint8_t len;
len = lwns_buffer_datalen(); //获取当前缓冲区接收到的数据长度
if(len == 10)
{
lwns_buffer_save_data(RX_DATA); //接收数据到用户数据区域
PRINTF("broadcast %d rec from %02x %02x %02x %02x %02x %02x\n", get_lwns_object_port(ptr),
sender->v8[0], sender->v8[1], sender->v8[2], sender->v8[3],
sender->v8[4], sender->v8[5]); //打印出本次消息的发送者地址
PRINTF("data:");
for(uint8_t i = 0; i < len; i++)
{
PRINTF("%02x ", RX_DATA[i]); //打印数据
}
PRINTF("\n");
}
else
{
PRINTF("data len err\n");
}
}
/*********************************************************************
* @fn broadcast_sent
*
* @brief lwns broadcast发送完成回调函数
*
* @param ptr - 本次发送完成的广播控制结构体指针.
*
* @return None.
*/
static void broadcast_sent(lwns_controller_ptr ptr)
{
PRINTF("broadcast %d sent\n", get_lwns_object_port(ptr)); //打印发送完成信息
}
/**
* lwns广播回调函数结构体,注册回调函数
*/
static const struct lwns_broadcast_callbacks broadcast_call = {
broadcast_recv, broadcast_sent};
/*********************************************************************
* @fn lwns_broadcast_process_init
*
* @brief lwns broadcast例程初始化.
*
* @param None.
*
* @return None.
*/
void lwns_broadcast_process_init(void)
{
broadcast_taskID = TMOS_ProcessEventRegister(lwns_broadcast_ProcessEvent);
lwns_broadcast_init(&broadcast, 136, &broadcast_call); //打开一个端口号为136的广播端口,注册回调函数
tmos_start_task(broadcast_taskID, BROADCAST_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(1000)); //开始周期性广播任务
}
/*********************************************************************
* @fn lwns_broadcast_ProcessEvent
*
* @brief lwns broadcast Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed.
*/
uint16_t lwns_broadcast_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & BROADCAST_EXAMPLE_TX_PERIOD_EVT)
{
uint8_t temp;
temp = TX_DATA[0];
for(uint8_t i = 0; i < 9; i++)
{
TX_DATA[i] = TX_DATA[i + 1]; //移位发送数据,以便观察效果
}
TX_DATA[9] = temp;
lwns_buffer_load_data(TX_DATA, sizeof(TX_DATA)); //载入需要发送的数据到缓冲区
lwns_broadcast_send(&broadcast); //广播发送数据
tmos_start_task(broadcast_taskID, BROADCAST_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(1000)); //周期性发送
return events ^ BROADCAST_EXAMPLE_TX_PERIOD_EVT;
}
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(task_id)) != NULL)
{
// Release the TMOS message
tmos_msg_deallocate(pMsg);
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
+322
View File
@@ -0,0 +1,322 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_mesh_example.c
* Author : WCH
* Version : V1.0
* Date : 2021/06/28
* Description : mesh传输程序例子
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "lwns_mesh_example.h"
//每个文件单独debug打印的开关,置0可以禁止本文件内部打印
#define DEBUG_PRINT_IN_THIS_FILE 1
#if DEBUG_PRINT_IN_THIS_FILE
#define PRINTF(...) PRINT(__VA_ARGS__)
#else
#define PRINTF(...) \
do \
{ \
} while(0)
#endif
#define MESH_TEST_ROUTE_AUTO 1 //设置是否自动管理路由表
#define MESH_TEST_SELF_ADDR_IDX 2 //当前测试中节点地址,在device_addr数组中
#define MESH_TEST_ADDR_MAX_IDX 2 //当前测试中,有多少个节点
static uint8_t mesh_test_send_dst = 0;
static lwns_mesh_controller lwns_mesh_test;
static uint8_t lwns_mesh_test_taskID;
static uint16_t lwns_mesh_test_ProcessEvent(uint8_t task_id, uint16_t events);
static uint8_t TX_DATA[10] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39};
static const lwns_addr_t device_addr[] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, //根节点地址
{0x00, 0x00, 0x00, 0x00, 0x01, 0x01}, //组1路由节点1
{0x00, 0x00, 0x00, 0x00, 0x01, 0x02}, //组1节点2
{0x00, 0x00, 0x00, 0x00, 0x01, 0x03}, //组1节点3
{0x00, 0x00, 0x00, 0x00, 0x01, 0x04}, //组1节点4
{0x00, 0x00, 0x00, 0x00, 0x02, 0x01}, //组2路由节点1
{0x00, 0x00, 0x00, 0x00, 0x02, 0x02}, //组2节点2
{0x00, 0x00, 0x00, 0x00, 0x02, 0x03}, //组2节点3
{0x00, 0x00, 0x00, 0x00, 0x02, 0x04}, //组2节点4
{0x00, 0x00, 0x00, 0x00, 0x03, 0x01}, //组3路由节点1
{0x00, 0x00, 0x00, 0x00, 0x03, 0x02}, //组3节点2
{0x00, 0x00, 0x00, 0x00, 0x03, 0x03}, //组3节点3
{0x00, 0x00, 0x00, 0x00, 0x03, 0x04}, //组3节点4
};
static void lwns_mesh_recv(lwns_controller_ptr ptr,
const lwns_addr_t *sender, uint8_t hops);
static void lwns_mesh_sent(lwns_controller_ptr ptr);
static void lwns_mesh_timedout(lwns_controller_ptr ptr);
/*********************************************************************
* @fn lwns_mesh_recv
*
* @brief lwns mesh接收回调函数
*
* @param ptr - 本次接收到的数据所属的mesh控制结构体指针.
* @param sender - 本次接收到的数据的发送者地址指针.
* @param hops - 本次接收到的数据的从发送方到本节点经历的跳数.
*
* @return None.
*/
static void lwns_mesh_recv(lwns_controller_ptr ptr,
const lwns_addr_t *sender, uint8_t hops)
{
PRINTF("mesh %d received from %02x.%02x.%02x.%02x.%02x.%02x: %s (%d)\n",
get_lwns_object_port(ptr), sender->v8[0], sender->v8[1],
sender->v8[2], sender->v8[3], sender->v8[4], sender->v8[5],
(char *)lwns_buffer_dataptr(), lwns_buffer_datalen());
if(MESH_TEST_SELF_ADDR_IDX != 0)
{
//不为0,证明是从机,收到后回复主机
lwns_buffer_save_data(TX_DATA);
tmos_set_event(lwns_mesh_test_taskID, MESH_EXAMPLE_TX_NODE_EVT);
}
}
/*********************************************************************
* @fn lwns_mesh_sent
*
* @brief lwns mesh发送完成回调函数
*
* @param ptr - 本次发送完成的mesh控制结构体指针.
*
* @return None.
*/
static void lwns_mesh_sent(lwns_controller_ptr ptr)
{
PRINTF("mesh %d packet sent\n", get_lwns_object_port(ptr));
}
/*********************************************************************
* @fn lwns_mesh_timedout
*
* @brief lwns mesh发送超时回调函数
*
* @param ptr - 本次发送完成的mesh控制结构体指针.
*
* @return None.
*/
static void lwns_mesh_timedout(lwns_controller_ptr ptr)
{
//寻找路由超时才会进入该回调,如果已经有路由,但是下一跳节点掉线,不会进入该回调。由lwns_route_init(TRUE, 60, HTIMER_SECOND_NUM);来管理掉线时间。
PRINTF("mesh %d packet timedout\n", get_lwns_object_port(ptr));
}
/**
* lwns mesh回调函数结构体,注册回调函数
*/
static const struct lwns_mesh_callbacks callbacks = {lwns_mesh_recv,
lwns_mesh_sent, lwns_mesh_timedout};
/*
* mesh采用netflood模块进行寻找路由,所以初始化参数中包括了netflood所需要的参数
* mesh为利用路由进行多跳转发的基础结构
* mesh模块使用前必须初始化路由,包括库初始化时给路由表提供的内存空间。
*/
/*********************************************************************
* @fn lwns_mesh_process_init
*
* @brief lwns mesh例程初始化.
*
* @param None.
*
* @return None.
*/
void lwns_mesh_process_init(void)
{
uint8_t route_enable = FALSE;
lwns_addr_set(
(lwns_addr_t *)(&device_addr[MESH_TEST_SELF_ADDR_IDX])); //改变lwns内部addr
if(device_addr[MESH_TEST_SELF_ADDR_IDX].v8[5] == 1)
{
//每一组第一个节点打开路由功能,其他节点不打开路由功能
route_enable = TRUE;
}
lwns_mesh_test_taskID = TMOS_ProcessEventRegister(lwns_mesh_test_ProcessEvent);
#if MESH_TEST_ROUTE_AUTO
lwns_route_init(TRUE, 60, HTIMER_SECOND_NUM);
#else
lwns_route_init(TRUE, 0, HTIMER_SECOND_NUM); //disable auto clean route entry
#endif /*MESH_TEST_ROUTE_AUTO*/
lwns_mesh_init(&lwns_mesh_test, 132, //打开一个端口号132的mesh网络,同时占用后其他的两个端口用作寻找路由,即133,134也同时打开了。
HTIMER_SECOND_NUM / 2, //netflood的QUEUETIME功能
1, //netflood的dups功能
2, //最大跳跃次数层级为5级,即数据包最多可以经过5次转发,超出就丢弃数据包
FALSE, //在路由请求的转发过程中,收到了新的需要转发的数据包,旧数据包是立刻发送出去还是丢弃,FALSE为立刻发送,TRUE为丢弃。
50, //网络恢复参数,该值定义了一个差距,如果包序号比内存内保存的数据包序号小的值大于此值,则会认为网络故障恢复,继续接收该数据包。
//同时,该值也决定了判定为新数据包的差值,即来自同一个节点的新数据包的序号不可以比内存中的大过多,即比此值还大。
//例如,内存中保存的为10,新数据包序号为60,差值为50,大于等于此时设置的50,所以将不会被认为为新的数据包,被丢弃。
//只有序号为59,差值为49,小于该值,才会被接收。
route_enable, //是否使能本机的路由功能,如果为false,不会响应其他节点的路由请求。
TRUE, //决定是否添加路由回路,比如收到了一个来自a节点的mesh数据包,本机是否需要存储前往a节点的路由表。FALSE不存,TRUE存。
HTIMER_SECOND_NUM * 2, //路由超时时间,超过时间,停止寻找路由,进入timeout回调,该值应大于 route_discovery_hoptime * (hops+1) * 2
&callbacks); //没有初始化路由表的话,会返回0,代表打开失败。返回1打开成功。
if(MESH_TEST_SELF_ADDR_IDX == 0)
{ //如果是主机,则开始周期性轮训其他节点。
mesh_test_send_dst = 1;
tmos_start_task(lwns_mesh_test_taskID, MESH_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(200));
#if MESH_TEST_ROUTE_AUTO
PRINTF("Auto route\n");
#else
uint8_t i;
for(i = 1; i < 5; i++)
{
lwns_route_add(&device_addr[i], &device_addr[1], 2); //手动管理,添加路由条目
}
for(i = 5; i < 9; i++)
{
lwns_route_add(&device_addr[i], &device_addr[5], 2); //手动管理,添加路由条目
}
for(i = 9; i < 13; i++)
{
lwns_route_add(&device_addr[i], &device_addr[9], 2); //手动管理,添加路由条目
}
}
else if(MESH_TEST_SELF_ADDR_IDX == 1)
{
lwns_route_add(&device_addr[4], &device_addr[4], 1); //手动管理,添加路由条目
lwns_route_add(&device_addr[3], &device_addr[3], 1); //手动管理,添加路由条目
lwns_route_add(&device_addr[2], &device_addr[2], 1); //手动管理,添加路由条目
lwns_route_add(&device_addr[0], &device_addr[0], 1); //手动管理,添加路由条目
}
else if(MESH_TEST_SELF_ADDR_IDX == 2)
{
lwns_route_add(&device_addr[0], &device_addr[1], 2); //手动管理,添加路由条目
}
else if(MESH_TEST_SELF_ADDR_IDX == 3)
{
lwns_route_add(&device_addr[0], &device_addr[1], 2); //手动管理,添加路由条目
}
else if(MESH_TEST_SELF_ADDR_IDX == 4)
{
lwns_route_add(&device_addr[0], &device_addr[1], 2); //手动管理,添加路由条目
}
else if(MESH_TEST_SELF_ADDR_IDX == 5)
{
lwns_route_add(&device_addr[6], &device_addr[6], 1); //手动管理,添加路由条目
lwns_route_add(&device_addr[7], &device_addr[7], 1); //手动管理,添加路由条目
lwns_route_add(&device_addr[8], &device_addr[8], 1); //手动管理,添加路由条目
lwns_route_add(&device_addr[0], &device_addr[0], 1); //手动管理,添加路由条目
}
else if(MESH_TEST_SELF_ADDR_IDX == 6)
{
lwns_route_add(&device_addr[0], &device_addr[5], 2); //手动管理,添加路由条目
}
else if(MESH_TEST_SELF_ADDR_IDX == 7)
{
lwns_route_add(&device_addr[0], &device_addr[5], 2); //手动管理,添加路由条目
}
else if(MESH_TEST_SELF_ADDR_IDX == 8)
{
lwns_route_add(&device_addr[0], &device_addr[5], 2); //手动管理,添加路由条目
}
else if(MESH_TEST_SELF_ADDR_IDX == 9)
{
lwns_route_add(&device_addr[10], &device_addr[10], 1); //手动管理,添加路由条目
lwns_route_add(&device_addr[11], &device_addr[11], 1); //手动管理,添加路由条目
lwns_route_add(&device_addr[12], &device_addr[12], 1); //手动管理,添加路由条目
lwns_route_add(&device_addr[0], &device_addr[0], 1); //手动管理,添加路由条目
}
else if(MESH_TEST_SELF_ADDR_IDX == 10)
{
lwns_route_add(&device_addr[0], &device_addr[9], 2); //手动管理,添加路由条目
}
else if(MESH_TEST_SELF_ADDR_IDX == 11)
{
lwns_route_add(&device_addr[0], &device_addr[9], 2); //手动管理,添加路由条目
}
else if(MESH_TEST_SELF_ADDR_IDX == 12)
{
lwns_route_add(&device_addr[0], &device_addr[9], 2); //手动管理,添加路由条目
#endif /*MESH_TEST_ROUTE_AUTO*/
}
}
/*********************************************************************
* @fn lwns_mesh_test_ProcessEvent
*
* @brief lwns mesh Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed.
*/
static uint16_t lwns_mesh_test_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & MESH_EXAMPLE_TX_PERIOD_EVT)
{ //主机周期性轮询从机任务
uint8_t temp;
struct lwns_route_entry *rt;
temp = TX_DATA[0];
for(uint8_t i = 0; i < 9; i++)
{
TX_DATA[i] = TX_DATA[i + 1]; //移位发送数据,以便观察效果
}
TX_DATA[9] = temp;
lwns_buffer_load_data(TX_DATA, sizeof(TX_DATA)); //载入需要发送的数据到缓冲区
rt = lwns_route_lookup(&device_addr[mesh_test_send_dst]); //在路由表中寻找下一跳路由
if(rt != NULL)
{
//打印下一跳路由信息
PRINTF("dst:%d,forwarding to %02x.%02x.%02x.%02x.%02x.%02x\n",
mesh_test_send_dst, rt->nexthop.v8[0], rt->nexthop.v8[1],
rt->nexthop.v8[2], rt->nexthop.v8[3], rt->nexthop.v8[4],
rt->nexthop.v8[5]);
}
else
{
PRINTF("no route to dst:%d\n", mesh_test_send_dst);
}
lwns_mesh_send(&lwns_mesh_test, &device_addr[mesh_test_send_dst]); //发送mesh消息
mesh_test_send_dst++; //轮询目标节点改为下一个
if(mesh_test_send_dst > MESH_TEST_ADDR_MAX_IDX)
{ //循环往复轮询
mesh_test_send_dst = 1;
}
tmos_start_task(lwns_mesh_test_taskID, MESH_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(2500)); //周期性轮询
return (events ^ MESH_EXAMPLE_TX_PERIOD_EVT);
}
if(events & MESH_EXAMPLE_TX_NODE_EVT)
{ //节点给主机发送数据的任务
struct lwns_route_entry *rt;
lwns_buffer_load_data(TX_DATA, sizeof(TX_DATA)); //载入需要发送的数据到缓冲区
rt = lwns_route_lookup(&device_addr[0]); //在路由表中寻找下一跳路由
if(rt != NULL)
{
//打印出下一跳路由信息
PRINTF("src:%d,forwarding to %02x.%02x.%02x.%02x.%02x.%02x\n",
MESH_TEST_SELF_ADDR_IDX, rt->nexthop.v8[0],
rt->nexthop.v8[1], rt->nexthop.v8[2], rt->nexthop.v8[3],
rt->nexthop.v8[4], rt->nexthop.v8[5]);
}
lwns_mesh_send(&lwns_mesh_test, &device_addr[0]); //调用mesh发送函数,进行数据的发送
return (events ^ MESH_EXAMPLE_TX_NODE_EVT);
}
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(task_id)) != NULL)
{
// Release the TMOS message
tmos_msg_deallocate(pMsg);
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
@@ -0,0 +1,163 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_multicast_example.c
* Author : WCH
* Version : V1.0
* Date : 2021/06/20
* Description : single-hop multicast,组播传输例子
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "lwns_multicast_example.h"
//每个文件单独debug打印的开关,置0可以禁止本文件内部打印
#define DEBUG_PRINT_IN_THIS_FILE 1
#if DEBUG_PRINT_IN_THIS_FILE
#define PRINTF(...) PRINT(__VA_ARGS__)
#else
#define PRINTF(...) \
do \
{ \
} while(0)
#endif
static uint8_t subaddrs_index = 0; //发送订阅地址序号
#define SUBADDR_NUM 3 //订阅地址数量
static uint16_t subaddrs[SUBADDR_NUM] = {1, 2, 3}; //订阅地址数组
static uint8_t TX_DATA[10] =
{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
static uint8_t RX_DATA[10];
static uint16_t lwns_multicast_ProcessEvent(uint8_t task_id, uint16_t events);
static void multicast_recv(lwns_controller_ptr c, uint16_t subaddr, const lwns_addr_t *sender); //组播接收回调函数
static void multicast_sent(lwns_controller_ptr ptr); //组播发送完成回调函数
static lwns_multicast_controller multicast; //声明组播控制结构体
static uint8_t multicast_taskID; //声明组播控制任务id
/*********************************************************************
* @fn multicast_recv
*
* @brief lwns multicast接收回调函数
*
* @param ptr - 本次接收到的数据所属的组播控制结构体指针.
* @param subaddr - 本次接收到的数据的订阅地址.
* @param sender - 本次接收到的数据的发送者地址指针.
*
* @return None.
*/
static void multicast_recv(lwns_controller_ptr ptr, uint16_t subaddr, const lwns_addr_t *sender)
{
uint8_t len;
len = lwns_buffer_datalen(); //获取当前缓冲区接收到的数据长度
if(len == 10)
{
lwns_buffer_save_data(RX_DATA); //接收数据到用户数据区域
PRINTF("multicast %d rec from %02x %02x %02x %02x %02x %02x\n",
get_lwns_object_port(ptr),
sender->v8[0], sender->v8[1], sender->v8[2], sender->v8[3],
sender->v8[4], sender->v8[5]); //from为接收到的数据的发送方地址
PRINTF("subaddr:%d data:", subaddr);
for(uint8_t i = 0; i < len; i++)
{
PRINTF("%02x ", RX_DATA[i]);
}
PRINTF("\n");
}
else
{
PRINTF("data len err\n");
}
}
/*********************************************************************
* @fn multicast_sent
*
* @brief lwns multicast发送完成回调函数
*
* @param ptr - 本次发送完成的组播控制结构体指针.
*
* @return None.
*/
static void multicast_sent(lwns_controller_ptr ptr)
{
PRINTF("multicast %d sent\n", get_lwns_object_port(ptr));
}
/**
* lwns组播回调函数结构体,注册回调函数
*/
static const struct lwns_multicast_callbacks multicast_callbacks =
{multicast_recv, multicast_sent};
/*********************************************************************
* @fn lwns_multicast_process_init
*
* @brief lwns multicast例程初始化.
*
* @param None.
*
* @return None.
*/
void lwns_multicast_process_init(void)
{
multicast_taskID = TMOS_ProcessEventRegister(lwns_multicast_ProcessEvent);
lwns_multicast_init(&multicast,
136, //打开一个端口号为136的组播
subaddrs, //订阅地址数组指针
SUBADDR_NUM, //订阅地址数量
&multicast_callbacks); //返回0代表打开失败。返回1打开成功。
tmos_start_task(multicast_taskID, MULTICAST_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(1000));
}
/*********************************************************************
* @fn lwns_multicast_ProcessEvent
*
* @brief lwns multicast Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed.
*/
uint16_t lwns_multicast_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & MULTICAST_EXAMPLE_TX_PERIOD_EVT)
{ //周期性在不同的组播地址上发送组播消息
uint8_t temp;
temp = TX_DATA[0];
for(uint8_t i = 0; i < 9; i++)
{
TX_DATA[i] = TX_DATA[i + 1]; //移位发送数据,以便观察效果
}
TX_DATA[9] = temp;
lwns_buffer_load_data(TX_DATA, sizeof(TX_DATA)); //载入需要发送的数据到缓冲区
if(subaddrs_index >= SUBADDR_NUM)
{
subaddrs_index = 0;
}
lwns_multicast_send(&multicast, subaddrs[subaddrs_index]); //组播发送数据给指定节点
subaddrs_index++;
tmos_start_task(multicast_taskID, MULTICAST_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(1000)); //周期性发送
return events ^ MULTICAST_EXAMPLE_TX_PERIOD_EVT;
}
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(task_id)) != NULL)
{
// Release the TMOS message
tmos_msg_deallocate(pMsg);
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
@@ -0,0 +1,177 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_multinetflood_example.c
* Author : WCH
* Version : V1.0
* Date : 2021/11/10
* Description : multinetflood,组播网络泛洪传输例子
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "lwns_multinetflood_example.h"
//每个文件单独debug打印的开关,置0可以禁止本文件内部打印
#define DEBUG_PRINT_IN_THIS_FILE 1
#if DEBUG_PRINT_IN_THIS_FILE
#define PRINTF(...) PRINT(__VA_ARGS__)
#else
#define PRINTF(...) \
do \
{ \
} while(0)
#endif
/*
* 订阅的地址为2字节u16类型。
*/
static uint8_t subaddrs_index = 0; //发送订阅地址序号
#define SUBADDR_NUM 3 //订阅地址数量
static uint16_t subaddrs[SUBADDR_NUM] = {1, 2, 3}; //订阅地址数组
static uint8_t TX_DATA[LWNS_DATA_SIZE] = {0}; //最大长度数据收发测试
static uint8_t RX_DATA[LWNS_DATA_SIZE] = {0}; //最大长度数据收发测试
static uint16_t lwns_multinetflood_ProcessEvent(uint8_t task_id, uint16_t events);
static void multinetflood_recv(lwns_controller_ptr ptr, uint16_t subaddr, const lwns_addr_t *sender, uint8_t hops); //组播网络泛洪接收回调函数
static void multinetflood_sent(lwns_controller_ptr ptr); //组播网络泛洪发送完成回调函数
static lwns_multinetflood_controller multinetflood; //声明组播网络泛洪控制结构体
static uint8_t multinetflood_taskID; //组播网络泛洪控制任务id
/*********************************************************************
* @fn multinetflood_recv
*
* @brief lwns multinetflood接收回调函数
*
* @param ptr - 本次接收到的数据所属的multinetflood控制结构体指针.
* @param subaddr - 本次接收到的数据的订阅地址.
* @param sender - 本次接收到的数据的发送者地址指针.
* @param hops - 本次接收到的数据的从发送方到本节点经历的跳数.
*
* @return None.
*/
static void multinetflood_recv(lwns_controller_ptr ptr, uint16_t subaddr, const lwns_addr_t *sender, uint8_t hops)
{
uint8_t len;
len = lwns_buffer_datalen(); //获取当前缓冲区接收到的数据长度
lwns_buffer_save_data(RX_DATA); //接收数据到用户数据区域
PRINTF("multinetflood %d rec from %02x %02x %02x %02x %02x %02x\n",
get_lwns_object_port(ptr),
sender->v8[0], sender->v8[1], sender->v8[2], sender->v8[3],
sender->v8[4], sender->v8[5]); //from为接收到的数据的发送方地址
PRINTF("subaddr:%d,data:", subaddr);
for(uint8_t i = 0; i < len; i++)
{
PRINTF("%02x ", RX_DATA[i]); //打印出数据
}
PRINTF("\n");
}
/*********************************************************************
* @fn multinetflood_sent
*
* @brief lwns multinetflood发送完成回调函数
*
* @param ptr - 本次发送完成的组播网络泛洪控制结构体指针.
*
* @return None.
*/
static void multinetflood_sent(lwns_controller_ptr ptr)
{
PRINTF("multinetflood %d sent\n", get_lwns_object_port(ptr));
}
/**
* lwns 组播网络泛洪回调函数结构体,注册回调函数
*/
static const struct lwns_multinetflood_callbacks multinetflood_callbacks =
{multinetflood_recv, multinetflood_sent};
/*********************************************************************
* @fn lwns_multinetflood_process_init
*
* @brief lwns multinetflood例程初始化.
*
* @param None.
*
* @return None.
*/
void lwns_multinetflood_process_init(void)
{
multinetflood_taskID = TMOS_ProcessEventRegister(lwns_multinetflood_ProcessEvent);
for(uint8_t i = 0; i < LWNS_DATA_SIZE; i++)
{
TX_DATA[i] = i;
}
lwns_multinetflood_init(&multinetflood,
137, //打开一个端口号为137的组播网络泛洪结构体
HTIMER_SECOND_NUM, //最大等待转发时间
1, //在等待期间,接收到几次同样的数据包就取消本数据包的发送
3, //最大转发层级
FALSE, //在等待转发过程中,收到了新的需要转发的数据包,旧数据包是立刻发送出去还是丢弃,FALSE为立刻发送,TRUE为丢弃。
50, //网络恢复参数,该值定义了一个差距,如果包序号比内存内保存的数据包序号小的值大于此值,则会认为网络故障恢复,继续接收该数据包。
//同时,该值也决定了判定为新数据包的差值,即来自同一个节点的新数据包的序号不可以比内存中的大过多,即比此值还大。
//例如,内存中保存的为10,新数据包序号为60,差值为50,大于等于此时设置的50,所以将不会被认为为新的数据包,被丢弃。
//只有序号为59,差值为49,小于该值,才会被接收。
TRUE, //本机是否转发目标非本机的数据包,类似于蓝牙mesh是否启用relay功能。
subaddrs, //订阅的地址数组指针
SUBADDR_NUM, //订阅地址数量
&multinetflood_callbacks); //返回0代表打开失败。返回1打开成功。
#if 1
tmos_start_task(multinetflood_taskID, MULTINETFLOOD_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(1000));
#endif
}
/*********************************************************************
* @fn lwns_multinetflood_ProcessEvent
*
* @brief lwns multinetflood Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed.
*/
uint16_t lwns_multinetflood_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & MULTINETFLOOD_EXAMPLE_TX_PERIOD_EVT)
{
uint8_t temp;
temp = TX_DATA[0];
for(uint8_t i = 0; i < 9; i++)
{
TX_DATA[i] = TX_DATA[i + 1]; //移位发送数据,以便观察效果
}
TX_DATA[9] = temp;
lwns_buffer_load_data(TX_DATA, sizeof(TX_DATA)); //载入需要发送的数据到缓冲区
if(subaddrs_index >= SUBADDR_NUM)
{
subaddrs_index = 0;
}
lwns_multinetflood_send(&multinetflood, subaddrs[subaddrs_index]); //组播网络泛洪发送数据到订阅地址
subaddrs_index++;
tmos_start_task(multinetflood_taskID, MULTINETFLOOD_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(1000)); //周期性发送
return events ^ MULTINETFLOOD_EXAMPLE_TX_PERIOD_EVT;
}
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(task_id)) != NULL)
{
// Release the TMOS message
tmos_msg_deallocate(pMsg);
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
@@ -0,0 +1,179 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_netflood_example.c
* Author : WCH
* Version : V1.0
* Date : 2021/07/12
* Description : netflood,网络泛洪传输例子
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "lwns_netflood_example.h"
//每个文件单独debug打印的开关,置0可以禁止本文件内部打印
#define DEBUG_PRINT_IN_THIS_FILE 1
#if DEBUG_PRINT_IN_THIS_FILE
#define PRINTF(...) PRINT(__VA_ARGS__)
#else
#define PRINTF(...) \
do \
{ \
} while(0)
#endif
static uint8_t TX_DATA[LWNS_DATA_SIZE] = {0}; //最大长度数据收发测试
static uint8_t RX_DATA[LWNS_DATA_SIZE] = {0}; //最大长度数据收发测试
static uint16_t lwns_netflood_ProcessEvent(uint8_t task_id, uint16_t events);
static int netflood_recv(lwns_controller_ptr ptr,
const lwns_addr_t *from,
const lwns_addr_t *originator, uint8_t hops);
static void netflood_sent(lwns_controller_ptr ptr);
static void netflood_dropped(lwns_controller_ptr ptr);
/**
* lwns 网络泛洪回调函数结构体,注册回调函数
*/
static const struct lwns_netflood_callbacks callbacks = {netflood_recv,
netflood_sent, netflood_dropped};
static uint8_t netflood_taskID;
void lwns_netflood_process_init(void);
static lwns_netflood_controller netflood; //网络泛洪控制结构体
/*********************************************************************
* @fn netflood_recv
*
* @brief lwns netflood接收回调函数
*
* @param ptr - 本次接收到的数据所属的netflood控制结构体指针.
* @param from - 本次接收到的数据的上一跳转发者的地址指针.
* @param originator - 本次接收到的数据的发送者地址指针.
* @param hops - 本次接收到的数据的从发送方到本节点经历的跳数.
*
* @return 0/1 - 0表示本节点不再转发该数据包,1表示本节点继续转发该数据包.
*/
static int netflood_recv(lwns_controller_ptr ptr,
const lwns_addr_t *from,
const lwns_addr_t *originator, uint8_t hops)
{
uint8_t len;
len = lwns_buffer_datalen(); //获取当前缓冲区接收到的数据长度
PRINTF("netflood %d rec %02x %02x %02x %02x %02x %02x,hops=%d\r\n", get_lwns_object_port(ptr),
from->v8[0], from->v8[1], from->v8[2], from->v8[3], from->v8[4],
from->v8[5], hops); //打印转发者,即为收到的本次转发数据是谁转发的。
PRINTF("netflood orec %02x %02x %02x %02x %02x %02x,hops=%d\r\n",
originator->v8[0], originator->v8[1], originator->v8[2],
originator->v8[3], originator->v8[4], originator->v8[5],
hops); //打印出信息发起者,即为发起本次网络泛洪的节点地址。
lwns_buffer_save_data(RX_DATA); //接收数据到用户数据区域
PRINTF("data:");
for(uint8_t i = 0; i < len; i++)
{
PRINTF("%02x ", RX_DATA[i]);
}
PRINTF("\n");
return 1; //返回1,则本节点将继续发送netflood,转发数据
//return 0;//返回0,则本节点不再继续netflood,直接终止
}
/*********************************************************************
* @fn netflood_sent
*
* @brief lwns netflood发送完成回调函数
*
* @param ptr - 本次发送完成的网络泛洪控制结构体指针.
*
* @return None.
*/
static void netflood_sent(lwns_controller_ptr ptr)
{
PRINTF("netflood %d sent\n", get_lwns_object_port(ptr));
}
/*********************************************************************
* @fn netflood_dropped
*
* @brief lwns netflood数据包丢弃回调函数
*
* @param ptr - 本次发送完成的网络泛洪控制结构体指针.
*
* @return None.
*/
static void netflood_dropped(lwns_controller_ptr ptr)
{
PRINTF("netflood %d dropped\n", get_lwns_object_port(ptr));
}
/*********************************************************************
* @fn lwns_netflood_process_init
*
* @brief lwns netflood例程初始化.
*
* @param None.
*
* @return None.
*/
void lwns_netflood_process_init(void)
{
netflood_taskID = TMOS_ProcessEventRegister(lwns_netflood_ProcessEvent);
for(uint8_t i = 0; i < LWNS_DATA_SIZE; i++)
{
TX_DATA[i] = i;
}
lwns_netflood_init(&netflood,
137, //打开一个端口号为137的泛洪结构体
HTIMER_SECOND_NUM * 1, //等待转发时间
1, //在等待期间,接收到几次同样的数据包就取消本数据包的发送
3, //最大转发层级
FALSE, //在等待转发过程中,收到了新的需要转发的数据包,旧数据包是立刻发送出去还是丢弃,FALSE为立刻发送,TRUE为丢弃。
50, //网络恢复参数,该值定义了一个差距,如果包序号比内存内保存的数据包序号小的值大于此值,则会认为网络故障恢复,继续接收该数据包。
//同时,该值也决定了判定为新数据包的差值,即来自同一个节点的新数据包的序号不可以比内存中的大过多,即比此值还大。
//例如,内存中保存的为10,新数据包序号为60,差值为50,大于等于此时设置的50,所以将不会被认为为新的数据包,被丢弃。
//只有序号为59,差值为49,小于该值,才会被接收。
&callbacks); //返回0代表打开失败。返回1打开成功。
#if 1
tmos_start_task(netflood_taskID, NETFLOOD_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(1000));
#endif
}
/*********************************************************************
* @fn lwns_netflood_ProcessEvent
*
* @brief lwns netflood Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed.
*/
static uint16_t lwns_netflood_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & NETFLOOD_EXAMPLE_TX_PERIOD_EVT)
{
PRINTF("send\n");
lwns_buffer_load_data(TX_DATA, sizeof(TX_DATA)); //载入需要发送的数据到缓冲区
lwns_netflood_send(&netflood); //发送网络泛洪数据包
tmos_start_task(netflood_taskID, NETFLOOD_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(3000)); //10s发送一次
return (events ^ NETFLOOD_EXAMPLE_TX_PERIOD_EVT);
}
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(task_id)) != NULL)
{
// Release the TMOS message
tmos_msg_deallocate(pMsg);
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
+188
View File
@@ -0,0 +1,188 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_ruc_example.c
* Author : WCH
* Version : V1.0
* Date : 2021/06/30
* Description : reliable unicast,可靠单播传输例子
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "lwns_ruc_example.h"
//每个文件单独debug打印的开关,置0可以禁止本文件内部打印
#define DEBUG_PRINT_IN_THIS_FILE 1
#if DEBUG_PRINT_IN_THIS_FILE
#define PRINTF(...) PRINT(__VA_ARGS__)
#else
#define PRINTF(...) \
do \
{ \
} while(0)
#endif
#if 1
static lwns_addr_t dst_addr = {{0xa3, 0xdf, 0x38, 0xe4, 0xc2, 0x84}}; //目标节点地址,测试时,请根据电路板芯片MAC地址不同进行修改。修改为接收方的MAC地址,请勿使用自己的MAC地址
#else
static lwns_addr_t dst_addr = {{0xd9, 0x37, 0x3c, 0xe4, 0xc2, 0x84}};
#endif
static lwns_ruc_controller ruc; //声明可靠单播控制结构体
static uint8_t TX_DATA[10] =
{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
static uint8_t RX_DATA[10];
static uint8_t ruc_taskID;
uint16_t lwns_ruc_ProcessEvent(uint8_t task_id, uint16_t events);
static void recv_ruc(lwns_controller_ptr ptr,
const lwns_addr_t *sender);
static void sent_ruc(lwns_controller_ptr ptr,
const lwns_addr_t *to, uint8_t retransmissions);
static void timedout_ruc(lwns_controller_ptr ptr,
const lwns_addr_t *to);
/*********************************************************************
* @fn recv_ruc
*
* @brief lwns ruc接收回调函数
*
* @param ptr - 本次接收到的数据所属的可靠单播控制结构体指针.
* @param sender - 本次接收到的数据的发送者地址指针.
*
* @return None.
*/
static void recv_ruc(lwns_controller_ptr ptr,
const lwns_addr_t *sender)
{
//ruc中接收到发送给自己的数据后,才会调用该回调
uint8_t len;
len = lwns_buffer_datalen(); //获取当前缓冲区接收到的数据长度
if(len == 10)
{
lwns_buffer_save_data(RX_DATA); //接收数据到用户数据区域
PRINTF("ruc %d rec %02x %02x %02x %02x %02x %02x\r\n", get_lwns_object_port(ptr), sender->v8[0],
sender->v8[1], sender->v8[2], sender->v8[3], sender->v8[4], sender->v8[5]);
PRINTF("data:");
for(uint8_t i = 0; i < len; i++)
{
PRINTF("%02x ", RX_DATA[i]);
}
PRINTF("\n");
}
else
{
PRINTF("data len err\n");
}
}
/*********************************************************************
* @fn sent_ruc
*
* @brief lwns ruc发送完成回调函数
*
* @param ptr - 本次发送完成的可靠单播控制结构体指针.
*
* @return None.
*/
static void sent_ruc(lwns_controller_ptr ptr,
const lwns_addr_t *to, uint8_t retransmissions)
{
//ruc中发送成功,并且收到目标节点的ack回复后,才会调用该回调
PRINTF("ruc %d sent %d\r\n", get_lwns_object_port(ptr), retransmissions);
tmos_start_task(ruc_taskID, RUC_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(1000)); //更新任务时间,发送并收到回复后,1秒钟后再发送
}
/*********************************************************************
* @fn timedout_ruc
*
* @brief lwns ruc发送超时回调函数
*
* @param ptr - 本次发送完成的ruc控制结构体指针.
*
* @return None.
*/
static void timedout_ruc(lwns_controller_ptr ptr,
const lwns_addr_t *to)
{
//ruc中,再重发次数超过最大重发次数后,会调用该回调。
PRINTF("ruc %d timedout\n", get_lwns_object_port(ptr));
tmos_start_task(ruc_taskID, RUC_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(1000));
}
/**
* lwns 可靠单播回调函数结构体,注册回调函数
*/
static const struct lwns_ruc_callbacks ruc_callbacks = {
recv_ruc, sent_ruc, timedout_ruc}; //声明可靠单播回调结构体
/*********************************************************************
* @fn lwns_ruc_process_init
*
* @brief lwns ruc例程初始化.
*
* @param None.
*
* @return None.
*/
void lwns_ruc_process_init(void)
{
lwns_ruc_init(&ruc,
144, //打开一个端口号为144的可靠单播
HTIMER_SECOND_NUM, //等待ack时间间隔,没收到就会重发
&ruc_callbacks); //返回0代表打开失败。返回1打开成功。
ruc_taskID = TMOS_ProcessEventRegister(lwns_ruc_ProcessEvent);
tmos_start_task(ruc_taskID, RUC_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(1000));
}
/*********************************************************************
* @fn lwns_ruc_ProcessEvent
*
* @brief lwns ruc Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed.
*/
uint16_t lwns_ruc_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & RUC_EXAMPLE_TX_PERIOD_EVT)
{
uint8_t temp;
temp = TX_DATA[0];
for(uint8_t i = 0; i < 9; i++)
{
TX_DATA[i] = TX_DATA[i + 1]; //移位发送数据,以便观察效果
}
TX_DATA[9] = temp;
lwns_buffer_load_data(TX_DATA, sizeof(TX_DATA)); //载入需要发送的数据到缓冲区
lwns_ruc_send(&ruc,
&dst_addr, //可靠单播目标地址
4 //最大重发次数
); //可靠单播发送函数:发送参数,目标地址,最大重发次数,默认一秒钟重发一次
return events ^ RUC_EXAMPLE_TX_PERIOD_EVT;
}
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(task_id)) != NULL)
{
// Release the TMOS message
tmos_msg_deallocate(pMsg);
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
+208
View File
@@ -0,0 +1,208 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_rucft_example.c
* Author : WCH
* Version : V1.0
* Date : 2021/06/30
* Description : reliable unicast file transfer,可靠单播文件传输例子
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "lwns_rucft_example.h"
//每个文件单独debug打印的开关,置0可以禁止本文件内部打印
#define DEBUG_PRINT_IN_THIS_FILE 1
#if DEBUG_PRINT_IN_THIS_FILE
#define PRINTF(...) PRINT(__VA_ARGS__)
#else
#define PRINTF(...) \
do \
{ \
} while(0)
#endif
#if 1
static lwns_addr_t dst_addr = {{0x66, 0xdf, 0x38, 0xe4, 0xc2, 0x84}}; //目标节点地址,测试时,请根据电路板芯片MAC地址不同进行修改。修改为接收方的MAC地址,请勿使用自己的MAC地址
#else
static lwns_addr_t dst_addr = {{0xd9, 0x37, 0x3c, 0xe4, 0xc2, 0x84}};
#endif
static uint8_t rucft_taskID;
static lwns_rucft_controller rucft; //声明rucft控制结构体
#define FILESIZE 4000
static char strsend[FILESIZE]; //发送缓冲区
static char *strp;
static void write_file(lwns_controller_ptr ptr, const lwns_addr_t *sender,
int offset, int flag, char *data, int datalen);
static int read_file(lwns_controller_ptr ptr, int offset, char *to);
static void timedout_rucft(lwns_controller_ptr ptr);
/**
* lwns 可靠单播文件传输回调函数结构体,注册回调函数
*/
const static struct lwns_rucft_callbacks rucft_callbacks = {write_file,
read_file, timedout_rucft};
uint16_t lwns_rucft_ProcessEvent(uint8_t task_id, uint16_t events);
/*********************************************************************
* @fn write_file
*
* @brief lwns rucft接收回调函数,作为写入文件回调函数
*
* @param ptr - 本次接收到的数据所属的netflood控制结构体指针.
* @param sender - 本次接收到的数据的发送者地址指针.
* @param offset - 本次接收到的数据的偏移量,也是本次文件传输接收已经收到的数据量.
* @param flag - 本次接收到数据的标志,LWNS_RUCFT_FLAG_NONE/LWNS_RUCFT_FLAG_NEWFILE/LWNS_RUCFT_FLAG_END.
* @param data - 本次接收到的数据的头指针.
* @param datalen - 本次接收到的数据的长度.
*
* @return None.
*/
static void write_file(lwns_controller_ptr ptr, const lwns_addr_t *sender,
int offset, int flag, char *data, int datalen)
{
//sender为发送方的地址
//如果需要接收不同的文件,需要在此函数中做好接口
if(datalen > 0)
{ //声明个缓冲从data里取数据打印
PRINTF("r:%c\n", *data);
}
if(flag == LWNS_RUCFT_FLAG_END)
{
PRINTF("re\n");
//本次文件传输的最后一个包
}
else if(flag == LWNS_RUCFT_FLAG_NONE)
{
PRINTF("ru\n");
//本次文件传输正常的包
}
else if(flag == LWNS_RUCFT_FLAG_NEWFILE)
{
PRINTF("rn\n");
//本次文件传输的第一个包
}
}
/*********************************************************************
* @fn read_file
*
* @brief lwns rucft发送完成回调函数,作为读取文件回调函数
*
* @param ptr - 本次接收到的数据所属的netflood控制结构体指针.
* @param offset - 本次接收到的数据的偏移量,也是本次文件传输发送已经发送的数据量.
* @param to - 本次需要发送的数据缓冲区的头指针,用户将数据拷贝到此指针指向的内存空间。.
*
* @return size - 返回的size即为本次需要发送的数据长度,不可大于LWNS_RUCFT_DATASIZE.
*/
static int read_file(lwns_controller_ptr ptr, int offset, char *to)
{
//to为需要保存数据过去的指针
//如果需要发送不同的文件,需要在此函数中做好接口
int size = LWNS_RUCFT_DATASIZE;
if(offset >= FILESIZE)
{
//上次已经发完,本次是最后确认
PRINTF("Send done\n");
tmos_start_task(rucft_taskID, RUCFT_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(5000)); //5秒钟后继续发送测试
return 0;
}
else if(offset + LWNS_RUCFT_DATASIZE >= FILESIZE)
{
size = FILESIZE - offset;
}
//把本次需要发送的内容压进包缓冲
tmos_memcpy(to, strp + offset, size);
return size;
}
/*********************************************************************
* @fn timedout_rucft
*
* @brief lwns rucft发送超时回调函数
*
* @param ptr - 本次发送完成的ruc控制结构体指针.
*
* @return None.
*/
static void timedout_rucft(lwns_controller_ptr ptr)
{
//rucft中,发送方再重发次数超过最大重发次数后,会调用该回调。
//接收方超时没接收到下一个包也会调用
PRINTF("rucft %d timedout\r\n", get_lwns_object_port(ptr));
}
/*********************************************************************
* @fn lwns_rucft_process_init
*
* @brief lwns rucft例程初始化.
*
* @param None.
*
* @return None.
*/
void lwns_rucft_process_init(void)
{
lwns_addr_t MacAddr;
rucft_taskID = TMOS_ProcessEventRegister(lwns_rucft_ProcessEvent);
lwns_rucft_init(&rucft, 137, //端口号
HTIMER_SECOND_NUM / 10, //等待目标节点ack时间
5, //最大重发次数,与ruc中的ruc_send的重发次数功能一样
&rucft_callbacks //回调函数
); //返回0代表打开失败。返回1打开成功。
int i;
for(i = 0; i < FILESIZE; i++)
{ //LWNS_RUCFT_DATASIZE个LWNSNK_RUCFT_DATASIZE个b,等等,初始化需要发送的数据
strsend[i] = 'a' + i / LWNS_RUCFT_DATASIZE;
}
strp = strsend;
FLASH_GetMACAddress(MacAddr.v8);
if(lwns_addr_cmp(&MacAddr, &dst_addr))
{
}
else
{
tmos_start_task(rucft_taskID, RUCFT_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(1000));
}
}
/*********************************************************************
* @fn lwns_rucft_ProcessEvent
*
* @brief lwns rucft Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed.
*/
uint16_t lwns_rucft_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & RUCFT_EXAMPLE_TX_PERIOD_EVT)
{
PRINTF("send\n");
lwns_rucft_send(&rucft, &dst_addr); //开始发送至目标节点,用户启用发送时要配置好回调函数中的数据包读取
return events ^ RUCFT_EXAMPLE_TX_PERIOD_EVT;
}
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(task_id)) != NULL)
{
// Release the TMOS message
tmos_msg_deallocate(pMsg);
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
+75
View File
@@ -0,0 +1,75 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_sec.c
* Author : WCH
* Version : V1.0
* Date : 2021/09/17
* Description : lwns消息加密
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "lwns_sec.h"
static uint8_t lwns_sec_key[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; //用户自行更改为自己的秘钥,或者改为可以从主机获取,并存储在eeprom中
/*********************************************************************
* @fn lwns_msg_encrypt
*
* @brief lwns消息加密
*
* @param src - 待加密的数据缓冲头指针.
* @param to - 待存储加密数据的数据缓存区头指针.
* @param mlen - 待加密的数据长度.
*
* @return 加密后的数据长度.
*/
int lwns_msg_encrypt(uint8_t *src, uint8_t *to, uint8_t mlen)
{
uint16_t i = 0;
uint8_t esrc[16];
while(1)
{
if((mlen - i) < 16)
{
tmos_memcpy(esrc, src + i, (mlen - i)); //扩充到16字节,其他为0
LL_Encrypt(lwns_sec_key, esrc, to + i);
}
else
{
LL_Encrypt(lwns_sec_key, src + i, to + i);
}
i += 16;
if(i >= mlen)
{
break;
}
}
return i; //返回加密后数据长度
}
/*********************************************************************
* @fn lwns_msg_decrypt
*
* @brief lwns消息解密
*
* @param src - 待解密的数据缓冲头指针.
* @param to - 待存储解密数据的数据缓存区头指针.
* @param mlen - 待解密的数据长度,必须为16的倍数.
*
* @return 解密后的数据长度.
*/
int lwns_msg_decrypt(uint8_t *src, uint8_t *to, uint8_t mlen)
{
unsigned short i = 0;
while(1)
{
LL_Decrypt(lwns_sec_key, src + i, to + i);
i += 16;
if(i >= mlen)
{
break;
}
}
return i;
}
@@ -0,0 +1,158 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_unicast_example.c
* Author : WCH
* Version : V1.0
* Date : 2021/06/19
* Description : lwns单播传输例子
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "lwns_unicast_example.h"
//每个文件单独debug打印的开关,置0可以禁止本文件内部打印
#define DEBUG_PRINT_IN_THIS_FILE 1
#if DEBUG_PRINT_IN_THIS_FILE
#define PRINTF(...) PRINT(__VA_ARGS__)
#else
#define PRINTF(...) \
do \
{ \
} while(0)
#endif
#if 1
static lwns_addr_t dst_addr = {{0xab, 0xdf, 0x38, 0xe4, 0xc2, 0x84}}; //目标节点地址,测试时,请根据电路板芯片MAC地址不同进行修改。修改为接收方的MAC地址,请勿使用自己的MAC地址
#else
static lwns_addr_t dst_addr = {{0xd9, 0x37, 0x3c, 0xe4, 0xc2, 0x84}};
#endif
static uint8_t TX_DATA[10] =
{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
static uint8_t RX_DATA[10];
static uint16_t lwns_unicast_ProcessEvent(uint8_t task_id, uint16_t events);
static void unicast_recv(lwns_controller_ptr c, const lwns_addr_t *from); //单播接收回调函数
static void unicast_sent(lwns_controller_ptr ptr); //单播发送完成回调函数
static lwns_unicast_controller unicast; //声明单播控制结构体
static uint8_t unicast_taskID; //声明单播控制任务id
/*********************************************************************
* @fn unicast_recv
*
* @brief lwns unicast接收回调函数
*
* @param ptr - 本次接收到的数据所属的单播控制结构体指针.
* @param sender - 本次接收到的数据的发送者地址指针.
*
* @return None.
*/
static void unicast_recv(lwns_controller_ptr ptr, const lwns_addr_t *sender)
{
uint8_t len;
len = lwns_buffer_datalen(); //获取当前缓冲区接收到的数据长度
if(len == 10)
{
lwns_buffer_save_data(RX_DATA); //接收数据到用户数据区域
PRINTF("unicast %d rec from %02x %02x %02x %02x %02x %02x\n",
get_lwns_object_port(ptr),
sender->v8[0], sender->v8[1], sender->v8[2], sender->v8[3],
sender->v8[4], sender->v8[5]); //sender为接收到的数据的发送方地址
PRINTF("data:");
for(uint8_t i = 0; i < len; i++)
{
PRINTF("%02x ", RX_DATA[i]);
}
PRINTF("\n");
}
else
{
PRINTF("data len err\n");
}
}
/*********************************************************************
* @fn unicast_sent
*
* @brief lwns unicast发送完成回调函数
*
* @param ptr - 本次发送完成的可靠单播控制结构体指针.
*
* @return None.
*/
static void unicast_sent(lwns_controller_ptr ptr)
{
PRINTF("unicast %d sent\n", get_lwns_object_port(ptr));
}
/**
* lwns 单播回调函数结构体,注册回调函数
*/
static const struct lwns_unicast_callbacks unicast_callbacks =
{unicast_recv, unicast_sent};
/*********************************************************************
* @fn lwns_unicast_process_init
*
* @brief lwns unicast例程初始化.
*
* @param None.
*
* @return None.
*/
void lwns_unicast_process_init(void)
{
unicast_taskID = TMOS_ProcessEventRegister(lwns_unicast_ProcessEvent);
lwns_unicast_init(&unicast,
136, //打开一个端口号为136的单播
&unicast_callbacks); //返回0代表打开失败。返回1打开成功。
tmos_start_task(unicast_taskID, UNICAST_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(1000));
}
/*********************************************************************
* @fn lwns_unicast_ProcessEvent
*
* @brief lwns unicast Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed.
*/
uint16_t lwns_unicast_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & UNICAST_EXAMPLE_TX_PERIOD_EVT)
{
uint8_t temp;
temp = TX_DATA[0];
for(uint8_t i = 0; i < 9; i++)
{
TX_DATA[i] = TX_DATA[i + 1]; //移位发送数据,以便观察效果
}
TX_DATA[9] = temp;
lwns_buffer_load_data(TX_DATA, sizeof(TX_DATA)); //载入需要发送的数据到缓冲区
lwns_unicast_send(&unicast, &dst_addr); //单播发送数据给指定节点
tmos_start_task(unicast_taskID, UNICAST_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(1000)); //周期性发送
return events ^ UNICAST_EXAMPLE_TX_PERIOD_EVT;
}
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(task_id)) != NULL)
{
// Release the TMOS message
tmos_msg_deallocate(pMsg);
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
@@ -0,0 +1,165 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : lwns_uninetflood_example.c
* Author : WCH
* Version : V1.0
* Date : 2021/10/25
* Description : lwns单播网络泛洪传输例子,将数据网络泛洪发送至指定节点
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "lwns_uninetflood_example.h"
//每个文件单独debug打印的开关,置0可以禁止本文件内部打印
#define DEBUG_PRINT_IN_THIS_FILE 1
#if DEBUG_PRINT_IN_THIS_FILE
#define PRINTF(...) PRINT(__VA_ARGS__)
#else
#define PRINTF(...) \
do \
{ \
} while(0)
#endif
#if 1
static lwns_addr_t dst_addr = {{0xa3, 0xdf, 0x38, 0xe4, 0xc2, 0x84}}; //目标节点地址,测试时,请根据电路板芯片MAC地址不同进行修改。修改为接收方的MAC地址,请勿使用自己的MAC地址
#else
static lwns_addr_t dst_addr = {{0xd9, 0x37, 0x3c, 0xe4, 0xc2, 0x84}};
#endif
static uint8_t TX_DATA[LWNS_DATA_SIZE] = {0}; //最大长度数据收发测试
static uint8_t RX_DATA[LWNS_DATA_SIZE] = {0}; //最大长度数据收发测试
static uint16_t lwns_uninetflood_ProcessEvent(uint8_t task_id, uint16_t events);
static void uninetflood_recv(lwns_controller_ptr ptr, const lwns_addr_t *sender, uint8_t hops); //单播网络泛洪接收回调函数
static void uninetflood_sent(lwns_controller_ptr ptr); //单播网络泛洪发送完成回调函数
static lwns_uninetflood_controller uninetflood; //单播网络泛洪控制结构体
static uint8_t uninetflood_taskID; //单播网络泛洪控制任务id
/*********************************************************************
* @fn uninetflood_recv
*
* @brief lwns uninetflood接收回调函数
*
* @param ptr - 本次接收到的数据所属的uninetflood控制结构体指针.
* @param sender - 本次接收到的数据的发送者地址指针.
* @param hops - 本次接收到的数据的从发送方到本节点经历的跳数.
*
* @return None.
*/
static void uninetflood_recv(lwns_controller_ptr ptr, const lwns_addr_t *sender, uint8_t hops)
{
uint8_t len;
len = lwns_buffer_datalen(); //获取当前缓冲区接收到的数据长度
lwns_buffer_save_data(RX_DATA); //接收数据到用户数据区域
PRINTF("uninetflood %d rec from %02x %02x %02x %02x %02x %02x\n",
get_lwns_object_port(ptr),
sender->v8[0], sender->v8[1], sender->v8[2], sender->v8[3],
sender->v8[4], sender->v8[5]); //from为接收到的数据的发送方地址
PRINTF("data:");
for(uint8_t i = 0; i < len; i++)
{
PRINTF("%02x ", RX_DATA[i]); //打印出数据
}
PRINTF("\n");
}
/*********************************************************************
* @fn uninetflood_sent
*
* @brief lwns uninetflood发送完成回调函数
*
* @param ptr - 本次发送完成的可靠单播控制结构体指针.
*
* @return None.
*/
static void uninetflood_sent(lwns_controller_ptr ptr)
{
PRINTF("uninetflood %d sent\n", get_lwns_object_port(ptr));
}
/**
* lwns 单播网络泛洪回调函数结构体,注册回调函数
*/
static const struct lwns_uninetflood_callbacks uninetflood_callbacks =
{uninetflood_recv, uninetflood_sent};
/*********************************************************************
* @fn lwns_uninetflood_process_init
*
* @brief lwns uninetflood例程初始化.
*
* @param None.
*
* @return None.
*/
void lwns_uninetflood_process_init(void)
{
uninetflood_taskID = TMOS_ProcessEventRegister(lwns_uninetflood_ProcessEvent);
for(uint8_t i = 0; i < LWNS_DATA_SIZE; i++)
{
TX_DATA[i] = i;
}
lwns_uninetflood_init(&uninetflood,
137, //打开一个端口号为137的单播网络泛洪结构体
HTIMER_SECOND_NUM * 2, //最大等待转发时间
1, //在等待期间,接收到几次同样的数据包就取消本数据包的发送
3, //最大转发层级
FALSE, //在等待转发过程中,收到了新的需要转发的数据包,旧数据包是立刻发送出去还是丢弃,FALSE为立刻发送,TRUE为丢弃。
50, //网络恢复参数,该值定义了一个差距,如果包序号比内存内保存的数据包序号小的值大于此值,则会认为网络故障恢复,继续接收该数据包。
//同时,该值也决定了判定为新数据包的差值,即来自同一个节点的新数据包的序号不可以比内存中的大过多,即比此值还大。
//例如,内存中保存的为10,新数据包序号为60,差值为50,大于等于此时设置的50,所以将不会被认为为新的数据包,被丢弃。
//只有序号为59,差值为49,小于该值,才会被接收。
TRUE, //本机是否转发目标非本机的数据包,类似于蓝牙mesh是否启用relay功能。
&uninetflood_callbacks); //返回0代表打开失败。返回1打开成功。
tmos_start_task(uninetflood_taskID, UNINETFLOOD_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(1000));
}
/*********************************************************************
* @fn lwns_uninetflood_ProcessEvent
*
* @brief lwns uninetflood Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The TMOS assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return events not processed.
*/
uint16_t lwns_uninetflood_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & UNINETFLOOD_EXAMPLE_TX_PERIOD_EVT)
{
uint8_t temp;
temp = TX_DATA[0];
for(uint8_t i = 0; i < 9; i++)
{
TX_DATA[i] = TX_DATA[i + 1]; //移位发送数据,以便观察效果
}
TX_DATA[9] = temp;
lwns_buffer_load_data(TX_DATA, sizeof(TX_DATA)); //载入需要发送的数据到缓冲区
lwns_uninetflood_send(&uninetflood, &dst_addr); //单播网络泛洪发送数据给目标地址
tmos_start_task(uninetflood_taskID, UNINETFLOOD_EXAMPLE_TX_PERIOD_EVT,
MS1_TO_SYSTEM_TIME(1000)); //周期性发送
return events ^ UNINETFLOOD_EXAMPLE_TX_PERIOD_EVT;
}
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(task_id)) != NULL)
{
// Release the TMOS message
tmos_msg_deallocate(pMsg);
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
+989
View File
@@ -0,0 +1,989 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : system_ch32v20x.c
* Author : WCH
* Version : V1.0.0
* Date : 2021/06/06
* Description : CH32V20x Device Peripheral Access Layer System Source File.
* For HSE = 32Mhz (CH32V208x/CH32V203RBT6)
* For HSE = 8Mhz (other CH32V203x)
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "ch32v20x.h"
/*
* Uncomment the line corresponding to the desired System clock (SYSCLK) frequency (after
* reset the HSI is used as SYSCLK source).
* If none of the define below is enabled, the HSI is used as System clock source.
*/
//#define SYSCLK_FREQ_HSE HSE_VALUE
//#define SYSCLK_FREQ_48MHz_HSE 48000000
//#define SYSCLK_FREQ_56MHz_HSE 56000000
//#define SYSCLK_FREQ_72MHz_HSE 72000000
#define SYSCLK_FREQ_96MHz_HSE 96000000
//#define SYSCLK_FREQ_120MHz_HSE 120000000
//#define SYSCLK_FREQ_144MHz_HSE 144000000
//#define SYSCLK_FREQ_HSI HSI_VALUE
//#define SYSCLK_FREQ_48MHz_HSI 48000000
//#define SYSCLK_FREQ_56MHz_HSI 56000000
//#define SYSCLK_FREQ_72MHz_HSI 72000000
//#define SYSCLK_FREQ_96MHz_HSI 96000000
//#define SYSCLK_FREQ_120MHz_HSI 120000000
//#define SYSCLK_FREQ_144MHz_HSI 144000000
/* Clock Definitions */
#ifdef SYSCLK_FREQ_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_48MHz_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz_HSE; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_56MHz_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz_HSE; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_72MHz_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz_HSE; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_96MHz_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_96MHz_HSE; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_120MHz_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_120MHz_HSE; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_144MHz_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_144MHz_HSE; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_48MHz_HSI
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz_HSI; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_56MHz_HSI
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz_HSI; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_72MHz_HSI
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz_HSI; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_96MHz_HSI
uint32_t SystemCoreClock = SYSCLK_FREQ_96MHz_HSI; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_120MHz_HSI
uint32_t SystemCoreClock = SYSCLK_FREQ_120MHz_HSI; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_144MHz_HSI
uint32_t SystemCoreClock = SYSCLK_FREQ_144MHz_HSI; /* System Clock Frequency (Core Clock) */
#else
uint32_t SystemCoreClock = HSI_VALUE; /* System Clock Frequency (Core Clock) */
#endif
__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
/* system_private_function_proto_types */
static void SetSysClock(void);
#ifdef SYSCLK_FREQ_HSE
static void SetSysClockToHSE( void );
#elif defined SYSCLK_FREQ_48MHz_HSE
static void SetSysClockTo48_HSE( void );
#elif defined SYSCLK_FREQ_56MHz_HSE
static void SetSysClockTo56_HSE( void );
#elif defined SYSCLK_FREQ_72MHz_HSE
static void SetSysClockTo72_HSE( void );
#elif defined SYSCLK_FREQ_96MHz_HSE
static void SetSysClockTo96_HSE( void );
#elif defined SYSCLK_FREQ_120MHz_HSE
static void SetSysClockTo120_HSE( void );
#elif defined SYSCLK_FREQ_144MHz_HSE
static void SetSysClockTo144_HSE( void );
#elif defined SYSCLK_FREQ_48MHz_HSI
static void SetSysClockTo48_HSI( void );
#elif defined SYSCLK_FREQ_56MHz_HSI
static void SetSysClockTo56_HSI( void );
#elif defined SYSCLK_FREQ_72MHz_HSI
static void SetSysClockTo72_HSI( void );
#elif defined SYSCLK_FREQ_96MHz_HSI
static void SetSysClockTo96_HSI( void );
#elif defined SYSCLK_FREQ_120MHz_HSI
static void SetSysClockTo120_HSI( void );
#elif defined SYSCLK_FREQ_144MHz_HSI
static void SetSysClockTo144_HSI( void );
#endif
/*********************************************************************
* @fn SystemInit
*
* @brief Setup the microcontroller system Initialize the Embedded Flash Interface,
* the PLL and update the SystemCoreClock variable.
*
* @return none
*/
void SystemInit (void)
{
RCC->CTLR |= (uint32_t)0x00000001;
RCC->CFGR0 &= (uint32_t)0xF8FF0000;
RCC->CTLR &= (uint32_t)0xFEF6FFFF;
RCC->CTLR &= (uint32_t)0xFFFBFFFF;
RCC->CFGR0 &= (uint32_t)0xFF80FFFF;
RCC->INTR = 0x009F0000;
SetSysClock();
}
/*********************************************************************
* @fn SystemCoreClockUpdate
*
* @brief Update SystemCoreClock variable according to Clock Register Values.
*
* @return none
*/
void SystemCoreClockUpdate (void)
{
uint32_t tmp = 0, pllmull = 0, pllsource = 0, Pll_6_5 = 0;
tmp = RCC->CFGR0 & RCC_SWS;
switch (tmp)
{
case 0x00:
SystemCoreClock = HSI_VALUE;
break;
case 0x04:
SystemCoreClock = HSE_VALUE;
break;
case 0x08:
pllmull = RCC->CFGR0 & RCC_PLLMULL;
pllsource = RCC->CFGR0 & RCC_PLLSRC;
pllmull = ( pllmull >> 18) + 2;
if(pllmull == 17) pllmull = 18;
if (pllsource == 0x00)
{
if(EXTEN->EXTEN_CTR & EXTEN_PLL_HSI_PRE){
SystemCoreClock = HSI_VALUE * pllmull;
}
else{
SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
}
}
else
{
#if defined (CH32V20x_D8W)
if((RCC->CFGR0 & (3<<22)) == (3<<22))
{
SystemCoreClock = ((HSE_VALUE>>1)) * pllmull;
}
else
#endif
if ((RCC->CFGR0 & RCC_PLLXTPRE) != (uint32_t)RESET)
{
#if defined (CH32V20x_D8) || defined (CH32V20x_D8W)
SystemCoreClock = ((HSE_VALUE>>2) >> 1) * pllmull;
#else
SystemCoreClock = (HSE_VALUE >> 1) * pllmull;
#endif
}
else
{
#if defined (CH32V20x_D8) || defined (CH32V20x_D8W)
SystemCoreClock = (HSE_VALUE>>2) * pllmull;
#else
SystemCoreClock = HSE_VALUE * pllmull;
#endif
}
}
if(Pll_6_5 == 1) SystemCoreClock = (SystemCoreClock / 2);
break;
default:
SystemCoreClock = HSI_VALUE;
break;
}
tmp = AHBPrescTable[((RCC->CFGR0 & RCC_HPRE) >> 4)];
SystemCoreClock >>= tmp;
}
/*********************************************************************
* @fn SetSysClock
*
* @brief Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
SetSysClockToHSE();
#elif defined SYSCLK_FREQ_48MHz_HSE
SetSysClockTo48_HSE();
#elif defined SYSCLK_FREQ_56MHz_HSE
SetSysClockTo56_HSE();
#elif defined SYSCLK_FREQ_72MHz_HSE
SetSysClockTo72_HSE();
#elif defined SYSCLK_FREQ_96MHz_HSE
SetSysClockTo96_HSE();
#elif defined SYSCLK_FREQ_120MHz_HSE
SetSysClockTo120_HSE();
#elif defined SYSCLK_FREQ_144MHz_HSE
SetSysClockTo144_HSE();
#elif defined SYSCLK_FREQ_48MHz_HSI
SetSysClockTo48_HSI();
#elif defined SYSCLK_FREQ_56MHz_HSI
SetSysClockTo56_HSI();
#elif defined SYSCLK_FREQ_72MHz_HSI
SetSysClockTo72_HSI();
#elif defined SYSCLK_FREQ_96MHz_HSI
SetSysClockTo96_HSI();
#elif defined SYSCLK_FREQ_120MHz_HSI
SetSysClockTo120_HSI();
#elif defined SYSCLK_FREQ_144MHz_HSI
SetSysClockTo144_HSI();
#endif
/* If none of the define above is enabled, the HSI is used as System clock
* source (default after reset)
*/
}
#ifdef SYSCLK_FREQ_HSE
/*********************************************************************
* @fn SetSysClockToHSE
*
* @brief Sets HSE as System clock source and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockToHSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV1;
/* Select HSE as system clock source
* CH32V20x_D6 (HSE=8MHZ)
* CH32V20x_D8 (HSE=32MHZ)
* CH32V20x_D8W (HSE=32MHZ)
*/
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_HSE;
/* Wait till HSE is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x04)
{
}
}
else
{
/* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_48MHz_HSE
/*********************************************************************
* @fn SetSysClockTo48_HSE
*
* @brief Sets System clock frequency to 48MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo48_HSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 6 = 48 MHz (HSE=8MHZ)
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 6 = 48 MHz (HSE=32MHZ)
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 6 = 48 MHz (HSE=32MHZ)
*/
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL6);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_56MHz_HSE
/*********************************************************************
* @fn SetSysClockTo56_HSE
*
* @brief Sets System clock frequency to 56MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo56_HSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 7 = 56 MHz (HSE=8MHZ)
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 7 = 56 MHz (HSE=32MHZ)
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 7 = 56 MHz (HSE=32MHZ)
*/
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL7);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_72MHz_HSE
/*********************************************************************
* @fn SetSysClockTo72_HSE
*
* @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo72_HSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 9 = 72 MHz (HSE=8MHZ)
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 9 = 72 MHz (HSE=32MHZ)
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 9 = 72 MHz (HSE=32MHZ)
*/
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL9);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_96MHz_HSE
/*********************************************************************
* @fn SetSysClockTo96_HSE
*
* @brief Sets System clock frequency to 96MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo96_HSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 12 = 96 MHz (HSE=8MHZ)
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 12 = 96 MHz (HSE=32MHZ)
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 12 = 96 MHz (HSE=32MHZ)
*/
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL12);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_120MHz_HSE
/*********************************************************************
* @fn SetSysClockTo120_HSE
*
* @brief Sets System clock frequency to 120MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo120_HSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if(HSEStatus == (uint32_t)0x01)
{
#if defined (CH32V20x_D8W)
RCC->CFGR0 |= (uint32_t)(3<<22);
/* HCLK = SYSCLK/2 */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV2;
#else
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
#endif
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 15 = 120 MHz (HSE=8MHZ)
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 15 = 120 MHz (HSE=32MHZ)
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/2 * 15 = 240 MHz (HSE=32MHZ)
*/
RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_PLLSRC | RCC_PLLXTPRE |
RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL15);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_144MHz_HSE
/*********************************************************************
* @fn SetSysClockTo144_HSE
*
* @brief Sets System clock frequency to 144MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo144_HSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 18 = 144 MHz (HSE=8MHZ)
* CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 18 = 144 MHz (HSE=32MHZ)
* CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 18 = 144 MHz (HSE=32MHZ)
*/
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL18);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_48MHz_HSI
/*********************************************************************
* @fn SetSysClockTo48_HSI
*
* @brief Sets System clock frequency to 48MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo48_HSI(void)
{
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSI * 6 = 48 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL6);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
#elif defined SYSCLK_FREQ_56MHz_HSI
/*********************************************************************
* @fn SetSysClockTo56_HSI
*
* @brief Sets System clock frequency to 56MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo56_HSI(void)
{
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSI * 7 = 48 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL7);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
#elif defined SYSCLK_FREQ_72MHz_HSI
/*********************************************************************
* @fn SetSysClockTo72_HSI
*
* @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo72_HSI(void)
{
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSI * 9 = 72 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL9);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
#elif defined SYSCLK_FREQ_96MHz_HSI
/*********************************************************************
* @fn SetSysClockTo96_HSI
*
* @brief Sets System clock frequency to 96MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo96_HSI(void)
{
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSI * 12 = 96 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL12);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
#elif defined SYSCLK_FREQ_120MHz_HSI
/*********************************************************************
* @fn SetSysClockTo120_HSI
*
* @brief Sets System clock frequency to 120MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo120_HSI(void)
{
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSI * 15 = 120 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_PLLSRC | RCC_PLLXTPRE |
RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL15);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
#elif defined SYSCLK_FREQ_144MHz_HSI
/*********************************************************************
* @fn SetSysClockTo144_HSI
*
* @brief Sets System clock frequency to 144MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo144_HSI(void)
{
EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSI * 18 = 144 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL18);
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
#endif