📄 uartcomm.c
字号:
*******************************************************************************/
#include "includes.h"
#define WRITE_ENABLE 1 //属性可写
#define READ_ENABLE 2 //属性可读
#define RW_ENAB (WRITE_ENABLE | READ_ENABLE)
#define R_ENAB (READ_ENABLE)
#define W_ENAB (WRITE_ENABLE)
#define RW_DISABLE 0
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
typedef struct STC_TAG_PROP
{
INT8S cFlag;
INT8U abyPropRW[4]; //分别为位、字节、字、双字的操作属性
//WRITE_ENABLE与READ_ENABLE作或运算
//为0时不能进行相应范围的操作
INT32S maxAddr[4]; //分别为位、字节、字、双字的最大允许操作地址,
} STC_TAG_PROP;
const static STC_TAG_PROP s_astcTagProp[] = //TAG属性定义
{
{'M', RW_ENAB, RW_ENAB, RW_ENAB, RW_ENAB, 65535, 65535, 65534, 65532},
{'G', RW_ENAB, RW_ENAB, RW_ENAB, RW_ENAB, 65535, 65535, 65534, 65532},
{'L', RW_ENAB, RW_ENAB, RW_ENAB, RW_ENAB, 65535, 65535, 65534, 65532},
{'S', RW_ENAB, RW_ENAB, RW_ENAB, RW_ENAB, 65535, 65535, 65534, 65532},
{'F', RW_ENAB, RW_ENAB, RW_ENAB, RW_ENAB, 65535, 65535, 65534, 65532},
{'X', R_ENAB, R_ENAB, R_ENAB, R_ENAB, 65535, 65535, 65534, 65532},
{'Y', RW_ENAB, RW_ENAB, RW_ENAB, RW_ENAB, 65535, 65535, 65534, 65532},
{'T', RW_ENAB, RW_DISABLE, RW_DISABLE, RW_ENAB, 65535, 65535, 65535, 65535},
{'C', RW_ENAB, RW_DISABLE, RW_DISABLE, RW_ENAB, 65535, 65535, 65535, 65535},
{'R', RW_ENAB, RW_ENAB, RW_ENAB, RW_ENAB, 65535, 65535, 65534, 65532},
{'I', R_ENAB, R_ENAB, R_ENAB, R_ENAB, 65535, 65535, 65534, 65532},
{'Q', RW_ENAB, RW_ENAB, RW_ENAB, RW_ENAB, 65535, 65535, 65534, 65532},
{'P', RW_DISABLE, RW_DISABLE, RW_DISABLE, RW_ENAB, 65535, 65535, 65534, 65532}
};
INT32S g_iComNumber = DEF_COM1; //工作过程中选取的串口值
INT32S g_iMaxFrameSize = DEF_MaxFrameSize; //工作过程中的最大帧长
INT32S g_iMaxOutTime = DEF_MaxOutTime; //工作过程中的等待时间
/*******************************************************************************
函数名: IsTagValid
描 述: 检查tag是否为有效
输 入: pstcTag 需要检查的TAG
byTestRW 对读写属性进行检查,为下列四者之一
RW_ENAB : 必须包含读写属性
R_ENAB : 必须包含只读属性
W_ENAB : 必须包含可写属性
RW_DISABLE: 包含只读或只写属性
输 出: 无
返回值: FALSE TAG无效
TRUE TAG有效
*******************************************************************************/
static INT8U IsTagValid(const STC_TAG *pstcTag, INT8U byTestRW)
{
INT8U byIndex;
INT8U byRangeIdx;
if (pstcTag->enmType > ENUM_OPER_DWORD)
{
return FALSE;
}
for (byIndex = 0; byIndex < ARRAY_SIZE(s_astcTagProp); byIndex++)
{
if (pstcTag->cFlag == s_astcTagProp[byIndex].cFlag)
{
break;
}
}
if (byIndex >= ARRAY_SIZE(s_astcTagProp))
{
return FALSE;
}
byRangeIdx = (INT8U)pstcTag->enmType;
if (s_astcTagProp[byIndex].abyPropRW[byRangeIdx] == RW_DISABLE)
{ //对应范围操作不允许
return FALSE;
}
if ((s_astcTagProp[byIndex].abyPropRW[byRangeIdx] & byTestRW) != byTestRW)
{ //不包含对应范围操作数
return FALSE;
}
if (pstcTag->addr >= s_astcTagProp[byIndex].maxAddr[byRangeIdx]
|| pstcTag->addr < 0)
{
return FALSE;
}
else if (byRangeIdx == ENUM_OPER_BIT && (pstcTag->bit < 0 || pstcTag->bit > 7))
{ //位操作数但位溢出
return FALSE;
}
return TRUE;
}
/*******************************************************************************
函数名: IsDecodeSuccess
描 述: 解码十进制格式的tag,并判断tag是否为有效
输 入: pszDecTag 需要解码的Tag名, 为十进制格式
byTestRW 对TAG读写属性进行检查,为下列四者之一
RW_ENAB : 必须包含读写属性
R_ENAB : 必须包含只读属性
W_ENAB : 必须包含可写属性
RW_DISABLE: 包含只读或只写属性
输 出: pstcTag 存放解码后的TAG,pstcTag为NULL时不输出
返回值: 0 解码失败
1 解码成功
其他 :
十进制方式位Tag定义 (引导符 + 偏移地址 + '.' + 位)
十进制方式字节、字、双字Tag定义 (引导符 + 范围符 + 偏移地址) 范围符有'B' 'W' 'D'
有效的引导符 该引导符操作范围 读写操作
M: 辅助继存器 (位、字节、字、双字) 读写
G: 全局继存器 (位、字节、字、双字) 读写
L: 局部继存器 (位、字节、字、双字) 读写
S: 静态继存器 (位、字节、字、双字) 读写
F: 特殊功能继存器 (位、字节、字、双字) 读写
X: 输入继存器 (位、字节、字、双字) 只读
Y: 输出继存器 (位、字节、字、双字) 读写
T: 定时器 (位、双字) 读写
C: 计数器 (位、双字) 读写
R: 只读继存器 (位、双字、字、双字) 只读
I: 外部输入继存器 (位、双字、字、双字) 只读
Q: 外部输出继存器 (位、双字、字、双字) 只写
P: 程序继存器 (双字) 读写
以下为有效十进制位TAG:
M100.0、G10.7、L20.2、S11.2、 F0.0、 X0.0、 Y0.0、T1.2、 C2.3、 R0.1、I0.2、 Q1.1
对应十六进制位TAG(固定为6个字节):
M00064 G7000A L20014 S2000B F00000 X00000 Y00000 T20001 C30002 R10000 I20000 Q10001
以下为有效十进制字节TAG
MB100、GB100、LB100、 SB11、 FB0、 XB0、 YB0、 RB0、 IB0、 QB0
对应十六进制字节TAG(固定为6个字节):
MB0064 GB0064 LB0064 SB000B FB0000 XB0000 YB0000 RB0000 EB0000 QB0000
以下为有效十进制字TAG
MW100、GW100、LW100、 SW11、FW0、 XW0、 YW0、 RW0、 IW0、 QW0
对应十六进制字TAG(固定为6个字节):
MW0064 GW0064 LW0064 SW000B FW0000 XW0000 YW0000 RW0000 IW0000 QW0000
以下为有效十进制双字TAG
MD100、GD100、LD100、 SD11、FD0、 XD0、 YD0、 TD0、 CD0、 RD0、 ID0、 QD0
对应十六进制双字TAG(固定为6个字节):
MD0064 GD0064 LD0064 SD000D FD0000 XD0000 YD0000 TD0000 CD0000 RD0000 ID0000 QD0000
*******************************************************************************/
INT8U IsDecodeSuccess(const char *pszDecTag, STC_TAG *pstcTag, INT8U byTestRW)
{
EOperType enmType;
STC_TAG stcTag;
INT32S addr = -1;
INT32S bit = -1;
INT8S cFlag = toupper(pszDecTag[0]);
INT8S cRange = toupper(pszDecTag[1]);
if (!isupper(cFlag))
{
return FALSE; //若不是合法引导符,返回false
}
if (isdigit(cRange)) //表示为位TAG操作
{
sscanf(pszDecTag + 1, "%d.%d", &addr,&bit);
stcTag.cFlag = cFlag;
stcTag.enmType = ENUM_OPER_BIT;
stcTag.addr = addr; //偏移地址
stcTag.bit = bit; //位
if (pstcTag != NULL)
{
*pstcTag = stcTag;
}
return IsTagValid(&stcTag, byTestRW);
}
else if (cRange == 'B' || cRange == 'W' || cRange == 'D')
{
sscanf(pszDecTag + 2, "%d", &addr); //偏移地址
if (cRange == 'B')
{
enmType = ENUM_OPER_BYTE;
}
else if (cRange == 'W')
{
enmType = ENUM_OPER_WORD;
}
else
{
enmType = ENUM_OPER_DWORD;
}
stcTag.cFlag = cFlag;
stcTag.enmType = enmType;
stcTag.addr = addr;
stcTag.bit = -1; //位无效
if (pstcTag != NULL)
{
*pstcTag = stcTag;
}
return IsTagValid(&stcTag, byTestRW);
}
else
{
return FALSE;
}
}
/*******************************************************************************
函数名: CaculateLRC
描 述: 计算字符串msg的校验码
输 入: msg 需校验的信息字符串
msgLength 信息字符串的长度
输 出: 无
返回值: INT8U 类型,信息串的校验码
*******************************************************************************/
static INT8U CaculateLRC(const INT8U *msg, INT16U msgLength)
{
INT8U uchLRC = 0;
while (msgLength--)
{
uchLRC += *msg++;
}
return (INT8U)(-(INT8S)uchLRC);
}
/*******************************************************************************
函数名: SendReadBitCommand
描 述: 发送读位信息,供读位函数调用
输 入: byAddr 选用的下位机地址,如1,2等
pstcTagCmd 读取位的信息TAG,详见通讯协议的方式
输 出: 无
返回值: INT32S 类型,其值表示函数的执行结果,操作成功返回发送的数据长度,否则返回
错误代码,调用GetErrMsg可获得详细的错误信息
*******************************************************************************/
INT32S SendReadBitCommand(const STC_TAG_COMMAND *pstcTagCmd, INT8U byAddr)
{
INT32S len, result;
INT8S* buf = (INT8S *)malloc(g_iMaxFrameSize + 1); //用来存储发送的数据
/*将buf中的数据格式化为通讯协议所要求的格式*/
len = sprintf(buf, ":%02X%02X%C%C%04X%02X", byAddr, COMMAND_BIT_RD,
pstcTagCmd->stcTag.cFlag, pstcTagCmd->stcTag.bit + 0x30,
pstcTagCmd->stcTag.addr, pstcTagCmd->byRange);
/*LRC校验和结束符*/
len += sprintf(&buf[len], "%02X\x0d\x0a", CaculateLRC(buf + 1, len - 1));
result = sio_write(g_iComNumber, buf, len); //发送到串口发送缓冲区
free(buf); //释放buf指针
#ifndef FORTESTONLY //测试编译开关
return result;
#else
return len; //for test only
#endif
}
/*******************************************************************************
函数名: SendReadByteCommand
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -