| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903 |
- /******************************************************************************
- 版权所有:
- 文件名称: plc.c
- 文件版本: 01.01
- 创建作者: sunxi
- 创建日期: 2015-11-02
- 功能说明: 可编程逻辑
- 其它说明:
- 1、只有实点可以合并成双点,且一个实点只能参加一个双点合并。双点合并在转发点表中
- 第一个点必须为合位,第二个点必须为分位。
- 修改记录:
- */
- /*------------------------------- 头文件 --------------------------------------
- */
- #include "head.h"
-
- /*------------------------------- 宏定义 --------------------------------------
- */
- // 逻辑点定义
- // 逻辑点由16位构成
- // 高3位: 类型 0保留,其它为真正类型
- // 次高5位: 开关号,0为公共,其它为开关序号
- // 低8位: 点号, 0为无效点号,取值返回为0.
- #define LP_TYPE 0XE000 // 逻辑点类型
- #define LP_SW 0X1F00 // 开关号
- #define LP_INDEX 0X00FF // 点号
- #define LP_TYPE_YX 0X2000 // 遥信点
- #define LP_TYPE_YK 0X4000 // 遥控点
- #define LP_TYPE_YC 0X6000 // 遥测点
- //#define LP_TYPE_EV 0X8000 // 事件点
- #define LP_TYPE_PLC 0XA000 // PLC 点
- #define LP_TYPE_PLC_CST 0XC000 // PLC 常量
- #define LP_TYPE_PLC_OPT 0XE000 // PLC 操作符
- #define LP_SW_PUB 0
- #define LP_SW_BEGIN 1
- #define LP_SW_END 31
- #define PLC_LOGIC_NOT (LP_TYPE_PLC_OPT | 0X0001)
- #define PLC_LOGIC_AND (LP_TYPE_PLC_OPT | 0X0002)
- #define PLC_LOGIC_OR (LP_TYPE_PLC_OPT | 0X0003)
- #define PLC_LOGIC_XOR (LP_TYPE_PLC_OPT | 0X0004)
- /*------------------------------ 类型结构 -------------------------------------
- */
- //可编程逻辑文件头
- struct plc_config
- {
- // 配置文件头
- struct cfg_file_head cfh;
- //工程文件名
- s8 prj_name[64];
- // 表达式
- u32 exp_addr; // 地址
- u32 exp_num; // 个数
- u32 exp_len; // 表达式长度
- // 保留
- u32 re_addr; //地址
- u32 re_num; //个数
- //对应描述文件
- u32 rsc_version; // 版本
- u32 rsc_signature; // 签名
- u32 rsc_length; // 长度
- u16 rsc_crc; // CRC
- u16 reserved0;
- };
- struct di_db
- {
- // 初始化值
- u32 timeout; // 双点滤波超时值
- u16 ev_code[2]; // 两个单点的遥信事件代码,由slot和no组合而成,从转发点表来
- // 双点采集用
- u32 us0; // 超时原点
- u8 bChange; // 标识双点变位动作
- u8 value0; // 双点结果,滤波前,由遥信处理程序直接生成
- u8 value1; // 双点结果,滤波后,且根据转发点表完成取反操作
-
- struct timespec ts; // 动作时刻
- };
- /*------------------------------ 全局变量 -------------------------------------
- */
- // 逻辑点数组
- struct lp g_lp[LP_NUM];
- // PLC处理数据
- u32 g_plc_num;
- struct plc g_plc[PLC_EXP_NUM+1];
- u32 g_plc_merge_index; // 合并点在PLC表中的位置
- // 双点遥信结构
- struct di_db g_di_db[MAX_DPI_NUMBER];
- /*------------------------------ 函数声明 -------------------------------------
- */
- void plc_db_soe(EVENT_STRUCT *ev);
- /*------------------------------ 外部函数 -------------------------------------
- 外部函数供其它实体文件引用,必须仔细检查传入参数的合法性.
- */
- int plc_yx2index(u8 sw, u8 type)
- {
- if (sw > SWITCH_NUM_MAX)
- {
- return -1;
- }
- if (type == 0)
- {
- return -1;
- }
- type--;
- if (sw == 0)
- {
- return type;
- }
- else
- {
- sw--;
- return PUB_DI_NUM_ALL + (SW_DI_NUM_ALL * sw) + type;
- }
- return -2;
- }
- SOE_DEF *plc_yx2soe(u8 sw, u8 type)
- {
- if (sw > SWITCH_NUM_MAX)
- {
- return NULL;
- }
- if (type == 0)
- {
- return NULL;
- }
- type--;
- if (sw == 0)
- {
- if (type >= PUB_DI_NUM && type < PUB_DI_NUM_ALL)
- {
- return (SOE_DEF *)&tAllSOE[type - PUB_DI_NUM + EV_SW_NUM];
- }
- }
- else
- {
- if (type >= SW_DI_NUM && type < SW_DI_NUM_ALL)
- {
- return (SOE_DEF *)&tAllSOE[type - SW_DI_NUM];
- }
- }
- return NULL;
- }
- s32 plc_get_input(u16 ld)
- {
- u16 type, sw, no;
- s32 r;
- type = (ld & LP_TYPE);
- sw = (ld & LP_SW) >> 8;
- no = (ld & LP_INDEX);
- r = 0;
- switch (type)
- {
- case LP_TYPE_YX:
- r = GetRmtYxVal(sw, no);
- r = (r == SW_DI_TYPE_ON);
- break;
- case LP_TYPE_YC:
- r = GetRmtMeaVal(sw, no, NULL);
- break;
- case LP_TYPE_PLC:
- r = g_plc[no].result;
- break;
- case LP_TYPE_PLC_CST:
- break;
- }
- return r;
- }
- int plc_init_iec_table(void)
- {
- u16 i, j, ep;
- u16 v;
- int index;
- SOE_DEF *soe;
- // 处理单点,如果一个逻辑点对应多个通讯点,将除第一个通讯点外的其它通讯点放入PLC逻辑中
- for (i = 0; i < g_table_head->di_num; i++)
- {
- index = plc_yx2index(g_di_table[i].owner, g_di_table[i].indexno);
- if (index < 0)
- {
- continue;
- }
- // 将第一个通讯点滤除
- if (g_lp[index].cp == g_di_table[i].cp)
- {
- continue;
- }
- // 没有通讯点,不需要
- if (g_di_table[i].cp == 0)
- {
- continue;
- }
- // 除第一个通讯点外的其它通讯点,放入PLC逻辑中
- // 检查空间
- if (g_plc_num >= PLC_EXP_NUM)
- {
- rt_printf("g_plc_num单点越限(g_plc_num=%d,i=%d).\r\n", g_plc_num, i);
- return -1;
- }
- // 通讯点
- g_plc[g_plc_num].cp = g_di_table[i].cp;
- // 标志,目前只有故障记录标志
- soe = plc_yx2soe(g_di_table[i].owner, g_di_table[i].indexno);
- if (soe)
- {
- if (soe->soe_def & SOE_TYPE_FAULT)
- {
- g_plc[g_plc_num].flag = (PLC_FLAG_FAULT | (g_di_table[i].owner << 16));
- }
- }
- // 插入操作数
- ep = 0;
- v = LP_TYPE_YX;
- v |= (g_di_table[i].owner << 8) | g_di_table[i].indexno;
- g_plc[g_plc_num].exp[ep++] = v;
- // 单点取反
- if (g_di_table[i].is_inverse)
- {
- g_plc[g_plc_num].exp[ep++] = PLC_LOGIC_NOT;
- }
- // 结束符
- g_plc[g_plc_num].exp[ep++] = 0;
- g_plc_num++;
- }
- // 处理合并点
- g_plc_merge_index = g_plc_num;
- for (i = 0; i < g_table_head->dimerge_num; i++)
- {
- if (g_plc_num >= PLC_EXP_NUM)
- {
- rt_printf("g_plc_num合并点越限(g_plc_num=%d,i=%d).\r\n", g_plc_num, i);
- return -2;
- }
- g_plc[g_plc_num].cp = g_di_merge_table[i].cp;
- ep = 0;
- for (j = 0; j < MIX_YX_NUMBER; j++)
- {
- u8 no = g_di_merge_table[i].no[j] & 0xff;
- u8 owner = (g_di_merge_table[i].no[j] >> 8) & 0xff;
- // 组合点号为空代表结束,退出。
- if (g_di_merge_table[i].no[j] == 0)
- {
- break;
- }
- // 标志,目前只有故障记录标志
- soe = plc_yx2soe(owner, no);
- if (soe)
- {
- if (soe->soe_def & SOE_TYPE_FAULT)
- {
- g_plc[g_plc_num].flag = (PLC_FLAG_FAULT | (owner << 16));
- }
- }
- // 插入操作数
- v = LP_TYPE_YX | (owner << 8) | no;
- g_plc[g_plc_num].exp[ep++] = v;
- // 单点取反
- if (g_di_merge_table[i].is_inv[j])
- {
- g_plc[g_plc_num].exp[ep++] = PLC_LOGIC_NOT;
- }
- // 插入或运算符
- if (j)
- {
- g_plc[g_plc_num].exp[ep++] = PLC_LOGIC_OR;
- }
- }
- // 合并点取反
- if (g_di_merge_table[i].is_inv_all)
- {
- g_plc[g_plc_num].exp[ep++] = PLC_LOGIC_NOT;
- }
- // 结束符
- g_plc[g_plc_num].exp[ep++] = 0;
- // 检查长度是否越界
- if (ep > PLC_EXP_LEN)
- {
- rt_printf("plc_iec_table: 表达式太长(i=%d,j=%d,ep=%d).\r\n", i, j, ep);
- return -3;
- }
- g_plc_num++;
- }
- // g_plc[2].do_owner = 0;
- // g_plc[2].do_index = 1;
- return 0;
- }
- int plc_init(void)
- {
- int i, j, k, index, ret;
- u8 sw, no;
- u32 timeout[2] = {0};
- u32 timeout_add;
- // 初值
- for (i = 0; i < LP_NUM; i++)
- {
- g_lp[i].cp = 0;
- g_lp[i].db_index = -1;
- }
- if (equ_config_null())
- {
- return -1;
- }
- // 单点
- // 保存第一个单点通讯点号
- for (i = 0; i < g_table_head->di_num; i++)
- {
- index = plc_yx2index(g_di_table[i].owner, g_di_table[i].indexno);
- if (index < 0)
- {
- // 跳过备用点
- continue;
- }
- if (g_lp[index].cp == 0)
- {
- g_lp[index].cp = g_di_table[i].cp;
- }
- }
- // 双点
- if (g_table_head->di_db_num > MAX_DPI_NUMBER)
- {
- return -2;
- }
- for (i = 0; i < g_table_head->di_db_num; i++)
- {
- for (k = 0; k < 2; k++)
- {
- sw = (u8)(g_di_db_table[i].no[k] >> 8);
- no = (u8)(g_di_db_table[i].no[k]);
- // 得到检查索引
- index = plc_yx2index(sw, no);
- if (index < 0)
- {
- return -3;
- }
- // 一个逻辑点只能对应一个双点
- if (g_lp[index].db_index >= 0)
- {
- return -4;
- }
- g_lp[index].db_index = i;
- // 得到滤波时间
- for (j = 0; j < g_equ_config->di_num; j++)
- {
- if ((g_equ_config_di[j].owner == sw) && (g_equ_config_di[j].type == no))
- {
- g_di_db[i].ev_code[k] = (g_equ_config_di[j].slot << 8) | g_equ_config_di[j].index;
- timeout[k] = g_equ_config_di[j].filter_time * USTIMER_MS;
- break;
- }
- }
- // 初始化双点值
- if (j != g_equ_config->di_num)
- {
- // 双点标准定义中,分位在bit0,合位在bit1.在转发点表中合位在前,分位在后
- // 所以移位必须取反一下。
- int sft = !k;
- if (dido_di_is_on(g_equ_config_di[j].slot, g_equ_config_di[j].index))
- {
- g_di_db[i].value0 |= 1 << sft;
- }
- else
- {
- g_di_db[i].value0 &= ~(1 << sft);
- }
- g_di_db[i].value1 = g_di_db[i].value0;
- if (g_di_db_table[i].is_inv[k])
- {
- g_di_db[i].value1 ^= 1 << sft;
- }
- }
- else
- {
- rt_printf("双点需要实际通道对应(i=%d)\r\n", i);
- return -5;
- }
- }
- // 双点确认延时(两点滤波时间差),转化为us,再增加20ms,以确保双点变位成功
- // 2017-09-05:在电科院测试,遥信10ms滤波,双点没有变位信号。针对此情况修改如下:
- // 1、附加延时由固定的20ms改为最小滤波时间的1/4,这样10ms的遥信滤波,将有2.5ms的附加延时。
- // 初步评估2.5ms的延时相对于5ms的中断间隔是个合适的值,
- // 2、如果附加延时大于20ms则限制为20ms,防止延时过长。
- if (timeout[0] >= timeout[1])
- {
- g_di_db[i].timeout = (timeout[0] - timeout[1]);
- timeout_add = timeout[1] / 4;
- }
- else
- {
- g_di_db[i].timeout = (timeout[1] - timeout[0]);
- timeout_add = timeout[0] / 4;
- }
- if (timeout_add > 20 * USTIMER_MS)
- {
- timeout_add = 20 * USTIMER_MS;
- }
- g_di_db[i].timeout += timeout_add;
- }
- // 解析PLC文件
- // 将转发点表中的多余单点和合并点转入PLC模块
- ret = plc_init_iec_table();
- if (ret < 0)
- {
- ret -= 10;
- }
- plc_scan(0);
- return ret;
- }
- int plc_exit(void)
- {
- return 0;
- }
- u8 plc_db_value(int index)
- {
- return g_di_db[index].value1;
- }
- void plc_db_init_value(u8 slot, u8 no, u8 v)
- {
- int index, db_index;
- u16 ev_code;
- ev_code = (slot << 8) | no;
- // 得到检查逻辑点索引
- index = plc_yx2index(g_di_st[slot][no].owner, g_di_st[slot][no].type);
- if (index < 0)
- {
- return;
- }
- // 检查双点索引
- db_index = g_lp[index].db_index;
- if (db_index < 0)
- {
- return;
- }
- #if 1
- // 取消正在进行的双点处理过程
- g_di_db[db_index].bChange = 0;
- #else
- // 双点第一次变位,记录时标
- if (g_di_db[db_index].bChange == 0)
- {
- g_di_db[db_index].ts = ev->ts;
- g_di_db[db_index].bChange = 1;
- }
- #endif
- // 每次变位都重新获取超时起点和双点的值
- g_di_db[db_index].us0 = ustimer_get_origin();
- if (ev_code == g_di_db[db_index].ev_code[0])
- {
- index = 1;
- }
- else if (ev_code == g_di_db[db_index].ev_code[1])
- {
- index = 0;
- }
- else
- {
- rt_printf("plc_db_soe:ev_code err!\r\n");
- return;
- }
- // 滤波前的值
- if (v)
- {
- g_di_db[db_index].value0 |= 1 << index;
- }
- else
- {
- g_di_db[db_index].value0 &= ~(1 << index);
- }
- // 滤波后的值
- // 双点标准定义中,分位在bit0,合位在bit1.在转发点表中合位在前,分位在后
- // 所以移位必须取反一下。
- if (g_di_db_table[db_index].is_inv[!index])
- {
- v = !v;
- }
- if (v)
- {
- g_di_db[db_index].value1 |= (1 << index);
- }
- else
- {
- g_di_db[db_index].value1 &= ~(1 << index);
- }
- #if 0
- rt_printf("db_init:db=%d,index=%d,is_inv=%d,v0=%d,v1=%d\r\n",
- db_index,index,
- g_di_db_table[db_index].is_inv[!index],
- g_di_db[db_index].value0,
- g_di_db[db_index].value1);
- #endif
- return;
- }
- void plc_db_soe(EVENT_STRUCT *ev)
- {
- int index, db_index;
- u8 slot, no;
- slot = (ev->ev_code >> 8);
- no = ev->ev_code & 0xff;
- // 得到检查逻辑点索引
- index = plc_yx2index(g_di_st[slot][no].owner, g_di_st[slot][no].type);
- if (index < 0)
- {
- return;
- }
- // 检查双点索引
- db_index = g_lp[index].db_index;
- if (db_index < 0)
- {
- return;
- }
- // 双点第一次变位,记录时标
- if (g_di_db[db_index].bChange == 0)
- {
- g_di_db[db_index].ts = ev->ts;
- g_di_db[db_index].bChange = 1;
- }
- // 每次变位都重新获取超时起点和双点的值
- g_di_db[db_index].us0 = ustimer_get_origin();
- if (ev->ev_code == g_di_db[db_index].ev_code[0])
- {
- index = 1;
- }
- else if (ev->ev_code == g_di_db[db_index].ev_code[1])
- {
- index = 0;
- }
- else
- {
- rt_printf("plc_db_soe:ev_code err!\r\n");
- return;
- }
- if (ev->ev_value)
- {
- g_di_db[db_index].value0 |= 1 << index;
- }
- else
- {
- g_di_db[db_index].value0 &= ~(1 << index);
- }
- return;
- }
- // 双点滤波处理,得到滤波后的值
- static void plc_db_scan(void)
- {
- int i, value;
- uint32_t flags;
- for (i = 0; i < g_table_head->di_db_num; i++)
- {
- if (g_di_db[i].bChange)
- {
- // 屏蔽中断的情况下检查超时,防止超时和value不对应。
- value = -1;
- rt_irq_save(flags);
- if (ustimer_get_duration(g_di_db[i].us0) >= g_di_db[i].timeout)
- {
- value = g_di_db[i].value0;
- }
- rt_irq_restore(flags);
- if (value != -1)
- {
- g_di_db[i].bChange = 0;
- if (g_di_db_table[i].is_inv[0])
- {
- value ^= 2;
- }
- if (g_di_db_table[i].is_inv[1])
- {
- value ^= 1;
- }
- // 如果和旧值相等,说明信号已返回,不应送SOE。
- if (value != g_di_db[i].value1)
- {
- soe_record_dpi(i, value, &g_di_db[i].ts);
- g_di_db[i].value1 = value;
- }
- }
- }
- }
- return;
- }
- int plc_scan(int is_rec)
- {
- static s32 r[64];
- u16 *p, i, rp;
- // 双点扫描
- plc_db_scan();
- // PLC扫描
- for (i = 0; i < g_plc_num; i++)
- {
- p = g_plc[i].exp;
- rp = 0;
- while (*p)
- {
- // 操作数,直接压栈
- if (((*p) & LP_TYPE) != LP_TYPE_PLC_OPT)
- {
- r[rp++] = plc_get_input(*p);
- }
- // 运算符,出栈计算,结果压栈
- else
- {
- switch (*p)
- {
- case PLC_LOGIC_NOT:
- r[rp - 1] = (~r[rp - 1]) & 0x01;
- break;
- case PLC_LOGIC_AND:
- r[rp - 2] = r[rp - 1] & r[rp - 2];
- rp--;
- break;
- case PLC_LOGIC_OR:
- r[rp - 2] = r[rp - 1] | r[rp - 2];
- rp--;
- break;
- case PLC_LOGIC_XOR:
- r[rp - 2] = r[rp - 1] ^ r[rp - 2];
- rp--;
- break;
- default:
- return -1;
- }
- }
- p++;
- }
- // 全部计算完毕,rp应该等1.
- if (rp != 1)
- {
- rt_err_set(ERR_CODE_PLC, 0);
- rt_printf("plc_scan:i=%d,rp=%d\r\n", i, rp);
- }
- if (g_plc[i].result != r[rp - 1])
- {
- g_plc[i].result = r[rp - 1];
- // 开出
- if (g_plc[i].do_index)
- {
- int type;
- if (g_plc[i].result)
- {
- type = SW_DO_TYPE_ON;
- soe_record_opt(EV_PLC_HZ, ((g_plc[i].do_owner << 8) | g_plc[i].do_index));
- }
- else
- {
- type = SW_DO_TYPE_OFF;
- soe_record_opt(EV_PLC_TZ, ((g_plc[i].do_owner << 8) | g_plc[i].do_index));
- }
- if (g_plc[i].do_owner == 0)
- {
- sw_do_pub(g_plc[i].do_index - 1, type);
- }
- else
- {
- sw_do(g_plc[i].do_owner - 1, g_plc[i].do_index - 1, type);
- }
- }
- // 需要送主站
- if (g_plc[i].cp && is_rec)
- {
- u8 value = g_plc[i].result ? 1 : 0;
- soe_record_plc(i, value, g_plc[i].flag);
- }
- }
- }
- return 0;
- }
- /*------------------------------ 内部函数 -------------------------------------
- 内部函数以下划线‘_’开头,不需要检查参数的合法性.
- */
- /*------------------------------ 测试函数 -------------------------------------
- 一个实体文件必须带一个本模块的测试函数来进行单元测试,如果的确不方便在本模块中
- 进行单元测试,必须在此注明实际的测试位置(例如在哪个实体文件中使用哪个测试函数).
- */
- int plc_lp_printf(void)
- {
- int i,begin[5];
- begin[0] = 0;
- begin[1] = PUB_DI_NUM;
- begin[2] = PUB_DI_NUM_ALL;
- begin[3] = PUB_DI_NUM_ALL + SW_DI_NUM*SWITCH_NUM_MAX;
- begin[4] = PUB_DI_NUM_ALL + SW_DI_NUM*SWITCH_NUM_MAX + EV_SW_NUM*SWITCH_NUM_MAX;
-
- rt_printf("\r\n");
- for (i=0; i<LP_NUM; i++)
- {
- if(g_lp[i].cp == 0 && g_lp[i].db_index == -1)
- {
- continue;
- }
-
- rt_printf("%04d:通讯点:0x%04x, 双点索引:%02d, ", i,g_lp[i].cp,g_lp[i].db_index);
-
- // 公共实点
- if (i>= begin[0] && i<begin[1])
- {
- rt_printf("资源点:%s\r\n", g_pub_di_name[i]);
- }
- // 公共虚点
- else if (i>= begin[1] && i<begin[2])
- {
- rt_printf("资源点:%s\r\n", tAllSOE[(i-begin[1])+EV_SW_NUM].strName);
- }
- // 开关实点搜集
- else if (i>= begin[2] && i<begin[3])
- {
- rt_printf("资源点:开关%02d%s\r\n",(i-begin[2])/SW_DI_NUM,g_sw_di_name[(i-begin[2])%SW_DI_NUM]);
- }
- // 开关虚点搜集
- else if (i>= begin[3] && i<begin[4])
- {
- rt_printf("资源点:开关%02d%s\r\n", (i-begin[3])/EV_SW_NUM,tAllSOE[(i-begin[3])%EV_SW_NUM].strName);
- }
- }
- return 0;
- }
- int plc_info_printf(void)
- {
- u16 *p,i;
-
- rt_printf("\r\n可编程逻辑表(num=%d):\r\n",g_plc_num);
- for(i=0;i<g_plc_num;i++)
- {
- p = g_plc[i].exp;
- rt_printf("PLC%02d:地址=0x%04x,结果=%d,开出归属=%d,开出索引=%d.\r\n",
- i,g_plc[i].cp,g_plc[i].result,g_plc[i].do_owner,g_plc[i].do_index);
- rt_printf("EXP%02d:",i);
- while(*p)
- {
- // 操作数
- if((*p&LP_TYPE) != LP_TYPE_PLC_OPT)
- {
- rt_printf("%04x,",*p);
- }
- // 运算符
- else
- {
- switch(*p)
- {
- case PLC_LOGIC_NOT:
- rt_printf("~,");
- break;
-
- case PLC_LOGIC_AND:
- rt_printf("&,");
- break;
-
- case PLC_LOGIC_OR:
- rt_printf("|,");
- break;
-
- case PLC_LOGIC_XOR:
- rt_printf("^,");
- break;
- default:
- return -1;
- }
- }
- p++;
- }
- rt_printf("\r\n\r\n");
- }
- // 双点信息
- rt_printf("\r\n双点信息(num=%d):\r\n",g_table_head->di_db_num);
- rt_printf("timeout\tevcode0\tevcode1\tbChange\tv0\tv1\r\n");
- for(i=0;i<g_table_head->di_db_num;i++)
- {
- struct di_db *db;
- db = & g_di_db[i];
- rt_printf("%d\t%04x\t%04x\t%d\t%d\t%d\r\n",db->timeout,db->ev_code[0],db->ev_code[1],db->bChange,db->value0,db->value1);
- }
- return 0;
- }
- /*------------------------------ 文件结束 -------------------------------------
- */
|