From f0d941bef6a9b6e3af78cfc68e1f82d6b47ccb2f Mon Sep 17 00:00:00 2001 From: fishsoupisgood Date: Tue, 26 May 2020 14:33:34 +0100 Subject: happy --- stm32/app/ot.c | 413 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 413 insertions(+) create mode 100644 stm32/app/ot.c (limited to 'stm32/app/ot.c') diff --git a/stm32/app/ot.c b/stm32/app/ot.c new file mode 100644 index 0000000..e604b50 --- /dev/null +++ b/stm32/app/ot.c @@ -0,0 +1,413 @@ +#include "project.h" + + +typedef struct { + uint8_t flags: 5; + uint8_t type: 3; + uint8_t data[2]; +} OT_Msg; + + +#define FLAGS_PENDING_THM 1U << 0 +#define FLAGS_PROCESSED_THM 1U << 1 +#define FLAGS_PENDING_USR 1U << 2 +#define FLAGS_PROCESSED_USR 1U << 3 +#define FLAGS_PENDING_OVR 1U << 4 + +#define FLAGS_PENDING (FLAGS_PENDING_THM|FLAGS_PENDING_USR | FLAGS_PENDING_OVR) + +#define IDX_MAX 0x300 + +static OT_Msg ot_thm_req[IDX_MAX]; +static OT_Msg ot_blr_rsp[IDX_MAX]; + +#define OT_NEXT(a) (((a) < 0x2ff) ? ((a)+1):0) +#define OT_INDEX(t,id) ((((unsigned) (t) ) <<8 ) | ((unsigned) (id))) +#define OT_IDX_TO_ID(idx) ((idx) & 0xff) +#define OT_IDX_TO_TYPE(idx) ((idx) >> 8) + +static unsigned ot_req_idx; +static unsigned in_flight_req_type; +static unsigned blr_backoff; +static unsigned ot_status_wdt; + + +#define OT_READ_DATA 0x0 +#define OT_WRITE_DATA 0x1 +#define OT_INVALID_DATA 0x2 +#define OT_READ_ACK 0x4 +#define OT_WRITE_ACK 0x5 +#define OT_DATA_INVALID 0x6 +#define OT_UNKNOWN_DATAID 0x7 + + +#define OT_IDX_STATUS 0 +/*TX*/ +#define OT_IDX_STATUS_BIT_ENABLE_CH (1U << 0) +#define OT_IDX_STATUS_BIT_ENABLE_DHW (1U << 1) + +/*RX*/ +#define OT_IDX_STATUS_BIT_FAULT (1U << 0) +#define OT_IDX_STATUS_BIT_CH_MODE (1U << 1) +#define OT_IDX_STATUS_BIT_DHW_MODE (1U << 2) +#define OT_IDX_STATUS_BIT_FLAME (1U << 3) + +#define OT_IDX_CONTROL_SETPOINT 1 +#define OT_IDX_DHW_SETPOINT 56 + + +#define OT_IDX_CH_WATER_PRESSURE 18 +#define OT_IDX_RETURN_WATER_TEMP 28 + + + +unsigned ot_override_ch = 0; +unsigned ot_override_dhw = 0; + + +static inline int parity (uint8_t v) +{ + return (0x6996u >> ((v ^ (v >> 4)) & 0xf)) & 1; +} + +void ot_parity (uint8_t *data) +{ + int p; + p = parity (data[0]); + p ^= parity (data[1]); + p ^= parity (data[2]); + p ^= parity (data[3]); + + if (p) data[0] ^= 0x80; +} + + +static const char *type_str[8] = { + ">Read Data", + ">Write Data", + ">Invalid Data", + ">Reserved", + "> 4) & 7; + + + printf ("%s%02x%02x%02x%02x %s %s\r\n", + who, + msg[0], + msg[1], + msg[2], + msg[3], + type_str[type], + what + ); +} + +static void send_reply_to_thm (unsigned idx) +{ + uint8_t reply[4]; + + if (ot_tx_thm (NULL)) return; + + reply[0] = ot_blr_rsp[idx].type << 4; + reply[1] = OT_IDX_TO_ID (idx); + reply[2] = ot_blr_rsp[idx].data[0]; + reply[3] = ot_blr_rsp[idx].data[1]; + + ot_debug ("B", reply, ""); + + ot_parity (reply); + ot_tx_thm (reply); + + ot_blr_rsp[idx].flags &= ~FLAGS_PROCESSED_THM; + +} + + +static int send_req_to_blr (unsigned idx) +{ + uint8_t req[4]; + + if (ot_tx_blr (NULL)) return -1; + + + + req[0] = ot_thm_req[ot_req_idx].type << 4; + req[1] = OT_IDX_TO_ID (ot_req_idx); + req[2] = ot_thm_req[ot_req_idx].data[0]; + req[3] = ot_thm_req[ot_req_idx].data[1]; + + ot_parity (req); + ot_debug (" S", req, ""); + + return ot_tx_blr (req); +} + + + + +void ot_rx_thm (uint8_t *msg, int error) +{ + unsigned type = (msg[0] >> 4) & 7; + unsigned id = msg[1]; + + unsigned idx; + + if (error) return; + + if (type > 2) { + ot_debug ("T", msg, "message type invalid for thermostat"); + return; + } + + if (ot_override_ch) { + if ((id == OT_IDX_STATUS) && (type == OT_READ_DATA)) /* Turn on heating */ + msg[2] |= OT_IDX_STATUS_BIT_ENABLE_CH; + + if ((id == OT_IDX_CONTROL_SETPOINT) && (type == OT_WRITE_DATA)) /* set water temp */ + msg[2] = ot_override_ch; + + } + + if (ot_override_dhw) { + if ((id == OT_IDX_STATUS) && (type == OT_READ_DATA)) /* Turn on hotwater */ + msg[2] |= OT_IDX_STATUS_BIT_ENABLE_DHW; + + if ((id == OT_IDX_DHW_SETPOINT) && (type == OT_WRITE_DATA)) /* set water temp */ + msg[2] = ot_override_dhw; + + } + + if ((id == OT_IDX_STATUS) && (type == OT_READ_DATA)) + ot_status_wdt = 0; + + ot_debug ("T", msg, ""); + + idx = OT_INDEX (type, id); + + if (ot_blr_rsp[idx].flags & FLAGS_PROCESSED_THM) + send_reply_to_thm (idx); + + else { + ot_thm_req[idx].type = type; + ot_thm_req[idx].data[0] = msg[2];; + ot_thm_req[idx].data[1] = msg[3];; + ot_thm_req[idx].flags |= FLAGS_PENDING_THM; + } +} + +void ot_rx_blr (uint8_t *msg, int error) +{ + unsigned type = (msg[0] >> 4) & 7; + unsigned id = msg[1]; + uint16_t t; + unsigned handled = 0 ; + + unsigned idx; + + if (error) return; + + ot_debug (" A", msg, ""); + + idx = OT_INDEX (in_flight_req_type, id); + + + if ((in_flight_req_type == OT_READ_DATA) && (type != OT_READ_ACK)) { + switch (idx) { + case OT_IDX_CH_WATER_PRESSURE: + t = pressure_ch(); + handled = 1; + break; + + case OT_IDX_RETURN_WATER_TEMP: + t = temp_ch_return(); + handled = 1; + break; + + } + + if (handled) { + + type = OT_READ_ACK; + + msg[0] &= 0x8f; + msg[0] |= type << 4; + msg[2] = t >> 8; + msg[3] = t & 0xff; + ot_debug ("B", msg, ""); + } + } + + ot_blr_rsp[idx].type = type; + ot_blr_rsp[idx].data[0] = msg[2];; + ot_blr_rsp[idx].data[1] = msg[3];; + ot_blr_rsp[idx].flags |= FLAGS_PROCESSED_THM | FLAGS_PROCESSED_USR; + + if (ot_thm_req[idx].flags & FLAGS_PENDING_THM) { + ot_thm_req[idx].flags &= ~FLAGS_PENDING_THM; + send_reply_to_thm (idx); + } + + if (ot_thm_req[idx].flags & FLAGS_PENDING_USR) { + ot_thm_req[idx].flags &= ~FLAGS_PENDING_USR; + //send_reply_to_usr (idx); + } + + if (ot_thm_req[idx].flags & FLAGS_PENDING_OVR) + ot_thm_req[idx].flags &= ~FLAGS_PENDING_OVR; + + blr_backoff = 0; + +} + + + +static void ot_boiler_worker (void) +{ + unsigned i; + + if (blr_backoff) { + blr_backoff--; + return; + } + + if (ot_tx_blr (NULL)) return; + + + for (i = 0; i < IDX_MAX; ++i, ot_req_idx = OT_NEXT (ot_req_idx)) { + + if (ot_thm_req[ot_req_idx].flags & FLAGS_PENDING) { + + if (!send_req_to_blr (ot_req_idx)) { + ot_thm_req[ot_req_idx].flags &= ~FLAGS_PENDING; + in_flight_req_type = OT_IDX_TO_TYPE (ot_req_idx); + blr_backoff = 10; + ot_req_idx = OT_NEXT (ot_req_idx); + return; + } + } + + } + +} + + +static void ot_request (unsigned flags, unsigned type, unsigned id, uint8_t *data) +{ + unsigned idx = OT_INDEX (type, id); + + ot_thm_req[idx].type = type; + + if (data) { + ot_thm_req[idx].data[0] = data[0]; + ot_thm_req[idx].data[1] = data[1]; + } else { + ot_thm_req[idx].data[0] = 0; + ot_thm_req[idx].data[1] = 0; + } + + ot_thm_req[idx].flags |= FLAGS_PENDING_USR; + +} + +void ot_request_usr (unsigned type, unsigned id, uint8_t *data) +{ + ot_request (FLAGS_PENDING_USR, type, id, data); +} +static void ot_request_ovr (unsigned type, unsigned id, uint8_t *data) +{ + ot_request (FLAGS_PENDING_OVR, type, id, data); +} + + + +static void ot_force_status (void) +{ + uint8_t data[2] = { (ot_override_ch ? OT_IDX_STATUS_BIT_ENABLE_CH : 0) | (ot_override_dhw ? OT_IDX_STATUS_BIT_ENABLE_DHW : 0), 0}; + + ot_request_ovr (OT_READ_DATA, OT_IDX_STATUS, data); + +} + +static void ot_30s_ticker (void) +{ + uint8_t data[2]; + + printf ("Q send temp set points\r\n"); + + if (ot_override_ch) { + data[0] = ot_override_ch; + data[1] = 0; + ot_request_ovr (OT_WRITE_DATA, OT_IDX_CONTROL_SETPOINT, data); + } + + if (ot_override_dhw) { + + data[0] = ot_override_dhw; + data[1] = 0; + ot_request_ovr (OT_WRITE_DATA, OT_IDX_DHW_SETPOINT, data); + } + + ot_request_ovr (OT_READ_DATA, OT_IDX_CH_WATER_PRESSURE, NULL); + ot_request_ovr (OT_READ_DATA, OT_IDX_RETURN_WATER_TEMP, NULL); + +} + + + + +static void ot_4hz_ticker (void) +{ + static unsigned i; + i++; + + ot_boiler_worker(); + + ot_status_wdt++; + + if (ot_status_wdt > 120) { + printf ("Q forcing status packet\r\n"); + ot_force_status(); + ot_status_wdt = 0; + } + + + if (i >= 120) { + ot_30s_ticker(); + i = 0; + } + + + led_yellow_set (ot_blr_rsp[OT_INDEX (OT_READ_DATA, OT_IDX_STATUS)].data[1] & OT_IDX_STATUS_BIT_FAULT); + led_green1_set (ot_blr_rsp[OT_INDEX (OT_READ_DATA, OT_IDX_STATUS)].data[1] & OT_IDX_STATUS_BIT_CH_MODE); + led_green2_set (ot_blr_rsp[OT_INDEX (OT_READ_DATA, OT_IDX_STATUS)].data[1] & OT_IDX_STATUS_BIT_DHW_MODE); + led_red_set (ot_blr_rsp[OT_INDEX (OT_READ_DATA, OT_IDX_STATUS)].data[1] & OT_IDX_STATUS_BIT_FLAME); + +} + + +void ot_tick (void) +{ + static unsigned i; + i++; + + if (i >= 500) { + ot_4hz_ticker(); + i = 0; + } + + +} + + +void ot_init (void) +{ + ot_phy_rx_init(); + ot_phy_tx_init(); +} -- cgit v1.2.3