Beispiel #1
0
        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 ReaderTask(CancellationToken readerToken)
        {
            while (!readerToken.IsCancellationRequested)
            {
                try
                {
                    byte[] readData = x10interface.ReadData();
                    if (readData.Length > 0)
                    {
                        logger.Debug(BitConverter.ToString(readData));
                        // last command ACK timeout
                        var elapsedFromWaitAck = DateTime.Now - waitAckTimestamp;
                        if (elapsedFromWaitAck.TotalSeconds >= commandTimeoutSeconds && communicationState != X10CommState.Ready)
                        {
                            logger.Warn("Command acknowledge timeout");
                            communicationState = X10CommState.Ready;
                        }
                        // last command succesfully sent
                        if (communicationState == X10CommState.WaitingAck && readData[0] == (int)X10CommandType.PLC_Ready && readData.Length <= 2) // ack received
                        {
                            logger.Debug("Command succesfull");
                            communicationState = X10CommState.Ready;
                        }
                        else if ((readData.Length >= 13 || (readData.Length == 2 && readData[0] == 0xFF && readData[1] == 0x00)) && !isInterfaceReady)
                        {
                            OnConnectionStatusChanged(new ConnectionStatusChangedEventArgs(true));
                            UpdateInterfaceTime(false);
                            communicationState = X10CommState.Ready;
                        }
                        else if (readData.Length == 2 && communicationState == X10CommState.WaitingChecksum && readData[0] == expectedChecksum && readData[1] == 0x00)
                        {
                            // checksum is received only from CM11
                            logger.Debug("Received checksum {0}, expected {1}", BitConverter.ToString(readData), expectedChecksum.ToString("X2"));
                            //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;
                            logger.Debug("MACRO: {0}", BitConverter.ToString(readData));
                        }
                        else if (readData[0] == (int)X10CommandType.RF)
                        {
                            lastReceivedTs = DateTime.Now;

                            bool isSecurityCode = (readData.Length == 8 && readData[1] == (byte)X10Defs.RfSecurityPrefix && ((readData[3] ^ readData[2]) == 0x0F) && ((readData[5] ^ readData[4]) == 0xFF));
                            bool isCodeValid = isSecurityCode || (readData.Length == 6 && readData[1] == (byte)X10Defs.RfCommandPrefix && ((readData[3] & ~readData[2]) == readData[3] && (readData[5] & ~readData[4]) == readData[5]));

                            // Still unknown meaning of the last byte in security codes
                            if (isSecurityCode && readData[7] == 0x80)
                                readData[7] = 0x00;

                            // Repeated messages check
                            if (isCodeValid)
                            {
                                if (lastRfMessage == BitConverter.ToString(readData) && (lastReceivedTs - lastRfReceivedTs).TotalMilliseconds < minRfRepeatDelayMs)
                                {
                                    logger.Warn("Ignoring repeated message within {0}ms", minRfRepeatDelayMs);
                                    continue;
                                }
                                lastRfMessage = BitConverter.ToString(readData);
                                lastRfReceivedTs = DateTime.Now;
                            }

                            logger.Debug("RFCOM: {0}", BitConverter.ToString(readData));
                            OnRfDataReceived(new RfDataReceivedEventArgs(readData));

                            // Decode received 32 bit message
                            // house code + 4th bit of unit code
                            // unit code (3 bits) + function code
                            if (isSecurityCode)
                            {
                                var securityEvent = X10RfSecurityEvent.NotSet;
                                Enum.TryParse<X10RfSecurityEvent>(readData[4].ToString(), out securityEvent);
                                uint securityAddress = BitConverter.ToUInt32(new byte[] { readData[2], readData[6], readData[7], 0x00 }, 0);
                                if (securityEvent != X10RfSecurityEvent.NotSet)
                                {
                                    logger.Debug("Security Event {0} Address {1}", securityEvent, securityAddress);
                                    OnRfSecurityReceived(new RfSecurityReceivedEventArgs(securityEvent, securityAddress));
                                }
                                else
                                {
                                    logger.Warn("Could not parse security event");
                                }
                            }
                            else if (isCodeValid)
                            {
                                // Parse function code
                                var hf = X10RfFunction.NotSet;
                                Enum.TryParse<X10RfFunction>(readData[4].ToString(), out hf);
                                // House code (4bit) + unit code (4bit)
                                byte hu = readData[2];
                                // Parse house code
                                var houseCode = X10HouseCode.NotSet;
                                Enum.TryParse<X10HouseCode>((Utility.ReverseByte((byte)(hu >> 4)) >> 4).ToString(), out houseCode);
                                switch (hf)
                                {
                                case X10RfFunction.Dim:
                                case X10RfFunction.Bright:
                                    logger.Debug("Command {0}", hf);
                                    if (hf == X10RfFunction.Dim)
                                        CommandEvent_Dim((byte)X10Defs.DimBrightStep);
                                    else
                                        CommandEvent_Bright((byte)X10Defs.DimBrightStep);
                                    OnRfCommandReceived(new RfCommandReceivedEventArgs(hf, X10HouseCode.NotSet, X10UnitCode.Unit_NotSet));
                                    break;
                                case X10RfFunction.AllLightsOn:
                                case X10RfFunction.AllLightsOff:
                                    if (houseCode != X10HouseCode.NotSet)
                                    {
                                        logger.Debug("Command {0} HouseCode {1}", hf, houseCode);
                                        if (hf == X10RfFunction.AllLightsOn)
                                            CommandEvent_AllLightsOn(houseCode);
                                        else
                                            CommandEvent_AllUnitsOff(houseCode);
                                        OnRfCommandReceived(new RfCommandReceivedEventArgs(hf, houseCode, X10UnitCode.Unit_NotSet));
                                    }
                                    else
                                    {
                                        logger.Warn("Unable to decode house code value");
                                    }
                                    break;
                                case X10RfFunction.NotSet:
                                    logger.Warn("Unable to decode function value");
                                    break;
                                default:
                                    // Parse unit code
                                    string houseUnit = Convert.ToString(hu, 2).PadLeft(8, '0');
                                    string unitFunction = Convert.ToString(readData[4], 2).PadLeft(8, '0');
                                    string uc = (Convert.ToInt16(houseUnit.Substring(5, 1) + unitFunction.Substring(1, 1) + unitFunction.Substring(4, 1) + unitFunction.Substring(3, 1), 2) + 1).ToString();
                                    // Parse module function
                                    var fn = X10RfFunction.NotSet;
                                    Enum.TryParse<X10RfFunction>(unitFunction[2].ToString(), out fn);
                                    switch (fn)
                                    {
                                    case X10RfFunction.On:
                                    case X10RfFunction.Off:
                                        var unitCode = X10UnitCode.Unit_NotSet;
                                        Enum.TryParse<X10UnitCode>("Unit_" + uc.ToString(), out unitCode);
                                        if (unitCode != X10UnitCode.Unit_NotSet)
                                        {
                                            logger.Debug("Command {0} HouseCode {1} UnitCode {2}", fn, houseCode, unitCode.Value());
                                            UnselectModules();
                                            SelectModule(houseCode.ToString() + unitCode.Value().ToString());
                                            if (fn == X10RfFunction.On)
                                                CommandEvent_On();
                                            else
                                                CommandEvent_Off();
                                            OnRfCommandReceived(new RfCommandReceivedEventArgs(fn, houseCode, unitCode));
                                        }
                                        else
                                        {
                                            logger.Warn("Could not parse unit code");
                                        }
                                        break;
                                    }
                                    break;
                                }
                            }
                            else
                            {
                                logger.Warn("Bad Rf message received");
                            }
                        }
                        else if ((readData[0] == (int)X10CommandType.PLC_Poll) && readData.Length <= 2)
                        {
                            OnConnectionStatusChanged(new ConnectionStatusChangedEventArgs(true));
                            SendMessage(new byte[] { (byte)X10CommandType.PLC_ReplyToPoll }); // reply to poll
                        }
                        else if ((readData[0] == (int)X10CommandType.PLC_FilterFail_Poll) && readData.Length <= 2)
                        {
                            OnConnectionStatusChanged(new ConnectionStatusChangedEventArgs(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;
                            logger.Debug("PLCRX: {0}", BitConverter.ToString(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);
                                    }

                                    logger.Debug("FNMAP: {0}", BitConverter.ToString(functionBitmap));
                                    logger.Debug("DATA : {0}", BitConverter.ToString(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);

                                            logger.Debug("      {0}) Address = {1}", b, address);

                                            if (newAddressData)
                                            {
                                                newAddressData = false;
                                                UnselectModules();
                                            }
                                            SelectModule(address);

                                            OnPlcAddressReceived(new PlcAddressReceivedEventArgs(houseCode, unitCode));
                                        }
                                        else if (functionBitmap[b] == (byte)X10FunctionType.Function) // function
                                        {
                                            var command = (X10Command)Convert.ToInt16(messageData[b].ToString("X2").Substring(1, 1), 16);
                                            var houseCode = X10HouseCode.NotSet;
                                            Enum.TryParse<X10HouseCode>(Convert.ToInt16(messageData[b].ToString("X2").Substring(0, 1), 16).ToString(), out houseCode);

                                            logger.Debug("      {0}) House code = {1}", b, houseCode);
                                            logger.Debug("      {0})    Command = {1}", b, command);

                                            switch (command)
                                            {
                                            case X10Command.All_Lights_Off:
                                                if (houseCode != X10HouseCode.NotSet)
                                                    CommandEvent_AllUnitsOff(houseCode);
                                                break;
                                            case X10Command.All_Lights_On:
                                                if (houseCode != X10HouseCode.NotSet)
                                                    CommandEvent_AllLightsOn(houseCode);
                                                break;
                                            case X10Command.On:
                                                CommandEvent_On();
                                                break;
                                            case X10Command.Off:
                                                CommandEvent_Off();
                                                break;
                                            case X10Command.Bright:
                                                CommandEvent_Bright(messageData[++b]);
                                                break;
                                            case X10Command.Dim:
                                                CommandEvent_Dim(messageData[++b]);
                                                break;
                                            }
                                            newAddressData = true;

                                            OnPlcFunctionReceived(new PlcFunctionReceivedEventArgs(command, houseCode));
                                        }
                                    }
                                }
                            }
                        }
                        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/Mono 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;
                        logger.Error(e);
                    }
                }
            }
        }
Beispiel #3
0
        private void SendMessage(byte[] message)
        {
            try
            {

                // Wait for message delivery acknowledge
                if (message.Length > 1 && IsConnected)
                {
                    lock(waitAckMonitor)
                    {
                        while((DateTime.Now - lastReceivedTs).TotalMilliseconds < 500)
                        {
                            Thread.Sleep(50);
                        }

                        DebugLog("X10 <", Utility.ByteArrayToString(message));
                        x10interface.WriteData(message);

                        commandLastMessage = message;
                        waitAckTimestamp = DateTime.Now;

                        if (x10interface.GetType().Equals(typeof(CM11)))
                        {
                            expectedChecksum = (byte)((message[0] + message[1]) & 0xff);
                            communicationState = X10CommState.WaitingChecksum;
                        }
                        else
                        {
                            communicationState = X10CommState.WaitingAck;
                        }

                        while (commandResendAttempts < commandResendMax && communicationState != X10CommState.Ready)
                        {
                            var elapsedFromWaitAck = DateTime.Now - waitAckTimestamp;
                            while (elapsedFromWaitAck.TotalSeconds < commandTimeoutSeconds && communicationState != X10CommState.Ready)
                            {
                                Thread.Sleep(50);
                                elapsedFromWaitAck = DateTime.Now - waitAckTimestamp;
                            }
                            if (elapsedFromWaitAck.TotalSeconds >= commandTimeoutSeconds && communicationState != X10CommState.Ready)
                            {
                                // Resend last message
                                commandResendAttempts++;
                                DebugLog(
                                    "X10 >",
                                    "PREVIOUS COMMAND TIMED OUT, RESENDING(" + commandResendAttempts + ")"
                                );
                                x10interface.WriteData(commandLastMessage);
                                waitAckTimestamp = DateTime.Now;
                            }
                        }
                        commandResendAttempts = 0;
                        commandLastMessage = new byte[0];

                    }
                }
                else
                {

                    DebugLog("X10 <", Utility.ByteArrayToString(message));
                    x10interface.WriteData(message);

                }

            }
            catch (Exception ex)
            {
                DebugLog("X10 !", ex.Message);
                DebugLog("X10 !", ex.StackTrace);

                gotReadWriteError = true;
            }
            Thread.Sleep(50);
        }
Beispiel #4
0
        private void WriterThreadLoop()
        {
            while (true)
            {
                try
                {
                    if (sendQueue.Count > 0)
                    {

                        if (communicationState != X10CommState.Ready)
                        {
                            Monitor.Enter(stateLock);
                            //if (x10interface.GetType().Equals(typeof(CM15)))
                            //{
                            //    Monitor.Wait(stateLock, 3000);
                            //}
                            //else
                            //{
                                Monitor.Wait(stateLock, 5000);
                            //}
                            communicationState = X10CommState.Ready;
                            Monitor.Exit(stateLock);
                        }

                        byte[] msg = sendQueue.Dequeue();
                        SendMessage(msg);

                        if (msg.Length > 1)
                        {
                            if (x10interface.GetType().Equals(typeof(CM11)))
                            {
                                expectedChecksum = (byte)((msg[0] + msg[1]) & 0xff);
                                communicationState = X10CommState.WaitingChecksum;
                            }
                            else
                            {
                                communicationState = X10CommState.WaitingAck;
                            }
                        }

                    }
                    else
                    {
                        Thread.Sleep(100);
                    }
                }
                catch (Exception ex)
                {
                    DebugLog("X10 !", ex.Message);
                    DebugLog("X10 !", ex.StackTrace);

                    gotReadWriteError = true;

                    Thread.Sleep(1000);
                }
            }
        }
        private void SendMessage(byte[] message)
        {
            try
            {
                if (message.Length > 1 && IsConnected)
                {
                    // Wait for message delivery acknowledge
                    lock (waitAckMonitor)
                    {
                        // have a 500ms pause between each output message
                        while ((DateTime.Now - lastReceivedTs).TotalMilliseconds < 500)
                        {
                            Thread.Sleep(1);
                        }

                        logger.Debug(BitConverter.ToString(message));
                        if (!x10interface.WriteData(message))
                        {
                            logger.Warn("Interface I/O error");
                        }

                        commandLastMessage = message;
                        waitAckTimestamp = DateTime.Now;

                        if (x10interface.GetType().Equals(typeof(CM11)))
                        {
                            expectedChecksum = (byte)((message[0] + message[1]) & 0xff);
                            communicationState = X10CommState.WaitingChecksum;
                        }
                        else
                        {
                            communicationState = X10CommState.WaitingAck;
                        }

                        while (commandResendAttempts < commandResendMax && communicationState != X10CommState.Ready)
                        {
                            var elapsedFromWaitAck = DateTime.Now - waitAckTimestamp;
                            while (elapsedFromWaitAck.TotalSeconds < commandTimeoutSeconds && communicationState != X10CommState.Ready)
                            {
                                Thread.Sleep(1);
                                elapsedFromWaitAck = DateTime.Now - waitAckTimestamp;
                            }
                            if (elapsedFromWaitAck.TotalSeconds >= commandTimeoutSeconds && communicationState != X10CommState.Ready)
                            {
                                // Resend last message
                                commandResendAttempts++;
                                logger.Warn("Previous command timed out, resending ({0})", commandResendAttempts);
                                if (!x10interface.WriteData(commandLastMessage))
                                {
                                    logger.Warn("Interface I/O error");
                                }
                                waitAckTimestamp = DateTime.Now;
                            }
                        }
                        commandResendAttempts = 0;
                        commandLastMessage = new byte[0];
                    }
                }
                else
                {
                    logger.Debug(BitConverter.ToString(message));
                    if (!x10interface.WriteData(message))
                    {
                        logger.Warn("Interface I/O error");
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex);
                gotReadWriteError = true;
            }
        }
Beispiel #6
0
 private void SetInterfaceReady()
 {
     Monitor.Enter(stateLock);
     communicationState = X10CommState.Ready;
     Monitor.Pulse(stateLock);
     Monitor.Exit(stateLock);
 }
Beispiel #7
0
        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;
                    }
                }
            }
        }
Beispiel #8
0
        private void SendMessage(byte[] message)
        {
            try
            {
                // Wait for message delivery acknowledge
                if (message.Length > 1 && IsConnected)
                {
                    lock (waitAckMonitor)
                    {
                        while ((DateTime.Now - lastReceivedTs).TotalMilliseconds < 500)
                        {
                            Thread.Sleep(50);
                        }

                        DebugLog("X10 <", Utility.ByteArrayToString(message));
                        x10interface.WriteData(message);

                        commandLastMessage = message;
                        waitAckTimestamp   = DateTime.Now;

                        if (x10interface.GetType().Equals(typeof(CM11)))
                        {
                            expectedChecksum   = (byte)((message[0] + message[1]) & 0xff);
                            communicationState = X10CommState.WaitingChecksum;
                        }
                        else
                        {
                            communicationState = X10CommState.WaitingAck;
                        }

                        while (commandResendAttempts < commandResendMax && communicationState != X10CommState.Ready)
                        {
                            var elapsedFromWaitAck = DateTime.Now - waitAckTimestamp;
                            while (elapsedFromWaitAck.TotalSeconds < commandTimeoutSeconds && communicationState != X10CommState.Ready)
                            {
                                Thread.Sleep(50);
                                elapsedFromWaitAck = DateTime.Now - waitAckTimestamp;
                            }
                            if (elapsedFromWaitAck.TotalSeconds >= commandTimeoutSeconds && communicationState != X10CommState.Ready)
                            {
                                // Resend last message
                                commandResendAttempts++;
                                DebugLog(
                                    "X10 >",
                                    "PREVIOUS COMMAND TIMED OUT, RESENDING(" + commandResendAttempts + ")"
                                    );
                                x10interface.WriteData(commandLastMessage);
                                waitAckTimestamp = DateTime.Now;
                            }
                        }
                        commandResendAttempts = 0;
                        commandLastMessage    = new byte[0];
                    }
                }
                else
                {
                    DebugLog("X10 <", Utility.ByteArrayToString(message));
                    x10interface.WriteData(message);
                }
            }
            catch (Exception ex)
            {
                DebugLog("X10 !", ex.Message);
                DebugLog("X10 !", ex.StackTrace);

                gotReadWriteError = true;
            }
            Thread.Sleep(50);
        }
Beispiel #9
0
        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);
                    }
                }
            }
        }
Beispiel #10
0
        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);
                    }
                }
            }
        }