]> mj.ucw.cz Git - home-hw.git/commitdiff
test-sinclair: Rewritten RC code
authorMartin Mares <mj@ucw.cz>
Fri, 14 Jul 2023 15:00:57 +0000 (17:00 +0200)
committerMartin Mares <mj@ucw.cz>
Fri, 14 Jul 2023 15:00:57 +0000 (17:00 +0200)
test-sinclair/main.c

index 29ddb6ad7ef03b12db536444b9233e16ab001302..7cfe1b427507c088a3400adc54b38175196b4f92 100644 (file)
@@ -64,7 +64,7 @@ static void gpio_init(void)
 
        // PA8 = IR remote control
        gpio_clear(GPIOA, GPIO8);
-       gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO8);
+       gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO8);
 }
 
 static void usart_init(void)
@@ -302,60 +302,77 @@ static void tm_show(void)
 
 /*** Infra-red remote control simulator ***/
 
-enum rc_keys {
-       RC_POWER_OFF,
-       RC_POWER_ON,
-       RC_HIGH,
-       RC_MED,
-       RC_LO,
-       RC_SLEEP,
-       RC_DRY,
-       RC_WARM,
-       RC_COLD,
-       RC_T17,
-       RC_T18,
-       RC_T19,
-       RC_T20,
-       RC_T21,
-       RC_T22,
-       RC_T23,
-       RC_T24,
-       RC_T25,
-       RC_T26,
-       RC_T27,
-       RC_T28,
-       RC_T29,
-       RC_T30,
-       RC_MAX
+#define RC_POWER_OFF_HI                0b00000000000000000000
+#define RC_POWER_OFF_LO                0b00000000000000010000000010100100
+
+#define RC_DEFAULT_HI          0b00000011000000000000
+
+// Various temperatures
+#define RC_17_COOL_AUTO                0b00000000000000010000000000101001
+#define RC_18_COOL_AUTO                0b00000000000000010000000000111000
+#define RC_19_COOL_AUTO                0b00000000000000010000000001000111
+#define RC_20_COOL_AUTO                0b00000000000000010000000001010110
+#define RC_21_COOL_AUTO                0b00000000000000010000000001100101
+#define RC_22_COOL_AUTO                0b00000000000000010000000001110100
+#define RC_23_COOL_AUTO                0b00000000000000010000000010000011
+#define RC_24_COOL_AUTO                0b00000000000000010000000010010010
+#define RC_25_COOL_AUTO                0b00000000000000010000000010100001
+#define RC_26_COOL_AUTO                0b00000000000000010000000010110000
+#define RC_27_COOL_AUTO                0b00000000000000010000000011001111
+#define RC_28_COOL_AUTO                0b00000000000000010000000011011110
+#define RC_29_COOL_AUTO                0b00000000000000010000000011101101
+#define RC_30_COOL_AUTO                0b00000000000000010000000011111100
+
+// Various fan settings
+#define RC_17_COOL_HI          0b00000000000000010000100000100001
+#define RC_17_COOL_MED         0b00000000000000010001000100100111
+#define RC_17_COOL_LO          0b00000000000000010010001000100101
+
+// Stand-alone, no temperature nor fan setting
+#define RC_DEHUMIDIFY          0b00000000000000010010010000100011
+
+// Combines with a temperature setting, but no fan setting
+#define RC_17_WARM             0b00000000000000010000001100100110
+
+// All modes have a sleep variant, which we do not use yet
+#define RC_17_COOL_AUTO_SLEEP  0b00000000000010010000000000100001
+
+static const u32 rc_fan_settings[4] = {
+       0,
+       RC_17_COOL_LO ^ RC_17_COOL_AUTO,
+       RC_17_COOL_MED ^ RC_17_COOL_AUTO,
+       RC_17_COOL_HI ^ RC_17_COOL_AUTO,
 };
 
-static const char * const rc_patterns[RC_MAX] = {
-       [RC_POWER_OFF]  = "*#*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*A*B*A*A*B*A*A*#*$",
-       [RC_POWER_ON]   = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*A*B*A*A*A*A*B*#*$",
-       [RC_HIGH]       = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*B*A*A*A*B*A*B*A*B*A*A*B*#*$",
-       [RC_MED]        = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*B*A*A*A*B*B*A*B*A*B*B*B*B*#*$",
-       [RC_LO]         = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*B*A*A*A*B*A*B*A*B*A*B*B*A*B*#*$",
-       [RC_SLEEP]      = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*B*A*A*B*A*A*A*B*A*B*A*B*A*A*B*A*B*#*$",
-       [RC_DRY]        = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*B*A*A*B*A*A*B*A*B*A*B*A*B*B*#*$",
-       [RC_WARM]       = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*B*B*B*A*B*A*B*B*B*A*#*$",
-       [RC_COLD]       = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*A*B*A*A*A*A*B*#*$",
-       [RC_T17]        = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*A*A*B*A*B*A*A*B*#*$",
-       [RC_T18]        = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*A*A*B*B*B*A*A*A*#*$",
-       [RC_T19]        = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*A*B*A*A*A*B*B*B*#*$",
-       [RC_T20]        = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*A*B*A*B*A*B*B*A*#*$",
-       [RC_T21]        = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*A*B*B*A*A*B*A*B*#*$",
-       [RC_T22]        = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*A*B*B*B*A*B*A*A*#*$",
-       [RC_T23]        = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*A*A*A*A*A*B*B*#*$",
-       [RC_T24]        = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*A*A*B*A*A*B*A*#*$",
-       [RC_T25]        = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*A*B*A*A*A*A*B*#*$",
-       [RC_T26]        = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*A*B*B*A*A*A*A*#*$",
-       [RC_T27]        = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*B*A*A*B*B*B*B*#*$",
-       [RC_T28]        = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*B*A*B*B*B*B*A*#*$",
-       [RC_T29]        = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*B*B*A*B*B*A*B*#*$",
-       [RC_T30]        = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*B*B*B*B*B*A*A*#*$",
+static const u32 rc_temp_settings[14] = {
+#define X(t) RC_##t##_COOL_AUTO ^ RC_17_COOL_AUTO
+       X(17),
+       X(18),
+       X(19),
+       X(20),
+       X(21),
+       X(22),
+       X(23),
+       X(24),
+       X(25),
+       X(26),
+       X(27),
+       X(28),
+       X(29),
+       X(30),
+#undef X
 };
 
-static const char rc_keys[] = "Oohmlsdwc7890123456&*()";
+enum rc_mode {
+       MODE_OFF,
+       MODE_COOL,
+       MODE_WARM,
+       MODE_DEHUMIDIFY,
+};
+
+static byte rc_mode;           // MODE_xxx
+static byte rc_fan;            // 0-3
+static byte rc_temp;           // 17-30
 
 static void rc_init(void)
 {
@@ -369,46 +386,76 @@ static void rc_init(void)
        nvic_enable_irq(NVIC_TIM4_IRQ);
 }
 
-static volatile const char *rc_pattern_pos;
-static volatile char rc_pending;
+static u32 rc_pattern[2];
+static uint rc_tick;
+
+static void rc_encode(void)
+{
+       if (rc_mode == MODE_OFF) {
+               rc_pattern[0] = RC_POWER_OFF_HI;
+               rc_pattern[1] = RC_POWER_OFF_LO;
+               return;
+       }
+
+       rc_pattern[0] = RC_DEFAULT_HI;
+       uint t = rc_temp, f = rc_fan;
+
+       if (rc_mode == MODE_COOL) {
+               rc_pattern[1] = RC_17_COOL_AUTO;
+       } else if (rc_mode == MODE_WARM) {
+               rc_pattern[1] = RC_17_WARM;
+               f = 0;
+       } else {
+               rc_pattern[1] = RC_DEHUMIDIFY;
+               f = t = 0;
+       }
+
+       rc_pattern[1] ^= rc_fan_settings[f];
+
+       if (t >= 17 && t < 17 + ARRAY_SIZE(rc_temp_settings))
+               rc_pattern[1] ^= rc_temp_settings[t - 17];
+}
 
 void tim4_isr(void)
 {
        if (TIM_SR(TIM4) & TIM_SR_UIF) {
                TIM_SR(TIM4) &= ~TIM_SR_UIF;
 
-               if (!rc_pattern_pos)    // Just to be sure
-                       return;
-
                bool val;       // 1=pulse, 0=break
                uint duration;  // in μs
 
-               switch (*rc_pattern_pos++) {
-                       case '#':
+               switch (rc_tick++) {
+                       case 0:
+                               // Better be safe
+                               return;
+                       case 2:
+                       case 108:
+                               // Initial / final marker
                                val = 0;
                                duration = 3600;
                                break;
-                       case '*':
-                               val = 1;
-                               duration = 565;
-                               break;
-                       case 'A':
-                               val = 0;
-                               duration = 480;
-                               break;
-                       case 'B':
-                               val = 0;
-                               duration = 1471;
-                               break;
-                       case '$':
+                       case 110:
+                               // Inter-packet gap
                                val = 0;
                                duration = 10000;
                                break;
-                       default:
-                               // End of transmission
-                               rc_pattern_pos = NULL;
-                               rc_pending = 0;
+                       case 111:
+                               // End of message
+                               rc_tick = 0;
                                return;
+                       default:
+                               if (rc_tick % 2) {
+                                       val = 1;
+                                       duration = 565;
+                               } else {
+                                       // Even ticks 4 to 106 transmit 52 bits of data
+                                       uint i = 12 + (rc_tick - 4) / 2;
+                                       val = 0;
+                                       if (rc_pattern[i>>5] & (1 << (i & 31)))
+                                               duration = 1471;
+                                       else
+                                               duration = 480;
+                               }
                }
 
                if (val)
@@ -422,24 +469,80 @@ void tim4_isr(void)
        }
 }
 
-static bool rc_send(char key)
+static void rc_send(void)
 {
-       if (rc_pending)
-               return false;
-       if (!key)
-               return false;
-
-       const char *s = strchr(rc_keys, key);
-       if (!s)
-               return false;
-       rc_pending = key;
-       rc_pattern_pos = rc_patterns[s - rc_keys];
-       debug_printf("RC sending: %c\n", key);
+       if (rc_tick)
+               return;
+
+       rc_encode();
+       debug_printf("RC sending: %05x %08x\n", (uint) rc_pattern[0], (uint) rc_pattern[1]);
+       rc_tick = 1;
 
        timer_set_period(TIM4, 1);
        timer_generate_event(TIM4, TIM_EGR_UG);
        timer_enable_counter(TIM4);
-       return true;
+}
+
+static bool rc_key(char key)
+{
+       if (key == 'o') {
+               rc_mode = MODE_OFF;
+               rc_send();
+               return true;
+       } else if (key == 'c') {
+               rc_mode = MODE_COOL;
+               rc_send();
+               return true;
+       } else if (key == 'w') {
+               rc_mode = MODE_WARM;
+               rc_send();
+               return true;
+       } else if (key == 'd') {
+               rc_mode = MODE_DEHUMIDIFY;
+               rc_send();
+               return true;
+       } else if (key == 'a') {
+               rc_fan = 0;
+               rc_send();
+               return true;
+       } else if (key == 'l') {
+               rc_fan = 1;
+               rc_send();
+               return true;
+       } else if (key == 'm') {
+               rc_fan = 2;
+               rc_send();
+               return true;
+       } else if (key == 'h') {
+               rc_fan = 3;
+               rc_send();
+               return true;
+       } else if (key >= '7' && key <= '9') {
+               rc_temp = key - '0' + 10;
+               rc_send();
+               return true;
+       } else if (key >= '0' && key <= '6') {
+               rc_temp = key - '0' + 20;
+               rc_send();
+               return true;
+       } else if (key == '&') {
+               rc_temp = 27;
+               rc_send();
+               return true;
+       } else if (key == '*') {
+               rc_temp = 28;
+               rc_send();
+               return true;
+       } else if (key == '(') {
+               rc_temp = 29;
+               rc_send();
+               return true;
+       } else if (key == ')') {
+               rc_temp = 30;
+               rc_send();
+               return true;
+       }
+       return false;
 }
 
 /*** USB ***/
@@ -658,7 +761,17 @@ int main(void)
 
                if (usart_get_flag(USART1, USART_SR_RXNE)) {
                        uint ch = usart_recv(USART1);
-                       debug_putc(ch);
+#if 0
+                       if (ch == '1')
+                               gpio_set(GPIOA, GPIO8);
+                       else if (ch == '0')
+                               gpio_clear(GPIOA, GPIO8);
+#else
+                       if (rc_key(ch))
+                               ;
+#endif
+                       else
+                               debug_putc(ch);
                }
 
                if (usb_event_pending) {