public override bool ParseResponse(byte[] buffer) { if (!IsResponseOK(buffer)) { // response not OK => do nothing return(false); } m_networkAddress = AdapterHelper.UInt16FromXbeeFrame(buffer, DATA_OFFSET_IN_RESPONSE_BUFFER); return(true); }
protected bool IsResponseOK(byte[] buffer) { int offset = 0; // verify cluster Id offset = AdapterHelper.MAC_ADDR_LENGTH; offset += AdapterHelper.NETWORK_ADDRESS_LENGTH; offset += SOURCE_ENDPOINT.Length; offset += DESTINATION_ENDPOINT.Length; UInt16 tempValue = AdapterHelper.UInt16FromXbeeFrame(buffer, offset); if (tempValue != m_responseClusterId) { return(false); } if (!m_isZdoCommand) { // there is nothing more to control for ZCL // // - cluster ID is hard to control (Phillips Hue light bulb respond with ZHA profile even though they are ZLL profile) // - status of ZCL command is inside ZCL payload and depends on each ZCL command return(true); } // verify profile Id offset += DEFAULT_CLUSTER_ID.Length; byte[] profileId = PROFILE_ID; for (int index = 0; index < profileId.Length; index++) { if (buffer[index + offset] != profileId[index]) { return(false); } } // verify status only for response to ZDO command (ZDO notification don't have status) if (!m_isNotification) { offset = GetZdoPayloadOffset() - ZIGBEE_STATUS_LENGTH; if (buffer[offset] != ZdoHelper.ZDO_ERROR_SUCCESS) { return(false); } } return(true); }
private bool CheckResponse() { bool checkNextResponse = false; int headerSize = 0; bool signalResponseReceived = false; byte[] response = null; XBeeATCommand atCommand = null; ZigBeeCommand zigBeeCommand = null; lock (m_locker) { if (COMMAND_PREFIX[0] != m_currentResponse[0]) { // response buffer is invalid => discard m_currentResponse = null; return(checkNextResponse); } headerSize = COMMAND_PREFIX.Length + sizeof(UInt16); if (m_currentResponse.Length <= headerSize) { // not enough bytes => wait for more return(checkNextResponse); } // get size of response int payloadLength = (int)AdapterHelper.UInt16FromXbeeFrame(m_currentResponse, COMMAND_PREFIX.Length); int fullResponseLength = payloadLength + headerSize + CHECKSUM_LENGTH; if (m_currentResponse.Length < fullResponseLength) { // not enough bytes => wait for more return(checkNextResponse); } // verify checksum if (IsCheckSumOk(ref m_currentResponse, headerSize, payloadLength + CHECKSUM_LENGTH)) { // trace Rx buffer to debug output Logger.TraceRxBuffer(m_currentResponse); // get frame type byte frameType = m_currentResponse[headerSize]; // find corresponding command or corresponding notification if (frameType == AT_COMMAND_LOCAL_RECEIVE[0] || frameType == AT_COMMAND_REMOTE_RECEIVE[0]) { // get command ID byte commandId = m_currentResponse[headerSize + AT_COMMAND_LOCAL_RECEIVE.Length]; if (m_pendingATCmdList.TryGetValue(commandId, out atCommand)) { Debug.WriteLineIf(Logger.IsVerbose(), "got response", atCommand.ToString()); // command found => parse response and remove from list int responseHeaderLength = sizeof(byte) + AT_COMMAND_LOCAL_RECEIVE.Length; payloadLength -= responseHeaderLength; response = new byte[payloadLength]; Array.Copy(m_currentResponse, headerSize + responseHeaderLength, response, 0, payloadLength); atCommand.ParseResponse(response); RemovePendingATCmd(commandId); signalResponseReceived = true; } else { Debug.WriteLineIf(Logger.IsVerbose(), "unmanaged response to AT COMMAND or AT COMMAND notification"); } } else if (frameType == EXPLICIT_RX_INDICATOR[0]) { int responseHeaderLength = sizeof(byte); payloadLength -= responseHeaderLength; response = new byte[payloadLength]; Array.Copy(m_currentResponse, headerSize + responseHeaderLength, response, 0, payloadLength); byte zdoSequenceNumber = m_currentResponse[headerSize + EXPLICIT_RX_INDICATOR.Length + ZigBeeCommand.GetSequenceNumberOffestInZdoFrame()]; byte zclSequenceNumber = m_currentResponse[headerSize + EXPLICIT_RX_INDICATOR.Length + ZigBeeCommand.GetSequenceNumberOffestInZclFrame()]; if ((m_pendingZigBeeCmdList.TryGetValue(zdoSequenceNumber, out zigBeeCommand) && zigBeeCommand.IsZdoCommand) || (m_pendingZigBeeCmdList.TryGetValue(zclSequenceNumber, out zigBeeCommand) && !zigBeeCommand.IsZdoCommand)) { Debug.WriteLineIf(Logger.IsVerbose(), "got response to ZDO or ZCL command", zigBeeCommand.ToString()); zigBeeCommand.ParseResponse(response); if (zigBeeCommand.IsZdoCommand) { RemovePendingZigBeeCmd(zdoSequenceNumber); } else { RemovePendingZigBeeCmd(zclSequenceNumber); } signalResponseReceived = true; } else { // check if this is an awaited notification foreach (var notification in m_ZigBeeNotificationList) { // "try" parsing response to figure out if it // correspond to a awaited notification if (notification.Value.ParseResponse(response)) { // corresponding notification found Debug.WriteLineIf(Logger.IsVerbose(), "notification of ZDO or ZCL command", notification.Value.ToString()); break; } } Debug.WriteLineIf(Logger.IsVerbose(), "unmanaged response to ZDO or ZCL command"); } } else { Debug.WriteLineIf(Logger.IsVerbose(), "received frame OK but not handled"); } } // remove response from buffer ClearResponseBuffer(fullResponseLength); if (m_currentResponse != null && m_currentResponse.Length != 0) { checkNextResponse = true; } } if (signalResponseReceived) { if (null != atCommand) { atCommand.SignalResponseReceive(); } else if (null != zigBeeCommand) { zigBeeCommand.SignalResponseReceive(); } } return(checkNextResponse); }
public override bool ParseResponse(byte[] buffer) { SOURCE_INFO sourceInfo = new SOURCE_INFO(); // verify command Id int offset = GetZclCommandIdOffset(ref buffer); if (COMMAND_ID_REPORT_ATTRIBUTES != buffer[offset]) { return(false); } if (OnReception == null) { // can't signal anything // however this is not an error => return true return(true); } // get Mac address, network address, endpoint Id and cluster Id of source offset = 0; sourceInfo.macAddress = AdapterHelper.UInt64FromXbeeFrame(buffer, offset); offset = AdapterHelper.MAC_ADDR_LENGTH; sourceInfo.networkAddress = AdapterHelper.UInt16FromXbeeFrame(buffer, offset); offset += AdapterHelper.NETWORK_ADDRESS_LENGTH; sourceInfo.endpointId = buffer[offset]; offset++; // skip destination end point offset++; sourceInfo.clusterId = AdapterHelper.UInt16FromXbeeFrame(buffer, offset); string strBuffer = ""; foreach (byte b in buffer) { strBuffer = strBuffer + b.ToString() + " "; } loggingServices.WriteLine <ZclReportAttributes>("strBuffer = [" + strBuffer + "]"); loggingServices.WriteLine <ZclReportAttributes>("macAddress = [" + sourceInfo.macAddress + "]"); loggingServices.WriteLine <ZclReportAttributes>("networkAddress = [" + sourceInfo.networkAddress + "]"); loggingServices.WriteLine <ZclReportAttributes>("endpointId = [" + sourceInfo.endpointId + "]"); loggingServices.WriteLine <ZclReportAttributes>("clusterId = [" + sourceInfo.clusterId + "]"); // parse ZCL payload offset = GetZclPayloadOffset(ref buffer); loggingServices.WriteLine <ZclReportAttributes>("offset of addributeId = [" + offset + "]"); while (offset < buffer.Length) { object value = null; // from ZCL report attribute payload // - 1st byte is the attribute Id // - 2nd byte indicates the type // - following byte(s) contain the value UInt16 attributeId = AdapterHelper.UInt16FromZigBeeFrame(buffer, offset); loggingServices.WriteLine <ZclReportAttributes>("attributeId = [" + attributeId + "]"); offset += sizeof(UInt16); byte type = buffer[offset]; offset += sizeof(byte); loggingServices.WriteLine <ZclReportAttributes>("offset of value = [" + offset + "]"); if (!ZclHelper.GetValue(type, ref buffer, ref offset, out value)) { // give up if attribute can't be retrieved break; } // execute notification callback asynchronously Task.Run(() => { OnReception(sourceInfo, attributeId, value); }); } return(true); }
public override bool ParseResponse(byte[] buffer) { if (m_commandList.Count == 0) { // no server command registered return(false); } // get Mac address, endpoint Id, cluster Id and command Id of source int offset = 0; UInt64 macAddress = AdapterHelper.UInt64FromXbeeFrame(buffer, offset); offset = AdapterHelper.MAC_ADDR_LENGTH; // skip network address (mac address is enough) offset += AdapterHelper.NETWORK_ADDRESS_LENGTH; byte endpointId = buffer[offset]; offset++; // skip destination end point offset++; UInt16 clusterId = AdapterHelper.UInt16FromXbeeFrame(buffer, offset); offset = GetZclCommandIdOffset(ref buffer); byte commandId = buffer[offset]; // find element that matches Mac address, network address, endpoint Id and cluster Id var element = Find(macAddress, endpointId, clusterId, commandId); if (element == null) { // no corresponding element for that Zcl server command return(false); } if (element.OnReception == null) { // no notification hence nothing else to do return(true); } // get parameters offset = GetZclPayloadOffset(ref buffer); // fill in out parameters foreach (var parameter in element.ParamList) { object value; if (!ZclHelper.GetValue(parameter.ZigBeeType, ref buffer, ref offset, out value)) { // can't get one of the out parameters => nothing else to do // note that return value is true because server command has been found but can't be parsed return(true); } parameter.Data = value; } // execute notification callback asynchronously Task.Run(() => { element.OnReception(element); }); return(true); }