129 lines
8.9 KiB
C
129 lines
8.9 KiB
C
/* 每连接独立的IEC-104流式接收器:固定缓冲、完整APDU交付,不处理链路序号或ACK。 */
|
|
#ifndef IEC104_RECEIVER_H
|
|
#define IEC104_RECEIVER_H
|
|
|
|
#include "IEC104_Codec.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* 接收器操作结果;FRAME_ERROR表示收到非法报文,ERROR表示调用条件或内部状态非法。 */
|
|
typedef enum {
|
|
IEC104_RECEIVER_ERROR = -2, /* 参数、初始化状态、连接代次或内部进度非法 */
|
|
IEC104_RECEIVER_FRAME_ERROR = -1, /* 起始字节、APCI或ASDU最低长度非法,已清除候选帧 */
|
|
IEC104_RECEIVER_IN_PROGRESS = 0, /* 本次输入已消费完,尚无完整帧 */
|
|
IEC104_RECEIVER_OK = 1, /* Init、Reset、Release_Frame或Get_Status成功 */
|
|
IEC104_RECEIVER_FRAME_READY = 2, /* 已有一帧可读取,Feed不会继续消费后续字节 */
|
|
IEC104_RECEIVER_EMPTY = 3 /* Peek/Release时没有完整帧,半帧仍保留 */
|
|
} IEC104_ReceiverResult_t;
|
|
|
|
/* 调用方持有,每条连接使用独立实例;先Init,后续同连接串行操作,字段只由接口维护。
|
|
* is_frame_ready为0时:received_length为0表示等待帧头,1表示等待长度域,>=2表示收集报文体。
|
|
* is_frame_ready为1时:已收齐并通过APCI及ASDU最低长度检查,暂停输入,等待读取及释放。
|
|
* 完整帧保留至成功Release_Frame、Reset、Abort或重新Init,不保存自引用指针或私有Link状态。 */
|
|
typedef struct {
|
|
uint64_t connection_generation; /* 非零;新连接使用未复用的代次,拒绝旧I/O输入 */
|
|
uint16_t received_length; /* 已收到的候选帧字节数,0..255 */
|
|
uint16_t expected_length; /* APDU总长=长度域+2,范围6..255;长度域尚未知时为0 */
|
|
uint8_t is_initialized; /* 1表示Init成功;其他值不能作为已初始化实例使用 */
|
|
uint8_t is_frame_ready; /* 0表示尚无完整帧;1表示完整帧已就绪,等待显式释放 */
|
|
uint8_t buffer[IEC104_MAX_APDU_LEN]; /* 固定255字节,保存起始字节、长度域、控制域及可选ASDU */
|
|
} IEC104_Receiver_t;
|
|
|
|
/* 接收进度快照,不借用原文;供连接层判断新成帧、保留帧及诊断半帧进度。 */
|
|
typedef struct {
|
|
uint16_t received_length; /* 当前候选帧已收字节数;0表示尚无帧头 */
|
|
uint16_t expected_length; /* APDU总长;尚未取得长度域时为0 */
|
|
uint8_t has_complete_frame; /* 0/1:完整帧已通过格式及最低长度校验且尚未释放 */
|
|
} IEC104_ReceiverStatus_t;
|
|
|
|
/* 匹配代次并校验接收进度后写status;OK成功,ERROR不改输出,不重新分派报文。 */
|
|
extern IEC104_ReceiverResult_t IEC104_Receiver_Get_Status(
|
|
const IEC104_Receiver_t *receiver, uint64_t connection_generation, IEC104_ReceiverStatus_t *status);
|
|
|
|
/* 结束旧I/O及所有借用后解除接收器绑定;允许NULL,不操作外部TCP或Link。 */
|
|
extern void IEC104_Receiver_Abort(IEC104_Receiver_t *receiver);
|
|
|
|
/* 只读借用视图;apdu及I帧的apci.asdu指向Receiver缓冲,不拥有或复制原文;S/U帧的asdu为NULL。
|
|
* 成功Release_Frame/Reset/Init或Abort后失效;完整帧等待释放期间Feed消费0字节,Peek可重复读取。
|
|
* 调用方不得修改原文;跨释放保存数据时,先自行复制并在新缓冲上重新解析APCI。 */
|
|
typedef struct {
|
|
uint64_t connection_generation; /* 当前完整帧所属连接代次;来自接收器绑定的代次 */
|
|
const uint8_t *apdu; /* 完整APDU首地址,指向receiver->buffer */
|
|
uint16_t apdu_length; /* 完整APDU字节数,包含起始字节和长度域 */
|
|
IEC104_ApciInfo_t apci; /* APCI解析结果;I帧的asdu指向apdu+IEC104_APCI_LEN */
|
|
} IEC104_ReceivedFrame_t;
|
|
|
|
/**
|
|
* 功能:清空接收器并绑定非零连接代次,用于首次使用或新连接换代。
|
|
* 输入参数:receiver——调用方提供的接收器存储;connection_generation——连接层分配的非零代次。
|
|
* 输出参数:receiver——成功时全部清零,再设置代次及初始化标志。
|
|
* 返回值:OK表示成功;ERROR表示参数非法,不修改receiver。
|
|
* 说明:旧连接及其I/O须先结束,再为新连接重新Init;已有帧视图在成功初始化后失效。
|
|
* 只初始化接收器,不初始化Link或发送模块。
|
|
*/
|
|
extern IEC104_ReceiverResult_t IEC104_Receiver_Init(
|
|
IEC104_Receiver_t *receiver, uint64_t connection_generation);
|
|
|
|
/**
|
|
* 功能:按序递入任意长度字节片段,支持半包、粘包;每次最多收齐一帧。
|
|
* 输入参数:receiver——已初始化接收器;connection_generation——本次输入所属代次;
|
|
* data——输入首地址,仅在length非0时必须非NULL;length——输入字节数。
|
|
* 输出参数:consumed——非NULL,写入实际消费数,包括触发格式错误的字节;ERROR时为0;
|
|
* receiver——保存接收进度或一帧完整APDU;输入、consumed及receiver不得重叠。
|
|
* 返回值:FRAME_READY——已有完整帧,先Peek并处理,再Release;未释放时再次Feed消费0字节;
|
|
* IN_PROGRESS——全部输入已消费,尚无完整帧,保留已有半帧;
|
|
* FRAME_ERROR——起始字节、APCI或ASDU最低长度非法,清除候选帧,停止在错误位置;
|
|
* ERROR——参数、初始化状态、连接代次或内部进度非法,不修改接收器。
|
|
* 说明:未消费的尾部起点为data + *consumed,长度为length - *consumed,由调用方保留后再按序递入;
|
|
* 不能跳过剩余字节,也不能重复递入已消费字节。length为0可查询当前是否已有完整帧。
|
|
* FRAME_ERROR时已消费错误起始/长度字节或整个非法候选帧,是否断开由连接层决定。
|
|
* 帧边界遇到非0x68立即报错;报文体内不搜索帧头。无动态分配、锁、socket I/O或半帧超时。
|
|
* FRAME_READY保证APCI合法、ASDU公共头完整,且已知固定长度对象满足VSQ/SQ所需最低长度;
|
|
* 未知/变长类型、零对象及具体字段是否合法仍由业务检查,详见Parse_ASDU_Header。
|
|
* N(S)/N(R)与链路序号的关系及启停状态由链路层处理;旧连接代次的输入返回ERROR。
|
|
*/
|
|
extern IEC104_ReceiverResult_t IEC104_Receiver_Feed(
|
|
IEC104_Receiver_t *receiver, uint64_t connection_generation,
|
|
const uint8_t *data, uint32_t length, uint32_t *consumed);
|
|
|
|
/**
|
|
* 功能:读取当前完整帧的只读借用视图,允许重复读取,不释放报文。
|
|
* 输入参数:receiver——已初始化接收器;connection_generation——本次读取所属代次。
|
|
* 输出参数:frame——非NULL且不与receiver重叠,仅返回FRAME_READY时写入,其余返回不改输出。
|
|
* 返回值:FRAME_READY表示取得视图;EMPTY表示尚无完整帧;ERROR表示参数、代次或状态非法。
|
|
* 说明:视图有效期见IEC104_ReceivedFrame_t;将frame.apci的I/S交给同连接的SendManager受理一次,
|
|
* U帧由连接层按功能码分派。业务未受理(如Manager返回WAIT)时保持当前帧,不释放,
|
|
* 也不越过它分派后续帧;Peek到Release之间不得复位或替换当前帧。
|
|
*/
|
|
extern IEC104_ReceiverResult_t IEC104_Receiver_Peek_Frame(
|
|
const IEC104_Receiver_t *receiver, uint64_t connection_generation,
|
|
IEC104_ReceivedFrame_t *frame);
|
|
|
|
/**
|
|
* 功能:在完整帧已被受理后释放接收空间,允许继续接收下一帧。
|
|
* 输入参数:receiver——已初始化接收器;connection_generation——本次释放所属代次。
|
|
* 输出参数:receiver——成功时清除组帧进度,使已有视图失效;不清零缓冲、不修改链路。
|
|
* 返回值:OK表示释放成功;EMPTY表示没有完整帧,保留已有半帧;ERROR表示状态非法,不改对象。
|
|
* 说明:释放不代表已发送协议ACK;业务暂未受理当前帧时应保留它,稍后重试处理。
|
|
*/
|
|
extern IEC104_ReceiverResult_t IEC104_Receiver_Release_Frame(
|
|
IEC104_Receiver_t *receiver, uint64_t connection_generation);
|
|
|
|
/**
|
|
* 功能:显式丢弃当前半帧或完整帧,恢复到等待帧头的阶段。
|
|
* 输入参数:receiver——已初始化接收器;connection_generation——本次复位所属代次。
|
|
* 输出参数:receiver——成功时清除组帧进度,保留代次及缓冲字节,使所有已有视图失效。
|
|
* 返回值:OK表示复位完成;ERROR表示对象未初始化或代次非法,不修改receiver。
|
|
* 说明:仅核对初始化标志和代次,允许清除异常组帧进度;新连接换代必须用Init。
|
|
* 不复位Link,也不能作为链路序号错误的恢复手段。
|
|
*/
|
|
extern IEC104_ReceiverResult_t IEC104_Receiver_Reset(
|
|
IEC104_Receiver_t *receiver, uint64_t connection_generation);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif /* IEC104_RECEIVER_H */
|