This commit is contained in:
parent
80b303c5e3
commit
c086350b69
|
@ -7,11 +7,14 @@ encoding//LIB/CH58xBLE_LIB.h=GBK
|
|||
encoding//Ld/Link.ld=GBK
|
||||
encoding//StdPeriphDriver/CH58x_gpio.c=GBK
|
||||
encoding//StdPeriphDriver/CH58x_sys.c=GBK
|
||||
encoding//StdPeriphDriver/CH58x_uart1.c=GBK
|
||||
encoding//StdPeriphDriver/CH58x_uart3.c=GBK
|
||||
encoding//StdPeriphDriver/inc/CH585SFR.h=GBK
|
||||
encoding//StdPeriphDriver/inc/CH58x_clk.h=GBK
|
||||
encoding//StdPeriphDriver/inc/CH58x_common.h=GBK
|
||||
encoding//StdPeriphDriver/inc/CH58x_gpio.h=GBK
|
||||
encoding//StdPeriphDriver/inc/CH58x_sys.h=GBK
|
||||
encoding//StdPeriphDriver/inc/CH58x_uart.h=GBK
|
||||
encoding//StdPeriphDriver/inc/ISP585.h=GBK
|
||||
encoding//bsp/inc/bsp_master.h=GBK
|
||||
encoding//bsp/inc/bsp_uart.h=UTF-8
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* @Author: mbw
|
||||
* @Date: 2024-12-03 11:13:13
|
||||
* @LastEditors: mbw && 1600520629@qq.com
|
||||
* @LastEditTime: 2024-12-06 14:47:52
|
||||
* @LastEditTime: 2024-12-13 11:32:24
|
||||
* @FilePath: \ble_-tyq_-bjq_-ch584-m\APP\include\multiCentral.h
|
||||
* @Description:
|
||||
* @
|
||||
|
@ -107,7 +107,7 @@ typedef struct
|
|||
* Task Initialization for the BLE Application
|
||||
*/
|
||||
extern void Central_Init(void);
|
||||
|
||||
extern uint8_t centralTaskId;
|
||||
/*
|
||||
* Task Event Processor for the BLE Application
|
||||
*/
|
||||
|
@ -115,6 +115,7 @@ extern uint16_t Central_ProcessEvent(uint8_t task_id, uint16_t events);
|
|||
extern centralConnItem_t centralConnList[CENTRAL_MAX_CONNECTION];
|
||||
|
||||
int BSP_Master_Send(centralConnItem_t *centralConnList, uint8_t id, uint8_t *Data, uint8_t Len);
|
||||
void Master_Connect(void);
|
||||
/*********************************************************************
|
||||
*********************************************************************/
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "multiCentral.h"
|
||||
#include "bsp_uart.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "bsp_flash.h"
|
||||
#include "bsp_valve.h"
|
||||
|
||||
#undef LOG_ENABLE
|
||||
|
@ -23,7 +23,7 @@
|
|||
* CONSTANTS
|
||||
*/
|
||||
// Maximum number of scan responses
|
||||
#define DEFAULT_MAX_SCAN_RES 10
|
||||
#define DEFAULT_MAX_SCAN_RES 30
|
||||
|
||||
// Scan duration in 0.625ms
|
||||
#define DEFAULT_SCAN_DURATION 2400 // 2400*0.625 = 1500ms
|
||||
|
@ -48,7 +48,7 @@
|
|||
#define DEFAULT_DISCOVERY_WHITE_LIST FALSE
|
||||
|
||||
// TRUE to use high scan duty cycle when creating link
|
||||
#define DEFAULT_LINK_HIGH_DUTY_CYCLE FALSE
|
||||
#define DEFAULT_LINK_HIGH_DUTY_CYCLE TRUE
|
||||
|
||||
// TRUE to use white list when creating link
|
||||
#define DEFAULT_LINK_WHITE_LIST FALSE
|
||||
|
@ -84,7 +84,7 @@
|
|||
#define DEFAULT_IO_CAPABILITIES GAPBOND_IO_CAP_NO_INPUT_NO_OUTPUT
|
||||
|
||||
// Default service discovery timer delay in 0.625ms
|
||||
#define DEFAULT_SVC_DISCOVERY_DELAY 1600
|
||||
#define DEFAULT_SVC_DISCOVERY_DELAY 800
|
||||
|
||||
// Default parameter update delay in 0.625ms
|
||||
#define DEFAULT_PARAM_UPDATE_DELAY 3200
|
||||
|
@ -137,7 +137,7 @@ enum
|
|||
*/
|
||||
|
||||
// Task ID for internal task/event processing
|
||||
static uint8_t centralTaskId;
|
||||
uint8_t centralTaskId;
|
||||
|
||||
// Number of scan results
|
||||
static uint8_t centralScanRes;
|
||||
|
@ -146,10 +146,10 @@ static uint8_t centralScanRes;
|
|||
static gapDevRec_t centralDevList[DEFAULT_MAX_SCAN_RES];
|
||||
|
||||
// Peer device address
|
||||
static peerAddrDefItem_t PeerAddrDef[CENTRAL_MAX_CONNECTION] = {
|
||||
peerAddrDefItem_t PeerAddrDef[CENTRAL_MAX_CONNECTION] = {
|
||||
// {0xcf, 0xb4, 0x8f, 0x10, 0x53, 0x5c},
|
||||
// {0xe1, 0X51, 0x89, 0x88, 0x19, 0x70},
|
||||
{0xb6, 0xb4, 0x8f, 0x10, 0x53, 0x5c},
|
||||
// {0xb6, 0xb4, 0x8f, 0x10, 0x53, 0x5c},
|
||||
// {0x03, 0x02, 0x03, 0xE4, 0xC2, 0x84},
|
||||
};
|
||||
|
||||
|
@ -708,18 +708,18 @@ static void centralEventCB(gapRoleEvent_t *pEvent)
|
|||
centralAddDeviceInfo(pEvent->deviceInfo.addr, pEvent->deviceInfo.addrType);
|
||||
}
|
||||
break;
|
||||
|
||||
case GAP_DEVICE_DISCOVERY_EVENT:
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
#if 1
|
||||
// See if peer device has been discovered
|
||||
for (i = 0; i < centralScanRes; i++)
|
||||
{
|
||||
if (centralAddrCmp(PeerAddrDef, centralDevList[i].addr))
|
||||
break;
|
||||
// if (centralAddrCmp(PeerAddrDef, centralDevList[i].addr))
|
||||
// break;
|
||||
// if (tmos_memcmp(valve_list.valve_data[0].valve_mac, centralDevList[i].addr, B_ADDR_LEN))
|
||||
break;
|
||||
}
|
||||
|
||||
// Peer device not found
|
||||
if (i == centralScanRes)
|
||||
{
|
||||
|
@ -735,15 +735,24 @@ static void centralEventCB(gapRoleEvent_t *pEvent)
|
|||
else
|
||||
{
|
||||
logDebug("Device found...\r\n");
|
||||
#if 0
|
||||
GAPRole_CentralEstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE,
|
||||
DEFAULT_LINK_WHITE_LIST,
|
||||
centralDevList[i].addrType,
|
||||
centralDevList[i].addr);
|
||||
#endif
|
||||
|
||||
GAPRole_CentralEstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE,
|
||||
DEFAULT_LINK_WHITE_LIST,
|
||||
ADDRTYPE_PUBLIC,
|
||||
valve_list.valve_data[0].valve_mac);
|
||||
logInfo("valve_list.valve_data[0].valve_mac:");
|
||||
logHexDumpAll(valve_list.valve_data[0].valve_mac, B_ADDR_LEN);
|
||||
// Start establish link timeout event
|
||||
tmos_start_task(centralTaskId, ESTABLISH_LINK_TIMEOUT_EVT, ESTABLISH_LINK_TIMEOUT);
|
||||
logDebug("Connecting...\r\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -784,6 +793,7 @@ static void centralEventCB(gapRoleEvent_t *pEvent)
|
|||
|
||||
// Start RSSI polling
|
||||
tmos_start_task(centralConnList[connItem].taskID, START_READ_RSSI_EVT, DEFAULT_RSSI_PERIOD);
|
||||
|
||||
}
|
||||
|
||||
// 连接1
|
||||
|
@ -1070,7 +1080,7 @@ static void centralGATTDiscoveryEvent(uint8_t connItem, gattMsgEvent_t *pMsg)
|
|||
centralConnList[connItem].charHd3 = char_value_handle;
|
||||
logDebug("char3 Write handle\t:%04x\r\n", char_value_handle);
|
||||
centralConnList[connItem].procedureInProgress = FALSE;
|
||||
tmos_start_task(centralConnList[CONNECT0_ITEM].taskID, CH3_WRITE_EVT, 3200);
|
||||
// tmos_start_task(centralConnList[CONNECT0_ITEM].taskID, CH3_WRITE_EVT, 3200);
|
||||
}
|
||||
}
|
||||
else if (tmos_memcmp(char_uuid, &char4uuid, 2))
|
||||
|
@ -1186,7 +1196,7 @@ int BSP_Master_Send(centralConnItem_t *centralConnList, uint8_t id, uint8_t *Dat
|
|||
if (res == SUCCESS)
|
||||
{
|
||||
logDebug("\n Master Write ok");
|
||||
centralConnList[id].procedureInProgress == FALSE;
|
||||
centralConnList[id].procedureInProgress = FALSE;
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
|
@ -1202,9 +1212,15 @@ int BSP_Master_Send(centralConnItem_t *centralConnList, uint8_t id, uint8_t *Dat
|
|||
ret = 2;
|
||||
}
|
||||
}
|
||||
ret = 3;
|
||||
else
|
||||
{
|
||||
ret = 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 4;
|
||||
}
|
||||
ret = 4;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1219,7 +1235,7 @@ int BSP_Master_Receive_Data(uint8_t task_id, uint8_t *data, uint16_t len)
|
|||
{ // 至少需要 4 个字节:起始码、长度、校验码、结束码
|
||||
logError("BT 数据帧长度不足");
|
||||
logHexDumpAll(data, len);
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
while (index < len && data[index] != 0xAA) // 寻找起始码 0xAA
|
||||
{
|
||||
|
@ -1229,7 +1245,7 @@ int BSP_Master_Receive_Data(uint8_t task_id, uint8_t *data, uint16_t len)
|
|||
{
|
||||
logError("BT 数据帧起始码错误");
|
||||
logHexDumpAll(data, len);
|
||||
return 2;
|
||||
return -2;
|
||||
}
|
||||
|
||||
uint16_t datalength = data[index + 2]; // 读取数据长度
|
||||
|
@ -1238,7 +1254,7 @@ int BSP_Master_Receive_Data(uint8_t task_id, uint8_t *data, uint16_t len)
|
|||
|
||||
logError("BT 数据帧长度错误");
|
||||
logHexDumpAll(data, len);
|
||||
return 3; //
|
||||
return -3; //
|
||||
}
|
||||
|
||||
uint8_t rx_sum = data[index + 3 + datalength]; // 读取校验码
|
||||
|
@ -1248,7 +1264,7 @@ int BSP_Master_Receive_Data(uint8_t task_id, uint8_t *data, uint16_t len)
|
|||
{
|
||||
logError("BT 数据帧校验码错误 rx_sum = %02X, calculated_sum = %02X", rx_sum, calculated_sum);
|
||||
logHexDumpAll(data, len);
|
||||
return 4;
|
||||
return -4;
|
||||
}
|
||||
|
||||
if (data[index + 3 + datalength + 1] != 0x55) // 检查结束码
|
||||
|
@ -1256,15 +1272,24 @@ int BSP_Master_Receive_Data(uint8_t task_id, uint8_t *data, uint16_t len)
|
|||
logError("BT 数据帧结束码错误");
|
||||
logHexDumpAll(data, len);
|
||||
|
||||
return 5;
|
||||
return -5;
|
||||
}
|
||||
logDebug("BT 数据帧校验通过");
|
||||
|
||||
// //有效数据长度
|
||||
size_t data_len = (datalength + 5);
|
||||
if (data[index + 1] == kCmdCfg) // 0x01 代表了其是控制阀门响应
|
||||
ret = data_len;
|
||||
if (data[index + 1] == kCmdCloseVavle) // 0x02 代表了其是控制阀门响应
|
||||
{
|
||||
logDebug("BT 控制阀门响应包");
|
||||
if (data[index + datalength + 2] == 1)//响应数据位
|
||||
{
|
||||
logInfo("BT 控制阀门成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
logError("BT 控制阀门失败");
|
||||
}
|
||||
logHexDumpAll(&data[index], len);
|
||||
}
|
||||
else if (data[index + 1] == kValveCmdRep) // 这个是代表了其是心跳数据包
|
||||
|
@ -1275,16 +1300,36 @@ int BSP_Master_Receive_Data(uint8_t task_id, uint8_t *data, uint16_t len)
|
|||
valve_list.valve_data[task_id].valve_id = data[index + 4];
|
||||
// tmos_memcpy(valve_list.valve_data[task_id].valve_mac, &data[index + 5], 6); //将数据提取到结构体中
|
||||
}
|
||||
// //有效数据长度
|
||||
// size_t data_len = (datalength + 5);
|
||||
// //到这一步说明数据没问题,将接收到的数据通过中心任务发送出去
|
||||
// uint8_t *p_data;
|
||||
// p_data = tmos_msg_allocate(data_len);
|
||||
// if (p_data)
|
||||
// {
|
||||
// tmos_memcpy(p_data, data, data_len);
|
||||
// tmos_msg_send(BtRxTaskId, p_data);
|
||||
// tmos_start_task(BtRxTaskId, SYS_EVENT_MSG, 0);
|
||||
// }
|
||||
//到这一步说明数据没问题,将接收到的数据通过中心任务发送出去
|
||||
uint8_t *p_data;
|
||||
p_data = tmos_msg_allocate(data_len);
|
||||
if (p_data)
|
||||
{
|
||||
tmos_memcpy(p_data, data, data_len);
|
||||
tmos_msg_send(BtRxTaskId, p_data);
|
||||
tmos_start_task(BtRxTaskId, SYS_EVENT_MSG, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void Master_Connect(void)
|
||||
{
|
||||
uint8_t cnt = Flash_Get_Valve_Num();
|
||||
logDebug("cnt:%d\r\n", cnt);
|
||||
for (uint8_t i = 0; i < cnt; i++)
|
||||
{
|
||||
if (valve_list.valve_data[cnt].valve_id != 0)
|
||||
{
|
||||
logDebug("valve_id:%d\r\n", valve_list.valve_data[cnt].valve_id);
|
||||
logHexDumpAll(valve_list.valve_data[cnt].valve_mac, 6);
|
||||
GAPRole_CentralEstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE,
|
||||
DEFAULT_LINK_WHITE_LIST,
|
||||
ADDRTYPE_PUBLIC,
|
||||
valve_list.valve_data[cnt].valve_mac);
|
||||
tmos_start_task(centralTaskId, ESTABLISH_LINK_TIMEOUT_EVT, ESTABLISH_LINK_TIMEOUT);
|
||||
logDebug("Connecting...\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* @Author: mbw
|
||||
* @Date: 2024-12-03 11:13:13
|
||||
* @LastEditors: mbw && 1600520629@qq.com
|
||||
* @LastEditTime: 2024-12-09 13:34:51
|
||||
* @LastEditTime: 2024-12-13 18:31:17
|
||||
* @FilePath: \ble_-tyq_-bjq_-ch584-m\APP\multiCentral_main.c
|
||||
* @Description:
|
||||
*
|
||||
|
@ -27,19 +27,17 @@
|
|||
#include "bsp_uart.h"
|
||||
#include "log.h"
|
||||
#include "bsp_flash.h"
|
||||
|
||||
|
||||
#include "bsp_valve.h"
|
||||
|
||||
#undef LOG_ENABLE
|
||||
#define LOG_ENABLE 1
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* GLOBAL TYPEDEFS
|
||||
*/
|
||||
__attribute__((aligned(4))) uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4];
|
||||
|
||||
#if(defined(BLE_MAC)) && (BLE_MAC == TRUE)
|
||||
#if (defined(BLE_MAC)) && (BLE_MAC == TRUE)
|
||||
const uint8_t MacAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};
|
||||
#endif
|
||||
|
||||
|
@ -51,12 +49,16 @@ const uint8_t MacAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};
|
|||
* @return none
|
||||
*/
|
||||
__HIGH_CODE
|
||||
__attribute__((noinline))
|
||||
void Main_Circulation()
|
||||
__attribute__((noinline)) void Main_Circulation()
|
||||
{
|
||||
while(1)
|
||||
while (1)
|
||||
{
|
||||
|
||||
TMOS_SystemProcess();
|
||||
|
||||
// BSP_Uart1_Send_Loop();
|
||||
BSP_Uart3_Send_Loop();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,16 +71,15 @@ void Main_Circulation()
|
|||
*/
|
||||
int main(void)
|
||||
{
|
||||
#if(defined(DCDC_ENABLE)) && (DCDC_ENABLE == TRUE)
|
||||
#if (defined(DCDC_ENABLE)) && (DCDC_ENABLE == TRUE)
|
||||
PWR_DCDCCfg(ENABLE);
|
||||
#endif
|
||||
HSECFG_Capacitance(HSECap_18p);
|
||||
SetSysClock(CLK_SOURCE_HSE_PLL_62_4MHz);
|
||||
#if(defined(HAL_SLEEP)) && (HAL_SLEEP == TRUE)
|
||||
#if (defined(HAL_SLEEP)) && (HAL_SLEEP == TRUE)
|
||||
GPIOA_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);
|
||||
GPIOB_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);
|
||||
#endif
|
||||
|
||||
CH58x_BLEInit();
|
||||
HAL_Init();
|
||||
GAPRole_CentralInit();
|
||||
|
@ -96,10 +97,11 @@ int main(void)
|
|||
UART1_DefInit();
|
||||
#elif DEBUG == Debug_UART3
|
||||
BSP_UART3_Init();
|
||||
logDebug("test log debug\n");
|
||||
#endif
|
||||
BSP_UART1_Init();//BT UART
|
||||
logDebug("test log debug\n");
|
||||
BSP_FLASH_Init();
|
||||
BSP_Valve_Init();
|
||||
BSP_UART1_Init(); // BT UART
|
||||
Main_Circulation();
|
||||
}
|
||||
|
||||
|
|
|
@ -42,13 +42,16 @@ typedef struct __attribute__((packed))
|
|||
void BSP_UART1_Init(void);
|
||||
unsigned int BSP_Uart1_Receive_Data(void *buf, unsigned int len);
|
||||
unsigned int BSP_Uart1_Send_Data(const void *buf, unsigned int len);
|
||||
|
||||
|
||||
unsigned int BSP_Uart1_Send_String(const void *buf);
|
||||
void BSP_Uart1_Send_Loop(void);
|
||||
void BSP_Uart3_Send_Loop(void);
|
||||
void BSP_UART3_Init(void);
|
||||
unsigned int BSP_Uart3_Receive_Data(void *buf, unsigned int len);
|
||||
unsigned int BSP_Uart3_Send_Data(const void *buf, unsigned int len);
|
||||
|
||||
uint8_t _CheckSum(const uint8_t *data, size_t len);
|
||||
uint8_t BT_GenerateRawFrame(BTFrameData *pRawData, const uint8_t *p_src, uint8_t src_len);
|
||||
|
||||
extern uint8_t BtRxTaskId;
|
||||
|
||||
#endif // !__BSP_UART_H__
|
||||
|
|
|
@ -21,7 +21,8 @@ typedef enum
|
|||
kValveCmdReg,
|
||||
kValveCmdRem,
|
||||
kValveCmdRep,
|
||||
kValveCmdMax
|
||||
kValveEventStatus,//阀门状态包
|
||||
kValveCmdMax,
|
||||
} ValveCmdType;
|
||||
|
||||
typedef enum
|
||||
|
@ -46,9 +47,6 @@ typedef enum
|
|||
kCmdData,
|
||||
} TeFrameCmd;
|
||||
|
||||
|
||||
typedef struct valve_data valve_data_t;
|
||||
|
||||
/*
|
||||
无线调压阀编号
|
||||
无线调压阀 MAC 地址
|
||||
|
@ -81,15 +79,20 @@ struct __attribute__((packed)) valve_data
|
|||
typedef struct valve_data_list
|
||||
{
|
||||
uint8_t valve_num;
|
||||
valve_data_t valve_data[MAX_VALVE_NUM];
|
||||
struct valve_data valve_data[MAX_VALVE_NUM];
|
||||
} valve_data_list_t;
|
||||
|
||||
extern valve_data_list_t valve_list;
|
||||
|
||||
void BSP_Valve_Init(void);
|
||||
int BSP_Bt_Valve_Ctr(uint8_t *data, uint8_t len);
|
||||
int BSP_Bt_Register_Valve(uint8_t *data, uint8_t len);
|
||||
int BSP_Bt_Remove_Valve(uint8_t *data, uint8_t len);
|
||||
int BSP_Bt_Replace_Valve(uint8_t *data, uint8_t len);
|
||||
void BSP_Bt_Valve_Updata(void);
|
||||
|
||||
int BSP_Bt_Valve_Ctr_Resp(uint8_t id, uint8_t *mac_addr, WireLessState status);
|
||||
|
||||
int BSP_Bt_Valve_Resp(uint8_t cmd, uint8_t id, uint8_t *mac_addr, uint8_t state);
|
||||
|
||||
#endif // ! __BSP_VALVE_H__
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* @Author: mbw
|
||||
* @Date: 2024-12-06 14:49:21
|
||||
* @LastEditors: mbw && 1600520629@qq.com
|
||||
* @LastEditTime: 2024-12-10 15:28:37
|
||||
* @LastEditTime: 2024-12-13 13:57:30
|
||||
* @FilePath: \ble_-tyq_-bjq_-ch584-m\bsp\src\bsp_flash.c
|
||||
* @Description: 主要用于对一些MAC地址等关键信息进行保存和读取操作
|
||||
*
|
||||
|
@ -68,7 +68,7 @@ int Flash_Get_Mac_Addr(uint8_t *mac_addr, uint8_t number)
|
|||
int Flash_Set_Valve_Num(uint8_t valve_num)
|
||||
{
|
||||
uint8_t page_buf[DATA_FLASH_PAGE_SIZE] = {0};
|
||||
uint8_t in_page_offset = (FLASH_INFO_ADDR - FLASH_MAC_INFO_START_ADDR);
|
||||
uint8_t in_page_offset = (FLASH_MAC_NUM_ADDR - FLASH_INFO_ADDR);
|
||||
Flash_ErasePage_ReadConfigInfo(page_buf);
|
||||
page_buf[in_page_offset] = valve_num;
|
||||
return Flash_Write_ConfigInfo(page_buf);
|
||||
|
@ -79,7 +79,15 @@ uint8_t Flash_Get_Valve_Num(void)
|
|||
{
|
||||
uint8_t num;
|
||||
EEPROM_READ(FLASH_MAC_NUM_ADDR, &num, FLASH_MAC_NUM_LEN);
|
||||
return num;
|
||||
if (num != 0xFF)
|
||||
{
|
||||
return num;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void BSP_FLASH_Init(void)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* @Author: mbw
|
||||
* @Date: 2024-12-06 16:52:30
|
||||
* @LastEditors: mbw && 1600520629@qq.com
|
||||
* @LastEditTime: 2024-12-12 17:30:58
|
||||
* @LastEditTime: 2024-12-13 18:26:38
|
||||
* @FilePath: \ble_-tyq_-bjq_-ch584-m\bsp\src\bsp_uart.c
|
||||
* @Description:
|
||||
*
|
||||
|
@ -12,10 +12,11 @@
|
|||
#include "lwrb.h"
|
||||
#include "CH58x_uart.h"
|
||||
#include "shell_port.h"
|
||||
#include "CH58xBLE_LIB.h"
|
||||
#include "CONFIG.h"
|
||||
#include "bsp_flash.h"
|
||||
#include "bsp_valve.h"
|
||||
#include "shell.h"
|
||||
#include "multiCentral.h"
|
||||
|
||||
#undef LOG_ENABLE
|
||||
#define LOG_ENABLE 1
|
||||
|
@ -92,7 +93,7 @@ unsigned int BSP_Uart3_Send_Data(const void *buf, unsigned int len)
|
|||
unsigned int ret;
|
||||
|
||||
ret = lwrb_write(&uart3_tx_t, buf, len);
|
||||
UART3_INTCfg(ENABLE, RB_IER_THR_EMPTY);
|
||||
// UART3_INTCfg(ENABLE, RB_IER_THR_EMPTY);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -169,14 +170,38 @@ int BSP_Bt_Process(uint8_t *data, uint16_t len)
|
|||
case kValveCmdReg:
|
||||
ret = BSP_Bt_Register_Valve(&data_buf[0], datalength);
|
||||
logDebug("recv cmd: 0x02, 执行的动作是注册阀门");
|
||||
if (ret == 0)
|
||||
{
|
||||
BSP_Bt_Valve_Resp(kValveCmdReg, CONNECT0_ITEM, valve_list.valve_data[CONNECT0_ITEM].valve_mac, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
BSP_Bt_Valve_Resp(kValveCmdReg, CONNECT0_ITEM, valve_list.valve_data[CONNECT0_ITEM].valve_mac, FALSE);
|
||||
}
|
||||
break;
|
||||
case kValveCmdRem:
|
||||
ret = BSP_Bt_Remove_Valve(&data_buf[0], datalength);
|
||||
logDebug("recv cmd: 0x03, 执行的动作是移除阀门");
|
||||
if (ret == 0)
|
||||
{
|
||||
BSP_Bt_Valve_Resp(kValveCmdRem, CONNECT0_ITEM, valve_list.valve_data[CONNECT0_ITEM].valve_mac, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
BSP_Bt_Valve_Resp(kValveCmdRem, CONNECT0_ITEM, valve_list.valve_data[CONNECT0_ITEM].valve_mac, FALSE);
|
||||
}
|
||||
break;
|
||||
case kValveCmdRep:
|
||||
ret = BSP_Bt_Replace_Valve(&data_buf[0], datalength);
|
||||
logDebug("recv cmd: 0x04, 执行的动作是更换阀门");
|
||||
if (ret == 0)
|
||||
{
|
||||
BSP_Bt_Valve_Resp(kValveCmdRep, CONNECT0_ITEM, valve_list.valve_data[CONNECT0_ITEM].valve_mac, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
BSP_Bt_Valve_Resp(kValveCmdRep, CONNECT0_ITEM, valve_list.valve_data[CONNECT0_ITEM].valve_mac, FALSE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logError("unknow cmd: %02X", data[index + 2]);
|
||||
|
@ -209,47 +234,95 @@ uint8_t BT_GenerateRawFrame(BTFrameData *pRawData, const uint8_t *p_src, uint8_t
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief 向报警器发送数据
|
||||
* @brief 解析蓝牙从机数据或数据帧格式正确的数据,用来向报警器发送
|
||||
* @param {uint8_t} task_id
|
||||
* @param {uint16_t} events
|
||||
* @return {*}
|
||||
*/
|
||||
uint16_t BSP_Send_Process(uint8_t *pdata, uint16_t len)
|
||||
uint16_t BSP_Send_Process(uint8_t *pdata)
|
||||
{
|
||||
int8_t ret = 0;
|
||||
__attribute__((aligned(4))) uint8_t buf[128] = {0};
|
||||
ret = BSP_Bt_Process(buf, len);
|
||||
if (ret != 0)
|
||||
int8_t ret = 0;
|
||||
__attribute__((aligned(4))) uint8_t master_rx_buf[64] = {0};
|
||||
|
||||
uint8_t found_frame_start = 0;
|
||||
uint8_t *frame_start = NULL;
|
||||
uint8_t *frame_end = NULL;
|
||||
size_t data_len = 0;
|
||||
uint8_t check_sum = 0;
|
||||
/*先通过指针地址去找帧头AA,然后再找帧尾55,然后计算倒数第二个字节之前的和校验,看是否等于倒数第二个字节,如果是,则数据正确,然后解析*/
|
||||
for (size_t i = 0; i < sizeof(master_rx_buf); i++)
|
||||
{
|
||||
logError("BT 操作失败[%d]", ret);
|
||||
if (!found_frame_start && pdata[i] == 0xAA)
|
||||
{
|
||||
frame_start = &pdata[i];
|
||||
found_frame_start = 1;
|
||||
}
|
||||
else if (found_frame_start && pdata[i] == 0x55)
|
||||
{
|
||||
frame_end = &pdata[i];
|
||||
data_len = frame_end - frame_start + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (frame_start == NULL || frame_end == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if ((data_len > sizeof(master_rx_buf)) || (data_len < 5))
|
||||
{
|
||||
logError("接收到的数据长度不对: data_len=%d", data_len);
|
||||
|
||||
return -2;
|
||||
}
|
||||
tmos_memcpy(master_rx_buf, frame_start, data_len);
|
||||
check_sum = _CheckSum(&master_rx_buf[0], data_len - 2);
|
||||
if (check_sum != master_rx_buf[data_len - 2])
|
||||
{
|
||||
logError("校验和不对: check_sum=%d, rx_sum[1]= %X", check_sum, master_rx_buf[data_len - 2]);
|
||||
|
||||
return -3;
|
||||
}
|
||||
/*到这一步,就说明数据接收正确,开始处理数据*/
|
||||
/*AA + CMD + DATA_LEN + DATA + CHECKSUM + END*/
|
||||
switch (master_rx_buf[1])
|
||||
{
|
||||
case kCmdCfg:
|
||||
break;
|
||||
case kCmdCloseVavle:
|
||||
BSP_Bt_Valve_Resp(kValveCmdCtr, valve_list.valve_data[0].valve_id, valve_list.valve_data[0].valve_mac, master_rx_buf[3]);
|
||||
break;
|
||||
case kCmdOpenVavle:
|
||||
break;
|
||||
case kCmdData:
|
||||
BSP_Bt_Valve_Resp(kValveEventStatus, valve_list.valve_data[0].valve_id, valve_list.valve_data[0].valve_mac, master_rx_buf[3]);
|
||||
break;
|
||||
default:
|
||||
logError("不支持的命令: %d", master_rx_buf[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t BT_ProcessEvent(uint8_t task_id, uint16_t events)
|
||||
{
|
||||
int8_t ret = 0;
|
||||
uint8_t *pMsg;
|
||||
uint8_t master_buf[64] = {0};
|
||||
if (events & SYS_EVENT_MSG)
|
||||
{
|
||||
uint8_t *pMsg;
|
||||
uint8_t master_buf[64] = {0};
|
||||
if ((pMsg = tmos_msg_receive(BtRxTaskId)) != NULL)
|
||||
{
|
||||
PRINT("revice data:");
|
||||
// for (uint8_t i = 0; i < 5; i++)
|
||||
// {
|
||||
// PRINT("%02x ", pMsg[i]);
|
||||
// }
|
||||
tmos_memcpy(master_buf, pMsg, sizeof(master_buf));
|
||||
PRINT("\r\n");
|
||||
// Release the TMOS message
|
||||
tmos_msg_deallocate(pMsg);
|
||||
BSP_Send_Process(master_buf);
|
||||
}
|
||||
}
|
||||
else if (events & BT_START_EVT)
|
||||
{
|
||||
lwrb_reset(&uart1_rx_t);
|
||||
tmos_start_task(task_id, BT_REC_EVT, 20);
|
||||
tmos_start_task(task_id, BT_INFO_UPDATA_EVT, 1000);
|
||||
lwrb_reset(&uart1_tx_t);
|
||||
tmos_start_task(task_id, BT_REC_EVT, 800);
|
||||
tmos_start_task(task_id, BT_INFO_UPDATA_EVT, 1600);
|
||||
return (events ^ BT_START_EVT);
|
||||
}
|
||||
else if (events & BT_REC_EVT)
|
||||
|
@ -265,13 +338,12 @@ uint16_t BT_ProcessEvent(uint8_t task_id, uint16_t events)
|
|||
logError("BT 操作失败[%d]", ret);
|
||||
}
|
||||
}
|
||||
tmos_start_task(task_id, BT_REC_EVT, 20);
|
||||
tmos_start_task(task_id, BT_REC_EVT, 100);
|
||||
return (events ^ BT_REC_EVT);
|
||||
}
|
||||
else if (events & BT_SEND_EVT)
|
||||
{
|
||||
// BSP_Uart1_Send_String("\r\n");//报警器端接收是以回车换行结尾,所以这里也加上换行
|
||||
tmos_start_task(task_id, BT_SEND_EVT, 1000);
|
||||
BSP_Uart1_Send_String("\r\n"); // 报警器端接收是以回车换行结尾,所以这里也加上换行
|
||||
return (events ^ BT_SEND_EVT);
|
||||
}
|
||||
else if (events & BT_INFO_UPDATA_EVT) // 更新蓝牙连接信息
|
||||
|
@ -285,16 +357,14 @@ uint16_t BT_ProcessEvent(uint8_t task_id, uint16_t events)
|
|||
/*BT与报警器主机接口*/
|
||||
void BSP_UART1_Init(void)
|
||||
{
|
||||
// GPIOPinRemap(ENABLE, RB_PIN_UART1);
|
||||
|
||||
/* 配置串口1:先配置IO口模式,再配置串口 */
|
||||
GPIOB_SetBits(BT_UART_RX_PIN);
|
||||
GPIOB_SetBits(BT_UART_TX_PIN);
|
||||
GPIOB_ModeCfg(BT_UART_RX_PIN, GPIO_ModeIN_PU); // RXD-配置上拉输入
|
||||
GPIOB_ModeCfg(BT_UART_TX_PIN, GPIO_ModeOut_PP_5mA); // TXD-配置推挽输出,注意先让IO口输出高电平
|
||||
UART1_DefInit();
|
||||
UART1_ByteTrigCfg(UART_1BYTE_TRIG);
|
||||
UART1_ByteTrigCfg(UART_7BYTE_TRIG);
|
||||
// 中断方式接收数据
|
||||
UART1_INTCfg(ENABLE, RB_IER_LINE_STAT | RB_IER_RECV_RDY | RB_IER_THR_EMPTY);
|
||||
UART1_INTCfg(ENABLE, RB_IER_LINE_STAT | RB_IER_RECV_RDY);
|
||||
PFIC_EnableIRQ(UART1_IRQn);
|
||||
UART1_FifoInit();
|
||||
BtRxTaskId = TMOS_ProcessEventRegister(BT_ProcessEvent);
|
||||
|
@ -311,9 +381,9 @@ void BSP_UART3_Init(void)
|
|||
GPIOB_ModeCfg(UART3_TX_PIN, GPIO_ModeOut_PP_5mA); // TXD-配置推挽输出,注意先让IO口输出高电平
|
||||
UART3_DefInit();
|
||||
UART3_BaudRateCfg(460800);
|
||||
UART3_ByteTrigCfg(UART_1BYTE_TRIG);
|
||||
UART3_ByteTrigCfg(UART_7BYTE_TRIG);
|
||||
// 中断方式接收数据
|
||||
UART3_INTCfg(ENABLE, RB_IER_LINE_STAT | RB_IER_RECV_RDY | RB_IER_THR_EMPTY);
|
||||
UART3_INTCfg(ENABLE, RB_IER_LINE_STAT | RB_IER_RECV_RDY);
|
||||
PFIC_EnableIRQ(UART3_IRQn);
|
||||
|
||||
UART3_FifoInit();
|
||||
|
@ -336,7 +406,7 @@ void UART1_IRQHandler(void)
|
|||
{
|
||||
case UART_II_LINE_STAT: // 线路状态错误
|
||||
{
|
||||
// UART1_GetLinSTA();
|
||||
UART1_GetLinSTA();
|
||||
break;
|
||||
}
|
||||
case UART_II_RECV_RDY:
|
||||
|
@ -349,8 +419,9 @@ void UART1_IRQHandler(void)
|
|||
break;
|
||||
|
||||
case UART_II_THR_EMPTY: // 发送缓存区空,可继续发送
|
||||
if (lwrb_read(&uart1_tx_t, &data, 1))
|
||||
if (lwrb_get_full(&uart1_tx_t) > 0)
|
||||
{
|
||||
lwrb_read(&uart1_tx_t, &data, 1);
|
||||
UART1_SendByte(data);
|
||||
}
|
||||
else
|
||||
|
@ -384,7 +455,7 @@ void UART3_IRQHandler(void)
|
|||
{
|
||||
case UART_II_LINE_STAT: // 线路状态错误
|
||||
{
|
||||
// UART1_GetLinSTA();
|
||||
UART3_GetLinSTA();
|
||||
break;
|
||||
}
|
||||
case UART_II_RECV_RDY:
|
||||
|
@ -395,16 +466,15 @@ void UART3_IRQHandler(void)
|
|||
}
|
||||
break;
|
||||
case UART_II_THR_EMPTY: // 发送缓存区空,可继续发送
|
||||
if (lwrb_get_full(&uart3_tx_t))
|
||||
{
|
||||
lwrb_read(&uart3_tx_t, &data, 1);
|
||||
UART3_SendByte(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
UART3_INTCfg(DISABLE, RB_IER_THR_EMPTY);
|
||||
}
|
||||
|
||||
// if (lwrb_get_full(&uart3_tx_t))
|
||||
// {
|
||||
// lwrb_read(&uart3_tx_t, &data, 1);
|
||||
// UART3_SendByte(data);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// UART3_INTCfg(DISABLE, RB_IER_THR_EMPTY);
|
||||
// }
|
||||
break;
|
||||
|
||||
case UART_II_MODEM_CHG: // 只支持串口0
|
||||
|
@ -415,6 +485,38 @@ void UART3_IRQHandler(void)
|
|||
}
|
||||
}
|
||||
|
||||
void BSP_Uart1_Send_Loop(void)
|
||||
{
|
||||
uint8_t data;
|
||||
while (R8_UART1_TFC < UART_FIFO_SIZE)
|
||||
{
|
||||
// 判断发送软件缓冲区,是否空,如果不空,就一个一个读出来,填到硬件fifo里
|
||||
if (lwrb_get_full(&uart1_tx_t))
|
||||
{
|
||||
lwrb_read(&uart1_tx_t, &data, 1);
|
||||
UART1_SendByte(data);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BSP_Uart3_Send_Loop(void)
|
||||
{
|
||||
uint8_t data;
|
||||
while (R8_UART3_TFC < UART_FIFO_SIZE)
|
||||
{
|
||||
// 判断发送软件缓冲区,是否空,如果不空,就一个一个读出来,填到硬件fifo里
|
||||
if (lwrb_get_full(&uart3_tx_t))
|
||||
{
|
||||
lwrb_read(&uart3_tx_t, &data, 1);
|
||||
UART3_SendByte(data);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int reboot(void)
|
||||
{
|
||||
PFIC_SystemReset();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* @Author: mbw
|
||||
* @Date: 2024-12-09 11:40:10
|
||||
* @LastEditors: mbw && 1600520629@qq.com
|
||||
* @LastEditTime: 2024-12-12 19:35:56
|
||||
* @LastEditTime: 2024-12-13 15:39:05
|
||||
* @FilePath: \ble_-tyq_-bjq_-ch584-m\bsp\src\bsp_valve.c
|
||||
* @Description:
|
||||
*
|
||||
|
@ -99,6 +99,7 @@ int BSP_Bt_Valve_Ctr(uint8_t *data, uint8_t len)
|
|||
/*注册阀门信息*/
|
||||
int BSP_Bt_Register_Valve(uint8_t *data, uint8_t len)
|
||||
{
|
||||
|
||||
size_t i = 0;
|
||||
uint8_t mac_addr[FLASH_MAC_INFO_LEN] = {0};
|
||||
if ((data[0] >= 1) && (data[0] <= 8))
|
||||
|
@ -123,7 +124,7 @@ int BSP_Bt_Register_Valve(uint8_t *data, uint8_t len)
|
|||
logError("register valve error");
|
||||
return 2;
|
||||
}
|
||||
tmos_start_task(BtRxTaskId, BT_INFO_UPDATA_EVT, 10);
|
||||
tmos_start_task(BtRxTaskId, BT_INFO_UPDATA_EVT, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -218,7 +219,7 @@ void BSP_Bt_Valve_Updata(void)
|
|||
uint8_t cnt = 0;
|
||||
uint8_t mac[6] = {0};
|
||||
uint8_t num = Flash_Get_Valve_Num();
|
||||
logInfo("BSP_Bt_Valve_Updata");
|
||||
logInfo("BSP_Bt_Valve_Updata num: %d ", num);
|
||||
tmos_memset(&valve_list, 0, sizeof(valve_data_list_t));
|
||||
for (int i = 0; i < MAX_VALVE_NUM; i++) // 这个循环是为了将数据拷贝到valve_list中, 并且保证id号和flash对应起来
|
||||
{
|
||||
|
@ -228,12 +229,20 @@ void BSP_Bt_Valve_Updata(void)
|
|||
{
|
||||
tmos_memcpy(valve_list.valve_data[cnt].valve_mac, mac, 6); // 这样做的目的就是读取方便,只需要根据flash中读取到的数量进行读取前N个值
|
||||
valve_list.valve_data[cnt].valve_id = i + 1;
|
||||
logDebug("updata valve_id: %d, valve_mac: %02X %02X %02X %02X %02X %02X",
|
||||
valve_list.valve_data[cnt].valve_id,
|
||||
valve_list.valve_data[cnt].valve_mac[0],
|
||||
valve_list.valve_data[cnt].valve_mac[1],
|
||||
valve_list.valve_data[cnt].valve_mac[2],
|
||||
valve_list.valve_data[cnt].valve_mac[3],
|
||||
valve_list.valve_data[cnt].valve_mac[4],
|
||||
valve_list.valve_data[cnt].valve_mac[5]);
|
||||
cnt++;
|
||||
logDebug(" updata valve_id: %d, valve_mac: %02X %02X %02X %02X %02X %02X", i + 1, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
valve_list.valve_num = cnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmos_memset(&valve_list.valve_data[i], 0, sizeof(valve_data_t));
|
||||
tmos_memset(&valve_list.valve_data[i], 0, sizeof(struct valve_data));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -241,25 +250,71 @@ void BSP_Bt_Valve_Updata(void)
|
|||
logError("BSP_Bt_Valve_Updata: flash read error");
|
||||
}
|
||||
}
|
||||
Flash_Set_Valve_Num(valve_list.valve_num);
|
||||
}
|
||||
|
||||
/*接收从机的状态上报数据,并对所有数据进行整理*/
|
||||
void BSP_Bt_Valve_Rx_Data(uint8_t *data, uint8_t len)
|
||||
int BSP_Bt_Valve_Resp(uint8_t cmd, uint8_t id, uint8_t *mac_addr, uint8_t state)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
uint8_t ret = 0;
|
||||
|
||||
BtData_t *ptr = (BtData_t *)tmos_msg_allocate(sizeof(BtData_t) + 8);
|
||||
ptr->cmd = kValveCmdRem;
|
||||
ptr->buf[0] = id;
|
||||
tmos_memcpy(&ptr->buf[1], mac_addr, 6);
|
||||
ptr->buf[7] = state;
|
||||
BT_GenerateRawFrame(&valve_frame_data, (uint8_t *)ptr, 8);
|
||||
tmos_msg_deallocate((uint8_t *)ptr);
|
||||
|
||||
ret = BSP_Uart1_Send_Data((uint8_t *)&valve_frame_data.buf[0], valve_frame_data.len);
|
||||
tmos_start_task(BtRxTaskId, BT_SEND_EVT, 50);
|
||||
if (ret == valve_frame_data.len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void BSP_Valve_Init(void)
|
||||
{
|
||||
uint8_t num = Flash_Get_Valve_Num();
|
||||
uint8_t cnt = 0;
|
||||
uint8_t mac[6] = {0};
|
||||
uint8_t num = Flash_Get_Valve_Num();
|
||||
logInfo("num: %d", num);
|
||||
|
||||
logInfo("BSP_Valve_Init");
|
||||
valve_list.valve_num = num;
|
||||
for (int i = 0; i < num; i++)
|
||||
for (int i = 0; i < MAX_VALVE_NUM; i++) // 这个循环是为了将数据拷贝到valve_list中, 并且保证id号和flash对应起来
|
||||
{
|
||||
valve_list.valve_data[i].valve_id = i + 1;
|
||||
Flash_Get_Mac_Addr(valve_list.valve_data[i].valve_mac, i);
|
||||
if (num > 0)
|
||||
{
|
||||
if (Flash_Get_Mac_Addr(mac, i) == 0)
|
||||
{
|
||||
if (tmos_isbufset(mac, 0xFF, 6) == FALSE) // 不是默认值
|
||||
{
|
||||
tmos_memcpy(valve_list.valve_data[cnt].valve_mac, mac, 6); // 这样做的目的就是读取方便,只需要根据flash中读取到的数量进行读取前N个值
|
||||
valve_list.valve_data[cnt].valve_id = i + 1;
|
||||
logDebug("updata valve_id: %d, valve_mac: %02X %02X %02X %02X %02X %02X",
|
||||
valve_list.valve_data[cnt].valve_id,
|
||||
valve_list.valve_data[cnt].valve_mac[0],
|
||||
valve_list.valve_data[cnt].valve_mac[1],
|
||||
valve_list.valve_data[cnt].valve_mac[2],
|
||||
valve_list.valve_data[cnt].valve_mac[3],
|
||||
valve_list.valve_data[cnt].valve_mac[4],
|
||||
valve_list.valve_data[cnt].valve_mac[5]);
|
||||
cnt++;
|
||||
valve_list.valve_num = cnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmos_memset(&valve_list.valve_data[i], 0, sizeof(struct valve_data));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logError("BSP_Bt_Valve_Updata: flash read error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logInfo("BSP_Valve_Init end");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue