private void ReaderThreadLoop() { while (true) { try { byte[] readData = x10interface.ReadData(); if (readData.Length > 0) { DebugLog("X10 >", Utility.ByteArrayToString(readData)); var elapsedFromWaitAck = DateTime.Now - waitAckTimestamp; if (elapsedFromWaitAck.TotalSeconds >= commandTimeoutSeconds && communicationState != X10CommState.Ready) { DebugLog( "X10 >", "COMMAND TIMEOUT" ); communicationState = X10CommState.Ready; } // if (communicationState == X10CommState.WaitingAck && readData[0] == (int)X10CommandType.PLC_Ready && readData.Length <= 2) // ack received { DebugLog( "X10 >", "COMMAND SUCCESSFUL" ); communicationState = X10CommState.Ready; } else if ((readData.Length >= 13 || (readData.Length == 2 && readData[0] == 0xFF && readData[1] == 0x00)) && !isInterfaceReady) { UpdateInterfaceTime(false); isInterfaceReady = true; communicationState = X10CommState.Ready; } else if (readData.Length == 2 && communicationState == X10CommState.WaitingChecksum && readData[0] == expectedChecksum && readData[1] == 0x00) { // checksum is received only from CM11 DebugLog( "X10 >", "CKSUM: " + "Expected [" + Utility.ByteArrayToString(new byte[] { expectedChecksum }) + "] Checksum ==> " + Utility.ByteArrayToString(readData) ); //TODO: checksum verification not handled, we just reply 0x00 (OK) SendMessage(new byte[] { 0x00 }); communicationState = X10CommState.WaitingAck; } else if (readData[0] == (int)X10CommandType.Macro) { lastReceivedTs = DateTime.Now; DebugLog("X10 >", "MACRO: " + Utility.ByteArrayToString(readData)); } else if (readData[0] == (int)X10CommandType.RF) { lastReceivedTs = DateTime.Now; DebugLog("X10 >", "RFCOM: " + Utility.ByteArrayToString(readData)); if (RfDataReceived != null) { Thread signal = new Thread(() => { addressedModules.Clear(); RfDataReceived(new RfDataReceivedAction() { RawData = readData }); }); signal.Start(); } } else if ((readData[0] == (int)X10CommandType.PLC_Poll) && readData.Length <= 2) { isInterfaceReady = true; SendMessage(new byte[] { (byte)X10CommandType.PLC_ReplyToPoll }); // reply to poll } else if ((readData[0] == (int)X10CommandType.PLC_FilterFail_Poll) && readData.Length <= 2) { isInterfaceReady = true; SendMessage(new byte[] { (int)X10CommandType.PLC_FilterFail_Poll }); // reply to filter fail poll } else if ((readData[0] == (int)X10CommandType.PLC_Poll)) { lastReceivedTs = DateTime.Now; DebugLog("X10 >", "PLCRX: " + Utility.ByteArrayToString(readData)); // if (readData.Length > 3) { bool newAddressData = true; int messageLength = readData[1]; if (readData.Length > messageLength - 2) { char[] bitmapData = Convert.ToString(readData[2], 2).PadLeft(8, '0').ToCharArray(); byte[] functionBitmap = new byte[messageLength - 1]; for (int i = 0; i < functionBitmap.Length; i++) { functionBitmap[i] = byte.Parse(bitmapData[7 - i].ToString()); } byte[] messageData = new byte[messageLength - 1]; Array.Copy(readData, 3, messageData, 0, messageLength - 1); // CM15 Extended receive has got inverted data if (messageLength > 2 && x10interface.GetType().Equals(typeof(CM15))) { Array.Reverse(functionBitmap, 0, functionBitmap.Length); Array.Reverse(messageData, 0, messageData.Length); } DebugLog("X10 >", "FNMAP: " + Utility.ByteArrayToString(functionBitmap)); DebugLog("X10 >", " DATA: " + Utility.ByteArrayToString(messageData)); for (int b = 0; b < messageData.Length; b++) { // read current byte data (type: 0x00 address, 0x01 function) if (functionBitmap[b] == (byte)X10FunctionType.Address) // address { string housecode = ((X10HouseCodes)Convert.ToInt16( messageData[b].ToString("X2").Substring( 0, 1 ), 16 )).ToString(); string unitcode = ((X10UnitCodes)Convert.ToInt16( messageData[b].ToString("X2").Substring( 1, 1 ), 16 )).ToString(); if (unitcode.IndexOf("_") > 0) { unitcode = unitcode.Substring(unitcode.IndexOf("_") + 1); } // DebugLog("X10 >", " " + b + ") House code = " + housecode); DebugLog("X10 >", " " + b + ") Unit code = " + unitcode); // string currentUnitCode = housecode + unitcode; if (!moduleStatus.Keys.Contains(currentUnitCode)) { var module = new X10Module() { Code = currentUnitCode }; module.PropertyChanged += ModulePropertyChanged; moduleStatus.Add(currentUnitCode, module); } var mod = moduleStatus[currentUnitCode]; // //TODO: this needs more testing.... if (!addressedModules.ContainsKey(housecode)) { addressedModules.Add(housecode, new List <X10Module>()); } else if (newAddressData) { newAddressData = false; addressedModules[housecode].Clear(); } // if (!addressedModules[housecode].Contains(mod)) { addressedModules[housecode].Add(mod); } } else if (functionBitmap[b] == (byte)X10FunctionType.Function) // function { string currentCommand = ((X10Command)Convert.ToInt16( messageData[b].ToString("X2").Substring( 1, 1 ), 16 )).ToString().ToUpper(); string currentHouseCode = ((X10HouseCodes)Convert.ToInt16( messageData[b].ToString("X2").Substring( 0, 1 ), 16 )).ToString(); // DebugLog("X10 >", " " + b + ") House code = " + currentHouseCode); DebugLog("X10 >", " " + b + ") Command = " + currentCommand); // // //TODO: this needs more testing.... if (!addressedModules.ContainsKey(currentHouseCode)) { addressedModules.Add(currentHouseCode, new List <X10Module>()); } // switch (currentCommand) { case "ALL_UNITS_OFF": if (currentHouseCode != "") { AllUnitsOff(currentHouseCode); } break; case "ALL_LIGHTS_ON": if (currentHouseCode != "") { AllLightsOn(currentHouseCode); } break; case "ON": ModulesOn(currentHouseCode); break; case "OFF": ModulesOff(currentHouseCode); break; case "BRIGHT": ModulesBright(currentHouseCode, messageData[++b]); break; case "DIM": ModulesDim(currentHouseCode, messageData[++b]); break; } // newAddressData = true; } } } } } else if ((readData[0] == (int)X10CommandType.PLC_TimeRequest)) // IS THIS A TIME REQUEST? { UpdateInterfaceTime(false); } else { #region This is an hack for detecting disconnection status on Linux platforms if (readData[0] == 0x00) { zeroChecksumCount++; } else { zeroChecksumCount = 0; } // if (zeroChecksumCount > 10) { zeroChecksumCount = 0; gotReadWriteError = true; Close(); } #endregion } } } catch (Exception e) { if (!e.GetType().Equals(typeof(TimeoutException)) && !e.GetType().Equals(typeof(OverflowException))) { DebugLog("X10 !", e.Message); DebugLog("X10 !", e.StackTrace); gotReadWriteError = true; } } } }
private void _readerThreadLoop() { lock (_accesslock) { while (true) { // try { byte[] readdata = _x10interface.ReadData(); if (readdata.Length >= 13) { /* * Console.WriteLine("\n\n\n\n{0}:{1}:{2}", (readdata[4] * 2).ToString("D2"), * (readdata[3]).ToString("D2"), * (readdata[2]).ToString("D2")); * */ /* * // A1 Status request * Thread t = new Thread(new ThreadStart(delegate() * { * Thread.Sleep(10000); * //_sendqueue.Enqueue(new byte[] { 0x8B }); * _sendqueue.Enqueue(new byte[] { 0x07, 0x67, 0x06, 0x03, 0x3b }); * _sendqueue.Enqueue(new byte[] { 0x07, 0x67, 0x06, 0x00, 0x37 }); * })); * t.Start(); */ if (!_statusrequestok) { _updateInterfaceTime(false); _statusrequestok = true; } } if (readdata.Length > 0) { //Console.WriteLine("<<<<< IN " + Utility.ByteArrayToString(readdata)); // if (readdata[0] == (int)X10CommandType.PLC_Ready) { _waitingchecksum = false; Monitor.Enter(_comlock); Monitor.Pulse(_comlock); Monitor.Exit(_comlock); } else if (readdata[0] == (int)X10CommandType.Macro) { //Console.WriteLine("Macro ==> " + Utility.ByteArrayToString(readdata)); } else if (readdata[0] == (int)X10CommandType.RF) { //Console.WriteLine("RF ==> " + Utility.ByteArrayToString(readdata)); if (RfDataReceived != null) { RfDataReceived(new RfDataReceivedAction() { RawData = readdata }); } } else if ((readdata[0] == (int)X10CommandType.PLC_Poll)) // && readdata.Length > 2) { _statusrequestok = true; _sendqueue.Enqueue(new byte[] { 0xC3 }); // reply to poll //Console.WriteLine("PLC ==> " + Utility.ByteArrayToString(readdata)); if (readdata.Length > 2) { if (readdata[2] == 0x00 && readdata.Length > 3) { string housecode = ((X10HouseCodes)Convert.ToInt16(readdata[3].ToString("X2").Substring(0, 1), 16)).ToString(); string unitcode = ((X10UnitCodes)Convert.ToInt16(readdata[3].ToString("X2").Substring(1, 1), 16)).ToString(); if (unitcode.IndexOf("_") > 0) { unitcode = unitcode.Substring(unitcode.IndexOf("_") + 1); } // //Console.WriteLine(" 0x00 = Address"); //Console.WriteLine(" House code = " + housecode); //Console.WriteLine(" Unit code = " + unitcode); // _currentunitcode = housecode + unitcode; } else if (readdata[2] == 0x01 && readdata.Length > 3) { string command = ((X10Command)Convert.ToInt16(readdata[3].ToString("X2").Substring(1, 1), 16)).ToString().ToUpper(); string housecode = ((X10HouseCodes)Convert.ToInt16(readdata[3].ToString("X2").Substring(0, 1), 16)).ToString(); //Console.WriteLine(" 0x01 = Function"); //Console.WriteLine(" House code = " + housecode); //Console.WriteLine(" Command = " + command); // if (_currentunitcode != "") { if (!_modstatus.Keys.Contains(_currentunitcode)) { X10Module module = new X10Module() { Code = _currentunitcode }; // module.PropertyChanged += _modulePropertyChanged; // _modstatus.Add(_currentunitcode, module); } X10Module mod = _modstatus[_currentunitcode]; switch (command) { case "ON": //mod.Status = "ON"; mod.Level = 1.0; break; case "OFF": //mod.Status = "OFF"; mod.Level = 0.0; break; case "BRIGHT": mod.Level += (double.Parse((readdata[4] >> 3).ToString()) / 16D); if (mod.Level > 1) { mod.Level = 1; } break; case "DIM": mod.Level -= (double.Parse((readdata[4] >> 3).ToString()) / 16D); if (mod.Level < 0) { mod.Level = 0; } break; case "ALL_UNITS_OFF": _allUnitsOff(housecode); break; case "ALL_LIGHTS_ON": _allLightsOn(housecode); break; } } } } } else if ((readdata[0] == (int)X10CommandType.PLC_TimeRequest)) // IS THIS A TIME REQUEST? { _updateInterfaceTime(false); } else { // BEGIN: This is an hack for detecting disconnection status in Linux/Raspi if (readdata[0] == 0x00) { _zerochecksumcount++; } else { _zerochecksumcount = 0; } // if (_zerochecksumcount > 10) { _zerochecksumcount = 0; gotReadWriteError = true; _close(); } // END: Linux/Raspi hack else if (_waitingchecksum) { //Console.WriteLine("Expected [" + Utility.ByteArrayToString(new byte[] { _expectedchecksum }) + "] Checksum ==> " + Utility.ByteArrayToString(readdata)); //TODO: checksum verification not handled, we just reply 0x00 (OK) _sendMessage(new byte[] { 0x00 }); } } } } catch (Exception e) { if (!e.GetType().Equals(typeof(TimeoutException))) { // TODO: add error logging gotReadWriteError = true; } } Monitor.Wait(_accesslock, 10); } } }
private void ReaderThreadLoop() { while (true) { try { byte[] readData = x10interface.ReadData(); if (readData.Length > 0) { Utility.DebugLog( "X10 >", Utility.ByteArrayToString(readData) ); // var elapsedFromWaitAck = DateTime.Now - waitAckTimestamp; if (elapsedFromWaitAck.TotalSeconds >= commandTimeoutSeconds && communicationState != X10CommState.Ready) { Utility.DebugLog( "X10 >", "COMMAND TIMEOUT" ); communicationState = X10CommState.Ready; } // if (communicationState == X10CommState.WaitingAck && readData[0] == (int)X10CommandType.PLC_Ready && readData.Length <= 2) // ack received { Utility.DebugLog( "X10 >", "COMMAND SUCCESSFUL" ); communicationState = X10CommState.Ready; } else if ((readData.Length >= 13 || (readData.Length == 2 && readData[0] == 0xFF && readData[1] == 0x00)) && !isInterfaceReady) { UpdateInterfaceTime(false); isInterfaceReady = true; communicationState = X10CommState.Ready; } else if (readData.Length == 2 && communicationState == X10CommState.WaitingChecksum && readData[0] == expectedChecksum && readData[1] == 0x00) { // checksum is received only from CM11 Utility.DebugLog( "X10 >", "CKSUM: " + "Expected [" + Utility.ByteArrayToString(new byte[] { expectedChecksum }) + "] Checksum ==> " + Utility.ByteArrayToString(readData) ); //TODO: checksum verification not handled, we just reply 0x00 (OK) SendMessage(new byte[] { 0x00 }); communicationState = X10CommState.WaitingAck; } else if (readData[0] == (int)X10CommandType.Macro) { lastReceivedTs = DateTime.Now; Utility.DebugLog("X10 >", "MACRO: " + Utility.ByteArrayToString(readData)); } else if (readData[0] == (int)X10CommandType.RF) { lastReceivedTs = DateTime.Now; string message = Utility.ByteArrayToString(readData); Utility.DebugLog("X10 >", "RFCOM: " + message); // repeated messages check if (lastRfMessage == message && (lastReceivedTs - lastRfReceivedTs).TotalMilliseconds < 200) { Utility.DebugLog("X10 >", "RFCOM: ^^^^^^^^^^^^^^^^^ Ignoring repeated message within 200ms"); continue; } lastRfMessage = message; lastRfReceivedTs = lastReceivedTs; // if (RfDataReceived != null) { Thread signal = new Thread(() => { try { RfDataReceived(new RfDataReceivedAction() { RawData = readData }); } catch { // TODO: handle/report exception } }); signal.Start(); } // Decode X10 RF Module Command (eg. "5D 20 70 8F 48 B7") if (readData.Length == 6 && readData[1] == 0x20 && ((readData[3] & ~readData[2]) == readData[3] && (readData[5] & ~readData[4]) == readData[5])) { byte hu = readData[2]; // house code + 4th bit of unit code byte hf = readData[4]; // unit code (3 bits) + function code string houseCode = ((X10HouseCode)(Utility.ReverseByte((byte)(hu >> 4)) >> 4)).ToString(); switch (hf) { case 0x98: // DIM ONE STEP CommandEvent_Dim(0x0F); break; case 0x88: // BRIGHT ONE STEP CommandEvent_Bright(0x0F); break; case 0x90: // ALL LIGHTS ON if (houseCode != "") { CommandEvent_AllLightsOn(houseCode); } break; case 0x80: // ALL LIGHTS OFF if (houseCode != "") { CommandEvent_AllUnitsOff(houseCode); } break; default: string houseUnit = Convert.ToString(hu, 2).PadLeft(8, '0'); string unitFunction = Convert.ToString(hf, 2).PadLeft(8, '0'); string unitCode = (Convert.ToInt16(houseUnit.Substring(5, 1) + unitFunction.Substring(1, 1) + unitFunction.Substring(4, 1) + unitFunction.Substring(3, 1), 2) + 1).ToString(); // UnselectModules(); SelectModule(houseCode + unitCode); // if (unitFunction[2] == '1') // 1 = OFF, 0 = ON { CommandEvent_Off(); } else { CommandEvent_On(); } break; } } } else if ((readData[0] == (int)X10CommandType.PLC_Poll) && readData.Length <= 2) { isInterfaceReady = true; SendMessage(new byte[] { (byte)X10CommandType.PLC_ReplyToPoll }); // reply to poll } else if ((readData[0] == (int)X10CommandType.PLC_FilterFail_Poll) && readData.Length <= 2) { isInterfaceReady = true; SendMessage(new byte[] { (int)X10CommandType.PLC_FilterFail_Poll }); // reply to filter fail poll } else if ((readData[0] == (int)X10CommandType.PLC_Poll)) { lastReceivedTs = DateTime.Now; Utility.DebugLog("X10 >", "PLCRX: " + Utility.ByteArrayToString(readData)); // if (readData.Length > 3) { int messageLength = readData[1]; if (readData.Length > messageLength - 2) { char[] bitmapData = Convert.ToString(readData[2], 2).PadLeft(8, '0').ToCharArray(); byte[] functionBitmap = new byte[messageLength - 1]; for (int i = 0; i < functionBitmap.Length; i++) { functionBitmap[i] = byte.Parse(bitmapData[7 - i].ToString()); } byte[] messageData = new byte[messageLength - 1]; Array.Copy(readData, 3, messageData, 0, messageLength - 1); // // CM15 Extended receive has got inverted data if (messageLength > 2 && x10interface.GetType().Equals(typeof(CM15))) { Array.Reverse(functionBitmap, 0, functionBitmap.Length); Array.Reverse(messageData, 0, messageData.Length); } // Utility.DebugLog("X10 >", "FNMAP: " + Utility.ByteArrayToString(functionBitmap)); Utility.DebugLog("X10 >", " DATA: " + Utility.ByteArrayToString(messageData)); for (int b = 0; b < messageData.Length; b++) { // read current byte data (type: 0x00 address, 0x01 function) if (functionBitmap[b] == (byte)X10FunctionType.Address) // address { X10HouseCode houseCode = (X10HouseCode)Convert.ToInt16(messageData[b].ToString("X2").Substring(0, 1), 16); X10UnitCode unitCode = (X10UnitCode)Convert.ToInt16(messageData[b].ToString("X2").Substring(1, 1), 16); string address = Utility.HouseUnitCodeFromEnum(houseCode, unitCode); // Utility.DebugLog("X10 >", " " + b + ") Address = " + address); // if (newAddressData) { newAddressData = false; UnselectModules(); } SelectModule(address); } else if (functionBitmap[b] == (byte)X10FunctionType.Function) // function { string function = ((X10Command)Convert.ToInt16(messageData[b].ToString("X2").Substring(1, 1), 16)).ToString().ToUpper(); string houseCode = ((X10HouseCode)Convert.ToInt16(messageData[b].ToString("X2").Substring(0, 1), 16)).ToString(); // Utility.DebugLog("X10 >", " " + b + ") House code = " + houseCode); Utility.DebugLog("X10 >", " " + b + ") Command = " + function); // switch (function) { case "ALL_UNITS_OFF": if (houseCode != "") { CommandEvent_AllUnitsOff(houseCode); } break; case "ALL_LIGHTS_ON": if (houseCode != "") { CommandEvent_AllLightsOn(houseCode); } break; case "ON": CommandEvent_On(); break; case "OFF": CommandEvent_Off(); break; case "BRIGHT": CommandEvent_Bright(messageData[++b]); break; case "DIM": CommandEvent_Dim(messageData[++b]); break; } // newAddressData = true; } } } } } else if ((readData[0] == (int)X10CommandType.PLC_TimeRequest)) // IS THIS A TIME REQUEST? { UpdateInterfaceTime(false); } else { #region This is an hack for detecting disconnection status on Linux platforms if (readData[0] == 0x00) { zeroChecksumCount++; } else { zeroChecksumCount = 0; } // if (zeroChecksumCount > 10) { zeroChecksumCount = 0; gotReadWriteError = true; Close(); } else { SendMessage(new byte[] { 0x00 }); } #endregion } } } catch (Exception e) { if (!e.GetType().Equals(typeof(TimeoutException)) && !e.GetType().Equals(typeof(OverflowException))) { gotReadWriteError = true; Utility.DebugLog("X10 !", e.Message); Utility.DebugLog("X10 !", e.StackTrace); } } } }