From af35cee030acdf7056dcc5ddaf9300a0da5bba46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Tue, 30 Jan 2018 22:16:22 +0100 Subject: [PATCH] untested new onewire commands (all except search algos) --- comm/msg_responses.c | 8 ++ comm/msg_responses.h | 9 ++ platform/timebase.h | 10 ++ units/1wire/_ow_internal.h | 4 + units/1wire/unit_1wire.c | 237 ++++++++++++++++++++++++++++++++----- utils/error.h | 1 + 6 files changed, 242 insertions(+), 27 deletions(-) diff --git a/comm/msg_responses.c b/comm/msg_responses.c index ed03d32..44df67d 100644 --- a/comm/msg_responses.c +++ b/comm/msg_responses.c @@ -33,6 +33,14 @@ void com_respond_buf(TF_ID frame_id, TF_TYPE type, const uint8_t *buf, uint32_t } +void com_respond_pb(TF_ID frame_id, TF_TYPE type, PayloadBuilder *pb) +{ + uint32_t len; + uint8_t *buf = pb_close(pb, &len); + com_respond_buf(frame_id, type, buf, len); +} + + void com_respond_ok(TF_ID frame_id) { com_respond_buf(frame_id, MSG_SUCCESS, NULL, 0); diff --git a/comm/msg_responses.h b/comm/msg_responses.h index 2a70521..0145c32 100644 --- a/comm/msg_responses.h +++ b/comm/msg_responses.h @@ -34,6 +34,15 @@ com_respond_snprintf(TF_ID frame_id, TF_TYPE type, const char *format, ...); */ void com_respond_buf(TF_ID frame_id, TF_TYPE type, const uint8_t *buf, uint32_t len); +/** + * Respond using a payload builder's content + * + * @param type - response type byte + * @param frame_id - ID of the original msg + * @param pb - builder + */ +void com_respond_pb(TF_ID frame_id, TF_TYPE type, PayloadBuilder *pb); + /** * Respond to a TF message with empty body and MSG_SUCCESS type. * diff --git a/platform/timebase.h b/platform/timebase.h index 2a02dc8..9286f14 100644 --- a/platform/timebase.h +++ b/platform/timebase.h @@ -21,6 +21,16 @@ */ uint64_t PTIM_GetMicrotime(void); +/** + * Get time in milliseconds since start + * + * @return time in ms + */ +static inline uint32_t PTIM_GetTime(void) +{ + return HAL_GetTick(); +} + /** * Microseconds busy delay * diff --git a/units/1wire/_ow_internal.h b/units/1wire/_ow_internal.h index 5038ba5..0b89a7f 100644 --- a/units/1wire/_ow_internal.h +++ b/units/1wire/_ow_internal.h @@ -19,7 +19,11 @@ struct priv { GPIO_TypeDef *port; uint32_t ll_pin; + TimerHandle_t busyWaitTimer; // timer used to wait for ds1820 measurement completion + bool busy; // flag used when the timer is running + uint32_t busyStart; + TF_ID busyRequestId; }; // Prototypes diff --git a/units/1wire/unit_1wire.c b/units/1wire/unit_1wire.c index 3ed95f7..3373936 100644 --- a/units/1wire/unit_1wire.c +++ b/units/1wire/unit_1wire.c @@ -78,7 +78,37 @@ static void U1WIRE_writeIni(Unit *unit, IniWriter *iw) static void U1WIRE_TimerCb(TimerHandle_t xTimer) { + Unit *unit = pvTimerGetTimerID(xTimer); + assert_param(unit); + struct priv *priv = unit->data; + assert_param(priv->busy); + + if (priv->parasitic) { + // this is the end of the 750ms measurement time + goto halt_ok; + } else { + bool ready = ow_read_bit(unit); + if (ready) { + goto halt_ok; + } + + uint32_t time = PTIM_GetTime(); + if (time - priv->busyStart > 1000) { + dbg("Timeout 1s not ready. Stopping polling timer."); + xTimerStop(xTimer, 100); + com_respond_error(priv->busyRequestId, E_HW_TIMEOUT); + priv->busy = false; + dbg("Done, timer stopped."); + } + } + return; +halt_ok: + dbg("End of measurement, stopping timer"); + xTimerStop(xTimer, 100); + com_respond_ok(priv->busyRequestId); + priv->busy = false; + dbg("Done, timer stopped."); } /** Allocate data structure and set defaults */ @@ -88,7 +118,12 @@ static error_t U1WIRE_preInit(Unit *unit) if (priv == NULL) return E_OUT_OF_MEM; // the timer is not started until needed - priv->busyWaitTimer = xTimerCreate("1w_tim", 750, false, unit, U1WIRE_TimerCb); + priv->busyWaitTimer = xTimerCreate("1w_tim", // name + 750, // interval (will be changed when starting it) + true, // periodic (we use this only for the polling variant, the one-shot will stop the timer in the CB) + unit, // user data + U1WIRE_TimerCb); // callback + if (priv->busyWaitTimer == NULL) return E_OUT_OF_MEM; // some defaults @@ -141,52 +176,200 @@ static void U1WIRE_deInit(Unit *unit) // ------------------------------------------------------------------------ enum PinCmd_ { - CMD_TEST = 0, + CMD_CHECK_PRESENCE = 0, // simply tests that any devices are attached + CMD_SEARCH_ADDR = 1, // perform a scan of the bus, retrieving all found device ROMs + CMD_SEARCH_ALARM = 2, // like normal scan, but retrieve only devices with alarm + CMD_READ_ADDR = 3, // read the ROM code from a single device (for single-device bus) + + CMD_SKIP_WRITE = 10, // write multiple bytes using the SKIP_ROM command + CMD_SKIP_READ = 11, // write and read multiple bytes using the SKIP_ROM command + CMD_MATCH_WRITE = 12, // write multiple bytes using a ROM address + CMD_MATCH_READ = 13, // write and read multiple bytes using a ROM address + + CMD_POLL_FOR_1 = 20, + + CMD_TEST = 100, }; +/** send the match-rom with address from a payload parser, or skip-rom */ +static void cmd_match_skip(Unit *unit, uint8_t command, PayloadParser *pp) +{ + uint64_t addr; + if (command == CMD_MATCH_WRITE || command == CMD_MATCH_READ) { + addr = pp_u64(pp); + ow_write_u8(unit, OW_ROM_MATCH); + ow_write_u64(unit, addr); + } + else { + ow_write_u8(unit, OW_ROM_SKIP); + } +} + /** Handle a request message */ static error_t U1WIRE_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) { + struct priv *priv = unit->data; + + bool presence; + uint64_t addr; + int remain; + + if (priv->busy) return E_BUSY; + switch (command) { - /** Write byte(s) - addr:u16, byte(s) */ - case CMD_TEST:; - bool presence = ow_reset(unit); + /** Simply check presence of any devices on the bus. Responds with SUCCESS or HW_TIMEOUT */ + case CMD_CHECK_PRESENCE: + dbg("Test presence"); + + // reset + presence = ow_reset(unit); + if (!presence) return E_HW_TIMEOUT; + + // build response + com_respond_ok(frame_id); + return E_SUCCESS; + + /** Read address of the single device on the bus - returns u64 */ + case CMD_READ_ADDR: + dbg("Write ADDR"); + // reset + presence = ow_reset(unit); if (!presence) return E_HW_TIMEOUT; - ow_write_u8(unit, OW_ROM_SKIP); + // command + ow_write_u8(unit, OW_ROM_READ); + + // read the ROM code + addr = ow_read_u64(unit); - ow_write_u8(unit, OW_DS1820_CONVERT_T); - while (!ow_read_bit(unit)); + // build response + PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL); + pb_u64(&pb, addr); + com_respond_pb(frame_id, MSG_SUCCESS, &pb); + return E_SUCCESS; - // TODO use knowledge of the use/non-use of parasitic mode to pick the optimal strategy (non-parasitic allows polling) + /** + * Write payload to the bus, no confirmation (unless requested). + * + * Payload: + * - Match variant: addr:u64, rest:write_data + * - Skip variant: all:write_data + */ + case CMD_MATCH_WRITE: + case CMD_SKIP_WRITE: + dbg("Write cmd"); + + // reset + presence = ow_reset(unit); + if (!presence) return E_HW_TIMEOUT; - // osDelay(750); - // TODO this will be done with an async timer - // If parasitive power is not used, we could poll and check the status bit + // MATCH_ROM+addr, or SKIP_ROM + cmd_match_skip(unit, command, pp); + // write the rest of the payload + remain = pp_length(pp); + for (int i = 0; i < remain; i++) { + ow_write_u8(unit, pp_u8(pp)); + } + return E_SUCCESS; + + /** + * Write and read. + * + * Payload: + * - Match variant: addr:u64, read_len:u16, rest:write_data + * - Skip variant: read_len:u16, rest:write_data + */ + case CMD_MATCH_READ: + case CMD_SKIP_READ:; + dbg("Read cmd"); + + // reset presence = ow_reset(unit); if (!presence) return E_HW_TIMEOUT; - ow_write_u8(unit, OW_ROM_SKIP); - ow_write_u8(unit, OW_DS1820_READ_SCRATCH); + // MATCH_ROM+addr, or SKIP_ROM + cmd_match_skip(unit, command, pp); - uint16_t temp = ow_read_u16(unit); - uint16_t threg = ow_read_u16(unit); - uint16_t reserved = ow_read_u16(unit); - uint8_t cnt_remain = ow_read_u8(unit); - uint8_t cnt_per_c = ow_read_u8(unit); - uint8_t crc = ow_read_u8(unit); - // TODO check CRC + // paylod prefix - number of bytes to read + uint16_t rcount = pp_u16(pp); - PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL); - pb_u16(&pb, temp); - pb_u8(&pb, cnt_remain); - pb_u8(&pb, cnt_per_c); + // write the rest of the payload + remain = pp_length(pp); + for (int i = 0; i < remain; i++) { + ow_write_u8(unit, pp_u8(pp)); + } - dbg("respond ..."); - com_respond_buf(frame_id, MSG_SUCCESS, pb.start, pb_length(&pb)); + // read the requested number of bytes + for (int i = 0; i < rcount; i++) { + unit_tmp512[i] = ow_read_u8(unit); + } + + // build response + com_respond_buf(frame_id, MSG_SUCCESS, (const uint8_t *) unit_tmp512, rcount); return E_SUCCESS; + /** + * This is the delay function for DS1820 measurements. + * + * Parasitic: Returns success after the required 750ms + * Non-parasitic: Returns SUCCESS after device responds '1', HW_TIMEOUT after 1s + */ + case CMD_POLL_FOR_1: + dbg("Poll for 1 - start"); + if (priv->parasitic) { + assert_param(pdPASS == xTimerChangePeriod(priv->busyWaitTimer, 750, 100)); + } + else { + // every 10 ticks + assert_param(pdPASS == xTimerChangePeriod(priv->busyWaitTimer, 10, 100)); + } + assert_param(pdPASS == xTimerReset(priv->busyWaitTimer, 100)); + priv->busy = true; + priv->busyStart = PTIM_GetTime(); + priv->busyRequestId = frame_id; + dbg("Timer dispatched"); + return E_SUCCESS; // We will respond when the timer expires + +// +// case CMD_TEST:; +// bool presence = ow_reset(unit); +// if (!presence) return E_HW_TIMEOUT; +// +// ow_write_u8(unit, OW_ROM_SKIP); +// +// ow_write_u8(unit, OW_DS1820_CONVERT_T); +// while (!ow_read_bit(unit)); +// +// // TODO use knowledge of the use/non-use of parasitic mode to pick the optimal strategy (non-parasitic allows polling) +// +// // osDelay(750); +// // TODO this will be done with an async timer +// // If parasitive power is not used, we could poll and check the status bit +// +// presence = ow_reset(unit); +// if (!presence) return E_HW_TIMEOUT; +// ow_write_u8(unit, OW_ROM_SKIP); +// +// ow_write_u8(unit, OW_DS1820_READ_SCRATCH); +// +// uint16_t temp = ow_read_u16(unit); +// uint16_t threg = ow_read_u16(unit); +// uint16_t reserved = ow_read_u16(unit); +// uint8_t cnt_remain = ow_read_u8(unit); +// uint8_t cnt_per_c = ow_read_u8(unit); +// uint8_t crc = ow_read_u8(unit); +// // TODO check CRC +// +// pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL); +// pb_u16(&pb, temp); +// pb_u8(&pb, cnt_remain); +// pb_u8(&pb, cnt_per_c); +// +// dbg("respond ..."); +// com_respond_buf(frame_id, MSG_SUCCESS, pb.start, pb_length(&pb)); +// return E_SUCCESS; + default: return E_UNKNOWN_COMMAND; } diff --git a/utils/error.h b/utils/error.h index b5d64a8..0089155 100644 --- a/utils/error.h +++ b/utils/error.h @@ -25,6 +25,7 @@ X(PROTOCOL_BREACH, NULL) /* eating with the wrong spoon */ \ X(BAD_UNIT_TYPE, NULL) \ X(NOT_IMPLEMENTED, NULL) \ + X(BUSY, NULL) \ \ /* VFS user errors (those are meant to be shown to user) */ \ X(ERROR_DURING_TRANSFER, "Error during transfer") \