Reactivate EMAC Greentea test (#378)

* Migrate emac test code into a library

* Build passes now!

* Fix STLINK bug, update README

* Reduce verbosity a bit

* Formatting

* Fix licenses
pull/15530/head
Jamie Smith 2024-10-29 20:52:57 -07:00 committed by GitHub
parent 197e043d78
commit e72b38a2be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 476 additions and 966 deletions

View File

@ -17,7 +17,7 @@ jobs:
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
@ -68,7 +68,7 @@ jobs:
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
@ -90,7 +90,7 @@ jobs:
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
@ -143,7 +143,7 @@ jobs:
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
@ -216,7 +216,7 @@ jobs:
steps:
-
name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
@ -244,7 +244,7 @@ jobs:
steps:
-
name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install python3-venv
run: |

View File

@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
submodules: recursive

View File

@ -134,7 +134,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install python3-venv
run: |

View File

@ -8,7 +8,7 @@ jobs:
container: ghcr.io/armmbed/mbed-os-env:master-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install Python packages
# Note: pip>=20.3 is needed to install dependencies of cysecuretools

View File

@ -13,8 +13,9 @@ Arm Mbed OS is an open source embedded operating system designed specifically fo
Mbed OS provides a platform that includes:
- Security foundations.
- Cloud management services.
- Drivers for sensors, I/O devices and connectivity.
- Embedded networking libraries, e.g Wi-Fi and Ethernet drivers and network libraries using them
- Drivers for microcontroller hardware features, including digital and analog I/O, PWM, and communications busses
- Storage features, including file system and block device abstractions and low-level drivers
This is Mbed OS Community Edition (CE), a fork focused on improving the build system and tooling, fixing bugs, and keeping maintenance going after ARM's step back from the Mbed project.

View File

@ -22,6 +22,8 @@ target_sources(mbed-nanostack-libservice
source/nvmHelper/ns_nvm_helper.c
)
target_link_libraries(mbed-nanostack-libservice PUBLIC mbed-nanostack-hal_mbed_cmsis_rtos)
# The definition, source files and include directories below
# are needed by mbed-trace which is part of the mbed-core CMake target
target_compile_definitions(mbed-core-flags

View File

@ -18,6 +18,14 @@
#ifndef ARM_HAL_INTERRUPT_PRIVATE_H_
#define ARM_HAL_INTERRUPT_PRIVATE_H_
#ifdef __cplusplus
extern "C" {
#endif
void platform_critical_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,6 +1,8 @@
# Copyright (c) 2020 ARM Limited. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
add_subdirectory(tests/emac_test_utils)
if(MBED_ENABLE_OS_INTERNAL_TESTS)
if(MBED_BUILD_GREENTEA_TESTS)
add_subdirectory(tests/TESTS)

View File

@ -1,2 +1,3 @@
add_subdirectory(emac)
add_subdirectory(interface)
add_subdirectory(wifi)

View File

@ -1,23 +1,15 @@
# Copyright (c) 2020 ARM Limited. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR)
set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../.. CACHE INTERNAL "")
set(TEST_TARGET mbed-connectivity-netsocket-network-emac)
include(${MBED_PATH}/tools/cmake/mbed_greentea.cmake)
project(${TEST_TARGET})
if(NOT "MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE=WIFI" IN_LIST MBED_CONFIG_DEFINITIONS AND
NOT "MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE=ETHERNET" IN_LIST MBED_CONFIG_DEFINITIONS)
set(TEST_SKIPPED "Requires wi-fi or ethernet to be the default network interface")
endif()
list(
APPEND
TEST_SOURCE_LIST
main.cpp
emac_TestMemoryManager.cpp
emac_TestNetworkStack.cpp
emac_ctp.cpp
emac_membuf.cpp
emac_test_broadcast.cpp
emac_test_initialize.cpp
emac_test_memory.cpp
@ -26,14 +18,16 @@ list(
emac_test_unicast_burst.cpp
emac_test_unicast_frame_len.cpp
emac_test_unicast_long.cpp
emac_util.cpp
)
mbed_greentea_add_test(
TEST_NAME
${TEST_TARGET}
mbed-connectivity-network-emac
TEST_SOURCES
${TEST_SOURCE_LIST}
TEST_REQUIRED_LIBS
mbed-emac
mbed-netsocket
mbed-emac-test-utils
TEST_SKIPPED
${TEST_SKIPPED}
)

View File

@ -4,7 +4,7 @@ This document describes how to run EMAC tests. The EMAC test cases are made usin
## Configuring the CTP echo server
To configure a device to be a CTP echo server, you need to enable the `echo-server` setting in the `json` file of the test environment application. When you configure a device to be a CTP echo server, it starts to forward CTP messages automatically when it is on and continues to do so until you switch it off.
To configure a device to be a CTP echo server, you need to flash it with the [mbed-ethernet-ctp-server](https://github.com/mbed-ce/mbed-ethernet-ctp-server) application. When you configure a device to be a CTP echo server, it starts to forward CTP messages automatically when it is on and continues to do so until you switch it off.
## Other configuration options
@ -56,28 +56,6 @@ Please refer to the following table for priorities of test cases. Priorities are
## Example commands
### CTP echo server
You can use the following command to a build CTP echo server:
`mbed test --compile -m TARGET -t GCC_ARM -v -n tests-network-emac --app-config TESTS/network/emac/template_mbed_app_echo_server.txt`
Replace TARGET with the target device. After building, flash the binary to the CTP echo server device.
You can verify that the CTP echo server has started properly by making a terminal connection to the device, resetting it and verifying that `echo server started successfully` prints on the terminal. You can run host tests when the CTP echo server is running on the Ethernet segment.
For Wi-Fi tests, the CTP echo server can also run on the ethernet side as long as the network configuration is such that Ethernet frames are routed between Wi-Fi and Ethernet.
The CTP echo server sends a 100-byte long broadcast CTP Ethernet frame every 60 seconds to inform the network of its presence.
### Running tests
You can use the following command to run tests:
`mbed test --compile --run -m TARGET -t GCC_ARM -v -n tests-network-emac --app-config TESTS/network/emac/template_mbed_app.txt`
Replace TARGET with the target device.
## Traces
Test cases have different trace levels based on how much tracing can be done without affecting the performance of the test case. Configure tracing using `SET\_TRACE\_LEVEL` macro.

View File

@ -1,229 +0,0 @@
/*
* Copyright (c) 2018, ARM Limited, All Rights Reserved
* 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 EMAC_TEST_MEMORY_MANAGER_H
#define EMAC_TEST_MEMORY_MANAGER_H
#include <list>
#include "EMACMemoryManager.h"
#define MEM_CHECK 0x01
#define MEM_NO_ALIGN 0x02
typedef struct emac_memory {
struct emac_memory *next;
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 */
bool first;
} emac_memory_t;
class EmacTestMemoryManager : public EMACMemoryManager {
public:
/**
* Creates emac test memory manager
*/
EmacTestMemoryManager();
/*
* Gets static instance
*/
static EmacTestMemoryManager &get_instance();
/**
* Allocates memory buffer from the heap
*
* Memory buffer allocated from heap is always contiguous and can be arbitrary size.
*
* @param size Size of the memory to allocate in bytes
* @param align Memory alignment requirement in bytes
* @return Allocated memory buffer, or NULL in case of error
*/
virtual emac_mem_buf_t *alloc_heap(uint32_t size, uint32_t align);
/**
* Allocates memory buffer from the heap
*
* Memory buffer allocated from heap is always contiguous and can be arbitrary size.
*
* @param size Size of the memory to allocate in bytes
* @param align Memory alignment requirement in bytes
* @param opt Options
* @return Allocated memory buffer, or NULL in case of error
*/
emac_mem_buf_t *alloc_heap(uint32_t size, uint32_t align, uint8_t opt);
/**
* Allocates memory buffer chain from a pool
*
* Memory allocated from pool is contiguous if size is equal or less than
* (aligned) allocation unit, otherwise may be chained. Will typically come from
* fixed-size packet pool memory.
*
* @param size Total size of the memory to allocate in bytes
* @param align Memory alignment requirement for each buffer in bytes
* @return Allocated memory buffer chain, or NULL in case of error
*/
virtual emac_mem_buf_t *alloc_pool(uint32_t size, uint32_t align);
/**
* Allocates memory buffer chain from a pool
*
* Memory allocated from pool is contiguous if size is equal or less than
* (aligned) allocation unit, otherwise may be chained. Will typically come from
* fixed-size packet pool memory.
*
* @param size Total size of the memory to allocate in bytes
* @param align Memory alignment requirement for each buffer in bytes
* @param opt Options
* @return Allocated memory buffer chain, or NULL in case of error
*/
emac_mem_buf_t *alloc_pool(uint32_t size, uint32_t align, uint8_t opt);
/**
* Get memory buffer pool allocation unit
*
* Returns the maximum size of contiguous memory that can be allocated from a pool.
*
* @param align Memory alignment requirement in bytes
* @return Contiguous memory size
*/
virtual uint32_t get_pool_alloc_unit(uint32_t align) const;
/**
* Free memory buffer chain
*
* If memory buffer is chained must point to the start of the chain. Frees all buffers
* from the chained list.
*
* @param buf Memory buffer chain to be freed.
*/
virtual void free(emac_mem_buf_t *buf);
/**
* Return total length of a memory buffer chain
*
* Returns a total length of this buffer and any following buffers in the chain.
*
* @param buf Memory buffer chain
* @return Total length in bytes
*/
virtual uint32_t get_total_len(const emac_mem_buf_t *buf) const;
/**
* 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(emac_mem_buf_t *to_buf, const emac_mem_buf_t *from_buf);
/**
* Concatenate two memory buffer chains
*
* Concatenates buffer chain to end of the other buffer chain. Concatenated-to buffer total length
* 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.
*
* @param to_buf Memory buffer chain to concatenate to
* @param cat_buf Memory buffer chain to concatenate
*/
virtual void cat(emac_mem_buf_t *to_buf, emac_mem_buf_t *cat_buf);
/**
* Returns the next buffer
*
* Returns the next buffer from the memory buffer chain.
*
* @param buf Memory buffer
* @return The next memory buffer, or NULL if last
*/
virtual emac_mem_buf_t *get_next(const emac_mem_buf_t *buf) const;
/**
* Return pointer to the payload of the buffer
*
* @param buf Memory buffer
* @return Pointer to the payload
*/
virtual void *get_ptr(const emac_mem_buf_t *buf) const;
/**
* Return payload size of the buffer
*
* @param buf Memory buffer
* @return Size in bytes
*/
virtual uint32_t get_len(const emac_mem_buf_t *buf) const;
/**
* Sets the payload size of the buffer
*
* 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.
*
* @param buf Memory buffer
* @param len Payload size, must be less or equal allocated size
*/
virtual void set_len(emac_mem_buf_t *buf, uint32_t len);
/**
* Sets memory buffer pool allocation unit
*
* Sets the maximum size of contiguous memory that can be allocated from a pool.
*
* @param alloc_unit Contiguous memory size
*/
virtual void set_alloc_unit(uint32_t alloc_unit);
/**
* Sets whether memory is available
*
* Can be used to disable memory allocation request from emac.
*
* @param memory True if memory is available
*/
void set_memory_available(bool memory);
/**
* Gets memory statistics
*
* Gets memory usage statistics
*
* @param buffers Number of buffers that are reserved
* @param memory Reserved memory in bytes
*/
void get_memory_statistics(int *buffers, int *memory);
private:
void validate_list() const;
template <typename TYPE> void check_value(TYPE value, const char *fmt, ...) const;
bool validate_ptr(const emac_mem_buf_t *buf) const;
void check_align(uint32_t align) const;
mutable rtos::Mutex m_mem_mutex;
std::list<emac_memory_t *> m_mem_buffers;
unsigned int m_alloc_unit;
bool m_memory_available;
};
#endif /* EMAC_TEST_MEMORY_MANAGER_H */

View File

@ -1,411 +0,0 @@
/*
* Copyright (c) 2018, ARM Limited, All Rights Reserved
* 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 EMAC_TEST_NETWORK_STACK_H
#define EMAC_TEST_NETWORK_STACK_H
#include "netsocket/nsapi_types.h"
#include "netsocket/EMAC.h"
#include "netsocket/OnboardNetworkStack.h"
#include "emac_TestMemoryManager.h"
class EmacTestNetworkStack : public OnboardNetworkStack, private mbed::NonCopyable<EmacTestNetworkStack> {
public:
static EmacTestNetworkStack &get_instance();
EmacTestNetworkStack();
virtual ~EmacTestNetworkStack() {}
class Interface : public OnboardNetworkStack::Interface {
public:
static Interface &get_instance();
/** Connect the interface to the network
*
* Sets up a connection on specified network interface, using DHCP or provided network details. If the @a dhcp is set to
* true all the remaining parameters are ignored.
*
* @param dhcp true if the network details should be acquired using DHCP
* @param ip IP address to be used for the interface as "W:X:Y:Z" or NULL
* @param netmask Net mask to be used for the interface as "W:X:Y:Z" or NULL
* @param gw Gateway address to be used for the interface as "W:X:Y:Z" or NULL
* @param stack Allow manual selection of IPv4 and/or IPv6.
* @param blocking Specify whether bringup blocks for connection completion.
* @return NSAPI_ERROR_OK on success, or error code
*/
virtual nsapi_error_t bringup(bool dhcp, const char *ip,
const char *netmask, const char *gw,
nsapi_ip_stack_t stack = DEFAULT_STACK,
bool blocking = true
);
/** Disconnect interface from the network
*
* After this call the network interface is inactive, to use it again user needs to call @a mbed_ipstack_bringup again.
*
* @return NSAPI_ERROR_OK on success, or error code
*/
virtual nsapi_error_t bringdown();
/** Register callback for status reporting
*
* The specified status callback function will be called on status changes
* on the network. The parameters on the callback are the event type and
* event-type dependent reason parameter.
*
* @param status_cb The callback for status changes
*/
virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
/** Get the connection status
*
* @return The connection status according to ConnectionStatusType
*/
virtual nsapi_connection_status_t get_connection_status() const;
/** Return MAC address of the network interface
*
* @return MAC address as "V:W:X:Y:Z"
*/
virtual char *get_mac_address(char *buf, nsapi_size_t buflen);
/** Set MAC address on the network interface
*
* @param mac_addr Buffer containing the MAC address in hexadecimal format.
* @param addr_len Length of provided buffer in bytes (6 or 8)
* @retval NSAPI_ERROR_OK on success
* @retval NSAPI_ERROR_UNSUPPORTED if this feature is not supported
* @retval NSAPI_ERROR_PARAMETER if address is not valid
* @retval NSAPI_ERROR_BUSY if address can't be set.
*/
virtual nsapi_error_t set_mac_address(uint8_t *mac_addr, nsapi_size_t addr_len);
/** Copies IP address of the network interface to user supplied buffer
*
* @param buf buffer to which IP address will be copied as "W:X:Y:Z"
* @param buflen size of supplied buffer
* @return Pointer to a buffer, or NULL if the buffer is too small
*/
virtual nsapi_error_t get_ip_address(SocketAddress *address);
MBED_DEPRECATED_SINCE("mbed-os-5.15", "String-based APIs are deprecated")
virtual char *get_ip_address(char *buf, nsapi_size_t buflen);
/** Copies netmask of the network interface to user supplied buffer
*
* @param buf buffer to which netmask will be copied as "W:X:Y:Z"
* @param buflen size of supplied buffer
* @return Pointer to a buffer, or NULL if the buffer is too small
*/
virtual nsapi_error_t get_netmask(SocketAddress *address);
MBED_DEPRECATED_SINCE("mbed-os-5.15", "String-based APIs are deprecated")
virtual char *get_netmask(char *buf, nsapi_size_t buflen);
/** Copies gateway address of the network interface to user supplied buffer
*
* @param buf buffer to which gateway address will be copied as "W:X:Y:Z"
* @param buflen size of supplied buffer
* @return Pointer to a buffer, or NULL if the buffer is too small
*/
virtual nsapi_error_t get_gateway(SocketAddress *address);
MBED_DEPRECATED_SINCE("mbed-os-5.15", "String-based APIs are deprecated")
virtual char *get_gateway(char *buf, nsapi_size_t buflen);
private:
friend EmacTestNetworkStack;
Interface();
EMAC *m_emac;
};
/** Register a network interface with the IP stack
*
* Connects EMAC layer with the IP stack and initializes all the required infrastructure.
* This function should be called only once for each available interface.
*
* @param emac EMAC HAL implementation for this network interface
* @param default_if true if the interface should be treated as the default one
* @param[out] interface_out pointer to stack interface object controlling the EMAC
* @return NSAPI_ERROR_OK on success, or error code
*/
virtual nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out, NetworkInterface *user_network_interface);
/** Translates a hostname to an IP address with specific version
*
* The hostname may be either a domain name or an IP address. If the
* hostname is an IP address, no network transactions will be performed.
*
* If no stack-specific DNS resolution is provided, the hostname
* will be resolve using a UDP socket on the stack.
*
* @param host Hostname to resolve
* @param address Destination for the host SocketAddress
* @param version IP version of address to resolve, NSAPI_UNSPEC indicates
* version is chosen by the stack (defaults to NSAPI_UNSPEC)
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t gethostbyname(const char *host,
SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC);
/** Add a domain name server to list of servers to query
*
* @param address Destination for the host address
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t add_dns_server(const SocketAddress &address);
protected:
/** Opens a socket
*
* Creates a network socket and stores it in the specified handle.
* The handle must be passed to following calls on the socket.
*
* A stack may have a finite number of sockets, in this case
* NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
*
* @param handle Destination for the handle to a newly created socket
* @param proto Protocol of socket to open, NSAPI_TCP or NSAPI_UDP
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto);
/** Close the socket
*
* Closes any open connection and deallocates any memory associated
* with the socket.
*
* @param handle Socket handle
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_close(nsapi_socket_t handle);
/** Bind a specific address to a socket
*
* Binding a socket specifies the address and port on which to receive
* data. If the IP address is zeroed, only the port is bound.
*
* @param handle Socket handle
* @param address Local address to bind
* @return 0 on success, negative error code on failure.
*/
virtual nsapi_error_t socket_bind(nsapi_socket_t handle, const SocketAddress &address);
/** Listen for connections on a TCP socket
*
* Marks the socket as a passive socket that can be used to accept
* incoming connections.
*
* @param handle Socket handle
* @param backlog Number of pending connections that can be queued
* simultaneously
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_listen(nsapi_socket_t handle, int backlog);
/** Connects TCP socket to a remote host
*
* Initiates a connection to a remote server specified by the
* indicated address.
*
* @param handle Socket handle
* @param address The SocketAddress of the remote host
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_connect(nsapi_socket_t handle, const SocketAddress &address);
/** Accepts a connection on a TCP socket
*
* The server socket must be bound and set to listen for connections.
* On a new connection, creates a network socket and stores it in the
* specified handle. The handle must be passed to following calls on
* the socket.
*
* A stack may have a finite number of sockets, in this case
* NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
*
* This call is non-blocking. If accept would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param server Socket handle to server to accept from
* @param handle Destination for a handle to the newly created socket
* @param address Destination for the remote address or NULL
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_accept(nsapi_socket_t server,
nsapi_socket_t *handle, SocketAddress *address = 0);
/** Send data over a TCP socket
*
* The socket must be connected to a remote host. Returns the number of
* bytes sent from the buffer.
*
* This call is non-blocking. If send would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Socket handle
* @param data Buffer of data to send to the host
* @param size Size of the buffer in bytes
* @return Number of sent bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_send(nsapi_socket_t handle,
const void *data, nsapi_size_t size);
/** Receive data over a TCP socket
*
* The socket must be connected to a remote host. Returns the number of
* bytes received into the buffer.
*
* This call is non-blocking. If recv would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Socket handle
* @param data Destination buffer for data received from the host
* @param size Size of the buffer in bytes
* @return Number of received bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_recv(nsapi_socket_t handle,
void *data, nsapi_size_t size);
/** Send a packet over a UDP socket
*
* Sends data to the specified address. Returns the number of bytes
* sent from the buffer.
*
* This call is non-blocking. If sendto would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Socket handle
* @param address The SocketAddress of the remote host
* @param data Buffer of data to send to the host
* @param size Size of the buffer in bytes
* @return Number of sent bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_sendto(nsapi_socket_t handle, const SocketAddress &address,
const void *data, nsapi_size_t size);
/** Receive a packet over a UDP socket
*
* Receives data and stores the source address in address if address
* is not NULL. Returns the number of bytes received into the buffer.
*
* This call is non-blocking. If recvfrom would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Socket handle
* @param address Destination for the source address or NULL
* @param buffer Destination buffer for data received from the host
* @param size Size of the buffer in bytes
* @return Number of received bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_recvfrom(nsapi_socket_t handle, SocketAddress *address,
void *buffer, nsapi_size_t size);
/** Register a callback on state change of the socket
*
* The specified callback will be called on state changes such as when
* the socket can recv/send/accept successfully and on when an error
* occurs. The callback may also be called spuriously without reason.
*
* The callback may be called in an interrupt context and should not
* perform expensive operations such as recv/send calls.
*
* @param handle Socket handle
* @param callback Function to call on state change
* @param data Argument to pass to callback
*/
virtual void socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data);
/* Set stack-specific socket options
*
* The setsockopt allow an application to pass stack-specific hints
* to the underlying stack. For unsupported options,
* NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified.
*
* @param handle Socket handle
* @param level Stack-specific protocol level
* @param optname Stack-specific option identifier
* @param optval Option value
* @param optlen Length of the option value
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t setsockopt(nsapi_socket_t handle, int level,
int optname, const void *optval, unsigned optlen);
/* Get stack-specific socket options
*
* The getstackopt allow an application to retrieve stack-specific hints
* from the underlying stack. For unsupported options,
* NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified.
*
* @param handle Socket handle
* @param level Stack-specific protocol level
* @param optname Stack-specific option identifier
* @param optval Destination for option value
* @param optlen Length of the option value
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t getsockopt(nsapi_socket_t handle, int level,
int optname, void *optval, unsigned *optlen);
private:
/** Call in callback
*
* Callback is used to call the call in method of the network stack.
*/
typedef mbed::Callback<nsapi_error_t (int delay_ms, mbed::Callback<void()> user_cb)> call_in_callback_cb_t;
/** Get a call in callback
*
* Get a call in callback from the network stack context.
*
* Callback should not take more than 10ms to execute, otherwise it might
* prevent underlying thread processing. A portable user of the callback
* should not make calls to network operations due to stack size limitations.
* The callback should not perform expensive operations such as socket recv/send
* calls or blocking operations.
*
* @return Call in callback
*/
virtual call_in_callback_cb_t get_call_in_callback();
/** Call a callback after a delay
*
* Call a callback from the network stack context after a delay. If function
* returns error callback will not be called.
*
* @param delay Delay in milliseconds
* @param func Callback to be called
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t call_in(int delay, mbed::Callback<void()> func);
Interface *m_interface;
};
#endif /* EMAC_TEST_NETWORK_STACK_H */

View File

@ -1,26 +0,0 @@
/*
* Copyright (c) 2017, ARM Limited, All Rights Reserved
* 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 EMAC_INITIALIZE_H
#define EMAC_INITIALIZE_H
unsigned char *emac_if_get_hw_addr(void);
bool emac_if_init(EMAC *emac);
EMAC *emac_if_get(void);
EmacTestMemoryManager *emac_m_mngr_get(void);
#endif /* EMAC_INITIALIZE_H */

View File

@ -93,7 +93,7 @@ void test_emac_broadcast(void)
RESET_ALL_ERROR_FLAGS;
SET_TRACE_LEVEL(TRACE_SEND | TRACE_ETH_FRAMES | TRACE_SUCCESS | TRACE_FAILURE);
START_TEST_LOOP(test_emac_broadcast_cb, 1 * SECOND_TO_MS);
START_TEST_LOOP(test_emac_broadcast_cb, 1s);
PRINT_ERROR_FLAGS;
TEST_ASSERT_FALSE(ERROR_FLAGS);

View File

@ -16,54 +16,25 @@
*/
#if defined(MBED_CONF_RTOS_PRESENT)
#include <inttypes.h>
#include "mbed.h"
#include "mbed_stats.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "NetworkInterface.h"
#include "EMAC.h"
#include "EMACMemoryManager.h"
#include "emac_TestMemoryManager.h"
#include "emac_TestNetworkStack.h"
#include "emac_initialize.h"
#include "EmacTestNetworkStack.h"
#include "emac_tests.h"
#include "emac_util.h"
#include "greentea_get_network_interface.h"
using namespace utest::v1;
static unsigned char eth_mac_addr[ETH_MAC_ADDR_LEN];
EMAC *emac_handle = NULL;
void test_emac_initialize()
{
worker_loop_init();
static NetworkInterface *network_interface = NetworkInterface::get_default_instance();
#define WIFI 2
#if MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE == WIFI
#if MBED_CONF_APP_WIFI_SCAN
WiFiAccessPoint ap[30];
int size = network_interface->wifiInterface()->scan(ap, 30);
for (int i = 0; i < size; i++) {
const char *ssid = ap[i].get_ssid();
nsapi_security_t security = ap[i].get_security();
int8_t rssi = ap[i].get_rssi();
char ch = ap[i].get_channel();
printf("BS %i\r\n", i);
printf("ssid %s\r\n", ssid);
printf("security %i\r\n", security);
printf("rssi %i\r\n", rssi);
printf("ch %i\r\n\r\n", ch);
}
#endif
#endif
static NetworkInterface *network_interface = get_network_interface();
// Power up the interface and emac driver
TEST_ASSERT_EQUAL_INT(NSAPI_ERROR_OK, network_interface->connect());
@ -71,51 +42,4 @@ void test_emac_initialize()
worker_loop_link_up_wait();
}
unsigned char *emac_if_get_hw_addr(void)
{
return &eth_mac_addr[0];
}
EMAC *emac_if_get(void)
{
return emac_handle;
}
EmacTestMemoryManager *emac_m_mngr_get(void)
{
return &EmacTestMemoryManager::get_instance();
}
bool emac_if_init(EMAC *emac)
{
emac_handle = emac;
emac->set_link_input_cb(emac_if_link_input_cb);
emac->set_link_state_cb(emac_if_link_state_change_cb);
if (!emac->power_up()) {
TEST_ASSERT_MESSAGE(0, "emac power up failed!");
}
int hwaddr_len = emac->get_hwaddr_size();
printf("emac hwaddr length %i\r\n\r\n", hwaddr_len);
TEST_ASSERT_MESSAGE(hwaddr_len == 6, "invalid emac hwaddr length!");
// If driver updates this, write it back, otherwise write default from mbed_mac_address
mbed_mac_address(reinterpret_cast<char *>(&eth_mac_addr[0]));
emac->get_hwaddr(eth_mac_addr);
emac->set_hwaddr(eth_mac_addr);
printf("emac hwaddr %x:%x:%x:%x:%x:%x\r\n\r\n", eth_mac_addr[0], eth_mac_addr[1], eth_mac_addr[2], eth_mac_addr[3], eth_mac_addr[4], eth_mac_addr[5]);
int mtu_size = emac->get_mtu_size();
printf("emac mtu %i\r\n\r\n", mtu_size);
emac_if_set_mtu_size(mtu_size);
char hw_name[11];
emac->get_ifname(hw_name, 10);
printf("emac if name %s\r\n\r\n", hw_name);
return true;
}
#endif // defined(MBED_CONF_RTOS_PRESENT)

View File

@ -152,10 +152,10 @@ void test_emac_memory_cb(int opt)
void test_emac_memory()
{
RESET_ALL_ERROR_FLAGS;
SET_TRACE_LEVEL(TRACE_SEND | TRACE_SUCCESS | TRACE_FAILURE);
SET_TRACE_LEVEL(TRACE_FAILURE);
if (ECHO_SERVER_ADDRESS_KNOWN) {
START_TEST_LOOP(test_emac_memory_cb, 100);
START_TEST_LOOP(test_emac_memory_cb, 100ms);
}
PRINT_ERROR_FLAGS;

View File

@ -45,7 +45,7 @@ void test_emac_multicast_filter_cb(int opt)
case 0:
printf("STEP 0: check unicast message functionality\r\n\r\n");
{
unsigned char *own_addr = emac_if_get_own_addr();
unsigned char const *own_addr = emac_if_get_own_addr();
memcpy(forward_addr, own_addr, 6);
}
receive = true;
@ -165,7 +165,7 @@ void test_emac_multicast_filter()
SET_TRACE_LEVEL(TRACE_SEND | TRACE_ETH_FRAMES | TRACE_SUCCESS | TRACE_FAILURE);
if (ECHO_SERVER_ADDRESS_KNOWN) {
START_TEST_LOOP(test_emac_multicast_filter_cb, 1 * SECOND_TO_MS);
START_TEST_LOOP(test_emac_multicast_filter_cb, 1s);
}
PRINT_ERROR_FLAGS;

View File

@ -69,7 +69,7 @@ void test_emac_unicast()
SET_TRACE_LEVEL(TRACE_SEND | TRACE_ETH_FRAMES | TRACE_SUCCESS | TRACE_FAILURE);
if (ECHO_SERVER_ADDRESS_KNOWN) {
START_TEST_LOOP(test_emac_unicast_cb, 1 * SECOND_TO_MS);
START_TEST_LOOP(test_emac_unicast_cb, 1ms);
}
PRINT_ERROR_FLAGS;

View File

@ -78,7 +78,7 @@ void test_emac_unicast_burst()
SET_TRACE_LEVEL(TRACE_SEND | TRACE_SUCCESS | TRACE_FAILURE);
if (ECHO_SERVER_ADDRESS_KNOWN) {
START_TEST_LOOP(test_emac_unicast_burst_cb, 100);
START_TEST_LOOP(test_emac_unicast_burst_cb, 100ms);
}
PRINT_ERROR_FLAGS;

View File

@ -73,7 +73,7 @@ void test_emac_unicast_frame_len()
SET_TRACE_LEVEL(TRACE_SEND | TRACE_SUCCESS | TRACE_FAILURE);
if (ECHO_SERVER_ADDRESS_KNOWN) {
START_TEST_LOOP(test_emac_unicast_frame_len_cb, 100);
START_TEST_LOOP(test_emac_unicast_frame_len_cb, 100ms);
}
PRINT_ERROR_FLAGS;

View File

@ -75,7 +75,7 @@ void test_emac_unicast_long()
SET_TRACE_LEVEL(TRACE_FAILURE);
if (ECHO_SERVER_ADDRESS_KNOWN) {
START_TEST_LOOP(test_emac_unicast_long_cb, 1);
START_TEST_LOOP(test_emac_unicast_long_cb, 1ms);
}
PRINT_ERROR_FLAGS;

View File

@ -18,40 +18,28 @@
#error [NOT_SUPPORTED] EMAC test cases require a RTOS to run
#else
#if !defined(MBED_CONF_APP_ECHO_SERVER) || \
!defined(MBED_CONF_APP_ECHO_SERVER_TRACE) || \
!defined(MBED_CONF_APP_WIFI_SCAN)
#error [NOT_SUPPORTED] Requires parameters from mbed_app.json
#else
#define ETHERNET 1
#define WIFI 2
#if MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE != ETHERNET && \
MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE != WIFI
#error [NOT_SUPPORTED] Either wifi or ethernet testing need to be enabled
#else
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "emac_tests.h"
#include "emac_util.h"
#include "OnboardNetworkStack.h"
#include "EmacTestNetworkStack.h"
using namespace utest::v1;
// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases)
{
#if !MBED_CONF_APP_ECHO_SERVER
#ifdef MBED_GREENTEA_TEST_EMAC_TIMEOUT_S
GREENTEA_SETUP(MBED_GREENTEA_TEST_EMAC_TIMEOUT_S, "default_auto");
#else
GREENTEA_SETUP(1400, "default_auto");
#endif // #ifdef MBED_GREENTEA_TEST_EMAC_TIMEOUT_S
#endif // #if !MBED_CONF_APP_ECHO_SERVER
return verbose_test_setup_handler(number_of_cases);
}
@ -77,6 +65,10 @@ int main()
return !Harness::run(specification);
}
#endif // (MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE != ETHERNET && MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE != WIFI)
#endif // !defined(MBED_CONF_APP_ECHO_SERVER) || !defined(MBED_CONF_APP_ECHO_SERVER_TRACE) || !defined(MBED_CONF_APP_WIFI_SCAN)
// Override network stack selection to return the EmacTest network stack
OnboardNetworkStack &OnboardNetworkStack::get_default_instance()
{
return EmacTestNetworkStack::get_instance();
}
#endif // !defined(MBED_CONF_RTOS_PRESENT)

View File

@ -0,0 +1,14 @@
add_library(mbed-emac-test-utils STATIC EXCLUDE_FROM_ALL)
target_sources(mbed-emac-test-utils PRIVATE
emac_membuf.cpp
emac_ctp.cpp
emac_util.cpp
EmacTestMemoryManager.cpp
EmacTestNetworkStack.cpp)
target_include_directories(mbed-emac-test-utils PUBLIC .)
target_link_libraries(mbed-emac-test-utils PUBLIC
mbed-core-flags
mbed-rtos-flags
mbed-netsocket-api
mbed-nanostack-libservice
mbed-nanostack-hal_mbed_cmsis_rtos)

View File

@ -21,17 +21,13 @@
#include <list>
#include <stdlib.h>
#include "unity.h"
#include "rtos/Mutex.h"
extern "C" {
#include "arm_hal_interrupt_private.h"
}
#include "nsdynmemLIB.h"
#include "arm_hal_interrupt_private.h"
#include "EMACMemoryManager.h"
#include "emac_TestMemoryManager.h"
#include "EmacTestMemoryManager.h"
#define BUF_HEAD "headheadheadhead"
#define BUF_HEAD_SIZE 16
@ -480,9 +476,9 @@ template <typename TYPE> void EmacTestMemoryManager::check_value(TYPE value, con
if (!value) {
va_list ap;
va_start(ap, fmt);
snprintf(s_trace_buffer + sizeof(MEM_MNGR_TRACE) - 1, sizeof(s_trace_buffer) - sizeof(MEM_MNGR_TRACE) - 1, fmt, ap);
vfprintf(stderr, fmt, ap);
assert(false);
va_end(ap);
TEST_ASSERT_MESSAGE(0, s_trace_buffer);
}
}

View File

@ -0,0 +1,137 @@
/*
* Copyright (c) 2018, ARM Limited, All Rights Reserved
* 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 EMAC_TEST_MEMORY_MANAGER_H
#define EMAC_TEST_MEMORY_MANAGER_H
#include <list>
#include "EMACMemoryManager.h"
#define MEM_CHECK 0x01
#define MEM_NO_ALIGN 0x02
typedef struct emac_memory {
struct emac_memory *next;
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 */
bool first;
} emac_memory_t;
class EmacTestMemoryManager : public EMACMemoryManager {
public:
/**
* Creates emac test memory manager
*/
EmacTestMemoryManager();
/*
* Gets static instance
*/
static EmacTestMemoryManager &get_instance();
emac_mem_buf_t *alloc_heap(uint32_t size, uint32_t align) override;
emac_mem_buf_t *alloc_pool(uint32_t size, uint32_t align) override;
uint32_t get_pool_alloc_unit(uint32_t align) const override;
void free(emac_mem_buf_t *buf) override;
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;
void *get_ptr(const emac_mem_buf_t *buf) const override;
uint32_t get_len(const emac_mem_buf_t *buf) const override;
void set_len(emac_mem_buf_t *buf, uint32_t len) override;
/**
* Allocates memory buffer from the heap
*
* Memory buffer allocated from heap is always contiguous and can be arbitrary size.
*
* @param size Size of the memory to allocate in bytes
* @param align Memory alignment requirement in bytes
* @param opt Options
* @return Allocated memory buffer, or NULL in case of error
*/
emac_mem_buf_t *alloc_heap(uint32_t size, uint32_t align, uint8_t opt);
/**
* Allocates memory buffer chain from a pool
*
* Memory allocated from pool is contiguous if size is equal or less than
* (aligned) allocation unit, otherwise may be chained. Will typically come from
* fixed-size packet pool memory.
*
* @param size Total size of the memory to allocate in bytes
* @param align Memory alignment requirement for each buffer in bytes
* @param opt Options
* @return Allocated memory buffer chain, or NULL in case of error
*/
emac_mem_buf_t *alloc_pool(uint32_t size, uint32_t align, uint8_t opt);
/**
* Sets memory buffer pool allocation unit
*
* Sets the maximum size of contiguous memory that can be allocated from a pool.
*
* @param alloc_unit Contiguous memory size
*/
virtual void set_alloc_unit(uint32_t alloc_unit);
/**
* Sets whether memory is available
*
* Can be used to disable memory allocation request from emac.
*
* @param memory True if memory is available
*/
void set_memory_available(bool memory);
/**
* Gets memory statistics
*
* Gets memory usage statistics
*
* @param buffers Number of buffers that are reserved
* @param memory Reserved memory in bytes
*/
void get_memory_statistics(int *buffers, int *memory);
private:
void validate_list() const;
template <typename TYPE> void check_value(TYPE value, const char *fmt, ...) const;
bool validate_ptr(const emac_mem_buf_t *buf) const;
void check_align(uint32_t align) const;
mutable rtos::Mutex m_mem_mutex;
std::list<emac_memory_t *> m_mem_buffers;
unsigned int m_alloc_unit;
bool m_memory_available;
};
#endif /* EMAC_TEST_MEMORY_MANAGER_H */

View File

@ -14,29 +14,52 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined(MBED_CONF_RTOS_PRESENT)
#include "unity.h"
#include "EMACMemoryManager.h"
#include "emac_TestNetworkStack.h"
#include "emac_initialize.h"
#include "EmacTestNetworkStack.h"
#include "mbed_interface.h"
bool EmacTestNetworkStack::emac_if_init(EMAC *emac)
{
emac->set_link_input_cb(emac_if_link_input_cb);
emac->set_link_state_cb(emac_if_link_state_change_cb);
if (!emac->power_up()) {
printf("emac power up failed!");
return false;
}
int hwaddr_len = emac->get_hwaddr_size();
printf("emac hwaddr length %i\r\n\r\n", hwaddr_len);
if (hwaddr_len != 6) {
printf("invalid emac hwaddr length %d!\n", hwaddr_len);
return false;
}
// If driver updates this, write it back, otherwise write default from mbed_mac_address
mbed_mac_address(reinterpret_cast<char *>(&eth_mac_addr[0]));
emac->get_hwaddr(eth_mac_addr);
emac->set_hwaddr(eth_mac_addr);
printf("emac hwaddr %x:%x:%x:%x:%x:%x\r\n\r\n", eth_mac_addr[0], eth_mac_addr[1], eth_mac_addr[2], eth_mac_addr[3], eth_mac_addr[4], eth_mac_addr[5]);
int mtu_size = emac->get_mtu_size();
printf("emac mtu %i\r\n\r\n", mtu_size);
emac_if_set_mtu_size(mtu_size);
char hw_name[11];
emac->get_ifname(hw_name, 10);
printf("emac if name %s\r\n\r\n", hw_name);
return true;
}
EmacTestNetworkStack::EmacTestNetworkStack()
: m_interface(NULL)
: m_interface(*this)
{
}
nsapi_error_t EmacTestNetworkStack::gethostbyname(const char *host, SocketAddress *address, nsapi_version_t version)
{
return NSAPI_ERROR_OK;
}
nsapi_error_t EmacTestNetworkStack::add_dns_server(const SocketAddress &address)
{
return NSAPI_ERROR_OK;
}
nsapi_error_t EmacTestNetworkStack::call_in(int delay, mbed::Callback<void()> func)
{
@ -117,24 +140,34 @@ void EmacTestNetworkStack::socket_attach(nsapi_socket_t handle, void (*callback)
nsapi_error_t EmacTestNetworkStack::add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out, NetworkInterface *user_network_interface)
{
// Test network stack supports only one interface
TEST_ASSERT_MESSAGE(!m_interface, "Only one interface supported!");
// Only one interface is supported
if (m_interface.m_emac != nullptr) {
return NSAPI_ERROR_UNSUPPORTED;
}
m_interface = &EmacTestNetworkStack::Interface::get_instance();
TEST_ASSERT_MESSAGE(m_interface, "Invalid interface!");
m_interface->m_emac = &emac;
m_interface.m_emac = &emac;
EmacTestMemoryManager *memory_manager = &EmacTestMemoryManager::get_instance();
emac.set_memory_manager(*memory_manager);
*interface_out = m_interface;
*interface_out = &m_interface;
return NSAPI_ERROR_OK;
}
EmacTestNetworkStack::Interface::Interface()
: m_emac(NULL)
EMAC *EmacTestNetworkStack::get_emac()
{
return m_interface.m_emac;
}
unsigned char const *EmacTestNetworkStack::get_mac_addr() const
{
return eth_mac_addr;
}
EmacTestNetworkStack::Interface::Interface(EmacTestNetworkStack &netStack):
m_netStack(netStack),
m_emac(nullptr)
{
}
@ -152,7 +185,7 @@ nsapi_connection_status_t EmacTestNetworkStack::Interface::get_connection_status
char *EmacTestNetworkStack::Interface::get_mac_address(char *buf, nsapi_size_t buflen)
{
return NULL;
return nullptr;
}
nsapi_error_t EmacTestNetworkStack::Interface::set_mac_address(uint8_t *buf, nsapi_size_t buflen)
@ -165,35 +198,20 @@ nsapi_error_t EmacTestNetworkStack::Interface::get_ip_address(SocketAddress *add
return NSAPI_ERROR_OK;
}
char *EmacTestNetworkStack::Interface::get_ip_address(char *buf, nsapi_size_t buflen)
{
return NULL;
}
nsapi_error_t EmacTestNetworkStack::Interface::get_netmask(SocketAddress *address)
{
return NSAPI_ERROR_OK;
}
char *EmacTestNetworkStack::Interface::get_netmask(char *buf, nsapi_size_t buflen)
{
return NULL;
}
nsapi_error_t EmacTestNetworkStack::Interface::get_gateway(SocketAddress *address)
{
return NSAPI_ERROR_OK;
}
char *EmacTestNetworkStack::Interface::get_gateway(char *buf, nsapi_size_t buflen)
{
return NULL;
}
nsapi_error_t EmacTestNetworkStack::Interface::bringup(bool dhcp, const char *ip, const char *netmask, const char *gw, const nsapi_ip_stack_t stack, bool blocking)
{
if (!emac_if_init(m_emac)) {
TEST_ASSERT_MESSAGE(0, "emac initialization failed!");
if (!m_netStack.emac_if_init(m_emac)) {
return NSAPI_ERROR_DEVICE_ERROR;
}
return NSAPI_ERROR_OK;
@ -204,24 +222,8 @@ nsapi_error_t EmacTestNetworkStack::Interface::bringdown()
return NSAPI_ERROR_OK;
}
EmacTestNetworkStack::Interface &EmacTestNetworkStack::Interface::get_instance()
{
static EmacTestNetworkStack::Interface test_interface;
return test_interface;
}
EmacTestNetworkStack &EmacTestNetworkStack::get_instance()
{
static EmacTestNetworkStack test_stack;
return test_stack;
}
#define TEST 0x33254234
#if MBED_CONF_NSAPI_DEFAULT_STACK == TEST
#undef TEST
OnboardNetworkStack &OnboardNetworkStack::get_default_instance()
{
return EmacTestNetworkStack::get_instance();
}
#endif // defined(MBED_CONF_RTOS_PRESENT)
#endif

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 2018, ARM Limited, All Rights Reserved
* 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 EMAC_TEST_NETWORK_STACK_H
#define EMAC_TEST_NETWORK_STACK_H
#include "netsocket/nsapi_types.h"
#include "netsocket/EMAC.h"
#include "netsocket/OnboardNetworkStack.h"
#include "EmacTestMemoryManager.h"
#include "emac_util.h"
class EmacTestNetworkStack : public OnboardNetworkStack, private mbed::NonCopyable<EmacTestNetworkStack> {
unsigned char eth_mac_addr[ETH_MAC_ADDR_LEN];
bool emac_if_init(EMAC *emac);
public:
static EmacTestNetworkStack &get_instance();
EmacTestNetworkStack();
virtual ~EmacTestNetworkStack() {}
class Interface : public OnboardNetworkStack::Interface {
public:
/** Set MAC address on the network interface
*
* @param mac_addr Buffer containing the MAC address in hexadecimal format.
* @param addr_len Length of provided buffer in bytes (6 or 8)
* @retval NSAPI_ERROR_OK on success
* @retval NSAPI_ERROR_UNSUPPORTED if this feature is not supported
* @retval NSAPI_ERROR_PARAMETER if address is not valid
* @retval NSAPI_ERROR_BUSY if address can't be set.
*/
nsapi_error_t set_mac_address(uint8_t *mac_addr, nsapi_size_t addr_len);
nsapi_error_t bringup(bool dhcp, const char *ip,
const char *netmask, const char *gw,
nsapi_ip_stack_t stack,
bool blocking
) override;
nsapi_error_t bringdown() override;
void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb) override;
nsapi_connection_status_t get_connection_status() const override;
char *get_mac_address(char *buf, nsapi_size_t buflen) override;
nsapi_error_t get_ip_address(SocketAddress *address) override;
nsapi_error_t get_netmask(SocketAddress *address) override;
nsapi_error_t get_gateway(SocketAddress *address) override;
private:
friend EmacTestNetworkStack;
explicit Interface(EmacTestNetworkStack &netStack);
EmacTestNetworkStack &m_netStack;
EMAC *m_emac;
};
nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out, NetworkInterface *user_network_interface) override;
/// Get a pointer to the EMAC driver. Will return nullptr if no interface has been added yet.
EMAC *get_emac();
/// Get the MAC address being used for the ethernet port
unsigned char const *get_mac_addr() const;
protected:
nsapi_error_t socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto) override;
nsapi_error_t socket_close(nsapi_socket_t handle) override;
nsapi_error_t socket_bind(nsapi_socket_t handle, const SocketAddress &address) override;
nsapi_error_t socket_listen(nsapi_socket_t handle, int backlog) override;
nsapi_error_t socket_connect(nsapi_socket_t handle, const SocketAddress &address) override;
nsapi_error_t socket_accept(nsapi_socket_t server,
nsapi_socket_t *handle, SocketAddress *address = 0) override;
nsapi_size_or_error_t socket_send(nsapi_socket_t handle,
const void *data, nsapi_size_t size) override;
nsapi_size_or_error_t socket_recv(nsapi_socket_t handle,
void *data, nsapi_size_t size) override;
nsapi_size_or_error_t socket_sendto(nsapi_socket_t handle, const SocketAddress &address,
const void *data, nsapi_size_t size) override;
nsapi_size_or_error_t socket_recvfrom(nsapi_socket_t handle, SocketAddress *address,
void *buffer, nsapi_size_t size) override;
void socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data) override;
nsapi_error_t setsockopt(nsapi_socket_t handle, int level,
int optname, const void *optval, unsigned optlen) override;
nsapi_error_t getsockopt(nsapi_socket_t handle, int level,
int optname, void *optval, unsigned *optlen) override;
private:
call_in_callback_cb_t get_call_in_callback() override;
nsapi_error_t call_in(int delay, mbed::Callback<void()> func) override;
Interface m_interface;
};
#endif /* EMAC_TEST_NETWORK_STACK_H */

View File

@ -0,0 +1,2 @@
# EMAC Test Utils library
This folder contains a testing implementation of a network stack and a memory manager, as well as code for sending and receiving Connection Test Protocol (CTP) packets. It is used in the EMAC test and in the CTP echo server.

View File

@ -14,26 +14,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined(MBED_CONF_RTOS_PRESENT)
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest.h"
#include "mbed.h"
#include "EMAC.h"
#include "EMACMemoryManager.h"
#include "emac_TestMemoryManager.h"
#include "EmacTestMemoryManager.h"
#include "EmacTestNetworkStack.h"
#include "emac_tests.h"
#include "emac_ctp.h"
#include "emac_initialize.h"
#include "emac_util.h"
#include "emac_membuf.h"
using namespace utest::v1;
// Unique identifier for message
static int receipt_number = 0;
@ -64,7 +56,7 @@ static int emac_if_ctp_header_build(unsigned char *eth_frame, const unsigned cha
return receipt_number;
}
ctp_function emac_if_ctp_header_handle(unsigned char *eth_input_frame, unsigned char *eth_output_frame, unsigned char *origin_addr, int *receipt_number)
ctp_function emac_if_ctp_header_handle(unsigned char *eth_input_frame, unsigned char *eth_output_frame, unsigned char const *origin_addr, int *receipt_number)
{
if (eth_input_frame[12] != 0x90 || eth_input_frame[13] != 0x00) {
return CTP_NONE;
@ -123,10 +115,10 @@ void emac_if_ctp_msg_build(int eth_frame_len, const unsigned char *dest_addr, co
emac_mem_buf_t *buf;
if (options & CTP_OPT_HEAP) {
buf = emac_m_mngr_get()->alloc_heap(eth_frame_len, align, alloc_opt);
buf = EmacTestMemoryManager::get_instance().alloc_heap(eth_frame_len, align, alloc_opt);
} else {
// Default allocation is from pool
buf = emac_m_mngr_get()->alloc_pool(eth_frame_len, align, alloc_opt);
buf = EmacTestMemoryManager::get_instance().alloc_pool(eth_frame_len, align, alloc_opt);
}
if (!buf) {
@ -146,7 +138,6 @@ void emac_if_ctp_msg_build(int eth_frame_len, const unsigned char *dest_addr, co
emac_if_memory_buffer_write(buf, eth_output_frame_data, true);
emac_if_check_memory(true);
emac_if_get()->link_out(buf);
EmacTestNetworkStack::get_instance().get_emac()->link_out(buf);
emac_if_check_memory(false);
}
#endif // defined(MBED_CONF_RTOS_PRESENT)

View File

@ -34,7 +34,7 @@ enum ctp_function {
#define CTP_MSG_SEND(length, send_to_address, own_address, forward_to_address, mem_mngr_options) \
emac_if_ctp_msg_build(length, send_to_address, own_address, forward_to_address, mem_mngr_options)
ctp_function emac_if_ctp_header_handle(unsigned char *eth_input_frame, unsigned char *eth_output_frame, unsigned char *origin_addr, int *receipt_number);
ctp_function emac_if_ctp_header_handle(unsigned char *eth_input_frame, unsigned char *eth_output_frame, unsigned char const *origin_addr, int *receipt_number);
void emac_if_ctp_msg_build(int eth_frame_len, const unsigned char *dest_addr, const unsigned char *origin_addr, const unsigned char *forward_addr, int options);
void emac_if_ctp_reply_handle(int lenght, int invalid_data_index);

View File

@ -17,17 +17,13 @@
#if defined(MBED_CONF_RTOS_PRESENT)
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "mbed.h"
#include "EMAC.h"
#include "EMACMemoryManager.h"
#include "emac_TestMemoryManager.h"
#include "EmacTestMemoryManager.h"
#include "emac_initialize.h"
#include "emac_membuf.h"
#include "emac_util.h"
@ -36,9 +32,9 @@ int emac_if_memory_buffer_read(void *buf, unsigned char *eth_frame)
int eth_frame_index = 0;
int invalid_data_index = 0;
for (emac_mem_buf_t *mem_buf = buf; mem_buf != NULL; mem_buf = emac_m_mngr_get()->get_next(mem_buf)) {
unsigned char *buf_payload = (unsigned char *) emac_m_mngr_get()->get_ptr(mem_buf);
int buf_payload_len = emac_m_mngr_get()->get_len(mem_buf);
for (emac_mem_buf_t *mem_buf = buf; mem_buf != NULL; mem_buf = EmacTestMemoryManager::get_instance().get_next(mem_buf)) {
unsigned char *buf_payload = (unsigned char *) EmacTestMemoryManager::get_instance().get_ptr(mem_buf);
int buf_payload_len = EmacTestMemoryManager::get_instance().get_len(mem_buf);
for (int index = 0; index < buf_payload_len; index++) {
if (eth_frame_index < ETH_FRAME_HEADER_LEN) {
@ -60,9 +56,9 @@ void emac_if_memory_buffer_write(void *buf, unsigned char *eth_frame, bool write
{
int eth_frame_index = 0;
for (emac_mem_buf_t *mem_buf = buf; mem_buf != NULL; mem_buf = emac_m_mngr_get()->get_next(mem_buf)) {
unsigned char *buf_payload = (unsigned char *) emac_m_mngr_get()->get_ptr(mem_buf);
int buf_payload_len = emac_m_mngr_get()->get_len(mem_buf);
for (emac_mem_buf_t *mem_buf = buf; mem_buf != NULL; mem_buf = EmacTestMemoryManager::get_instance().get_next(mem_buf)) {
unsigned char *buf_payload = (unsigned char *) EmacTestMemoryManager::get_instance().get_ptr(mem_buf);
int buf_payload_len = EmacTestMemoryManager::get_instance().get_len(mem_buf);
for (int index = 0; index < buf_payload_len; index++) {
if (eth_frame_index < ETH_FRAME_HEADER_LEN) {

View File

@ -14,38 +14,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined(MBED_CONF_RTOS_PRESENT)
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "mbed.h"
#include "EMAC.h"
#include "EMACMemoryManager.h"
#include "emac_TestMemoryManager.h"
#include "EmacTestMemoryManager.h"
#include "EmacTestNetworkStack.h"
#include "emac_tests.h"
#include "emac_initialize.h"
#include "emac_util.h"
#include "emac_membuf.h"
#include "emac_ctp.h"
using namespace utest::v1;
/* For LPC boards define the memory bank ourselves to give us section placement
control */
#ifndef ETHMEM_SECTION
#if defined(TARGET_LPC1768)
# if defined (__ICCARM__)
# define ETHMEM_SECTION
# elif defined(TOOLCHAIN_GCC_CR)
# define ETHMEM_SECTION __attribute__((section(".data.$RamPeriph32")))
# else
# define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned))
# endif
#define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned))
#endif
#endif
@ -108,6 +93,8 @@ static unsigned int error_flags = 0;
static unsigned int no_response_cnt = 0;
static bool link_up = false;
static bool ctp_server_mode = false;
int emac_if_find_outgoing_msg(int receipt_number)
{
for (int i = 0; i < OUTGOING_MSG_COUNT; i++) {
@ -376,12 +363,12 @@ void emac_if_trace_to_ascii_hex_dump(const char *prefix, int len, unsigned char
void emac_if_set_all_multicast(bool all)
{
emac_if_get()->set_all_multicast(all);
EmacTestNetworkStack::get_instance().get_emac()->set_all_multicast(all);
}
void emac_if_add_multicast_group(uint8_t *address)
{
emac_if_get()->add_multicast_group(address);
EmacTestNetworkStack::get_instance().get_emac()->add_multicast_group(address);
}
void emac_if_set_output_memory(bool memory)
@ -410,8 +397,7 @@ void emac_if_set_memory(bool memory)
static bool memory_value = true;
if (memory_value != memory) {
memory_value = memory;
EmacTestMemoryManager *mem_mngr = emac_m_mngr_get();
mem_mngr->set_memory_available(memory);
EmacTestMemoryManager::get_instance().set_memory_available(memory);
}
}
@ -428,18 +414,18 @@ void emac_if_link_input_cb(void *buf)
{
if (link_input_event.post(buf) == 0) {
if (buf) {
emac_m_mngr_get()->free(buf);
EmacTestMemoryManager::get_instance().free(buf);
}
}
}
static void link_input_event_cb(void *buf)
{
int length = emac_m_mngr_get()->get_total_len(buf);
int length = EmacTestMemoryManager::get_instance().get_total_len(buf);
if (length >= ETH_FRAME_HEADER_LEN) {
// Ethernet input frame
unsigned char eth_input_frame_data[ETH_FRAME_HEADER_LEN];
static unsigned char eth_input_frame_data[ETH_FRAME_HEADER_LEN];
memset(eth_input_frame_data, 0, ETH_FRAME_HEADER_LEN);
int invalid_data_index = emac_if_memory_buffer_read(buf, eth_input_frame_data);
@ -448,7 +434,7 @@ static void link_input_event_cb(void *buf)
unsigned char eth_output_frame_data[ETH_FRAME_HEADER_LEN];
int receipt_number;
ctp_function function = emac_if_ctp_header_handle(eth_input_frame_data, eth_output_frame_data, emac_if_get_hw_addr(), &receipt_number);
ctp_function function = emac_if_ctp_header_handle(eth_input_frame_data, eth_output_frame_data, EmacTestNetworkStack::get_instance().get_mac_addr(), &receipt_number);
if (function == CTP_REPLY) {
// If reply has valid receipt number
@ -462,13 +448,12 @@ static void link_input_event_cb(void *buf)
// Calls test loop
worker_loop_event_queue.call(current_test_step_cb_fnc, INPUT);
}
#if MBED_CONF_APP_ECHO_SERVER
// Echoes only if configured as echo server
} else if (function == CTP_FORWARD) {
}
// Echoes only if configured as echo server
else if (function == CTP_FORWARD && ctp_server_mode) {
emac_if_memory_buffer_write(buf, eth_output_frame_data, false);
emac_if_get()->link_out(buf);
buf = 0;
#endif
EmacTestNetworkStack::get_instance().get_emac()->link_out(buf);
buf = nullptr;
}
emac_if_add_echo_server_addr(&eth_input_frame_data[6]);
@ -482,7 +467,7 @@ static void link_input_event_cb(void *buf)
}
if (buf) {
emac_m_mngr_get()->free(buf);
EmacTestMemoryManager::get_instance().free(buf);
}
}
@ -508,24 +493,24 @@ void worker_loop_init(void)
}
}
void worker_loop_start(void (*test_step_cb_fnc)(int opt), int timeout)
void worker_loop_start(void (*test_step_cb_fnc)(int opt), std::chrono::milliseconds poll_rate, bool loop_forever)
{
current_test_step_cb_fnc = test_step_cb_fnc;
int test_step_cb_timer = worker_loop_event_queue.call_every(timeout, test_step_cb_fnc, TIMEOUT);
int timeout_outgoing_msg_timer = worker_loop_event_queue.call_every(1000, emac_if_timeout_outgoing_msg);
int test_step_cb_timer = worker_loop_event_queue.call_every(poll_rate, test_step_cb_fnc, TIMEOUT);
int timeout_outgoing_msg_timer = worker_loop_event_queue.call_every(1000ms, emac_if_timeout_outgoing_msg);
int validate_outgoing_msg_timer = 0;
if (timeout > 500) {
if (poll_rate > 500ms) {
// For long test step callback timeouts validates messages also between callback timeouts
validate_outgoing_msg_timer = worker_loop_event_queue.call_every(200, emac_if_validate_outgoing_msg);
validate_outgoing_msg_timer = worker_loop_event_queue.call_every(200ms, emac_if_validate_outgoing_msg);
}
#if MBED_CONF_APP_ECHO_SERVER
worker_loop_semaphore.acquire();
#else
worker_loop_semaphore.try_acquire_for(600 * SECOND_TO_MS);
#endif
if (loop_forever) {
worker_loop_semaphore.acquire();
} else {
worker_loop_semaphore.try_acquire_for(600s);
}
worker_loop_event_queue.cancel(test_step_cb_timer);
worker_loop_event_queue.cancel(timeout_outgoing_msg_timer);
@ -565,9 +550,9 @@ void worker_loop(void)
worker_loop_event_queue.dispatch_forever();
}
unsigned char *emac_if_get_own_addr(void)
unsigned char const *emac_if_get_own_addr(void)
{
return (emac_if_get_hw_addr());
return EmacTestNetworkStack::get_instance().get_mac_addr();
}
int emac_if_get_mtu_size()
@ -579,4 +564,8 @@ void emac_if_set_mtu_size(int mtu_size)
{
eth_mtu_size = mtu_size;
}
#endif // defined(MBED_CONF_RTOS_PRESENT)
void emac_if_set_ctp_server_enabled(bool enabled)
{
ctp_server_mode = enabled;
}

View File

@ -18,9 +18,8 @@
#ifndef EMAC_UTIL_H
#define EMAC_UTIL_H
#define SECOND_TO_US 1000000
#define SECOND_TO_MS 1000
#define MS_TO_US 1000
#include <cstdint>
#include <chrono>
extern const unsigned char eth_mac_broadcast_addr[];
@ -102,7 +101,7 @@ char emac_if_get_trace_level();
void emac_if_trace_to_ascii_hex_dump(const char *prefix, int len, char *data);
unsigned char *emac_if_get_own_addr(void);
unsigned char const *emac_if_get_own_addr(void);
int emac_if_get_mtu_size();
void emac_if_set_mtu_size(int mtu_size);
@ -118,8 +117,10 @@ void emac_if_set_input_memory(bool memory);
void emac_if_check_memory(bool output);
void emac_if_set_memory(bool memory);
void emac_if_set_ctp_server_enabled(bool enabled);
void worker_loop_init(void);
void worker_loop_start(void (*test_step_cb_fnc)(int opt), int timeout);
void worker_loop_start(void (*test_step_cb_fnc)(int opt), std::chrono::milliseconds poll_rate, bool loop_forever = false);
void worker_loop_end(void);
void worker_loop_link_up_wait(void);

12
run-formatter.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
# Copyright (c) 2024 Jamie Smith
# SPDX-License-Identifier: Apache-2.0
# Script to run the Astyle formatter on the Mbed OS code base.
# Run before submitting code changes!
git diff --name-only --diff-filter=d origin/master \
| ( grep '.*\.\(c\|cpp\|h\|hpp\)$' || true ) \
| ( grep -v -f .codecheckignore || true ) \
| while read file; do astyle -n --options=.astylerc "${file}"; done

View File

@ -66,11 +66,12 @@ set(MBED_GDB_PORT 23331 CACHE STRING "Port that the GDB server will be started o
set(MBED_UPLOAD_SERIAL_NUMBER "" CACHE STRING "Serial number of the Mbed board or the programming tool, for upload methods that select by serial number.")
# Handle legacy per-upload-method aliases for the upload serial number
foreach(LEGACY_VAR_NAME JLINK_USB_SERIAL_NUMBER LINKSERVER_PROBE_SN MBED_TARGET_UID OPENOCD_ADAPTER_SERIAL PYOCD_PROBE_UID STLINK_SERIAL_ARGUMENT STM32CUBE_PROBE_SN)
foreach(LEGACY_VAR_NAME JLINK_USB_SERIAL_NUMBER LINKSERVER_PROBE_SN MBED_TARGET_UID OPENOCD_ADAPTER_SERIAL PYOCD_PROBE_UID STLINK_PROBE_SN STM32CUBE_PROBE_SN)
if(DEFINED ${LEGACY_VAR_NAME})
if(NOT "${${LEGACY_VAR_NAME}}" STREQUAL "")
message(WARNING "${LEGACY_VAR_NAME} is deprecated, set the MBED_UPLOAD_SERIAL_NUMBER variable instead. MBED_UPLOAD_SERIAL_NUMBER will be set to the value of ${LEGACY_VAR_NAME}.")
set(MBED_UPLOAD_SERIAL_NUMBER ${${LEGACY_VAR_NAME}} CACHE STRING "" FORCE)
unset(STLINK_PROBE_SN CACHE)
endif()
endif()
endforeach()

View File

@ -99,7 +99,7 @@ class MemoryBankInfo:
class _Parser(ABC):
"""Internal interface for parsing"""
SECTIONS = ('.text', '.data', '.bss', '.heap', '.stack')
SECTIONS = ('.text', '.data', '.bss', '.heap', '.heap_0', '.stack')
MISC_FLASH_SECTIONS = ('.interrupts', '.flash_config')
OTHER_SECTIONS = ('.interrupts_ram', '.init', '.ARM.extab',
'.ARM.exidx', '.ARM.attributes', '.eh_frame',