From d0aef356ede0e5c36e1b98eb43b9cd2c2b34c039 Mon Sep 17 00:00:00 2001 From: Xael South Date: Sun, 10 Nov 2024 23:19:29 +0100 Subject: [PATCH] added bindings for xmlmbus --- .../SILABS/EFR32FG23x0xx/TEMPLATE/Makefile | 5 +- .../EFR32FG23x0xx/TEMPLATE/cfg/mcuconf.h | 6 +- testhal/SILABS/EFR32FG23x0xx/TEMPLATE/main.c | 302 +++++++----- .../TEMPLATE/xmlmbus/include/xmlmbus_buffer.h | 55 +++ .../xmlmbus/include/xmlmbus_mbus_common.h | 105 ++++ .../xmlmbus/include/xmlmbus_mbus_frame.h | 124 +++++ .../xmlmbus_mbus_proprietary_structs.h | 212 ++++++++ .../xmlmbus/include/xmlmbus_platform.h | 52 ++ .../TEMPLATE/xmlmbus/include/xmlmbus_server.h | 167 +++++++ .../TEMPLATE/xmlmbus/include/xmlmbus_util.h | 51 ++ .../TEMPLATE/xmlmbus/src/xmlmbus_buffer.c | 115 +++++ .../TEMPLATE/xmlmbus/src/xmlmbus_mbus_frame.c | 254 ++++++++++ .../TEMPLATE/xmlmbus/src/xmlmbus_server.c | 460 ++++++++++++++++++ .../TEMPLATE/xmlmbus/src/xmlmbus_util.c | 91 ++++ .../TEMPLATE/xmlmbus/xmlmbus_chibios.c | 143 ++++++ .../TEMPLATE/xmlmbus/xmlmbus_chibios.h | 45 ++ .../TEMPLATE/xmlmbus/xmlmbus_chibios.mk | 15 + 17 files changed, 2075 insertions(+), 127 deletions(-) create mode 100644 testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_buffer.h create mode 100644 testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_mbus_common.h create mode 100644 testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_mbus_frame.h create mode 100644 testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_mbus_proprietary_structs.h create mode 100644 testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_platform.h create mode 100644 testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_server.h create mode 100644 testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_util.h create mode 100644 testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/src/xmlmbus_buffer.c create mode 100644 testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/src/xmlmbus_mbus_frame.c create mode 100644 testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/src/xmlmbus_server.c create mode 100644 testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/src/xmlmbus_util.c create mode 100644 testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/xmlmbus_chibios.c create mode 100644 testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/xmlmbus_chibios.h create mode 100644 testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/xmlmbus_chibios.mk diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/Makefile b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/Makefile index b64592d702..55f4411ac1 100644 --- a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/Makefile +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/Makefile @@ -105,7 +105,7 @@ include $(CHIBIOS_CONTRIB)/os/hal/hal.mk include $(CHIBIOS)/os/hal/osal/rt-nil/osal.mk include $(CHIBIOS_CONTRIB)/os/hal/ports/SILABS/EFR32FG23/platform.mk include $(CHIBIOS_CONTRIB)/os/hal/boards/SILABS_EFR32FG23_DK2600A/board.mk -include $(CHIBIOS_CONTRIB)/ext/xmlmbus/xmlmbus_chibios.mk +include xmlmbus/xmlmbus_chibios.mk include emlib/emlib.mk include raillib/raillib.mk # RTOS files (optional). @@ -178,7 +178,8 @@ UDEFS += \ -DCLKIN0_FREQ=0UL \ -DLFRCO_FREQ=32768UL \ -DULFRCO_FREQ=1000UL \ - -DLFXO_FREQ=LFRCO_FREQ + -DLFXO_FREQ=LFRCO_FREQ \ + -DXMLMBUS_SERVER_HAS_MALLOC=0 # -DSL_TRUSTZONE_NONSECURE # -DSL_TRUSTZONE_SECURE \ diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/cfg/mcuconf.h b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/cfg/mcuconf.h index 3116692344..b806ae7f04 100644 --- a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/cfg/mcuconf.h +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/cfg/mcuconf.h @@ -70,7 +70,7 @@ #define EFR32_EM4GRPACLKSEL EFR32_EM4GRPACLKSEL_LFXO #define EFR32_EM4GRPACLK_ENABLED (EFR32_EM4GRPACLKSEL != EFR32_EM4GRPACLKSEL_NOCLOCK) -#define EFR32_EUSART1SEL EFR32_EUSART1SEL_EM01GRPCCLK +#define EFR32_EUSART1SEL EFR32_EUSART1SEL_LFXO #define EFR32_EUSART23SEL EFR32_EUSART23SEL_HFRCODPLL @@ -92,9 +92,9 @@ * SIO driver system settings. */ #define EFR32_SIO_USE_EUSART1 TRUE -#define EFR32_SIO_USE_EUSART2 TRUE +#define EFR32_SIO_USE_EUSART2 FALSE #define EFR32_SIO_USE_EUSART3 FALSE -#define EFR32_SIO_USE_USART1 TRUE +#define EFR32_SIO_USE_USART1 FALSE #define EFR32_EUSART1_RX_IRQ_PRIORITY 4 #define EFR32_EUSART1_TX_IRQ_PRIORITY 4 #define EFR32_EUSART2_RX_IRQ_PRIORITY 4 diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/main.c b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/main.c index 63728305cf..96ed30e9e7 100644 --- a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/main.c +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/main.c @@ -18,10 +18,10 @@ #include "cmsis_os.h" #include "hal.h" -#include "rail.h" -#include "sli_rail_util_callbacks.h" // for internal-only callback signatures -#include "sl_rail_util_init.h" -#include "sl_rail_util_protocol.h" +#include +#include +#include +#include static void led_on(void) { @@ -43,143 +43,163 @@ static void led_toggle(void) { palTogglePad(GPIOB, 2); } -void st_callback(unsigned alarm) { +/* Must return XMLMBUS_SERVER_OK if no error. */ +static int req_ud2_handler(struct xmlmbus_server_ctx *ctx, void *arg) { - stStopAlarmN(alarm); - stStartAlarmN(alarm, stGetCounter() + chTimeMS2I(3000)); -} + (void)arg; + int rc; -extern const RAIL_ChannelConfig_t *channelConfigs[]; + if (XMLMBUS_SERVER_OK != (rc = xmlmbus_server_write_fixed_header(ctx))) + return rc; -static RAIL_Handle_t railHandle; + return XMLMBUS_SERVER_OK; +} -enum { - WMBUS_MODE_T1A = 0, - WMBUS_MODE_C1A = 1, - WMBUS_MODE_S1 = 2 -}; +/* Must return XMLMBUS_SERVER_OK if no error. */ +static int snd_ud_read_memory(struct xmlmbus_server_ctx *ctx, void *arg, const uint8_t *in, uint32_t inlen, void *out, uint32_t *outlen) { -static void send_datagram(void) { + (void)ctx; + (void)arg; - static const uint8_t wmbus_datagram_1[] = { - 0x31, 0x44, 0x93, 0x44, 0x48, 0x32, 0x75, 0x26, 0x35, 0x08, // 0x6D, 0x95, - 0x7A, 0xA3, 0x00, 0x00, 0x20, 0x0B, 0x6E, 0x16, 0x00, 0x00, 0x4B, 0x6E, 0x21, 0x02, 0x00, 0x42, // 0x91, 0xDD, - 0x6C, 0xBF, 0x2A, 0xCB, 0x08, 0x6E, 0x16, 0x00, 0x00, 0xC2, 0x08, 0x6C, 0xDE, 0x29, 0x32, 0x6C, // 0x8C, 0xC4, - 0xFF, 0xFF, 0x04, 0x6D, 0x27, 0x0E, 0xD2, 0x2A, // 0x3D, 0x89 - }; + const uint32_t outlen_max = *outlen; - CC_ALIGN_DATA(16)static uint8_t railFifo[1024]; + static uint8_t simulated_memory[256]; - static int config_nr = WMBUS_MODE_T1A; - const RAIL_ChannelConfig_t *channel_config = channelConfigs[config_nr]; - config_nr = (config_nr + 1) % 3; - (void)RAIL_ConfigChannels(railHandle, channel_config, - &sli_rail_util_on_channel_config_change); + MemoryBlock_t memory_block; + if (inlen != sizeof(memory_block)) + return XMLMBUS_SERVER_ERROR_WRONG_DATA_LENGTH; - led_toggle(); + memcpy(&memory_block, in, sizeof(memory_block)); - #define RAIL_CHANNEL_0 0 - memcpy(railFifo, wmbus_datagram_1, sizeof(wmbus_datagram_1)); - RAIL_SetTxFifo(railHandle, railFifo, sizeof(wmbus_datagram_1), sizeof(railFifo)); - RAIL_StartTx(railHandle, RAIL_CHANNEL_0, RAIL_TX_OPTIONS_DEFAULT, NULL); + *outlen = MIN(outlen_max, MIN(memory_block.size, sizeof(simulated_memory))); + memcpy(out, simulated_memory, *outlen); + + return XMLMBUS_SERVER_OK; } -/* Overload weak function from sl_rail_util_callbacks.c. */ -void sl_rail_util_on_assert_failed(RAIL_Handle_t rail_handle, - RAIL_AssertErrorCodes_t error_code) { +static int snd_nke_handler(struct xmlmbus_server_ctx *ctx) { + + if (0 != xmlmbus_buffer_write_cfield(&ctx->buffer, MBUS_ACK)) + return (-1); - (void)rail_handle; - (void)error_code; - osalDbgAssert(false, "rail_handle with error_code"); + return 0; } -/* Overload weak function from sl_rail_util_callbacks.c. */ -void sl_rail_util_on_rf_ready(RAIL_Handle_t rail_handle) { +static const struct ctrl_cmd ctrl_cmd_table[] = { + { MBUS_REQ_UD2 | MBUS_CFIELD_FCB | MBUS_CFIELD_FCV, req_ud2_handler, NULL }, + { MBUS_REQ_UD2 | MBUS_CFIELD_FCV, req_ud2_handler, NULL }, + { MBUS_REQ_UD2 | MBUS_CFIELD_FCB, req_ud2_handler, NULL }, + { MBUS_REQ_UD2, req_ud2_handler, NULL }, +}; + +static const struct appl_cmd appl_cmd_table[] = { + { VIFE_LAYER1_APPLICATION & VIFE_LAYER_MASK, + VIFE_REQUEST_TYPE_MEMORY & VIFE_REQUEST_MASK, + VIFE_FUNCTION_READ_MEMORY & VIFE_FUNCTION_MASK, + snd_ud_read_memory, NULL }, +}; + +static const struct ci_cmd ci_cmd_table[] = { + { MBUS_SND_UD | MBUS_CFIELD_FCB | MBUS_CFIELD_FCV, MBUS_CI_DATA_SEND, xmlmbus_server_snd_ud_handler, NULL }, + { MBUS_SND_UD | MBUS_CFIELD_FCV, MBUS_CI_DATA_SEND, xmlmbus_server_snd_ud_handler, NULL }, + { MBUS_SND_UD | MBUS_CFIELD_FCB, MBUS_CI_DATA_SEND, xmlmbus_server_snd_ud_handler, NULL }, + { MBUS_SND_UD, MBUS_CI_DATA_SEND, xmlmbus_server_snd_ud_handler, NULL }, +}; + +static const SIOConfig sio_config = { + .baud = 2400U, /* Baudrate (2400 max. for LF operation) */ + .cfg0 = (0U << 0) | /* ASYNC operation */ + (4U << 5), /* Disable oversampling (for LF operation) */ + .framecfg = EFR32_SIO_LLD_EUSART_8E1, +}; + +static struct xmlmbus_server_ctx server_ctx = { + + .address = MBUS_ADDRESS_UNCONFIGURED, + .ident_no = 0x12345678, /* BCD number. */ + .manufacturer = 0xAABB, + .version = 0, + .medium = 0xFF, + + .ctrl_cmd_table = ctrl_cmd_table, + .ctrl_cmd_table_size = ARRAY_SIZE(ctrl_cmd_table), + .ci_cmd_table = ci_cmd_table, + .ci_cmd_table_size = ARRAY_SIZE(ci_cmd_table), + .appl_cmd_table = appl_cmd_table, + .appl_cmd_table_size = ARRAY_SIZE(appl_cmd_table), + .single_character_handler = snd_nke_handler, +}; + +static int cmd_read_timeout = 5000; /* Milliseconds. */ +static int cmd_write_timeout = 5000; /* Milliseconds. */ +static uint8_t buffer[MBUS_FRAME_SIZE_MAX]; + +static int server_iface_open(struct xmlmbus_interface *iface, int flags) { + + (void)flags; - (void)rail_handle; + #if EFR32_SIO_USE_EUSART1 == TRUE + palSetPadMode(GPIOA, 7, PAL_MODE_OUTPUT_PUSHPULL | PAL_MODE_ALTERNATE(CLKOUT2_LFXO)); + + palSetPadMode(GPIOA, 9, PAL_MODE_OUTPUT_PUSHPULL | PAL_MODE_ALTERNATE(EUSART0_TX)); + palSetPadMode(GPIOA, 10, PAL_MODE_INPUT_PULLUP | PAL_MODE_ALTERNATE(EUSART0_RX)); + + sioStart(iface->siop, &sio_config); + #else + #error "EUSART1 disabled!" + #endif + + return 0; } -/* Overload weak function from sl_rail_util_callbacks.c. */ -void sl_rail_util_on_channel_config_change(RAIL_Handle_t rail_handle, - const RAIL_ChannelConfigEntry_t *entry) { +static int server_iface_close(struct xmlmbus_interface *iface) { + + sioStop(iface->siop); + + palSetPadMode(GPIOA, 9, PAL_MODE_ALTERNATE(EUSART0_TX_DIS)); + palSetPadMode(GPIOA, 10, PAL_MODE_ALTERNATE(EUSART0_RX_DIS)); - (void)rail_handle; - (void)entry; + return 0; } -/* Overload weak function from sl_rail_util_callbacks.c. */ -void sl_rail_util_on_event(RAIL_Handle_t rail_handle, - RAIL_Events_t events) { +static int server_iface_read(struct xmlmbus_interface *iface, void *buf, unsigned long len, int flags, int timeout_msec) { - (void)rail_handle; - (void)events; + (void)flags; + + msg_t msg = sioSynchronizeRX(iface->siop, TIME_MS2I(timeout_msec)); + if (msg == MSG_OK) { + return (sioAsyncRead(iface->siop, buf, len)); + } + + return (-1); } -void custom_RAIL_Init(void) { - - RAIL_Status_t status; - (void)status; - - RAIL_Config_t sl_rail_config = { - .eventsCallback = &sli_rail_util_on_event, - // Other fields are ignored nowadays - }; - railHandle = RAIL_Init(&sl_rail_config, &sli_rail_util_on_rf_ready); - - RAIL_DataConfig_t data_config = { - .txSource = SL_RAIL_UTIL_INIT_DATA_FORMAT_INST0_TX_SOURCE, - .rxSource = SL_RAIL_UTIL_INIT_DATA_FORMAT_INST0_RX_SOURCE, - .txMethod = SL_RAIL_UTIL_INIT_DATA_FORMAT_INST0_TX_MODE, - .rxMethod = SL_RAIL_UTIL_INIT_DATA_FORMAT_INST0_RX_MODE, - }; - status = RAIL_ConfigData(railHandle, &data_config); - osalDbgCheck(status == RAIL_STATUS_NO_ERROR); - - const RAIL_ChannelConfig_t *channel_config = channelConfigs[WMBUS_MODE_C1A]; - - (void)RAIL_ConfigChannels(railHandle, - channel_config, - &sli_rail_util_on_channel_config_change); - status = sl_rail_util_protocol_config(railHandle, - SL_RAIL_UTIL_INIT_PROTOCOL_INST0_DEFAULT); - osalDbgCheck(status == RAIL_STATUS_NO_ERROR); - - status = RAIL_ConfigCal(railHandle, - 0U - | (SL_RAIL_UTIL_INIT_CALIBRATION_TEMPERATURE_NOTIFY_INST0_ENABLE - ? RAIL_CAL_TEMP : 0U) - | (SL_RAIL_UTIL_INIT_CALIBRATION_ONETIME_NOTIFY_INST0_ENABLE - ? RAIL_CAL_ONETIME : 0U)); - osalDbgCheck(status == RAIL_STATUS_NO_ERROR); - - status = RAIL_ConfigEvents(railHandle, RAIL_EVENTS_ALL, - SL_RAIL_UTIL_INIT_EVENT_INST0_MASK); - osalDbgCheck(status == RAIL_STATUS_NO_ERROR); - - RAIL_StateTransitions_t tx_transitions = { - .success = SL_RAIL_UTIL_INIT_TRANSITION_INST0_TX_SUCCESS, - .error = SL_RAIL_UTIL_INIT_TRANSITION_INST0_TX_ERROR - }; - status = RAIL_SetTxTransitions(railHandle, - &tx_transitions); - osalDbgCheck(status == RAIL_STATUS_NO_ERROR); - - RAIL_StateTransitions_t rx_transitions = { - .success = SL_RAIL_UTIL_INIT_TRANSITION_INST0_RX_SUCCESS, - .error = SL_RAIL_UTIL_INIT_TRANSITION_INST0_RX_ERROR - }; - status = RAIL_SetRxTransitions(railHandle, - &rx_transitions); - osalDbgCheck(status == RAIL_STATUS_NO_ERROR); +static int server_iface_write(struct xmlmbus_interface *iface, const void *buf, unsigned long len, int flags, int timeout_msec) { + + (void)flags; + + msg_t msg = sioSynchronizeTX(iface->siop, TIME_MS2I(timeout_msec)); + if (msg == MSG_OK) { + return (sioAsyncWrite(iface->siop, buf, len)); + } + + return (-1); } +static struct xmlmbus_interface server_iface = { + .siop = &SIOD1, + .open = server_iface_open, + .close = server_iface_close, + .read = server_iface_read, + .write = server_iface_write, +}; + /* * Application entry point. */ int main(void) { - int unused = 0; - (void)unused; + int rc; /* HAL initialization, this also initializes the configured device drivers and performs the board-specific initializations.*/ @@ -194,24 +214,62 @@ int main(void) { by default.*/ osKernelStart(); - led_off(); - custom_RAIL_Init(); - stSetCallback(1, st_callback); - stStartAlarmN(1, stGetCounter() + chTimeMS2I(3000)); - led_on(); - - //RAIL_TxStreamStart(railHandle, RAIL_STREAM_PN9_STREAM); - //RAIL_TxStreamStart(railHandle, RAIL_STREAM_CARRIER_WAVE); - - systime_t prev = chVTGetSystemTime(); + xmlmbus_interface_open(&server_iface, 0); /* * Normal main() thread activity, in this demo it does nothing except * sleeping in a loop and check the button state. */ while (true) { - send_datagram(); - prev = chThdSleepUntilWindowed(prev, chTimeAddX(prev, TIME_MS2I(3000))); + led_off(); + + int mbus_packet_size = xmlmbus_interface_read(&server_iface, buffer, sizeof(buffer), 0, cmd_read_timeout); + + if (mbus_packet_size > 0) { + led_on(); + + //log_buffer("REQUEST >>", buffer, mbus_packet_size); + + rc = xmlmbus_server_process_client_request(&server_ctx, buffer, mbus_packet_size); + if (rc != XMLMBUS_SERVER_OK) { + //fprintf(stderr, "Error processing client request: %d.\n", rc); + continue; + } + + unsigned long response_len = xmlmbus_server_get_response_buffer_used(&server_ctx); + if (response_len == 0) { + /* It must have been SND-NKE - don't respond at all. */ + continue; + } + + unsigned long buffer_used = 0; + rc = xmlmbus_interface_create_packet(&server_iface, buffer, &buffer_used, + xmlmbus_server_get_response_buffer(&server_ctx), + response_len); + if (rc != 0) { + //fprintf(stderr, "Error creating packet: %d.\n", rc); + continue; + } + + //log_buffer("RESPOND <<", buffer, buffer_used); + + if ((int)buffer_used != xmlmbus_interface_write(&server_iface, buffer, buffer_used, 0, cmd_write_timeout)) { + //fprintf(stderr, "Error writing response: %d.\n", rc); + continue; + } + + led_toggle(); + } + else if (mbus_packet_size < 0) { + rc = XMLMBUS_SERVER_ERROR; + //fprintf(stderr, "Error reading request: %d.\n", rc); + break; + } + else { + /* Nothing read. */ + } } + + xmlmbus_interface_close(&server_iface); } diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_buffer.h b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_buffer.h new file mode 100644 index 0000000000..d185ad503f --- /dev/null +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_buffer.h @@ -0,0 +1,55 @@ +/* + Copyright 2024 Xael South + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#pragma once + +#include +#include + +#include + +struct xmlmbus_buffer { + + uint8_t data[MBUS_FRAME_SIZE_MAX]; + size_t length; /** Number of bytes used in data. */ +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + +int xmlmbus_buffer_write_u8(struct xmlmbus_buffer*, uint8_t); + +int xmlmbus_buffer_write_u16(struct xmlmbus_buffer*, uint16_t); + +int xmlmbus_buffer_write_u24(struct xmlmbus_buffer *buffer, uint32_t); + +int xmlmbus_buffer_write_u32(struct xmlmbus_buffer*, uint32_t); + +int xmlmbus_buffer_write_u64(struct xmlmbus_buffer*, uint64_t); + +int xmlmbus_buffer_write_blob(struct xmlmbus_buffer*, const void*, size_t); + +int xmlmbus_buffer_write_cfield(struct xmlmbus_buffer*, uint8_t); + +int xmlmbus_buffer_write_afield(struct xmlmbus_buffer*, uint8_t); + +int xmlmbus_buffer_write_cifield(struct xmlmbus_buffer*, uint8_t); + +#ifdef __cplusplus +} +#endif diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_mbus_common.h b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_mbus_common.h new file mode 100644 index 0000000000..35a7d3efb7 --- /dev/null +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_mbus_common.h @@ -0,0 +1,105 @@ +/* + Copyright 2024 Xael South + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#pragma once + +#include + +#define MBUS_FRAME_SINGLE_START 0xE5u +#define MBUS_FRAME_SHORT_START 0x10u +#define MBUS_FRAME_LONG_START 0x68u +#define MBUS_FRAME_STOP 0x16u + +#define MBUS_ACK 0xE5u + +#define MBUS_FRAME_SIZE_SINGLE_CHARACTER 1u +#define MBUS_FRAME_SIZE_SHORT 5u +#define MBUS_FRAME_SIZE_CONTROL 9u +#define MBUS_FRAME_SIZE_DATA_SHORT (MBUS_FRAME_SIZE_SHORT - 3u) +#define MBUS_FRAME_SIZE_DATA_MAX 252u +#define MBUS_FRAME_SIZE_MAX (9u + MBUS_FRAME_SIZE_DATA_MAX) + +#define MBUS_ADDRESS_UNCONFIGURED 0u +#define MBUS_ADDRESS_MIN 1u +#define MBUS_ADDRESS_MAX 250u +#define MBUS_ADDRESS_RESERVED_251 251u +#define MBUS_ADDRESS_RESERVED_252 252u +#define MBUS_ADDRESS_IN_NETWORK_LAYER 253u +#define MBUS_ADDRESS_BROADCAST_ALL_REPLY 254u +#define MBUS_ADDRESS_BROADCAST_NO_REPLY 255u + +#define MBUS_CFIELD_REQUEST (1u << 6) /**< Calling direction. */ +#define MBUS_CFIELD_RESPONSE (0u << 6) /**< Reply direction. */ + +#define MBUS_CFIELD_FCB (1u << 5) /**< Frame Count Bit indicates successful transmission procedures. */ +#define MBUS_CFIELD_FCV (1u << 4) /**< Frame Count Valid is set -> FCB is used; FCV is not set -> FCB is ignored. */ + +#define MBUS_CFIELD_ACD (1u << 5) /**< With Access Demand bit set the slave shows that it wants to transmit Class 1 data. */ +#define MBUS_CFIELD_DFC (1u << 4) /**< With Data Flow Control bit is set the slave indicates that it can't accept any further data. */ + +#define MBUS_CFIELD_FUNCTION(f) (((f) & 0xFu) << 0) + +/** Initialization of Slave */ +#define MBUS_SND_NKE (MBUS_CFIELD_REQUEST | MBUS_CFIELD_FUNCTION(0x0)) + +/** Send User Data to Slave */ +#define MBUS_SND_UD (MBUS_CFIELD_REQUEST | MBUS_CFIELD_FUNCTION(0x3)) + +/** Request for Class 2 Data */ +#define MBUS_REQ_UD2 (MBUS_CFIELD_REQUEST | MBUS_CFIELD_FUNCTION(0xB)) + +/** Request for Class1 Data */ +#define MBUS_REQ_UD1 (MBUS_CFIELD_REQUEST | MBUS_CFIELD_FUNCTION(0xA)) + +/** Data Transfer from Slave to Master after Request */ +#define RSP_UD (MBUS_CFIELD_RESPONSE | MBUS_CFIELD_FUNCTION(0x8)) + +/* CI-Field codes used by the master. */ +#define MBUS_CI_DATA_SEND 0x51u +#define MBUS_CI_SELECTION_OF_SLAVES 0x52u +#define MBUS_CI_APPLICATION_RESET 0x50u +#define MBUS_CI_SYNCHRONIZE_ACTION 0x54u +#define MBUS_CI_SET_BAUDRATE_TO_300 0xB8u +#define MBUS_CI_SET_BAUDRATE_TO_600 0xB9u +#define MBUS_CI_SET_BAUDRATE_TO_1200 0xBAu +#define MBUS_CI_SET_BAUDRATE_TO_2400 0xBBu +#define MBUS_CI_SET_BAUDRATE_TO_4800 0xBCu +#define MBUS_CI_SET_BAUDRATE_TO_9600 0xBDu +#define MBUS_CI_SET_BAUDRATE_TO_19200 0xBEu +#define MBUS_CI_SET_BAUDRATE_TO_38400 0xBFu +#define MBUS_CI_RAM_READOUT 0xB1u +#define MBUS_CI_RAM_WRITE 0xB2u +#define MBUS_CI_INIT_TEST_MODE 0xB3u +#define MBUS_CI_EEPROM_READ 0xB4u +#define MBUS_CI_START_SOFTWARE_TEST 0xB6u + +/* CI-Field codes used by the slave. */ +#define MBUS_CI_REPORT_GENERAL_APPLICATION_ERROR 0x70u +#define MBUS_CI_REPORT_ALARM_STATUS 0x71u +#define MBUS_CI_VARIABLE_DATA_RESPOND 0x72u +#define MBUS_CI_FIXED_DATA_RESPOND 0x73u + +/* 6.3.1 Fixed Data Header */ +struct mbus_fixed_data_header { + uint32_t ident_no; + uint16_t manufacturer; + uint8_t version; + uint8_t medium; + uint8_t access_number; + uint8_t status; + uint16_t signature; +}; + diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_mbus_frame.h b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_mbus_frame.h new file mode 100644 index 0000000000..8b1102028b --- /dev/null +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_mbus_frame.h @@ -0,0 +1,124 @@ +/* + Copyright 2024 Xael South + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#pragma once + +#include + +#include + +typedef enum { + + XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_START_1 = 0, + XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_LENGTH_1, + XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_LENGTH_2, + XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_START_2, + XMLMBUS_MBUS_RX_FRAME_STATE_RX_DATA, + XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_CRC, + XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_STOP +} xmlmbus_mbus_rx_frame_state_t; + +struct xmlmbus_mbus_frame_state_machine_data { + int state; + uint8_t length_1; + uint8_t length_2; + uint8_t checksum; + unsigned bytes_to_receive; + unsigned datalen; + + union { + unsigned info; + + struct { + + unsigned length_error: 1; + unsigned start2_error: 1; + unsigned checksum_error: 1; + unsigned stop_error: 1; + unsigned rx_complete: 1; + } status; + }; + + uint8_t data[MBUS_FRAME_SIZE_MAX]; +}; + +struct mbus_single_frame { + uint8_t start; +}; + +struct mbus_short_frame { + uint8_t start; + uint8_t c; + uint8_t a; + uint8_t checksum; + uint8_t stop; +}; + +struct mbus_control_frame { + uint8_t start; + uint8_t length_1; + uint8_t length_2; + uint8_t start_2; + uint8_t c; + uint8_t a; + uint8_t ci; + uint8_t checksum; + uint8_t stop; +}; + +struct mbus_long_frame_header { + uint8_t start; + uint8_t length_1; + uint8_t length_2; + uint8_t start_2; + uint8_t c; + uint8_t a; + uint8_t ci; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + +void xmlmbus_reset_state_machine(struct xmlmbus_mbus_frame_state_machine_data *mach); + +int xmlmbus_process_state_machine(struct xmlmbus_mbus_frame_state_machine_data *mach, uint8_t b); + +void xmlmbus_mbus_frame_clear_error_mask(struct xmlmbus_mbus_frame_state_machine_data *mach); + +int xmlmbus_mbus_frame_is_length_error(const struct xmlmbus_mbus_frame_state_machine_data *mach); + +int xmlmbus_mbus_frame_is_start2_error(const struct xmlmbus_mbus_frame_state_machine_data *mach); + +int xmlmbus_mbus_frame_is_stop_error(const struct xmlmbus_mbus_frame_state_machine_data *mach); + +int xmlmbus_mbus_frame_is_checksum_error(const struct xmlmbus_mbus_frame_state_machine_data *mach); + +int xmlmbus_mbus_frame_is_good(const struct xmlmbus_mbus_frame_state_machine_data *mach); + +int xmlmbus_mbus_frame_is_rx_complete(const struct xmlmbus_mbus_frame_state_machine_data *mach); + +uint8_t xmlmbus_mbus_checksum(const uint8_t *buf, unsigned buflen); + +const uint8_t* xmlmbus_mbus_frame_get_data(const struct xmlmbus_mbus_frame_state_machine_data *mach); + +unsigned xmlmbus_mbus_frame_get_datalen(const struct xmlmbus_mbus_frame_state_machine_data *mach); + +#ifdef __cplusplus +} +#endif + diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_mbus_proprietary_structs.h b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_mbus_proprietary_structs.h new file mode 100644 index 0000000000..612413460e --- /dev/null +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_mbus_proprietary_structs.h @@ -0,0 +1,212 @@ +/* + Copyright 2024 Xael South + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* Don't edit this file, it's generated. */ + +#pragma once + +#include + +#include + +union VIF { + uint8_t value; + + struct { + uint8_t lsb: 7; + uint8_t msb: 1; + } vif; +}; + +struct xmlmbus_dib_with_data { + union VIF vife_layer; + union VIF vife_request; + union VIF vife_function; + union VIF vife_response; + const void *blob; + size_t blobsize; +}; + +#define DIF_BINARY_DATA_LENGTH_IS_0 0x00u +#define DIF_BINARY_DATA_LENGTH_IS_1 0x01u +#define DIF_BINARY_DATA_LENGTH_IS_2 0x02u +#define DIF_BINARY_DATA_LENGTH_IS_3 0x03u +#define DIF_BINARY_DATA_LENGTH_IS_4 0x04u +#define DIF_BINARY_DATA_LENGTH_IS_6 0x06u +#define DIF_BINARY_DATA_LENGTH_IS_8 0x07u +#define DIF_DATA_LENGTH_IS_LVAR 0x0Du +#define DIF_DATA_LENGTH_IS_INVALID 0xFFu +#define DIF_MANUFACTURER_SPECIAL_FUNCTION 0x0Fu + +#define VIF_MANUFACTURER_SPECIFIC 0xFFu + +#define VIFE_LAYER_MASK 0x03u +#define VIFE_LAYER_AUTHORIZATION 0x40u +#define VIFE_LAYER1_APPLICATION 0x41u + +#define VIFE_REQUEST_MASK 0x0Fu +#define VIFE_REQUEST_TYPE_SYSTEM 0x00u +#define VIFE_REQUEST_TYPE_DEVICE 0x01u +#define VIFE_REQUEST_TYPE_SETTINGS 0x02u +#define VIFE_REQUEST_TYPE_DATETIME 0x03u +#define VIFE_REQUEST_TYPE_STATUS 0x04u +#define VIFE_REQUEST_TYPE_RADIO 0x05u +#define VIFE_REQUEST_TYPE_VALUES 0x06u +#define VIFE_REQUEST_TYPE_MEMORY 0x07u + +#define VIFE_RESPONSE_MASK 0x1Fu +#define VIFE_RESPONSE_TYPE_CMD_EXEC_SUCCESS 0x10u +#define VIFE_RESPONSE_TYPE_CMD_EXEC_ERROR 0x11u +#define VIFE_RESPONSE_TYPE_CMD_UNIMPLEMENTED 0x12u +#define VIFE_RESPONSE_TYPE_CMD_UNAUTHORIZED 0x13u +#define VIFE_RESPONSE_TYPE_CMD_HAS_WRONG_PARAMETER 0x14u +#define VIFE_RESPONSE_TYPE_CMD_EXEC_RESULT 0x15u +#define VIFE_RESPONSE_TYPE_DEVICE_IS_BUSY 0x16u + +#define VIFE_FUNCTION_MASK 0x3Fu +#define VIFE_FUNCTION_READ_MEMORY 0x20u + +static inline uint8_t xmlmbus_get_dif_from_size(size_t size) { + + switch (size) { + case 0: + return DIF_BINARY_DATA_LENGTH_IS_0; + case 1: + return DIF_BINARY_DATA_LENGTH_IS_1; + case 2: + return DIF_BINARY_DATA_LENGTH_IS_2; + case 3: + return DIF_BINARY_DATA_LENGTH_IS_3; + case 4: + return DIF_BINARY_DATA_LENGTH_IS_4; + case 6: + return DIF_BINARY_DATA_LENGTH_IS_6; + case 8: + return DIF_BINARY_DATA_LENGTH_IS_8; + default: + break; + } + + return DIF_DATA_LENGTH_IS_LVAR; +} + +/** @return Length of application data or DIF_DATA_LENGTH_IS_INVALID in case of error. */ +static inline uint8_t xmlmbus_get_size_from_dif(uint8_t dif) { + + switch (dif) { + case DIF_BINARY_DATA_LENGTH_IS_0: + return 0; + + case DIF_BINARY_DATA_LENGTH_IS_1: + return 1; + + case DIF_BINARY_DATA_LENGTH_IS_2: + return 2; + + case DIF_BINARY_DATA_LENGTH_IS_3: + return 3; + + case DIF_BINARY_DATA_LENGTH_IS_4: + return 4; + + case DIF_BINARY_DATA_LENGTH_IS_6: + return 6; + + case DIF_BINARY_DATA_LENGTH_IS_8: + return 8; + + case DIF_DATA_LENGTH_IS_LVAR: + return DIF_DATA_LENGTH_IS_LVAR; /* Max length is in LVAR. */ + } + + return DIF_DATA_LENGTH_IS_INVALID; +} + +typedef enum XMLMBUS_ATTRIBUTE_PACKED { + BUILD_TYPE_RELEASE = 0, + BUILD_TYPE_DEBUG = 1 +} BuildType_t; + +typedef struct XMLMBUS_ATTRIBUTE_PACKED { + uint8_t major; + uint8_t minor; + uint8_t patch; + BuildType_t build_type; + uint16_t build_number; +} SoftwareVersion_t; + +typedef struct XMLMBUS_ATTRIBUTE_PACKED { + uint8_t major; + uint8_t minor; +} HardwareVersion_t; + +typedef struct XMLMBUS_ATTRIBUTE_PACKED { + SoftwareVersion_t sofware_version; + HardwareVersion_t hardware_version; + uint64_t reserved1; + uint64_t reserved2; +} DeviceIdentification_t; + +typedef struct XMLMBUS_ATTRIBUTE_PACKED { + uint64_t address; + uint32_t size; +} MemoryBlock_t; + +typedef struct XMLMBUS_ATTRIBUTE_PACKED { + uint8_t code[8]; +} Authcode_t; + +typedef struct XMLMBUS_ATTRIBUTE_PACKED { + uint32_t year: 8; /**< Years since 1980. */ + uint32_t month: 4; /**< Months 1..12. */ + uint32_t dstflag: 1; /**< DST correction flag. */ + uint32_t dayofweek: 3; /**< Day of week 1..7. */ + uint32_t day: 5; /**< Day of the month 1..31. */ + uint32_t milliseconds: 27; /**< Milliseconds since midnight. */ +} RTCDateTime_t; + +typedef struct XMLMBUS_ATTRIBUTE_PACKED { + uint32_t milliseconds; +} TimeoutMilliseconds_t; + +#define Default_SoftwareVersion_t (SoftwareVersion_t) { \ + .major = 0, .minor = 0, .patch = 0, .build_type = BUILD_TYPE_RELEASE, .build_number = 0 \ +} + +#define Default_HardwareVersion_t (HardwareVersion_t) { \ + .major = 0, .minor = 0 \ +} + +#define Default_DeviceIdentification_t (DeviceIdentification_t) { \ + .sofware_version = Default_SoftwareVersion_t, .hardware_version = Default_HardwareVersion_t, .reserved1 = 0, .reserved2 = 0 \ +} + +#define Default_MemoryBlock_t (MemoryBlock_t) { \ + .address = 0, .size = 0 \ +} + +#define Default_Authcode_t (Authcode_t) { \ + .code = {0, 0, 0, 0, 0, 0, 0, 0} \ +} + +#define Default_RTCDateTime_t (RTCDateTime_t) { \ + .year = 0, .month = 0, .dstflag = 0, .dayofweek = 0, .day = 0, .milliseconds = 0 \ +} + +#define Default_TimeoutMilliseconds_t (TimeoutMilliseconds_t) { \ + .milliseconds = 0 \ +} + diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_platform.h b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_platform.h new file mode 100644 index 0000000000..537a2966fa --- /dev/null +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_platform.h @@ -0,0 +1,52 @@ +/* + Copyright 2024 Xael South + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#pragma once + +#include + +#if !defined(MSVC_COMPILER) +#if defined(_MSC_VER) || defined(_MSC_FULL_VER) +#define MSVC_COMPILER 1 +#else +#define MSVC_COMPILER 0 +#define XMLMBUS_ATTRIBUTE_USED __attribute__((used)) +#define XMLMBUS_ATTRIBUTE_PACKED __attribute__((packed)) +#endif +#endif + +#if !defined(WINDOWS_BUILD) +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) || defined(__CYGWIN__) +#define WINDOWS_BUILD 1 + +#define msleep(msecs) Sleep(msecs) +#else +#define WINDOWS_BUILD 0 + +#include + +typedef int XMLMBUS_SOCKET; + +#define XMLMBUS_INVALID_SOCKET -1 +#define XMLMBUS_SOCKET_ERROR (-1) +#define XMLMBUS_SOCKET_EINPROGRESS EINPROGRESS + +#define xmlmbus_closesocket(fd) close(fd) + +#define msleep(msecs) usleep(msecs*1000) +#endif +#endif + diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_server.h b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_server.h new file mode 100644 index 0000000000..88b8281d82 --- /dev/null +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_server.h @@ -0,0 +1,167 @@ +/* + Copyright 2024 Xael South + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#pragma once + +#include +#include +#include + +#include +#include + +#ifndef XMLMBUS_SERVER_HAS_MALLOC +#define XMLMBUS_SERVER_HAS_MALLOC 1 +#endif + +enum xmlmbus_server_error { + XMLMBUS_SERVER_OK = 0, /* Must have the same value as XMLMBUS_OK. */ + + XMLMBUS_SERVER_ERROR = 0x1000, /* Must be "above" all other XMLLMBUS_ERROR_x. */ + XMLMBUS_SERVER_ERROR_NO_MEMORY, + XMLMBUS_SERVER_ERROR_WRONG_DIRECTION_IN_CFIELD, + XMLMBUS_SERVER_ERROR_WRONG_CI, + XMLMBUS_SERVER_ERROR_WRONG_DIF, + XMLMBUS_SERVER_ERROR_WRONG_VIF, + XMLMBUS_SERVER_ERROR_WRONG_AUTHCODE, + XMLMBUS_SERVER_ERROR_WRONG_DATA_LENGTH, + XMLMBUS_SERVER_ERROR_UNIMPLEMENTED_HANDLER, + XMLMBUS_SERVER_ERROR_WRONG_HANDLER_PARAMETER, + XMLMBUS_SERVER_ERROR_BUSY, + + XMLMBUS_SERVER_NOT_FOR_ME = 0x1010, + + XMLMBUS_SERVER_UNIMPLEMENTED_SINGLE_CHARACTER_FRAME_HANDLER = 0x1020, + XMLMBUS_SERVER_UNIMPLEMENTED_SHORT_FRAME_HANDLER, + XMLMBUS_SERVER_UNIMPLEMENTED_LONG_FRAME_HANDLER, + XMLMBUS_SERVER_ERROR_IN_SHORT_FRAME_HANDLER, + XMLMBUS_SERVER_ERROR_IN_LONG_FRAME_HANDLER, + + XMLMBUS_SERVER_CANT_OPEN_INTERFACE = 0x1030, +}; + +struct xmlmbus_server_ctx; /* Forward declaration. */ + +typedef int (*appl_cmd_func)(struct xmlmbus_server_ctx *ctx, void *arg, const uint8_t *in, uint32_t inlen, void *out, uint32_t *outlen); + +typedef int (*ci_cmd_func)(struct xmlmbus_server_ctx *ctx, void *arg, const uint8_t *in, uint32_t inlen); + +typedef int (*ctrl_cmd_func)(struct xmlmbus_server_ctx *ctx, void *arg); + +typedef int (*single_character_handler_func)(struct xmlmbus_server_ctx *ctx); + +struct ctrl_cmd { + uint8_t cfield; + ctrl_cmd_func func; + void *func_arg; +}; + +struct ci_cmd { + uint8_t cfield; + uint8_t ci; + ci_cmd_func func; + void *func_arg; +}; + +struct appl_cmd { + uint8_t layer; + uint8_t request; + uint8_t function; + appl_cmd_func func; + void *func_arg; +}; + +struct xmlmbus_server_ctx { + /* Internal variables, flags, etc. */ + struct xmlmbus_buffer buffer; + + uint8_t access_number; + uint8_t status; + + bool authorized; + + bool dynamically_allocated; + + /* Settings. */ + uint8_t address; + + uint32_t ident_no; + uint16_t manufacturer; + uint8_t version; + uint8_t medium; + + uint8_t auth_code_layer_1[8]; + + const struct ctrl_cmd *ctrl_cmd_table; + size_t ctrl_cmd_table_size; + + const struct ci_cmd *ci_cmd_table; + size_t ci_cmd_table_size; + + const struct appl_cmd *appl_cmd_table; + size_t appl_cmd_table_size; + + single_character_handler_func single_character_handler; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +#if XMLMBUS_SERVER_HAS_MALLOC +struct xmlmbus_server_ctx* xmlmbus_server_alloc(void); + +void xmlmbus_server_destroy(struct xmlmbus_server_ctx *ctx); +#endif + +struct xmlmbus_server_ctx* xmlmbus_server_static_alloc(void); + +uint8_t* xmlmbus_server_get_response_buffer(struct xmlmbus_server_ctx *ctx); + +uint32_t xmlmbus_server_get_response_buffer_size(const struct xmlmbus_server_ctx *ctx); + +uint32_t xmlmbus_server_get_response_buffer_used(const struct xmlmbus_server_ctx *ctx); + +int xmlmbus_server_process_client_request(struct xmlmbus_server_ctx *ctx, const uint8_t *in, uint32_t inlen); + +int xmlmbus_server_write_response_data(struct xmlmbus_server_ctx *ctx, struct xmlmbus_dib_with_data *data); + +int xmlmbus_server_write_fixed_header(struct xmlmbus_server_ctx *ctx); + +int xmlmbus_server_write_mdh(struct xmlmbus_server_ctx *ctx, uint8_t mdh); + +int xmlmbus_server_check_authcode(struct xmlmbus_server_ctx *ctx, const uint8_t auth_code[8]); + +int xmlmbus_server_snd_ud_handler(struct xmlmbus_server_ctx *ctx, void *arg, const uint8_t *in, uint32_t inlen); + +void xmlmbus_server_set_address(struct xmlmbus_server_ctx *ctx, uint8_t address); + +void xmlmbus_server_set_identification(struct xmlmbus_server_ctx *ctx, uint32_t ident_no, uint16_t manufacturer, uint8_t version, uint8_t medium); + +void xmlmbus_server_set_auth_code(struct xmlmbus_server_ctx *ctx, const uint8_t auth_code[8]); + +void xmlmbus_server_set_ctrl_cmd_table(struct xmlmbus_server_ctx *ctx, const struct ctrl_cmd *ctrl_cmd_table, uint32_t ctrl_cmd_table_size); + +void xmlmbus_server_set_ci_cmd_table(struct xmlmbus_server_ctx *ctx, const struct ci_cmd *ci_cmd_table, uint32_t ci_cmd_table_size); + +void xmlmbus_server_set_appl_cmd_table(struct xmlmbus_server_ctx *ctx, const struct appl_cmd *appl_cmd_table, uint32_t appl_cmd_table_size); + +void xmlmbus_server_set_single_character_handler(struct xmlmbus_server_ctx *ctx, single_character_handler_func single_character_handler); + +#ifdef __cplusplus +} +#endif + diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_util.h b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_util.h new file mode 100644 index 0000000000..3abd39f13f --- /dev/null +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/include/xmlmbus_util.h @@ -0,0 +1,51 @@ +/* + Copyright 2024 Xael South + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#pragma once + +#include +#include + +#if !defined(MAX) +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#endif + +#if !defined(MIN) +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +#if !defined(ARRAY_SIZE) +#define ARRAY_SIZE(arr) (sizeof((arr))/sizeof((arr)[0])) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +void timerspecsub(const struct timespec *a, const struct timespec *b, struct timespec *result); + +long timespecsub_to_msec(const struct timespec *ts); + +const char* xmlmbus_get_timestr(char *buf, size_t len); + +unsigned short xmlmbus_get_manufacturer_integer(const char *src); + +char* xmlmbus_get_manufacturer_string(char dest[4], unsigned short manufacturer); + +#ifdef __cplusplus +} +#endif + diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/src/xmlmbus_buffer.c b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/src/xmlmbus_buffer.c new file mode 100644 index 0000000000..c85c66c508 --- /dev/null +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/src/xmlmbus_buffer.c @@ -0,0 +1,115 @@ +/* + Copyright 2024 Xael South + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include + +static inline int _xmlmbus_buffer_write_u8(struct xmlmbus_buffer *buffer, uint8_t src) { + + if (buffer->length >= sizeof(buffer->data)) + return (-1); + buffer->data[buffer->length++] = src; + return 0; +} + +int xmlmbus_buffer_write_u8(struct xmlmbus_buffer *buffer, uint8_t src) { + + return (_xmlmbus_buffer_write_u8(buffer, src)); +} + +int xmlmbus_buffer_write_u16(struct xmlmbus_buffer *buffer, uint16_t src) { + + int rc = 0; + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src)); + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src >> 8)); + return rc; +} + +int xmlmbus_buffer_write_u24(struct xmlmbus_buffer *buffer, uint32_t src) { + + int rc = 0; + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src)); + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src >> 8)); + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src >> 16)); + return rc; +} + +int xmlmbus_buffer_write_u32(struct xmlmbus_buffer *buffer, uint32_t src) { + + int rc = 0; + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src)); + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src >> 8)); + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src >> 16)); + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src >> 24)); + return rc; +} + +int xmlmbus_buffer_write_u64(struct xmlmbus_buffer *buffer, uint64_t src) { + + int rc = 0; + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src)); + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src >> 8)); + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src >> 16)); + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src >> 24)); + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src >> 32)); + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src >> 40)); + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src >> 48)); + if (rc == 0) + rc = _xmlmbus_buffer_write_u8(buffer, (uint8_t)(src >> 56)); + return rc; +} + +int xmlmbus_buffer_write_blob(struct xmlmbus_buffer *buffer, const void *_src, size_t src_size) { + + int rc = 0; + const uint8_t *src = _src; + + while (rc == 0 && src_size--) + rc = _xmlmbus_buffer_write_u8(buffer, *src++); + + return rc; +} + +int xmlmbus_buffer_write_cfield(struct xmlmbus_buffer *packet, uint8_t src) { + + return (_xmlmbus_buffer_write_u8(packet, src)); +} + +int xmlmbus_buffer_write_afield(struct xmlmbus_buffer *packet, uint8_t src) { + + return (_xmlmbus_buffer_write_u8(packet, src)); +} + +int xmlmbus_buffer_write_cifield(struct xmlmbus_buffer *packet, uint8_t src) { + + return (_xmlmbus_buffer_write_u8(packet, src)); +} + diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/src/xmlmbus_mbus_frame.c b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/src/xmlmbus_mbus_frame.c new file mode 100644 index 0000000000..8b5d2e6439 --- /dev/null +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/src/xmlmbus_mbus_frame.c @@ -0,0 +1,254 @@ +/* + Copyright 2024 Xael South + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include + +static uint8_t _xmlmbus_mbus_checksum(const uint8_t *buf, unsigned buflen) { + + uint8_t checksum = 0; + + while (buflen--) { + checksum += *buf++; + } + + return checksum; +} + +static void _xmlmbus_clear_error_mask(struct xmlmbus_mbus_frame_state_machine_data *mach) { + + mach->info = 0; +} + +static void _xmlmbus_reset_state_machine(struct xmlmbus_mbus_frame_state_machine_data *mach) { + + mach->state = XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_START_1; + mach->length_1 = 0u; + mach->length_2 = 0u; + mach->checksum = 0u; + + mach->bytes_to_receive = 0u; + mach->datalen = 0u; + + _xmlmbus_clear_error_mask(mach); +} + +static int _xmlmbus_is_length_error(const struct xmlmbus_mbus_frame_state_machine_data *mach) { + + return (mach->status.length_error); +} + +static int _xmlmbus_is_start2_error(const struct xmlmbus_mbus_frame_state_machine_data *mach) { + + return (mach->status.start2_error); +} + +static int _xmlmbus_is_checksum_error(const struct xmlmbus_mbus_frame_state_machine_data *mach) { + + return (mach->status.checksum_error); +} + +static int _xmlmbus_is_stop_error(const struct xmlmbus_mbus_frame_state_machine_data *mach) { + + return (mach->status.stop_error); +} + +void xmlmbus_reset_state_machine(struct xmlmbus_mbus_frame_state_machine_data *mach) { + + _xmlmbus_reset_state_machine(mach); +} + +int xmlmbus_process_state_machine(struct xmlmbus_mbus_frame_state_machine_data *mach, uint8_t b) { + + if (mach->status.rx_complete != 0) + _xmlmbus_reset_state_machine(mach); + + switch (mach->state) { + case XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_START_1: + mach->bytes_to_receive = 0u; + mach->datalen = 0u; + mach->data[mach->datalen++] = b; + + if (MBUS_FRAME_SINGLE_START == b) { + mach->bytes_to_receive = 0u; + mach->status.rx_complete = 1u; + mach->state = XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_START_1; + } + else if (MBUS_FRAME_SHORT_START == b) { + /* One byte is already received. */ + mach->bytes_to_receive = MBUS_FRAME_SIZE_SHORT - 1u; + mach->status.rx_complete = 0u; + mach->state = XMLMBUS_MBUS_RX_FRAME_STATE_RX_DATA; + } + else if (MBUS_FRAME_LONG_START == b) { + /* One byte is already received. */ + mach->bytes_to_receive = MBUS_FRAME_SIZE_MAX - 1u; + mach->status.rx_complete = 0u; + mach->state = XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_LENGTH_1; + } + break; + + case XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_LENGTH_1: + mach->bytes_to_receive--; + mach->data[mach->datalen++] = b; + + mach->length_1 = b; + + mach->state = XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_LENGTH_2; + break; + + case XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_LENGTH_2: + mach->bytes_to_receive--; + mach->data[mach->datalen++] = b; + + mach->length_2 = b; + + if (mach->length_1 == mach->length_2) { + mach->status.length_error = 0; + mach->state = XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_START_2; + } + else { + mach->status.length_error = 1; + mach->state = XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_START_1; + } + break; + + case XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_START_2: + mach->bytes_to_receive--; + mach->data[mach->datalen++] = b; + + if (MBUS_FRAME_LONG_START == b) { + /* There are C, A, CI, data, CRC and STOP bytes to receive. */ + mach->bytes_to_receive = mach->length_1 + 2u; + mach->status.start2_error = 0; + mach->state = XMLMBUS_MBUS_RX_FRAME_STATE_RX_DATA; + } + else { + mach->status.start2_error = 1; + mach->state = XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_START_1; + } + break; + + case XMLMBUS_MBUS_RX_FRAME_STATE_RX_DATA: + mach->bytes_to_receive--; + mach->data[mach->datalen++] = b; + + if (mach->bytes_to_receive == 2u) { + /* There are CRC and STOP bytes to receive. */ + mach->state = XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_CRC; + } + break; + + case XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_CRC: + mach->bytes_to_receive--; + mach->data[mach->datalen++] = b; + + /* We will go until the end of the current frame. */ + mach->state = XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_STOP; + + if (MBUS_FRAME_SHORT_START == mach->data[0]) { + uint8_t checksum = _xmlmbus_mbus_checksum(&mach->data[1], mach->datalen - 1u - 1u); + mach->status.checksum_error = (checksum == b) ? 0 : 1; + } + else if (MBUS_FRAME_LONG_START == mach->data[0]) { + uint8_t checksum = _xmlmbus_mbus_checksum(&mach->data[4], mach->datalen - 4u - 1u); + mach->status.checksum_error = (checksum == b) ? 0 : 1; + } + else { + /* Unknown frame? */ + _xmlmbus_reset_state_machine(mach); + } + break; + + case XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_STOP: + mach->bytes_to_receive--; + mach->data[mach->datalen++] = b; + + /* Frame is definetely complete. */ + mach->status.rx_complete = 1u; + + /* And also stopped? */ + mach->status.stop_error = (MBUS_FRAME_STOP == b) ? 0 : 1; + + if (mach->bytes_to_receive == 0) { + mach->state = XMLMBUS_MBUS_RX_FRAME_STATE_WAIT_START_1; + } + else { + /* Still bytes to receive? */ + _xmlmbus_reset_state_machine(mach); + } + break; + } + + return (mach->status.rx_complete); +} + +void xmlmbus_mbus_frame_clear_error_mask(struct xmlmbus_mbus_frame_state_machine_data *mach) { + + _xmlmbus_clear_error_mask(mach); +} + +int xmlmbus_mbus_frame_is_length_error(const struct xmlmbus_mbus_frame_state_machine_data *mach) { + + return (_xmlmbus_is_length_error(mach)); +} + +int xmlmbus_mbus_frame_is_start2_error(const struct xmlmbus_mbus_frame_state_machine_data *mach) { + + return (_xmlmbus_is_start2_error(mach)); +} + +int xmlmbus_mbus_frame_is_checksum_error(const struct xmlmbus_mbus_frame_state_machine_data *mach) { + + return (_xmlmbus_is_checksum_error(mach)); +} + +int xmlmbus_mbus_frame_is_stop_error(const struct xmlmbus_mbus_frame_state_machine_data *mach) { + + return (_xmlmbus_is_stop_error(mach)); +} + +int xmlmbus_mbus_frame_is_good(const struct xmlmbus_mbus_frame_state_machine_data *mach) { + + unsigned error_mask = 0; + + error_mask |= _xmlmbus_is_length_error(mach) << 0; + error_mask |= _xmlmbus_is_start2_error(mach) << 1; + error_mask |= _xmlmbus_is_checksum_error(mach) << 2; + error_mask |= _xmlmbus_is_stop_error(mach) << 3; + + return ((error_mask == 0) ? 1 : 0); +} + +int xmlmbus_mbus_frame_is_rx_complete(const struct xmlmbus_mbus_frame_state_machine_data *mach) { + + return (mach->status.rx_complete); +} + +uint8_t xmlmbus_mbus_checksum(const uint8_t *buf, unsigned buflen) { + + return (_xmlmbus_mbus_checksum(buf, buflen)); +} + +const uint8_t* xmlmbus_mbus_frame_get_data(const struct xmlmbus_mbus_frame_state_machine_data *mach) { + + return (mach->data); +} + +unsigned xmlmbus_mbus_frame_get_datalen(const struct xmlmbus_mbus_frame_state_machine_data *mach) { + + return (mach->datalen); +} + diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/src/xmlmbus_server.c b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/src/xmlmbus_server.c new file mode 100644 index 0000000000..4d30a4b150 --- /dev/null +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/src/xmlmbus_server.c @@ -0,0 +1,460 @@ +/* + Copyright 2024 Xael South + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include + +#include +#include + +uint8_t* xmlmbus_server_get_response_buffer(struct xmlmbus_server_ctx *ctx) { + + return (ctx->buffer.data); +} + +uint32_t xmlmbus_server_get_response_buffer_size(const struct xmlmbus_server_ctx *ctx) { + + return (sizeof(ctx->buffer.data)); +} + +uint32_t xmlmbus_server_get_response_buffer_used(const struct xmlmbus_server_ctx *ctx) { + + return (ctx->buffer.length); +} + +static int xmlmbus_server_process_short_frame(struct xmlmbus_server_ctx *ctx, uint8_t cfield) { + + if (ctx->ctrl_cmd_table == NULL || ctx->ctrl_cmd_table_size == 0u) + return XMLMBUS_SERVER_UNIMPLEMENTED_SHORT_FRAME_HANDLER; + + int rc = XMLMBUS_SERVER_UNIMPLEMENTED_SHORT_FRAME_HANDLER; + + for (size_t i = 0; i < ctx->ctrl_cmd_table_size; i++) { + const struct ctrl_cmd *cmd = &ctx->ctrl_cmd_table[i]; + + if (cfield == cmd->cfield) { + if (cmd->func != NULL) { + if (0 == cmd->func(ctx, cmd->func_arg)) { + rc = XMLMBUS_SERVER_OK; + } + else { + rc = XMLMBUS_SERVER_ERROR_IN_SHORT_FRAME_HANDLER; + } + + /* Don't process any further here, because the control frame is over. */ + break; + } + } + } + + return rc; +} + +static int xmlmbus_server_process_long_frame(struct xmlmbus_server_ctx *ctx, uint8_t cfield, + const uint8_t *in, const size_t inlen) { + + if (ctx->ci_cmd_table == NULL || ctx->ci_cmd_table_size == 0u) + return XMLMBUS_SERVER_UNIMPLEMENTED_LONG_FRAME_HANDLER; + + int rc = XMLMBUS_SERVER_UNIMPLEMENTED_LONG_FRAME_HANDLER; + + const uint8_t ci = in[0]; + + for (size_t i = 0; i < ctx->ci_cmd_table_size; i++) { + const struct ci_cmd *cmd = &ctx->ci_cmd_table[i]; + + if (cfield == cmd->cfield && ci == cmd->ci) { + if (cmd->func != NULL) { + if (0 == cmd->func(ctx, cmd->func_arg, in, inlen)) { + rc = XMLMBUS_SERVER_OK; + } + else { + rc = XMLMBUS_SERVER_ERROR_IN_LONG_FRAME_HANDLER; + } + + /* Don't process any further here, because the long frame is over. */ + break; + } + } + } + + return rc; +} + +int xmlmbus_server_process_client_request(struct xmlmbus_server_ctx *ctx, const uint8_t *in, uint32_t inlen) { + + int rc; + unsigned cfield, address, length; + + if (ctx == NULL || in == NULL || inlen == 0u) + return XMLMBUS_SERVER_ERROR; + + ctx->buffer.length = 0; + + switch (inlen) { + case MBUS_FRAME_SIZE_SINGLE_CHARACTER: + if (ctx->single_character_handler != NULL) + rc = ctx->single_character_handler(ctx); + else + rc = XMLMBUS_SERVER_UNIMPLEMENTED_SINGLE_CHARACTER_FRAME_HANDLER; + break; + + case MBUS_FRAME_SIZE_SHORT: + cfield = in[1]; + address = in[2]; + //length = MBUS_FRAME_SIZE_DATA_SHORT; + + if ((cfield & MBUS_CFIELD_REQUEST) == 0) + return XMLMBUS_SERVER_ERROR_WRONG_DIRECTION_IN_CFIELD; + + if (address == MBUS_ADDRESS_BROADCAST_ALL_REPLY || address == ctx->address) + rc = xmlmbus_server_process_short_frame(ctx, cfield); + else + rc = XMLMBUS_SERVER_NOT_FOR_ME; + break; + + default: + cfield = in[4]; + address = in[5]; + length = in[1]; + + if ((cfield & MBUS_CFIELD_REQUEST) == 0) + return XMLMBUS_SERVER_ERROR_WRONG_DIRECTION_IN_CFIELD; + + if (address == MBUS_ADDRESS_BROADCAST_ALL_REPLY || address == ctx->address) + rc = xmlmbus_server_process_long_frame(ctx, cfield, &in[6], &in[4 + length] - &in[6]); + else + rc = XMLMBUS_SERVER_NOT_FOR_ME; + break; + } + + if (rc == XMLMBUS_SERVER_OK) { + ctx->access_number++; + } + + return rc; +} + +/* Must return XMLMBUS_SERVER_OK if no error. */ +int xmlmbus_server_write_response_data(struct xmlmbus_server_ctx *ctx, struct xmlmbus_dib_with_data *data) { + + int rc; + + const uint8_t dif_length = xmlmbus_get_dif_from_size(data->blobsize); + + if (0 != (rc = xmlmbus_buffer_write_u8(&ctx->buffer, dif_length))) + return XMLMBUS_SERVER_ERROR_NO_MEMORY; + + if (0 != (rc = xmlmbus_buffer_write_u8(&ctx->buffer, VIF_MANUFACTURER_SPECIFIC))) + return XMLMBUS_SERVER_ERROR_NO_MEMORY; + + data->vife_layer.vif.msb = 1u; /* Bit E is set in the request. */ + if (0 != (rc = xmlmbus_buffer_write_u8(&ctx->buffer, data->vife_layer.value))) + return XMLMBUS_SERVER_ERROR_NO_MEMORY; + + data->vife_request.vif.msb = 1u; /* Bit E is set in the request. */ + if (0 != (rc = xmlmbus_buffer_write_u8(&ctx->buffer, data->vife_request.value))) + return XMLMBUS_SERVER_ERROR_NO_MEMORY; + + data->vife_function.vif.msb = 1u; /* Bit E is set in the request. */ + if (0 != (rc = xmlmbus_buffer_write_u8(&ctx->buffer, data->vife_function.value))) + return XMLMBUS_SERVER_ERROR_NO_MEMORY; + + data->vife_response.vif.msb = 0u; /* Bit E is unset in the request. */ + if (0 != (rc = xmlmbus_buffer_write_u8(&ctx->buffer, data->vife_response.value))) + return XMLMBUS_SERVER_ERROR_NO_MEMORY; + + if (dif_length == DIF_DATA_LENGTH_IS_LVAR) { + if (0 != (rc = xmlmbus_buffer_write_u8(&ctx->buffer, data->blobsize))) + return XMLMBUS_SERVER_ERROR_NO_MEMORY; + } + + if (data->blobsize > 0) { + if (0 != (rc = xmlmbus_buffer_write_blob(&ctx->buffer, data->blob, data->blobsize))) + return XMLMBUS_SERVER_ERROR_NO_MEMORY; + } + + return XMLMBUS_SERVER_OK; +} + +/* Must return XMLMBUS_SERVER_OK if no error. */ +int xmlmbus_server_write_fixed_header(struct xmlmbus_server_ctx *ctx) { + + if (0 != xmlmbus_buffer_write_cfield(&ctx->buffer, RSP_UD)) + return XMLMBUS_SERVER_ERROR_NO_MEMORY; + + if (0 != xmlmbus_buffer_write_afield(&ctx->buffer, ctx->address)) + return XMLMBUS_SERVER_ERROR_NO_MEMORY; + + if (0 != xmlmbus_buffer_write_cifield(&ctx->buffer, MBUS_CI_VARIABLE_DATA_RESPOND)) + return XMLMBUS_SERVER_ERROR_NO_MEMORY; + + struct mbus_fixed_data_header header = { + .ident_no = ctx->ident_no, + .manufacturer = ctx->manufacturer, + .version = ctx->version, + .medium = ctx->medium, + + .access_number = ctx->access_number, + .status = ctx->status, + .signature = 0x0000, + }; + + if (0 != xmlmbus_buffer_write_blob(&ctx->buffer, &header, sizeof(header))) + return XMLMBUS_SERVER_ERROR_NO_MEMORY; + + return XMLMBUS_SERVER_OK; +} + +int xmlmbus_server_write_mdh(struct xmlmbus_server_ctx *ctx, uint8_t mdh) { + + if (0 != xmlmbus_buffer_write_u8(&ctx->buffer, mdh)) + return XMLMBUS_SERVER_ERROR_NO_MEMORY; + + return XMLMBUS_SERVER_OK; +} + +int xmlmbus_server_check_authcode(struct xmlmbus_server_ctx *ctx, const uint8_t auth_code[8]) { + + int rc = XMLMBUS_SERVER_OK; + + /* Compare byte for byte without using time-optimized memcmp() trying to prevent timing attack. */ + for (size_t i = 0; i < sizeof(ctx->auth_code_layer_1); ++i) { + if (ctx->auth_code_layer_1[i] != auth_code[i]) { + rc = XMLMBUS_SERVER_ERROR_WRONG_AUTHCODE; + } + } + + return rc; +} + +void xmlmbus_server_set_auth_code(struct xmlmbus_server_ctx *ctx, const uint8_t auth_code[8]) { + + memcpy(ctx->auth_code_layer_1, auth_code, sizeof(ctx->auth_code_layer_1)); +} + +void xmlmbus_server_set_ctrl_cmd_table(struct xmlmbus_server_ctx *ctx, const struct ctrl_cmd *ctrl_cmd_table, uint32_t ctrl_cmd_table_size) { + + ctx->ctrl_cmd_table = ctrl_cmd_table; + ctx->ctrl_cmd_table_size = ctrl_cmd_table_size; +} + +void xmlmbus_server_set_ci_cmd_table(struct xmlmbus_server_ctx *ctx, const struct ci_cmd *ci_cmd_table, uint32_t ci_cmd_table_size) { + + ctx->ci_cmd_table = ci_cmd_table; + ctx->ci_cmd_table_size = ci_cmd_table_size; +} + +void xmlmbus_server_set_appl_cmd_table(struct xmlmbus_server_ctx *ctx, const struct appl_cmd *appl_cmd_table, uint32_t appl_cmd_table_size) { + + ctx->appl_cmd_table = appl_cmd_table; + ctx->appl_cmd_table_size = appl_cmd_table_size; +} + +void xmlmbus_server_set_address(struct xmlmbus_server_ctx *ctx, uint8_t address) { + + ctx->address = address; +} + +void xmlmbus_server_set_identification(struct xmlmbus_server_ctx *ctx, uint32_t ident_no, uint16_t manufacturer, uint8_t version, uint8_t medium) { + + ctx->ident_no = ident_no; + ctx->manufacturer = manufacturer; + ctx->version = version; + ctx->medium = medium; +} + +void xmlmbus_server_set_single_character_handler(struct xmlmbus_server_ctx *ctx, single_character_handler_func single_character_handler) { + + ctx->single_character_handler = single_character_handler; +} + +struct xmlmbus_server_ctx* xmlmbus_server_static_alloc(void) { + + static struct xmlmbus_server_ctx ctx = { + .dynamically_allocated = false, + }; + + return (&ctx); +} + +#if XMLMBUS_SERVER_HAS_MALLOC +#include + +struct xmlmbus_server_ctx* xmlmbus_server_alloc(void) { + + struct xmlmbus_server_ctx *ctx = xmlmbus_zalloc(sizeof(struct xmlmbus_server_ctx)); + if (ctx == NULL) + return NULL; + + ctx->dynamically_allocated = true; + + return ctx; +} + +void xmlmbus_server_destroy(struct xmlmbus_server_ctx *ctx) { + + if (ctx == NULL) + return; + + if (ctx->dynamically_allocated) + xmlmbus_free(ctx); +} +#endif + +static int snd_ud_handle_layer_function(struct xmlmbus_server_ctx *ctx, struct xmlmbus_dib_with_data *data) { + + const uint8_t *in = data->blob; + size_t inlen = data->blobsize; + + uint8_t out[256]; + uint32_t outlen = sizeof(out); + + data->vife_response.value = VIFE_RESPONSE_TYPE_CMD_UNIMPLEMENTED; + data->blob = NULL; + data->blobsize = 0; + + for (size_t i = 0; i < ctx->appl_cmd_table_size; ++i) { + + const struct appl_cmd *cmd = &ctx->appl_cmd_table[i]; + if (cmd->layer == data->vife_layer.value && + cmd->request == data->vife_request.value && + cmd->function == data->vife_function.value) { + if (cmd->func != NULL) { + + int rc; + + if (ctx->authorized) + rc = cmd->func(ctx, cmd->func_arg, in, inlen, out, &outlen); + else + rc = XMLMBUS_SERVER_ERROR_WRONG_AUTHCODE; + + if (XMLMBUS_SERVER_OK == rc) { + if (outlen > 0) { + data->vife_response.value = VIFE_RESPONSE_TYPE_CMD_EXEC_RESULT; + data->blob = out; + data->blobsize = outlen; + } + else { + data->vife_response.value = VIFE_RESPONSE_TYPE_CMD_EXEC_SUCCESS; + } + } + else if (XMLMBUS_SERVER_ERROR_WRONG_AUTHCODE == rc) { + data->vife_response.value = VIFE_RESPONSE_TYPE_CMD_UNAUTHORIZED; + } + else if (XMLMBUS_SERVER_ERROR_WRONG_HANDLER_PARAMETER == rc) { + data->vife_response.value = VIFE_RESPONSE_TYPE_CMD_HAS_WRONG_PARAMETER; + } + else if (XMLMBUS_SERVER_ERROR_BUSY == rc) { + data->vife_response.value = VIFE_RESPONSE_TYPE_DEVICE_IS_BUSY; + data->blob = out; + data->blobsize = outlen; + } + else { + data->vife_response.value = VIFE_RESPONSE_TYPE_CMD_EXEC_ERROR; + data->blob = NULL; + data->blobsize = 0; + } + + break; + } + } + } + + int rc = xmlmbus_server_write_response_data(ctx, data); + if (rc != XMLMBUS_SERVER_OK) + return rc; + + return XMLMBUS_SERVER_OK; +} + +int xmlmbus_server_snd_ud_handler(struct xmlmbus_server_ctx *ctx, void *arg, const uint8_t *in, uint32_t inlen) { + + (void)arg; + int rc; + + const uint8_t * const begin = in; + + /* CI field must be MBUS_CI_DATA_SEND. */ + uint8_t ci = *in++; + if ((ci & MBUS_CI_DATA_SEND) != MBUS_CI_DATA_SEND) + return XMLMBUS_SERVER_ERROR_WRONG_CI; + + /* There is the authorization layer in front of data. */ + uint8_t dif = *in++; + if (dif != DIF_BINARY_DATA_LENGTH_IS_8) + return XMLMBUS_SERVER_ERROR_WRONG_DIF; + + uint8_t vif = *in++; + if (vif != VIF_MANUFACTURER_SPECIFIC) + return XMLMBUS_SERVER_ERROR_WRONG_VIF; + + uint8_t vife = *in++; + if (vife != VIFE_LAYER_AUTHORIZATION) + return XMLMBUS_SERVER_ERROR_WRONG_VIF; + + /* Finally check the authorization code. */ + const Authcode_t *auth = (const Authcode_t*)in; + if (XMLMBUS_SERVER_OK == xmlmbus_server_check_authcode(ctx, auth->code)) + ctx->authorized = true; + else + ctx->authorized = false; + + in += sizeof(*auth); + + /* Fixed header has always to be send. All following data + is up to functions implemented by the user. */ + if (XMLMBUS_SERVER_OK != (rc = xmlmbus_server_write_fixed_header(ctx))) + return rc; + + #if 0 + /* ... and don't forget the Manufacturer Defined Header. */ + if (XMLMBUS_SERVER_OK != (rc = xmlmbus_server_write_mdh(ctx, DIF_MANUFACTURER_SPECIAL_FUNCTION))) + return rc; + #endif + + /* DRH consists of DIB and VIB and in our implementation it's always 5 bytes long. */ + const unsigned DRH_length_in_request = 5u; + while (in + DRH_length_in_request < begin + inlen) { + dif = *in++; + + vif = *in++; + if (vif != VIF_MANUFACTURER_SPECIFIC) + return XMLMBUS_SERVER_ERROR_WRONG_VIF; + + struct xmlmbus_dib_with_data data; + data.vife_layer.value = *in++ & VIFE_LAYER_MASK; + data.vife_request.value = *in++ & VIFE_REQUEST_MASK; + data.vife_function.value = *in++ & VIFE_FUNCTION_MASK; + data.blobsize = (dif == DIF_DATA_LENGTH_IS_LVAR) ? *in++ : xmlmbus_get_size_from_dif(dif); + data.blob = in; + + if (data.blobsize == DIF_DATA_LENGTH_IS_INVALID || + data.blobsize > (size_t)inlen + (in - begin)) + return XMLMBUS_SERVER_ERROR_WRONG_DATA_LENGTH; + + in += data.blobsize; + + if (XMLMBUS_SERVER_OK != (rc = snd_ud_handle_layer_function(ctx, &data))) + return rc; + } + + /* The end of the data stream must have been reached. */ + if (in != begin + inlen) + return XMLMBUS_SERVER_ERROR_WRONG_DATA_LENGTH; + + return XMLMBUS_SERVER_OK; +} + diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/src/xmlmbus_util.c b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/src/xmlmbus_util.c new file mode 100644 index 0000000000..eb091b80f1 --- /dev/null +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/src/xmlmbus_util.c @@ -0,0 +1,91 @@ +/* + Copyright 2024 Xael South + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include +#include +#include +#include + +#include + +inline void timerspecsub(const struct timespec *a, const struct timespec *b, struct timespec *result) { + + result->tv_sec = a->tv_sec - b->tv_sec; + + result->tv_nsec = a->tv_nsec - b->tv_nsec; + + if (result->tv_nsec < 0) { + --result->tv_sec; + result->tv_nsec += 1000000000L; + } +} + +inline long timespecsub_to_msec(const struct timespec *ts) { + + return ((long)(ts->tv_sec * 1000L + ts->tv_nsec / 1000000L)); +} + +const char* xmlmbus_get_timestr(char *buf, size_t len) { + + struct timeval timeval; + struct tm timeinfo; + time_t seconds; + long milliseconds; + size_t n; + + if (buf) { + if (0 != gettimeofday(&timeval, NULL)) + return NULL; + seconds = timeval.tv_sec; + milliseconds = timeval.tv_usec / 1000; + if (!localtime_r(&seconds, &timeinfo)) + return NULL; + + n = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &timeinfo); + if (n <= 0) + return NULL; + n = snprintf(buf + n, len - n, ".%03ldZ", milliseconds); + if (n <= 0) + return NULL; + } + + return buf; +} + +inline unsigned short xmlmbus_get_manufacturer_integer(const char *src) { + + unsigned short manufacturer; + + if (!src) + return 0; + if (strlen(src) != 3) + return 0; + + manufacturer = (((int)src[0] - 64) << 10) | (((int)src[1] - 64) << 5) | (((int)src[2] - 64)); + + return manufacturer; +} + +inline char* xmlmbus_get_manufacturer_string(char dest[4], unsigned short manufacturer) { + + dest[0] = 64 + ((manufacturer >> 10) & 0x1f); + dest[1] = 64 + ((manufacturer >> 5) & 0x1f); + dest[2] = 64 + ((manufacturer >> 0) & 0x1f); + dest[3] = '\0'; + + return dest; +} + diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/xmlmbus_chibios.c b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/xmlmbus_chibios.c new file mode 100644 index 0000000000..09d66b256d --- /dev/null +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/xmlmbus_chibios.c @@ -0,0 +1,143 @@ +/* + Copyright 2024 Xael South + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include + +#include +#include + +int xmlmbus_interface_open(struct xmlmbus_interface *iface, int flags) { + + return (iface->open(iface, flags)); +} + +int xmlmbus_interface_close(struct xmlmbus_interface *iface) { + + return (iface->close(iface)); +} + +int xmlmbus_interface_read(struct xmlmbus_interface *iface, void *buf, unsigned long buflen, int flags, int timeout_msec) { + + int received_packet_size = 0; + int read_bytes; + uint8_t rx_data[512]; + int rx_complete = 0; + + xmlmbus_reset_state_machine(&iface->state_machine_data); + + systime_t start = chVTGetSystemTime(); + systime_t end = chTimeAddX(start, TIME_MS2I(timeout_msec)); + + while (0 == rx_complete && xmlmbus_mbus_frame_is_good(&iface->state_machine_data)) { + read_bytes = iface->read(iface, rx_data, sizeof(rx_data), flags, MIN(timeout_msec, 10)); + + for (int i = 0; + i < read_bytes && 0 == rx_complete && xmlmbus_mbus_frame_is_good(&iface->state_machine_data); + i++) { + rx_complete = xmlmbus_process_state_machine(&iface->state_machine_data, rx_data[i]); + if (rx_complete != 0) { + if (iface->state_machine_data.datalen <= buflen) { + received_packet_size = iface->state_machine_data.datalen; + memcpy(buf, iface->state_machine_data.data, iface->state_machine_data.datalen); + } + + break; + } + } + + if (!chVTIsSystemTimeWithin(start, end)) + break; + } + + return received_packet_size; +} + +int xmlmbus_interface_write(struct xmlmbus_interface *iface, const void *_buf, unsigned long buflen, int flags, int timeout_msec) { + + int total = 0; + const uint8_t *buf = _buf; + + systime_t start = chVTGetSystemTime(); + systime_t end = chTimeAddX(start, TIME_MS2I(timeout_msec)); + + while (buflen > 0) { + int written_bytes = iface->write(iface, buf, buflen, flags, MIN(timeout_msec, 10)); + if (written_bytes >= 0) { + total += written_bytes; + buf += written_bytes; + buflen -= written_bytes; + } + + if (!chVTIsSystemTimeWithin(start, end)) + break; + } + + return total; +} + +static int create_mbus_packet(uint8_t *dst, const uint8_t *src, size_t srclen) { + + uint8_t * const begin = dst; + uint8_t crc = 0; + + if (srclen > MBUS_FRAME_SIZE_DATA_MAX) + return (-1); + + if (srclen < MBUS_FRAME_SIZE_DATA_SHORT) + return (-1); + + if (srclen == MBUS_FRAME_SIZE_DATA_SHORT) { + *dst++ = MBUS_FRAME_SHORT_START; + } + else { + *dst++ = MBUS_FRAME_LONG_START; + *dst++ = srclen; + *dst++ = srclen; + *dst++ = MBUS_FRAME_LONG_START; + } + + while (srclen--) { + crc += *src; + *dst++ = *src++; + } + + *dst++ = crc; + *dst++ = MBUS_FRAME_STOP; + + return ((int)(dst - begin)); +} + +int xmlmbus_interface_create_packet(struct xmlmbus_interface *iface, void *dst, unsigned long *dstlen, const void *src, unsigned long srclen) { + + (void)iface; + int rc; + + if (srclen > 1) { + *dstlen = create_mbus_packet(dst, src, srclen); + rc = 0; + } + else if (srclen == 1) { + ((uint8_t*)dst)[0] = MBUS_FRAME_SINGLE_START; + *dstlen = MBUS_FRAME_SIZE_SINGLE_CHARACTER; + rc = 0; + } + else { + rc = -1; + } + + return rc; +} + diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/xmlmbus_chibios.h b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/xmlmbus_chibios.h new file mode 100644 index 0000000000..258ad6ad0a --- /dev/null +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/xmlmbus_chibios.h @@ -0,0 +1,45 @@ +/* + Copyright 2024 Xael South + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#pragma once + +#include "hal.h" +#include + +struct xmlmbus_interface { + SIODriver *siop; + + struct xmlmbus_mbus_frame_state_machine_data state_machine_data; + + int (*open)(struct xmlmbus_interface *iface, int flags); + + int (*close)(struct xmlmbus_interface *iface); + + int (*read)(struct xmlmbus_interface *iface, void *buf, unsigned long len, int flags, int timeout_msec); + + int (*write)(struct xmlmbus_interface *iface, const void *buf, unsigned long len, int flags, int timeout_msec); +}; + +int xmlmbus_interface_open(struct xmlmbus_interface *iface, int flags); + +int xmlmbus_interface_close(struct xmlmbus_interface *iface); + +int xmlmbus_interface_read(struct xmlmbus_interface *iface, void *buf, unsigned long buflen, int flags, int timeout_msec); + +int xmlmbus_interface_write(struct xmlmbus_interface *iface, const void *buf, unsigned long buflen, int flags, int timeout_msec); + +int xmlmbus_interface_create_packet(struct xmlmbus_interface *iface, void *dst, unsigned long *_dstlen, const void *src, unsigned long srclen); + diff --git a/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/xmlmbus_chibios.mk b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/xmlmbus_chibios.mk new file mode 100644 index 0000000000..da7a091629 --- /dev/null +++ b/testhal/SILABS/EFR32FG23x0xx/TEMPLATE/xmlmbus/xmlmbus_chibios.mk @@ -0,0 +1,15 @@ +# Required platform files. +XMLMBUS = xmlmbus + +XMLMBUSSRC = $(XMLMBUS)/src/xmlmbus_buffer.c \ + $(XMLMBUS)/src/xmlmbus_server.c \ + $(XMLMBUS)/src/xmlmbus_util.c \ + $(XMLMBUS)/src/xmlmbus_mbus_frame.c \ + $(XMLMBUS)/xmlmbus_chibios.c + +XMLMBUSINC = $(XMLMBUS)/include \ + $(XMLMBUS) + +# Shared variables +ALLCSRC += $(XMLMBUSSRC) +ALLINC += $(XMLMBUSINC)