diff --git a/cmsis/CMSIS_5/CMSIS/RTOS2/RTX/Source/rtx_mutex.c b/cmsis/CMSIS_5/CMSIS/RTOS2/RTX/Source/rtx_mutex.c index fb889b45d99..07c96bac1b1 100644 --- a/cmsis/CMSIS_5/CMSIS/RTOS2/RTX/Source/rtx_mutex.c +++ b/cmsis/CMSIS_5/CMSIS/RTOS2/RTX/Source/rtx_mutex.c @@ -520,6 +520,11 @@ const char *osMutexGetName (osMutexId_t mutex_id) { osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) { osStatus_t status; + // a null mutex handle is always invalid + if(mutex_id == 0) { + return osErrorParameter; + } + EvrRtxMutexAcquire(mutex_id, timeout); if (IsException() || IsIrqMasked()) { EvrRtxMutexError(mutex_id, (int32_t)osErrorISR); @@ -534,6 +539,11 @@ osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) { osStatus_t osMutexRelease (osMutexId_t mutex_id) { osStatus_t status; + // a null mutex handle is always invalid + if(mutex_id == 0) { + return osErrorParameter; + } + EvrRtxMutexRelease(mutex_id); if (IsException() || IsIrqMasked()) { EvrRtxMutexError(mutex_id, (int32_t)osErrorISR); @@ -561,6 +571,11 @@ osThreadId_t osMutexGetOwner (osMutexId_t mutex_id) { osStatus_t osMutexDelete (osMutexId_t mutex_id) { osStatus_t status; + // a null mutex handle is always invalid + if(mutex_id == 0) { + return osErrorParameter; + } + EvrRtxMutexDelete(mutex_id); if (IsException() || IsIrqMasked()) { EvrRtxMutexError(mutex_id, (int32_t)osErrorISR); diff --git a/cmsis/device/rtos/source/mbed_boot.c b/cmsis/device/rtos/source/mbed_boot.c index 910f832d692..5b50d3d7a43 100644 --- a/cmsis/device/rtos/source/mbed_boot.c +++ b/cmsis/device/rtos/source/mbed_boot.c @@ -83,6 +83,13 @@ void mbed_init(void) SCnSCB->ACTLR |= SCnSCB_ACTLR_DISDEFWBUF_Msk; #endif #endif + + // If present, set the bits to enable memory / usage / bus faults. + // Otherwise these will all get escalated to hard faults. +#ifdef SCB_SHCSR_MEMFAULTENA_Msk + SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk | SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk; +#endif + mbed_mpu_manager_init(); mbed_cpy_nvic(); mbed_sdk_init(); diff --git a/connectivity/drivers/emac/TARGET_Freescale_EMAC/kinetis_emac.cpp b/connectivity/drivers/emac/TARGET_Freescale_EMAC/kinetis_emac.cpp index cab47baae1d..5f7265bb740 100644 --- a/connectivity/drivers/emac/TARGET_Freescale_EMAC/kinetis_emac.cpp +++ b/connectivity/drivers/emac/TARGET_Freescale_EMAC/kinetis_emac.cpp @@ -395,17 +395,10 @@ bool Kinetis_EMAC::link_out(emac_mem_buf_t *buf) // If buffer is chained or not aligned then make a contiguous aligned copy of it if (memory_manager->get_next(buf) || reinterpret_cast(memory_manager->get_ptr(buf)) % ENET_BUFF_ALIGNMENT) { - emac_mem_buf_t *copy_buf; - copy_buf = memory_manager->alloc_heap(memory_manager->get_total_len(buf), ENET_BUFF_ALIGNMENT); - if (NULL == copy_buf) { - memory_manager->free(buf); - return false; + buf = memory_manager->realloc_heap(buf, ENET_BUFF_ALIGNMENT); + if(buf == nullptr) { + return false; } - - // Copy to new buffer and free original - memory_manager->copy(copy_buf, buf); - memory_manager->free(buf); - buf = copy_buf; } /* Check if a descriptor is available for the transfer (wait 10ms before dropping the buffer) */ diff --git a/connectivity/drivers/emac/TARGET_NXP_EMAC/TARGET_IMX/imx_emac.cpp b/connectivity/drivers/emac/TARGET_NXP_EMAC/TARGET_IMX/imx_emac.cpp index 57ca6892c72..935f01e29a9 100644 --- a/connectivity/drivers/emac/TARGET_NXP_EMAC/TARGET_IMX/imx_emac.cpp +++ b/connectivity/drivers/emac/TARGET_NXP_EMAC/TARGET_IMX/imx_emac.cpp @@ -396,17 +396,10 @@ bool Kinetis_EMAC::link_out(emac_mem_buf_t *buf) // If buffer is chained or not aligned then make a contiguous aligned copy of it if (memory_manager->get_next(buf) || reinterpret_cast(memory_manager->get_ptr(buf)) % ENET_BUFF_ALIGNMENT) { - emac_mem_buf_t *copy_buf; - copy_buf = memory_manager->alloc_heap(memory_manager->get_total_len(buf), ENET_BUFF_ALIGNMENT); - if (NULL == copy_buf) { - memory_manager->free(buf); + buf = memory_manager->realloc_heap(buf, ENET_BUFF_ALIGNMENT); + if (buf == nullptr) { return false; } - - // Copy to new buffer and free original - memory_manager->copy(copy_buf, buf); - memory_manager->free(buf); - buf = copy_buf; } SCB_CleanDCache_by_Addr(static_cast(memory_manager->get_ptr(buf)), memory_manager->get_len(buf)); diff --git a/connectivity/drivers/emac/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc17_emac.cpp b/connectivity/drivers/emac/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc17_emac.cpp index c272b52c601..09f404f9079 100644 --- a/connectivity/drivers/emac/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc17_emac.cpp +++ b/connectivity/drivers/emac/TARGET_NXP_EMAC/TARGET_LPCTarget/lpc17_emac.cpp @@ -505,16 +505,10 @@ bool LPC17_EMAC::link_out(emac_mem_buf_t *p) if (notdmasafe) { /* Allocate a buffer in DMA memory. MEMORY MANAGER HEAP MUST BE IN DMA SAFE MEMORY. */ - np = memory_manager->alloc_heap(memory_manager->get_total_len(p), 0); - if (np == NULL) { - memory_manager->free(p); + p = memory_manager->realloc_heap(p, 0); + if (p == nullptr) { return false; } - memory_manager->copy(np, p); - /* use the new buffer for descriptor queueing. The original buffer will - be de-allocated. */ - memory_manager->free(p); - p = np; dn = 1; } #else diff --git a/connectivity/drivers/emac/TARGET_NXP_EMAC/TARGET_MCU_LPC546XX/lpc546xx_emac.cpp b/connectivity/drivers/emac/TARGET_NXP_EMAC/TARGET_MCU_LPC546XX/lpc546xx_emac.cpp index cc5f09385f2..c5cc1ffd4fc 100644 --- a/connectivity/drivers/emac/TARGET_NXP_EMAC/TARGET_MCU_LPC546XX/lpc546xx_emac.cpp +++ b/connectivity/drivers/emac/TARGET_NXP_EMAC/TARGET_MCU_LPC546XX/lpc546xx_emac.cpp @@ -397,17 +397,11 @@ bool LPC546XX_EMAC::link_out(emac_mem_buf_t *buf) // If buffer is chained or not aligned then make a contiguous aligned copy of it if (memory_manager->get_next(buf) || reinterpret_cast(memory_manager->get_ptr(buf)) % ENET_BUFF_ALIGNMENT) { - emac_mem_buf_t *copy_buf; - copy_buf = memory_manager->alloc_heap(memory_manager->get_total_len(buf), ENET_BUFF_ALIGNMENT); - if (NULL == copy_buf) { - memory_manager->free(buf); - return false; - } - // Copy to new buffer and free original - memory_manager->copy(copy_buf, buf); - memory_manager->free(buf); - buf = copy_buf; + buf = memory_manager->realloc_heap(buf, ENET_BUFF_ALIGNMENT); + if(buf == nullptr) { + return false; + } } /* Check if a descriptor is available for the transfer. */ diff --git a/connectivity/drivers/emac/include/GenericEthDMA.h b/connectivity/drivers/emac/include/GenericEthDMA.h index f31fcee1c4e..85e1da7ea9a 100644 --- a/connectivity/drivers/emac/include/GenericEthDMA.h +++ b/connectivity/drivers/emac/include/GenericEthDMA.h @@ -244,22 +244,15 @@ namespace mbed { // Step 2: Copy packet if needed if(needToCopy) { - auto * newBuf = memory_manager->alloc_heap(memory_manager->get_total_len(buf), 0); - if(newBuf == nullptr) + buf = memory_manager->realloc_heap(buf, 0); + if(buf == nullptr) { // No free memory, drop packet return CompositeEMAC::ErrCode::OUT_OF_MEMORY; } - // We should have gotten just one contiguous buffer - MBED_ASSERT(memory_manager->get_next(newBuf) == nullptr); packetDescsUsed = 1; neededFreeDescs = packetDescsUsed + extraTxDescsToLeave; - - // Copy data over - memory_manager->copy_from_buf(static_cast(memory_manager->get_ptr(newBuf)), memory_manager->get_len(newBuf), buf); - memory_manager->free(buf); - buf = newBuf; } tr_debug("Transmitting packet of length %lu in %zu buffers and %zu descs\n", diff --git a/connectivity/drivers/wifi/CMakeLists.txt b/connectivity/drivers/wifi/CMakeLists.txt index 9f5277c615b..9fda8c3d05a 100644 --- a/connectivity/drivers/wifi/CMakeLists.txt +++ b/connectivity/drivers/wifi/CMakeLists.txt @@ -26,7 +26,7 @@ if("STM" IN_LIST MBED_TARGET_LABELS) add_subdirectory(TARGET_STM EXCLUDE_FROM_ALL) endif() -if("WHD" IN_LIST MBED_TARGET_LABELS) +if("COMPONENT_WHD=1" IN_LIST MBED_TARGET_DEFINITIONS) create_mbed_wifi_target() add_subdirectory(COMPONENT_WHD EXCLUDE_FROM_ALL) endif() diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/mbed_lib.json b/connectivity/drivers/wifi/COMPONENT_WHD/mbed_lib.json deleted file mode 100644 index 65af60bb039..00000000000 --- a/connectivity/drivers/wifi/COMPONENT_WHD/mbed_lib.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "cy_psoc6_whd", - "config": { - "present": 1 - } -} diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/mbed_lib.json5 b/connectivity/drivers/wifi/COMPONENT_WHD/mbed_lib.json5 new file mode 100644 index 00000000000..c734f6511f9 --- /dev/null +++ b/connectivity/drivers/wifi/COMPONENT_WHD/mbed_lib.json5 @@ -0,0 +1,10 @@ +{ + "name": "cy_psoc6_whd", + "config": { + "present": 1, + "tx-buffer-header-space": { + "help": "Header space in bytes that needs to be present in buffers passed from the Mbed EMAC to the WHD driver.", + "value": 64 + } + }, +} diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/CMakeLists.txt b/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/CMakeLists.txt index 5fdb8ded7e6..adab55df81e 100644 --- a/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/CMakeLists.txt +++ b/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/CMakeLists.txt @@ -8,16 +8,9 @@ target_include_directories(mbed-wifi target_sources(mbed-wifi PRIVATE - cy_network_buffer.c cybsp_wifi.c ) -target_link_libraries(mbed-wifi - PUBLIC - mbed-lwipstack - mbed-core-flags -) - if("DEVICE_EMAC=1" IN_LIST MBED_TARGET_DEFINITIONS) target_link_libraries(mbed-wifi PUBLIC diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/cy_network_buffer.c b/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/cy_network_buffer.c deleted file mode 100755 index 2e1ea4c90d3..00000000000 --- a/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/cy_network_buffer.c +++ /dev/null @@ -1,150 +0,0 @@ -/***********************************************************************************************//** - * \file cy_network_buffer.c - * - * \brief - * Basic set of APIs for dealing with network packet buffers. This is used by WHD - * for relaying data between the network stack and the connectivity chip. - * - *************************************************************************************************** - * \copyright - * Copyright 2018-2021 Cypress Semiconductor Corporation - * SPDX-License-Identifier: Apache-2.0 - * - * 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 "cy_network_buffer.h" -#include "cy_utils.h" -#include "cyhal_system.h" -#include "lwip/pbuf.h" -#include "lwip/memp.h" - -#define SDIO_BLOCK_SIZE (64U) - -//-------------------------------------------------------------------------------------------------- -// cy_host_buffer_get -//-------------------------------------------------------------------------------------------------- -whd_result_t cy_host_buffer_get(whd_buffer_t* buffer, whd_buffer_dir_t direction, - unsigned short size, unsigned long timeout_ms) -{ - struct pbuf* p = NULL; - unsigned long counter = 0; - - do - { - if (direction == WHD_NETWORK_TX) - { - // Allocate from the POOL if possible to avoid dynamic memory allocation - pbuf_type type = (size <= PBUF_POOL_BUFSIZE) ? PBUF_POOL : PBUF_RAM; - p = pbuf_alloc(PBUF_RAW, size, type); - } - else - { - // Increase allocation size to ensure the SDIO can write fully aligned blocks for - // best throughput performance - p = pbuf_alloc(PBUF_RAW, size + SDIO_BLOCK_SIZE, PBUF_RAM); - if (p != NULL) - { - p->len = size; - p->tot_len -= SDIO_BLOCK_SIZE; - } - } - - if (NULL == p) - { - cyhal_system_delay_ms(1); - } - } while (NULL == p && ++counter < timeout_ms); - - if (p != NULL) - { - *buffer = p; - return WHD_SUCCESS; - } - else - { - return WHD_BUFFER_ALLOC_FAIL; - } -} - - -//-------------------------------------------------------------------------------------------------- -// cy_buffer_release -//-------------------------------------------------------------------------------------------------- -void cy_buffer_release(whd_buffer_t buffer, whd_buffer_dir_t direction) -{ - CY_UNUSED_PARAMETER(direction); - (void)pbuf_free((struct pbuf*)buffer); -} - - -//-------------------------------------------------------------------------------------------------- -// cy_buffer_get_current_piece_data_pointer -//-------------------------------------------------------------------------------------------------- -uint8_t* cy_buffer_get_current_piece_data_pointer(whd_buffer_t buffer) -{ - CY_ASSERT(buffer != NULL); - struct pbuf* pbuffer= (struct pbuf*)buffer; - return (uint8_t*)pbuffer->payload; -} - - -//-------------------------------------------------------------------------------------------------- -// cy_buffer_get_current_piece_size -//-------------------------------------------------------------------------------------------------- -uint16_t cy_buffer_get_current_piece_size(whd_buffer_t buffer) -{ - CY_ASSERT(buffer != NULL); - struct pbuf* pbuffer = (struct pbuf*)buffer; - return (uint16_t)pbuffer->len; -} - - -//-------------------------------------------------------------------------------------------------- -// cy_buffer_set_size -//-------------------------------------------------------------------------------------------------- -whd_result_t cy_buffer_set_size(whd_buffer_t buffer, unsigned short size) -{ - CY_ASSERT(buffer != NULL); - struct pbuf* pbuffer = (struct pbuf*)buffer; - - if (size > ((unsigned short)WHD_LINK_MTU + - LWIP_MEM_ALIGN_SIZE(LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf))) + - LWIP_MEM_ALIGN_SIZE(size))) - { - return WHD_PMK_WRONG_LENGTH; - } - - pbuffer->tot_len = size; - pbuffer->len = size; - - return CY_RSLT_SUCCESS; -} - - -//-------------------------------------------------------------------------------------------------- -// cy_buffer_add_remove_at_front -//-------------------------------------------------------------------------------------------------- -whd_result_t cy_buffer_add_remove_at_front(whd_buffer_t* buffer, int32_t add_remove_amount) -{ - CY_ASSERT(buffer != NULL); - struct pbuf** pbuffer = (struct pbuf**)buffer; - - if ((u8_t)0 != pbuf_header(*pbuffer, (s16_t)(-add_remove_amount))) - { - return WHD_PMK_WRONG_LENGTH; - } - - return WHD_SUCCESS; -} diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/cy_network_buffer.h b/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/cy_network_buffer.h deleted file mode 100755 index 90b026689db..00000000000 --- a/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/cy_network_buffer.h +++ /dev/null @@ -1,170 +0,0 @@ -/***********************************************************************************************//** - * \file cy_network_buffer.h - * - * \brief - * Basic set of APIs for dealing with network packet buffers. This is used by WHD - * for relaying data between the network stack and the connectivity chip. - * - *************************************************************************************************** - * \copyright - * Copyright 2018-2021 Cypress Semiconductor Corporation - * SPDX-License-Identifier: Apache-2.0 - * - * 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. - **************************************************************************************************/ - -/** - * \addtogroup group_bsp_network_buffer Buffer management - * \{ - * Basic set of APIs for dealing with network packet buffers - */ - -#pragma once - -#include -#include -#include "cy_result.h" -#include "whd.h" -#include "whd_network_types.h" - -#if defined(__cplusplus) -extern "C" { -#endif - - -/** Allocates a packet buffer - * - * Attempts to allocate a packet buffer of the size requested. It can do this - * by allocating a pre-existing packet from a pool, using a static buffer, - * or by dynamically allocating memory. The method of allocation does not - * concern WHD, however it must match the way the network stack expects packet - * buffers to be allocated. Usually WHD requires packet of size of WHD_LINK_MTU - * which includes the MTU. Refer to whd_types.h to find the size of WHD_LINK_MTU. - * - * @param buffer : A pointer which receives the allocated packet buffer handle - * @param direction : Indicates transmit/receive direction that the packet buffer is - * used for. This may be needed if tx/rx pools are separate. - * @param size : The number of bytes to allocate. - * @param timeout_ms: Time to wait for a packet buffer to be available - * - * @return : CY_RSLT_SUCCESS or WHD_BUFFER_ALLOC_FAIL if the buffer could not be allocated - */ -whd_result_t cy_host_buffer_get(whd_buffer_t* buffer, whd_buffer_dir_t direction, - unsigned short size, unsigned long timeout_ms); - -/** Releases a packet buffer - * - * This function is used by WHD to indicate that it no longer requires - * a packet buffer. The buffer can then be released back into a pool for - * reuse, or the dynamically allocated memory can be freed, according to - * how the packet was allocated. - * Returns void since WHD cannot do anything about failures - * - * @param buffer : The handle of the packet buffer to be released - * @param direction : Indicates transmit/receive direction that the packet buffer has - * been used for. This might be needed if tx/rx pools are separate. - */ -void cy_buffer_release(whd_buffer_t buffer, whd_buffer_dir_t direction); - -/** Retrieves the current pointer of a packet buffer - * - * Since packet buffers usually need to be created with space at the - * front for additional headers, this function allows WHD to get - * the current 'front' location pointer. - * - * @param buffer : The handle of the packet buffer whose pointer is to be retrieved - * - * @return : The packet buffer's current pointer. - */ -uint8_t* cy_buffer_get_current_piece_data_pointer(whd_buffer_t buffer); - -/** Retrieves the size of a packet buffer - * - * Since packet buffers usually need to be created with space at the - * front for additional headers, the memory block used to contain a packet buffer - * will often be larger than the current size of the packet buffer data. - * This function allows WHD to retrieve the current size of a packet buffer's data. - * - * @param buffer : The handle of the packet buffer whose size is to be retrieved - * - * @return : The size of the packet buffer. - */ -uint16_t cy_buffer_get_current_piece_size(whd_buffer_t buffer); - -/** Sets the current size of a WHD packet - * - * This function sets the current length of a WHD packet buffer - * - * @param buffer : The packet to be modified - * @param size : The new size of the packet buffer - * - * @return : CY_RSLT_SUCCESS or WHD_PMK_WRONG_LENGTH if the requested size is not valid - */ -whd_result_t cy_buffer_set_size(whd_buffer_t buffer, unsigned short size); - -/** Moves the current pointer of a packet buffer - * - * Since packet buffers usually need to be created with space at the front for additional headers, - * this function allows WHD to move the current 'front' location pointer so that it has space to - * add headers to transmit packets, and so that the network stack does not see the internal WHD - * headers on received packets. - * - * @param buffer : A pointer to the handle of the current packet buffer for which the - * current pointer will be moved. On return this may contain a pointer - * to a newly allocated packet buffer which has been daisy chained to - * the front of the given one. This would be the case if the given - * packet buffer didn't have enough space at the front. - * @param add_remove_amount : This is the number of bytes to move the current pointer of the packet - * buffer - a negative value increases the space for headers at the - * front of the packet, a positive value decreases the space. - * - * @return : CY_RSLT_SUCCESS or WHD_PMK_WRONG_LENGTH if the added amount is - * outside the size of the buffer - */ -whd_result_t cy_buffer_add_remove_at_front(whd_buffer_t* buffer, int32_t add_remove_amount); - - -/** Called by WHD to pass received data to the network stack - * - * Packets received from the Wi-Fi network by WHD are forwarded to by calling function ptr which - * must be implemented in the network interface. Ethernet headers - * are present at the start of these packet buffers. - * - * This function is called asynchronously in the context of the - * WHD thread whenever new data has arrived. - * Packet buffers are allocated within WHD, and ownership is transferred - * to the network stack. The network stack or application is thus - * responsible for releasing the packet buffers. - * Most packet buffering systems have a pointer to the 'current point' within - * the packet buffer. When this function is called, the pointer points - * to the start of the Ethernet header. There is other inconsequential data - * before the Ethernet header. - * - * It is preferable that the (whd_network_process_ethernet_data)() function simply puts - * the received packet on a queue for processing by another thread. This avoids the - * WHD thread being unnecessarily tied up which would delay other packets - * being transmitted or received. - * - * @param interface : The interface on which the packet was received. - * @param buffer : Handle of the packet which has just been received. Responsibility for - * releasing this buffer is transferred from WHD at this point. - * - */ -void cy_network_process_ethernet_data(whd_interface_t interface, whd_buffer_t buffer); - - -#ifdef __cplusplus -} -#endif // __cplusplus - -/** \} group_bsp_network_buffer */ diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/cybsp_wifi.c b/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/cybsp_wifi.c index 2a4b49e8f56..a28b3b98996 100755 --- a/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/cybsp_wifi.c +++ b/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/cybsp_wifi.c @@ -24,9 +24,9 @@ #include "cybsp.h" #include "cybsp_wifi.h" -#include "cy_network_buffer.h" #include "cyabs_rtos.h" #include "whd_types.h" +#include "whd_network_types.h" #include "cyhal.h" #if defined(COMPONENT_BSP_DESIGN_MODUS) || defined(COMPONENT_CUSTOM_DESIGN_MODUS) #include "cycfg.h" @@ -89,16 +89,6 @@ static whd_driver_t whd_drv; extern whd_resource_source_t resource_ops; -static whd_buffer_funcs_t buffer_if_default = -{ - .whd_host_buffer_get = cy_host_buffer_get, - .whd_buffer_release = cy_buffer_release, - .whd_buffer_get_current_piece_data_pointer = cy_buffer_get_current_piece_data_pointer, - .whd_buffer_get_current_piece_size = cy_buffer_get_current_piece_size, - .whd_buffer_set_size = cy_buffer_set_size, - .whd_buffer_add_remove_at_front = cy_buffer_add_remove_at_front, -}; - static whd_netif_funcs_t netif_if_default = { .whd_network_process_ethernet_data = cy_network_process_ethernet_data, @@ -252,10 +242,7 @@ cy_rslt_t cybsp_wifi_init_primary_extended(whd_interface_t* interface, { resource_if = &resource_ops; } - if (buffer_if == NULL) - { - buffer_if = &buffer_if_default; - } + CY_ASSERT(buffer_if != NULL); if (netif_if == NULL) { netif_if = &netif_if_default; diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/cybsp_wifi.h b/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/cybsp_wifi.h index be71a9d01c6..1a0057646ee 100755 --- a/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/cybsp_wifi.h +++ b/connectivity/drivers/wifi/COMPONENT_WHD/whd-bsp-integration/cybsp_wifi.h @@ -48,6 +48,8 @@ extern "C" { #define CYBSP_RSLT_WIFI_SDIO_ENUM_TIMEOUT \ (CY_RSLT_CREATE(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_BOARD_LIB_WHD_INTEGRATION, 1)) + + /** Initializes the primary interface for the WiFi driver on the board. This sets up * the WHD interface to use the \ref group_bsp_network_buffer APIs and to communicate * over the SDIO interface on the board. This function does the following:
diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/CMakeLists.txt b/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/CMakeLists.txt index da463fc2e24..21a2bfe721a 100644 --- a/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/CMakeLists.txt +++ b/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/CMakeLists.txt @@ -16,6 +16,7 @@ target_sources(mbed-wifi interface/WhdSTAInterface.cpp interface/WhdSoftAPInterface.cpp interface/whd_emac.cpp + interface/WhdMemoryManagerInterface.cpp interface/whd_interface.cpp utils/cydhcp_server_debug.cpp diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/CyDhcpServer.cpp b/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/CyDhcpServer.cpp index ca84423ff9a..1f68d27d42d 100644 --- a/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/CyDhcpServer.cpp +++ b/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/CyDhcpServer.cpp @@ -18,9 +18,10 @@ #include "CyDhcpServer.h" #include "cy_utils.h" #include "Callback.h" -#include "def.h" #include "whd_types.h" +#include + #ifdef DHCP_EXTENSIVE_DEBUG extern "C" void dhcp_server_print_header_info(dhcp_packet_t *header, uint32_t datalen, const char *title); #endif @@ -143,7 +144,7 @@ static void addCommonOptions(dhcp_packet_t *dhcp, uint32_t &index, const uint32_ /* Prepare the Web proxy auto discovery URL */ char wpad_sample_url[] = "http://xxx.xxx.xxx.xxx/wpad.dat"; char ip_str[16]; - ipv4_to_string(ip_str, htonl(server_addr)); + ipv4_to_string(ip_str, __htonl(server_addr)); memcpy(&wpad_sample_url[7], &ip_str[0], 15); /* Server identifier */ @@ -151,13 +152,13 @@ static void addCommonOptions(dhcp_packet_t *dhcp, uint32_t &index, const uint32_ /* Lease Time */ addOption(dhcp, index, DHCP_LEASETIME_OPTION_CODE, static_cast(0x00015180)); /* Subnet Mask */ - addOption(dhcp, index, DHCP_SUBNETMASK_OPTION_CODE, htonl(netmask)); + addOption(dhcp, index, DHCP_SUBNETMASK_OPTION_CODE, __htonl(netmask)); /* Web proxy auto discovery URL */ addOption(dhcp, index, DHCP_WPAD_OPTION_CODE, (uint8_t *)&wpad_sample_url[0], strlen(wpad_sample_url)); /* Router (gateway) */ - addOption(dhcp, index, DHCP_ROUTER_OPTION_CODE, htonl(server_addr)); + addOption(dhcp, index, DHCP_ROUTER_OPTION_CODE, __htonl(server_addr)); /* DNS server */ - addOption(dhcp, index, DHCP_DNS_SERVER_OPTION_CODE, htonl(server_addr)); + addOption(dhcp, index, DHCP_DNS_SERVER_OPTION_CODE, __htonl(server_addr)); /* Interface MTU */ addOption(dhcp, index, DHCP_MTU_OPTION_CODE, static_cast(WHD_PAYLOAD_MTU)); } @@ -167,7 +168,7 @@ static void sendPacket(UDPSocket *socket, dhcp_packet_t *dhcp, uint32_t size) nsapi_size_or_error_t err; uint32_t broadcast_ip = 0xFFFFFFFF; char string_addr[16]; - ipv4_to_string(string_addr, htonl(broadcast_ip)); + ipv4_to_string(string_addr, __htonl(broadcast_ip)); SocketAddress sock_addr(string_addr, IP_PORT_DHCP_CLIENT); err = socket->sendto(sock_addr, reinterpret_cast(dhcp), size); @@ -255,8 +256,8 @@ void CyDhcpServer::handleDiscover(dhcp_packet_t *dhcp) memset(&dhcp->Options[0], 0, DHCP_PACKET_SIZE - sizeof(dhcp_packet_t) + 3); dhcp->Opcode = BOOTP_OP_REPLY; - dhcp->YourIpAddr = htonl(client_ip.addrv4.addr); - dhcp->MagicCookie = htonl(static_cast(DHCP_MSG_MAGIC_COOKIE)); + dhcp->YourIpAddr = __htonl(client_ip.addrv4.addr); + dhcp->MagicCookie = __htonl(static_cast(DHCP_MSG_MAGIC_COOKIE)); /* Add options */ index = 0; @@ -292,7 +293,7 @@ void CyDhcpServer::handleRequest(dhcp_packet_t *dhcp) } /* Locate the requested address in the options and keep requested address */ - req_ip.addrv4.addr = ntohl(*(uint32_t *)findOption(dhcp, DHCP_REQUESTED_IP_ADDRESS_OPTION_CODE)); + req_ip.addrv4.addr = __ntohl(*(uint32_t *)findOption(dhcp, DHCP_REQUESTED_IP_ADDRESS_OPTION_CODE)); memcpy(&client_mac, dhcp->ClientHwAddr, sizeof(client_mac)); if (!lookupAddress(client_mac, client_ip)) { @@ -304,7 +305,7 @@ void CyDhcpServer::handleRequest(dhcp_packet_t *dhcp) memset(&dhcp->Options[0], 0, DHCP_PACKET_SIZE - sizeof(dhcp_packet_t) + 3); dhcp->Opcode = BOOTP_OP_REPLY; - dhcp->MagicCookie = htonl(static_cast(DHCP_MSG_MAGIC_COOKIE)); + dhcp->MagicCookie = __htonl(static_cast(DHCP_MSG_MAGIC_COOKIE)); index = 0; /* Check if the requested IP address matches one we have assigned */ @@ -314,7 +315,7 @@ void CyDhcpServer::handleRequest(dhcp_packet_t *dhcp) addOption(dhcp, index, DHCP_SERVER_IDENTIFIER_OPTION_CODE, _server_addr.addrv4.addr); printf("\n\nDHCP_THREAD: %d REQUEST NAK\n", __LINE__); } else { - dhcp->YourIpAddr = htonl(client_ip.addrv4.addr); + dhcp->YourIpAddr = __htonl(client_ip.addrv4.addr); addOption(dhcp, index, DHCP_MESSAGETYPE_OPTION_CODE, static_cast(DHCP_MSG_TYPE_ACK)); addCommonOptions(dhcp, index, _server_addr.addrv4.addr, _netmask.addrv4.addr); diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/WhdMemoryManagerInterface.cpp b/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/WhdMemoryManagerInterface.cpp new file mode 100644 index 00000000000..4c2273a1171 --- /dev/null +++ b/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/WhdMemoryManagerInterface.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2025 Jamie Smith + * SPDX-License-Identifier: Apache-2.0 + * + * 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 "WhdMemoryManagerInterface.h" + +#include +#include + +// Note: Implementations adapted from Infineon's code for LwIP +// https://github.com/Infineon/wifi-host-driver/blob/master/docs/html/cy_network_buffer.c + +// Note: In this code, both "whd_buffer_t" and "net_stack_mem_buf_t *" represent pointers to opaque network +// stack buffers, and we use them interchangeably. + +whd_result_t mbed_whd_host_buffer_get(void *instance, whd_buffer_t*buffer, const whd_buffer_dir_t direction, const unsigned short size, + const unsigned long timeout_ms) { + auto * const memoryManager = static_cast(instance); + + mbed::Timer allocTimer; + allocTimer.start(); + + do { + + // Pool should only be used for Rx buffers and only if we can do a contiguous allocation. + // Note that IMO the official example code is wrong here -- pool buffers should only be used for Rx as + // they have some special properties in LwIP (a failed allocation triggers a cleanup of nonessential + // internal memory buffers). So I changed this from Tx to Rx. + const bool usePool = direction == WHD_NETWORK_RX && ((size + WHD_MEM_BUFFER_EXTRA_SPACE) <= memoryManager->get_pool_alloc_unit(WHD_MEM_BUFFER_ALIGNMENT)); + + if(usePool) { + // Try to allocate from the pool if possible to avoid dynamic memory allocation + *buffer = memoryManager->alloc_pool(size + WHD_MEM_BUFFER_EXTRA_SPACE, WHD_MEM_BUFFER_ALIGNMENT); + if(*buffer) { + return WHD_SUCCESS; + } + } + + // Now try using the heap + *buffer = memoryManager->alloc_heap(size + WHD_MEM_BUFFER_EXTRA_SPACE, WHD_MEM_BUFFER_ALIGNMENT); + if(*buffer) { + return WHD_SUCCESS; + } + + // Both failed? wait + rtos::ThisThread::sleep_for(std::chrono::milliseconds(1)); + } while(allocTimer.elapsed_time() < std::chrono::milliseconds(timeout_ms)); + + return WHD_BUFFER_ALLOC_FAIL; +} + +void mbed_whd_buffer_release(void *instance, const whd_buffer_t buffer, const whd_buffer_dir_t direction) { + (void)direction; + MBED_ASSERT(buffer != nullptr); + + auto * const memoryManager = static_cast(instance); + memoryManager->free(buffer); +} + +uint8_t * mbed_whd_buffer_get_current_piece_data_pointer(void *instance, whd_buffer_t buffer) { + MBED_ASSERT(buffer != nullptr); + auto * const memoryManager = static_cast(instance); + return static_cast(memoryManager->get_ptr(buffer)); +} + +uint16_t mbed_whd_buffer_get_current_piece_size(void *instance, whd_buffer_t buffer) { + MBED_ASSERT(buffer != nullptr); + auto * const memoryManager = static_cast(instance); + return memoryManager->get_len(buffer) - WHD_MEM_BUFFER_EXTRA_SPACE; +} + +whd_result_t mbed_whd_buffer_set_size(void *instance, whd_buffer_t buffer, unsigned short size) { + MBED_ASSERT(buffer != nullptr); + auto * const memoryManager = static_cast(instance); + + // Note that the example code has a rather confusing sanity check on size here. However, the Mbed + // net stack memory manager interface doesn't provide a way to check the original size of a buffer, + // so it's hard to port over properly. + // However, when we run this code in the EMAC test, the EmacTestMemoryManager will catch any incorrect + // usage here + memoryManager->set_len(buffer, size + WHD_MEM_BUFFER_EXTRA_SPACE); + + return WHD_SUCCESS; +} + +whd_result_t mbed_whd_buffer_add_remove_at_front(void *instance, whd_buffer_t*buffer, int32_t add_remove_amount) { + MBED_ASSERT(buffer != nullptr); + auto * const memoryManager = static_cast(instance); + + // Make sure we aren't trying to skip before the start of the buffer or after the end + if(add_remove_amount + memoryManager->get_header_skip_size(*buffer) < 0) { + return WHD_PMK_WRONG_LENGTH; + } + if(add_remove_amount > static_cast(memoryManager->get_len(*buffer) - WHD_MEM_BUFFER_EXTRA_SPACE)) { + return WHD_PMK_WRONG_LENGTH; + } + + memoryManager->skip_header_space(*buffer, add_remove_amount); + + return WHD_SUCCESS; +} + diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/WhdMemoryManagerInterface.h b/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/WhdMemoryManagerInterface.h new file mode 100644 index 00000000000..12054c037ff --- /dev/null +++ b/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/WhdMemoryManagerInterface.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025 Jamie Smith + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +#ifndef WHDMEMORYMANAGERINTERFACE_H +#define WHDMEMORYMANAGERINTERFACE_H + +#include "whd_network_types.h" +#include "whd.h" + +#include "NetStackMemoryManager.h" + +// Default to 4 byte alignment +constexpr size_t WHD_MEM_BUFFER_ALIGNMENT = sizeof(uint32_t); + +// The WHD driver likes to use SDIO block mode for reads, meaning that an additional up-to 63 bytes can be stored at the +// end of the buffer relative to its actual size. This means that this layer needs to allocate the buffers +// with additional space at the end relative to what was asked for, and then NOT report this space +// when asked about a buffer's length +constexpr size_t WHD_MEM_BUFFER_EXTRA_SPACE = 64; + +// These functions interface the Cypress WHD driver with Mbed's memory manager interface. +// For documentation on each function, see "struct whd_buffer_funcs" in whd_network_types.h + +whd_result_t mbed_whd_host_buffer_get(void* instance, whd_buffer_t *buffer, whd_buffer_dir_t direction, unsigned short size, + unsigned long timeout_ms); +void mbed_whd_buffer_release(void* instance, whd_buffer_t buffer, whd_buffer_dir_t direction); +uint8_t * mbed_whd_buffer_get_current_piece_data_pointer(void* instance, whd_buffer_t buffer); +uint16_t mbed_whd_buffer_get_current_piece_size(void* instance, whd_buffer_t buffer); +whd_result_t mbed_whd_buffer_set_size(void* instance, whd_buffer_t buffer, unsigned short size); +whd_result_t mbed_whd_buffer_add_remove_at_front(void* instance, whd_buffer_t *buffer, int32_t add_remove_amount); + +static inline whd_buffer_funcs_t getMbedWHDBufferFuncs(NetStackMemoryManager & memManager) { + return { + .instance = &memManager, + .whd_host_buffer_get = mbed_whd_host_buffer_get, + .whd_buffer_release = mbed_whd_buffer_release, + .whd_buffer_get_current_piece_data_pointer = mbed_whd_buffer_get_current_piece_data_pointer, + .whd_buffer_get_current_piece_size = mbed_whd_buffer_get_current_piece_size, + .whd_buffer_set_size = mbed_whd_buffer_set_size, + .whd_buffer_add_remove_at_front = mbed_whd_buffer_add_remove_at_front + }; +} + +#endif //WHDMEMORYMANAGERINTERFACE_H diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/WhdSTAInterface.cpp b/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/WhdSTAInterface.cpp index d527fbaf1ba..87fea76004e 100644 --- a/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/WhdSTAInterface.cpp +++ b/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/WhdSTAInterface.cpp @@ -20,9 +20,6 @@ #include #include "WhdSTAInterface.h" #include "nsapi.h" -#include "lwipopts.h" -#include "lwip/etharp.h" -#include "lwip/ethip6.h" #include "rtos.h" #include "whd_emac.h" #include "whd_wifi_api.h" @@ -263,6 +260,7 @@ nsapi_error_t WhdSTAInterface::connect() // initialize wiced, this is noop if already init if (!_whd_emac.powered_up) { + _whd_emac.set_memory_manager(_stack.get_memory_manager()); if(!_whd_emac.power_up()) { return NSAPI_ERROR_DEVICE_ERROR; } @@ -351,16 +349,21 @@ nsapi_error_t WhdSTAInterface::connect() return whd_toerror(res); } - if (whd_wifi_is_ready_to_transceive(_whd_emac.ifp) == WHD_SUCCESS) { - whd_emac_wifi_link_state_changed(_whd_emac.ifp, WHD_TRUE); - } - // bring up - return _interface->bringup(_dhcp, + auto ret = _interface->bringup(_dhcp, _ip_address[0] ? _ip_address : 0, _netmask[0] ? _netmask : 0, _gateway[0] ? _gateway : 0, DEFAULT_STACK); + + // There's a bit of a race condition here: many stacks attach a link state callback to the EMAC in their + // bringup() method, but the wifi may have already connected before we got here, meaning the callback never gets + // delivered. So, redeliver the link state callback now. + if (ret == NSAPI_ERROR_OK && whd_wifi_is_ready_to_transceive(_whd_emac.ifp) == WHD_SUCCESS) { + whd_emac_wifi_link_state_changed(_whd_emac.ifp, WHD_TRUE); + } + + return ret; } void WhdSTAInterface::wifi_on() diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/WhdSoftAPInterface.cpp b/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/WhdSoftAPInterface.cpp index 9009ab07545..0ddf5532a7e 100644 --- a/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/WhdSoftAPInterface.cpp +++ b/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/WhdSoftAPInterface.cpp @@ -16,12 +16,8 @@ */ #include "nsapi.h" -#include "lwipopts.h" #include "WhdSoftAPInterface.h" #include "nsapi.h" -#include "lwipopts.h" -#include "lwip/etharp.h" -#include "lwip/ethip6.h" #include "rtos.h" #include "whd_emac.h" #include "whd_wifi_api.h" diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/whd_emac.cpp b/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/whd_emac.cpp index 111839ec6cc..0f54310fc49 100644 --- a/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/whd_emac.cpp +++ b/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/whd_emac.cpp @@ -22,8 +22,6 @@ #include "cmsis_os.h" #include "whd_emac.h" -#include "lwip/etharp.h" -#include "lwip/ethip6.h" #include "events/mbed_shared_queues.h" #include "whd_wlioctl.h" #include "whd_buffer_api.h" @@ -32,6 +30,8 @@ #include "emac_eapol.h" #include "cy_result.h" +#include "WhdMemoryManagerInterface.h" + #if defined(CY_EXT_WIFI_FW_STORAGE) && !MBED_CONF_TARGET_XIP_ENABLE #include "cy_ext_wifi_fw_reserved_region_bd.h" #endif /* defined(CY_EXT_WIFI_FW_STORAGE) && !MBED_CONF_TARGET_XIP_ENABLE */ @@ -87,7 +87,25 @@ void WHD_EMAC::remove_multicast_group(const uint8_t *addr) void WHD_EMAC::set_all_multicast(bool all) { - /* No-op at this stage */ + // Sadly, the WHD wifi modules do not have a "pass all multicast" option. And extra sadly, + // nanostack does not track individual multicast subscriptions and just calls this function + // at bootup. + // So, we have to do an awful hack here of adding the "all systems" and "all routers" multicast + // addresses when this is enabled so that Nanostack's IPv6 stack can work. This is gross because + // it means subscribing to other multicast groups with Nanostack won't work, but it's the best + // we can do for now. + + uint8_t ALL_SYSTEMS_MCAST_MAC[] = {0x33, 0x33, 0x00, 0x00, 0x00, 0x01}; + uint8_t ALL_ROUTERS_MCAST_MAC[] = {0x33, 0x33, 0x00, 0x00, 0x00, 0x01}; + + if(all) { + add_multicast_group(ALL_SYSTEMS_MCAST_MAC); + add_multicast_group(ALL_ROUTERS_MCAST_MAC); + } + else { + remove_multicast_group(ALL_SYSTEMS_MCAST_MAC); + remove_multicast_group(ALL_ROUTERS_MCAST_MAC); + } } void WHD_EMAC::power_down() @@ -122,11 +140,11 @@ bool WHD_EMAC::power_up() reserved_region_bd->init(); extern whd_resource_source_t cy_ext_wifi_fw_resource_ops; - res = cybsp_wifi_init_primary_extended(&ifp /* OUT */, &cy_ext_wifi_fw_resource_ops, NULL, NULL); + res = cybsp_wifi_init_primary_extended(&ifp /* OUT */, &cy_ext_wifi_fw_resource_ops, &buffer_funcs.value(), NULL); reserved_region_bd->deinit(); #else - res = cybsp_wifi_init_primary(&ifp /* OUT */); + res = cybsp_wifi_init_primary_extended(&ifp /* OUT */, nullptr, &buffer_funcs.value(), nullptr); #endif /* defined(CY_EXT_WIFI_FW_STORAGE) && !MBED_CONF_TARGET_XIP_ENABLE */ } else { ifp = emac_other.ifp; @@ -182,33 +200,34 @@ void WHD_EMAC::set_link_state_cb(emac_link_state_change_cb_t state_cb) void WHD_EMAC::set_memory_manager(EMACMemoryManager &mem_mngr) { + // Ignore if we are using the same memory manager already + if(&mem_mngr == memory_manager) { + return; + } + + MBED_ASSERT(!powered_up); memory_manager = &mem_mngr; + buffer_funcs.emplace(getMbedWHDBufferFuncs(mem_mngr)); } bool WHD_EMAC::link_out(emac_mem_buf_t *buf) { - uint16_t offset = 64; - whd_buffer_t buffer; + // Currently we always need to copy the buffer, because the driver needs both some header space before the buffer, + // and 64 bytes padding after the buffer. Currently there is no way to force the IP stack(s) to allocate + // extra space in this manner, so we can't implement 0-copy Tx. Note that LwIP does have + // PBUF_LINK_ENCAPSULATION_HLEN which does half of this but we are still missing the other half. - uint16_t size = memory_manager->get_total_len(buf); + buf = memory_manager->realloc_heap(buf, WHD_MEM_BUFFER_ALIGNMENT, memory_manager->get_total_len(buf) + WHD_MEM_BUFFER_EXTRA_SPACE, MBED_CONF_CY_PSOC6_WHD_TX_BUFFER_HEADER_SPACE); - whd_result_t res = whd_host_buffer_get(drvp, &buffer, WHD_NETWORK_TX, size + offset, WHD_TRUE); - if (res != WHD_SUCCESS) { - memory_manager->free(buf); - return true; + if(!buf) { + return false; } - MBED_ASSERT(res == WHD_SUCCESS); - - whd_buffer_add_remove_at_front(drvp, &buffer, offset); - - void *dest = whd_buffer_get_current_piece_data_pointer(drvp, buffer); - memory_manager->copy_from_buf(dest, size, buf); if (activity_cb) { activity_cb(true); } - whd_network_send_ethernet_data(ifp, buffer); - memory_manager->free(buf); + + whd_network_send_ethernet_data(ifp, buf); return true; } @@ -264,8 +283,6 @@ extern "C" void cy_network_process_ethernet_data(whd_interface_t ifp, whd_buffer_t buffer) { - emac_mem_buf_t *mem_buf = NULL; - WHD_EMAC &emac = WHD_EMAC::get_instance(ifp->role); if (!emac.powered_up || !emac.emac_link_input_cb) { @@ -274,16 +291,12 @@ extern "C" return; } - uint8_t *data = whd_buffer_get_current_piece_data_pointer(emac.drvp, buffer); - - uint16_t size = whd_buffer_get_current_piece_size(emac.drvp, buffer); - + uint8_t const * const data = whd_buffer_get_current_piece_data_pointer(emac.drvp, buffer); + uint16_t const size = whd_buffer_get_current_piece_size(emac.drvp, buffer); if (size > WHD_ETHERNET_SIZE) { - uint16_t ethertype; - - ethertype = (uint16_t)(data[12] << 8 | data[13]); + const uint16_t ethertype = (uint16_t)(data[12] << 8 | data[13]); if (ethertype == EAPOL_PACKET_TYPE) { @@ -291,11 +304,14 @@ extern "C" emac_receive_eapol_packet(ifp, buffer); } else { - mem_buf = buffer; if (emac.activity_cb) { emac.activity_cb(false); } - emac.emac_link_input_cb(mem_buf); + + // The WHD layer allocates buffers with extra size used in SDIO reads. Trim off this size now. + emac.memory_manager->set_len(buffer, size); + + emac.emac_link_input_cb(buffer); } } } diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/whd_emac.h b/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/whd_emac.h index d50486e61d4..e527d171f44 100644 --- a/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/whd_emac.h +++ b/connectivity/drivers/wifi/COMPONENT_WHD/whd_mac/interface/whd_emac.h @@ -22,6 +22,7 @@ #include "EMACInterface.h" #include "WiFiInterface.h" #include "whd_int.h" +#include #include "rtos/Semaphore.h" #include "rtos/Mutex.h" @@ -32,131 +33,36 @@ class WHD_EMAC : public EMAC { static WHD_EMAC &get_instance(whd_interface_role_t role = WHD_STA_ROLE, const uint8_t *mac_addr = NULL); - /** - * Return maximum transmission unit - * - * @return MTU in bytes - */ - virtual uint32_t get_mtu_size() const; - - /** - * Gets memory buffer alignment preference - * - * Gets preferred memory buffer alignment of the Emac device. IP stack may or may not - * align link out memory buffer chains using the alignment. - * - * @return Memory alignment requirement in bytes - */ - virtual uint32_t get_align_preference() const; - - /** - * Return interface name - * - * @param name Pointer to where the name should be written - * @param size Maximum number of character to copy - */ - virtual void get_ifname(char *name, uint8_t size) const; - - /** - * Returns size of the underlying interface HW address size. - * - * @return HW address size in bytes - */ - virtual uint8_t get_hwaddr_size() const; - - /** - * Return interface-supplied HW address - * - * Copies HW address to provided memory, @param addr has to be of correct size see @a get_hwaddr_size - * - * HW address need not be provided if this interface does not have its own HW - * address configuration; stack will choose address from central system - * configuration if the function returns false and does not write to addr. - * - * @param addr HW address for underlying interface - * @return true if HW address is available - */ - virtual bool get_hwaddr(uint8_t *addr) const; - - /** - * Set HW address for interface - * - * Provided address has to be of correct size, see @a get_hwaddr_size - * - * Called to set the MAC address to actually use - if @a get_hwaddr is provided - * the stack would normally use that, but it could be overridden, eg for test - * purposes. - * - * @param addr Address to be set - */ - virtual void set_hwaddr(const uint8_t *addr); - - /** - * Sends the packet over the link - * - * That can not be called from an interrupt context. - * - * @param buf Packet to be send - * @return True if the packet was send successfully, False otherwise - */ - virtual bool link_out(emac_mem_buf_t *buf); - - /** - * Initializes the HW - * - * @return True on success, False in case of an error. - */ - virtual bool power_up(); - - /** - * Deinitializes the HW - * - */ - virtual void power_down(); - - /** - * Sets a callback that needs to be called for packets received for that interface - * - * @param input_cb Function to be register as a callback - */ - virtual void set_link_input_cb(emac_link_input_cb_t input_cb); - - /** - * Sets a callback that needs to be called on link status changes for given interface - * - * @param state_cb Function to be register as a callback - */ - virtual void set_link_state_cb(emac_link_state_change_cb_t state_cb); - - /** Add device to a multicast group - * - * @param address A multicast group hardware address - */ - virtual void add_multicast_group(const uint8_t *address); - - /** Remove device from a multicast group - * - * @param address A multicast group hardware address - */ - virtual void remove_multicast_group(const uint8_t *address); - - /** Request reception of all multicast packets - * - * @param all True to receive all multicasts - * False to receive only multicasts addressed to specified groups - */ - virtual void set_all_multicast(bool all); - - /** Sets memory manager that is used to handle memory buffers - * - * @param mem_mngr Pointer to memory manager - */ - virtual void set_memory_manager(EMACMemoryManager &mem_mngr); - - /** Set callback to receive EMAC activity events - * - * @param activity_cb The callback for activity events - */ + uint32_t get_mtu_size() const override; + + uint32_t get_align_preference() const override; + + void get_ifname(char *name, uint8_t size) const override; + + uint8_t get_hwaddr_size() const override; + + bool get_hwaddr(uint8_t *addr) const override; + + void set_hwaddr(const uint8_t *addr) override; + + bool link_out(emac_mem_buf_t *buf) override; + + bool power_up() override; + + void power_down() override; + + void set_link_input_cb(emac_link_input_cb_t input_cb) override; + + void set_link_state_cb(emac_link_state_change_cb_t state_cb) override; + + void add_multicast_group(const uint8_t *address) override; + + void remove_multicast_group(const uint8_t *address) override; + + void set_all_multicast(bool all) override; + + void set_memory_manager(EMACMemoryManager &mem_mngr) override; + virtual void set_activity_cb(mbed::Callback activity_cb); emac_link_input_cb_t emac_link_input_cb = NULL; /**< Callback for incoming data */ @@ -168,6 +74,7 @@ class WHD_EMAC : public EMAC { whd_interface_role_t interface_type; whd_driver_t drvp = NULL; whd_interface_t ifp = NULL; + std::optional buffer_funcs; whd_mac_t unicast_addr; whd_mac_t multicast_addr; mbed::Callback activity_cb; diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/wifi-host-driver/inc/whd_network_types.h b/connectivity/drivers/wifi/COMPONENT_WHD/wifi-host-driver/inc/whd_network_types.h index e09a2f75c6c..df4dcfd13f0 100755 --- a/connectivity/drivers/wifi/COMPONENT_WHD/wifi-host-driver/inc/whd_network_types.h +++ b/connectivity/drivers/wifi/COMPONENT_WHD/wifi-host-driver/inc/whd_network_types.h @@ -55,6 +55,10 @@ typedef enum */ struct whd_buffer_funcs { + /// Opaque pointer which should be passed as the first argument to each function. + /// Allows passing an instance pointer for a C++ class. + void* instance; + /** Allocates a packet buffer * * Implemented in the port layer interface which is specific to the @@ -67,6 +71,7 @@ struct whd_buffer_funcs * which includes the MTU, other other various header. Refer to whd_types.h * to find the size of WHD_LINK_MTU * + * @param instance Instance pointer as defined above. * @param buffer A pointer which receives the allocated packet buffer handle * @param direction Indicates transmit/receive direction that the packet buffer is * used for. This may be needed if tx/rx pools are separate. @@ -76,7 +81,7 @@ struct whd_buffer_funcs * @return WHD_SUCCESS or error code * */ - whd_result_t (*whd_host_buffer_get)(whd_buffer_t *buffer, whd_buffer_dir_t direction, unsigned short size, + whd_result_t (*whd_host_buffer_get)(void* instance, whd_buffer_t *buffer, whd_buffer_dir_t direction, unsigned short size, unsigned long timeout_ms); /** Releases a packet buffer @@ -89,12 +94,13 @@ struct whd_buffer_funcs * how the packet was allocated. * Returns void since WHD cannot do anything about failures * + * @param instance Instance pointer as defined above. * @param buffer The handle of the packet buffer to be released * @param direction Indicates transmit/receive direction that the packet buffer has * been used for. This might be needed if tx/rx pools are separate. * */ - void (*whd_buffer_release)(whd_buffer_t buffer, whd_buffer_dir_t direction); + void (*whd_buffer_release)(void* instance, whd_buffer_t buffer, whd_buffer_dir_t direction); /** Retrieves the current pointer of a packet buffer * @@ -104,11 +110,12 @@ struct whd_buffer_funcs * front for additional headers, this function allows WHD to get * the current 'front' location pointer. * + * @param instance Instance pointer as defined above. * @param buffer The handle of the packet buffer whose pointer is to be retrieved * * @return The packet buffer's current pointer. */ - uint8_t *(*whd_buffer_get_current_piece_data_pointer)(whd_buffer_t buffer); + uint8_t *(*whd_buffer_get_current_piece_data_pointer)(void* instance, whd_buffer_t buffer); /** Retrieves the size of a packet buffer * @@ -119,11 +126,12 @@ struct whd_buffer_funcs * will often be larger than the current size of the packet buffer data. * This function allows WHD to retrieve the current size of a packet buffer's data. * + * @param instance Instance pointer as defined above. * @param buffer The handle of the packet buffer whose size is to be retrieved * * @return The size of the packet buffer. */ - uint16_t (*whd_buffer_get_current_piece_size)(whd_buffer_t buffer); + uint16_t (*whd_buffer_get_current_piece_size)(void* instance, whd_buffer_t buffer); /** Sets the current size of a WHD packet * @@ -131,12 +139,13 @@ struct whd_buffer_funcs * buffering scheme in use. * This function sets the current length of a WHD packet buffer * + * @param instance Instance pointer as defined above. * @param buffer The packet to be modified * @param size The new size of the packet buffer * * @return WHD_SUCCESS or error code */ - whd_result_t (*whd_buffer_set_size)(whd_buffer_t buffer, unsigned short size); + whd_result_t (*whd_buffer_set_size)(void* instance, whd_buffer_t buffer, unsigned short size); /** Moves the current pointer of a packet buffer * @@ -147,6 +156,7 @@ struct whd_buffer_funcs * add headers to transmit packets, and so that the network stack does not see the internal WHD * headers on received packets. * + * @param instance Instance pointer as defined above. * @param buffer A pointer to the handle of the current packet buffer for which the * current pointer will be moved. On return this may contain a pointer * to a newly allocated packet buffer which has been daisy chained to @@ -158,7 +168,7 @@ struct whd_buffer_funcs * * @return WHD_SUCCESS or error code */ - whd_result_t (*whd_buffer_add_remove_at_front)(whd_buffer_t *buffer, int32_t add_remove_amount); + whd_result_t (*whd_buffer_add_remove_at_front)(void* instance, whd_buffer_t *buffer, int32_t add_remove_amount); }; /* @} */ @@ -202,6 +212,9 @@ struct whd_netif_funcs void (*whd_network_process_ethernet_data)(whd_interface_t ifp, whd_buffer_t buffer); }; +// Default global version of above function +void cy_network_process_ethernet_data(whd_interface_t interface, whd_buffer_t buffer); + /** To send an ethernet frame to WHD (called by the Network Stack) * * This function takes ethernet data from the network stack and queues it for transmission over the wireless network. diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/wifi-host-driver/src/bus_protocols/whd_bus_sdio_protocol.c b/connectivity/drivers/wifi/COMPONENT_WHD/wifi-host-driver/src/bus_protocols/whd_bus_sdio_protocol.c index 5944bf6e7ab..1ddfef3c772 100755 --- a/connectivity/drivers/wifi/COMPONENT_WHD/wifi-host-driver/src/bus_protocols/whd_bus_sdio_protocol.c +++ b/connectivity/drivers/wifi/COMPONENT_WHD/wifi-host-driver/src/bus_protocols/whd_bus_sdio_protocol.c @@ -699,6 +699,7 @@ whd_result_t whd_bus_sdio_read_frame(whd_driver_t whd_driver, whd_buffer_t *buff return WHD_SDIO_RX_FAIL; } } + whd_buffer_get_current_piece_data_pointer(whd_driver, *buffer); DELAYED_BUS_RELEASE_SCHEDULE(whd_driver, WHD_TRUE); return WHD_SUCCESS; } diff --git a/connectivity/drivers/wifi/COMPONENT_WHD/wifi-host-driver/src/whd_buffer_api.c b/connectivity/drivers/wifi/COMPONENT_WHD/wifi-host-driver/src/whd_buffer_api.c index 1c66b49c8f7..7c04708dbe2 100755 --- a/connectivity/drivers/wifi/COMPONENT_WHD/wifi-host-driver/src/whd_buffer_api.c +++ b/connectivity/drivers/wifi/COMPONENT_WHD/wifi-host-driver/src/whd_buffer_api.c @@ -65,7 +65,7 @@ whd_result_t whd_host_buffer_get(whd_driver_t whd_driver, whd_buffer_t *buffer, { if (whd_driver->buffer_if->whd_host_buffer_get) { - return whd_driver->buffer_if->whd_host_buffer_get(buffer, direction, size, timeout_ms); + return whd_driver->buffer_if->whd_host_buffer_get(whd_driver->buffer_if->instance, buffer, direction, size, timeout_ms); } else { @@ -94,7 +94,7 @@ whd_result_t whd_buffer_release(whd_driver_t whd_driver, whd_buffer_t buffer, wh { if (whd_driver->buffer_if->whd_buffer_release) { - whd_driver->buffer_if->whd_buffer_release(buffer, direction); + whd_driver->buffer_if->whd_buffer_release(whd_driver->buffer_if->instance, buffer, direction); return WHD_SUCCESS; } else @@ -121,7 +121,7 @@ uint8_t *whd_buffer_get_current_piece_data_pointer(whd_driver_t whd_driver, whd_ { if (whd_driver->buffer_if->whd_buffer_get_current_piece_data_pointer) { - return whd_driver->buffer_if->whd_buffer_get_current_piece_data_pointer(buffer); + return whd_driver->buffer_if->whd_buffer_get_current_piece_data_pointer(whd_driver->buffer_if->instance, buffer); } else { @@ -148,7 +148,7 @@ uint16_t whd_buffer_get_current_piece_size(whd_driver_t whd_driver, whd_buffer_t { if (whd_driver->buffer_if->whd_buffer_get_current_piece_size) { - return whd_driver->buffer_if->whd_buffer_get_current_piece_size(buffer); + return whd_driver->buffer_if->whd_buffer_get_current_piece_size(whd_driver->buffer_if->instance, buffer); } else { @@ -174,7 +174,7 @@ whd_result_t whd_buffer_set_size(whd_driver_t whd_driver, whd_buffer_t buffer, u { if (whd_driver->buffer_if->whd_buffer_set_size) { - return whd_driver->buffer_if->whd_buffer_set_size(buffer, size); + return whd_driver->buffer_if->whd_buffer_set_size(whd_driver->buffer_if->instance, buffer, size); } else { @@ -208,7 +208,7 @@ whd_result_t whd_buffer_add_remove_at_front(whd_driver_t whd_driver, whd_buffer_ { if (whd_driver->buffer_if->whd_buffer_add_remove_at_front) { - return whd_driver->buffer_if->whd_buffer_add_remove_at_front(buffer, add_remove_amount); + return whd_driver->buffer_if->whd_buffer_add_remove_at_front(whd_driver->buffer_if->instance, buffer, add_remove_amount); } else { diff --git a/connectivity/lwipstack/include/lwipstack/LWIPMemoryManager.h b/connectivity/lwipstack/include/lwipstack/LWIPMemoryManager.h index 5e38a4320b9..0152a970f9a 100644 --- a/connectivity/lwipstack/include/lwipstack/LWIPMemoryManager.h +++ b/connectivity/lwipstack/include/lwipstack/LWIPMemoryManager.h @@ -35,8 +35,6 @@ class LWIPMemoryManager final : public EMACMemoryManager { uint32_t get_total_len(const net_stack_mem_buf_t *buf) const override; - void copy(net_stack_mem_buf_t *to_buf, const net_stack_mem_buf_t *from_buf) override; - void copy_to_buf(net_stack_mem_buf_t *to_buf, const void *ptr, uint32_t len) override; uint32_t copy_from_buf(void *ptr, uint32_t len, const net_stack_mem_buf_t *from_buf) const override; @@ -53,6 +51,10 @@ class LWIPMemoryManager final : public EMACMemoryManager { Lifetime get_lifetime(const net_stack_mem_buf_t *buf) const override; + void skip_header_space(net_stack_mem_buf_t *buf, int32_t amount) override; + + int32_t get_header_skip_size(net_stack_mem_buf_t *buf) override; + private: // Allow callback to access private vars diff --git a/connectivity/lwipstack/include/lwipstack/LWIPStack.h b/connectivity/lwipstack/include/lwipstack/LWIPStack.h index b5cb88e248c..5a0b92a0423 100644 --- a/connectivity/lwipstack/include/lwipstack/LWIPStack.h +++ b/connectivity/lwipstack/include/lwipstack/LWIPStack.h @@ -345,7 +345,7 @@ class LWIP : public OnboardNetworkStack, private mbed::NonCopyable { void set_default_interface(OnboardNetworkStack::Interface *interface) override; /// Get the memory manager for the LwIP stack - LWIPMemoryManager &get_memory_manager() + LWIPMemoryManager &get_memory_manager() override { return memory_manager; } @@ -591,6 +591,7 @@ class LWIP : public OnboardNetworkStack, private mbed::NonCopyable { */ nsapi_error_t getsockopt(nsapi_socket_t handle, int level, int optname, void *optval, unsigned *optlen) override; + private: /** Call in callback diff --git a/connectivity/lwipstack/lwip/src/core/lwip_pbuf.c b/connectivity/lwipstack/lwip/src/core/lwip_pbuf.c index 1123041891b..dd258bb1ed5 100644 --- a/connectivity/lwipstack/lwip/src/core/lwip_pbuf.c +++ b/connectivity/lwipstack/lwip/src/core/lwip_pbuf.c @@ -176,7 +176,7 @@ pbuf_pool_is_empty(void) /* Initialize members of struct pbuf after allocation */ static void -pbuf_init_alloced_pbuf(struct pbuf *p, void *payload, u16_t tot_len, u16_t len, pbuf_type type, u8_t flags) +pbuf_init_alloced_pbuf(struct pbuf *p, void *payload, u16_t initial_header_bytes, u16_t tot_len, u16_t len, pbuf_type type, u8_t flags) { p->next = NULL; p->payload = payload; @@ -186,6 +186,7 @@ pbuf_init_alloced_pbuf(struct pbuf *p, void *payload, u16_t tot_len, u16_t len, p->flags = flags; p->ref = 1; p->if_idx = NETIF_NO_INDEX; + p->header_bytes_removed = initial_header_bytes; } /** @@ -251,7 +252,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) return NULL; } qlen = LWIP_MIN(rem_len, (u16_t)(PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset))); - pbuf_init_alloced_pbuf(q, LWIP_MEM_ALIGN((void *)((u8_t *)q + SIZEOF_STRUCT_PBUF + offset)), + pbuf_init_alloced_pbuf(q, LWIP_MEM_ALIGN((void *)((u8_t *)q + SIZEOF_STRUCT_PBUF + offset)), offset, rem_len, qlen, type, 0); LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); @@ -285,7 +286,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) if (p == NULL) { return NULL; } - pbuf_init_alloced_pbuf(p, LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)), + pbuf_init_alloced_pbuf(p, LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)), offset, length, length, type, 0); LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); @@ -336,7 +337,7 @@ pbuf_alloc_reference(void *payload, u16_t length, pbuf_type type) (type == PBUF_ROM) ? "ROM" : "REF")); return NULL; } - pbuf_init_alloced_pbuf(p, payload, length, length, type, 0); + pbuf_init_alloced_pbuf(p, payload, 0, length, length, type, 0); return p; } @@ -377,7 +378,7 @@ pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_cust } else { payload = NULL; } - pbuf_init_alloced_pbuf(&p->pbuf, payload, length, length, type, PBUF_FLAG_IS_CUSTOM); + pbuf_init_alloced_pbuf(&p->pbuf, payload, 0, length, length, type, PBUF_FLAG_IS_CUSTOM); return &p->pbuf; } #endif /* LWIP_SUPPORT_CUSTOM_PBUF */ @@ -522,7 +523,7 @@ pbuf_add_header_impl(struct pbuf *p, size_t header_size_increment, u8_t force) p->payload = payload; p->len = (u16_t)(p->len + increment_magnitude); p->tot_len = (u16_t)(p->tot_len + increment_magnitude); - + p->header_bytes_removed -= header_size_increment; return 0; } @@ -605,6 +606,7 @@ pbuf_remove_header(struct pbuf *p, size_t header_size_decrement) /* modify pbuf length fields */ p->len = (u16_t)(p->len - increment_magnitude); p->tot_len = (u16_t)(p->tot_len - increment_magnitude); + p->header_bytes_removed += increment_magnitude; LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_remove_header: old %p new %p (%"U16_F")\n", (void *)payload, (void *)p->payload, increment_magnitude)); diff --git a/connectivity/lwipstack/lwip/src/include/lwip/pbuf.h b/connectivity/lwipstack/lwip/src/include/lwip/pbuf.h index 82902a4e981..fd3477d9c64 100644 --- a/connectivity/lwipstack/lwip/src/include/lwip/pbuf.h +++ b/connectivity/lwipstack/lwip/src/include/lwip/pbuf.h @@ -202,6 +202,12 @@ struct pbuf { /** length of this buffer */ u16_t len; + /** + * Current number of header bytes that have been removed (skipped) from the start of the buffer. + * Added by Mbed to implement memory manager functionality. + */ + u16_t header_bytes_removed; + /** a bit field indicating pbuf type and allocation sources (see PBUF_TYPE_FLAG_*, PBUF_ALLOC_FLAG_* and PBUF_TYPE_ALLOC_SRC_MASK) */ diff --git a/connectivity/lwipstack/source/LWIPInterface.cpp b/connectivity/lwipstack/source/LWIPInterface.cpp index 35b4cfeb48a..1d8dfea5680 100644 --- a/connectivity/lwipstack/source/LWIPInterface.cpp +++ b/connectivity/lwipstack/source/LWIPInterface.cpp @@ -442,9 +442,11 @@ nsapi_error_t LWIP::add_ethernet_interface(EMAC &emac, bool default_if, OnboardN interface->memory_manager = &memory_manager; interface->ppp_enabled = false; - hostname = user_network_interface->get_hostname(); - if (hostname) { - netif_set_hostname(&interface->netif, hostname); + if (user_network_interface != nullptr) { + hostname = user_network_interface->get_hostname(); + if (hostname) { + netif_set_hostname(&interface->netif, hostname); + } } #if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE) diff --git a/connectivity/lwipstack/source/LWIPMemoryManager.cpp b/connectivity/lwipstack/source/LWIPMemoryManager.cpp index 054b84b4d21..2c2fa38d4da 100644 --- a/connectivity/lwipstack/source/LWIPMemoryManager.cpp +++ b/connectivity/lwipstack/source/LWIPMemoryManager.cpp @@ -61,11 +61,6 @@ uint32_t LWIPMemoryManager::get_total_len(const net_stack_mem_buf_t *buf) const return (static_cast(buf))->tot_len; } -void LWIPMemoryManager::copy(net_stack_mem_buf_t *to_buf, const net_stack_mem_buf_t *from_buf) -{ - pbuf_copy(static_cast(to_buf), static_cast(from_buf)); -} - void LWIPMemoryManager::copy_to_buf(net_stack_mem_buf_t *to_buf, const void *ptr, uint32_t len) { pbuf_take(static_cast(to_buf), ptr, len); @@ -124,6 +119,16 @@ NetStackMemoryManager::Lifetime LWIPMemoryManager::get_lifetime(const net_stack_ } } +void LWIPMemoryManager::skip_header_space(net_stack_mem_buf_t *const buf, const int32_t amount) +{ + MBED_ASSERT(pbuf_header(static_cast(buf), -amount) == 0); +} + +int32_t LWIPMemoryManager::get_header_skip_size(net_stack_mem_buf_t *buf) +{ + return static_cast(buf)->header_bytes_removed; +} + uint32_t LWIPMemoryManager::count_total_align(uint32_t size, uint32_t align) { uint32_t buffers = size / get_pool_alloc_unit(align); diff --git a/connectivity/nanostack/include/nanostack-interface/Nanostack.h b/connectivity/nanostack/include/nanostack-interface/Nanostack.h index f0cb31dbd1d..660f208d34d 100644 --- a/connectivity/nanostack/include/nanostack-interface/Nanostack.h +++ b/connectivity/nanostack/include/nanostack-interface/Nanostack.h @@ -54,7 +54,7 @@ class Nanostack : public OnboardNetworkStack, private mbed::NonCopyablenext = NULL; buf->payload = buf->mem; buf->len = size; + buf->header_size = 0; if (align) { uint32_t remainder = reinterpret_cast(buf->payload) % align; @@ -47,7 +49,7 @@ emac_mem_buf_t *NanostackMemoryManager::alloc_heap(uint32_t size, uint32_t align offset = align; } - buf->payload = static_cast(buf->payload) + offset; + buf->payload = buf->payload + offset; } } @@ -76,38 +78,11 @@ uint32_t NanostackMemoryManager::get_total_len(const emac_mem_buf_t *buf) const uint32_t total = 0; while (mem) { - total += mem->len; + total += mem->len - mem->header_size; // note: header size can only legally be set on the first buffer mem = mem->next; } - return total; -} -void NanostackMemoryManager::copy(emac_mem_buf_t *to, const emac_mem_buf_t *from) -{ - ns_stack_mem_t *to_mem = static_cast(to); - const ns_stack_mem_t *from_mem = static_cast(from); - MBED_ASSERT(get_total_len(to) >= get_total_len(from)); - - uint32_t to_offset = 0; - uint32_t from_offset = 0; - while (from_mem) { - uint32_t to_avail = to_mem->len - to_offset; - uint32_t from_avail = from_mem->len - from_offset; - uint32_t chunk = to_avail < from_avail ? to_avail : from_avail; - uint8_t *to_ptr = static_cast(to_mem->payload) + to_offset; - const uint8_t *from_ptr = static_cast(from_mem->payload) + from_offset; - memcpy(to_ptr, from_ptr, chunk); - to_offset += chunk; - if (to_offset == to_mem->len) { - to_mem = to_mem->next; - to_offset = 0; - } - from_offset += chunk; - if (from_offset == from_mem->len) { - from_mem = from_mem->next; - from_offset = 0; - } - } + return total; } void NanostackMemoryManager::cat(emac_mem_buf_t *to_buf, emac_mem_buf_t *cat_buf) @@ -115,6 +90,8 @@ void NanostackMemoryManager::cat(emac_mem_buf_t *to_buf, emac_mem_buf_t *cat_buf ns_stack_mem_t *to_mem = static_cast(to_buf); ns_stack_mem_t *cat_mem = static_cast(cat_buf); + MBED_ASSERT(cat_mem->header_size == 0); + while (to_mem->next) { to_mem = to_mem->next; } @@ -129,19 +106,20 @@ emac_mem_buf_t *NanostackMemoryManager::get_next(const emac_mem_buf_t *buf) cons void *NanostackMemoryManager::get_ptr(const emac_mem_buf_t *buf) const { - return static_cast(buf)->payload; + auto mem = static_cast(buf); + return mem->payload + mem->header_size; } uint32_t NanostackMemoryManager::get_len(const emac_mem_buf_t *buf) const { - return static_cast(buf)->len; + auto mem = static_cast(buf); + return mem->len - mem->header_size; } void NanostackMemoryManager::set_len(emac_mem_buf_t *buf, uint32_t len) { - ns_stack_mem_t *mem = static_cast(buf); - - mem->len = len; + auto *mem = static_cast(buf); + mem->len = len + mem->header_size; } NetStackMemoryManager::Lifetime NanostackMemoryManager::get_lifetime(const net_stack_mem_buf_t *buf) const @@ -151,6 +129,24 @@ NetStackMemoryManager::Lifetime NanostackMemoryManager::get_lifetime(const net_s return Lifetime::HEAP_ALLOCATED; } +void NanostackMemoryManager::skip_header_space(net_stack_mem_buf_t *buf, int32_t amount) +{ + auto *const mem = static_cast(buf); + + if (amount > 0) { + MBED_ASSERT(amount + static_cast(mem->header_size) < static_cast(mem->len)); // header_size cannot exceed len + } else { + MBED_ASSERT(-1 * amount <= static_cast(mem->header_size)); // header_size cannot go below 0 + } + + mem->header_size += amount; +} + +int32_t NanostackMemoryManager::get_header_skip_size(net_stack_mem_buf_t *buf) +{ + return static_cast(buf)->header_size; +} + void mbed_ns_heap_free_hook() { auto &callback = Nanostack::get_instance().get_memory_manager().onPoolSpaceAvailCallback; diff --git a/connectivity/nanostack/mbed-mesh-api/source/include/NanostackMemoryManager.h b/connectivity/nanostack/mbed-mesh-api/source/include/NanostackMemoryManager.h index 1589e166f3e..17a8a3ad9bd 100644 --- a/connectivity/nanostack/mbed-mesh-api/source/include/NanostackMemoryManager.h +++ b/connectivity/nanostack/mbed-mesh-api/source/include/NanostackMemoryManager.h @@ -39,8 +39,6 @@ class NanostackMemoryManager final : public EMACMemoryManager { uint32_t get_total_len(const emac_mem_buf_t *buf) const override; - void copy(emac_mem_buf_t *to_buf, const emac_mem_buf_t *from_buf) override; - void cat(emac_mem_buf_t *to_buf, emac_mem_buf_t *cat_buf) override; emac_mem_buf_t *get_next(const emac_mem_buf_t *buf) const override; @@ -52,6 +50,10 @@ class NanostackMemoryManager final : public EMACMemoryManager { void set_len(emac_mem_buf_t *buf, uint32_t len) override; Lifetime get_lifetime(const net_stack_mem_buf_t *buf) const override; + + void skip_header_space(net_stack_mem_buf_t *buf, int32_t amount) override; + + int32_t get_header_skip_size(net_stack_mem_buf_t *buf) override; }; #endif /* NANOSTACK_MEMORY_MANAGER_H */ diff --git a/connectivity/netsocket/include/netsocket/EMAC.h b/connectivity/netsocket/include/netsocket/EMAC.h index 4bd384aa320..cc2477c3e32 100644 --- a/connectivity/netsocket/include/netsocket/EMAC.h +++ b/connectivity/netsocket/include/netsocket/EMAC.h @@ -49,7 +49,10 @@ class EMAC { typedef mbed::Callback emac_link_input_cb_t; /** - * Callback to be register with EMAC interface and to be called for link status changes + * Callback to be registered with EMAC interface and to be called for link status changes. + * + * Note that duplicate callbacks (i.e. this being called twice when the network comes up) + * are possible in some cases. * *
* \c up : Link status diff --git a/connectivity/netsocket/include/netsocket/EthernetInterface.h b/connectivity/netsocket/include/netsocket/EthernetInterface.h index b0583187a8b..d35463beeb9 100644 --- a/connectivity/netsocket/include/netsocket/EthernetInterface.h +++ b/connectivity/netsocket/include/netsocket/EthernetInterface.h @@ -22,7 +22,7 @@ #include "EMACInterface.h" -/** Implementation of the NetworkStack for an EMAC-based Ethernet driver. +/** Implementation of NetworkInterface for an EMAC-based Ethernet driver. */ class EthernetInterface : public EMACInterface, public EthInterface { public: diff --git a/connectivity/netsocket/include/netsocket/NetStackMemoryManager.h b/connectivity/netsocket/include/netsocket/NetStackMemoryManager.h index cc04f15976e..3f904ef35fb 100644 --- a/connectivity/netsocket/include/netsocket/NetStackMemoryManager.h +++ b/connectivity/netsocket/include/netsocket/NetStackMemoryManager.h @@ -18,6 +18,8 @@ #ifndef NET_STACK_MEMORY_MANAGER_H #define NET_STACK_MEMORY_MANAGER_H +#include + /** * Network Stack interface memory manager * @@ -47,7 +49,8 @@ #include "nsapi.h" #include "Callback.h" -typedef void net_stack_mem_buf_t; // Memory buffer +// Opaque struct representing a memory buffer or a chain of memory buffers. +typedef void net_stack_mem_buf_t; class NetStackMemoryManager { protected: @@ -87,6 +90,21 @@ class NetStackMemoryManager { */ virtual net_stack_mem_buf_t *alloc_pool(uint32_t size, uint32_t align) = 0; + /** + * @brief Reallocates a buffer or buffer chain as a contiguous (non-chained) heap buffer, freeing the original. + * + * Only the visible data in the source buffer is copied, not any skipped headers. Data from chained + * buffers *will* be copied. + * + * @param orig_buf Original buffer. Will be freed whether or not the new buffer is allocated. + * @param new_align Alignment to allocate the new buffer with + * @param new_len If set, this length will be used instead of the buffer's original length + * @param new_header_skip_size If set, this header skip size will be set on the new buffer. If unset, no header skip will be set + * + * @return Pointer to new buffer, or nullptr if allocation failed. + */ + net_stack_mem_buf_t *realloc_heap(net_stack_mem_buf_t *orig_buf, uint32_t new_align, std::optional new_len = std::nullopt, std::optional new_header_skip_size = std::nullopt); + /** * Get memory buffer pool allocation unit * @@ -131,18 +149,7 @@ class NetStackMemoryManager { virtual uint32_t get_total_len(const net_stack_mem_buf_t *buf) const = 0; /** - * Copy a memory buffer chain - * - * Copies data from one buffer chain to another. Copy operation does not adjust the lengths - * of the copied-to memory buffer chain, so chain total lengths must be the same. - * - * @param to_buf Memory buffer chain to copy to - * @param from_buf Memory buffer chain to copy from - */ - virtual void copy(net_stack_mem_buf_t *to_buf, const net_stack_mem_buf_t *from_buf) = 0; - - /** - * Copy to a memory buffer chain + * @brief Copy from a raw buffer in memory to a memory buffer chain * * Copies data to a buffer chain. Copy operation does not adjust the lengths * of the copied-to memory buffer chain, so chain total length must match the @@ -155,9 +162,10 @@ class NetStackMemoryManager { virtual void copy_to_buf(net_stack_mem_buf_t *to_buf, const void *ptr, uint32_t len); /** - * Copy from a memory buffer chain + * @brief Copy from a memory buffer chain to a raw buffer in memory. * - * Copies data from a memory buffer chain. + * Header skip bytes are processed, so the copy will begin AFTER the header bytes of + * \c from_buf * * @param len Data length * @param ptr Pointer to data @@ -173,6 +181,8 @@ class NetStackMemoryManager { * is adjusted accordingly. cat_buf must point to the start of a the chain. After concatenation * to_buf's chain now owns those buffers, and they will be freed when the to_buf chain is freed. * + * @warning It is forbidden for \c cat_buf to have skipped header bytes. + * * @param to_buf Memory buffer chain to concatenate to * @param cat_buf Memory buffer chain to concatenate */ @@ -207,6 +217,8 @@ class NetStackMemoryManager { /** * Return pointer to the payload of the buffer * + * Note that this is affected by the current header skip size (see below) + * * @param buf Memory buffer * @return Pointer to the payload */ @@ -215,6 +227,8 @@ class NetStackMemoryManager { /** * Return payload size of this individual buffer (NOT including any chained buffers) * + * Note that this is affected by the current header skip size (see below) + * * @param buf Memory buffer * @return Size in bytes */ @@ -226,6 +240,8 @@ class NetStackMemoryManager { * The allocated payload size will not change. It is not permitted * to change the length of a buffer that is not the first (or only) in a chain. * + * Note that this is affected by the current header skip size (see below) + * * *Note as of Dec 2024: Different implementations (Nanostack vs LwIP) disagree about * how to implement this operation. Specifically, if called on the head of a buffer * chain, the LwIP implementation allows changing the length of the chain as a whole. @@ -239,6 +255,51 @@ class NetStackMemoryManager { */ virtual void set_len(net_stack_mem_buf_t *buf, uint32_t len) = 0; + /** + * @brief Skips (or un-skips) header space from the buffer. + * + * Skipping n bytes of header space causes the buffer's payload pointer to refer to a location n bytes after + * the base address of the packet buffer, and the length of the buffer to be decreased by n. + * + * This is commonly used to skip protocol headers in network + * packets. For example, if you have an Ethernet frame, skipping 14 bytes of header space will cause + * the "start" of the packet buffer to point to the IP header instead. + * + * Multiple calls to this function add together, so for example if you first skip 14 bytes, then -4, then + * 10, the result will be 20 total bytes of skipped header. + * + * @param buf Buffer to operate on. + * @param amount Amount of header space to skip. Negative values are allowed and cause + * previously skipped header space to be removed. + * + * @warning Skipping a larger total header space than the size of the first buffer in the chain, or skipping a negative + * total header space, results in undefined behavior. + */ + virtual void skip_header_space(net_stack_mem_buf_t *buf, int32_t amount) = 0; + + /** + * @brief Restores previously skipped header space to the buffer. + * + * This function is the inverse of \c skip_header_space(). + * + * @param buf Buffer to operate on. + * @param amount Amount of header space to skip. Negative values are allowed and cause + * previously skipped header space to be removed. + */ + inline void restore_header_space(net_stack_mem_buf_t *buf, const int32_t amount) + { + skip_header_space(buf, -1 * amount); + } + + /** + * @brief Get the total number of header bytes that are currently being skipped. + * + * This is the aggregate result of all \c skip_header_space() / \c restore_header_space() calls. + * + * @param buf Buffer to operate on. + */ + virtual int32_t get_header_skip_size(net_stack_mem_buf_t *buf) = 0; + enum class Lifetime { POOL_ALLOCATED, ///< Allocated from the memory manager's pool HEAP_ALLOCATED, ///< Allocated from the memory manager's heap diff --git a/connectivity/netsocket/include/netsocket/OnboardNetworkStack.h b/connectivity/netsocket/include/netsocket/OnboardNetworkStack.h index e42ab31a6e7..7148f1773f3 100644 --- a/connectivity/netsocket/include/netsocket/OnboardNetworkStack.h +++ b/connectivity/netsocket/include/netsocket/OnboardNetworkStack.h @@ -171,6 +171,11 @@ class OnboardNetworkStack : public NetworkStack { */ virtual nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, Interface **interface_out, NetworkInterface *user_network_interface = NULL) = 0; + /** + * @brief Get a reference to the memory manager used by this stack. + */ + virtual EMACMemoryManager &get_memory_manager() = 0; + virtual nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, Interface **interface_out, const uint8_t *mac_addr, NetworkInterface *user_network_interface = NULL) { diff --git a/connectivity/netsocket/source/NetStackMemoryManager.cpp b/connectivity/netsocket/source/NetStackMemoryManager.cpp index 08470b7d7ea..f7537f28040 100644 --- a/connectivity/netsocket/source/NetStackMemoryManager.cpp +++ b/connectivity/netsocket/source/NetStackMemoryManager.cpp @@ -17,6 +17,32 @@ #include "NetStackMemoryManager.h" +net_stack_mem_buf_t *NetStackMemoryManager::realloc_heap(net_stack_mem_buf_t *orig_buf, uint32_t new_align, std::optional new_len, std::optional new_header_skip_size) +{ + + const uint32_t orig_buf_len = get_total_len(orig_buf); + const uint32_t new_total_len = new_len.value_or(orig_buf_len) + new_header_skip_size.value_or(0); + auto *new_buf = alloc_heap(new_total_len, new_align); + + if (!new_buf) { + free(orig_buf); + return nullptr; + } + + if (new_header_skip_size.has_value()) { + skip_header_space(new_buf, *new_header_skip_size); + } + + // We should have gotten just one contiguous buffer + MBED_ASSERT(get_next(new_buf) == nullptr); + + // Copy data over + const uint32_t len_to_copy = std::min(new_len.value_or(orig_buf_len), orig_buf_len); + copy_from_buf(get_ptr(new_buf), len_to_copy, orig_buf); + free(orig_buf); + return new_buf; +} + void NetStackMemoryManager::copy_to_buf(net_stack_mem_buf_t *to_buf, const void *ptr, uint32_t len) { while (to_buf && len) { diff --git a/connectivity/netsocket/tests/TESTS/netsocket/tls/cert.h b/connectivity/netsocket/tests/TESTS/netsocket/tls/cert.h index f3b62ac720f..5bbcaedbdef 100644 --- a/connectivity/netsocket/tests/TESTS/netsocket/tls/cert.h +++ b/connectivity/netsocket/tests/TESTS/netsocket/tls/cert.h @@ -25,30 +25,35 @@ // using these instructions: https://os.mbed.com/docs/mbed-os/v5.15/tutorials/tls-tutorial.html const char *tls_global::cert = "-----BEGIN CERTIFICATE-----\n" - "MIIEVzCCAj+gAwIBAgIRALBXPpFzlydw27SHyzpFKzgwDQYJKoZIhvcNAQELBQAw\n" + "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" "TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" - "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw\n" - "WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg\n" - "RW5jcnlwdDELMAkGA1UEAxMCRTYwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATZ8Z5G\n" - "h/ghcWCoJuuj+rnq2h25EqfUJtlRFLFhfHWWvyILOR/VvtEKRqotPEoJhC6+QJVV\n" - "6RlAN2Z17TJOdwRJ+HB7wxjnzvdxEP6sdNgA1O1tHHMWMxCcOrLqbGL0vbijgfgw\n" - "gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD\n" - "ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSTJ0aYA6lRaI6Y1sRCSNsj\n" - "v1iU0jAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB\n" - "AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g\n" - "BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu\n" - "Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAfYt7SiA1sgWGCIpunk46r4AExIRc\n" - "MxkKgUhNlrrv1B21hOaXN/5miE+LOTbrcmU/M9yvC6MVY730GNFoL8IhJ8j8vrOL\n" - "pMY22OP6baS1k9YMrtDTlwJHoGby04ThTUeBDksS9RiuHvicZqBedQdIF65pZuhp\n" - "eDcGBcLiYasQr/EO5gxxtLyTmgsHSOVSBcFOn9lgv7LECPq9i7mfH3mpxgrRKSxH\n" - "pOoZ0KXMcB+hHuvlklHntvcI0mMMQ0mhYj6qtMFStkF1RpCG3IPdIwpVCQqu8GV7\n" - "s8ubknRzs+3C/Bm19RFOoiPpDkwvyNfvmQ14XkyqqKK5oZ8zhD32kFRQkxa8uZSu\n" - "h4aTImFxknu39waBxIRXE4jKxlAmQc4QjFZoq1KmQqQg0J/1JF8RlFvJas1VcjLv\n" - "YlvUB2t6npO6oQjB3l+PNf0DpQH7iUx3Wz5AjQCi6L25FjyE06q6BZ/QlmtYdl/8\n" - "ZYao4SRqPEs/6cAiF+Qf5zg2UkaWtDphl1LKMuTNLotvsX99HP69V2faNyegodQ0\n" - "LyTApr/vT01YPE46vNsDLgK+4cL6TrzC/a4WcmF5SRJ938zrv/duJHLXQIku5v0+\n" - "EwOy59Hdm0PT/Er/84dDV0CSjdR/2XuZM3kpysSKLgD1cKiDA+IRguODCxfO9cyY\n" - "Ig46v9mFmBvyH04=\n" - "-----END CERTIFICATE-----\n"; + "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n" + "WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n" + "ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n" + "MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n" + "h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n" + "0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n" + "A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n" + "T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n" + "B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n" + "B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n" + "KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n" + "OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n" + "jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n" + "qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n" + "rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" + "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n" + "hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n" + "ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n" + "3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n" + "NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n" + "ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n" + "TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n" + "jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n" + "oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n" + "4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n" + "mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n" + "emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n" + "-----END CERTIFICATE-----"; #endif //#if defined(MBED_CONF_APP_ECHO_SERVER_USE_CUSTOM_CERT) && MBED_CONF_APP_ECHO_SERVER_USE_CUSTOM_CERT diff --git a/connectivity/netsocket/tests/TESTS/netsocket/udp/udpsocket_recv_timeout.cpp b/connectivity/netsocket/tests/TESTS/netsocket/udp/udpsocket_recv_timeout.cpp index f130c2bf1bf..c56283e4669 100644 --- a/connectivity/netsocket/tests/TESTS/netsocket/udp/udpsocket_recv_timeout.cpp +++ b/connectivity/netsocket/tests/TESTS/netsocket/udp/udpsocket_recv_timeout.cpp @@ -63,7 +63,7 @@ void UDPSOCKET_RECV_TIMEOUT() if (recvd == NSAPI_ERROR_WOULD_BLOCK) { osSignalWait(SIGNAL_SIGIO, SIGIO_TIMEOUT); - tr_info("MBED: recvfrom() took: %dms", timer.read_ms()); + tr_info("MBED: recvfrom() took: %" PRIi64 "ms", std::chrono::duration_cast(timer.elapsed_time()).count()); if (timer.elapsed_time() > 150ms) { TEST_ASSERT(150ms - timer.elapsed_time() < 51ms); } else { diff --git a/connectivity/netsocket/tests/TESTS/network/emac/emac_test_initialize.cpp b/connectivity/netsocket/tests/TESTS/network/emac/emac_test_initialize.cpp index 1a271821067..64d20ad0786 100644 --- a/connectivity/netsocket/tests/TESTS/network/emac/emac_test_initialize.cpp +++ b/connectivity/netsocket/tests/TESTS/network/emac/emac_test_initialize.cpp @@ -49,13 +49,24 @@ void test_emac_initialize() */ void test_emac_power_down_and_power_up() { + // If we are using a wi-fi interface, we need to disconnect from the network first +#if MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE == WIFI + TEST_ASSERT_EQUAL_INT(NSAPI_ERROR_OK, get_network_interface()->disconnect()); +#endif + EmacTestNetworkStack::get_instance().get_emac()->power_down(); // Note: Currently the EMAC does not deliver a link state change to down callback when powered down. // Might change that in the future but for now we need to deliver the callback manually. emac_if_link_state_change_cb(false); + // If using wi-fi, call connect which should auto-powerup the EMAC driver. + // Otherwise, manually power it up. +#if MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE == WIFI + TEST_ASSERT_EQUAL_INT(NSAPI_ERROR_OK, get_network_interface()->connect()); +#else TEST_ASSERT_TRUE(EmacTestNetworkStack::get_instance().get_emac()->power_up()); +#endif // Currently EMACs may expect set_hwaddr() to be called after power up as this API is not well defined. EmacTestNetworkStack::get_instance().get_emac()->set_hwaddr(EmacTestNetworkStack::get_instance().get_mac_addr()); diff --git a/connectivity/netsocket/tests/TESTS/network/emac/main.cpp b/connectivity/netsocket/tests/TESTS/network/emac/main.cpp index 6cea89d148b..c58caa7e076 100644 --- a/connectivity/netsocket/tests/TESTS/network/emac/main.cpp +++ b/connectivity/netsocket/tests/TESTS/network/emac/main.cpp @@ -51,13 +51,13 @@ Case cases[] = { Case("EMAC unicast frame length", test_emac_unicast_frame_len), Case("EMAC unicast burst", test_emac_unicast_burst), Case("EMAC unicast long", test_emac_unicast_long), + Case("EMAC memory", test_emac_memory), + Case("EMAC power down and power up", test_emac_power_down_and_power_up), + Case("EMAC unicast again after power cycle", test_emac_unicast), #if !((MBED_CONF_NETWORK_EMAC_NO_SUPPORT_FOR_MULTICAST_FILTER == 1) && \ (MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE == WIFI)) Case("EMAC multicast filter", test_emac_multicast_filter), #endif // !(MBED_CONF_NETWORK_EMAC_NO_SUPPORT_FOR_MULTICAST_FILTER == 1) - Case("EMAC memory", test_emac_memory), - Case("EMAC power down and power up", test_emac_power_down_and_power_up), - Case("EMAC unicast again after power cycle", test_emac_unicast), }; Specification specification(test_setup, cases); diff --git a/connectivity/netsocket/tests/UNITTESTS/doubles/OnboardNetworkStack_mock.h b/connectivity/netsocket/tests/UNITTESTS/doubles/OnboardNetworkStack_mock.h index 79c3b3ffe1c..105be46d161 100644 --- a/connectivity/netsocket/tests/UNITTESTS/doubles/OnboardNetworkStack_mock.h +++ b/connectivity/netsocket/tests/UNITTESTS/doubles/OnboardNetworkStack_mock.h @@ -52,6 +52,7 @@ class OnboardNetworkStackMock : public OnboardNetworkStack { MOCK_METHOD4(add_ethernet_interface_mock, nsapi_error_t(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out, NetworkInterface *user_network_interface)); + MOCK_METHOD(EMACMemoryManager &, get_memory_manager, (), (override)); // Wrapper written to handle function with the default argument in the gmock. nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, Interface **interface_out, NetworkInterface *user_network_interface = NULL) diff --git a/connectivity/netsocket/tests/emac_test_utils/EmacTestMemoryManager.cpp b/connectivity/netsocket/tests/emac_test_utils/EmacTestMemoryManager.cpp index 0296ede8967..bd7bb22176b 100644 --- a/connectivity/netsocket/tests/emac_test_utils/EmacTestMemoryManager.cpp +++ b/connectivity/netsocket/tests/emac_test_utils/EmacTestMemoryManager.cpp @@ -118,15 +118,16 @@ emac_mem_buf_t *EmacTestMemoryManager::alloc_heap(uint32_t size, uint32_t align, CHECK_ASSERT(buf->buffer, "alloc_heap() no memory"); buf->next = 0; - buf->ptr = static_cast(buf->buffer) + BUF_HEAD_SIZE; + buf->ptr = static_cast(buf->buffer) + BUF_HEAD_SIZE; buf->orig_len = size; buf->len = size; buf->first = true; buf->lifetime = Lifetime::HEAP_ALLOCATED; + buf->header_skip_amount = 0; if (opt & MEM_NO_ALIGN) { if (reinterpret_cast(buf->ptr) % sizeof(uint16_t) == 0) { - buf->ptr = static_cast(buf->ptr) + 1; + buf->ptr = static_cast(buf->ptr) + 1; } } else if (align) { uint32_t remainder = reinterpret_cast(buf->ptr) % align; @@ -135,14 +136,14 @@ emac_mem_buf_t *EmacTestMemoryManager::alloc_heap(uint32_t size, uint32_t align, if (offset >= align) { offset = align; } - buf->ptr = static_cast(buf->ptr) + offset; + buf->ptr = static_cast(buf->ptr) + offset; } } - char *buffer_head = static_cast(buf->ptr) - BUF_HEAD_SIZE; + uint8_t *buffer_head = static_cast(buf->ptr) - BUF_HEAD_SIZE; memcpy(buffer_head, BUF_HEAD, BUF_HEAD_SIZE); - char *buffer_tail = static_cast(buf->ptr) + buf->len; + uint8_t *buffer_tail = static_cast(buf->ptr) + buf->len; memcpy(buffer_tail, BUF_TAIL, BUF_TAIL_SIZE); // Scribble over the buffer contents with 'y' so it's totally obvious if someone uses it uninitialized. @@ -277,12 +278,12 @@ void EmacTestMemoryManager::free(emac_mem_buf_t *buf) return; } - char *buffer_head = static_cast(mem_buf->ptr) - BUF_HEAD_SIZE; + uint8_t *buffer_head = static_cast(mem_buf->ptr) - BUF_HEAD_SIZE; if (memcmp(buffer_head, BUF_HEAD, BUF_HEAD_SIZE) != 0) { CHECK_ASSERT(0, "free(): %p head overwrite", mem_buf); } - char *buffer_tail = static_cast(mem_buf->ptr) + mem_buf->orig_len; + uint8_t *buffer_tail = static_cast(mem_buf->ptr) + mem_buf->orig_len; if (memcmp(buffer_tail, BUF_TAIL, BUF_TAIL_SIZE) != 0) { CHECK_ASSERT(0, "free(): %p tail overwrite", mem_buf); } @@ -333,65 +334,12 @@ uint32_t EmacTestMemoryManager::get_total_len(const emac_mem_buf_t *buf) const uint32_t total_len = 0; for (emac_memory_t *mem_buf = (emac_memory_t *) buf; mem_buf != NULL; mem_buf = mem_buf->next) { - total_len += mem_buf->len; + total_len += mem_buf->len - mem_buf->header_skip_amount; } return total_len; } -void EmacTestMemoryManager::copy(emac_mem_buf_t *to_buf, const emac_mem_buf_t *from_buf) -{ - validate_list(); - - if (!validate_ptr(to_buf)) { - CHECK_ASSERT(0, "copy(): %p invalid to buffer\n", to_buf); - return; - } - - if (!validate_ptr(from_buf)) { - CHECK_ASSERT(0, "copy(): %p invalid from buffer\n", from_buf); - return; - } - - if (get_total_len(to_buf) != get_total_len(from_buf)) { - CHECK_ASSERT(0, "copy(): %p to and %p from buffer total lengths not same\n", to_buf, from_buf); - return; - } - - unsigned int to_buf_offset = 0; - unsigned int from_buf_offset = 0; - - emac_memory_t *to_mem_buf = static_cast(to_buf); - const emac_memory_t *from_mem_buf = static_cast(from_buf); - - while (to_mem_buf && from_mem_buf) { - unsigned int buf_copy_len; - - // Is there data in from buffer - buf_copy_len = from_mem_buf->len - from_buf_offset; - if (buf_copy_len == 0) { - from_mem_buf = from_mem_buf->next; - from_buf_offset = 0; - continue; - } - - // Is there space left in to buffer - if (buf_copy_len > to_mem_buf->len - to_buf_offset) { - buf_copy_len = to_mem_buf->len - to_buf_offset; - } - if (buf_copy_len == 0) { - to_mem_buf = to_mem_buf->next; - to_buf_offset = 0; - continue; - } - - // Copy data - memcpy(static_cast(to_mem_buf->ptr) + to_buf_offset, static_cast(from_mem_buf->ptr) + from_buf_offset, buf_copy_len); - from_buf_offset += buf_copy_len; - to_buf_offset += buf_copy_len; - } -} - void EmacTestMemoryManager::cat(emac_mem_buf_t *to_buf, emac_mem_buf_t *cat_buf) { validate_list(); @@ -446,7 +394,7 @@ void *EmacTestMemoryManager::get_ptr(const emac_mem_buf_t *buf) const } const emac_memory_t *mem_buf = static_cast(buf); - return mem_buf->ptr; + return mem_buf->ptr + mem_buf->header_skip_amount; } uint32_t EmacTestMemoryManager::get_len(const emac_mem_buf_t *buf) const @@ -459,7 +407,7 @@ uint32_t EmacTestMemoryManager::get_len(const emac_mem_buf_t *buf) const } const emac_memory_t *mem_buf = static_cast(buf); - return mem_buf->len; + return mem_buf->len - mem_buf->header_skip_amount; } void EmacTestMemoryManager::set_len(emac_mem_buf_t *buf, uint32_t len) @@ -473,6 +421,9 @@ void EmacTestMemoryManager::set_len(emac_mem_buf_t *buf, uint32_t len) emac_memory_t *mem_buf = static_cast(buf); + // get_len() subtracts the header size from the length, so to stay consistent we need to add it here. + len += mem_buf->header_skip_amount; + if (len > mem_buf->orig_len) { CHECK_ASSERT(0, "set_len(): %p new length %i must be less or equal allocated size %i\n", buf, len, mem_buf->orig_len); return; @@ -488,9 +439,39 @@ void EmacTestMemoryManager::set_len(emac_mem_buf_t *buf, uint32_t len) NetStackMemoryManager::Lifetime EmacTestMemoryManager::get_lifetime(const net_stack_mem_buf_t *buf) const { + if (!validate_ptr(buf)) { + CHECK_ASSERT(0, "get_lifetime(): %p invalid buffer\n", buf); + } + return static_cast(buf)->lifetime; } +void EmacTestMemoryManager::skip_header_space(net_stack_mem_buf_t *buf, int32_t amount) +{ + if (!validate_ptr(buf)) { + CHECK_ASSERT(0, "skip_header_space(): %p invalid buffer\n", buf); + } + + auto mem = static_cast(buf); + + if (amount > 0) { + CHECK_ASSERT(amount + mem->header_skip_amount <= static_cast(mem->len), "skip_header_space(): header size cannot exceed len"); + } else { + CHECK_ASSERT(amount + mem->header_skip_amount > 0, "skip_header_space(): header size cannot go below 0"); + } + + mem->header_skip_amount += amount; +} + +int32_t EmacTestMemoryManager::get_header_skip_size(net_stack_mem_buf_t *buf) +{ + if (!validate_ptr(buf)) { + CHECK_ASSERT(0, "get_header_skip_size(): %p invalid buffer\n", buf); + } + + return static_cast(buf)->header_skip_amount; +} + void EmacTestMemoryManager::set_alloc_unit(uint32_t alloc_unit) { validate_list(); @@ -590,12 +571,12 @@ void EmacTestMemoryManager::validate_list() const for (std::list::const_iterator it = m_mem_buffers.begin(); it != m_mem_buffers.end(); ++it) { mem_buf = static_cast(*it); - char *buffer_head = static_cast(mem_buf->ptr) - BUF_HEAD_SIZE; + uint8_t *buffer_head = static_cast(mem_buf->ptr) - BUF_HEAD_SIZE; if (memcmp(buffer_head, BUF_HEAD, BUF_HEAD_SIZE) != 0) { CHECK_ASSERT(0, "validate_list(): %p head overwrite", mem_buf); } - char *buffer_tail = static_cast(mem_buf->ptr) + mem_buf->orig_len; + uint8_t *buffer_tail = static_cast(mem_buf->ptr) + mem_buf->orig_len; if (memcmp(buffer_tail, BUF_TAIL, BUF_TAIL_SIZE) != 0) { CHECK_ASSERT(0, "validate_list(): %p tail overwrite", mem_buf); } diff --git a/connectivity/netsocket/tests/emac_test_utils/EmacTestMemoryManager.h b/connectivity/netsocket/tests/emac_test_utils/EmacTestMemoryManager.h index 70beb00c533..224d227e1b6 100644 --- a/connectivity/netsocket/tests/emac_test_utils/EmacTestMemoryManager.h +++ b/connectivity/netsocket/tests/emac_test_utils/EmacTestMemoryManager.h @@ -30,7 +30,8 @@ typedef struct emac_memory { void *buffer; /**< Pointer to allocated buffer */ unsigned int orig_len; /**< Original buffer length (set_len() does not change) */ unsigned int len; /**< Buffer length */ - void *ptr; /**< Aligned pointer */ + int header_skip_amount; ///< Bytes being skiped for the header + uint8_t *ptr; /**< Aligned pointer */ bool first; EMACMemoryManager::Lifetime lifetime; } emac_memory_t; @@ -58,8 +59,6 @@ class EmacTestMemoryManager : public EMACMemoryManager { uint32_t get_total_len(const emac_mem_buf_t *buf) const override; - void copy(emac_mem_buf_t *to_buf, const emac_mem_buf_t *from_buf) override; - void cat(emac_mem_buf_t *to_buf, emac_mem_buf_t *cat_buf) override; emac_mem_buf_t *get_next(const emac_mem_buf_t *buf) const override; @@ -72,6 +71,10 @@ class EmacTestMemoryManager : public EMACMemoryManager { Lifetime get_lifetime(const net_stack_mem_buf_t *buf) const override; + void skip_header_space(net_stack_mem_buf_t *buf, int32_t amount) override; + + int32_t get_header_skip_size(net_stack_mem_buf_t *buf) override; + /** * Allocates memory buffer from the heap * diff --git a/connectivity/netsocket/tests/emac_test_utils/EmacTestNetworkStack.h b/connectivity/netsocket/tests/emac_test_utils/EmacTestNetworkStack.h index 322e29d5d06..1ae0bb743a6 100644 --- a/connectivity/netsocket/tests/emac_test_utils/EmacTestNetworkStack.h +++ b/connectivity/netsocket/tests/emac_test_utils/EmacTestNetworkStack.h @@ -87,6 +87,12 @@ class EmacTestNetworkStack : public OnboardNetworkStack, private mbed::NonCopyab /// Get the MAC address being used for the ethernet port unsigned char const *get_mac_addr() const; + /// Get the memory manager for the test stack + EmacTestMemoryManager &get_memory_manager() override + { + return EmacTestMemoryManager::get_instance(); + } + protected: nsapi_error_t socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto) override; diff --git a/connectivity/netsocket/tests/emac_test_utils/emac_util.cpp b/connectivity/netsocket/tests/emac_test_utils/emac_util.cpp index 62a1ffe8c0c..64c551c4e29 100644 --- a/connectivity/netsocket/tests/emac_test_utils/emac_util.cpp +++ b/connectivity/netsocket/tests/emac_test_utils/emac_util.cpp @@ -231,10 +231,12 @@ bool emac_if_update_reply_to_outgoing_msg(int receipt_number, int length, int in minimum frame length or sent length (in case frame has been converted to be longer than minimum length does not validate length) */ if (length != ETH_FRAME_MIN_LEN && length != ETH_FRAME_PADD_LEN && outgoing_msgs[outgoing_msg_index].length != length && length < ETH_FRAME_MIN_LEN) { + printf("Expected length %d, %d, or %d, actual %d\n", ETH_FRAME_MIN_LEN, ETH_FRAME_PADD_LEN, outgoing_msgs[outgoing_msg_index].length, length); outgoing_msgs[outgoing_msg_index].flags |= INVALID_LENGTH; } } else { if (outgoing_msgs[outgoing_msg_index].length != length) { + printf("Expected length %d, actual %d\n", outgoing_msgs[outgoing_msg_index].length, length); outgoing_msgs[outgoing_msg_index].flags |= INVALID_LENGTH; } } diff --git a/hal/include/hal/rtc_api.h b/hal/include/hal/rtc_api.h index 642628096c7..6c66d939822 100644 --- a/hal/include/hal/rtc_api.h +++ b/hal/include/hal/rtc_api.h @@ -46,6 +46,9 @@ extern "C" { * - Verified by test rtc_write_read_test. * * The functions ::rtc_isenabled returns 1 if the RTC is counting and the time has been set, * 0 otherwise - Verified by test rtc_enabled_test. + * * ::rtc_read may be called before rtc_write. If the RTC time has not been set, this will return the + * time since some arbitrary epoch. If the RTC time was set on a previous boot, this will return time + * based on what was set then. * * # Undefined behaviour * * Calling any function other than ::rtc_init before the initialisation of the RTC diff --git a/hal/tests/TESTS/mbed_hal/rtc/main.cpp b/hal/tests/TESTS/mbed_hal/rtc/main.cpp index 544c0271e98..33ac67d83f0 100644 --- a/hal/tests/TESTS/mbed_hal/rtc/main.cpp +++ b/hal/tests/TESTS/mbed_hal/rtc/main.cpp @@ -98,13 +98,24 @@ void rtc_sleep_test_support(bool deepsleep_mode) } #endif -/* Test that ::rtc_init can be called multiple times. */ +/* Tests ::rtc_init() behavior: + - rtc_init() can be called multiple times + - rtc_isenabled() returns false before init and true after + - RTC returns valid time after being initialized (though that time may be anything). */ void rtc_init_test() { + TEST_ASSERT_FALSE(RealTimeClock::isenabled()); + for (int i = 0; i < 10; i++) { RealTimeClock::init(); + + TEST_ASSERT_TRUE(RealTimeClock::isenabled()); } + // Note that if the RTC returns an invalid time after being initialized, this function will crash Mbed, + // so we just need to call it. + RealTimeClock::now(); + RealTimeClock::free(); } diff --git a/targets/TARGET_Cypress/TARGET_PSOC6/cy_rtc_api.c b/targets/TARGET_Cypress/TARGET_PSOC6/cy_rtc_api.c index eb88baaec28..b0a9cc90d3c 100644 --- a/targets/TARGET_Cypress/TARGET_PSOC6/cy_rtc_api.c +++ b/targets/TARGET_Cypress/TARGET_PSOC6/cy_rtc_api.c @@ -27,21 +27,37 @@ extern "C" { static cyhal_rtc_t cy_rtc; +static bool rtc_initialized = false; + void rtc_init(void) { - if (CY_RSLT_SUCCESS != cyhal_rtc_init(&cy_rtc)) { - MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_FAILED_OPERATION), "cyhal_rtc_init"); + if(!rtc_initialized) + { + if (CY_RSLT_SUCCESS != cyhal_rtc_init(&cy_rtc)) { + MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_FAILED_OPERATION), "cyhal_rtc_init"); + } + + // Default CyHAL RTC behavior is for the RTC to start at year 0 when first initialized. + // However, this will cause rtc_read() to crash as this date is not representable as a time_t. + // To fix this, if the time has never been set before, set it to Jan 1 1970. + if(!cyhal_rtc_is_enabled(&cy_rtc)) // This function is poorly named but returns whether the time has ever been set. + { + rtc_write(0); + } + + rtc_initialized = true; } } void rtc_free(void) { cyhal_rtc_free(&cy_rtc); + rtc_initialized = false; } int rtc_isenabled(void) { - return cyhal_rtc_is_enabled(&cy_rtc) ? 1 : 0; + return rtc_initialized; } time_t rtc_read(void) @@ -51,7 +67,7 @@ time_t rtc_read(void) MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_FAILED_OPERATION), "cyhal_rtc_read"); } time_t seconds; - if (!_rtc_maketime(&rtc_time, &seconds, RTC_FULL_LEAP_YEAR_SUPPORT)) { + if (!_rtc_maketime(&rtc_time, &seconds, RTC_4_YEAR_LEAP_YEAR_SUPPORT)) { MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_FAILED_OPERATION), "_rtc_maketime"); } return seconds;