X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=aircon%2Ffirmware%2Fmain.c;h=da9df476d2e6403e1fc47cf0d726e2e5f47285d1;hb=bb37203461a4380e32be26594a74b77727dda97d;hp=824ee7a999c7805c3b330eea8a6742b9c3326177;hpb=0fab2dc8a2fc98b2829ae8ce2b66fc5cc4aab88a;p=home-hw.git diff --git a/aircon/firmware/main.c b/aircon/firmware/main.c index 824ee7a..da9df47 100644 --- a/aircon/firmware/main.c +++ b/aircon/firmware/main.c @@ -18,7 +18,10 @@ #include -static void clock_setup(void) +static void rc_init(void); +static bool rc_send(char key); + +static void clock_init(void) { rcc_clock_setup_in_hse_8mhz_out_72mhz(); @@ -44,7 +47,7 @@ static void clock_setup(void) rcc_periph_reset_pulse(RST_TIM4); } -static void gpio_setup(void) +static void gpio_init(void) { // Switch JTAG off to free up pins gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON, 0); @@ -97,21 +100,23 @@ void sys_tick_handler(void) ms_ticks++; } -static void tick_setup(void) +static void tick_init(void) { systick_set_frequency(1000, 72000000); systick_counter_enable(); systick_interrupt_enable(); } +#if 0 static void delay_ms(uint ms) { u32 start_ticks = ms_ticks; while (ms_ticks - start_ticks < ms) ; } +#endif -static void usart_setup(void) +static void usart_init(void) { usart_set_baudrate(USART1, 115200); usart_set_databits(USART1, 8); @@ -154,7 +159,6 @@ static void pwm_init(void) // 50% PWM for the IR LED timer_set_oc_mode(TIM4, TIM_OC2, TIM_OCM_FORCE_HIGH); // will be TIM_OCM_PWM1 when transmitting - // timer_set_oc_mode(TIM4, TIM_OC2, TIM_OCM_PWM1); // FIXME timer_set_oc_value(TIM4, TIM_OC2, T4_CYCLE / 2); timer_set_oc_polarity_high(TIM4, TIM_OC2); timer_enable_oc_output(TIM4, TIM_OC2); @@ -170,23 +174,31 @@ static void pwm_init(void) int main(void) { - clock_setup(); - gpio_setup(); - tick_setup(); - usart_setup(); + clock_init(); + gpio_init(); + tick_init(); + usart_init(); pwm_init(); + rc_init(); - debug_puts("Hello, world!\n"); + debug_puts("Hello, world! This is Aircon Controller speaking.\n"); ds_init(); modbus_init(); - byte cycles = 0; + u32 last_show_temp = 0; + u32 last_ds_step = 0; + for (;;) { - debug_led_toggle(); - delay_ms(100); - ds_step(); + if (ms_ticks - last_ds_step >= 100) { + debug_led_toggle(); + ds_step(); + last_ds_step = ms_ticks; + } + modbus_loop(); + +#if 0 if (usart_get_flag(USART1, USART_SR_RXNE)) { uint ch = usart_recv(USART1); if (ch == 'B') { @@ -215,17 +227,146 @@ int main(void) * % = pwm*4.389 - 12.723 */ timer_set_oc_value(TIM4, TIM_OC1, T4_CYCLE * fan_pwm / 256); + } else { + rc_send(ch); } } - if (cycles++ >= 50) { - cycles = 0; +#endif + + if (ms_ticks - last_show_temp >= 5000) { show_temperature(); + last_show_temp = ms_ticks; } + + wait_for_interrupt(); } return 0; } +/*** Infra-red remote control transmitter ***/ + +enum rc_keys { + RC_AUTO, + RC_TEMP_UP, + RC_FUNC, + RC_HI, + RC_TIMER, + RC_MID, + RC_TEMP_DOWN, + RC_SLEEP, + RC_LOW, + RC_POWER, + RC_MAX +}; + +static const char * const rc_patterns[RC_MAX] = { + [RC_AUTO] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*A*B*B*A*B*A*A*B*B*A*A*B*A*B*B*A*$", + [RC_TEMP_UP] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*A*A*B*A*B*A*A*B*B*B*A*B*A*B*B*A*$", + [RC_FUNC] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*B*A*B*B*B*A*A*B*A*B*A*A*A*B*B*A*$", + [RC_HI] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*B*A*A*B*B*A*A*B*A*B*B*A*A*B*B*A*$", + [RC_TIMER] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*A*B*B*B*B*A*A*B*B*A*A*A*A*B*B*A*$", + [RC_MID] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*B*B*A*B*B*A*A*B*A*A*B*A*A*B*B*A*$", + [RC_TEMP_DOWN] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*B*A*B*A*B*A*A*B*A*B*A*B*A*B*B*A*$", + [RC_SLEEP] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*B*B*B*B*B*A*A*B*A*A*A*A*A*B*B*A*$", + [RC_LOW] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*A*B*A*B*B*A*A*B*B*A*B*A*A*B*B*A*$", + [RC_POWER] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*A*A*B*B*B*A*A*B*B*B*A*A*A*B*B*A*$", +}; + +static const char rc_keys[] = "aufhtmdslp"; + +static void rc_init(void) +{ + // TIM1 runs at 1 MHz and it is used for timing of RC pulses + timer_set_prescaler(TIM1, CPU_CLOCK_MHZ - 1); + timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); + timer_update_on_overflow(TIM1); + timer_disable_preload(TIM1); + timer_one_shot_mode(TIM1); + timer_enable_irq(TIM1, TIM_DIER_UIE); + nvic_enable_irq(NVIC_TIM1_UP_IRQ); +} + +static volatile const char *rc_pattern_pos; +static volatile char rc_pending; + +void tim1_up_isr(void) +{ + if (TIM_SR(TIM1) & TIM_SR_UIF) { + TIM_SR(TIM1) &= ~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 '^': + val = 1; + duration = 9032; + break; + case '#': + val = 0; + duration = 4457; + break; + case '*': + val = 1; + duration = 619; + break; + case 'A': + val = 0; + duration = 514; + break; + case 'B': + val = 0; + duration = 1617; + break; + case '$': + val = 0; + duration = 10000; + break; + default: + // End of transmission + gpio_set(GPIOC, GPIO13); + rc_pattern_pos = NULL; + rc_pending = 0; + return; + } + + if (val) + timer_set_oc_mode(TIM4, TIM_OC2, TIM_OCM_PWM1); + else + timer_set_oc_mode(TIM4, TIM_OC2, TIM_OCM_FORCE_HIGH); + + timer_set_period(TIM1, duration - 1); + timer_generate_event(TIM1, TIM_EGR_UG); + timer_enable_counter(TIM1); + } +} + +static bool rc_send(char key) +{ + 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); + + gpio_clear(GPIOC, GPIO13); + + timer_set_period(TIM1, 1); + timer_generate_event(TIM1, TIM_EGR_UG); + timer_enable_counter(TIM1); + return true; +} + /*** Modbus callbacks ***/ bool modbus_check_discrete_input(u16 addr UNUSED) @@ -271,9 +412,11 @@ void modbus_set_coil(u16 addr, bool value) } } +#define AIRCON_IREG_DS_ID_MAX (AIRCON_IREG_DS_ID_BASE + 3*DS_NUM_SENSORS) + bool modbus_check_input_register(u16 addr) { - return (addr < AIRCON_IREG_MAX || addr >= AIRCON_IREG_DS_ID_BASE && addr < AIRCON_IREG_DS_ID_MAX); + return (addr < AIRCON_IREG_MAX || addr >= AIRCON_IREG_DS_ID_BASE && addr < AIRCON_IREG_DS_ID_BASE); } static const byte temp_sensor_addrs[][8] = { @@ -315,6 +458,7 @@ u16 modbus_get_holding_register(u16 addr) case AIRCON_HREG_EXCHANGER_FAN: return fan_pwm; case AIRCON_HREG_REMOTE_CONTROL: + return rc_pending; default: return 0; } @@ -328,6 +472,8 @@ void modbus_set_holding_register(u16 addr, u16 value) timer_set_oc_value(TIM4, TIM_OC1, T4_CYCLE * fan_pwm / 256); break; case AIRCON_HREG_REMOTE_CONTROL: + if (!rc_send(value)) + modbus_slave_error(); break; default: ;