Rewrite all units and other logic to better use return values and added TRY() helper

sipo
Ondřej Hruška 6 years ago
parent 465242a0f1
commit ab2dfe3a76
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 4
      comm/msg_bulkwrite.c
  2. 12
      comm/msg_responses.c
  3. 39
      comm/msg_responses.h
  4. 31
      framework/resources.c
  5. 15
      framework/resources.h
  6. 5
      framework/settings.c
  7. 9
      framework/unit.h
  8. 58
      framework/unit_registry.c
  9. 2
      framework/unit_registry.h
  10. 35
      units/digital_in/unit_din.c
  11. 42
      units/digital_out/unit_dout.c
  12. 168
      units/i2c/unit_i2c.c
  13. 10
      units/i2c/unit_i2c.h
  14. 114
      units/neopixel/unit_neopixel.c
  15. 40
      units/neopixel/unit_neopixel.h
  16. 4
      units/neopixel/ws2812.c
  17. 4
      units/neopixel/ws2812.h
  18. 38
      units/test/unit_test.c
  19. 32
      utils/error.c
  20. 44
      utils/error.h
  21. 24
      vfs/file_stream.c
  22. 3
      vfs/vfs_manager.c

@ -28,9 +28,9 @@ static TF_Result bulkwrite_lst(TinyFrame *tf, TF_Msg *msg)
goto close; goto close;
} }
else if (msg->type == MSG_BULK_DATA || msg->type == MSG_BULK_END) { 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) { if (bulk->offset >= bulk->len) {
com_respond_err(bulk->frame_id, "WRITE OVERRUN"); com_respond_error(bulk->frame_id, E_OVERRUN);
goto close; goto close;
} }

@ -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); 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) 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_error(TF_ID frame_id, error_t error)
void com_respond_malformed_cmd(TF_ID frame_id)
{ {
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));
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

@ -11,7 +11,6 @@
/** /**
* Respond to a TF message using printf-like formatting. * Respond to a TF message using printf-like formatting.
* Works synchronously, must be called on a job queue.
* *
* @param type - response type byte * @param type - response type byte
* @param frame_id - ID of the original msg * @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. * 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 type - response type byte
* @param frame_id - ID of the original msg * @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. * 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 * @param frame_id - ID of the original msg
*/ */
void com_respond_ok(TF_ID frame_id); 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. * 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 type - response type byte
* @param buf - byte buffer * @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. * Same like tf_respond_buf(), but the buffer length is measured with strlen.
* Used to sending ASCII string responses. * Used to sending ASCII string responses.
* Works synchronously, must be called on a job queue.
* *
* @param type - response type byte * @param type - response type byte
* @param frame_id - ID of the original msg * @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); 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. * Schedule sending a one-byte response with MSG_SUCCESS type.
* Schedules a high priority job.
* *
* @param frame_id - ID of the original msg * @param frame_id - ID of the original msg
* @param d - data * @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. * Schedule sending a two-byte response with MSG_SUCCESS type.
* Schedules a high priority job.
* *
* @param frame_id - ID of the original msg * @param frame_id - ID of the original msg
* @param d - data * @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. * Schedule sending a 4-byte response with MSG_SUCCESS type.
* Schedules a high priority job.
* *
* @param frame_id - ID of the original msg * @param frame_id - ID of the original msg
* @param d - data * @param d - data

@ -42,7 +42,7 @@ void rsc_init_registry(void)
* @param rsc - resource to claim * @param rsc - resource to claim
* @return true on successful 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_initialized);
assert_param(rsc > R_NONE && rsc < R_RESOURCE_COUNT); 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!", dbg("ERROR!! Unit %s failed to claim resource %s, already held by %s!",
unit->name, rsc_names[rsc], resources[rsc].owner->name); unit->name, rsc_names[rsc], resources[rsc].owner->name);
unit->status = E_RESOURCE_NOT_AVAILABLE; return E_RESOURCE_NOT_AVAILABLE;
return false;
} }
resources[rsc].owner = unit; 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 * @param rsc1 - last resource to claim
* @return true on complete claim, false if any failed (none are claimed in that case) * @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(rsc_initialized);
assert_param(rsc0 > R_NONE && rsc0 < R_RESOURCE_COUNT); 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); assert_param(unit != NULL);
for (int i = rsc0; i <= rsc1; i++) { 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; bool suc = true;
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
if (pins & (1 << i)) { if (pins & (1 << i)) {
Resource rsc = pin2resource(port_name, (uint8_t) i, &suc); Resource rsc = pin2resource(port_name, (uint8_t) i, &suc);
if (!suc) { if (!suc) return E_BAD_CONFIG;
unit->status = E_BAD_CONFIG;
// rsc_teardown(unit); TRY(rsc_claim(unit, rsc));
return false;
}
suc = rsc_claim(unit, rsc);
if (!suc) {
// rsc_teardown(unit);
return false;
}
} }
} }
return true; return E_SUCCESS;
} }
/** /**

@ -81,13 +81,8 @@ enum hw_resource {
void rsc_init_registry(void); void rsc_init_registry(void);
bool rsc_claim(Unit *unit, Resource rsc); error_t rsc_claim(Unit *unit, Resource rsc);
bool rsc_claim_range(Unit *unit, Resource rsc0, Resource rsc1); error_t 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);
/** /**
* Claim GPIOs by bitmask and port name, atomically. * Claim GPIOs by bitmask and port name, atomically.
* Tear down the unit on failure. * Tear down the unit on failure.
@ -97,6 +92,10 @@ void rsc_free_range(Unit *unit, Resource rsc0, Resource rsc1);
* @param pins - pins, bitmask * @param pins - pins, bitmask
* @return success * @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 #endif //GEX_RESOURCES_H

@ -308,8 +308,9 @@ void settings_load_ini_key(const char *restrict section, const char *restrict ke
namebuf[csptr - nameptr - 1] = 0; namebuf[csptr - nameptr - 1] = 0;
uint8_t cs = (uint8_t) avr_atoi(csptr + 1); uint8_t cs = (uint8_t) avr_atoi(csptr + 1);
bool res = ureg_load_unit_ini_key(namebuf, key, value, cs); error_t rv = ureg_load_unit_ini_key(namebuf, key, value, cs);
if (!res) dbg("!! error loading %s@%d.%s = %s", namebuf, (int)cs, key, value); if (rv != E_SUCCESS)
dbg("!! error loading %s@%d.%s = %s - error %s", namebuf, (int)cs, key, value, error_get_message(rv));
} else { } else {
dbg("! Bad config key: [%s] %s = %s", section, key, value); dbg("! Bad config key: [%s] %s = %s", section, key, value);
} }

@ -48,7 +48,7 @@ struct unit_driver {
/** /**
* Pre-init: allocate data object, init defaults * 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. * 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 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 * @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. * Export settings to a INI file.
* Capacity will likely be 512 bytes, do not waste space!
* *
* @param buffer - destination buffer * @param buffer - destination buffer
* @param capacity - buffer size * @param capacity - buffer size
@ -88,7 +87,7 @@ struct unit_driver {
/** /**
* Finalize the init sequence, validate settings, enable peripherals and prepare for operation * 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... * 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. * 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);
}; };
/** /**

@ -100,6 +100,7 @@ static void add_unit_to_list(UlistEntry *le)
Unit *ureg_instantiate(const char *driver_name) Unit *ureg_instantiate(const char *driver_name)
{ {
bool suc = true; bool suc = true;
error_t rv;
// Find type in the repository // Find type in the repository
UregEntry *re = ureg_head; UregEntry *re = ureg_head;
@ -113,19 +114,19 @@ Unit *ureg_instantiate(const char *driver_name)
Unit *pUnit = &le->unit; Unit *pUnit = &le->unit;
pUnit->driver = re->driver; pUnit->driver = re->driver;
pUnit->status = E_LOADING; pUnit->status = E_LOADING; // indeterminate default state
pUnit->data = NULL; pUnit->data = NULL;
pUnit->callsign = 0; pUnit->callsign = 0;
suc = pUnit->driver->preInit(pUnit); rv = pUnit->driver->preInit(pUnit);
if (!suc) { if (rv != E_SUCCESS) {
// tear down what we already allocated and abort // tear down what we already allocated and abort
// If it failed this early, the only plausible explanation is failed malloc, // If it failed this early, the only plausible explanation is failed malloc,
// in which case the data structure is not populated and keeping the // in which case the data structure is not populated and keeping the
// broken unit doesn't serve any purpose. Just ditch it... // 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); clean_failed_unit(pUnit);
free(le); free(le);
return NULL; return NULL;
@ -219,9 +220,9 @@ bool ureg_load_units(PayloadParser *pp)
dbg("Adding unit \"%s\" of type %s", pUnit->name, pUnit->driver->name); dbg("Adding unit \"%s\" of type %s", pUnit->name, pUnit->driver->name);
suc = pUnit->driver->init(pUnit); // finalize the load and init the unit pUnit->status = pUnit->driver->init(pUnit); // finalize the load and init the unit
if (pUnit->status == E_LOADING) { if (pUnit->status != E_SUCCESS) {
pUnit->status = suc ? E_SUCCESS : E_BAD_CONFIG; dbg("!!! error initing unit %s: %s", pUnit->name, error_get_message(pUnit->status));
} }
} // end unit } // end unit
} }
@ -298,7 +299,7 @@ bool ureg_instantiate_by_ini(const char *restrict driver_name, const char *restr
} }
/** Load unit key-value */ /** 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 key,
const char *restrict value, const char *restrict value,
uint8_t callsign) uint8_t callsign)
@ -313,10 +314,10 @@ bool ureg_load_unit_ini_key(const char *restrict name,
li = li->next; 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) bool ureg_finalize_all_init(void)
{ {
dbg("Finalizing units init..."); dbg("Finalizing units init...");
@ -326,18 +327,13 @@ bool ureg_finalize_all_init(void)
while (li != NULL) { while (li != NULL) {
Unit *const pUnit = &li->unit; Unit *const pUnit = &li->unit;
bool s = pUnit->driver->init(pUnit); pUnit->status = pUnit->driver->init(pUnit);
if (!s) { if (pUnit->status != E_SUCCESS) {
dbg("!!!! error initing unit %s", pUnit->name); dbg("!!! error initing unit %s: %s", pUnit->name, error_get_message(pUnit->status));
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;
} }
// try to assign unique callsigns // try to assign unique callsigns
// FIXME this is wrong, sometimes leads to duplicate CS
if (pUnit->callsign == 0) { if (pUnit->callsign == 0) {
pUnit->callsign = callsign++; pUnit->callsign = callsign++;
} else { } else {
@ -346,7 +342,7 @@ bool ureg_finalize_all_init(void)
} }
} }
suc &= s; suc &= (pUnit->status == E_SUCCESS);
li = li->next; li = li->next;
} }
return suc; 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); iw_section(iw, "%s:%s@%d", pUnit->driver->name, pUnit->name, (int)pUnit->callsign);
if (pUnit->status != E_SUCCESS) { 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); pUnit->driver->cfgWriteIni(pUnit, iw);
} }
@ -445,10 +441,8 @@ void ureg_deliver_unit_request(TF_Msg *msg)
bool confirmed = (bool) (command & 0x80); bool confirmed = (bool) (command & 0x80);
command &= 0x7F; command &= 0x7F;
if (!pp.ok) { dbg("!! pp not OK!"); }
if (callsign == 0 || !pp.ok) { if (callsign == 0 || !pp.ok) {
com_respond_malformed_cmd(msg->frame_id); com_respond_error(msg->frame_id, E_MALFORMED_COMMAND);
return; return;
} }
@ -456,12 +450,14 @@ void ureg_deliver_unit_request(TF_Msg *msg)
while (li != NULL) { while (li != NULL) {
Unit *const pUnit = &li->unit; Unit *const pUnit = &li->unit;
if (pUnit->callsign == callsign && pUnit->status == E_SUCCESS) { 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. // send extra SUCCESS confirmation message.
// error is expected to have already been reported. // error is expected to have already been reported.
if (ok && confirmed) { if (rv == E_SUCCESS) {
com_respond_ok(msg->frame_id); if (confirmed) com_respond_ok(msg->frame_id);
} else {
com_respond_error(msg->frame_id, rv);
} }
return; return;
} }
@ -469,7 +465,7 @@ void ureg_deliver_unit_request(TF_Msg *msg)
} }
// Not found // 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 */ /** Send a response for a unit-list request */
@ -492,7 +488,11 @@ void ureg_report_active_units(TF_ID frame_id)
bool suc = true; bool suc = true;
uint8_t *buff = malloc_ck(msglen, &suc); 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); PayloadBuilder pb = pb_start(buff, msglen, NULL);
pb_u8(&pb, (uint8_t) count); // assume we don't have more than 255 units pb_u8(&pb, (uint8_t) count); // assume we don't have more than 255 units

@ -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) * @param callsign - callsign (is part of the section string)
* @return success * @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 key,
const char *restrict value, const char *restrict value,
uint8_t callsign); uint8_t callsign);

@ -51,7 +51,7 @@ static void DI_writeBinary(Unit *unit, PayloadBuilder *pb)
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Parse a key-value pair from the INI file */ /** 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; bool suc = true;
struct priv *priv = unit->data; 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")) { else if (streq(key, "pull-down")) {
priv->pulldown = parse_pinmask(value, &suc); priv->pulldown = parse_pinmask(value, &suc);
dbg("parsinf ini, pulldown = %X", priv->pulldown);
} }
else { 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 */ /** 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 */ /** Allocate data structure and set defaults */
static bool DI_preInit(Unit *unit) static error_t DI_preInit(Unit *unit)
{ {
bool suc = true; bool suc = true;
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc);
CHECK_SUC(); if (!suc) return E_OUT_OF_MEM;
// some defaults // some defaults
priv->port_name = 'A'; priv->port_name = 'A';
@ -113,11 +113,11 @@ static bool DI_preInit(Unit *unit)
priv->pulldown = 0x0000; priv->pulldown = 0x0000;
priv->pullup = 0x0000; priv->pullup = 0x0000;
return true; return E_SUCCESS;
} }
/** Finalize unit set-up */ /** Finalize unit set-up */
static bool DI_init(Unit *unit) static error_t DI_init(Unit *unit)
{ {
bool suc = true; bool suc = true;
struct priv *priv = unit->data; struct priv *priv = unit->data;
@ -127,14 +127,10 @@ static bool DI_init(Unit *unit)
// --- Parse config --- // --- Parse config ---
priv->port = port2periph(priv->port_name, &suc); priv->port = port2periph(priv->port_name, &suc);
if (!suc) { if (!suc) return E_BAD_CONFIG;
unit->status = E_BAD_CONFIG;
return false;
}
// Claim all needed pins // Claim all needed pins
suc = rsc_claim_gpios(unit, priv->port_name, priv->pins); TRY(rsc_claim_gpios(unit, priv->port_name, priv->pins));
CHECK_SUC();
uint16_t mask = 1; uint16_t mask = 1;
for (int i = 0; i < 16; i++, 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 */ /** 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; (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); PayloadBuilder pb = pb_start((uint8_t*)unit_tmp512, 64, NULL);
pb_u16(&pb, packed); pb_u16(&pb, packed);
com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, pb_length(&pb)); com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, pb_length(&pb));
break; return E_SUCCESS;
default: default:
com_respond_bad_cmd(frame_id); return E_UNKNOWN_COMMAND;
return false;
} }
return true;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

@ -48,7 +48,7 @@ static void DO_writeBinary(Unit *unit, PayloadBuilder *pb)
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Parse a key-value pair from the INI file */ /** 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; bool suc = true;
struct priv *priv = unit->data; 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); priv->open_drain = parse_pinmask(value, &suc);
} }
else { 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 */ /** 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 */ /** Allocate data structure and set defaults */
static bool DO_preInit(Unit *unit) static error_t DO_preInit(Unit *unit)
{ {
bool suc = true; bool suc = true;
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc);
CHECK_SUC(); if (!suc) return E_OUT_OF_MEM;
// some defaults // some defaults
priv->port_name = 'A'; priv->port_name = 'A';
@ -105,11 +106,11 @@ static bool DO_preInit(Unit *unit)
priv->open_drain = 0x0000; priv->open_drain = 0x0000;
priv->initial = 0x0000; priv->initial = 0x0000;
return true; return E_SUCCESS;
} }
/** Finalize unit set-up */ /** Finalize unit set-up */
static bool DO_init(Unit *unit) static error_t DO_init(Unit *unit)
{ {
bool suc = true; bool suc = true;
struct priv *priv = unit->data; struct priv *priv = unit->data;
@ -119,14 +120,10 @@ static bool DO_init(Unit *unit)
// --- Parse config --- // --- Parse config ---
priv->port = port2periph(priv->port_name, &suc); priv->port = port2periph(priv->port_name, &suc);
if (!suc) { if (!suc) return E_BAD_CONFIG;
unit->status = E_BAD_CONFIG;
return false;
}
// Claim all needed pins // Claim all needed pins
suc = rsc_claim_gpios(unit, priv->port_name, priv->pins); TRY(rsc_claim_gpios(unit, priv->port_name, priv->pins));
CHECK_SUC();
uint16_t mask = 1; uint16_t mask = 1;
for (int i = 0; i < 16; i++, 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->pins;
priv->port->ODR |= priv->initial; priv->port->ODR |= priv->initial;
return true; return E_SUCCESS;
} }
/** Tear down the unit */ /** Tear down the unit */
@ -190,10 +187,8 @@ enum PinCmd_ {
}; };
/** Handle a request message */ /** 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; struct priv *priv = unit->data;
uint16_t packed = pp_u16(pp); 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; set = spread;
reset = (~spread) & mask; reset = (~spread) & mask;
priv->port->BSRR = set | (reset<<16); priv->port->BSRR = set | (reset<<16);
break; return E_SUCCESS;
case CMD_SET: case CMD_SET:
priv->port->BSRR = spread; priv->port->BSRR = spread;
break; return E_SUCCESS;
case CMD_CLEAR: case CMD_CLEAR:
priv->port->BSRR = (spread<<16); priv->port->BSRR = (spread<<16);
break; return E_SUCCESS;
case CMD_TOGGLE:; case CMD_TOGGLE:;
spread = (uint16_t) (~priv->port->ODR) & mask; spread = (uint16_t) (~priv->port->ODR) & mask;
set = spread; set = spread;
reset = (~spread) & mask; reset = (~spread) & mask;
priv->port->BSRR = set | (reset<<16); priv->port->BSRR = set | (reset<<16);
break; return E_SUCCESS;
default: default:
com_respond_bad_cmd(frame_id); return E_UNKNOWN_COMMAND;
return false;
} }
return true;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

@ -55,7 +55,7 @@ static void UI2C_writeBinary(Unit *unit, PayloadBuilder *pb)
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Parse a key-value pair from the INI file */ /** 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; bool suc = true;
struct priv *priv = unit->data; 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); priv->speed = (uint8_t) avr_atoi(value);
} }
else { 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 */ /** 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 */ /** Allocate data structure and set defaults */
static bool UI2C_preInit(Unit *unit) static error_t UI2C_preInit(Unit *unit)
{ {
bool suc = true; bool suc = true;
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc);
CHECK_SUC(); if (!suc) return E_OUT_OF_MEM;
// some defaults // some defaults
priv->periph_num = 1; priv->periph_num = 1;
@ -112,41 +113,36 @@ static bool UI2C_preInit(Unit *unit)
priv->anf = true; priv->anf = true;
priv->dnf = 0; priv->dnf = 0;
return true; return E_SUCCESS;
} }
/** Finalize unit set-up */ /** Finalize unit set-up */
static bool UI2C_init(Unit *unit) static error_t UI2C_init(Unit *unit)
{ {
bool suc = true; bool suc = true;
struct priv *priv = unit->data; struct priv *priv = unit->data;
if (!(priv->periph_num >= 1 && priv->periph_num <= 2)) { if (!(priv->periph_num >= 1 && priv->periph_num <= 2)) {
unit->status = E_BAD_CONFIG; dbg("!! Bad I2C periph"); // TODO report
dbg("!! Bad I2C periph"); return E_BAD_CONFIG;
return false;
} }
if (!(priv->speed >= 1 && priv->speed <= 3)) { if (!(priv->speed >= 1 && priv->speed <= 3)) {
unit->status = E_BAD_CONFIG;
dbg("!! Bad I2C speed"); dbg("!! Bad I2C speed");
return false; return E_BAD_CONFIG;
} }
if (priv->dnf > 15) { if (priv->dnf > 15) {
unit->status = E_BAD_CONFIG;
dbg("!! Bad I2C DNF bw"); dbg("!! Bad I2C DNF bw");
return false; return E_BAD_CONFIG;
} }
// assign and claim the peripheral // assign and claim the peripheral
if (priv->periph_num == 1) { if (priv->periph_num == 1) {
suc = rsc_claim(unit, R_I2C1); TRY(rsc_claim(unit, R_I2C1));
CHECK_SUC();
priv->periph = I2C1; priv->periph = I2C1;
} else { } else {
suc = rsc_claim(unit, R_I2C2); TRY(rsc_claim(unit, R_I2C2));
CHECK_SUC();
priv->periph = I2C2; priv->periph = I2C2;
} }
@ -192,15 +188,15 @@ static bool UI2C_init(Unit *unit)
// first, we have to claim the pins // first, we have to claim the pins
Resource r_sda = pin2resource(portname, pin_sda, &suc); Resource r_sda = pin2resource(portname, pin_sda, &suc);
Resource r_scl = pin2resource(portname, pin_scl, &suc); Resource r_scl = pin2resource(portname, pin_scl, &suc);
CHECK_SUC(); if (!suc) return E_BAD_CONFIG;
rsc_claim(unit, r_sda);
rsc_claim(unit, r_scl); TRY(rsc_claim(unit, r_sda));
CHECK_SUC(); TRY(rsc_claim(unit, r_scl));
GPIO_TypeDef *port = port2periph(portname, &suc); GPIO_TypeDef *port = port2periph(portname, &suc);
uint32_t ll_pin_scl = pin2ll(pin_scl, &suc); uint32_t ll_pin_scl = pin2ll(pin_scl, &suc);
uint32_t ll_pin_sda = pin2ll(pin_sda, &suc); uint32_t ll_pin_sda = pin2ll(pin_sda, &suc);
CHECK_SUC(); if (!suc) return E_BAD_CONFIG;
// configure AF // configure AF
if (pin_scl < 8) LL_GPIO_SetAFPin_0_7(port, ll_pin_scl, af_i2c); 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_DisableOwnAddress1(priv->periph); // OA not used
LL_I2C_SetMode(priv->periph, LL_I2C_MODE_I2C); // not using SMBus LL_I2C_SetMode(priv->periph, LL_I2C_MODE_I2C); // not using SMBus
return true; return E_SUCCESS;
} }
/** Tear down the unit */ /** Tear down the unit */
@ -283,19 +279,19 @@ static void i2c_reset(struct priv *priv)
LL_I2C_Enable(priv->periph); 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(); uint32_t t_start = HAL_GetTick();
while (((priv->periph->ISR & flag)!=0) != stop_state) { while (((priv->periph->ISR & flag)!=0) != stop_state) {
if (HAL_GetTick() - t_start > 10) { if (HAL_GetTick() - t_start > 10) {
i2c_reset(priv); 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; 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; 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 (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)) { TRY(i2c_wait_until_flag(priv, I2C_ISR_BUSY, 0));
dbg("BUSY TOUT");
return false;
}
bool first = true; bool first = true;
while (bcount > 0) { 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; bcount -= chunk_remain;
for (; chunk_remain > 0; chunk_remain--) { for (; chunk_remain > 0; chunk_remain--) {
if (!i2c_wait_until_flag(priv, I2C_ISR_TXIS, 1)) { TRY(i2c_wait_until_flag(priv, I2C_ISR_TXIS, 1));
dbg("TXIS TOUT, remain %d", (int)chunk_remain);
return false;
}
uint8_t byte = *bytes++; uint8_t byte = *bytes++;
LL_I2C_TransmitData8(priv->periph, byte); LL_I2C_TransmitData8(priv->periph, byte);
} }
} }
if (!i2c_wait_until_flag(priv, I2C_ISR_STOPF, 1)) { TRY(i2c_wait_until_flag(priv, I2C_ISR_STOPF, 1));
dbg("STOPF TOUT");
return false;
}
LL_I2C_ClearFlag_STOP(priv->periph); 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; 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; 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 (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)) { TRY(i2c_wait_until_flag(priv, I2C_ISR_BUSY, 0));
dbg("BUSY TOUT");
return false;
}
bool first = true; bool first = true;
uint32_t n = 0;
while (bcount > 0) { while (bcount > 0) {
if (!first) { if (!first) {
if (!i2c_wait_until_flag(priv, I2C_ISR_TCR, 1)) { TRY(i2c_wait_until_flag(priv, I2C_ISR_TCR, 1));
dbg("TCR TOUT");
return false;
}
} }
uint8_t chunk_remain = (uint8_t) ((bcount > 255) ? 255 : bcount); // if more than 255, first chunk is 255 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; bcount -= chunk_remain;
for (; chunk_remain > 0; chunk_remain--) { for (; chunk_remain > 0; chunk_remain--) {
if (!i2c_wait_until_flag(priv, I2C_ISR_RXNE, 1)) { TRY(i2c_wait_until_flag(priv, I2C_ISR_RXNE, 1));
dbg("RXNE TOUT");
return false;
}
uint8_t byte = LL_I2C_ReceiveData8(priv->periph); uint8_t byte = LL_I2C_ReceiveData8(priv->periph);
*dest++ = byte; *dest++ = byte;
} }
} }
if (!i2c_wait_until_flag(priv, I2C_ISR_STOPF, 1)) { TRY(i2c_wait_until_flag(priv, I2C_ISR_STOPF, 1));
dbg("STOPF TOUT");
return false;
}
LL_I2C_ClearFlag_STOP(priv->periph); 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, &regnum, 1)) { TRY(UU_I2C_Write(unit, addr, &regnum, 1));
return false; TRY(UU_I2C_Read(unit, addr, dest, width));
} return E_SUCCESS;
// 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;
} }
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); PayloadBuilder pb = pb_start((uint8_t*)unit_tmp512, 512, NULL);
pb_u8(&pb, regnum); pb_u8(&pb, regnum);
pb_buf(&pb, bytes, width); pb_buf(&pb, bytes, width);
if (!UU_I2C_Write(unit, addr, (uint8_t *) unit_tmp512, pb_length(&pb))) { TRY(UU_I2C_Write(unit, addr, (uint8_t *) unit_tmp512, pb_length(&pb)));
return false; return E_SUCCESS;
}
return true;
} }
/** Handle a request message */ /** 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; uint16_t addr;
uint32_t len; uint32_t len;
uint8_t regnum;
uint32_t size;
// 10-bit address has the highest bit set to 1 to indicate this // NOTE: 10-bit addresses must have the highest bit set to 1 for indication (0x8000 | addr)
uint8_t regnum; // register number
uint32_t size; // register width
switch (command) { switch (command) {
/** Write byte(s) - addr:u16, byte(s) */
case CMD_WRITE: case CMD_WRITE:
addr = pp_u16(pp); addr = pp_u16(pp);
const uint8_t *bb = pp_tail(pp, &len); const uint8_t *bb = pp_tail(pp, &len);
if (!UU_I2C_Write(unit, addr, bb, len)) { return UU_I2C_Write(unit, addr, bb, len);
com_respond_err(frame_id, "TX FAIL");
return false;
}
break;
/** Read byte(s) - addr:u16, len:u16 */
case CMD_READ: case CMD_READ:
addr = pp_u16(pp); addr = pp_u16(pp);
len = pp_u16(pp); len = pp_u16(pp);
if (!UU_I2C_Read(unit, addr, (uint8_t *) unit_tmp512, len)) { TRY(UU_I2C_Read(unit, addr, (uint8_t *) unit_tmp512, len));
com_respond_err(frame_id, "RX FAIL");
return false;
}
com_respond_buf(frame_id, MSG_SUCCESS, (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:; case CMD_READ_REG:;
addr = pp_u16(pp); addr = pp_u16(pp);
regnum = pp_u8(pp); // register number 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)) { TRY(UU_I2C_ReadReg(unit, addr, regnum, (uint8_t *) unit_tmp512, size));
com_respond_err(frame_id, "READ REG FAIL");
return false;
}
com_respond_buf(frame_id, MSG_SUCCESS, (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: case CMD_WRITE_REG:
addr = pp_u16(pp); addr = pp_u16(pp);
regnum = pp_u8(pp); // register number regnum = pp_u8(pp); // register number
const uint8_t *tail = pp_tail(pp, &size); const uint8_t *tail = pp_tail(pp, &size);
if (!UU_I2C_WriteReg(unit, addr, regnum, tail, size)) { return UU_I2C_WriteReg(unit, addr, regnum, tail, size);
com_respond_err(frame_id, "WRITE REG FAIL");
return false;
}
break;
default: default:
com_respond_bad_cmd(frame_id); return E_UNKNOWN_COMMAND;
return false;
} }
return true;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

@ -20,7 +20,7 @@ extern const UnitDriver UNIT_I2C;
* @param bcount - byte count * @param bcount - byte count
* @return success * @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 * 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 * @param bcount - byte count
* @return success * @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. * 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) * @param width - register width (or multiple consecutive registers total size)
* @return success * @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 * 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) * @param width - register width (number of bytes)
* @return success * @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 * 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 * @param value - byte to write to the register
* @return success * @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); return UU_I2C_WriteReg(unit, addr, regnum, &value, 1);
} }

@ -43,7 +43,7 @@ static void Npx_writeBinary(Unit *unit, PayloadBuilder *pb)
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Parse a key-value pair from the INI file */ /** 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; bool suc = true;
struct priv *priv = unit->data; 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); priv->pixels = (uint16_t) avr_atoi(value);
} }
else { 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 */ /** 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 */ /** Allocate data structure and set defaults */
static bool Npx_preInit(Unit *unit) static error_t Npx_preInit(Unit *unit)
{ {
bool suc = true; bool suc = true;
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc);
CHECK_SUC(); if (!suc) return E_OUT_OF_MEM;
// some defaults // some defaults
priv->pin_number = 0; priv->pin_number = 0;
priv->port_name = 'A'; priv->port_name = 'A';
priv->pixels = 1; priv->pixels = 1;
return true; return E_SUCCESS;
} }
/** Finalize unit set-up */ /** Finalize unit set-up */
static bool Npx_init(Unit *unit) static error_t Npx_init(Unit *unit)
{ {
bool suc = true; bool suc = true;
struct priv *priv = unit->data; struct priv *priv = unit->data;
@ -100,13 +101,10 @@ static bool Npx_init(Unit *unit)
priv->ll_pin = pin2ll(priv->pin_number, &suc); priv->ll_pin = pin2ll(priv->pin_number, &suc);
priv->port = port2periph(priv->port_name, &suc); priv->port = port2periph(priv->port_name, &suc);
Resource rsc = pin2resource(priv->port_name, priv->pin_number, &suc); Resource rsc = pin2resource(priv->port_name, priv->pin_number, &suc);
if (!suc) { if (!suc) return E_BAD_CONFIG;
unit->status = E_BAD_CONFIG;
return false;
}
// --- Claim resources --- // --- Claim resources ---
if (!rsc_claim(unit, rsc)) return false; TRY(rsc_claim(unit, rsc));
// --- Init hardware --- // --- Init hardware ---
LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT); 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); ws2812_clear(priv->port, priv->ll_pin, priv->pixels);
return true; return E_SUCCESS;
} }
/** Tear down the unit */ /** 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_ { enum PinCmd_ {
CMD_CLEAR = 0, CMD_CLEAR = 0,
CMD_LOAD = 1, CMD_LOAD = 1,
@ -149,46 +192,39 @@ enum PinCmd_ {
}; };
/** Handle a request message */ /** 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; uint32_t len;
const uint8_t *bytes;
struct priv *priv = unit->data;
switch (command) { switch (command) {
/** Clear the entire strip */
case CMD_CLEAR: case CMD_CLEAR:
ws2812_clear(priv->port, priv->ll_pin, priv->pixels); return UU_NEOPIXEL_Clear(unit);
break;
case CMD_LOAD: /** Load packed RGB colors (length must match the strip size) */
if (pp_length(pp) != priv->pixels*3) goto bad_count; case CMD_LOAD:;
ws2812_load_raw(priv->port, priv->ll_pin, pp->current, priv->pixels); bytes = pp_tail(pp, &len);
break; return UU_NEOPIXEL_Load(unit, bytes, len);
/** Load sparse (uint32_t) colors, 0x00RRGGBB, little endian. */
case CMD_LOAD_U32_LE: case CMD_LOAD_U32_LE:
if (pp_length(pp) != priv->pixels*4) goto bad_count; bytes = pp_tail(pp, &len);
ws2812_load_sparse(priv->port, priv->ll_pin, pp->current, priv->pixels, 0); return UU_NEOPIXEL_LoadU32LE(unit, bytes, len);
break;
/** Load sparse (uint32_t) colors, 0x00RRGGBB, big endian. */
case CMD_LOAD_U32_BE: case CMD_LOAD_U32_BE:
if (pp_length(pp) != priv->pixels*4) goto bad_count; bytes = pp_tail(pp, &len);
ws2812_load_sparse(priv->port, priv->ll_pin, pp->current, priv->pixels, 1); return UU_NEOPIXEL_LoadU32BE(unit, bytes, len);
break;
/** Get the Neopixel strip length */
case CMD_GET_LEN: case CMD_GET_LEN:
com_respond_u16(frame_id, priv->pixels); com_respond_u16(frame_id, UU_NEOPIXEL_GetCount(unit));
break; return E_SUCCESS;
default: default:
com_respond_bad_cmd(frame_id); return E_UNKNOWN_COMMAND;
return false;
} }
return true;
bad_count:
com_respond_err(frame_id, "BAD PIXEL COUNT");
return false;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

@ -9,4 +9,44 @@
extern const UnitDriver UNIT_NEOPIXEL; 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 #endif //U_NEOPIXEL_H

@ -28,7 +28,7 @@ void ws2812_byte(GPIO_TypeDef *port, uint32_t ll_pin, uint8_t b)
} }
/** Set many RGBs from packed stream */ /** 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(); vPortEnterCritical();
uint8_t b, g, r; 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 */ /** 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(); vPortEnterCritical();
uint8_t b, g, r; uint8_t b, g, r;

@ -11,7 +11,7 @@
* @param rgbs - packed R,G,B, R,G,B, ... array * @param rgbs - packed R,G,B, R,G,B, ... array
* @param count - number of pixels (triplets) * @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) * 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 count - number of pixels
* @param bigendian - big endian ordering * @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 #endif //WS2812_H

@ -32,14 +32,9 @@ static void Tst_writeBinary(Unit *unit, PayloadBuilder *pb)
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Parse a key-value pair from the INI file */ /** 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; return E_BAD_KEY;
struct priv *priv = unit->data;
//
return suc;
} }
/** Generate INI file section for the unit */ /** 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 */ /** Allocate data structure and set defaults */
static bool Tst_preInit(Unit *unit) static error_t Tst_preInit(Unit *unit)
{ {
bool suc = true; bool suc = true;
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); 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 */ /** Finalize unit set-up */
static bool Tst_init(Unit *unit) static error_t Tst_init(Unit *unit)
{ {
bool suc = true; bool suc = true;
struct priv *priv = unit->data; struct priv *priv = unit->data;
// //
return true; return E_SUCCESS;
} }
/** Tear down the unit */ /** 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 */ /** 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) { switch (command) {
case CMD_PING: case CMD_PING:
com_respond_ok(frame_id); com_respond_ok(frame_id);
break; return E_SUCCESS;
case CMD_ECHO:; case CMD_ECHO:;
uint32_t len; uint32_t len;
const uint8_t *data = pp_tail(pp, &len); const uint8_t *data = pp_tail(pp, &len);
com_respond_buf(frame_id, MSG_SUCCESS, data, len); com_respond_buf(frame_id, MSG_SUCCESS, data, len);
break; return E_SUCCESS;
case CMD_BULKREAD:; case CMD_BULKREAD:;
BulkRead *br = malloc(sizeof(struct bulk_read)); 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; br->read = br_longtext;
bulkread_start(comm, br); bulkread_start(comm, br);
break; return E_SUCCESS;
case CMD_BULKWRITE:; case CMD_BULKWRITE:;
BulkWrite *bw = malloc(sizeof(struct bulk_write)); 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; bw->write = bw_dump;
bulkwrite_start(comm, bw); bulkwrite_start(comm, bw);
break; return E_SUCCESS;
default: default:
com_respond_bad_cmd(frame_id); return E_UNKNOWN_COMMAND;
return false;
} }
return true;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

@ -21,6 +21,13 @@
#include "platform.h" #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[] = { static const char *const error_message[] = {
#define X(name, text) text, #define X(name, text) text,
X_ERROR_CODES X_ERROR_CODES
@ -28,18 +35,33 @@ static const char *const error_message[] = {
}; };
COMPILER_ASSERT(ERROR_COUNT == ELEMENTS_IN_ARRAY(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) { if (error < ERROR_COUNT) {
msg = error_message[error]; msg = error_message[error];
} }
if (0 == msg) { if (NULL == msg) {
assert_param(0); return error_get_name(error);
msg = "";
} }
return msg; 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;
}

@ -26,25 +26,35 @@
} }
#endif #endif
// fields: name, msg. If msg is NULL, name as string will be used instead.
#define X_ERROR_CODES \ #define X_ERROR_CODES \
/* Shared errors */ \ /* Shared errors */ \
X(SUCCESS,"OK") \ X(SUCCESS, NULL) /* operation succeeded / unit loaded */ \
X(FAILURE,"Failure") \ X(FAILURE, NULL) /* generic error */ \
X(INTERNAL,"Internal error") \ X(INTERNAL_ERROR, NULL) /* a bug */ \
X(LOADING,"Init in progress") \ 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 */ \ /* VFS user errors (those are meant to be shown to user) */ \
X(ERROR_DURING_TRANSFER,"Error during transfer") \ X(ERROR_DURING_TRANSFER, "Error during transfer") \
X(TRANSFER_TIMEOUT,"Transfer timed out") \ 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") \
X(OOO_SECTOR,"File sent out of order by PC") \
\ \
/* File stream errors */ \ /* File stream errors/status */ \
X(SUCCESS_DONE,"End of stream") \ X(SUCCESS_DONE, NULL) \
X(SUCCESS_DONE_OR_CONTINUE,"End of stream, or more to come") \ X(SUCCESS_DONE_OR_CONTINUE, NULL) \
\ \
/* Unit loading */ \ /* Unit loading */ \
X(BAD_CONFIG, "Configuration error") \ 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(OUT_OF_MEM, "Not enough RAM") \
X(RESOURCE_NOT_AVAILABLE, "Required pin / peripheral not available") X(RESOURCE_NOT_AVAILABLE, "Required pin / peripheral not available")
@ -56,7 +66,15 @@ typedef enum {
ERROR_COUNT ERROR_COUNT
} error_t; } 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 #ifdef __cplusplus
} }

@ -100,16 +100,16 @@ error_t stream_open(stream_type_t stream_type)
// Stream must not be open already // Stream must not be open already
if (stream_state != STREAM_STATE_CLOSED) { if (stream_state != STREAM_STATE_CLOSED) {
vfs_printf("!! Stream is not closed, cant open"); trap("!! Stream is not closed, cant open");
assert_param(0); // assert_param(0);
return E_INTERNAL; // return E_INTERNAL;
} }
// Stream must be of a supported type // Stream must be of a supported type
if (stream_type >= STREAM_TYPE_COUNT) { if (stream_type >= STREAM_TYPE_COUNT) {
vfs_printf("!! Stream bad type"); trap("!! Stream bad type");
assert_param(0); // assert_param(0);
return E_INTERNAL; // return E_INTERNAL;
} }
Indicator_Effect(STATUS_DISK_BUSY); 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 // Stream must be open already
if (stream_state != STREAM_STATE_OPEN) { if (stream_state != STREAM_STATE_OPEN) {
vfs_printf("!! Stream is not open, cant write"); trap("!! Stream is not open, cant write");
assert_param(0); // assert_param(0);
return E_INTERNAL; // return E_INTERNAL;
} }
// Check thread after checking state since the stream thread is // 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 // Stream must not be closed already
if (STREAM_STATE_CLOSED == stream_state) { if (STREAM_STATE_CLOSED == stream_state) {
vfs_printf("!! Stream already closed"); trap("!! Stream already closed");
assert_param(0); // assert_param(0);
return E_INTERNAL; // return E_INTERNAL;
} }
// Check thread after checking state since the stream thread is // Check thread after checking state since the stream thread is

@ -941,7 +941,8 @@ static void transfer_update_state(error_t status)
// Set the fail reason // Set the fail reason
fail_reason = local_status; 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 // If this state change is not from aborting a transfer

Loading…
Cancel
Save