📄 protocol.c
字号:
//work
//1.设置采集器地址不需长按按键
//2.
// 载波缓冲区,检测
void upCommCheck(void)
{
unsigned char temp;
unsigned char serial;
unsigned int addr;
if(BuffPLCMark.Sta != c_RecEnd) //载波接收完成?
{
return;
}
//载波帧格式判断,并数据域减33
if(_FALSE == frame645Checklow(BuffPLC))
{
goto BuffPLCCheckErr; //指令错误
}
temp = BuffPLC[c_OffsetC];
if((temp&0x80) != 0)
{
goto BuffPLCCheckErr; //防止某些表,红外载波一起往外发数据!!
}
//指令参数保存
v_FrameC = BuffPLC[c_OffsetC];
v_FrameL = BuffPLC[c_OffsetL];
v_DI0 = BuffPLC[c_OffsetDI0];
v_DI1 = BuffPLC[c_OffsetDI1];
//判断是否为广播命令
if(0x0 == lowmemcmppgm2ram(BuffPLC+1, RomBroadID, 6u))
{
//******* 广播指令处理 ************
if(_TRUE == BroadDispose()) //广播指令处理
{
goto BuffPLCCheckEnd;
}
else
{
goto BuffPLCCheckErr;
}
}
///////////////指令处理///////////////
//1.判断指令来源,红外需要判地址
if(c_Port_Irf == v_RecPort)
{
if(0 != memcmph2l(BuffPLC+1, CollectorID, 6))
{
goto BuffPLCCheckErr; //地址不对
}
}
else
{
memcpyl2h(CollectorID, BuffPLC+1, 6); //防止没有设置红外地址
}
//判断指令对象
if(_FALSE == CommObjCheck()) //判断指令对象
{
//*******************************************************
//* 针对电表相关操作
//*******************************************************/
//保存指令中电表表号
memcpyl2h(MeterID, (BuffPLC+c_OffsetData+v_FrameL-8), 0x06);
//获取电表序号
serial = getMeterSr(MeterID); //获取电表序号
//*************************** linyou, 2008-11-20
//确定规约格式,通过控制字确认。0x11,0x14为07版645。其他默认为97版645
if((v_FrameC == 0x11) || (0x14 == v_FrameC))
{
v_frame_mark = _frame_07;
goto RtTaskset; //07直接透传
}
else
{
v_frame_mark = _frame_97;
}
//***************************
if(v_FrameC == 0x01u)
{
v_DirRetCont = 0; //备份数据有效期计数器
//判断抄表间隔0xff透传
getStrFM(tempBuff, a_AmrSpace, 1);
temp = tempBuff[0];
if(temp == 0xff) goto RtTaskset;
//判断表号是否存在
if(serial > c_MaxMeterAmount) //序号大于容量即是不存在
{
//该电表不存在,保存该表号
serial = addOneMeter(MeterID); //只需要表号,返回序号
//设置测试任务
if(c_TaskFree == TestTask.start)
{
//空闲才设定
TestTask.start = c_TaskAllStart;
TestTask.Sta = c_TaskFree;
TestTask.serial = serial;
}
goto RtTaskset;
}
else
{
//电表存在
//判断抄读标识
if(0x90 == v_DI1)
{
//读取失败次数,确认数据有效性
getStrFM(tempBuff, a_FalseNO + serial*c_OneSize, 1);
if(0x0 != tempBuff[0]) goto RtTaskset;
//抄读当前电能块,第一字节是长度
getStrFMlow(BuffPLC+c_OffsetDI1, a_Consume + serial*c_OneSize, 20+1);
//数据处理
if(0x1f == v_DI0)
{
v_FrameL = BuffPLC[c_OffsetDI1] + 2 + 6; //数据长度 + DI0DI1
memcpyh2l(BuffPLC+c_OffsetData+v_FrameL-8, MeterID, 6);
v_FrameC = 0x81;
goto BuffPLCCheckEnd;
}
else if(0x10 == v_DI0)
{
//抄读当前总电能
v_FrameL = 0x04 + 2 + 6; //数据长度 + DI0DI1
memcpyh2l(BuffPLC+c_OffsetData+4, MeterID, 6);
v_FrameC = 0x81;
goto BuffPLCCheckEnd;
}
}
else if((0x9a == v_DI1) || (0x9e == v_DI1))
{
//抄读冻结电能块:日期+长度+数据,
//不能使用上行缓冲区,否则判断和上次指令是否一致时有误
getStrFM(tempBuff, a_FzConsume + serial*c_OneSize, 20+2);
//数据有效性判断
if(tempBuff[0] == 0)
{
//读取失败次数,确认当前数据有效性
getStrFM(tempBuff, a_FalseNO + serial*c_OneSize, 1);
if(0x0 != tempBuff[0]) goto RtTaskset;
//抄读当前电能块,第一字节是长度
getStrFM(tempBuff+1, a_Consume + serial*c_OneSize, 20+1);
}
//转移数据到上行缓冲区
v_FrameL = tempBuff[1]; //数据长度
memcpyh2l(BuffPLC+c_OffsetData, tempBuff+2, v_FrameL);
if(0x1f == v_DI0)
{
v_FrameL += 8; //数据长度 + DI0DI1 + 表号
memcpyh2l(BuffPLC+c_OffsetData+v_FrameL-8, MeterID, 6);
v_FrameC = 0x81;
goto BuffPLCCheckEnd;
}
else if(0x10 == v_DI0)
{
//抄读冻结总电能
v_FrameL = 0x04 + 2 + 6; //数据长度 + DI0DI1 + 表号
memcpyh2l(BuffPLC+c_OffsetData+4, MeterID, 6);
v_FrameC = 0x81;
goto BuffPLCCheckEnd;
}
goto BuffPLCCheckErr;
}
else if((0xE8 == v_DI1) || (0x9d == v_DI1))
{
//获取标志
getStrFM(tempBuff, a_24ConMark, 0x02);
//当前日期减一
highmemcpy(tempBuff+2, timerBuff+dd, 3);
DateDec(tempBuff+2);
if(tempBuff[0] == tempBuff[2])
{
addr = a_24Consume0; //返回前一天数据
}
else if(tempBuff[1] == tempBuff[2])
{
addr = a_24Consume1;
}
else
{
v_hhTask = timerBuff[hh];
v_hhTask = bytebcdtohex(v_hhTask); //开始一次小时抄读
goto BuffPLCCheckErr;
}
v_FrameC = 0x81;
if(0xE8 == v_DI1)
{
v_FrameL = 32; //2+24+6=32
memcpyh2l(BuffPLC+c_OffsetData+24, MeterID, 6);
}
else
{
v_FrameL = 2+16+6;
memcpyh2l(BuffPLC+c_OffsetData+16, MeterID, 6);
}
if(0x60 == v_DI0)
{
//0~5点整点电量
getStrFMlow(BuffPLC+c_OffsetData, (addr+c_OneSize*serial), 24);
goto BuffPLCCheckEnd;
}
else if(0x61 == v_DI0)
{
//6~11点整点电量
getStrFMlow(BuffPLC+c_OffsetData, (addr+c_OneSize*serial+24), 24);
goto BuffPLCCheckEnd;
}
else if(0x62 == v_DI0)
{
//12~17点整点电量
getStrFMlow(BuffPLC+c_OffsetData, (addr+c_OneSize*serial+48), 24);
goto BuffPLCCheckEnd;
}
else if(0x63 == v_DI0)
{
//18~23点整点电量
getStrFMlow(BuffPLC+c_OffsetData, (addr+c_OneSize*serial)+72, 24);
goto BuffPLCCheckEnd;
}
else if(0x30 == v_DI0)
{
//0~3点
getStrFMlow(BuffPLC+c_OffsetData, (addr+c_OneSize*serial), 16);
goto BuffPLCCheckEnd;
}
else if(0x31 == v_DI0)
{
//4~7点
getStrFMlow(BuffPLC+c_OffsetData, (addr+c_OneSize*serial)+16, 16);
goto BuffPLCCheckEnd;
}
else if(0x32 == v_DI0)
{
//8~11点
getStrFMlow(BuffPLC+c_OffsetData, (addr+c_OneSize*serial)+32, 16);
goto BuffPLCCheckEnd;
}
else if(0x33 == v_DI0)
{
//12~15点
getStrFMlow(BuffPLC+c_OffsetData, (addr+c_OneSize*serial)+48, 16);
goto BuffPLCCheckEnd;
}
else if(0x34 == v_DI0)
{
//16~19点
getStrFMlow(BuffPLC+c_OffsetData, (addr+c_OneSize*serial)+64, 16);
goto BuffPLCCheckEnd;
}
else if(0x35 == v_DI0)
{
//20~23点
getStrFMlow(BuffPLC+c_OffsetData, (addr+c_OneSize*serial)+80, 16);
goto BuffPLCCheckEnd;
}
goto BuffPLCCheckErr;
}
}
RtTaskset:
if(RtTask.Sta != c_Free) goto BuffPLCCheckErr; //如果有实时任务在处理直接退出
//抄读类,判断是否和上次实时指令一致
//和上一次指令比较,抄读类指令暂存数据,下次查询直接上传
if(0 == lowmemcmp(BuffPLC+c_OffsetDI0, lastCommBack, 10)) //只比较DI0 DI1 ID(6) CS 16 或者DI0, DI1 DI2 DI3 + ID[6]
{
//两次指令一致
//判断数据有效性
BuffPLCMark.RetCont++; //直接上传次数+1
//组织回应帧
if(RtData[0] == c_UpData)
{
v_FrameL = RtData[1]; //数据长度
memcpyh2l(BuffPLC+c_OffsetDI0, RtData+2, v_FrameL); //数据
memcpyh2l(BuffPLC+c_OffsetData+v_FrameL-2, MeterID, 6); //表号
v_FrameC = v_RetCback;
v_FrameL += 6; //加表号长度
if(BuffPLCMark.RetCont >= c_RetCont) //判断上传次数
{
lowmemset(lastCommBack, 0xff, 4); //暂存数据失效
v_DirRetCont = 0; //数据有效性计数器
BuffPLCMark.RetCont = 0;
}
Delay1msx(10);
goto BuffPLCCheckEnd;
}
}
//指令备份
lowmemcpy(lastCommBack, BuffPLC+c_OffsetDI0, 10);
}
else
{
lastCommBack[0] = 0; //非抄读类指令,内存数据失效
}
//***** 指令转发,设定实时抄表任务 ****
//准备新的实时抄表指令
highmemcpy(RtMeterID, MeterID, 6u);
//设定抄读项,没有DI0DI1时,没有实际意义
RtTask.DI0 = v_DI0;
RtTask.DI1 = v_DI1;
RtTask.Ctr = v_FrameC;
RtTask.len = v_FrameL - 6; //减6字节表号
RtData[0] = c_DownData; //标示数据方向是下发到485
memcpyl2h(RtData+1, BuffPLC+c_OffsetDI0, RtTask.len);//只保存数据域,包括DI0,DI1
RtTask.Port = v_RecPort;
RtTask.Sta = c_TaskRun; //开始实时任务
RtTask.FeCont = 2; //默认2FE
goto BuffPLCCheckErr; //没有数据上传
}
else
{
//*******************************************************
//* 针对采集器有关操作
//*******************************************************/
if(v_FrameC == 0x01)
{
p_BuffPLC = BuffPLC+c_OffsetData;
/////////////////抄读类
if(v_DI1 == 0xc0)
{
//co20, c038, c010, c011
if(v_DI0 == 0x20)
{
//C020 返回波特率和电表纪录数、电表数量
*p_BuffPLC++ = v_OnOffSta; //开盖状态
*p_BuffPLC++ = getMeterAmount(); //获取电表数量
*p_BuffPLC = *(p_BuffPLC-1); //和以前指令统一
v_FrameC = 0x81;
v_FrameL = 0x03 + 0x02;
goto BuffPLCCheckEnd;
}
else if(v_DI0 == 0x38)
{
//按长度区分是读取表特征字,还是读取采集间隔
if(v_FrameL == 0x02)
{
//C038 返回版本号 + 抄表间隔时间
*p_BuffPLC++ = c_VER;
getStrFM(tempBuff, a_AmrSpace, 0x01); //采集间隔,16进制
*p_BuffPLC++ = tempBuff[0];
v_FrameC = 0x81;
v_FrameL = 0x02 + 0x02;
goto BuffPLCCheckEnd;
}
else if(v_FrameL == 0x08)
{
//电表特征字
//保存指令中电表表号
memcpyl2h(MeterID, (BuffPLC+c_OffsetData+v_FrameL-8), 0x06);
//获取电表序号
serial = getMeterSr(MeterID);
if(serial > c_MaxMeterAmount)
{
//没有该表添加0xFF
*p_BuffPLC ++ = 0xff;
}
else
{
getStrFMlow(p_BuffPLC, a_MeterMark+c_OneSize*serial, 1);
p_BuffPLC++;
}
memcpyh2l(p_BuffPLC, MeterID, 6);
v_FrameC = 0x81;
v_FrameL = 0x02 + 0x01 + 0x06;
goto BuffPLCCheckEnd;
}
}
else if(v_DI0 == 0x10)
{
//C010 返回日期周次YYMMDDWW
getStrRTC(tempBuff, 0x03, 0x04); //8025时钟地址,03是周开始
memcpyh2l(p_BuffPLC, tempBuff, 4);
v_FrameC = 0x81;
v_FrameL = 0x04 + 0x02;
goto BuffPLCCheckEnd;
}
else if(v_DI0 == 0x11)
{
//C011 ss mm hh
getStrRTClow(p_BuffPLC, 0x00, 0x03); //8025时钟地址,00是秒开始
v_FrameC = 0x81;
v_FrameL = 0x03 + 0x02;
goto BuffPLCCheckEnd;
}
else if(v_DI0 == 0x33)
{
if(0xff == BuffPLC[c_OffsetData]) //读取全部电表地址
{
if(v_RecPort == c_Port_Irf)
{
ReturnAllMeterID(); //返回所有表号
}
goto BuffPLCCheckErr; //已经返回
}
}
}
else if(v_DI1 == 0xc1)
{
if(v_DI0 == 0x17)
{
//C117 抄表日时
getStrFMlow(p_BuffPLC, a_FreezeTime, 0x02);
v_FrameC = 0x81;
v_FrameL = 0x02 + 0x02;
goto BuffPLCCheckEnd;
}
}
v_FrameC = 0xC1;
}
//*******设置类 数据域格式(pa p0 p1 p2 + data),密码+数据
else if(v_FrameC == 0x04)
{
//#ifndef DEBUG
// if(_Set == 1) goto BuffPLCCheckErr; //判断按键
//#endif
if(v_DI1 == 0xC1)
{
//C117
if((v_DI0 == 0x17) && (v_FrameL == 0x08))
{
//C117 设置自动抄表日时
v_ExtRunFlag = c_putStrFM;
putStrFMlow(a_FreezeTime, BuffPLC+c_OffsetData+4, 0x02); //前4字节为密码
v_FrameC = 0x84;
v_FrameL = 0x00;
goto BuffPLCCheckEnd;
}
}
else if(v_DI1 == 0xC0)
{
//C038,C010,C011
if((v_DI0 == 0x38) && (v_FrameL == 0x07))
{
//C038 设置抄表间隔,只能设置为10,15,20, 30,60,0xff
temp = BuffPLC[c_OffsetData+4];
if((temp!=10)&&(temp!=15)&&(temp!=20)&&(temp!=30)&&(temp!=60)&&(temp!=0xff))
{
v_FrameC = 0xC4;
}
else
{
v_ExtRunFlag = c_putStrFM;
tempBuff[0] = temp; //16内存分BANK,特殊处理
putStrFM(a_AmrSpace, tempBuff, 0x01); //16内存分BANK
v_FrameC = 0x84;
}
v_FrameL = 0x00;
goto BuffPLCCheckEnd;
}
else if((v_DI0 == 0x10) && (v_FrameL == 10))
{
//设置日期周次(wwddmmyy)
v_ExtRunFlag = c_putStrRTC;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -