diff --git a/comm/msg_bulkwrite.c b/comm/msg_bulkwrite.c index ef605bb..dbbfe7b 100644 --- a/comm/msg_bulkwrite.c +++ b/comm/msg_bulkwrite.c @@ -28,9 +28,9 @@ static TF_Result bulkwrite_lst(TinyFrame *tf, TF_Msg *msg) goto close; } else if (msg->type == MSG_BULK_DATA || msg->type == MSG_BULK_END) { - // if past len, say we're done and close + // if past len, speak up if (bulk->offset >= bulk->len) { - com_respond_err(bulk->frame_id, "WRITE OVERRUN"); + com_respond_error(bulk->frame_id, E_OVERRUN); goto close; } diff --git a/comm/msg_responses.c b/comm/msg_responses.c index 6b5b6a4..3e6128b 100644 --- a/comm/msg_responses.c +++ b/comm/msg_responses.c @@ -60,7 +60,7 @@ void com_respond_str(TF_TYPE type, TF_ID frame_id, const char *str) // --------------------------------------------------------------------------- -void com_respond_err(TF_ID frame_id, const char *message) +static void respond_err(TF_ID frame_id, const char *message) { com_respond_str(MSG_ERROR, frame_id, message); } @@ -68,13 +68,15 @@ void com_respond_err(TF_ID frame_id, const char *message) void com_respond_bad_cmd(TF_ID frame_id) { - com_respond_err(frame_id, "BAD COMMAND"); + respond_err(frame_id, "BAD COMMAND"); } - -void com_respond_malformed_cmd(TF_ID frame_id) +void com_respond_error(TF_ID frame_id, error_t error) { - com_respond_err(frame_id, "MALFORMED PAYLOAD"); + if (error == E_SUCCESS) + com_respond_ok(frame_id); + else + respond_err(frame_id, error_get_message(error)); } // --------------------------------------------------------------------------- diff --git a/comm/msg_responses.h b/comm/msg_responses.h index 8189092..e773504 100644 --- a/comm/msg_responses.h +++ b/comm/msg_responses.h @@ -11,7 +11,6 @@ /** * Respond to a TF message using printf-like formatting. - * Works synchronously, must be called on a job queue. * * @param type - response type byte * @param frame_id - ID of the original msg @@ -23,7 +22,6 @@ com_respond_snprintf(TF_ID frame_id, TF_TYPE type, const char *format, ...); /** * Respond to a TF message with a buffer of fixed length and custom type. - * Works synchronously, must be called on a job queue. * * @param type - response type byte * @param frame_id - ID of the original msg @@ -34,15 +32,21 @@ void com_respond_buf(TF_ID frame_id, TF_TYPE type, const uint8_t *buf, uint32_t /** * Respond to a TF message with empty body and MSG_SUCCESS type. - * Works synchronously, must be called on a job queue. * * @param frame_id - ID of the original msg */ void com_respond_ok(TF_ID frame_id); +/** + * Respond with a error constant (converted to string) + * + * @param frame_id - ID of the original msg + * @param error - error to report + */ +void com_respond_error(TF_ID frame_id, error_t error); + /** * Same like tf_respond_buf(), but used for sending spontaneous reports. - * Works synchronously, must be called on a job queue / timer task etc. * * @param type - response type byte * @param buf - byte buffer @@ -53,7 +57,6 @@ void com_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len); /** * Same like tf_respond_buf(), but the buffer length is measured with strlen. * Used to sending ASCII string responses. - * Works synchronously, must be called on a job queue. * * @param type - response type byte * @param frame_id - ID of the original msg @@ -61,32 +64,8 @@ void com_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len); */ void com_respond_str(TF_TYPE type, TF_ID frame_id, const char *str); -/** - * Schedule sending an ASCII string error response. - * Schedules a low priority job. - * - * @param frame_id - ID of the original msg - * @param str - character buffer, zero terminated - */ -void com_respond_err(TF_ID frame_id, const char *str); - -/** - * Variant of sched_respond_err() for reporting bad received command code - * - * @param msg_id - ID of the original msg - */ -void com_respond_bad_cmd(TF_ID frame_id); - -/** - * Variant of sched_respond_err() for reporting malformed commands (e.g. too short payload) - * - * @param msg_id - ID of the original msg - */ -void com_respond_malformed_cmd(TF_ID frame_id); - /** * Schedule sending a one-byte response with MSG_SUCCESS type. - * Schedules a high priority job. * * @param frame_id - ID of the original msg * @param d - data @@ -95,7 +74,6 @@ void com_respond_u8(TF_ID frame_id, uint8_t d); /** * Schedule sending a two-byte response with MSG_SUCCESS type. - * Schedules a high priority job. * * @param frame_id - ID of the original msg * @param d - data @@ -104,7 +82,6 @@ void com_respond_u16(TF_ID frame_id, uint16_t d); /** * Schedule sending a 4-byte response with MSG_SUCCESS type. - * Schedules a high priority job. * * @param frame_id - ID of the original msg * @param d - data diff --git a/framework/resources.c b/framework/resources.c index 80b1047..e901e81 100644 --- a/framework/resources.c +++ b/framework/resources.c @@ -42,7 +42,7 @@ void rsc_init_registry(void) * @param rsc - resource to claim * @return true on successful claim */ -bool rsc_claim(Unit *unit, Resource rsc) +error_t rsc_claim(Unit *unit, Resource rsc) { assert_param(rsc_initialized); assert_param(rsc > R_NONE && rsc < R_RESOURCE_COUNT); @@ -53,12 +53,11 @@ bool rsc_claim(Unit *unit, Resource rsc) dbg("ERROR!! Unit %s failed to claim resource %s, already held by %s!", unit->name, rsc_names[rsc], resources[rsc].owner->name); - unit->status = E_RESOURCE_NOT_AVAILABLE; - return false; + return E_RESOURCE_NOT_AVAILABLE; } resources[rsc].owner = unit; - return true; + return E_SUCCESS; } /** @@ -69,7 +68,7 @@ bool rsc_claim(Unit *unit, Resource rsc) * @param rsc1 - last resource to claim * @return true on complete claim, false if any failed (none are claimed in that case) */ -bool rsc_claim_range(Unit *unit, Resource rsc0, Resource rsc1) +error_t rsc_claim_range(Unit *unit, Resource rsc0, Resource rsc1) { assert_param(rsc_initialized); assert_param(rsc0 > R_NONE && rsc0 < R_RESOURCE_COUNT); @@ -77,33 +76,25 @@ bool rsc_claim_range(Unit *unit, Resource rsc0, Resource rsc1) assert_param(unit != NULL); for (int i = rsc0; i <= rsc1; i++) { - if (!rsc_claim(unit, (Resource) i)) return false; + TRY(rsc_claim(unit, (Resource) i)); } - return true; + return E_SUCCESS; } -bool rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins) +error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins) { bool suc = true; for (int i = 0; i < 16; i++) { if (pins & (1 << i)) { Resource rsc = pin2resource(port_name, (uint8_t) i, &suc); - if (!suc) { - unit->status = E_BAD_CONFIG; -// rsc_teardown(unit); - return false; - } - - suc = rsc_claim(unit, rsc); - if (!suc) { -// rsc_teardown(unit); - return false; - } + if (!suc) return E_BAD_CONFIG; + + TRY(rsc_claim(unit, rsc)); } } - return true; + return E_SUCCESS; } /** diff --git a/framework/resources.h b/framework/resources.h index 4ecb400..e9f6254 100644 --- a/framework/resources.h +++ b/framework/resources.h @@ -81,13 +81,8 @@ enum hw_resource { void rsc_init_registry(void); -bool rsc_claim(Unit *unit, Resource rsc); -bool rsc_claim_range(Unit *unit, Resource rsc0, Resource rsc1); -void rsc_teardown(Unit *unit); - -void rsc_free(Unit *unit, Resource rsc); -void rsc_free_range(Unit *unit, Resource rsc0, Resource rsc1); - +error_t rsc_claim(Unit *unit, Resource rsc); +error_t rsc_claim_range(Unit *unit, Resource rsc0, Resource rsc1); /** * Claim GPIOs by bitmask and port name, atomically. * Tear down the unit on failure. @@ -97,6 +92,10 @@ void rsc_free_range(Unit *unit, Resource rsc0, Resource rsc1); * @param pins - pins, bitmask * @return success */ -bool rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins); +error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins); + +void rsc_teardown(Unit *unit); +void rsc_free(Unit *unit, Resource rsc); +void rsc_free_range(Unit *unit, Resource rsc0, Resource rsc1); #endif //GEX_RESOURCES_H diff --git a/framework/settings.c b/framework/settings.c index f32997c..f6f04eb 100644 --- a/framework/settings.c +++ b/framework/settings.c @@ -308,8 +308,9 @@ void settings_load_ini_key(const char *restrict section, const char *restrict ke namebuf[csptr - nameptr - 1] = 0; uint8_t cs = (uint8_t) avr_atoi(csptr + 1); - bool res = ureg_load_unit_ini_key(namebuf, key, value, cs); - if (!res) dbg("!! error loading %s@%d.%s = %s", namebuf, (int)cs, key, value); + error_t rv = ureg_load_unit_ini_key(namebuf, key, value, cs); + if (rv != E_SUCCESS) + dbg("!! error loading %s@%d.%s = %s - error %s", namebuf, (int)cs, key, value, error_get_message(rv)); } else { dbg("! Bad config key: [%s] %s = %s", section, key, value); } diff --git a/framework/unit.h b/framework/unit.h index 6ce4a5c..791da70 100644 --- a/framework/unit.h +++ b/framework/unit.h @@ -48,7 +48,7 @@ struct unit_driver { /** * Pre-init: allocate data object, init defaults */ - bool (*preInit)(Unit *unit); + error_t (*preInit)(Unit *unit); /** * Load settings from binary storage, parse and store them in the data object. @@ -73,11 +73,10 @@ struct unit_driver { * @param key - key from the INI file * @param value - value from the ini file; strings have already removed quotes and replaced escape sequences with ASCII as needed */ - bool (*cfgLoadIni)(Unit *unit, const char *key, const char *value); + error_t (*cfgLoadIni)(Unit *unit, const char *key, const char *value); /** * Export settings to a INI file. - * Capacity will likely be 512 bytes, do not waste space! * * @param buffer - destination buffer * @param capacity - buffer size @@ -88,7 +87,7 @@ struct unit_driver { /** * Finalize the init sequence, validate settings, enable peripherals and prepare for operation */ - bool (*init)(Unit *unit); + error_t (*init)(Unit *unit); /** * De-initialize the unit: de-init peripheral, free resources, free data object... @@ -99,7 +98,7 @@ struct unit_driver { /** * Handle an incoming request. Return true if command was OK. */ - bool (*handleRequest)(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp); + error_t (*handleRequest)(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp); }; /** diff --git a/framework/unit_registry.c b/framework/unit_registry.c index 4036d71..6978429 100644 --- a/framework/unit_registry.c +++ b/framework/unit_registry.c @@ -100,6 +100,7 @@ static void add_unit_to_list(UlistEntry *le) Unit *ureg_instantiate(const char *driver_name) { bool suc = true; + error_t rv; // Find type in the repository UregEntry *re = ureg_head; @@ -113,19 +114,19 @@ Unit *ureg_instantiate(const char *driver_name) Unit *pUnit = &le->unit; pUnit->driver = re->driver; - pUnit->status = E_LOADING; + pUnit->status = E_LOADING; // indeterminate default state pUnit->data = NULL; pUnit->callsign = 0; - suc = pUnit->driver->preInit(pUnit); - if (!suc) { + rv = pUnit->driver->preInit(pUnit); + if (rv != E_SUCCESS) { // tear down what we already allocated and abort // If it failed this early, the only plausible explanation is failed malloc, // in which case the data structure is not populated and keeping the // broken unit doesn't serve any purpose. Just ditch it... - dbg("!! Unit type %s failed to pre-init!", driver_name); + dbg("!! Unit type %s failed to pre-init! %s", driver_name, error_get_message(rv)); clean_failed_unit(pUnit); free(le); return NULL; @@ -219,9 +220,9 @@ bool ureg_load_units(PayloadParser *pp) dbg("Adding unit \"%s\" of type %s", pUnit->name, pUnit->driver->name); - suc = pUnit->driver->init(pUnit); // finalize the load and init the unit - if (pUnit->status == E_LOADING) { - pUnit->status = suc ? E_SUCCESS : E_BAD_CONFIG; + pUnit->status = pUnit->driver->init(pUnit); // finalize the load and init the unit + if (pUnit->status != E_SUCCESS) { + dbg("!!! error initing unit %s: %s", pUnit->name, error_get_message(pUnit->status)); } } // end unit } @@ -298,7 +299,7 @@ bool ureg_instantiate_by_ini(const char *restrict driver_name, const char *restr } /** Load unit key-value */ -bool ureg_load_unit_ini_key(const char *restrict name, +error_t ureg_load_unit_ini_key(const char *restrict name, const char *restrict key, const char *restrict value, uint8_t callsign) @@ -313,10 +314,10 @@ bool ureg_load_unit_ini_key(const char *restrict name, li = li->next; } - return false; + return E_NO_SUCH_UNIT; } -/** Finalize untis init */ +/** Finalize units init. Returns true if all inited OK. */ bool ureg_finalize_all_init(void) { dbg("Finalizing units init..."); @@ -326,18 +327,13 @@ bool ureg_finalize_all_init(void) while (li != NULL) { Unit *const pUnit = &li->unit; - bool s = pUnit->driver->init(pUnit); - if (!s) { - dbg("!!!! error initing unit %s", pUnit->name); - if (pUnit->status == E_LOADING) { - // assume it's a config error if not otherwise specified - pUnit->status = E_BAD_CONFIG; - } - } else { - pUnit->status = E_SUCCESS; + pUnit->status = pUnit->driver->init(pUnit); + if (pUnit->status != E_SUCCESS) { + dbg("!!! error initing unit %s: %s", pUnit->name, error_get_message(pUnit->status)); } // try to assign unique callsigns + // FIXME this is wrong, sometimes leads to duplicate CS if (pUnit->callsign == 0) { pUnit->callsign = callsign++; } else { @@ -346,7 +342,7 @@ bool ureg_finalize_all_init(void) } } - suc &= s; + suc &= (pUnit->status == E_SUCCESS); li = li->next; } return suc; @@ -358,7 +354,7 @@ static void export_unit_do(UlistEntry *li, IniWriter *iw) iw_section(iw, "%s:%s@%d", pUnit->driver->name, pUnit->name, (int)pUnit->callsign); if (pUnit->status != E_SUCCESS) { - iw_comment(iw, "!!! %s", error_get_string(pUnit->status)); + iw_comment(iw, "!!! %s", error_get_message(pUnit->status)); } pUnit->driver->cfgWriteIni(pUnit, iw); } @@ -445,10 +441,8 @@ void ureg_deliver_unit_request(TF_Msg *msg) bool confirmed = (bool) (command & 0x80); command &= 0x7F; - if (!pp.ok) { dbg("!! pp not OK!"); } - if (callsign == 0 || !pp.ok) { - com_respond_malformed_cmd(msg->frame_id); + com_respond_error(msg->frame_id, E_MALFORMED_COMMAND); return; } @@ -456,12 +450,14 @@ void ureg_deliver_unit_request(TF_Msg *msg) while (li != NULL) { Unit *const pUnit = &li->unit; if (pUnit->callsign == callsign && pUnit->status == E_SUCCESS) { - bool ok = pUnit->driver->handleRequest(pUnit, msg->frame_id, command, &pp); + error_t rv = pUnit->driver->handleRequest(pUnit, msg->frame_id, command, &pp); // send extra SUCCESS confirmation message. // error is expected to have already been reported. - if (ok && confirmed) { - com_respond_ok(msg->frame_id); + if (rv == E_SUCCESS) { + if (confirmed) com_respond_ok(msg->frame_id); + } else { + com_respond_error(msg->frame_id, rv); } return; } @@ -469,7 +465,7 @@ void ureg_deliver_unit_request(TF_Msg *msg) } // Not found - com_respond_snprintf(msg->frame_id, MSG_ERROR, "NO UNIT @ %"PRIu8, callsign); + com_respond_error(msg->frame_id, E_NO_SUCH_UNIT); } /** Send a response for a unit-list request */ @@ -492,7 +488,11 @@ void ureg_report_active_units(TF_ID frame_id) bool suc = true; uint8_t *buff = malloc_ck(msglen, &suc); - if (!suc) { com_respond_str(MSG_ERROR, frame_id, "OUT OF MEMORY"); return; } + if (!suc) { + com_respond_error(frame_id, E_OUT_OF_MEM); + return; + } + { PayloadBuilder pb = pb_start(buff, msglen, NULL); pb_u8(&pb, (uint8_t) count); // assume we don't have more than 255 units diff --git a/framework/unit_registry.h b/framework/unit_registry.h index c6339ba..c9c17e9 100644 --- a/framework/unit_registry.h +++ b/framework/unit_registry.h @@ -99,7 +99,7 @@ bool ureg_instantiate_by_ini(const char *restrict driver_name, const char *restr * @param callsign - callsign (is part of the section string) * @return success */ -bool ureg_load_unit_ini_key(const char *restrict name, +error_t ureg_load_unit_ini_key(const char *restrict name, const char *restrict key, const char *restrict value, uint8_t callsign); diff --git a/units/digital_in/unit_din.c b/units/digital_in/unit_din.c index c28f8f8..1cca3b7 100644 --- a/units/digital_in/unit_din.c +++ b/units/digital_in/unit_din.c @@ -51,7 +51,7 @@ static void DI_writeBinary(Unit *unit, PayloadBuilder *pb) // ------------------------------------------------------------------------ /** Parse a key-value pair from the INI file */ -static bool DI_loadIni(Unit *unit, const char *key, const char *value) +static error_t DI_loadIni(Unit *unit, const char *key, const char *value) { bool suc = true; struct priv *priv = unit->data; @@ -67,13 +67,13 @@ static bool DI_loadIni(Unit *unit, const char *key, const char *value) } else if (streq(key, "pull-down")) { priv->pulldown = parse_pinmask(value, &suc); - dbg("parsinf ini, pulldown = %X", priv->pulldown); } else { - return false; + return E_BAD_KEY; } - return suc; + if (!suc) return E_BAD_VALUE; + return E_SUCCESS; } /** Generate INI file section for the unit */ @@ -101,11 +101,11 @@ static void DI_writeIni(Unit *unit, IniWriter *iw) // ------------------------------------------------------------------------ /** Allocate data structure and set defaults */ -static bool DI_preInit(Unit *unit) +static error_t DI_preInit(Unit *unit) { bool suc = true; struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); - CHECK_SUC(); + if (!suc) return E_OUT_OF_MEM; // some defaults priv->port_name = 'A'; @@ -113,11 +113,11 @@ static bool DI_preInit(Unit *unit) priv->pulldown = 0x0000; priv->pullup = 0x0000; - return true; + return E_SUCCESS; } /** Finalize unit set-up */ -static bool DI_init(Unit *unit) +static error_t DI_init(Unit *unit) { bool suc = true; struct priv *priv = unit->data; @@ -127,14 +127,10 @@ static bool DI_init(Unit *unit) // --- Parse config --- priv->port = port2periph(priv->port_name, &suc); - if (!suc) { - unit->status = E_BAD_CONFIG; - return false; - } + if (!suc) return E_BAD_CONFIG; // Claim all needed pins - suc = rsc_claim_gpios(unit, priv->port_name, priv->pins); - CHECK_SUC(); + TRY(rsc_claim_gpios(unit, priv->port_name, priv->pins)); uint16_t mask = 1; for (int i = 0; i < 16; i++, mask <<= 1) { @@ -158,7 +154,7 @@ static bool DI_init(Unit *unit) } } - return true; + return E_SUCCESS; } @@ -196,7 +192,7 @@ enum PinCmd_ { }; /** Handle a request message */ -static bool DI_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) +static error_t DI_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) { (void)pp; @@ -209,14 +205,11 @@ static bool DI_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Payloa PayloadBuilder pb = pb_start((uint8_t*)unit_tmp512, 64, NULL); pb_u16(&pb, packed); com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, pb_length(&pb)); - break; + return E_SUCCESS; default: - com_respond_bad_cmd(frame_id); - return false; + return E_UNKNOWN_COMMAND; } - - return true; } // ------------------------------------------------------------------------ diff --git a/units/digital_out/unit_dout.c b/units/digital_out/unit_dout.c index dfd26a4..1724204 100644 --- a/units/digital_out/unit_dout.c +++ b/units/digital_out/unit_dout.c @@ -48,7 +48,7 @@ static void DO_writeBinary(Unit *unit, PayloadBuilder *pb) // ------------------------------------------------------------------------ /** Parse a key-value pair from the INI file */ -static bool DO_loadIni(Unit *unit, const char *key, const char *value) +static error_t DO_loadIni(Unit *unit, const char *key, const char *value) { bool suc = true; struct priv *priv = unit->data; @@ -66,10 +66,11 @@ static bool DO_loadIni(Unit *unit, const char *key, const char *value) priv->open_drain = parse_pinmask(value, &suc); } else { - return false; + return E_BAD_KEY; } - return suc; + if (!suc) return E_BAD_VALUE; + return E_SUCCESS; } /** Generate INI file section for the unit */ @@ -93,11 +94,11 @@ static void DO_writeIni(Unit *unit, IniWriter *iw) // ------------------------------------------------------------------------ /** Allocate data structure and set defaults */ -static bool DO_preInit(Unit *unit) +static error_t DO_preInit(Unit *unit) { bool suc = true; struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); - CHECK_SUC(); + if (!suc) return E_OUT_OF_MEM; // some defaults priv->port_name = 'A'; @@ -105,11 +106,11 @@ static bool DO_preInit(Unit *unit) priv->open_drain = 0x0000; priv->initial = 0x0000; - return true; + return E_SUCCESS; } /** Finalize unit set-up */ -static bool DO_init(Unit *unit) +static error_t DO_init(Unit *unit) { bool suc = true; struct priv *priv = unit->data; @@ -119,14 +120,10 @@ static bool DO_init(Unit *unit) // --- Parse config --- priv->port = port2periph(priv->port_name, &suc); - if (!suc) { - unit->status = E_BAD_CONFIG; - return false; - } + if (!suc) return E_BAD_CONFIG; // Claim all needed pins - suc = rsc_claim_gpios(unit, priv->port_name, priv->pins); - CHECK_SUC(); + TRY(rsc_claim_gpios(unit, priv->port_name, priv->pins)); uint16_t mask = 1; for (int i = 0; i < 16; i++, mask <<= 1) { @@ -148,7 +145,7 @@ static bool DO_init(Unit *unit) priv->port->ODR &= ~priv->pins; priv->port->ODR |= priv->initial; - return true; + return E_SUCCESS; } /** Tear down the unit */ @@ -190,10 +187,8 @@ enum PinCmd_ { }; /** Handle a request message */ -static bool DO_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) +static error_t DO_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) { - (void)pp; - struct priv *priv = unit->data; uint16_t packed = pp_u16(pp); @@ -208,29 +203,26 @@ static bool DO_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Payloa set = spread; reset = (~spread) & mask; priv->port->BSRR = set | (reset<<16); - break; + return E_SUCCESS; case CMD_SET: priv->port->BSRR = spread; - break; + return E_SUCCESS; case CMD_CLEAR: priv->port->BSRR = (spread<<16); - break; + return E_SUCCESS; case CMD_TOGGLE:; spread = (uint16_t) (~priv->port->ODR) & mask; set = spread; reset = (~spread) & mask; priv->port->BSRR = set | (reset<<16); - break; + return E_SUCCESS; default: - com_respond_bad_cmd(frame_id); - return false; + return E_UNKNOWN_COMMAND; } - - return true; } // ------------------------------------------------------------------------ diff --git a/units/i2c/unit_i2c.c b/units/i2c/unit_i2c.c index f68664c..2dd4b0e 100644 --- a/units/i2c/unit_i2c.c +++ b/units/i2c/unit_i2c.c @@ -55,7 +55,7 @@ static void UI2C_writeBinary(Unit *unit, PayloadBuilder *pb) // ------------------------------------------------------------------------ /** Parse a key-value pair from the INI file */ -static bool UI2C_loadIni(Unit *unit, const char *key, const char *value) +static error_t UI2C_loadIni(Unit *unit, const char *key, const char *value) { bool suc = true; struct priv *priv = unit->data; @@ -73,10 +73,11 @@ static bool UI2C_loadIni(Unit *unit, const char *key, const char *value) priv->speed = (uint8_t) avr_atoi(value); } else { - return false; + return E_BAD_KEY; } - return suc; + if (!suc) return E_BAD_VALUE; + return E_SUCCESS; } /** Generate INI file section for the unit */ @@ -100,11 +101,11 @@ static void UI2C_writeIni(Unit *unit, IniWriter *iw) // ------------------------------------------------------------------------ /** Allocate data structure and set defaults */ -static bool UI2C_preInit(Unit *unit) +static error_t UI2C_preInit(Unit *unit) { bool suc = true; struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); - CHECK_SUC(); + if (!suc) return E_OUT_OF_MEM; // some defaults priv->periph_num = 1; @@ -112,41 +113,36 @@ static bool UI2C_preInit(Unit *unit) priv->anf = true; priv->dnf = 0; - return true; + return E_SUCCESS; } /** Finalize unit set-up */ -static bool UI2C_init(Unit *unit) +static error_t UI2C_init(Unit *unit) { bool suc = true; struct priv *priv = unit->data; if (!(priv->periph_num >= 1 && priv->periph_num <= 2)) { - unit->status = E_BAD_CONFIG; - dbg("!! Bad I2C periph"); - return false; + dbg("!! Bad I2C periph"); // TODO report + return E_BAD_CONFIG; } if (!(priv->speed >= 1 && priv->speed <= 3)) { - unit->status = E_BAD_CONFIG; dbg("!! Bad I2C speed"); - return false; + return E_BAD_CONFIG; } if (priv->dnf > 15) { - unit->status = E_BAD_CONFIG; dbg("!! Bad I2C DNF bw"); - return false; + return E_BAD_CONFIG; } // assign and claim the peripheral if (priv->periph_num == 1) { - suc = rsc_claim(unit, R_I2C1); - CHECK_SUC(); + TRY(rsc_claim(unit, R_I2C1)); priv->periph = I2C1; } else { - suc = rsc_claim(unit, R_I2C2); - CHECK_SUC(); + TRY(rsc_claim(unit, R_I2C2)); priv->periph = I2C2; } @@ -192,15 +188,15 @@ static bool UI2C_init(Unit *unit) // first, we have to claim the pins Resource r_sda = pin2resource(portname, pin_sda, &suc); Resource r_scl = pin2resource(portname, pin_scl, &suc); - CHECK_SUC(); - rsc_claim(unit, r_sda); - rsc_claim(unit, r_scl); - CHECK_SUC(); + if (!suc) return E_BAD_CONFIG; + + TRY(rsc_claim(unit, r_sda)); + TRY(rsc_claim(unit, r_scl)); GPIO_TypeDef *port = port2periph(portname, &suc); uint32_t ll_pin_scl = pin2ll(pin_scl, &suc); uint32_t ll_pin_sda = pin2ll(pin_sda, &suc); - CHECK_SUC(); + if (!suc) return E_BAD_CONFIG; // configure AF if (pin_scl < 8) LL_GPIO_SetAFPin_0_7(port, ll_pin_scl, af_i2c); @@ -237,7 +233,7 @@ static bool UI2C_init(Unit *unit) LL_I2C_DisableOwnAddress1(priv->periph); // OA not used LL_I2C_SetMode(priv->periph, LL_I2C_MODE_I2C); // not using SMBus - return true; + return E_SUCCESS; } /** Tear down the unit */ @@ -283,19 +279,19 @@ static void i2c_reset(struct priv *priv) LL_I2C_Enable(priv->periph); } -static bool i2c_wait_until_flag(struct priv *priv, uint32_t flag, bool stop_state) +static error_t i2c_wait_until_flag(struct priv *priv, uint32_t flag, bool stop_state) { uint32_t t_start = HAL_GetTick(); while (((priv->periph->ISR & flag)!=0) != stop_state) { if (HAL_GetTick() - t_start > 10) { i2c_reset(priv); - return false; + return E_HW_TIMEOUT; } } - return true; + return E_SUCCESS; } -bool UU_I2C_Write(Unit *unit, uint16_t addr, const uint8_t *bytes, uint32_t bcount) +error_t UU_I2C_Write(Unit *unit, uint16_t addr, const uint8_t *bytes, uint32_t bcount) { struct priv *priv = unit->data; @@ -304,10 +300,7 @@ bool UU_I2C_Write(Unit *unit, uint16_t addr, const uint8_t *bytes, uint32_t bcou uint32_t ll_addrsize = (addrsize == 7) ? LL_I2C_ADDRSLAVE_7BIT : LL_I2C_ADDRSLAVE_10BIT; if (addrsize == 7) addr <<= 1; // 7-bit address must be shifted to left for LL to use it correctly - if (!i2c_wait_until_flag(priv, I2C_ISR_BUSY, 0)) { - dbg("BUSY TOUT"); - return false; - } + TRY(i2c_wait_until_flag(priv, I2C_ISR_BUSY, 0)); bool first = true; while (bcount > 0) { @@ -320,24 +313,18 @@ bool UU_I2C_Write(Unit *unit, uint16_t addr, const uint8_t *bytes, uint32_t bcou bcount -= chunk_remain; for (; chunk_remain > 0; chunk_remain--) { - if (!i2c_wait_until_flag(priv, I2C_ISR_TXIS, 1)) { - dbg("TXIS TOUT, remain %d", (int)chunk_remain); - return false; - } + TRY(i2c_wait_until_flag(priv, I2C_ISR_TXIS, 1)); uint8_t byte = *bytes++; LL_I2C_TransmitData8(priv->periph, byte); } } - if (!i2c_wait_until_flag(priv, I2C_ISR_STOPF, 1)) { - dbg("STOPF TOUT"); - return false; - } + TRY(i2c_wait_until_flag(priv, I2C_ISR_STOPF, 1)); LL_I2C_ClearFlag_STOP(priv->periph); - return true; + return E_SUCCESS; } -bool UU_I2C_Read(Unit *unit, uint16_t addr, uint8_t *dest, uint32_t bcount) +error_t UU_I2C_Read(Unit *unit, uint16_t addr, uint8_t *dest, uint32_t bcount) { struct priv *priv = unit->data; @@ -346,19 +333,12 @@ bool UU_I2C_Read(Unit *unit, uint16_t addr, uint8_t *dest, uint32_t bcount) uint32_t ll_addrsize = (addrsize == 7) ? LL_I2C_ADDRSLAVE_7BIT : LL_I2C_ADDRSLAVE_10BIT; if (addrsize == 7) addr <<= 1; // 7-bit address must be shifted to left for LL to use it correctly - if (!i2c_wait_until_flag(priv, I2C_ISR_BUSY, 0)) { - dbg("BUSY TOUT"); - return false; - } + TRY(i2c_wait_until_flag(priv, I2C_ISR_BUSY, 0)); bool first = true; - uint32_t n = 0; while (bcount > 0) { if (!first) { - if (!i2c_wait_until_flag(priv, I2C_ISR_TCR, 1)) { - dbg("TCR TOUT"); - return false; - } + TRY(i2c_wait_until_flag(priv, I2C_ISR_TCR, 1)); } uint8_t chunk_remain = (uint8_t) ((bcount > 255) ? 255 : bcount); // if more than 255, first chunk is 255 @@ -369,116 +349,84 @@ bool UU_I2C_Read(Unit *unit, uint16_t addr, uint8_t *dest, uint32_t bcount) bcount -= chunk_remain; for (; chunk_remain > 0; chunk_remain--) { - if (!i2c_wait_until_flag(priv, I2C_ISR_RXNE, 1)) { - dbg("RXNE TOUT"); - return false; - } + TRY(i2c_wait_until_flag(priv, I2C_ISR_RXNE, 1)); uint8_t byte = LL_I2C_ReceiveData8(priv->periph); *dest++ = byte; } } - if (!i2c_wait_until_flag(priv, I2C_ISR_STOPF, 1)) { - dbg("STOPF TOUT"); - return false; - } + TRY(i2c_wait_until_flag(priv, I2C_ISR_STOPF, 1)); LL_I2C_ClearFlag_STOP(priv->periph); - return true; + return E_SUCCESS; } -bool UU_I2C_ReadReg(Unit *unit, uint16_t addr, uint8_t regnum, uint8_t *dest, uint32_t width) +error_t UU_I2C_ReadReg(Unit *unit, uint16_t addr, uint8_t regnum, uint8_t *dest, uint32_t width) { - if (!UU_I2C_Write(unit, addr, ®num, 1)) { - return false; - } - - // we read the register as if it was a unsigned integer - if (!UU_I2C_Read(unit, addr, (uint8_t *) unit_tmp512, width)) { - return false; - } - - return true; + TRY(UU_I2C_Write(unit, addr, ®num, 1)); + TRY(UU_I2C_Read(unit, addr, dest, width)); + return E_SUCCESS; } -bool UU_I2C_WriteReg(Unit *unit, uint16_t addr, uint8_t regnum, const uint8_t *bytes, uint32_t width) +error_t UU_I2C_WriteReg(Unit *unit, uint16_t addr, uint8_t regnum, const uint8_t *bytes, uint32_t width) { + // we have to insert the address first - needs a buffer (XXX realistically the buffer needs 1-4 bytes + addr) PayloadBuilder pb = pb_start((uint8_t*)unit_tmp512, 512, NULL); pb_u8(&pb, regnum); pb_buf(&pb, bytes, width); - if (!UU_I2C_Write(unit, addr, (uint8_t *) unit_tmp512, pb_length(&pb))) { - return false; - } - - return true; + TRY(UU_I2C_Write(unit, addr, (uint8_t *) unit_tmp512, pb_length(&pb))); + return E_SUCCESS; } /** Handle a request message */ -static bool UI2C_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) +static error_t UI2C_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) { - struct priv *priv = unit->data; - uint16_t addr; uint32_t len; + uint8_t regnum; + uint32_t size; - // 10-bit address has the highest bit set to 1 to indicate this - - uint8_t regnum; // register number - uint32_t size; // register width + // NOTE: 10-bit addresses must have the highest bit set to 1 for indication (0x8000 | addr) switch (command) { + /** Write byte(s) - addr:u16, byte(s) */ case CMD_WRITE: addr = pp_u16(pp); const uint8_t *bb = pp_tail(pp, &len); - if (!UU_I2C_Write(unit, addr, bb, len)) { - com_respond_err(frame_id, "TX FAIL"); - return false; - } - break; + return UU_I2C_Write(unit, addr, bb, len); + /** Read byte(s) - addr:u16, len:u16 */ case CMD_READ: addr = pp_u16(pp); len = pp_u16(pp); - if (!UU_I2C_Read(unit, addr, (uint8_t *) unit_tmp512, len)) { - com_respond_err(frame_id, "RX FAIL"); - return false; - } + TRY(UU_I2C_Read(unit, addr, (uint8_t *) unit_tmp512, len)); com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, len); - break; + return E_SUCCESS; + /** Read register(s) - addr:u16, reg:u8, size:u16 */ case CMD_READ_REG:; addr = pp_u16(pp); regnum = pp_u8(pp); // register number - size = pp_u8(pp); // total number of bytes to read (allows use of auto-increment) + size = pp_u16(pp); // total number of bytes to read (allows use of auto-increment) - if (!UU_I2C_ReadReg(unit, addr, regnum, (uint8_t *) unit_tmp512, size)) { - com_respond_err(frame_id, "READ REG FAIL"); - return false; - } + TRY(UU_I2C_ReadReg(unit, addr, regnum, (uint8_t *) unit_tmp512, size)); com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, size); - break; + return E_SUCCESS; + /** Write a register - addr:u16, reg:u8, byte(s) */ case CMD_WRITE_REG: addr = pp_u16(pp); regnum = pp_u8(pp); // register number - const uint8_t *tail = pp_tail(pp, &size); - if (!UU_I2C_WriteReg(unit, addr, regnum, tail, size)) { - com_respond_err(frame_id, "WRITE REG FAIL"); - return false; - } - break; + return UU_I2C_WriteReg(unit, addr, regnum, tail, size); default: - com_respond_bad_cmd(frame_id); - return false; + return E_UNKNOWN_COMMAND; } - - return true; } // ------------------------------------------------------------------------ diff --git a/units/i2c/unit_i2c.h b/units/i2c/unit_i2c.h index 1301710..4d65ef7 100644 --- a/units/i2c/unit_i2c.h +++ b/units/i2c/unit_i2c.h @@ -20,7 +20,7 @@ extern const UnitDriver UNIT_I2C; * @param bcount - byte count * @return success */ -bool UU_I2C_Write(Unit *unit, uint16_t addr, const uint8_t *bytes, uint32_t bcount); +error_t UU_I2C_Write(Unit *unit, uint16_t addr, const uint8_t *bytes, uint32_t bcount); /** * Raw read from I2C @@ -31,7 +31,7 @@ bool UU_I2C_Write(Unit *unit, uint16_t addr, const uint8_t *bytes, uint32_t bcou * @param bcount - byte count * @return success */ -bool UU_I2C_Read(Unit *unit, uint16_t addr, uint8_t *dest, uint32_t bcount); +error_t UU_I2C_Read(Unit *unit, uint16_t addr, uint8_t *dest, uint32_t bcount); /** * Read one or more registers from a I2C register-based device with auto-increment. @@ -43,7 +43,7 @@ bool UU_I2C_Read(Unit *unit, uint16_t addr, uint8_t *dest, uint32_t bcount); * @param width - register width (or multiple consecutive registers total size) * @return success */ -bool UU_I2C_ReadReg(Unit *unit, uint16_t addr, uint8_t regnum, uint8_t *dest, uint32_t width); +error_t UU_I2C_ReadReg(Unit *unit, uint16_t addr, uint8_t regnum, uint8_t *dest, uint32_t width); /** * Write a register value @@ -55,7 +55,7 @@ bool UU_I2C_ReadReg(Unit *unit, uint16_t addr, uint8_t regnum, uint8_t *dest, ui * @param width - register width (number of bytes) * @return success */ -bool UU_I2C_WriteReg(Unit *unit, uint16_t addr, uint8_t regnum, const uint8_t *bytes, uint32_t width); +error_t UU_I2C_WriteReg(Unit *unit, uint16_t addr, uint8_t regnum, const uint8_t *bytes, uint32_t width); /** * Write a 8-bit register value @@ -66,7 +66,7 @@ bool UU_I2C_WriteReg(Unit *unit, uint16_t addr, uint8_t regnum, const uint8_t *b * @param value - byte to write to the register * @return success */ -static inline bool UU_I2C_WriteReg8(Unit *unit, uint16_t addr, uint8_t regnum, uint8_t value) +static inline error_t UU_I2C_WriteReg8(Unit *unit, uint16_t addr, uint8_t regnum, uint8_t value) { return UU_I2C_WriteReg(unit, addr, regnum, &value, 1); } diff --git a/units/neopixel/unit_neopixel.c b/units/neopixel/unit_neopixel.c index 30f9c62..7c15754 100644 --- a/units/neopixel/unit_neopixel.c +++ b/units/neopixel/unit_neopixel.c @@ -43,7 +43,7 @@ static void Npx_writeBinary(Unit *unit, PayloadBuilder *pb) // ------------------------------------------------------------------------ /** Parse a key-value pair from the INI file */ -static bool Npx_loadIni(Unit *unit, const char *key, const char *value) +static error_t Npx_loadIni(Unit *unit, const char *key, const char *value) { bool suc = true; struct priv *priv = unit->data; @@ -55,10 +55,11 @@ static bool Npx_loadIni(Unit *unit, const char *key, const char *value) priv->pixels = (uint16_t) avr_atoi(value); } else { - return false; + return E_BAD_KEY; } - return suc; + if (!suc) return E_BAD_VALUE; + return E_SUCCESS; } /** Generate INI file section for the unit */ @@ -76,22 +77,22 @@ static void Npx_writeIni(Unit *unit, IniWriter *iw) // ------------------------------------------------------------------------ /** Allocate data structure and set defaults */ -static bool Npx_preInit(Unit *unit) +static error_t Npx_preInit(Unit *unit) { bool suc = true; struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); - CHECK_SUC(); + if (!suc) return E_OUT_OF_MEM; // some defaults priv->pin_number = 0; priv->port_name = 'A'; priv->pixels = 1; - return true; + return E_SUCCESS; } /** Finalize unit set-up */ -static bool Npx_init(Unit *unit) +static error_t Npx_init(Unit *unit) { bool suc = true; struct priv *priv = unit->data; @@ -100,13 +101,10 @@ static bool Npx_init(Unit *unit) priv->ll_pin = pin2ll(priv->pin_number, &suc); priv->port = port2periph(priv->port_name, &suc); Resource rsc = pin2resource(priv->port_name, priv->pin_number, &suc); - if (!suc) { - unit->status = E_BAD_CONFIG; - return false; - } + if (!suc) return E_BAD_CONFIG; // --- Claim resources --- - if (!rsc_claim(unit, rsc)) return false; + TRY(rsc_claim(unit, rsc)); // --- Init hardware --- LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT); @@ -117,7 +115,7 @@ static bool Npx_init(Unit *unit) ws2812_clear(priv->port, priv->ll_pin, priv->pixels); - return true; + return E_SUCCESS; } /** Tear down the unit */ @@ -140,6 +138,51 @@ static void Npx_deInit(Unit *unit) // ------------------------------------------------------------------------ +/* Clear the strip */ +error_t UU_NEOPIXEL_Clear(Unit *unit) +{ + struct priv *priv = unit->data; + ws2812_clear(priv->port, priv->ll_pin, priv->pixels); + return E_SUCCESS; +} + +/* Load packed */ +error_t UU_NEOPIXEL_Load(Unit *unit, const uint8_t *packed_rgb, uint32_t nbytes) +{ + struct priv *priv = unit->data; + if (nbytes != 3*priv->pixels) return E_BAD_COUNT; + ws2812_load_raw(priv->port, priv->ll_pin, packed_rgb, priv->pixels); + return E_SUCCESS; +} + +/* Load U32, LE or BE */ +static error_t load_u32(Unit *unit, const uint8_t *bytes, uint32_t nbytes, bool bige) +{ + struct priv *priv = unit->data; + if (nbytes != 4*priv->pixels) return E_BAD_COUNT; + ws2812_load_sparse(priv->port, priv->ll_pin, bytes, priv->pixels, bige); + return E_SUCCESS; +} + +/* Load U32, LE */ +inline error_t UU_NEOPIXEL_LoadU32LE(Unit *unit, const uint8_t *bytes, uint32_t nbytes) +{ + return load_u32(unit, bytes, nbytes, false); +} + +/* Load U32, BE */ +inline error_t UU_NEOPIXEL_LoadU32BE(Unit *unit, const uint8_t *bytes, uint32_t nbytes) +{ + return load_u32(unit, bytes, nbytes, true); +} + +/* Get the pixel count */ +inline uint16_t UU_NEOPIXEL_GetCount(Unit *unit) +{ + struct priv *priv = unit->data; + return priv->pixels; +} + enum PinCmd_ { CMD_CLEAR = 0, CMD_LOAD = 1, @@ -149,46 +192,39 @@ enum PinCmd_ { }; /** Handle a request message */ -static bool Npx_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) +static error_t Npx_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) { - (void)pp; - - struct priv *priv = unit->data; + uint32_t len; + const uint8_t *bytes; switch (command) { + /** Clear the entire strip */ case CMD_CLEAR: - ws2812_clear(priv->port, priv->ll_pin, priv->pixels); - break; + return UU_NEOPIXEL_Clear(unit); - case CMD_LOAD: - if (pp_length(pp) != priv->pixels*3) goto bad_count; - ws2812_load_raw(priv->port, priv->ll_pin, pp->current, priv->pixels); - break; + /** Load packed RGB colors (length must match the strip size) */ + case CMD_LOAD:; + bytes = pp_tail(pp, &len); + return UU_NEOPIXEL_Load(unit, bytes, len); + /** Load sparse (uint32_t) colors, 0x00RRGGBB, little endian. */ case CMD_LOAD_U32_LE: - if (pp_length(pp) != priv->pixels*4) goto bad_count; - ws2812_load_sparse(priv->port, priv->ll_pin, pp->current, priv->pixels, 0); - break; + bytes = pp_tail(pp, &len); + return UU_NEOPIXEL_LoadU32LE(unit, bytes, len); + /** Load sparse (uint32_t) colors, 0x00RRGGBB, big endian. */ case CMD_LOAD_U32_BE: - if (pp_length(pp) != priv->pixels*4) goto bad_count; - ws2812_load_sparse(priv->port, priv->ll_pin, pp->current, priv->pixels, 1); - break; + bytes = pp_tail(pp, &len); + return UU_NEOPIXEL_LoadU32BE(unit, bytes, len); + /** Get the Neopixel strip length */ case CMD_GET_LEN: - com_respond_u16(frame_id, priv->pixels); - break; + com_respond_u16(frame_id, UU_NEOPIXEL_GetCount(unit)); + return E_SUCCESS; default: - com_respond_bad_cmd(frame_id); - return false; + return E_UNKNOWN_COMMAND; } - - return true; - -bad_count: - com_respond_err(frame_id, "BAD PIXEL COUNT"); - return false; } // ------------------------------------------------------------------------ diff --git a/units/neopixel/unit_neopixel.h b/units/neopixel/unit_neopixel.h index 11d4980..24613ef 100644 --- a/units/neopixel/unit_neopixel.h +++ b/units/neopixel/unit_neopixel.h @@ -9,4 +9,44 @@ extern const UnitDriver UNIT_NEOPIXEL; +/** + * Clear the Neopixel strip + * + * @param unit + * @return success + */ +error_t UU_NEOPIXEL_Clear(Unit *unit); + +/** + * Load the strip with packed bytes R,G,B. + * + * @param unit + * @param packed_rgb - bytes to load + * @param nbytes - number of bytes, must be count*3 + * @return success + */ +error_t UU_NEOPIXEL_Load(Unit *unit, const uint8_t *packed_rgb, uint32_t nbytes); + +/** + * Load the strip with sparse (uint32_t) colors 0x00RRGGBB as little endian bytes + * (B, G, R, 0, ...) + * + * @param unit + * @param bytes - bytes to load + * @param nbytes - number of bytes, must be count*4 + * @return success + */ +error_t UU_NEOPIXEL_LoadU32LE(Unit *unit, const uint8_t *bytes, uint32_t nbytes); + +/** + * Load the strip with sparse (uint32_t) colors 0x00RRGGBB as big endian bytes + * (0, R, G, B, ...) + * + * @param unit + * @param bytes - bytes to load + * @param nbytes - number of bytes, must be count*4 + * @return success + */ +error_t UU_NEOPIXEL_LoadU32BE(Unit *unit, const uint8_t *bytes, uint32_t nbytes); + #endif //U_NEOPIXEL_H diff --git a/units/neopixel/ws2812.c b/units/neopixel/ws2812.c index 3ff9eaa..81e6b28 100644 --- a/units/neopixel/ws2812.c +++ b/units/neopixel/ws2812.c @@ -28,7 +28,7 @@ void ws2812_byte(GPIO_TypeDef *port, uint32_t ll_pin, uint8_t b) } /** Set many RGBs from packed stream */ -void ws2812_load_raw(GPIO_TypeDef *port, uint32_t ll_pin, uint8_t *rgbs, uint32_t count) +void ws2812_load_raw(GPIO_TypeDef *port, uint32_t ll_pin, const uint8_t *rgbs, uint32_t count) { vPortEnterCritical(); uint8_t b, g, r; @@ -45,7 +45,7 @@ void ws2812_load_raw(GPIO_TypeDef *port, uint32_t ll_pin, uint8_t *rgbs, uint32_ } /** Set many RGBs from uint32 stream */ -void ws2812_load_sparse(GPIO_TypeDef *port, uint32_t ll_pin, uint8_t *rgbs, uint32_t count, bool bigendian) +void ws2812_load_sparse(GPIO_TypeDef *port, uint32_t ll_pin, const uint8_t *rgbs, uint32_t count, bool bigendian) { vPortEnterCritical(); uint8_t b, g, r; diff --git a/units/neopixel/ws2812.h b/units/neopixel/ws2812.h index 0278767..b692f10 100644 --- a/units/neopixel/ws2812.h +++ b/units/neopixel/ws2812.h @@ -11,7 +11,7 @@ * @param rgbs - packed R,G,B, R,G,B, ... array * @param count - number of pixels (triplets) */ -void ws2812_load_raw(GPIO_TypeDef *port, uint32_t ll_pin, uint8_t *rgbs, uint32_t count); +void ws2812_load_raw(GPIO_TypeDef *port, uint32_t ll_pin, const uint8_t *rgbs, uint32_t count); /** * Load all pixels with BLACK (0,0,0) @@ -30,6 +30,6 @@ void ws2812_clear(GPIO_TypeDef *port, uint32_t ll_pin, uint32_t count); * @param count - number of pixels * @param bigendian - big endian ordering */ -void ws2812_load_sparse(GPIO_TypeDef *port, uint32_t ll_pin, uint8_t *rgbs, uint32_t count, bool bigendian); +void ws2812_load_sparse(GPIO_TypeDef *port, uint32_t ll_pin, const uint8_t *rgbs, uint32_t count, bool bigendian); #endif //WS2812_H diff --git a/units/test/unit_test.c b/units/test/unit_test.c index dc73409..51ce0b6 100644 --- a/units/test/unit_test.c +++ b/units/test/unit_test.c @@ -32,14 +32,9 @@ static void Tst_writeBinary(Unit *unit, PayloadBuilder *pb) // ------------------------------------------------------------------------ /** Parse a key-value pair from the INI file */ -static bool Tst_loadIni(Unit *unit, const char *key, const char *value) +static error_t Tst_loadIni(Unit *unit, const char *key, const char *value) { - bool suc = true; - struct priv *priv = unit->data; - - // - - return suc; + return E_BAD_KEY; } /** Generate INI file section for the unit */ @@ -53,26 +48,26 @@ static void Tst_writeIni(Unit *unit, IniWriter *iw) // ------------------------------------------------------------------------ /** Allocate data structure and set defaults */ -static bool Tst_preInit(Unit *unit) +static error_t Tst_preInit(Unit *unit) { bool suc = true; struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); - CHECK_SUC(); + if (!suc) return E_OUT_OF_MEM; // - return true; + return E_SUCCESS; } /** Finalize unit set-up */ -static bool Tst_init(Unit *unit) +static error_t Tst_init(Unit *unit) { bool suc = true; struct priv *priv = unit->data; // - return true; + return E_SUCCESS; } /** Tear down the unit */ @@ -124,22 +119,18 @@ static void bw_dump(struct bulk_write *bulk, const uint8_t *chunk, uint32_t len) } /** Handle a request message */ -static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) +static error_t Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) { - (void)pp; - - struct priv *priv = unit->data; - switch (command) { case CMD_PING: com_respond_ok(frame_id); - break; + return E_SUCCESS; case CMD_ECHO:; uint32_t len; const uint8_t *data = pp_tail(pp, &len); com_respond_buf(frame_id, MSG_SUCCESS, data, len); - break; + return E_SUCCESS; case CMD_BULKREAD:; BulkRead *br = malloc(sizeof(struct bulk_read)); @@ -150,7 +141,7 @@ static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo br->read = br_longtext; bulkread_start(comm, br); - break; + return E_SUCCESS; case CMD_BULKWRITE:; BulkWrite *bw = malloc(sizeof(struct bulk_write)); @@ -161,14 +152,11 @@ static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo bw->write = bw_dump; bulkwrite_start(comm, bw); - break; + return E_SUCCESS; default: - com_respond_bad_cmd(frame_id); - return false; + return E_UNKNOWN_COMMAND; } - - return true; } // ------------------------------------------------------------------------ diff --git a/utils/error.c b/utils/error.c index c8abefa..b8b81b1 100644 --- a/utils/error.c +++ b/utils/error.c @@ -21,6 +21,13 @@ #include "platform.h" +static const char *const error_names[] = { +#define X(name, text) STR(name), + X_ERROR_CODES +#undef X +}; +COMPILER_ASSERT(ERROR_COUNT == ELEMENTS_IN_ARRAY(error_names)); + static const char *const error_message[] = { #define X(name, text) text, X_ERROR_CODES @@ -28,18 +35,33 @@ static const char *const error_message[] = { }; COMPILER_ASSERT(ERROR_COUNT == ELEMENTS_IN_ARRAY(error_message)); -const char *error_get_string(error_t error) +const char *error_get_message(error_t error) { - const char *msg = 0; + const char *msg = NULL; if (error < ERROR_COUNT) { msg = error_message[error]; } - if (0 == msg) { - assert_param(0); - msg = ""; + if (NULL == msg) { + return error_get_name(error); } return msg; } + +const char *error_get_name(error_t error) +{ + const char *name = 0; + + if (error < ERROR_COUNT) { + name = error_names[error]; + } + + if (0 == name) { + dbg("%d", (int)error); + trap("MISSING ERROR NAME"); + } + + return name; +} diff --git a/utils/error.h b/utils/error.h index 936523e..1b004a2 100644 --- a/utils/error.h +++ b/utils/error.h @@ -26,25 +26,35 @@ } #endif +// fields: name, msg. If msg is NULL, name as string will be used instead. #define X_ERROR_CODES \ /* Shared errors */ \ - X(SUCCESS,"OK") \ - X(FAILURE,"Failure") \ - X(INTERNAL,"Internal error") \ - X(LOADING,"Init in progress") \ + X(SUCCESS, NULL) /* operation succeeded / unit loaded */ \ + X(FAILURE, NULL) /* generic error */ \ + X(INTERNAL_ERROR, NULL) /* a bug */ \ + X(LOADING, NULL) /* unit is loading */ \ + X(UNKNOWN_COMMAND, NULL) \ + X(BAD_COUNT, NULL) \ + X(MALFORMED_COMMAND, NULL) \ + X(NOT_APPLICABLE, NULL) \ + X(HW_TIMEOUT, NULL) \ + X(NO_SUCH_UNIT, NULL) \ + X(OVERRUN, NULL) /* used in bulk transfer */ \ + X(PROTOCOL_BREACH, NULL) /* eating with the wrong spoon */ \ \ - /* VFS user errors */ \ - X(ERROR_DURING_TRANSFER,"Error during transfer") \ - X(TRANSFER_TIMEOUT,"Transfer timed out") \ - /*X(FILE_BOUNDS,"Possible mismatch between file size and size programmed")*/ \ - X(OOO_SECTOR,"File sent out of order by PC") \ + /* VFS user errors (those are meant to be shown to user) */ \ + X(ERROR_DURING_TRANSFER, "Error during transfer") \ + X(TRANSFER_TIMEOUT, "Transfer timed out") \ + X(OOO_SECTOR, "File sent out of order by PC") \ \ - /* File stream errors */ \ - X(SUCCESS_DONE,"End of stream") \ - X(SUCCESS_DONE_OR_CONTINUE,"End of stream, or more to come") \ + /* File stream errors/status */ \ + X(SUCCESS_DONE, NULL) \ + X(SUCCESS_DONE_OR_CONTINUE, NULL) \ \ /* Unit loading */ \ X(BAD_CONFIG, "Configuration error") \ + X(BAD_KEY, "Unexpected config key") \ + X(BAD_VALUE, "Bad config value") \ X(OUT_OF_MEM, "Not enough RAM") \ X(RESOURCE_NOT_AVAILABLE, "Required pin / peripheral not available") @@ -56,7 +66,15 @@ typedef enum { ERROR_COUNT } error_t; -const char *error_get_string(error_t error) __attribute__((pure)); +const char *error_get_message(error_t error) __attribute__((pure)); +const char *error_get_name(error_t error) __attribute__((pure)); + +/** Check return value and return it if not E_SUCCESS */ +#define TRY(call) do { \ + error_t _rv; \ + _rv = call; \ + if (E_SUCCESS != _rv) return _rv; \ +} while (0) #ifdef __cplusplus } diff --git a/vfs/file_stream.c b/vfs/file_stream.c index 08580bb..482787d 100644 --- a/vfs/file_stream.c +++ b/vfs/file_stream.c @@ -100,16 +100,16 @@ error_t stream_open(stream_type_t stream_type) // Stream must not be open already if (stream_state != STREAM_STATE_CLOSED) { - vfs_printf("!! Stream is not closed, cant open"); - assert_param(0); - return E_INTERNAL; + trap("!! Stream is not closed, cant open"); +// assert_param(0); +// return E_INTERNAL; } // Stream must be of a supported type if (stream_type >= STREAM_TYPE_COUNT) { - vfs_printf("!! Stream bad type"); - assert_param(0); - return E_INTERNAL; + trap("!! Stream bad type"); +// assert_param(0); +// return E_INTERNAL; } Indicator_Effect(STATUS_DISK_BUSY); @@ -136,9 +136,9 @@ error_t stream_write(const uint8_t *data, uint32_t size) // Stream must be open already if (stream_state != STREAM_STATE_OPEN) { - vfs_printf("!! Stream is not open, cant write"); - assert_param(0); - return E_INTERNAL; + trap("!! Stream is not open, cant write"); +// assert_param(0); +// return E_INTERNAL; } // Check thread after checking state since the stream thread is @@ -169,9 +169,9 @@ error_t stream_close(void) // Stream must not be closed already if (STREAM_STATE_CLOSED == stream_state) { - vfs_printf("!! Stream already closed"); - assert_param(0); - return E_INTERNAL; + trap("!! Stream already closed"); +// assert_param(0); +// return E_INTERNAL; } // Check thread after checking state since the stream thread is diff --git a/vfs/vfs_manager.c b/vfs/vfs_manager.c index 2aa238e..152c915 100644 --- a/vfs/vfs_manager.c +++ b/vfs/vfs_manager.c @@ -941,7 +941,8 @@ static void transfer_update_state(error_t status) // Set the fail reason fail_reason = local_status; - vfs_printf(" Transfer finished, status: %i=%s\r\n", fail_reason, error_get_string(fail_reason)); + vfs_printf(" Transfer finished, status: %i=%s\r\n", fail_reason, + error_get_message(fail_reason)); } // If this state change is not from aborting a transfer