/// <summary> /// 分发响应 /// </summary> /// <param name="cmdId">响应报文命令ID</param> /// <param name="payload">响应负载</param> /// <param name="length">响应负载长度</param> private void dispatchResponse(enCmd cmdId, byte[] payload, byte length) { eRC rc = (eRC)payload[0]; m_u8RxDataLen = (byte)(length - 1); Array.Copy(payload, 1, m_u8aRxData, 0, m_u8RxDataLen); // 检查接收到的命令id是否与请求的id相同 if (cmdId == m_ReqCmdId) { if (m_evReplyArrived != null) { // call the callback m_evReplyArrived(cmdId, rc, m_u8aRxData, m_u8RxDataLen); // reset m_ReqCmdId = enCmd.CMDID_END; // Kous: 注销事件处理函数的方式可能存在问题 m_evReplyArrived = null; // Kous: 清空接收数据缓存 Array.Clear(m_u8aRxData, 0, m_u8RxDataLen); m_u8RxDataLen = 0; } else { CommStackLog.RecordErr(enLogLayer.eSerial, "m_evReplyArrived=null"); } } else { CommStackLog.RecordErr(enLogLayer.eSerial, "cmdId=" + cmdId.ToString() + " m_ReqCmdId=" + m_ReqCmdId.ToString()); } }
/// <summary> /// 发送请求去报文 /// </summary> /// <param name="cmdId">输出报文的命令ID</param> /// <param name="isAck">输出报文是否为响应报文</param> /// <param name="shouldBeAcked">输出报文是否需要响应</param> /// <param name="payload">输出报文的负载</param> /// <param name="length">输出报文的负载长度</param> /// <param name="replyCb">响应回调函数</param> /// <param name="bRetry">是否为重发报文</param> /// <returns>错误码</returns> private enErrCode sendRequestNoCheck(enCmd cmdId, bool isAck, bool shouldBeAcked, byte[] payload, byte length, DlgtReply replyCb, bool bRetry = false) { byte control = 0; // register reply callback m_ReqCmdId = cmdId; m_evReplyArrived = replyCb; // create the control byte if (isAck) { control |= FLAG_ACK; } else { control |= FLAG_DATA; } if (shouldBeAcked) { control |= FLAG_ACKNOWLEDGED; } else { control |= FLAG_UNACKNOWLEDGED; } lock (m_hdlcore) { // send the frame over serial if (bRetry) { m_u8TxPacketId--; } if (!output1Frame(control, (byte)cmdId, m_u8TxPacketId, length, payload)) { return(enErrCode.ERR_INVALID_PARAM); } // increment the txPacketId m_u8TxPacketId++; } return(enErrCode.ERR_NONE); }
/// <summary> /// 发送请求去报文 /// </summary> /// <param name="cmdId">输出报文的命令ID</param> /// <param name="isAck">输出报文是否为响应报文</param> /// <param name="payload">输出报文的负载</param> /// <param name="length">输出报文的负载长度</param> /// <param name="replyCb">响应回调函数</param> /// <param name="bRetry">是否为重发报文</param> /// <returns>错误码</returns> public enErrCode SendRequest(enCmd cmdId, bool isAck, byte[] payload, byte length, DlgtReply replyCb, bool bRetry = false) { // abort if not connected if (m_SerStatus != enSerStatus.SER_ST_CONNECTED) { return(enErrCode.ERR_NOT_CONNECTED); } // send the request return(sendRequestNoCheck(cmdId, isAck, !isAck, payload, length, replyCb, bRetry)); }
public void Reset() { // 重置底层 if (m_Ser != null) { m_Ser.Reset(); } m_bBusyTx = false; m_u8CmdId = enCmd.CMDID_END; m_u8OutputBufLen = 0; Adapter2MeshBridge = null; lock (m_dicAsyncCmdRespRecords) { m_dicAsyncCmdRespRecords.Clear(); } m_asigMgrResponsed.Reset(); }
/// <summary> /// 接受新的数据帧解析函数 /// </summary> /// <param name="rxFrame">帧数据及</param> /// <param name="rxFrameLen">帧长度</param> private void rxHdlcFrame(byte[] rxFrame, byte rxFrameLen) { if (rxFrame == null) { return; } if (isInvalidCmd(rxFrame[1])) { CommStackLog.RecordErr(enLogLayer.eSerial, "Err cmd(0x" + rxFrame[1].ToString("X2") + ")"); return; } bool isAck = false; bool shouldAck = false; bool isRepeatId = false; bool isNotifData = false; //接收报文的个数 m_i32RxFrameCnt++; // parse header m_u8RxControl = rxFrame[0]; m_RxCmdId = (enCmd)rxFrame[1]; m_u8RxSeqNum = rxFrame[2]; m_u8RxPyldLen = rxFrame[3]; enNotifyType notType = (enNotifyType)rxFrame[4]; if (m_RxCmdId == enCmd.CMDID_NOTIFICATION && (notType == enNotifyType.NOTIFID_NOTIFDATA || notType == enNotifyType.NOTIFID_NOTIFEVENT)) { isNotifData = true; } // 提取出HDLC帧中负载数据 Array.Copy(rxFrame, 4, m_u8aRxPayload, 0, m_u8RxPyldLen); // 解析接受到的HDLC帧是响应帧还是数据帧(请求帧) isAck = ((m_u8RxControl & FLAG_ACK) != 0); // 如果HDLC帧是数据帧解析接受到的HDLC帧是否需要应答 shouldAck = ((m_u8RxControl & FLAG_ACKNOWLEDGED) != 0); // 应答报文 if (isAck) { // 通知上层响应帧到达 if (m_u8RxPyldLen > 0) { // Kous: 是上层应用请求的响应报文,回调上层应用定义的响应通知函数 dispatchResponse(m_RxCmdId, m_u8aRxPayload, m_u8RxPyldLen); } } // 请求报文 else { // 非数据通知时才检测更新m_u8RxPacketId if (!isNotifData) { // 是否为重复请求报文 if (m_bRxPacketIdInit && m_u8RxSeqNum == m_u8RxPacketId) { CommStackLog.RecordInf(enLogLayer.eSerial, "SO(" + m_u8RxSeqNum.ToString() + ") repeats"); isRepeatId = true; } else { isRepeatId = false; m_bRxPacketIdInit = true; m_u8RxPacketId = m_u8RxSeqNum; // 记录接收到的报文序列号 } } // 如果报文是需要响应的报文,则在Ser层直接回应 if (shouldAck) { byte len = 1; byte[] payload = new byte[len]; payload[0] = (byte)eRC.RC_OK; //Thread.Sleep(20); output1Frame(FLAG_ACK | FLAG_ACKNOWLEDGED, (byte)m_RxCmdId, m_u8RxPacketId, len, payload, true); } switch (m_RxCmdId) { case enCmd.CMID_HELLO_RESPONSE: { if (m_u8RxPyldLen >= 5 && m_u8aRxPayload[HELLO_RESP_OFFS_RC] == 0 && m_u8aRxPayload[HELLO_RESP_OFFS_VERSION] == API_VERSION) { // change state m_SerStatus = enSerStatus.SER_ST_CONNECTED; // record manager sequence number m_bRxPacketIdInit = true; m_u8RxPacketId = m_u8aRxPayload[HELLO_RESP_OFFS_MGRSEQNO]; // 通知会话层新的会话已经建立 if (m_evStatusChanged != null) { m_evStatusChanged(m_SerStatus); } // 新的会话建立完成,则下发CLI命令 m_hdlcore.MoniterCli(); } ; break; } case enCmd.CMID_MGR_HELLO: { // 以下8行用于过滤短时间内收到的重复MgrHello报文 TimeSpan tsMgrHello = DateTime.Now - m_dtLastMgrHello; m_dtLastMgrHello = DateTime.Now; // 4秒内收到的MgrHello认为为重复 if (tsMgrHello.TotalMilliseconds < 2000) { CommStackLog.RecordInf(enLogLayer.eSerial, "Redundant MgrHello"); break; } // 以上8行用于过滤短时间内收到的重复MgrHello报文 if (m_u8RxPyldLen >= 2) { // change state m_SerStatus = enSerStatus.SER_ST_DISCONNECTED; // 通知会话层新的当前会话已经失效 if (m_evStatusChanged != null) { m_evStatusChanged(m_SerStatus); } } break; } default: { // dispatch //if (m_u8RxPyldLen > 0 && m_evRequestArrived != null && isRepeatId == false) // m_evRequestArrived(m_RxCmdId, m_u8RxControl, m_u8aRxPayload, m_u8RxPyldLen); if (m_u8RxPyldLen > 0 && m_evRequestArrived != null) { if (isNotifData) { m_evRequestArrived(m_RxCmdId, m_u8RxControl, m_u8aRxPayload, m_u8RxPyldLen); } else if (isRepeatId == false) { m_evRequestArrived(m_RxCmdId, m_u8RxControl, m_u8aRxPayload, m_u8RxPyldLen); } } break; } } // Kous: 清空接收负载缓存 Array.Clear(m_u8aRxPayload, 0, m_u8RxPyldLen); m_u8RxPyldLen = 0; } }