WTZSSoftWare/Src/Communicaion.c

494 lines
16 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "cmsis_os.h"
#include "cmsis_os2.h"
#include "main.h"
#include "stdio.h"
#include "usb_device.h"
#include <math.h>
#include <stdint.h>
#include <string.h>
typedef struct
{
const char *cmd;
int cmd_id;
} CmdTable;
/*
自定义协议
帧头 0xAA 55
帧长度 1字节
帧序号 1字节
帧类型 1字节
数据域 N字节
帧校验 1字节
| 帧头 | 命令 | 长度 | 帧号 | 数据 (128B) | CRC16 |
|--------|------|--------|------|-------------|--------|
| AA 55 | 01 | 00 80 | 01 | [0xXX...] | 2字节 |
| 帧头 | 命令 | 长度 | 帧号 | 数据 (128B) | CRC16 |
|--------|------|--------|------|-------------|--------|
| AA 55 | 04 | 00 80 | FF | 00 |
*/
// extern uint8_t Uart_ReadCache[128];
// extern _Bool ReadFlag;
// uint8_t CPk = 0; // 当前包计数
// void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
// {
// UNUSED(huart);
// __HAL_UART_CLEAR_OREFLAG(huart);
// __HAL_UART_CLEAR_IDLEFLAG(huart);
// if(__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) != RESET) //
// 空闲中断标记被置位
// {
// __HAL_UART_CLEAR_IDLEFLAG(huart); // 清除中断标记
// HAL_UART_DMAStop(huart); // 停止DMA接收
// CPk = __HAL_DMA_GET_COUNTER(huart->hdmarx); // 总数据量
// HAL_UARTEx_ReceiveToIdle_DMA(huart, Uart_ReadCache, 128); //
// 重新启动DMA接收
// }
// // if ((Uart_ReadCache[0] == 'C') && (Uart_ReadCache[1] == 'M') &&
// (Uart_ReadCache[2] == 'D'))
// // {
// // char buf[10];
// // uint16_t i,j,k= 0;
// // HAL_GPIO_WritePin( GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
// // for( k = 0; k < 8; k ++ )
// // {
// // for( i = 0; i < 3; i ++)
// // {
// // for( j = 0; j < 98; j ++)
// // {
// // sprintf( buf, "%.4f\r\n", OutPut1[k][i][j]);
// // HAL_UART_Transmit(&huart, (uint8_t
// *)buf,strlen(buf),0xFFFF);
// // while(HAL_UART_GetState(&huart) ==
// HAL_UART_STATE_BUSY_TX);//锟斤拷锟経ART锟斤拷锟酵斤拷锟斤拷
// // }
// // }
// // }
// // ReadFlag = 1;
// // HAL_GPIO_WritePin( GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
// // }
// // HAL_UARTEx_ReceiveToIdle_IT(&huart1, (uint8_t *)&Uart_ReadCache, 100);
// //锟劫匡拷锟斤拷锟斤拷锟斤拷锟叫讹拷
// }
// #include "command.h"
// 假设每个通道每个频率点4字节(float)每帧最大数据长度为120字节(30个float)
#define MAX_FRAME_DATA_LEN 120
// 指令的最小长度
#define COMMAND_MIN_LENGTH 4
// 循环缓冲区大小
#define BUFFER_SIZE 121
// 循环缓冲区
uint8_t buffer[BUFFER_SIZE];
// 循环缓冲区读索引
uint8_t readIndex = 0;
// 循环缓冲区写索引
uint8_t writeIndex = 0;
/**
* @brief 增加读索引
* @param length 要增加的长度
*/
void Command_AddReadIndex(uint8_t length)
{
readIndex += length;
readIndex %= BUFFER_SIZE;
}
/**
* @brief 读取第i位数据 超过缓存区长度自动循环
* @param i 要读取的数据索引
*/
uint8_t Command_Read(uint8_t i)
{
uint8_t index = i % BUFFER_SIZE;
return buffer[index];
}
/**
* @brief 计算未处理的数据长度
* @return 未处理的数据长度
* @retval 0 缓冲区为空
* @retval 1~BUFFER_SIZE-1 未处理的数据长度
* @retval BUFFER_SIZE 缓冲区已满
*/
// uint8_t Command_GetLength() {
// // 读索引等于写索引时,缓冲区为空
// if (readIndex == writeIndex) {
// return 0;
// }
// // 如果缓冲区已满,返回BUFFER_SIZE
// if (writeIndex + 1 == readIndex || (writeIndex == BUFFER_SIZE - 1 &&
// readIndex == 0)) {
// return BUFFER_SIZE;
// }
// // 如果缓冲区未满,返回未处理的数据长度
// if (readIndex <= writeIndex) {
// return writeIndex - readIndex;
// } else {
// return BUFFER_SIZE - readIndex + writeIndex;
// }
// }
uint8_t Command_GetLength() { return (writeIndex + BUFFER_SIZE - readIndex) % BUFFER_SIZE; }
/**
* @brief 计算缓冲区剩余空间
* @return 剩余空间
* @retval 0 缓冲区已满
* @retval 1~BUFFER_SIZE-1 剩余空间
* @retval BUFFER_SIZE 缓冲区为空
*/
uint8_t Command_GetRemain() { return BUFFER_SIZE - Command_GetLength(); }
/**
* @brief 向缓冲区写入数据
* @param data 要写入的数据指针
* @param length 要写入的数据长度
* @return 写入的数据长度
*/
uint8_t Command_Write(uint8_t *data, uint16_t length)
{
// 如果缓冲区不足 则不写入数据 返回0
if (Command_GetRemain() < length)
{
return 0;
}
// 使用memcpy函数将数据写入缓冲区
if (writeIndex + length < BUFFER_SIZE)
{
memcpy(buffer + writeIndex, data, length);
writeIndex += length;
}
else
{
uint8_t firstLength = BUFFER_SIZE - writeIndex;
memcpy(buffer + writeIndex, data, firstLength);
memcpy(buffer, data + firstLength, length - firstLength);
writeIndex = length - firstLength;
}
return length;
}
/**
* @brief 尝试获取一条指令
* @param command 指令存放指针
* @return 获取的指令长度
* @retval 0 没有获取到指令
*/
uint8_t Command_GetCommand(uint8_t *command)
{
/*
| 帧头 | 命令 | 长度 | 帧号 | 数据 (128B) | CRC16 |
|--------|------|--------|------|-------------|--------|
| AA 55 | 04 | 80 | FF | 00 |
*/
// 寻找完整指令
while (1)
{
// 如果缓冲区长度小于COMMAND_MIN_LENGTH 则不可能有完整的指令
if (Command_GetLength() < COMMAND_MIN_LENGTH)
{
return 0;
}
// 如果不是包头 则跳过 重新开始寻找
if (((Command_Read(readIndex) != 0xAA) || (Command_Read(readIndex + 1) != 0x55)))
{
Command_AddReadIndex(1);
continue;
}
// 如果缓冲区长度小于指令长度 则不可能有完整的指令
uint8_t length = Command_Read(readIndex + 3);
if (Command_GetLength() < length)
{
return 0;
}
// 如果校验和不正确 则跳过 重新开始寻找
uint16_t sum = 0;
for (uint8_t i = 0; i < length - 2; i++)
{
sum += Command_Read(readIndex + i);
}
if (sum != (Command_Read(readIndex + length - 2) << 8 | Command_Read(readIndex + length - 1)))
{
Command_AddReadIndex(1);
continue;
}
// 如果找到完整指令 则将指令写入command 返回指令长度
for (uint8_t i = 0; i < length; i++)
{
command[i] = Command_Read(readIndex + i);
}
Command_AddReadIndex(length);
return length;
}
}
extern osSemaphoreId_t Command_Semaphore;
extern UART_HandleTypeDef huart1;
extern uint16_t CLKHZ[98];
extern void CLKHZSET(uint16_t Deep);
extern float LineCheckF[32];
union
{
float ufloat;
uint32_t u32;
uint16_t u16[2];
uint8_t u8[4];
} uDataCover;
uint16_t FramePack(uint8_t *buf, uint8_t cmd, uint8_t frameNum, uint8_t *data, uint16_t dataLength)
{
uint8_t Lenth = 0;
uint16_t crcSum = 0;
memset(buf, 0, 128);
buf[0] = 0xAA; // 帧头
buf[1] = 0x55; // 帧头
buf[2] = cmd; // 命令
buf[3] = 0x00; // 长度
buf[4] = frameNum; // 帧号
Lenth = 7;
for (uint8_t i = 0; i < 5; i++)
{
crcSum += buf[i];
}
for (uint8_t i = 0; i < dataLength; i++)
{
buf[i + 5] = data[i];
crcSum += data[i];
Lenth += 1;
}
buf[3] = Lenth; // 更新长度
crcSum +=Lenth;
buf[Lenth - 2] = crcSum >> 8; // CRC高字节
buf[Lenth - 1] = crcSum & 0xFF; // CRC低字节
return Lenth;
}
struct uCommunication CommunicationData;
extern float OutPut1[8][4][98];
extern float OutPut2[8][4][98];
extern float OutPut3[8][4][98];
extern float OutPut4[8][4][98];
extern uint8_t Uart_ReadCache[128];
uint8_t command[50];
uint8_t SendBuf[128];
int commandLength = 0;
uint8_t dtime = 10;
void Command_Deal(void)
{
osSemaphoreAcquire(Command_Semaphore, osWaitForever); // 等待命令信号量
do
{
memset(command,0,50);
commandLength = Command_GetCommand(command);
if (commandLength == 0)
{
return;
}
uint8_t cmd = command[2]; // 获取命令
uint8_t SenDataLenth = 0;
switch (cmd)
{
case 1: // 开始测试命令
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_7, GPIO_PIN_RESET);
osDelay(50);
HAL_GPIO_WritePin(GPIOI, GPIO_PIN_7, GPIO_PIN_SET);
CommunicationData.MeasurementPrecision = 0;
CommunicationData.MeasurementFlag = 1;
break;
case 2: // 终止测试命令
CommunicationData.MeasurementPrecision = 0;
CommunicationData.MeasurementFlag = 0;
break;
case 3: // 设定深度
CommunicationData.Deep = (command[5] << 8) | command[6];
CLKHZSET(CommunicationData.Deep);
break;
case 4: // 设置增益
CommunicationData.Gain = command[5];
break;
case 5: // 设定通道数量
CommunicationData.ChannelNum = command[5];
break;
case 6: // 道接地信号强度测试命令
CommunicationData.SingelStrengthMeasurementFlag = 1;
CommunicationData.MeasurementPrecision = 0;
break;
case 7: // 获取通道接地信号强度
if (CommunicationData.MeasurementPrecision == 100.0f)
{
SenDataLenth = FramePack(SendBuf, 0x07, 0x01, (uint8_t *)LineCheckF, 16 * 4);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_UART_Transmit(&huart1, SendBuf, SenDataLenth, HAL_MAX_DELAY);
while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX)
; // 等待UART发送完成
osDelay(50);
SenDataLenth = FramePack(SendBuf, 0x07, 0xFF, (uint8_t *)(LineCheckF + 16), 16 * 4);
HAL_UART_Transmit(&huart1, SendBuf, SenDataLenth, HAL_MAX_DELAY);
while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX)
;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
osDelay(100);
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, Uart_ReadCache, 128); // 重新启动DMA接收
}
break;
case 8: // 获取测量进度
{
SenDataLenth = FramePack(SendBuf, 0x08, 0xFF, (uint8_t *)&CommunicationData.MeasurementPrecision, 1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_UART_Transmit(&huart1, SendBuf, SenDataLenth, HAL_MAX_DELAY);
while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX)
; // 等待UART发送完成
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
break;
}
case 9: // 获取测量结果
if (CommunicationData.MeasurementPrecision == 100.0f)
{
uint8_t totalChannels = CommunicationData.ChannelNum;
uint8_t totalFreqs = 0;
for (uint8_t i = 0; i < 98; i++)
{
if (CLKHZ[i] != 0)
totalFreqs++;
else
break;
}
uint32_t totalDataLen = totalChannels * totalFreqs * 4;
uint8_t frameNum = 1;
uint32_t sentLen = 0;
while (sentLen < totalDataLen)
{
/**
* 根据剩余待发送数据长度,计算本次发送的数据长度,并组装数据帧。
*
* 1. 计算本次发送的数据长度 sendLen不超过 MAX_FRAME_DATA_LEN。
* 2. 初始化数据缓冲区 dataBuf。
* 3. 遍历每个待发送的 float 数据(每 4 字节为一个 float根据 globalIdx 计算通道号 ch 和频点 freq。
* 4. 根据通道号 ch 从对应的 OutPut 数组中获取数据 val。
* - ch < 8: 从 OutPut1 取数据
* - ch < 16: 从 OutPut2 取数据
* - ch < 24: 从 OutPut3 取数据
* - ch < 32: 从 OutPut4 取数据
* 5. 将获取到的 float 数据 val 拷贝到 dataBuf 中,准备发送。
*
* 参数说明:
* - totalDataLen: 总数据长度(字节)
* - sentLen: 已发送的数据长度(字节)
* - MAX_FRAME_DATA_LEN: 单帧最大数据长度(字节)
* - totalChannels: 总通道数
* - OutPut1~4: 四组输出数据数组
*/
uint32_t remain = totalDataLen - sentLen;
uint8_t sendLen = (remain > MAX_FRAME_DATA_LEN) ? MAX_FRAME_DATA_LEN : remain;
uint8_t dataBuf[MAX_FRAME_DATA_LEN];
// 组装数据
uint32_t dataIdx = 0;
uint32_t globalIdx = sentLen / 4;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
osDelay(dtime);
for (uint8_t i = 0; i < sendLen / 4; i++)
{
uint8_t ch = (globalIdx % totalChannels);
uint8_t freq = (globalIdx / totalChannels);
float val = 0.0f;
if (ch < 8)
val = OutPut1[ch][0][freq];
else if (ch < 16)
val = OutPut2[ch - 8][0][freq];
else if (ch < 24)
val = OutPut3[ch - 16][0][freq];
else if (ch < 32)
val = OutPut4[ch - 24][0][freq];
memcpy(&dataBuf[dataIdx], &val, 4);
dataIdx += 4;
globalIdx++;
}
uint8_t thisFrameNum = (sentLen + sendLen >= totalDataLen) ? 0xFF : frameNum;
SenDataLenth = FramePack(SendBuf, 0x09, thisFrameNum, dataBuf, sendLen);
HAL_UART_Transmit(&huart1, SendBuf, SenDataLenth, HAL_MAX_DELAY);
while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX)
;
sentLen += sendLen;
frameNum++;
}
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
osDelay(100);
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, Uart_ReadCache, 128); // 重新启动DMA接收
}
break;
case 10: // 获取电池电压
SenDataLenth = FramePack(SendBuf, 0x0A, 0x01, (uint8_t *)&CommunicationData.BatteryVoltage, 4);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_UART_Transmit(&huart1, SendBuf, SenDataLenth, HAL_MAX_DELAY);
while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX)
; // 等待UART发送完成
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
break;
case 11: // 获取电流
SenDataLenth = FramePack(SendBuf, 0x0B, 0x01, (uint8_t *)&CommunicationData.BatteryCurrent, 4);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_UART_Transmit(&huart1, SendBuf, SenDataLenth, HAL_MAX_DELAY);
while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX)
; // 等待UART发送完成
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
break;
}
}
while(commandLength != 0);
}
/*
| 帧头 | 命令 | 长度 | 帧号 | 数据 (128B) | CRC16 |
|--------|------|--------|------|-------------|--------|
| AA 55 | 04 | 80 | FF | 00 |
设定频率
设置增益
设定通道数量
道接地信号强度测试命令
获取通道接地信号强度
开始测试命令
终止测试命令
获取测量进度
获取测量结果
获取电池电压
获取电流
CmdTable cmd_table[] = {
{"CMD_START", 1}, // 开始测试命令
{"CMD_STOP", 2}, // 终止测试命令
{"CMD_SET_FREQ", 3}, // 设定深度
{"CMD_SET_GAIN", 4}, // 设置增益
{"CMD_SET_CHANNELS", 5}, // 设定通道数量
{"CMD_TEST_GROUND", 6}, // 道接地信号强度测试命令
{"CMD_GET_GROUND", 7}, // 获取通道接地信号强度
{"CMD_GET_PROGRESS", 8}, // 获取测量进度
{"CMD_GET_RESULT", 9}, // 获取测量结果
{"CMD_GET_BATTERY_VOLTAGE", 10}, // 获取电池电压
{"CMD_GET_CURRENT", 11}, // 获取电流
// ...更多命令
};
*/