X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=aircon%2Ffirmware%2Fmain.c;h=da9df476d2e6403e1fc47cf0d726e2e5f47285d1;hb=bb37203461a4380e32be26594a74b77727dda97d;hp=556ec89440533c052af0d7a8f239ec26e036fcc3;hpb=d44f6eb429d864273ba050ee4c1c32c30dfb05a6;p=home-hw.git diff --git a/aircon/firmware/main.c b/aircon/firmware/main.c index 556ec89..da9df47 100644 --- a/aircon/firmware/main.c +++ b/aircon/firmware/main.c @@ -7,6 +7,7 @@ #include "util.h" #include "ds18b20.h" #include "modbus.h" +#include "registers.h" #include #include @@ -17,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(); @@ -43,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); @@ -96,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); @@ -153,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); @@ -169,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') { @@ -214,40 +227,147 @@ 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; } -/*** Modbus callbacks ***/ - -enum aircon_coils { - AIRCON_COIL_EXCHANGER_BYPASS, - AIRCON_COIL_MAX, +/*** 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 }; -enum aircon_input_registers { - AIRCON_IREG_TEMP_FROM_INSIDE, - AIRCON_IREG_TEMP_TO_INSIDE, - AIRCON_IREG_TEMP_FROM_OUTSIDE, - AIRCON_IREG_TEMP_TO_OUTSIDE, - AIRCON_IREG_TEMP_MIXED, - AIRCON_IREG_MAX, - AIRCON_IREG_DS_ID_BASE = 0x1000, - AIRCON_IREG_DS_ID_MAX = AIRCON_IREG_DS_ID_BASE + 4*DS_NUM_SENSORS, +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*$", }; -enum aircon_holding_registers { - AIRCON_HREG_EXCHANGER_FAN, - AIRCON_HREG_REMOTE_CONTROL, - AIRCON_HREG_MAX, -}; +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) { @@ -292,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_MAX && 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] = { @@ -309,17 +431,17 @@ u16 modbus_get_input_register(u16 addr) { if (addr <= AIRCON_IREG_TEMP_MIXED) { byte i = 0; - while (i < DS_NUM_SENSORS && memcmp(ds_sensors[i].address, temp_sensor_addrs[addr], 8)) + while (i < DS_NUM_SENSORS && memcmp(ds_sensors[i].address + 1, temp_sensor_addrs[addr], 6)) i++; if (i >= DS_NUM_SENSORS) return 0x8000; if (ds_sensors[i].current_temp == DS_TEMP_UNKNOWN) return 0x8000; - return ds_sensors[i].current_temp & 0xffff; + return ((ds_sensors[i].current_temp + 5) / 10) & 0xffff; } else if (addr >= AIRCON_IREG_DS_ID_BASE && addr < AIRCON_IREG_DS_ID_MAX) { - byte i = (addr - AIRCON_IREG_DS_ID_BASE) / 4; - byte j = (addr - AIRCON_IREG_DS_ID_BASE) % 4; - return get_u16_be(ds_sensors[i].address + 2*j); + byte i = (addr - AIRCON_IREG_DS_ID_BASE) / 3; + byte j = (addr - AIRCON_IREG_DS_ID_BASE) % 3; + return get_u16_be(ds_sensors[i].address + 2*j + 1); } else { return 0; } @@ -336,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; } @@ -349,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: ;