最近写了个解析指令集的,之前是一个大 switch,改动或者添加一条指令就非常麻烦。所以我就来啦!
之前我是这样的,拉跨的一批。
之后是这样的:
协议的拼凑
具体不同指令对应的不同参数部分用了键值对,键 -> 指令,值 -> 函数指针
像这样,把指令与函数对应起来,取值时就调这个函数,在函数中获取对应的参数。
是不是非常清晰了哇!我自己可都太爱这种方式了。
要是单片机中也能这样实现那可就太好了!
具体的代码
#include "mainwindow.h" | |
#include "ui_mainwindow.h" | |
#include "CRC16/crc.h" | |
#include <qstring.h> | |
#include "Conversion/conversion.h" | |
//QString str_uint8_t_to_str(uint8_t *udata,int length); | |
typedef QString (MainWindow::*function)(void);// 指令函数 typedef | |
QMap<QString, function> cmdmap_liftlamp;// 指令对应函数 | |
QMap<QString, QString> cmdmap_liftlamp_parsing;// 指令对应解析 | |
QMap<QString, QString> cmderrortype_liftlamp; | |
QMap<int, QString> cmdsend_liftlamp; | |
bool liftlampCycleSendEnable; | |
int liftlampCycleSendnumber; | |
int liftlampCycleSendnumber_max; | |
QMap<int, bool> cmdsend_liftlamp_checkbox; | |
extern CMDPARSING_UNION cmdprotocolparsing; | |
void MainWindow::vcmdmap_checkBox_status(){ | |
//----------------------- 发送遍历数组键值对 ---------------------// | |
liftlampCycleSendnumber = 0; | |
liftlampCycleSendnumber_max=6; | |
cmdsend_liftlamp[0]="030101"; | |
cmdsend_liftlamp_checkbox[0]=ui->checkBox_ID->checkState(); | |
cmdsend_liftlamp[1]="030102"; | |
cmdsend_liftlamp_checkbox[1]=ui->checkBox_data->checkState(); | |
cmdsend_liftlamp[2]="03010D"; | |
cmdsend_liftlamp_checkbox[2]=ui->checkBox_lora_1->checkState(); | |
cmdsend_liftlamp[3]="030112"; | |
cmdsend_liftlamp_checkbox[3]=ui->checkBox_lora_AES->checkState(); | |
cmdsend_liftlamp[4]="03010F"; | |
cmdsend_liftlamp_checkbox[4]=ui->checkBox_lora_rate->checkState(); | |
cmdsend_liftlamp[5]="030113"; | |
cmdsend_liftlamp_checkbox[5]=ui->checkBox_current_value->checkState(); | |
} | |
void vcmdmapInit_liftlamp(){ | |
//----------------------- 指令对应解析 ---------------------// | |
cmdmap_liftlamp_parsing["010101"] = "任务执行"; | |
cmdmap_liftlamp_parsing["010102"] = "任务结束"; | |
cmdmap_liftlamp_parsing["010103"] = "开灯"; | |
cmdmap_liftlamp_parsing["010104"] = "关灯"; | |
cmdmap_liftlamp_parsing["020100"] = "设置进入"; | |
cmdmap_liftlamp_parsing["030101"] = "设置设备ID号"; | |
cmdmap_liftlamp_parsing["030102"] = "设置日期"; | |
cmdmap_liftlamp_parsing["030103"] = "设置设备资源"; | |
cmdmap_liftlamp_parsing["030104"] = "设置灯下降高度"; | |
cmdmap_liftlamp_parsing["030105"] = "设置极限高度"; | |
cmdmap_liftlamp_parsing["030106"] = "设置极限时间"; | |
cmdmap_liftlamp_parsing["030107"] = "自动设置极限时间开始"; | |
cmdmap_liftlamp_parsing["030108"] = "自动设置极限时间结束"; | |
cmdmap_liftlamp_parsing["030109"] = "设置工作时间"; | |
cmdmap_liftlamp_parsing["03010A"] = "设置科室、房间号"; | |
cmdmap_liftlamp_parsing["03010B"] = "设置科室、房间号、灯下降高度"; | |
cmdmap_liftlamp_parsing["03010C"] = "设置微波增益"; | |
cmdmap_liftlamp_parsing["03010D"] = "设置LoRa信道"; | |
cmdmap_liftlamp_parsing["03010E"] = "设置LoRa发送功率"; | |
cmdmap_liftlamp_parsing["03010F"] = "设置LoRa空速"; | |
cmdmap_liftlamp_parsing["030110"] = "设置LoRa Uart 波特率"; | |
cmdmap_liftlamp_parsing["030111"] = "设置LoRa信道、空速、功率"; | |
cmdmap_liftlamp_parsing["030112"] = "设置LoRa AES密钥"; | |
cmdmap_liftlamp_parsing["030113"] = "设置电机参考电压"; | |
cmdmap_liftlamp_parsing["03011A"] = "设置云平台下发参数"; | |
cmdmap_liftlamp_parsing["03011F"] = "清除故障标记"; | |
cmdmap_liftlamp_parsing["030120"] = "清除灯升降次数、灯点亮时间"; | |
cmdmap_liftlamp_parsing["030121"] = "系统恢复默认配制"; | |
cmdmap_liftlamp_parsing["030130"] = "保存设置并退出"; | |
cmdmap_liftlamp_parsing["030131"] = "退出设置不保存"; | |
cmdmap_liftlamp_parsing["040101"] = "获得设备状态"; | |
cmdmap_liftlamp_parsing["040102"] = "获得系统配制参数"; | |
cmdmap_liftlamp_parsing["040103"] = "获得电机电流、灯电流"; | |
cmdmap_liftlamp_parsing["040104"] = "获得设备工作状态"; | |
cmdmap_liftlamp_parsing["050100"] = "进入手动调试模式"; | |
cmdmap_liftlamp_parsing["060100"] = "退出手动调试模式"; | |
cmdmap_liftlamp_parsing["070101"] = "调试模式指令空闲"; | |
cmdmap_liftlamp_parsing["070102"] = "调试模式指令灯架上升"; | |
cmdmap_liftlamp_parsing["070103"] = "调试模式指令灯架下降"; | |
cmdmap_liftlamp_parsing["070104"] = "调试模式指令灯亮灭"; | |
cmdmap_liftlamp_parsing["080100"] = "透传指令"; | |
cmdmap_liftlamp_parsing["090100"] = "系统复位指令"; | |
cmdmap_liftlamp_parsing["AC0100"] = "接收到的数据有效"; | |
cmdmap_liftlamp_parsing["AC0101"] = "接收到的数据无效"; | |
cmdmap_liftlamp_parsing["FF0101"] = "设备工作状态"; | |
cmdmap_liftlamp_parsing["FF0102"] = "设备工作结束上传参数"; | |
cmdmap_liftlamp_parsing["FF0103"] = "系统配制参数"; | |
cmdmap_liftlamp_parsing["FF0104"] = "警告命令用于警告联网"; | |
//----------------------- 指令对应函数 ---------------------// | |
cmdmap_liftlamp["设置设备ID号"]=&MainWindow::sprotocol_liftlampGetPar_ID; | |
cmdmap_liftlamp["设置日期"]=&MainWindow::sprotocol_liftlampGetPar_DATA; | |
cmdmap_liftlamp["设置LoRa信道"]=&MainWindow::sprotocol_liftlampGetPar_LORA_Channel; | |
cmdmap_liftlamp["设置LoRa AES密钥"]=&MainWindow::sprotocol_liftlampGetPar_LORA_AES; | |
cmdmap_liftlamp["设置LoRa空速"]=&MainWindow::sprotocol_liftlampGetPar_LORA_Rate; | |
cmdmap_liftlamp["设置电机参考电压"]=&MainWindow::sprotocol_liftlampGetPar_MOTOR_Current; | |
cmdmap_liftlamp["进入手动调试模式"]=&MainWindow::sprotocol_liftlampGetPar_void; | |
cmdmap_liftlamp["退出手动调试模式"]=&MainWindow::sprotocol_liftlampGetPar_void; | |
cmdmap_liftlamp["调试模式指令灯架上升"]=&MainWindow::sprotocol_liftlampGetPar_void; | |
cmdmap_liftlamp["调试模式指令灯架下降"]=&MainWindow::sprotocol_liftlampGetPar_void; | |
cmdmap_liftlamp["调试模式指令灯亮灭"]=&MainWindow::sprotocol_liftlampGetPar_void; | |
cmdmap_liftlamp["获得系统配制参数"]=&MainWindow::sprotocol_liftlampGetPar_void; | |
cmdmap_liftlamp["获得电机电流、灯电流"]=&MainWindow::sprotocol_liftlampGetPar_void; | |
} | |
void MainWindow::vprotocol_liftlamp_send_Auto(){ | |
// 使能了循环发送 | |
if(liftlampCycleSendEnable){ | |
while((liftlampCycleSendnumber<liftlampCycleSendnumber_max)&&(!cmdsend_liftlamp_checkbox.value(liftlampCycleSendnumber))){ | |
liftlampCycleSendnumber++; | |
} | |
if((liftlampCycleSendnumber)>=liftlampCycleSendnumber_max){ | |
liftlampCycleSendnumber=0; | |
liftlampCycleSendEnable=false; | |
// 配置完成后,写入记录 | |
vexcelCmdAddLog(); | |
// 配置完后把 ID 自增 1 | |
vcmdmap_Cycle_Send_Over_ID(true); | |
return ; | |
} | |
vprotocol_liftlamp_send(cmdsend_liftlamp.value(liftlampCycleSendnumber)); | |
liftlampCycleSendnumber++; | |
} | |
} | |
void MainWindow::vprotocol_liftlamp_send(QString value){ | |
// 拼接字符串 | |
QString qstring_context = ""; | |
// 帧头 | |
qstring_context.append("FB"); | |
// 添加指令 | |
qstring_context.append(value); | |
// 添加状态 | |
qstring_context.append("00"); | |
// 添加源设备 | |
qstring_context.append("00000000"); | |
// 添加目标设备 | |
if(ui->tabWidget_factory->currentIndex()==0){ | |
qstring_context.append("00000000"); | |
}else{ | |
if(value=="040102"){ | |
qstring_context.append("00000000"); | |
}else{ | |
qstring_context.append(ui->lineEdit_liftlamp_ID->text()); | |
} | |
} | |
// 添加参数 | |
QString (MainWindow::*getpar)(void); | |
getpar=cmdmap_liftlamp.value(cmdmap_liftlamp_parsing.value(value)); | |
qstring_context.append((this->*getpar)()); | |
// 计算 CRC | |
QString str_crc=qstring_context; | |
str_crc.remove(0,2);// 去掉帧头 | |
qstring_context.append(qstrCrcCalc(str_crc).mid(2,2)+qstrCrcCalc(str_crc).mid(0,2)); | |
//qstring_context.append(qstrCrcCalc(str_crc)); | |
// 添加帧尾 | |
qstring_context.append("FE"); | |
// 发送 | |
ServerPortSendData(qstring_context); | |
} | |
// 接收指令后的解析 | |
void MainWindow::vprotocol_liftlamp_cmdparsing(int length){ | |
if(cmdprotocolparsing.info.data_head!=0xFB){ | |
// 找不到头 | |
memset(cmdprotocolparsing.byte,0,1024); | |
return; | |
} | |
int datalength = (cmdprotocolparsing.byte[14]<<8)+cmdprotocolparsing.byte[13]; | |
if(datalength>=1024){ | |
datalength=1024; | |
} | |
// 判断 CRC | |
uint16_t crccompare=uiCRC16Calc(cmdprotocolparsing.byte+1,datalength+15+3-4); | |
cmdprotocolparsing.info.crc[1]=cmdprotocolparsing.byte[datalength+15+3-3]; | |
cmdprotocolparsing.info.crc[0]=cmdprotocolparsing.byte[datalength+15+3-2]; | |
cmdprotocolparsing.info.data_end=cmdprotocolparsing.byte[datalength+15+3-1]; | |
cmdprotocolparsing.byte[datalength+15+3-3]=0; | |
cmdprotocolparsing.byte[datalength+15+3-2]=0; | |
cmdprotocolparsing.byte[datalength+15+3-1]=0; | |
//crc | |
if(crccompare!=((cmdprotocolparsing.info.crc[0]<<8)+cmdprotocolparsing.info.crc[1])){ | |
return; | |
} | |
// 上行数据 | |
if(cmdprotocolparsing.info.status!=0x01){ | |
return; | |
} | |
// 设备为升降灯 | |
if(cmdprotocolparsing.info.devtype==0x01){ | |
int cmdlength = cmdprotocolparsing.info.parlen[0]+(cmdprotocolparsing.info.parlen[1]<<8); | |
// 应答 | |
if(cmdprotocolparsing.info.cmd.DataByte==0xAC){ | |
// 有效 | |
if(cmdprotocolparsing.info.fun==0x00){ | |
if(CurrentButton == "自动获取"){ | |
QString LampID = str_uint8_t_to_str(cmdprotocolparsing.info.sdevid,4); | |
if(LampID!=ui->lineEdit_liftlamp_ID->text()){ | |
ui->lineEdit_liftlamp_ID->setText(LampID); | |
} | |
}else if(CurrentButton == "进入调试"){ | |
}else if(CurrentButton == "上升"){ | |
}else if(CurrentButton == "下降"){ | |
}else if(CurrentButton == "开灯"){ | |
}else if(CurrentButton == "获取电流"){ | |
// 判断长度 | |
if(cmdlength==5+4){ | |
// 长度没问题 | |
// | |
//[0]:灯的工作状态 | |
//1234 环境信噪比 | |
//[5-6]:电机电流 | |
//[7-8]:灯电流 FB AC 01 00 01 04 00 00 01 00 00 00 00 09 00 08 10 A1 E0 00 0A 00 01 00 DE DC FE | |
int motorcurrent = cmdprotocolparsing.info.par[5]+(cmdprotocolparsing.info.par[6]<<8); | |
int lampcurrent = cmdprotocolparsing.info.par[7]+(cmdprotocolparsing.info.par[8]<<8); | |
ui->lcdNumber_real_time_curent->display(motorcurrent); | |
ui->lcdNumber_real_time_curent_lamp->display(lampcurrent); | |
} | |
} | |
} | |
} | |
} | |
} | |
// 参数增加长度 | |
QString sprotocol_liftlampMakeup_str_addlen(QString string,int length){ | |
QString string_c = string; | |
uint8_t u8length[2]; | |
u8length[0]=length/2; | |
u8length[1]=(length/2)>>8; | |
string_c.insert(0,str_uint8_t_to_str(u8length,2)); | |
return string_c; | |
} | |
// 字符串补齐 并添加长度 | |
QString sprotocol_liftlampMakeup_str_len(QString string,int length){ | |
QString string_complete; | |
string_complete=string; | |
while((string_complete.length()<length)||((string_complete.length()%2)!=0)){ | |
string_complete.insert(0,"0"); | |
} | |
string_complete = sprotocol_liftlampMakeup_str_addlen(string_complete,length); | |
return string_complete; | |
} | |
// 获取指令参数 | |
QString MainWindow::sprotocol_liftlampGetPar_void(){ | |
static QString par="0000"; | |
return par; | |
} | |
QString MainWindow::sprotocol_liftlampGetPar_ID(){ | |
QString par=ui->lineEdit_liftlampID->text(); | |
par = sprotocol_liftlampMakeup_str_len(par,8); | |
return par; | |
} | |
QString MainWindow::sprotocol_liftlampGetPar_DATA(){ | |
QString par=ui->lineEdit_liftlamp_data->text(); | |
par = sprotocol_liftlampMakeup_str_len(par,8); | |
return par; | |
} | |
QString MainWindow::sprotocol_liftlampGetPar_LORA_Channel(){ | |
QString par=ui->lineEdit_lora_1->text(); | |
par = sprotocol_liftlampMakeup_str_len(par,2); | |
return par; | |
} | |
QString MainWindow::sprotocol_liftlampGetPar_LORA_AES(){ | |
QString par=ui->lineEdit_lora_AES->text(); | |
par = sprotocol_liftlampMakeup_str_len(par,16*2); | |
return par; | |
} | |
QString MainWindow::sprotocol_liftlampGetPar_LORA_Rate(){ | |
QString par=ui->lineEdit_lora_rate->text(); | |
par = sprotocol_liftlampMakeup_str_len(par,2); | |
return par; | |
} | |
QString MainWindow::sprotocol_liftlampGetPar_MOTOR_Current(){ | |
QString par=ui->lineEdit_current_value->text(); | |
par = sprotocol_liftlampMakeup_str_len(par,4); | |
return par; | |
} | |
QString MainWindow::sprotocol_liftlampGetPar_LAMP_Current(){ | |
QString par=ui->lineEdit_current_value_2->text(); | |
par = sprotocol_liftlampMakeup_str_len(par,4); | |
return par; | |
} |