Browse Source

Decode of Panasonic LZ35

Thomas Chef 1 năm trước cách đây
mục cha
commit
09576c3824
7 tập tin đã thay đổi với 143 bổ sung45 xóa
  1. 2 1
      main/config.h
  2. 5 1
      main/ir_transmit.c
  3. 6 1
      main/main.c
  4. 6 4
      main/mqtt.c
  5. 28 12
      main/receiver.c
  6. 68 22
      main/toshiba_ir.c
  7. 28 4
      main/toshiba_ir.h

+ 2 - 1
main/config.h

@@ -8,12 +8,13 @@
 // These defines configures which code to generate (to save download time during development)
 //#define WIFI_ENABLED
 //#define MQTT_ENABLED
-#define ENABLE_DS18B20
+//#define ENABLE_DS18B20
 
 //#define MQTT_DEBUG              // Add an extra debug string to the topic-string
 
 #define RX_TIMER
 #define IR_RECEIVER
+//#define IR_TRANSMIT
 
 #define ONE_WIRE_BUS_IO           GPIO_NUM_32   // Temp sensors
 

+ 5 - 1
main/ir_transmit.c

@@ -8,6 +8,8 @@
 #include "toshiba_ir.h"
 #include "config.h"
 
+#ifdef IR_TRANSMIT
+
 // RMT values
 #define RMT_TX_CHANNEL RMT_CHANNEL_0
 #define RMT_TX_GPIO    GPIO_NUM_26
@@ -94,8 +96,10 @@ void initIrTransmit() {
         toshiba_rmt[i].val = (kToshibaAcBitMark << 0) | (1 << 15) | (kToshibaAcZeroSpace << 16);    // Header of IR Transmit
     }
 
-    toshibaTxQueue = xQueueCreate( 5, kToshibaNumberOfBytes );
+    toshibaTxQueue = xQueueCreate( 5, kPanasonicNumberOfBytes );
 	xTaskCreatePinnedToCore(toshibaTxTask, "toshibaTxTask", 1024*10, NULL, 2, NULL,0);
 
 	ESP_LOGI("IR_TRANSMIT","Init done.");
 }
+
+#endif

+ 6 - 1
main/main.c

@@ -44,6 +44,7 @@ void app_main(void)
     initWifi();             // Init WIFI
 #endif
 
+// MQTT Task is receiving orders for IR and is triggering a send of Transmit IR Codes
 #ifdef MQTT_ENABLED
     mqtt_init();
 #endif
@@ -53,7 +54,9 @@ void app_main(void)
 #endif
 
 vTaskDelay(1000 / portTICK_PERIOD_MS);
+#ifdef IR_TRANSMIT
 initIrTransmit();
+#endif
 
     TickType_t vLastWakeTime = xTaskGetTickCount();
 
@@ -68,10 +71,12 @@ initIrTransmit();
         vTaskDelayUntil( &vLastWakeTime, 10000 / portTICK_PERIOD_MS );
 
         // Start temp measuring task
+#ifdef ENABLE_DS18B20
         xTaskCreatePinnedToCore(readAndSendTemps, "readAndSendTemps", 1024*10, NULL, 2, NULL,1);
+#endif
 
         /*ESP_LOGI("MAIN","Send a test-IR Tx Data");
-        const uint8_t data[kToshibaNumberOfBytes] = { 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x30, 0xA3, 0x00, 0x92 };
+        const uint8_t data[kPanasonicNumberOfBytes] = { 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x30, 0xA3, 0x00, 0x92 };
         // F2 0D 03 FC 01 30 A3 00 92
         xQueueSend( toshibaTxQueue, &(data[0]), 0 );*/
 

+ 6 - 4
main/mqtt.c

@@ -74,18 +74,19 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
             break;
         case MQTT_EVENT_DATA:
             ESP_LOGI(TAG, "MQTT_EVENT_DATA Topic: <%.*s>", event->topic_len, event->topic);
+#ifdef IR_TRANSMIT
             //printf("DATA=%.*s\r\n", event->data_len, event->data);
             if( strncmp(event->topic,"hall/ac/ir_cmd_tx",event->topic_len) == 0 ) {
 
-                uint8_t data[kToshibaNumberOfBytes];
+                uint8_t data[kPanasonicNumberOfBytes];
 
-                if( event->data_len != kToshibaNumberOfBytes*2 ) {
+                if( event->data_len != kPanasonicNumberOfBytes*2 ) {
                     ESP_LOGE("MQTT","Wrong length in MQTT-data %u",event->data_len);
                     break;
                 }
                 
                 bool exitRx = false;
-                for(uint8_t i=0;i<kToshibaNumberOfBytes*2;i++) {
+                for(uint8_t i=0;i<kPanasonicNumberOfBytes*2;i++) {
                     const unsigned char c = event->data[i];
                     if( c<'0' || c>'F' || (c>'9' && c<'A') ) {
                         ESP_LOGE("MQTT","Wrong chars in MQTT-data");
@@ -96,7 +97,7 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
                 if( exitRx ) break;
                 
                 char *cp = event->data;
-                for(uint8_t i=0;i<kToshibaNumberOfBytes;i++) {
+                for(uint8_t i=0;i<kPanasonicNumberOfBytes;i++) {
                     int n = sscanf(cp, "%02X", (unsigned int*)&data[i]);
                     if( n != 1 ) {
                         ESP_LOGE("MQTT","Wrong chars (sscanf) in MQTT-data");
@@ -108,6 +109,7 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
                 ESP_LOGI("MQTT","Received a Toshiba IR Code for transmit");
 
                 xQueueSend( toshibaTxQueue, &data, 0 );
+#endif
             }
             break;
         case MQTT_EVENT_ERROR:

+ 28 - 12
main/receiver.c

@@ -29,10 +29,12 @@
 uint32_t dataArr[1000];
 uint32_t dataArrIdx = 0;
 
-
-
-
-
+uint8_t bitReverse(uint8_t b) {
+   b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
+   b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
+   b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
+   return b;
+}
 
 void receiverTask(void *pvParameter)
 {
@@ -41,27 +43,41 @@ void receiverTask(void *pvParameter)
 
     while (1) {
 
+        // Here we receive every individual pulse that has been detected by the isr-pulse-rx-function: timer_tg0_isr
         while( xQueueReceive( rxQueue, &width, 100 ) == pdTRUE ) {
 
-            //ESP_LOGI("D", "%u", width);
+            //ESP_LOGI("D", "%u", width);     // Debug to show every received pulse as a separate log line
 
             // Receive the Toshiba IR
+            // Send the pulse to the receiver that tries to interpret the pulse
             union ToshibaProtocolU* data = (union ToshibaProtocolU*)nextPulseToshiba_ir(width);
             if( data != NULL ) {
 
-                char mqtt_s[50];
-                sprintf(mqtt_s,"%02X%02X%02X%02X%02X%02X%02X%02X%02X",data->raw[0],data->raw[1],data->raw[2],data->raw[3],data->raw[4],data->raw[5],data->raw[6],data->raw[7],data->raw[8]);
-                ESP_LOGI("TOSHIBA","MQTT: %s", mqtt_s);
+                // Panasonic has LSB8 format so we need to bit-reverse each byte
+                for( uint8_t i=0; i<kPanasonicNumberOfBytes; i++ ) data->raw[i] = bitReverse(data->raw[i]);
+
+                char mqtt_s[100];
+                sprintf(mqtt_s,"A %02X%02X%02X%02X%02X%02X%02X%02X",data->raw[0],data->raw[1],data->raw[2],data->raw[3],data->raw[4],data->raw[5],data->raw[6],data->raw[7]);
+                sprintf(mqtt_s,"B %02X%02X%02X%02X%02X%02X%02X%02X",data->raw[8],data->raw[9],data->raw[10],data->raw[11],data->raw[12],data->raw[13],data->raw[14],data->raw[15]);
+                sprintf(mqtt_s,"C %02X%02X%02X",data->raw[16],data->raw[17],data->raw[18]);
+                //ESP_LOGI("TOSHIBA","MQTT: %s", mqtt_s);
 
 #ifdef MQTT_ENABLED
                 sendMQTTMessage("hall/ac/ir_cmd_rx", mqtt_s);
 #endif
 
-                ESP_LOGI("TOSHIBA", "Data: %02X %02X %02X %02X %02X %02X %02X %02X %02X",data->raw[0],data->raw[1],data->raw[2],data->raw[3],data->raw[4],data->raw[5],data->raw[6],data->raw[7],data->raw[8]);
+                ESP_LOGI("TOSHIBA", "Data A: %02X%02X%02X%02X%02X%02X%02X%02X",data->raw[0],data->raw[1],data->raw[2],data->raw[3],data->raw[4],data->raw[5],data->raw[6],data->raw[7]);
+                ESP_LOGI("TOSHIBA", "Data B: %02X%02X%02X%02X%02X%02X%02X%02X",data->raw[8],data->raw[9],data->raw[10],data->raw[11],data->raw[12],data->raw[13],data->raw[14],data->raw[15]);
+                ESP_LOGI("TOSHIBA", "Data C: %02X%02X%02X",data->raw[16],data->raw[17],data->raw[18]);
+
+                const uint8_t tempBits = data->raw[6] & 0x1F;
+                float setTemp = 16.0f + (tempBits>>1);
+                if( tempBits & 0x01 ) setTemp += 0.5f;
+                //ESP_LOGI("TOSHIBA", "Temp: %.1f", setTemp );
 
-                const uint8_t fan = (data->data.Fan > 0) ? data->data.Fan-1 : data->data.Fan;
-                const uint8_t power = (data->data.Mode == 3) ? 1 : 0;
-                ESP_LOGI("TOSHIBA","Mode:%u Temp:%u Fan:%u",power,data->data.Temp+17u,fan);
+                const uint8_t fan = data->raw[8]>>4;
+                const uint8_t power = data->raw[5]&0x01;
+                ESP_LOGI("TOSHIBA","Power:%u Temp:%.1f Fan:%u",power,setTemp,fan);
 
 #ifdef WIFI_ENABLED
                 //sendUDPMessage(dataStr, true);

+ 68 - 22
main/toshiba_ir.c

@@ -31,10 +31,37 @@ uint8_t xorBytes(const uint8_t * const start, const uint16_t length);
  * 
  */
 
+/*****
+ * Panasonic decode 19 bytes
+ *
+ *         1 2 3 4 5 6 7 8  9 0 1 2 3 4 5 6  7 8 9 
+ * 30 deg 4004072000123C61 C560007007000091 000054   0011 1100  - 11100 1C 28
+ * 24 deg 4004072000120C61 C560007007000091 000078   0000 1100  - 10000 10 16
+ * 23 deg 4004072000127461 C560007007000091 000038   0111 0100  - 01110  E 14
+ * 22 deg 4004072000123461 C560007007000091 000058   0011 0100  - 01100  C 12
+ * 21.5   400407200012D461 C560007007000091 000098   1101 0100  - 01011  B 11
+ * 21 deg 4004072000125461 C560007007000091 000018   0101 0100  - 01010  A 10
+ * 16 deg 4004072000120461 C560007007000091 000070   0000 0100  - 00000  0 00
+ *        0220E00400482086 A306000EE0000089 00000E   0010 0010 17 grader
+ * 
+ * 
+ * Fan in byte ([8] >> 4)
+ * 10 = Auto
+ *  3 = F1
+ *  4 = F2
+ *  5 = F3
+ *  6 = F4
+ *  7 = F5
+ * 
+ * Power in data->raw[5]&0x01
+ * 0 = OFF
+ * 1 = ON
+*/
 
 
-uint8_t data[kToshibaNumberOfBytes];            // Temp data during rx
-uint8_t dataTransfer[kToshibaNumberOfBytes];    // Send as pointer to receiver
+
+uint8_t data[kPanasonicNumberOfBytes];            // Temp data during rx
+uint8_t dataTransfer[kPanasonicNumberOfBytes];    // Send as pointer to receiver
 
 enum
 {
@@ -55,7 +82,7 @@ void Toshiba_ir_ResetDecoder()
     //ESP_LOGI("T", "Reset decoder");
     rx_numBits = 0;
     rx_state = UNKNOWN;
-    memset(data,0,kToshibaNumberOfBytes);
+    memset(data,0,kPanasonicNumberOfBytes);
 }
 
 static void addBit(uint8_t value)
@@ -73,52 +100,61 @@ static void addBit(uint8_t value)
     rx_numBits++;
 }
 
-#define START_PULSE_MIN (kToshibaAcHdrMark-200)
-#define START_PULSE_MAX (kToshibaAcHdrMark+200)
+#define HDR_MARK_MIN (kPanasonicAcHdrMark-200)
+#define HDR_MARK_MAX (kPanasonicAcHdrMark+200)
+
+#define HDR_SPACE_MIN (kPanasonicAcHdrSpace-200)
+#define HDR_SPACE_MAX (kPanasonicAcHdrSpace+200)
 
-#define T0_PULSE_MIN (kToshibaAcBitMark-100)
-#define T0_PULSE_MAX (kToshibaAcBitMark+100)
+#define T0_PULSE_MIN (kPanasonicAcBitMark-100)
+#define T0_PULSE_MAX (kPanasonicAcBitMark+100)
 
-#define SHORT_PULSE_MIN (kToshibaAcZeroSpace-100)
-#define SHORT_PULSE_MAX (kToshibaAcZeroSpace+100)
+#define SHORT_PULSE_MIN (kPanasonicAcZeroSpace-100)
+#define SHORT_PULSE_MAX (kPanasonicAcZeroSpace+100)
 
-#define LONG_PULSE_MIN (kToshibaAcOneSpace-100)
-#define LONG_PULSE_MAX (kToshibaAcOneSpace+100)
+#define LONG_PULSE_MIN (kPanasonicAcOneSpace-100)
+#define LONG_PULSE_MAX (kPanasonicAcOneSpace+100)
 
+#define GAP_PULSE_MIN (kPanasonicAcUsualGap-200)
+#define GAP_PULSE_MAX (kPanasonicAcUsualGap+200)
 
+
+// Pulse decoder
 static int32_t rx_decode(uint32_t width)
 {
     switch (rx_state) {
         case UNKNOWN: // Start of frame A
-            if ( START_PULSE_MIN <= width && width <= START_PULSE_MAX )
+            if ( HDR_MARK_MIN <= width && width <= HDR_MARK_MAX )
             {
                 rx_state = STARTER;
-                //ESP_LOGI("T", "->STARTER");
+                ESP_LOGI("T", "STARTER A");
             }
             else
             {
+                ESP_LOGI("T", "Err STARTER A");
                 return -1; // error, reset
             }
             break;
         
         case STARTER: // Start of frame B
-            if ( START_PULSE_MIN <= width && width <= START_PULSE_MAX )
+            if ( HDR_SPACE_MIN <= width && width <= HDR_SPACE_MAX )
             {
                 rx_state = T0;
-                //ESP_LOGI("T", "STARTER");
+                ESP_LOGI("T", "STARTER B");
             }
             else
             {
+                ESP_LOGI("T", "Err STARTER B");
                 return -1; // error, reset
             }
             break;
 
 
-        case T0: // First half of pulse : HIGH around 230us
+        case T0: // First half of pulse
 
-            if(rx_numBits == kToshibaNumberOfBits)
+            if(rx_numBits == kPanasonicNumberOfBits)
             { // end of frame
-                //ESP_LOGI("T", "END OF FRAME");
+                ESP_LOGI("T", "END OF FRAME");
                 rx_state = DONE;
                 return 1;
             }
@@ -129,6 +165,7 @@ static int32_t rx_decode(uint32_t width)
             }
             else
             {
+                ESP_LOGI("T", "Err T0");
                 return -1; // error, reset
             }
             break;
@@ -144,8 +181,16 @@ static int32_t rx_decode(uint32_t width)
                 addBit(1);
                 //ESP_LOGI("T", "Long %u", rx_numBits);
             }
+            else if( GAP_PULSE_MIN <= width && width <= GAP_PULSE_MAX )
+            {
+                ESP_LOGI("T", "GAP-Pulse. Restart");
+                rx_numBits = 0;
+                rx_state = UNKNOWN;
+                break;
+            }
             else
             {
+                ESP_LOGI("T", "Err T1");
                 return -1; // error, reset
             }
             rx_state = T0;
@@ -164,6 +209,7 @@ uint8_t* nextPulseToshiba_ir(uint32_t width)
     {
         if (rx_state != DONE)
         {
+            // Send the pulse to the decoder
             switch (rx_decode(width))
             {
             case -1:
@@ -172,15 +218,15 @@ uint8_t* nextPulseToshiba_ir(uint32_t width)
             case 1:
                 rx_state = DONE;
                 // Check checksum
-                if( xorBytes(data,8) == data[8] ) {
-                    memcpy(dataTransfer,data,kToshibaNumberOfBytes);
+                //if( xorBytes(data,8) == data[8] ) {
+                    memcpy(dataTransfer,data,kPanasonicNumberOfBytes);
                     Toshiba_ir_ResetDecoder();
                     retVal = dataTransfer;
-                }
+                /*}
                 else {
                     ESP_LOGE("TOSHIBA", "WRONG CHKSUM");
                     Toshiba_ir_ResetDecoder();
-                }
+                }*/
                 break;
             }
         }

+ 28 - 4
main/toshiba_ir.h

@@ -4,20 +4,44 @@
 #include <stdbool.h>
 #include <stdint.h>
 
-// Toshiba A/C
+// Toshiba A/C 
+/*
 #define kToshibaAcHdrMark ((uint32_t)4420)
 #define kToshibaAcHdrSpace ((uint32_t)4450)
 #define kToshibaAcBitMark ((uint32_t)570)
 #define kToshibaAcOneSpace ((uint32_t)1600)
 #define kToshibaAcZeroSpace ((uint32_t)510)
 #define kToshibaAcUsualGap ((uint32_t)7960)
+*/
+
+/*
+Between two Panasonic IR Resends:
+I (8094) D: 410
+I (8094) D: 460
+I (8094) D: 9900
+I (8104) D: 3580
+I (8104) D: 1630
+I (8104) D: 500
+I (8104) D: 410
+I (8114) D: 460*/
+
+// Panasonic LZ35 A/C
+#define kPanasonicAcHdrMark ((uint32_t)3456)
+#define kPanasonicAcHdrSpace ((uint32_t)1728)
+#define kPanasonicAcBitMark ((uint32_t)432)
+#define kPanasonicAcOneSpace ((uint32_t)1296)
+#define kPanasonicAcZeroSpace ((uint32_t)432)
+#define kPanasonicAcUsualGap ((uint32_t)9940)
+
+#define kPanasonicNumberOfBits 152
+#define kPanasonicNumberOfBytes (kPanasonicNumberOfBits/8)  // 19 Bytes
 
 void Toshiba_ir_ResetDecoder ();
 
 uint8_t* nextPulseToshiba_ir(uint32_t width);
 
-#define kToshibaNumberOfBits 72
-#define kToshibaNumberOfBytes (kToshibaNumberOfBits/8)
+//#define kToshibaNumberOfBits 72
+//#define kToshibaNumberOfBytes (kToshibaNumberOfBits/8)
 
 struct toshibaDataBits {
     // Byte[0] - 0xF2
@@ -58,7 +82,7 @@ struct toshibaDataBits {
 
 
 union ToshibaProtocolU {
-  uint8_t raw[kToshibaNumberOfBytes];  ///< The state in code form.
+  uint8_t raw[kPanasonicNumberOfBytes];  ///< The state in code form.
   struct toshibaDataBits data;
 };