#include <libopencm3/stm32/timer.h>
#include <libopencm3/stm32/usart.h>
+#include <string.h>
+
static void clock_setup(void)
{
rcc_clock_setup_in_hse_8mhz_out_72mhz();
// 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)
{
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");
}
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') {
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
*
* % = 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) {
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;
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)