/// <summary> /// Do CAL Management comms transaction, expecting local echo /// </summary> /// <param name="communicationChannel"></param> /// <param name="calCommand"></param> /// <returns></returns> bool DoCALCommsTransaction(Interface.Communication.ICommunicationChannel communicationChannel, ICBusCommand calCommand) { var rxBuffer = new byte[128]; var commandString = calCommand.ToCBusString(); Logger.DebugFormat("TX {0}:{1}", calCommand, commandString); CBus.Protocol.CBusProtcol.SendCommand(communicationChannel, calCommand); Thread.Sleep(200); var rxLen = communicationChannel.ReceiveBytes(rxBuffer, rxBuffer.Length); var rxDataString = GetReceivedString(rxBuffer, rxLen); if (rxDataString.StartsWith(commandString)) { Logger.DebugFormat("RX:{0}", rxDataString.Substring(commandString.Length)); return(true); } else { Logger.WarnFormat("RX:{0}", rxDataString); return(false); } }
protected override void OnThreadEntry(object ThreadContext) { var context = ThreadContext as BaseThreadedDevice.ThreadContext; var protocol = new CBusProtcol(256); var rxBuffer = new byte[256]; var keepAliveTimeout = DateTime.Now; var keepAliveInterval = TimeSpan.FromSeconds(10); CBusSALCommand _pendingCommand = null; var _state = new CBusProtcol.CBusStateMachine(); while (context.KeepRunning) { var clock = DateTime.Now; try { if (!_CommunicationChannel.IsOpen) { if (!_CommunicationChannel.Open()) { Thread.Sleep(500); } else { if (!PerformLogon(_CommunicationChannel)) { Logger.WarnFormat("Logon Failed"); _CommunicationChannel.Close(); } else { Logger.Info("Logon Success"); } } } if (_CommunicationChannel.IsOpen) { #region Process Received Messages int bytesReceived = _CommunicationChannel.ReceiveBytes(rxBuffer, rxBuffer.Length); if (bytesReceived > 0) { var rxCharacterBufferPointer = 0; var receviedCharacters = Protocol.CBusProtcol.CharacterEncoding.GetChars(rxBuffer, 0, bytesReceived); while (rxCharacterBufferPointer < receviedCharacters.Length) { if (protocol.TryProcessReceivedBytes(receviedCharacters, receviedCharacters.Length, ref rxCharacterBufferPointer, _state)) { //Log received messages if (Logger.IsDebugEnabled) { Logger.DebugFormat("State:{0}", _state); var cmdString = CBusSALCommand.BinaryArrayToHexString(_state.CommandBytes, _state.CommandLength); Logger.DebugFormat( "Rx Message:{0}", cmdString); } switch (_state.MessageType) { case CBusProtcol.CBusMessageType.ACK: { if (_state.ACK_Character.HasValue && _pendingCommand != null && _pendingCommand.AckCharacter.HasValue) { //ACK Received if (_state.ACK_Character.Value == _pendingCommand.AckCharacter.Value) { Logger.DebugFormat("Positive ACK Received"); if (_pendingCommand != null) { //When command acked, same as receiving an unsolicited message switch (_pendingCommand.ApplicationType) { case CBusProtcol.ApplicationTypes.LIGHTING: ProcessLightingMessageResponse((CBusLightingCommand)_pendingCommand); break; case CBusProtcol.ApplicationTypes.TRIGGER: ProcessTriggerMessageResponse((CBusTriggerCommand)_pendingCommand); break; } _pendingCommand = null; } } } break; } case CBusProtcol.CBusMessageType.NAK: case CBusProtcol.CBusMessageType.NAK_CORRUPTED: case CBusProtcol.CBusMessageType.NAK_NO_CLOCK: case CBusProtcol.CBusMessageType.NAK_MESSAGE_TOO_LONG: Logger.WarnFormat("NAK Received: {0}", _state.MessageType); _pendingCommand = null; break; case CBusProtcol.CBusMessageType.SAL_MESSAGE_RECEIVED: case CBusProtcol.CBusMessageType.MONITORED_SAL_MESSAGE_RECEIVED: { CBusSALCommand cmd; var isMonitoredSAL = (_state.MessageType == CBusProtcol.CBusMessageType.MONITORED_SAL_MESSAGE_RECEIVED); //In smart mode all messages are received in Long format var isSmartMode = (_configBuilder.Options_1 & CBusProtcol.Interface_Options_1.SMART) != 0; if (_CBusAddressMap.TryParseCommand(_state.CommandBytes, _state.CommandLength, isMonitoredSAL, !isSmartMode, out cmd)) { switch (cmd.ApplicationType) { case CBusProtcol.ApplicationTypes.LIGHTING: { //Process Command var lightingCommand = (CBus.Protocol.CBusLightingCommand)cmd; ProcessLightingMessageResponse(lightingCommand); break; } case CBusProtcol.ApplicationTypes.TRIGGER: { var triggerCommand = (CBus.Protocol.CBusTriggerCommand)cmd; ProcessTriggerMessageResponse(triggerCommand); break; } default: Logger.WarnFormat("Unknown CBus application Type (Discarding), {0}", cmd.ApplicationType); break; } } else { if (Logger.IsWarnEnabled) { var cmdString = CBusSALCommand.BinaryArrayToHexString(_state.CommandBytes, _state.CommandLength); Logger.WarnFormat("Failed to process command, {0}", cmdString); Logger.WarnFormat("State:{0}", _state); } } break; } }//END: Switch //Reset state after a positive outcome _state.Reset(); } else { //No message received } } } #endregion #region Tx Command ICommand command = _commandQueue.Dequeue(); if (command != null) { if (command is Command.Device.LightingDeviceCommand) { var cmd = (Command.Device.LightingDeviceCommand)command; var preset = _presetMap.SingleOrDefault(x => x.PresetName == cmd.Preset); if (preset != null) { if (preset.CBusCommandType == PresetMap.CommandType.Lighting) { //byte ApplicationLightingAddress = preset.CBusApplicationId; //if (_CBusAddressMap.TryGetApplicationAddress(CBusProtcol.ApplicationTypes.LIGHTING, out ApplicationLightingAddress)) { _pendingCommand = new CBus.Protocol.CBusLightingCommand( CBus.Protocol.CBusSALCommand.CBusHeader.PPM, preset.CBusApplicationId, new CBusLightingCommand.LightingCommand( cmd.TargetState ? CBusLightingCommand.LightingCommand.LightingCommandId.ON : CBusLightingCommand.LightingCommand.LightingCommandId.OFF, preset.CBusGroupAddress) ); } } else if (preset.CBusCommandType == PresetMap.CommandType.Trigger) { //byte ApplicationTriggerAddress = preset.CBusApplicationId; //if (_CBusAddressMap.TryGetApplicationAddress(CBusProtcol.ApplicationTypes.TRIGGER, out ApplicationTriggerAddress)) { _pendingCommand = new CBus.Protocol.CBusTriggerCommand( CBus.Protocol.CBusSALCommand.CBusHeader.PPM, preset.CBusApplicationId, new[] { new CBusTriggerCommand.TriggerCommand(preset.CBusGroupAddress, preset.CBusLevelOrAction) } ); } } if (_pendingCommand != null) { _pendingCommand.AckCharacter = protocol.NextConfirmationCharacter(); Logger.DebugFormat("TX {0}:{1}", _pendingCommand, _pendingCommand.ToCBusString()); CBusProtcol.SendCommand(_CommunicationChannel, _pendingCommand); keepAliveTimeout = clock.Add(keepAliveInterval); } } else { //Preset not recognised } } else { //Un Supported Command } } #endregion Tx Command else { if (keepAliveTimeout < clock) { keepAliveTimeout = clock.Add(keepAliveInterval); var ping = Protocol.CBusProtcol.CharacterEncoding.GetBytes("\r\n"); _CommunicationChannel.SendBytes(ping, ping.Length); Logger.DebugFormat("Lighting Keep Alive Sent"); } else { _commandQueue.Handle.WaitOne(500); } } } else { //Comms not open Thread.Sleep(1000); } } catch (ThreadInterruptedException) { Logger.Debug("Thread Interrupted"); } catch (Exception ex) { if (ex is ThreadAbortException) { throw; } else { Logger.Error("Thread Error", ex); Thread.Sleep(1000); } } } }
private bool PerformLogon(Interface.Communication.ICommunicationChannel communicationChannel) { var rxBuffer = new byte[128]; string rxString = string.Empty; var resetCount = 3; var resetSuccess = false; do { ICBusCommand calCommand = _configBuilder.ResetCommand(); Logger.DebugFormat("TX {0}:{1}", calCommand, calCommand.ToCBusString()); CBus.Protocol.CBusProtcol.SendCommand(communicationChannel, calCommand); CBus.Protocol.CBusProtcol.SendCommand(communicationChannel, calCommand); //Wait for response Thread.Sleep(200); var rxLen = communicationChannel.ReceiveBytes(rxBuffer, rxBuffer.Length); rxString = GetReceivedString(rxBuffer, rxLen); Logger.DebugFormat("RX:{0}", rxString); resetCount--; resetSuccess = rxString.Contains(CBus.Protocol.CBusProtcol.MODE_RESET_CHAR); } while (!resetSuccess && resetCount > 0); if (resetSuccess) { _ActiveApplications.Sort(); for (int i = 0; i < _ActiveApplications.Count(); i++) { var calCommand_App = _configBuilder.RegisterApplication1Monitor(_ActiveApplications[i]); if (!DoCALCommsTransaction(communicationChannel, calCommand_App)) { return(false); } } var calCommand = _configBuilder.Set_CAL_Options3(CBusProtcol.Interface_Options_3.LOCAL_SAL); if (!DoCALCommsTransaction(communicationChannel, calCommand)) { return(false); } //See 4.3.3.1 CAL Reply, to under stand response (Long Form response as SMART selected) //Tx:@A3300059 //Response: 86FAFA0032300024 calCommand = _configBuilder.Set_CAL_Options1( CBusProtcol.Interface_Options_1.CONNECT | CBusProtcol.Interface_Options_1.SRCHK | CBusProtcol.Interface_Options_1.SMART | CBusProtcol.Interface_Options_1.IDIOM ); if (!DoCALCommsTransaction(communicationChannel, calCommand)) { return(false); } return(true); } return(false); }