diff --git a/examples/MyLampThing-0/README.md b/examples/MyLampThing-0/README.md new file mode 100644 index 0000000..e69de29 diff --git a/examples/MyLampThing-0/lib/README b/examples/MyLampThing-0/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/examples/MyLampThing-0/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/examples/MyLampThing-0/platformio.ini b/examples/MyLampThing-0/platformio.ini new file mode 100644 index 0000000..88ada65 --- /dev/null +++ b/examples/MyLampThing-0/platformio.ini @@ -0,0 +1,14 @@ +; SPDX-FileCopyrightText: 2024 Junde Yhi +; SPDX-License-Identifier: MIT + +[platformio] +name = MyLampThing-0 + +[env:uno] +platform = atmelavr +board = uno +framework = arduino +lib_deps = + quicksander/ArduinoHttpServer@~0.10 + arduino-libraries/Ethernet@^2.0 + symlink://../../ diff --git a/examples/MyLampThing-0/src/main.ino b/examples/MyLampThing-0/src/main.ino new file mode 100644 index 0000000..9ecb150 --- /dev/null +++ b/examples/MyLampThing-0/src/main.ino @@ -0,0 +1,85 @@ +/*! + SPDX-FileCopyrightText: 2024 Junde Yhi + SPDX-License-Identifier: MIT +*/ + +#include + +#include +#include +#include + +static char const application_json[] = "application/json"; + +static unsigned char t_scratchpad[32] = {}; +static struct tinywot_request t_request = {}; +static struct tinywot_response t_response = {}; +static struct tinywot_thing t_thing = {}; + +static byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +static byte ip[] = { 10, 36, 24, 51 }; +static EthernetServer server = EthernetServer(80); + +void setup(void) { + pinMode(13, OUTPUT); + digitalWrite(13, LOW); + + Ethernet.begin(mac, ip); + server.begin(); +} + +void loop(void) { + enum tinywot_status t_status = TINYWOT_STATUS_UNKNOWN; + + Ethernet.maintain(); + + EthernetClient eth_client = server.available(); + if (!eth_client) { + return; + } + + ArduinoHttpServer::StreamHttpRequest<256> httpRequest(eth_client); + + if (httpRequest.readRequest()) { + ArduinoHttpServer::Method method = httpRequest.getMethod(); + + if (method == ArduinoHttpServer::Method::Get) { + t_request.op = TINYWOT_OPERATION_TYPE_READPROPERTY; + } else if (method == ArduinoHttpServer::Method::Post) { + t_request.op = TINYWOT_OPERATION_TYPE_WRITEPROPERTY; + } else { + t_request.op = TINYWOT_OPERATION_TYPE_UNKNOWN; + } + + const String& href = httpRequest.getResource().toString(); + memcpy(t_request.target, href.c_str(), href.length()); + + t_response.payload.content = t_scratchpad; + + t_status = tinywot_thing_process_request(&t_thing, &t_response, &t_request); + if (t_status != TINYWOT_STATUS_SUCCESS) { + client.stop(); + memset(t_scratchpad, 0, sizeof(t_scratchpad)); + memset(&t_request, 0, sizeof(struct tinywot_request)); + memset(&t_response, 0, sizeof(struct tinywot_response)); + return; + } + + // if (method == ArduinoHttpServer::Method::Get) { + // if (httpRequest.getResource().toString() == "/status") { + // ArduinoHttpServer::StreamHttpReply response(client, application_json); + // response.send(digitalRead(13) == HIGH ? "true" : "false"); + // } else { + // ArduinoHttpServer::StreamHttpErrorReply response(client, application_json, "404"); + // } + // } else { + // ArduinoHttpServer::StreamHttpErrorReply response(client, application_json, "405"); + // } + } + + client.stop(); + + memset(t_scratchpad, 0, sizeof(t_scratchpad)); + memset(&t_request, 0, sizeof(struct tinywot_request)); + memset(&t_response, 0, sizeof(struct tinywot_response)); +} diff --git a/include/tinywot/core.h b/include/tinywot/core.h index d0e0dc0..40e8ab4 100644 --- a/include/tinywot/core.h +++ b/include/tinywot/core.h @@ -9,7 +9,7 @@ The Core part of TinyWoT is only a small portion of data structure definitions and helper functions. It is designed to be the platform- - agnostic basis of other components: + agnostic basis of the two other components: - Protocol Binding - Servient @@ -38,41 +38,34 @@ extern "C" { /*! \brief Status codes. - These are return values used and recognized across the library. Values - between 1 and 127 are general status codes. Values between 128 and 255 - indicate errors. 0 is an undefined value that is regarded as an error - when encountered. + These are return values used and recognized across the library. */ enum tinywot_status { /*! - \brief An undefined status. - - This can be used to initialize a `tinywot_status` variable, but is - seen as an error across the library. + \brief There is insufficient memory to complete an action. */ - TINYWOT_STATUS_UNKNOWN = 0x00, + TINYWOT_STATUS_ERROR_NOT_ENOUGH_MEMORY = -5, /*! - \brief The operation has been successful. + \brief The function is not implemented. */ - TINYWOT_STATUS_SUCCESS, + TINYWOT_STATUS_ERROR_NOT_IMPLEMENTED = -4, /*! - \brief The end of stream (EOS) has been reached. + \brief Something is missing. + + This can happen when a requested target and operation type cannot + match any handler registered in a Thing. */ - TINYWOT_STATUS_END_OF_STREAM, + TINYWOT_STATUS_ERROR_NOT_FOUND = -3, /*! - \brief The operation has been successful, but not all work has been - done; it hasn't been fully completed yet. + \brief The requested operation is not allowed. - Depending on the context, the caller is given the chance to perform - some action on the already returned data, then call the same - function again, with the right arguments to carry on, until either - `TINYWOT_STATUS_SUCCESS` or `TINYWOT_STATUS_END_OF_STREAM` is - received, when there is no more data to process. + This can happen when a target can be matched, but does not accept + the operation type requested. */ - TINYWOT_STATUS_NOT_FINISHED, + TINYWOT_STATUS_ERROR_NOT_ALLOWED = -2, /*! \brief A generic error. @@ -81,44 +74,31 @@ enum tinywot_status { Applications and libraries should try to use other error codes when possible. */ - TINYWOT_STATUS_ERROR_GENERIC = 0x80, + TINYWOT_STATUS_ERROR_GENERIC = -1, /*! - \brief The requested operation is not allowed. - - This can happen when a target can be matched, but does not accept - the operation type requested. + \brief An unknown status. */ - TINYWOT_STATUS_ERROR_NOT_ALLOWED, + TINYWOT_STATUS_UNKNOWN = 0, /*! - \brief Something is missing. - - This can happen when a requested target and operation type cannot - match any handler registered in a Thing. + \brief The operation has been successful and completed. */ - TINYWOT_STATUS_ERROR_NOT_FOUND, + TINYWOT_STATUS_SUCCESS = 1, /*! - \brief The function is not implemented. - */ - TINYWOT_STATUS_ERROR_NOT_IMPLEMENTED, + \brief The operation has been successful, but not all work has been + done; it hasn't been fully completed yet. - /*! - \brief There is insufficient memory to complete an action. + Depending on the context, the caller is given the chance to perform + some action on the already returned data, then call the same + function again, with the right arguments to carry on, until + `TINYWOT_STATUS_SUCCESS` is received, when there is no more data to + process. */ - TINYWOT_STATUS_ERROR_NOT_ENOUGH_MEMORY, + TINYWOT_STATUS_PARTIAL = 2, }; -/*! - \brief Check if the supplied `tinywot_status` hints an error. - \memberof tinywot_status - - \param[in] self A `tinywot_status`. - \return `true` if `self` is an error, `false` otherwise. -*/ -bool tinywot_status_is_error(enum tinywot_status self); - /*! \brief Operation types. @@ -133,183 +113,132 @@ bool tinywot_status_is_error(enum tinywot_status self); [Table 27]: https://www.w3.org/TR/wot-thing-description11/#table-well-known-operation-types */ -enum tinywot_operation_type { +enum tinywot_op { /* 0bqf'ty'yxwr */ /*! \brief A default, invalid operation type reserved for variable initialization. */ - TINYWOT_OPERATION_TYPE_UNKNOWN = 0, + TINYWOT_OP_UNKNOWN = 0x00u, /* 0b00'00'0000 */ /*! \brief Identifies the read operation on Property Affordances to retrieve the corresponding data. */ - TINYWOT_OPERATION_TYPE_READPROPERTY, + TINYWOT_OP_READPROPERTY = 0x51u, /* 0b01'01'0001 */ /*! \brief Identifies the write operation on Property Affordances to update the corresponding data. */ - TINYWOT_OPERATION_TYPE_WRITEPROPERTY, + TINYWOT_OP_WRITEPROPERTY = 0x52u, /* 0b01'01'0010 */ /*! \brief Identifies the observe operation on Property Affordances to be notified with the new data when the Property is updated. */ - TINYWOT_OPERATION_TYPE_OBSERVEPROPERTY, + TINYWOT_OP_OBSERVEPROPERTY = 0x54u, /* 0b01'01'0100 */ /*! \brief Identifies the unobserve operation on Property Affordances to stop the corresponding notifications. */ - TINYWOT_OPERATION_TYPE_UNOBSERVEPROPERTY, + TINYWOT_OP_UNOBSERVEPROPERTY = 0x58u, /* 0b01'01'1000 */ /*! \brief Identifies the invoke operation on Action Affordances to perform the corresponding action. */ - TINYWOT_OPERATION_TYPE_INVOKEACTION, + TINYWOT_OP_INVOKEACTION = 0x64u, /* 0b01'10'0100 */ /*! \brief Identifies the querying operation on Action Affordances to get the status of the corresponding action. */ - TINYWOT_OPERATION_TYPE_QUERYACTION, + TINYWOT_OP_QUERYACTION = 0x61u, /* 0b01'10'0001 */ /*! \brief Identifies the cancel operation on Action Affordances to cancel the ongoing corresponding action. */ - TINYWOT_OPERATION_TYPE_CANCELACTION, + TINYWOT_OP_CANCELACTION = 0x68u, /* 0b01'10'1000 */ /*! \brief Identifies the subscribe operation on Event Affordances to be notified by the Thing when the event occurs. */ - TINYWOT_OPERATION_TYPE_SUBSCRIBEEVENT, + TINYWOT_OP_SUBSCRIBEEVENT = 0x74u, /* 0b01'11'0100 */ /*! \brief Identifies the unsubscribe operation on Event Affordances to stop the corresponding notifications. */ - TINYWOT_OPERATION_TYPE_UNSUBSCRIBEEVENT, + TINYWOT_OP_UNSUBSCRIBEEVENT = 0x78u, /* 0b01'11'1000 */ /*! \brief Identifies the readallproperties operation on a Thing to retrieve the data of all Properties in a single interaction. */ - TINYWOT_OPERATION_TYPE_READALLPROPERTIES, + TINYWOT_OP_READALLPROPERTIES = 0x91u, /* 0b10'01'0001 */ /*! \brief Identifies the writeallproperties operation on a Thing to update the data of all writable Properties in a single interaction. */ - TINYWOT_OPERATION_TYPE_WRITEALLPROPERTIES, + TINYWOT_OP_WRITEALLPROPERTIES = 0x92u, /* 0b10'01'0010 */ /*! \brief Identifies the readmultipleproperties operation on a Thing to retrieve the data of selected Properties in a single interaction. */ - TINYWOT_OPERATION_TYPE_READMULTIPLEPROPERTIES, + TINYWOT_OP_READMULTIPLEPROPERTIES = 0xd1u, /* 0b11'01'0001 */ /*! \brief Identifies the writemultipleproperties operation on a Thing to update the data of selected writable Properties in a single interaction. */ - TINYWOT_OPERATION_TYPE_WRITEMULTIPLEPROPERTIES, + TINYWOT_OP_WRITEMULTIPLEPROPERTIES = 0xd2u, /* 0b11'01'0010 */ /*! \brief Identifies the observeallproperties operation on Properties to be notified with new data when any Property is updated. */ - TINYWOT_OPERATION_TYPE_OBSERVEALLPROPERTIES, + TINYWOT_OP_OBSERVEALLPROPERTIES = 0xd4u, /* 0b11'01'0100 */ /*! \brief Identifies the unobserveallproperties operation on Properties to stop notifications from all Properties in a single interaction. */ - TINYWOT_OPERATION_TYPE_UNOBSERVEALLPROPERTIES, + TINYWOT_OP_UNOBSERVEALLPROPERTIES = 0xd8u, /* 0b11'01'1000 */ /*! \brief Identifies the queryallactions operation on a Thing to get the status of all Actions in a single interaction. */ - TINYWOT_OPERATION_TYPE_QUERYALLACTIONS, + TINYWOT_OP_QUERYALLACTIONS = 0xe1u, /* 0b11'10'0001 */ /*! \brief Identifies the subscribeallevents operation on Events to subscribe to notifications from all Events in a single interaction. */ - TINYWOT_OPERATION_TYPE_SUBSCRIBEALLEVENTS, + TINYWOT_OP_SUBSCRIBEALLEVENTS = 0xf4u, /* 0b11'11'0100 */ /*! \brief Identifies the unsubscribeallevents operation on Events to unsubscribe from notifications from all Events in a single interaction. */ - TINYWOT_OPERATION_TYPE_UNSUBSCRIBEALLEVENTS, -}; - -/*! - \brief Response status. - - Compared with `tinywot_status`, these status codes are more public - faced; too detailed errors are mapped into the `INTERNAL_ERROR` value - instead. Thus, they are more suitable for protocol bindings. -*/ -enum tinywot_response_status { - /*! - \brief A default, invalid value reserved for variable - initialization. - */ - TINYWOT_RESPONSE_STATUS_UNKNOWN = 0, - - /*! - \brief The operation has been completed and successful. - */ - TINYWOT_RESPONSE_STATUS_OK, - - /*! - \brief A generic error. - */ - TINYWOT_RESPONSE_STATUS_INTERNAL_ERROR, - - /*! - \brief The function is not implemented. - */ - TINYWOT_RESPONSE_STATUS_NOT_SUPPORTED, - - /*! - \brief Something is missing. - */ - TINYWOT_RESPONSE_STATUS_NOT_FOUND, - - /*! - \brief The requested operation is not allowed. - */ - TINYWOT_RESPONSE_STATUS_NOT_ALLOWED, + TINYWOT_OP_UNSUBSCRIBEALLEVENTS = 0xf8u, /* 0b11'11'1000 */ }; /*! - \brief Map a `tinywot_status` to a `tinywot_response_status`. - \memberof tinywot_response_status - - \param[in] status A `tinywot_status`. - \return A `tinywot_response_status`. -*/ -enum tinywot_response_status tinywot_response_status_from_tinywot_status( - enum tinywot_status const status -); - -/*! - \brief Metadata about a chunk of data. + \brief A chunk of data and the metadata about it. */ struct tinywot_payload { /*! \brief A pointer to the buffer holding the actual data. */ - void *content; + unsigned char *content; /*! \brief The size of buffer pointed by `content` in byte. @@ -334,42 +263,6 @@ struct tinywot_payload { uint_fast16_t content_type; }; -/*! - \brief Append the memory content pointed by `data` to a - `tinywot_payload`. - \memberof tinywot_payload - - This copies the memory pointed by `data` to the end of - `tinywot_payload::content`. - - \param[in] self An instance of `tinywot_payload`. - \param[in] data A pointer to a memory region containing data. - \param[in] data_size_byte How long is the data, in bytes. - \return `tinywot_status` -*/ -enum tinywot_status tinywot_payload_append( - struct tinywot_payload *self, - void const *data, - size_t data_size_byte -); - -/*! - \brief Append the NUL-terminated string pointed by `str` to a - `tinywot_payload`. - \memberof tinywot_payload - - This function is like `tinywot_payload_append()` except that it - copies and concatenates the strings rather than blindly append. - - \param[in] self An instance of `tinywot_payload`. - \param[in] str A pointer to a NUL-terminated string. - \return `tinywot_status` -*/ -enum tinywot_status tinywot_payload_append_string( - struct tinywot_payload *self, - char const *str -); - /*! \brief The size of buffer reserved for `tinywot_request::target`. */ @@ -393,14 +286,14 @@ struct tinywot_request { struct tinywot_payload payload; /*! - \brief The intended operation type extracted from the request. + \brief The name of affordance. */ - enum tinywot_operation_type op; + char const *name; /*! - \brief The intended submision target extracted from the request. + \brief The intended operation type extracted from the request. */ - char target[TINYWOT_REQUEST_TARGET_BUFFER_SIZE_BYTE]; + enum tinywot_op op; }; /*! @@ -419,11 +312,8 @@ struct tinywot_response { /*! \brief A status code for the response. - - This is normally calculated from the \ref status_codes returned by - functions. */ - enum tinywot_response_status status; + enum tinywot_status status; }; /*! @@ -487,7 +377,7 @@ struct tinywot_form { /*! \brief The allowed operation type on this form. */ - enum tinywot_operation_type op; + enum tinywot_op op; /*! \brief A function pointer to the actual implementation of the form. @@ -638,7 +528,7 @@ enum tinywot_status tinywot_thing_find_form( struct tinywot_thing const *self, struct tinywot_form **form, char const *target, - enum tinywot_operation_type op + enum tinywot_op op ); /*! @@ -689,7 +579,7 @@ enum tinywot_status tinywot_thing_add_form( enum tinywot_status tinywot_thing_change_form( struct tinywot_thing *self, char const *target, - enum tinywot_operation_type op, + enum tinywot_op op, struct tinywot_form const *form ); @@ -708,7 +598,7 @@ enum tinywot_status tinywot_thing_change_form( enum tinywot_status tinywot_thing_remove_form( struct tinywot_thing *self, char const *target, - enum tinywot_operation_type op + enum tinywot_op op ); /*! @@ -805,6 +695,18 @@ struct tinywot_protocol { ); }; +char const *tinywot_status_to_string(enum tinywot_status self); +enum tinywot_status tinywot_payload_append( + struct tinywot_payload *self, + void const *data, + size_t data_size_byte +); +enum tinywot_status tinywot_payload_append_string( + struct tinywot_payload *self, + char const *str +); + + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/include/tinywot/type.h b/include/tinywot/type.h new file mode 100644 index 0000000..920071d --- /dev/null +++ b/include/tinywot/type.h @@ -0,0 +1,155 @@ +#ifndef WT_TYPE_H +#define WT_TYPE_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum wt_status +{ + WT_STATUS_ERROR_NOT_ENOUGH_MEMORY = -5, + WT_STATUS_ERROR_NOT_IMPLEMENTED = -4, + WT_STATUS_ERROR_NOT_FOUND = -3, + WT_STATUS_ERROR_NOT_ALLOWED = -2, + WT_STATUS_ERROR_GENERIC = -1, + WT_STATUS_UNKNOWN = 0, + WT_STATUS_SUCCESS = 1, + WT_STATUS_PARTIAL = 2, +}; + +enum wt_op +{ /* 0bnn'vv'yxwr */ + WT_OP_UNKNOWN = 0x00u, /* 0b00'00'0000 */ + + WT_OP_READPROPERTY = 0x51u, /* 0b01'01'0001 */ + WT_OP_WRITEPROPERTY = 0x52u, /* 0b01'01'0010 */ + WT_OP_OBSERVEPROPERTY = 0x54u, /* 0b01'01'0100 */ + WT_OP_UNOBSERVEPROPERTY = 0x58u, /* 0b01'01'1000 */ + + WT_OP_INVOKEACTION = 0x64u, /* 0b01'10'0100 */ + WT_OP_QUERYACTION = 0x61u, /* 0b01'10'0001 */ + WT_OP_CANCELACTION = 0x68u, /* 0b01'10'1000 */ + + WT_OP_SUBSCRIBEEVENT = 0x74u, /* 0b01'11'0100 */ + WT_OP_UNSUBSCRIBEEVENT = 0x78u, /* 0b01'11'1000 */ + + WT_OP_READMULTIPLEPROPERTIES = 0x91u, /* 0b10'01'0001 */ + WT_OP_WRITEMULTIPLEPROPERTIES = 0x92u, /* 0b10'01'0010 */ + + WT_OP_READALLPROPERTIES = 0xd1u, /* 0b11'01'0001 */ + WT_OP_WRITEALLPROPERTIES = 0xd2u, /* 0b11'01'0010 */ + WT_OP_OBSERVEALLPROPERTIES = 0xd4u, /* 0b11'01'0100 */ + WT_OP_UNOBSERVEALLPROPERTIES = 0xd8u, /* 0b11'01'1000 */ + + WT_OP_QUERYALLACTIONS = 0xe1u, /* 0b11'10'0001 */ + + WT_OP_SUBSCRIBEALLEVENTS = 0xf4u, /* 0b11'11'0100 */ + WT_OP_UNSUBSCRIBEALLEVENTS = 0xf8u, /* 0b11'11'1000 */ +}; + +struct wt_payload +{ + unsigned char *content; + size_t buffer_size; + size_t content_length; + uint_fast16_t content_type; +}; + +struct wt_request +{ + struct wt_payload payload; + char const *name; + uint_fast16_t op; +}; + +struct wt_response +{ + struct wt_payload payload; + uint_fast8_t status; +}; + +struct wt_form +{ + char const *name; + char const *target; + uint_fast16_t ops_allowed; + int (*handler)(struct wt_payload * restrict payload_response, + struct wt_payload const * restrict payload_request, + intptr_t *context); + intptr_t context; +}; + +enum wt_protocol_mode +{ + WT_PROTOCOL_READ_REQUEST_WRITE_RESPONSE = 1, + WT_PROTOCOL_WRITE_REQUEST_READ_RESPONSE = 2, +}; + +struct wt_interface_protocol +{ + int (*set_mode)(void *self, enum wt_protocol_mode mode); + + int (*read)(void *self, + unsigned char const *buffer, + size_t data_size, + size_t *read_size); + int (*write)(void *self, + unsigned char *buffer, + size_t buffer_size, + size_t *written_size); + + int (*get_target)(void *self, char *buffer, size_t buffer_size); + int (*get_op)(void *self, uint_fast16_t *op, uint_fast16_t ops_allowed); + int (*get_payload)(void *self, struct wt_payload *payload); + + int (*set_target)(void *self, char *buffer); + int (*set_op)(void *self, uint_fast16_t op); + int (*set_payload)(void *self, struct wt_payload const *payload); + + int (*get_response)(void *self, struct wt_response *response); + int (*set_response)(void *self, struct wt_response const *response); +}; + +struct wt_interface_form_store +{ + int (*set_forms)(void *self, + struct wt_form const *forms, + size_t buffer_size, + size_t forms_number); + + int (*add_form)(void *self, struct wt_form const *form); + int (*change_form)(void *self, + struct wt_form const * restrict form_input, + struct wt_form const * restrict form_criteria, + enum wt_form_select select); + int (*remove_form)(void *self, + struct wt_form const *form_criteria, + enum wt_form_select select); + + int (*find_form_by_name)(void *self, + struct wt_form *form_result, + char const *name); + int (*find_form_by_target)(void *self, + struct wt_form *form_result, + char const *target); +}; + +struct wt_interface_servient +{ + int (*set_protocol)(void *self, + struct wt_interface_protocol const *protocol); + int (*set_form_store)(void *self, + struct wt_interface_form_store const *form_store); + + int (*run_once)(void *self); +}; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* WT_TYPE_H */ diff --git a/platformio.ini b/platformio.ini index 5c1cfc4..974778c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,6 +9,7 @@ ; SPDX-License-Identifier: CC0-1.0 [platformio] +name = TinyWoT Core default_envs = test_native ; Run unit tests on the local build machine. diff --git a/script/README.md b/script/README.md new file mode 100644 index 0000000..d507397 --- /dev/null +++ b/script/README.md @@ -0,0 +1,17 @@ +# Useful Scriptlets During Development + +- [`dev.containerfile`](./dev.containerfile): Recipe for building the standard development environment for TinyWoT Core. + +## Development Container + +### Build + +```sh +podman build -t ghcr.io/tinywot/core/dev:latest -f - < dev.containerfile +``` + +### Run + +```sh +podman run --volume /path/to/repo:core --device /dev/ttyACM0 --userns keep-id:uid=1000,gid=1000 --tty --interactive ghcr.io/tinywot/core/dev:latest +``` diff --git a/src/core.c b/src/core.c index d45d80a..9e979ba 100644 --- a/src/core.c +++ b/src/core.c @@ -14,31 +14,72 @@ #include -bool tinywot_status_is_error(enum tinywot_status self) { - return self == 0 || self > 0x7f; -} +static char const tinywot_status_success_string[] = + "success"; +static char const tinywot_status_partial_string[] = + "partial content"; +static char const tinywot_status_error_generic_string[] = + "unspecified error"; +static char const tinywot_status_error_not_allowed_string[] = + "operation not allowed"; +static char const tinywot_status_error_not_found_string[] = + "target not found"; +static char const tinywot_status_error_not_implemented_string[] = + "function not implemented"; +static char const tinywot_status_error_not_enough_memory_string[] = + "insufficient memory"; +static char const tinywot_status_unknown_string[] = + "unknown"; + +/*! + \brief Retrieve a string out of a `tinywot_status`. + \memberof tinywot_status + + \param[in] self A `tinywot_status`. + \return A string representation of the provided `tinywot_status`. +*/ +char const *tinywot_status_to_string(enum tinywot_status self) { + switch (self) { + case TINYWOT_STATUS_SUCCESS: + return tinywot_status_success_string; + + case TINYWOT_STATUS_PARTIAL: + return tinywot_status_partial_string; + + case TINYWOT_STATUS_ERROR_GENERIC: + return tinywot_status_error_generic_string; -enum tinywot_response_status tinywot_response_status_from_tinywot_status( - enum tinywot_status const status -) { - switch (status) { case TINYWOT_STATUS_ERROR_NOT_ALLOWED: - return TINYWOT_RESPONSE_STATUS_NOT_ALLOWED; + return tinywot_status_error_not_allowed_string; case TINYWOT_STATUS_ERROR_NOT_FOUND: - return TINYWOT_RESPONSE_STATUS_NOT_FOUND; + return tinywot_status_error_not_found_string; case TINYWOT_STATUS_ERROR_NOT_IMPLEMENTED: - return TINYWOT_RESPONSE_STATUS_NOT_SUPPORTED; + return tinywot_status_error_not_implemented_string; - case TINYWOT_STATUS_SUCCESS: - return TINYWOT_RESPONSE_STATUS_OK; + case TINYWOT_STATUS_ERROR_NOT_ENOUGH_MEMORY: + return tinywot_status_error_not_enough_memory_string; + case TINYWOT_STATUS_UNKNOWN: /* fall through */ default: - return TINYWOT_RESPONSE_STATUS_INTERNAL_ERROR; + return tinywot_status_unknown_string; } } +/*! + \brief Append the memory content pointed by `data` to a + `tinywot_payload`. + \memberof tinywot_payload + + This copies the memory pointed by `data` to the end of + `tinywot_payload::content`. + + \param[in] self An instance of `tinywot_payload`. + \param[in] data A pointer to a memory region containing data. + \param[in] data_size_byte How long is the data, in bytes. + \return `tinywot_status` +*/ enum tinywot_status tinywot_payload_append( struct tinywot_payload *self, void const *data, @@ -58,6 +99,18 @@ enum tinywot_status tinywot_payload_append( return TINYWOT_STATUS_SUCCESS; } +/*! + \brief Append the NUL-terminated string pointed by `str` to a + `tinywot_payload`. + \memberof tinywot_payload + + This function is like `tinywot_payload_append()` except that it + copies and concatenates the strings rather than blindly append. + + \param[in] self An instance of `tinywot_payload`. + \param[in] str A pointer to a NUL-terminated string. + \return `tinywot_status` +*/ enum tinywot_status tinywot_payload_append_string( struct tinywot_payload *self, char const *str