From 990f16e892019ee4f0d335bb8a4b988c08977916 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Tue, 16 Jul 2019 18:27:38 +0200 Subject: [PATCH] Aircon: MODBUS commands --- aircon/main.c | 136 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 101 insertions(+), 35 deletions(-) diff --git a/aircon/main.c b/aircon/main.c index 12d2345..556ec89 100644 --- a/aircon/main.c +++ b/aircon/main.c @@ -15,6 +15,8 @@ #include #include +#include + static void clock_setup(void) { rcc_clock_setup_in_hse_8mhz_out_72mhz(); @@ -123,9 +125,8 @@ static void usart_setup(void) // TIM4 will run on CPU clock, it will overflow with frequency 38 kHz (IR modulation frequency) #define T4_CYCLE ((CPU_CLOCK_MHZ * 1000000 + 37999) / 38000) -// FIXME static byte bypass_active; -static byte pwm; +static byte fan_pwm; static void show_temperature(void) { @@ -139,7 +140,7 @@ static void show_temperature(void) debug_printf("%3d.%03d", t / 1000, t % 1000); } debug_printf(" %d", bypass_active); - debug_printf(" %d", pwm); + debug_printf(" %d", fan_pwm); debug_puts("\r\n"); } @@ -179,26 +180,12 @@ int main(void) ds_init(); modbus_init(); -#if 0 - for (;;) { - debug_led_toggle(); - - //gpio_clear(GPIOB, GPIO0); - //delay_ms(50); - //gpio_set(GPIOB, GPIO0); - delay_ms(100); - - modbus_loop(); - ds_step(); - } -#endif - -#if 1 byte cycles = 0; for (;;) { debug_led_toggle(); delay_ms(100); ds_step(); + modbus_loop(); if (usart_get_flag(USART1, USART_SR_RXNE)) { uint ch = usart_recv(USART1); if (ch == 'B') { @@ -210,7 +197,7 @@ int main(void) gpio_clear(GPIOC, GPIO15); // opto-coupler gpio_set(GPIOB, GPIO0); // LED } else if (ch >= '0' && ch <= '9') { - pwm = 3*(ch - '0') + 1; + fan_pwm = 3*(ch - '0') + 1; /* * ch pwm % * 0 1 0 @@ -226,7 +213,7 @@ int main(void) * * % = pwm*4.389 - 12.723 */ - timer_set_oc_value(TIM4, TIM_OC1, T4_CYCLE * pwm / 256); + timer_set_oc_value(TIM4, TIM_OC1, T4_CYCLE * fan_pwm / 256); } } if (cycles++ >= 50) { @@ -234,13 +221,34 @@ int main(void) show_temperature(); } } -#endif return 0; } /*** Modbus callbacks ***/ +enum aircon_coils { + AIRCON_COIL_EXCHANGER_BYPASS, + AIRCON_COIL_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, +}; + +enum aircon_holding_registers { + AIRCON_HREG_EXCHANGER_FAN, + AIRCON_HREG_REMOTE_CONTROL, + AIRCON_HREG_MAX, +}; + bool modbus_check_discrete_input(u16 addr UNUSED) { return false; @@ -251,42 +259,100 @@ bool modbus_get_discrete_input(u16 addr UNUSED) return false; } -bool modbus_check_coil(u16 addr UNUSED) +bool modbus_check_coil(u16 addr) { - return false; + return addr < AIRCON_COIL_MAX; } -bool modbus_get_coil(u16 addr UNUSED) +bool modbus_get_coil(u16 addr) { - return false; + switch (addr) { + case AIRCON_COIL_EXCHANGER_BYPASS: + return bypass_active; + default: + return false; + } } -void modbus_set_coil(u16 addr UNUSED, bool value UNUSED) +void modbus_set_coil(u16 addr, bool value) { + switch (addr) { + case AIRCON_COIL_EXCHANGER_BYPASS: + bypass_active = value; + if (bypass_active) { + gpio_set(GPIOC, GPIO15); // opto-coupler + gpio_clear(GPIOB, GPIO0); // LED + } else { + gpio_clear(GPIOC, GPIO15); // opto-coupler + gpio_set(GPIOB, GPIO0); // LED + } + break; + default: + ; + } } -bool modbus_check_input_register(u16 addr UNUSED) +bool modbus_check_input_register(u16 addr) { - return false; + return (addr < AIRCON_IREG_MAX || addr >= AIRCON_IREG_DS_ID_MAX && addr < AIRCON_IREG_DS_ID_MAX); } -u16 modbus_get_input_register(u16 addr UNUSED) +static const byte temp_sensor_addrs[][8] = { + { 0xAA, 0x36, 0x69, 0x19, 0x13, 0x02 }, + { 0x4A, 0x1B, 0x79, 0x97, 0x01, 0x03 }, + { 0xAA, 0xAC, 0xD9, 0x18, 0x13, 0x02 }, + { 0x30, 0x66, 0x79, 0x97, 0x08, 0x03 }, + { 0xAA, 0x02, 0x64, 0x19, 0x13, 0x02 }, +}; + +u16 modbus_get_input_register(u16 addr) { - return 0; + if (addr <= AIRCON_IREG_TEMP_MIXED) { + byte i = 0; + while (i < DS_NUM_SENSORS && memcmp(ds_sensors[i].address, temp_sensor_addrs[addr], 8)) + 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; + } 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); + } else { + return 0; + } } -bool modbus_check_holding_register(u16 addr UNUSED) +bool modbus_check_holding_register(u16 addr) { - return (addr < 16); + return addr < AIRCON_HREG_MAX; } -u16 modbus_get_holding_register(u16 addr UNUSED) +u16 modbus_get_holding_register(u16 addr) { - return 0xbeef; + switch (addr) { + case AIRCON_HREG_EXCHANGER_FAN: + return fan_pwm; + case AIRCON_HREG_REMOTE_CONTROL: + default: + return 0; + } } -void modbus_set_holding_register(u16 addr UNUSED, u16 value UNUSED) +void modbus_set_holding_register(u16 addr, u16 value) { + switch (addr) { + case AIRCON_HREG_EXCHANGER_FAN: + fan_pwm = MIN(value, 255); + timer_set_oc_value(TIM4, TIM_OC1, T4_CYCLE * fan_pwm / 256); + break; + case AIRCON_HREG_REMOTE_CONTROL: + break; + default: + ; + } } void modbus_ready_hook(void) -- 2.39.2