#include <string.h>
-static void clock_setup(void)
+static void rc_init(void);
+
+static void clock_init(void)
{
rcc_clock_setup_in_hse_8mhz_out_72mhz();
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);
ms_ticks++;
}
-static void tick_setup(void)
+static void tick_init(void)
{
systick_set_frequency(1000, 72000000);
systick_counter_enable();
;
}
-static void usart_setup(void)
+static void usart_init(void)
{
usart_set_baudrate(USART1, 115200);
usart_set_databits(USART1, 8);
static byte bypass_active;
static byte fan_pwm;
+// FIXME
static void show_temperature(void)
{
debug_putc('#');
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");
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;
+
+ const char *s = strchr(rc_keys, key);
+ if (!s)
+ return false;
+ rc_pending = key;
+ rc_pattern_pos = rc_patterns[s - rc_keys];
+
+ 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)
case AIRCON_HREG_EXCHANGER_FAN:
return fan_pwm;
case AIRCON_HREG_REMOTE_CONTROL:
+ return rc_pending;
default:
return 0;
}
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:
;