Remove LWIP tests

pull/5268/head
Sarah Marsh 2017-08-04 16:31:55 -05:00 committed by adbridge
parent 174ed07013
commit 4da41d7fb8
16 changed files with 0 additions and 2841 deletions

View File

@ -1 +0,0 @@
host_tests/*

View File

@ -1,82 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* 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.
*/
#if !FEATURE_LWIP
#error [NOT_SUPPORTED] LWIP not supported for this target
#endif
#if DEVICE_EMAC
#error [NOT_SUPPORTED] Not supported for WiFi targets
#endif
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "EthernetInterface.h"
using namespace utest::v1;
// Bringing the network up and down
template <int COUNT>
void test_bring_up_down() {
EthernetInterface eth;
for (int i = 0; i < COUNT; i++) {
int err = eth.connect();
TEST_ASSERT_EQUAL(0, err);
printf("MBED: IP Address %s\r\n", eth.get_ip_address());
printf("MBED: Netmask %s\r\n", eth.get_netmask());
printf("MBED: Gateway %s\r\n", eth.get_gateway());
TEST_ASSERT(eth.get_ip_address());
TEST_ASSERT(eth.get_netmask());
TEST_ASSERT(eth.get_gateway());
UDPSocket udp;
err = udp.open(&eth);
TEST_ASSERT_EQUAL(0, err);
err = udp.close();
TEST_ASSERT_EQUAL(0, err);
TCPSocket tcp;
err = tcp.open(&eth);
TEST_ASSERT_EQUAL(0, err);
err = tcp.close();
TEST_ASSERT_EQUAL(0, err);
err = eth.disconnect();
TEST_ASSERT_EQUAL(0, err);
}
}
// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases) {
GREENTEA_SETUP(120, "default_auto");
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("Bringing the network up and down", test_bring_up_down<1>),
Case("Bringing the network up and down twice", test_bring_up_down<2>),
};
Specification specification(test_setup, cases);
int main() {
return !Harness::run(specification);
}

View File

@ -1,125 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* 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.
*/
#if !FEATURE_LWIP
#error [NOT_SUPPORTED] LWIP not supported for this target
#endif
#if DEVICE_EMAC
#error [NOT_SUPPORTED] Not supported for WiFi targets
#endif
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "EthernetInterface.h"
using namespace utest::v1;
// Hostname for testing against
// Must have A and AAAA records
#ifndef MBED_DNS_TEST_HOST
#define MBED_DNS_TEST_HOST "connector.mbed.com"
#endif
// Address info from stack
const char *ip_literal;
nsapi_version_t ip_pref;
const char *ip_pref_repr;
// Network setup
EthernetInterface net;
void net_bringup() {
int err = net.connect();
TEST_ASSERT_EQUAL(0, err);
printf("MBED: Connected to network\n");
printf("MBED: IP Address: %s\n", net.get_ip_address());
ip_literal = net.get_ip_address();
ip_pref = SocketAddress(ip_literal).get_ip_version();
ip_pref_repr = (ip_pref == NSAPI_IPv4) ? "ipv4" :
(ip_pref == NSAPI_IPv6) ? "ipv6" : "unspec";
}
// DNS tests
void test_dns_query() {
SocketAddress addr;
int err = net.gethostbyname(MBED_DNS_TEST_HOST, &addr);
printf("DNS: query \"%s\" => \"%s\"\n",
MBED_DNS_TEST_HOST, addr.get_ip_address());
TEST_ASSERT_EQUAL(0, err);
TEST_ASSERT((bool)addr);
TEST_ASSERT(strlen(addr.get_ip_address()) > 1);
}
void test_dns_query_pref() {
SocketAddress addr;
int err = net.gethostbyname(MBED_DNS_TEST_HOST, &addr, ip_pref);
printf("DNS: query %s \"%s\" => \"%s\"\n",
ip_pref_repr, MBED_DNS_TEST_HOST, addr.get_ip_address());
TEST_ASSERT_EQUAL(0, err);
TEST_ASSERT((bool)addr);
TEST_ASSERT(strlen(addr.get_ip_address()) > 1);
TEST_ASSERT_EQUAL(ip_pref, addr.get_ip_version());
}
void test_dns_literal() {
SocketAddress addr;
int err = net.gethostbyname(ip_literal, &addr);
printf("DNS: literal \"%s\" => \"%s\"\n",
ip_literal, addr.get_ip_address());
TEST_ASSERT_EQUAL(0, err);
TEST_ASSERT((bool)addr);
TEST_ASSERT(strlen(addr.get_ip_address()) > 1);
TEST_ASSERT(strcmp(ip_literal, addr.get_ip_address()) == 0);
}
void test_dns_literal_pref() {
SocketAddress addr;
int err = net.gethostbyname(ip_literal, &addr, ip_pref);
printf("DNS: literal %s \"%s\" => \"%s\"\n",
ip_pref_repr, ip_literal, addr.get_ip_address());
TEST_ASSERT_EQUAL(0, err);
TEST_ASSERT((bool)addr);
TEST_ASSERT(strlen(addr.get_ip_address()) > 1);
TEST_ASSERT_EQUAL(ip_pref, addr.get_ip_version());
TEST_ASSERT(strcmp(ip_literal, addr.get_ip_address()) == 0);
}
// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases) {
GREENTEA_SETUP(120, "default_auto");
net_bringup();
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("DNS query", test_dns_query),
Case("DNS preference query", test_dns_query_pref),
Case("DNS literal", test_dns_literal),
Case("DNS preference literal", test_dns_literal_pref),
};
Specification specification(test_setup, cases);
int main() {
return !Harness::run(specification);
}

View File

@ -1,195 +0,0 @@
# Copyright 2015 ARM Limited, All rights reserved
#
# 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.
import sys
import select
import socket
import logging
from threading import Thread
from sys import stdout
from SocketServer import BaseRequestHandler, TCPServer
from mbed_host_tests import BaseHostTest, event_callback
class TCPEchoClientHandler(BaseRequestHandler):
def handle(self):
"""
Handles a connection. Test starts by client(i.e. mbed) connecting to server.
This connection handler receives data and echoes back to the client util
{{end}} is received. Then it sits on recv() for client to terminate the
connection.
Note: reason for not echoing data back after receiving {{end}} is that send
fails raising a SocketError as client closes connection.
"""
while self.server.isrunning():
try:
data = self.recv()
if not data: break
except Exception as e:
break
try:
# echo data back to the client
self.send(data)
except Exception as e:
break
def recv(self):
"""
Try to receive until server is shutdown
"""
while self.server.isrunning():
rl, wl, xl = select.select([self.request], [], [], 1)
if len(rl):
return self.request.recv(1024)
def send(self, data):
"""
Try to send until server is shutdown
"""
while self.server.isrunning():
rl, wl, xl = select.select([], [self.request], [], 1)
if len(wl):
self.request.sendall(data)
break
class TCPServerWrapper(TCPServer):
"""
Wrapper over TCP server to implement server initiated shutdown.
Adds a flag:= running that a request handler can check and come out of
recv loop when shutdown is called.
"""
def __init__(self, addr, request_handler):
# hmm, TCPServer is not sub-classed from object!
if issubclass(TCPServer, object):
super(TCPServerWrapper, self).__init__(addr, request_handler)
else:
TCPServer.__init__(self, addr, request_handler)
self.running = False
def serve_forever(self):
self.running = True
if issubclass(TCPServer, object):
super(TCPServerWrapper, self).serve_forever()
else:
TCPServer.serve_forever(self)
def shutdown(self):
self.running = False
if issubclass(TCPServer, object):
super(TCPServerWrapper, self).shutdown()
else:
TCPServer.shutdown(self)
def isrunning(self):
return self.running
class TCPEchoClientTest(BaseHostTest):
def __init__(self):
"""
Initialise test parameters.
:return:
"""
BaseHostTest.__init__(self)
self.SERVER_IP = None # Will be determined after knowing the target IP
self.SERVER_PORT = 0 # Let TCPServer choose an arbitrary port
self.server = None
self.server_thread = None
self.target_ip = None
@staticmethod
def find_interface_to_target_addr(target_ip):
"""
Finds IP address of the interface through which it is connected to the target.
:return:
"""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.connect((target_ip, 0)) # Target IP, any port
except socket.error:
s.connect((target_ip, 8000)) # Target IP, 'random' port
ip = s.getsockname()[0]
s.close()
return ip
def setup_tcp_server(self):
"""
sets up a TCP server for target to connect and send test data.
:return:
"""
# !NOTE: There should mechanism to assert in the host test
if self.SERVER_IP is None:
self.log("setup_tcp_server() called before determining server IP!")
self.notify_complete(False)
# Returning none will suppress host test from printing success code
self.server = TCPServerWrapper((self.SERVER_IP, self.SERVER_PORT), TCPEchoClientHandler)
ip, port = self.server.server_address
self.SERVER_PORT = port
self.server.allow_reuse_address = True
self.log("HOST: Listening for TCP connections: " + self.SERVER_IP + ":" + str(self.SERVER_PORT))
self.server_thread = Thread(target=TCPEchoClientTest.server_thread_func, args=(self,))
self.server_thread.start()
@staticmethod
def server_thread_func(this):
"""
Thread function to run TCP server forever.
:param this:
:return:
"""
this.server.serve_forever()
@event_callback("target_ip")
def _callback_target_ip(self, key, value, timestamp):
"""
Callback to handle reception of target's IP address.
:param key:
:param value:
:param timestamp:
:return:
"""
self.target_ip = value
self.SERVER_IP = self.find_interface_to_target_addr(self.target_ip)
self.setup_tcp_server()
@event_callback("host_ip")
def _callback_host_ip(self, key, value, timestamp):
"""
Callback for request for host IP Addr
"""
self.send_kv("host_ip", self.SERVER_IP)
@event_callback("host_port")
def _callback_host_port(self, key, value, timestamp):
"""
Callback for request for host port
"""
self.send_kv("host_port", self.SERVER_PORT)
def teardown(self):
if self.server:
self.server.shutdown()
self.server_thread.join()

View File

@ -1,127 +0,0 @@
"""
mbed SDK
Copyright (c) 2011-2013 ARM Limited
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.
"""
import sys
import socket
from sys import stdout
from threading import Thread
from SocketServer import BaseRequestHandler, UDPServer
from mbed_host_tests import BaseHostTest, event_callback
class UDPEchoClientHandler(BaseRequestHandler):
def handle(self):
""" UDP packet handler. Echoes data back to sender's address.
"""
data, sock = self.request
sock.sendto(data, self.client_address)
class UDPEchoClientTest(BaseHostTest):
def __init__(self):
"""
Initialise test parameters.
:return:
"""
BaseHostTest.__init__(self)
self.SERVER_IP = None # Will be determined after knowing the target IP
self.SERVER_PORT = 0 # Let TCPServer choose an arbitrary port
self.server = None
self.server_thread = None
self.target_ip = None
@staticmethod
def find_interface_to_target_addr(target_ip):
"""
Finds IP address of the interface through which it is connected to the target.
:return:
"""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.connect((target_ip, 0)) # Target IP, any port
except socket.error:
s.connect((target_ip, 8000)) # Target IP, 'random' port
ip = s.getsockname()[0]
s.close()
return ip
def setup_udp_server(self):
"""
sets up a UDP server for target to connect and send test data.
:return:
"""
# !NOTE: There should mechanism to assert in the host test
if self.SERVER_IP is None:
self.log("setup_udp_server() called before determining server IP!")
self.notify_complete(False)
# Returning none will suppress host test from printing success code
self.server = UDPServer((self.SERVER_IP, self.SERVER_PORT), UDPEchoClientHandler)
ip, port = self.server.server_address
self.SERVER_PORT = port
self.server.allow_reuse_address = True
self.log("HOST: Listening for UDP packets: " + self.SERVER_IP + ":" + str(self.SERVER_PORT))
self.server_thread = Thread(target=UDPEchoClientTest.server_thread_func, args=(self,))
self.server_thread.start()
@staticmethod
def server_thread_func(this):
"""
Thread function to run TCP server forever.
:param this:
:return:
"""
this.server.serve_forever()
@event_callback("target_ip")
def _callback_target_ip(self, key, value, timestamp):
"""
Callback to handle reception of target's IP address.
:param key:
:param value:
:param timestamp:
:return:
"""
self.target_ip = value
self.SERVER_IP = self.find_interface_to_target_addr(self.target_ip)
self.setup_udp_server()
@event_callback("host_ip")
def _callback_host_ip(self, key, value, timestamp):
"""
Callback for request for host IP Addr
"""
self.send_kv("host_ip", self.SERVER_IP)
@event_callback("host_port")
def _callback_host_port(self, key, value, timestamp):
"""
Callback for request for host port
"""
self.send_kv("host_port", self.SERVER_PORT)
def teardown(self):
if self.server:
self.server.shutdown()
self.server_thread.join()

View File

@ -1,142 +0,0 @@
"""
mbed SDK
Copyright (c) 2011-2013 ARM Limited
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.
"""
import sys
import socket
import json
import random
import itertools
import time
from sys import stdout
from threading import Thread
from SocketServer import BaseRequestHandler, UDPServer
from mbed_host_tests import BaseHostTest, event_callback
class UDPEchoClientHandler(BaseRequestHandler):
def handle(self):
""" UDP packet handler. Responds with multiple simultaneous packets
"""
data, sock = self.request
pattern = [ord(d) << 4 for d in data]
# Each byte in request indicates size of packet to recieve
# Each packet size is shifted over by 4 to fit in a byte, which
# avoids any issues with endianess or decoding
for packet in pattern:
data = [random.randint(0, 255) for _ in range(packet-1)]
data.append(reduce(lambda a,b: a^b, data))
data = ''.join(map(chr, data))
sock.sendto(data, self.client_address)
# Sleep a tiny bit to compensate for local network
time.sleep(0.01)
class UDPEchoClientTest(BaseHostTest):
def __init__(self):
"""
Initialise test parameters.
:return:
"""
BaseHostTest.__init__(self)
self.SERVER_IP = None # Will be determined after knowing the target IP
self.SERVER_PORT = 0 # Let TCPServer choose an arbitrary port
self.server = None
self.server_thread = None
self.target_ip = None
@staticmethod
def find_interface_to_target_addr(target_ip):
"""
Finds IP address of the interface through which it is connected to the target.
:return:
"""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.connect((target_ip, 0)) # Target IP, any port
except socket.error:
s.connect((target_ip, 8000)) # Target IP, 'random' port
ip = s.getsockname()[0]
s.close()
return ip
def setup_udp_server(self):
"""
sets up a UDP server for target to connect and send test data.
:return:
"""
# !NOTE: There should mechanism to assert in the host test
if self.SERVER_IP is None:
self.log("setup_udp_server() called before determining server IP!")
self.notify_complete(False)
# Returning none will suppress host test from printing success code
self.server = UDPServer((self.SERVER_IP, self.SERVER_PORT), UDPEchoClientHandler)
ip, port = self.server.server_address
self.SERVER_PORT = port
self.server.allow_reuse_address = True
self.log("HOST: Listening for UDP packets: " + self.SERVER_IP + ":" + str(self.SERVER_PORT))
self.server_thread = Thread(target=UDPEchoClientTest.server_thread_func, args=(self,))
self.server_thread.start()
@staticmethod
def server_thread_func(this):
"""
Thread function to run TCP server forever.
:param this:
:return:
"""
this.server.serve_forever()
@event_callback("target_ip")
def _callback_target_ip(self, key, value, timestamp):
"""
Callback to handle reception of target's IP address.
:param key:
:param value:
:param timestamp:
:return:
"""
self.target_ip = value
self.SERVER_IP = self.find_interface_to_target_addr(self.target_ip)
self.setup_udp_server()
@event_callback("host_ip")
def _callback_host_ip(self, key, value, timestamp):
"""
Callback for request for host IP Addr
"""
self.send_kv("host_ip", self.SERVER_IP)
@event_callback("host_port")
def _callback_host_port(self, key, value, timestamp):
"""
Callback for request for host port
"""
self.send_kv("host_port", self.SERVER_PORT)
def teardown(self):
if self.server:
self.server.shutdown()
self.server_thread.join()

View File

@ -1,118 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* 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.
*/
#if !FEATURE_LWIP
#error [NOT_SUPPORTED] LWIP not supported for this target
#endif
#if DEVICE_EMAC
#error [NOT_SUPPORTED] Not supported for WiFi targets
#endif
#include "mbed.h"
#include "EthernetInterface.h"
#include "TCPSocket.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest.h"
using namespace utest::v1;
#ifndef MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE
#define MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE 256
#endif
namespace {
char tx_buffer[MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE] = {0};
char rx_buffer[MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE] = {0};
const char ASCII_MAX = '~' - ' ';
}
void prep_buffer(char *tx_buffer, size_t tx_size) {
for (size_t i=0; i<tx_size; ++i) {
tx_buffer[i] = (rand() % 10) + '0';
}
}
void test_tcp_echo() {
EthernetInterface eth;
int err = eth.connect();
if (err) {
printf("MBED: failed to connect with an error of %d\r\n", err);
TEST_ASSERT_EQUAL(0, err);
}
printf("MBED: TCPClient IP address is '%s'\n", eth.get_ip_address());
printf("MBED: TCPClient waiting for server IP and port...\n");
greentea_send_kv("target_ip", eth.get_ip_address());
bool result = false;
char recv_key[] = "host_port";
char ipbuf[60] = {0};
char portbuf[16] = {0};
unsigned int port = 0;
greentea_send_kv("host_ip", " ");
greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf));
greentea_send_kv("host_port", " ");
greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf));
sscanf(portbuf, "%u", &port);
printf("MBED: Server IP address received: %s:%d \n", ipbuf, port);
TCPSocket sock(&eth);
SocketAddress tcp_addr(ipbuf, port);
if (sock.connect(tcp_addr) == 0) {
printf("HTTP: Connected to %s:%d\r\n", ipbuf, port);
printf("tx_buffer buffer size: %u\r\n", sizeof(tx_buffer));
printf("rx_buffer buffer size: %u\r\n", sizeof(rx_buffer));
prep_buffer(tx_buffer, sizeof(tx_buffer));
sock.send(tx_buffer, sizeof(tx_buffer));
printf("MBED: Finished sending\r\n");
// Server will respond with HTTP GET's success code
const int ret = sock.recv(rx_buffer, sizeof(rx_buffer));
printf("MBED: Finished receiving\r\n");
result = !memcmp(tx_buffer, rx_buffer, sizeof(tx_buffer));
TEST_ASSERT_EQUAL(ret, sizeof(rx_buffer));
TEST_ASSERT(result);
}
sock.close();
eth.disconnect();
TEST_ASSERT(result);
}
// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases) {
GREENTEA_SETUP(120, "tcp_echo");
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("TCP echo", test_tcp_echo),
};
Specification specification(test_setup, cases);
int main() {
return !Harness::run(specification);
}

View File

@ -1,160 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* 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.
*/
#if !FEATURE_LWIP
#error [NOT_SUPPORTED] LWIP not supported for this target
#endif
#if DEVICE_EMAC
#error [NOT_SUPPORTED] Not supported for WiFi targets
#endif
#include "mbed.h"
#include "EthernetInterface.h"
#include "TCPSocket.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest.h"
using namespace utest::v1;
#ifndef MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE
#define MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE 64
#endif
#ifndef MBED_CFG_TCP_CLIENT_ECHO_THREADS
#define MBED_CFG_TCP_CLIENT_ECHO_THREADS 3
#endif
EthernetInterface net;
SocketAddress tcp_addr;
Mutex iomutex;
void prep_buffer(char *tx_buffer, size_t tx_size) {
for (size_t i=0; i<tx_size; ++i) {
tx_buffer[i] = (rand() % 10) + '0';
}
}
// Each echo class is in charge of one parallel transaction
class Echo {
private:
char tx_buffer[MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE];
char rx_buffer[MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE];
TCPSocket sock;
Thread thread;
public:
// Limiting stack size to 1k
Echo(): thread(osPriorityNormal, 1024) {
}
void start() {
osStatus status = thread.start(callback(this, &Echo::echo));
TEST_ASSERT_EQUAL(osOK, status);
}
void join() {
osStatus status = thread.join();
TEST_ASSERT_EQUAL(osOK, status);
}
void echo() {
int err = sock.open(&net);
TEST_ASSERT_EQUAL(0, err);
err = sock.connect(tcp_addr);
TEST_ASSERT_EQUAL(0, err);
iomutex.lock();
printf("HTTP: Connected to %s:%d\r\n",
tcp_addr.get_ip_address(), tcp_addr.get_port());
printf("tx_buffer buffer size: %u\r\n", sizeof(tx_buffer));
printf("rx_buffer buffer size: %u\r\n", sizeof(rx_buffer));
iomutex.unlock();
prep_buffer(tx_buffer, sizeof(tx_buffer));
sock.send(tx_buffer, sizeof(tx_buffer));
// Server will respond with HTTP GET's success code
const int ret = sock.recv(rx_buffer, sizeof(rx_buffer));
bool result = !memcmp(tx_buffer, rx_buffer, sizeof(tx_buffer));
TEST_ASSERT_EQUAL(ret, sizeof(rx_buffer));
TEST_ASSERT(result);
err = sock.close();
TEST_ASSERT_EQUAL(0, err);
}
};
Echo *echoers[MBED_CFG_TCP_CLIENT_ECHO_THREADS];
void test_tcp_echo_parallel() {
int err = net.connect();
TEST_ASSERT_EQUAL(0, err);
printf("MBED: TCPClient IP address is '%s'\n", net.get_ip_address());
printf("MBED: TCPClient waiting for server IP and port...\n");
greentea_send_kv("target_ip", net.get_ip_address());
char recv_key[] = "host_port";
char ipbuf[60] = {0};
char portbuf[16] = {0};
unsigned int port = 0;
greentea_send_kv("host_ip", " ");
greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf));
greentea_send_kv("host_port", " ");
greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf));
sscanf(portbuf, "%u", &port);
printf("MBED: Server IP address received: %s:%d \n", ipbuf, port);
tcp_addr.set_ip_address(ipbuf);
tcp_addr.set_port(port);
// Startup echo threads in parallel
for (int i = 0; i < MBED_CFG_TCP_CLIENT_ECHO_THREADS; i++) {
echoers[i] = new Echo;
echoers[i]->start();
}
for (int i = 0; i < MBED_CFG_TCP_CLIENT_ECHO_THREADS; i++) {
echoers[i]->join();
delete echoers[i];
}
net.disconnect();
}
// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases) {
GREENTEA_SETUP(120, "tcp_echo");
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("TCP echo parallel", test_tcp_echo_parallel),
};
Specification specification(test_setup, cases);
int main() {
return !Harness::run(specification);
}

View File

@ -1,121 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* 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.
*/
#if !FEATURE_LWIP
#error [NOT_SUPPORTED] LWIP not supported for this target
#endif
#if DEVICE_EMAC
#error [NOT_SUPPORTED] Not supported for WiFi targets
#endif
#include <algorithm>
#include "mbed.h"
#include "EthernetInterface.h"
#include "TCPSocket.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest.h"
using namespace utest::v1;
namespace {
// Test connection information
const char *HTTP_SERVER_NAME = "os.mbed.com";
const char *HTTP_SERVER_FILE_PATH = "/media/uploads/mbed_official/hello.txt";
const int HTTP_SERVER_PORT = 80;
#if defined(TARGET_VK_RZ_A1H)
const int RECV_BUFFER_SIZE = 300;
#else
const int RECV_BUFFER_SIZE = 512;
#endif
// Test related data
const char *HTTP_OK_STR = "200 OK";
const char *HTTP_HELLO_STR = "Hello world!";
// Test buffers
char buffer[RECV_BUFFER_SIZE] = {0};
}
bool find_substring(const char *first, const char *last, const char *s_first, const char *s_last) {
const char *f = std::search(first, last, s_first, s_last);
return (f != last);
}
void test_tcp_hello_world() {
bool result = false;
EthernetInterface eth;
//eth.init(); //Use DHCP
eth.connect();
printf("TCP client IP Address is %s\r\n", eth.get_ip_address());
TCPSocket sock(&eth);
printf("HTTP: Connection to %s:%d\r\n", HTTP_SERVER_NAME, HTTP_SERVER_PORT);
if (sock.connect(HTTP_SERVER_NAME, HTTP_SERVER_PORT) == 0) {
printf("HTTP: OK\r\n");
// We are constructing GET command like this:
// GET http://developer.mbed.org/media/uploads/mbed_official/hello.txt HTTP/1.0\n\n
strcpy(buffer, "GET http://");
strcat(buffer, HTTP_SERVER_NAME);
strcat(buffer, HTTP_SERVER_FILE_PATH);
strcat(buffer, " HTTP/1.0\n\n");
// Send GET command
sock.send(buffer, strlen(buffer));
// Server will respond with HTTP GET's success code
const int ret = sock.recv(buffer, sizeof(buffer) - 1);
buffer[ret] = '\0';
// Find 200 OK HTTP status in reply
bool found_200_ok = find_substring(buffer, buffer + ret, HTTP_OK_STR, HTTP_OK_STR + strlen(HTTP_OK_STR));
// Find "Hello World!" string in reply
bool found_hello = find_substring(buffer, buffer + ret, HTTP_HELLO_STR, HTTP_HELLO_STR + strlen(HTTP_HELLO_STR));
TEST_ASSERT(found_200_ok);
TEST_ASSERT(found_hello);
if (found_200_ok && found_hello) result = true;
printf("HTTP: Received %d chars from server\r\n", ret);
printf("HTTP: Received 200 OK status ... %s\r\n", found_200_ok ? "[OK]" : "[FAIL]");
printf("HTTP: Received '%s' status ... %s\r\n", HTTP_HELLO_STR, found_hello ? "[OK]" : "[FAIL]");
printf("HTTP: Received message:\r\n");
printf("%s", buffer);
sock.close();
} else {
printf("HTTP: ERROR\r\n");
}
eth.disconnect();
TEST_ASSERT(result);
}
// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases) {
GREENTEA_SETUP(120, "default_auto");
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("TCP hello world", test_tcp_hello_world),
};
Specification specification(test_setup, cases);
int main() {
return !Harness::run(specification);
}

View File

@ -1,258 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* 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.
*/
#if !FEATURE_LWIP
#error [NOT_SUPPORTED] LWIP not supported for this target
#endif
#if DEVICE_EMAC
#error [NOT_SUPPORTED] Not supported for WiFi targets
#endif
#ifndef MBED_EXTENDED_TESTS
#error [NOT_SUPPORTED] Pressure tests are not supported by default
#endif
#include "mbed.h"
#include "EthernetInterface.h"
#include "TCPSocket.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest.h"
using namespace utest::v1;
#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN
#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN 64
#endif
#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX
#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX 0x80000
#endif
#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED
#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED 0x6d626564
#endif
#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG
#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG false
#endif
// Simple xorshift pseudorandom number generator
class RandSeq {
private:
uint32_t x;
uint32_t y;
static const int A = 15;
static const int B = 18;
static const int C = 11;
public:
RandSeq(uint32_t seed=MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED)
: x(seed), y(seed) {}
uint32_t next(void) {
x ^= x << A;
x ^= x >> B;
x ^= y ^ (y >> C);
return x + y;
}
void skip(size_t size) {
for (size_t i = 0; i < size; i++) {
next();
}
}
void buffer(uint8_t *buffer, size_t size) {
RandSeq lookahead = *this;
for (size_t i = 0; i < size; i++) {
buffer[i] = lookahead.next() & 0xff;
}
}
int cmp(uint8_t *buffer, size_t size) {
RandSeq lookahead = *this;
for (size_t i = 0; i < size; i++) {
int diff = buffer[i] - (lookahead.next() & 0xff);
if (diff != 0) {
return diff;
}
}
return 0;
}
};
// Shared buffer for network transactions
uint8_t *buffer;
size_t buffer_size;
// Tries to get the biggest buffer possible on the device. Exponentially
// grows a buffer until heap runs out of space, and uses half to leave
// space for the rest of the program
void generate_buffer(uint8_t **buffer, size_t *size, size_t min, size_t max) {
size_t i = min;
while (i < max) {
void *b = malloc(i);
if (!b) {
i /= 4;
if (i < min) {
i = min;
}
break;
}
free(b);
i *= 2;
}
*buffer = (uint8_t *)malloc(i);
*size = i;
TEST_ASSERT(buffer);
}
void test_tcp_packet_pressure() {
generate_buffer(&buffer, &buffer_size,
MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN,
MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX);
printf("MBED: Generated buffer %d\r\n", buffer_size);
EthernetInterface eth;
int err = eth.connect();
TEST_ASSERT_EQUAL(0, err);
printf("MBED: TCPClient IP address is '%s'\n", eth.get_ip_address());
printf("MBED: TCPClient waiting for server IP and port...\n");
greentea_send_kv("target_ip", eth.get_ip_address());
char recv_key[] = "host_port";
char ipbuf[60] = {0};
char portbuf[16] = {0};
unsigned int port = 0;
greentea_send_kv("host_ip", " ");
greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf));
greentea_send_kv("host_port", " ");
greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf));
sscanf(portbuf, "%u", &port);
printf("MBED: Server IP address received: %s:%d \n", ipbuf, port);
TCPSocket sock;
SocketAddress tcp_addr(ipbuf, port);
Timer timer;
timer.start();
// Tests exponentially growing sequences
for (size_t size = MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN;
size < MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX;
size *= 2) {
err = sock.open(&eth);
TEST_ASSERT_EQUAL(0, err);
err = sock.connect(tcp_addr);
TEST_ASSERT_EQUAL(0, err);
printf("TCP: %s:%d streaming %d bytes\r\n", ipbuf, port, size);
sock.set_blocking(false);
// Loop to send/recv all data
RandSeq tx_seq;
RandSeq rx_seq;
size_t rx_count = 0;
size_t tx_count = 0;
size_t window = buffer_size;
while (tx_count < size || rx_count < size) {
// Send out data
if (tx_count < size) {
size_t chunk_size = size - tx_count;
if (chunk_size > window) {
chunk_size = window;
}
tx_seq.buffer(buffer, chunk_size);
int td = sock.send(buffer, chunk_size);
if (td > 0) {
if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) {
printf("TCP: tx -> %d\r\n", td);
}
tx_seq.skip(td);
tx_count += td;
} else if (td != NSAPI_ERROR_WOULD_BLOCK) {
// We may fail to send because of buffering issues,
// cut buffer in half
if (window > MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN) {
window /= 2;
}
if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) {
printf("TCP: Not sent (%d), window = %d\r\n", td, window);
}
}
}
// Verify recieved data
while (rx_count < size) {
int rd = sock.recv(buffer, buffer_size);
TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK);
if (rd > 0) {
if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) {
printf("TCP: rx <- %d\r\n", rd);
}
int diff = rx_seq.cmp(buffer, rd);
TEST_ASSERT_EQUAL(0, diff);
rx_seq.skip(rd);
rx_count += rd;
} else if (rd == NSAPI_ERROR_WOULD_BLOCK) {
break;
}
}
}
err = sock.close();
TEST_ASSERT_EQUAL(0, err);
}
timer.stop();
printf("MBED: Time taken: %fs\r\n", timer.read());
printf("MBED: Speed: %.3fkb/s\r\n",
8*(2*MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX -
MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN) / (1000*timer.read()));
eth.disconnect();
}
// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases) {
GREENTEA_SETUP(120, "tcp_echo");
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("TCP packet pressure", test_tcp_packet_pressure),
};
Specification specification(test_setup, cases);
int main() {
return !Harness::run(specification);
}

View File

@ -1,320 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* 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.
*/
#if !FEATURE_LWIP
#error [NOT_SUPPORTED] LWIP not supported for this target
#endif
#if DEVICE_EMAC
#error [NOT_SUPPORTED] Not supported for WiFi targets
#endif
#ifndef MBED_EXTENDED_TESTS
#error [NOT_SUPPORTED] Parallel pressure tests are not supported by default
#endif
#include "mbed.h"
#include "EthernetInterface.h"
#include "TCPSocket.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest.h"
using namespace utest::v1;
#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN
#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN 64
#endif
#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX
#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX 0x80000
#endif
#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED
#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED 0x6d626564
#endif
#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS
#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS 3
#endif
#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG
#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG false
#endif
// Simple xorshift pseudorandom number generator
class RandSeq {
private:
uint32_t x;
uint32_t y;
static const int A = 15;
static const int B = 18;
static const int C = 11;
public:
RandSeq(uint32_t seed=MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED)
: x(seed), y(seed) {}
uint32_t next(void) {
x ^= x << A;
x ^= x >> B;
x ^= y ^ (y >> C);
return x + y;
}
void skip(size_t size) {
for (size_t i = 0; i < size; i++) {
next();
}
}
void buffer(uint8_t *buffer, size_t size) {
RandSeq lookahead = *this;
for (size_t i = 0; i < size; i++) {
buffer[i] = lookahead.next() & 0xff;
}
}
int cmp(uint8_t *buffer, size_t size) {
RandSeq lookahead = *this;
for (size_t i = 0; i < size; i++) {
int diff = buffer[i] - (lookahead.next() & 0xff);
if (diff != 0) {
return diff;
}
}
return 0;
}
};
// Tries to get the biggest buffer possible on the device. Exponentially
// grows a buffer until heap runs out of space, and uses half to leave
// space for the rest of the program
void generate_buffer(uint8_t **buffer, size_t *size, size_t min, size_t max) {
size_t i = min;
while (i < max) {
void *b = malloc(i);
if (!b) {
i /= 4;
if (i < min) {
i = min;
}
break;
}
free(b);
i *= 2;
}
*buffer = (uint8_t *)malloc(i);
*size = i;
TEST_ASSERT(buffer);
}
// Global variables shared between pressure tests
EthernetInterface net;
SocketAddress tcp_addr;
Timer timer;
Mutex iomutex;
// Single instance of a pressure test
class PressureTest {
private:
uint8_t *buffer;
size_t buffer_size;
TCPSocket sock;
Thread thread;
public:
PressureTest(uint8_t *buffer, size_t buffer_size)
: buffer(buffer), buffer_size(buffer_size) {
}
void start() {
osStatus status = thread.start(callback(this, &PressureTest::run));
TEST_ASSERT_EQUAL(osOK, status);
}
void join() {
osStatus status = thread.join();
TEST_ASSERT_EQUAL(osOK, status);
}
void run() {
// Tests exponentially growing sequences
for (size_t size = MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN;
size < MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX;
size *= 2) {
int err = sock.open(&net);
TEST_ASSERT_EQUAL(0, err);
err = sock.connect(tcp_addr);
TEST_ASSERT_EQUAL(0, err);
iomutex.lock();
printf("TCP: %s:%d streaming %d bytes\r\n",
tcp_addr.get_ip_address(), tcp_addr.get_port(), size);
iomutex.unlock();
sock.set_blocking(false);
// Loop to send/recv all data
RandSeq tx_seq;
RandSeq rx_seq;
size_t rx_count = 0;
size_t tx_count = 0;
size_t window = buffer_size;
while (tx_count < size || rx_count < size) {
// Send out data
if (tx_count < size) {
size_t chunk_size = size - tx_count;
if (chunk_size > window) {
chunk_size = window;
}
tx_seq.buffer(buffer, chunk_size);
int td = sock.send(buffer, chunk_size);
if (td > 0) {
if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) {
iomutex.lock();
printf("TCP: tx -> %d\r\n", td);
iomutex.unlock();
}
tx_seq.skip(td);
tx_count += td;
} else if (td != NSAPI_ERROR_WOULD_BLOCK) {
// We may fail to send because of buffering issues,
// cut buffer in half
if (window > MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN) {
window /= 2;
}
if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) {
iomutex.lock();
printf("TCP: Not sent (%d), window = %d\r\n", td, window);
iomutex.unlock();
}
}
}
// Verify recieved data
while (rx_count < size) {
int rd = sock.recv(buffer, buffer_size);
TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK);
if (rd > 0) {
if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) {
iomutex.lock();
printf("TCP: rx <- %d\r\n", rd);
iomutex.unlock();
}
int diff = rx_seq.cmp(buffer, rd);
TEST_ASSERT_EQUAL(0, diff);
rx_seq.skip(rd);
rx_count += rd;
} else if (rd == NSAPI_ERROR_WOULD_BLOCK) {
break;
}
}
}
err = sock.close();
TEST_ASSERT_EQUAL(0, err);
}
}
};
PressureTest *pressure_tests[MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS];
void test_tcp_packet_pressure_parallel() {
uint8_t *buffer;
size_t buffer_size;
generate_buffer(&buffer, &buffer_size,
MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN,
MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX);
size_t buffer_subsize = buffer_size / MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS;
printf("MBED: Generated buffer %d\r\n", buffer_size);
printf("MBED: Split into %d buffers %d\r\n",
MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS,
buffer_subsize);
int err = net.connect();
TEST_ASSERT_EQUAL(0, err);
printf("MBED: TCPClient IP address is '%s'\n", net.get_ip_address());
printf("MBED: TCPClient waiting for server IP and port...\n");
greentea_send_kv("target_ip", net.get_ip_address());
char recv_key[] = "host_port";
char ipbuf[60] = {0};
char portbuf[16] = {0};
unsigned int port = 0;
greentea_send_kv("host_ip", " ");
greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf));
greentea_send_kv("host_port", " ");
greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf));
sscanf(portbuf, "%u", &port);
printf("MBED: Server IP address received: %s:%d \n", ipbuf, port);
tcp_addr.set_ip_address(ipbuf);
tcp_addr.set_port(port);
timer.start();
// Startup pressure tests in parallel
for (int i = 0; i < MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS; i++) {
pressure_tests[i] = new PressureTest(&buffer[i*buffer_subsize], buffer_subsize);
pressure_tests[i]->start();
}
for (int i = 0; i < MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS; i++) {
pressure_tests[i]->join();
delete pressure_tests[i];
}
timer.stop();
printf("MBED: Time taken: %fs\r\n", timer.read());
printf("MBED: Speed: %.3fkb/s\r\n",
MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS*
8*(2*MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX -
MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN) / (1000*timer.read()));
net.disconnect();
}
// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases) {
GREENTEA_SETUP(120, "tcp_echo");
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("TCP packet pressure parallel", test_tcp_packet_pressure_parallel),
};
Specification specification(test_setup, cases);
int main() {
return !Harness::run(specification);
}

View File

@ -1,165 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* 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.
*/
#if !FEATURE_LWIP
#error [NOT_SUPPORTED] LWIP not supported for this target
#endif
#if DEVICE_EMAC
#error [NOT_SUPPORTED] Not supported for WiFi targets
#endif
#include "mbed.h"
#include "EthernetInterface.h"
#include "UDPSocket.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest.h"
using namespace utest::v1;
#ifndef MBED_CFG_UDP_DTLS_HANDSHAKE_BUFFER_SIZE
#define MBED_CFG_UDP_DTLS_HANDSHAKE_BUFFER_SIZE 512
#endif
#ifndef MBED_CFG_UDP_DTLS_HANDSHAKE_RETRIES
#define MBED_CFG_UDP_DTLS_HANDSHAKE_RETRIES 16
#endif
#ifndef MBED_CFG_UDP_DTLS_HANDSHAKE_PATTERN
#define MBED_CFG_UDP_DTLS_HANDSHAKE_PATTERN 112, 384, 200, 219, 25
#endif
#ifndef MBED_CFG_UDP_DTLS_HANDSHAKE_TIMEOUT
#define MBED_CFG_UDP_DTLS_HANDSHAKE_TIMEOUT 1500
#endif
uint8_t buffer[MBED_CFG_UDP_DTLS_HANDSHAKE_BUFFER_SIZE] = {0};
int udp_dtls_handshake_pattern[] = {MBED_CFG_UDP_DTLS_HANDSHAKE_PATTERN};
const int udp_dtls_handshake_count = sizeof(udp_dtls_handshake_pattern) / sizeof(int);
void test_udp_dtls_handshake() {
EthernetInterface eth;
int err = eth.connect();
TEST_ASSERT_EQUAL(0, err);
printf("MBED: UDPClient IP address is '%s'\n", eth.get_ip_address());
printf("MBED: UDPClient waiting for server IP and port...\n");
greentea_send_kv("target_ip", eth.get_ip_address());
bool result = false;
char recv_key[] = "host_port";
char ipbuf[60] = {0};
char portbuf[16] = {0};
unsigned int port = 0;
greentea_send_kv("host_ip", " ");
greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf));
greentea_send_kv("host_port", " ");
greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf));
sscanf(portbuf, "%u", &port);
printf("MBED: UDP Server IP address received: %s:%d \n", ipbuf, port);
// align each size to 4-bits
for (int i = 0; i < udp_dtls_handshake_count; i++) {
udp_dtls_handshake_pattern[i] = (~0xf & udp_dtls_handshake_pattern[i]) + 0x10;
}
printf("MBED: DTLS pattern [");
for (int i = 0; i < udp_dtls_handshake_count; i++) {
printf("%d", udp_dtls_handshake_pattern[i]);
if (i != udp_dtls_handshake_count-1) {
printf(", ");
}
}
printf("]\r\n");
UDPSocket sock;
SocketAddress udp_addr(ipbuf, port);
sock.set_timeout(MBED_CFG_UDP_DTLS_HANDSHAKE_TIMEOUT);
for (int attempt = 0; attempt < MBED_CFG_UDP_DTLS_HANDSHAKE_RETRIES; attempt++) {
err = sock.open(&eth);
TEST_ASSERT_EQUAL(0, err);
for (int i = 0; i < udp_dtls_handshake_count; i++) {
buffer[i] = udp_dtls_handshake_pattern[i] >> 4;
}
err = sock.sendto(udp_addr, buffer, udp_dtls_handshake_count);
printf("UDP: tx -> %d\r\n", err);
TEST_ASSERT_EQUAL(udp_dtls_handshake_count, err);
int step = 0;
while (step < udp_dtls_handshake_count) {
err = sock.recvfrom(NULL, buffer, sizeof(buffer));
printf("UDP: rx <- %d ", err);
// check length
if (err != udp_dtls_handshake_pattern[step]) {
printf("x (expected %d)\r\n", udp_dtls_handshake_pattern[step]);
break;
}
// check quick xor of packet
uint8_t check = 0;
for (int j = 0; j < udp_dtls_handshake_pattern[step]; j++) {
check ^= buffer[j];
}
if (check != 0) {
printf("x (checksum 0x%02x)\r\n", check);
break;
}
// successfully got a packet
printf("\r\n");
step += 1;
}
err = sock.close();
TEST_ASSERT_EQUAL(0, err);
// got through all steps, test passed
if (step == udp_dtls_handshake_count) {
result = true;
break;
}
}
eth.disconnect();
TEST_ASSERT(result);
}
// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases) {
GREENTEA_SETUP(120, "udp_shotgun");
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("UDP DTLS handshake", test_udp_dtls_handshake),
};
Specification specification(test_setup, cases);
int main() {
return !Harness::run(specification);
}

View File

@ -1,159 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* 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.
*/
#if !FEATURE_LWIP
#error [NOT_SUPPORTED] LWIP not supported for this target
#endif
#if DEVICE_EMAC
#error [NOT_SUPPORTED] Not supported for WiFi targets
#endif
#include "mbed.h"
#include "EthernetInterface.h"
#include "UDPSocket.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest.h"
using namespace utest::v1;
#ifndef MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE
#define MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE 64
#endif
#ifndef MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT
#define MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT 500
#endif
namespace {
char tx_buffer[MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE] = {0};
char rx_buffer[MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE] = {0};
const char ASCII_MAX = '~' - ' ';
const int ECHO_LOOPS = 16;
char uuid[GREENTEA_UUID_LENGTH] = {0};
}
// Creates a buffer that contains the test's UUID in the first part of the contents
// so the output can be associated with individual test runs. The rest of the
// buffer is filled with random data so it is unique within the CURRENT test run.
//
// Ex. A test with UUID of `33e5002c-9722-4685-817a-709cc69c4701` would have a
// buffer filled with something like `33e5002c-9722-4685-817a-709cc69c4701 12594387`
// where `33e5002c-9722-4685-817a-709cc69c4701` is the UUID and `12594387` is the random data
void prep_buffer(char *uuid, char *tx_buffer, size_t tx_size) {
size_t i = 0;
memcpy(tx_buffer, uuid, strlen(uuid));
i += strlen(uuid);
tx_buffer[i++] = ' ';
for (; i<tx_size; ++i) {
tx_buffer[i] = (rand() % 10) + '0';
}
}
void test_udp_echo() {
EthernetInterface eth;
int err = eth.connect();
TEST_ASSERT_EQUAL(0, err);
printf("UDP client IP Address is %s\n", eth.get_ip_address());
greentea_send_kv("target_ip", eth.get_ip_address());
char recv_key[] = "host_port";
char ipbuf[60] = {0};
char portbuf[16] = {0};
unsigned int port = 0;
UDPSocket sock;
sock.open(&eth);
sock.set_timeout(MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT);
greentea_send_kv("host_ip", " ");
greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf));
greentea_send_kv("host_port", " ");
greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf));
sscanf(portbuf, "%u", &port);
printf("MBED: UDP Server IP address received: %s:%d \n", ipbuf, port);
SocketAddress udp_addr(ipbuf, port);
int success = 0;
for (unsigned int i = 0; success < ECHO_LOOPS; i++) {
prep_buffer(uuid, tx_buffer, sizeof(tx_buffer));
int ret = sock.sendto(udp_addr, tx_buffer, sizeof(tx_buffer));
if (ret >= 0) {
printf("[%02u] sent %d bytes - %.*s \n", i, ret, ret, tx_buffer);
} else {
printf("[%02u] Network error %d\n", i, ret);
continue;
}
SocketAddress temp_addr;
ret = sock.recvfrom(&temp_addr, rx_buffer, sizeof(rx_buffer));
if (ret >= 0) {
printf("[%02u] recv %d bytes - %.*s \n", i, ret, ret, tx_buffer);
} else {
printf("[%02u] Network error %d\n", i, ret);
continue;
}
if ((temp_addr == udp_addr &&
ret == sizeof(tx_buffer) &&
memcmp(rx_buffer, tx_buffer, sizeof(rx_buffer)) == 0)) {
success += 1;
printf("[%02u] success #%d\n", i, success);
continue;
}
// failed, clean out any remaining bad packets
sock.set_timeout(0);
while (true) {
err = sock.recvfrom(NULL, NULL, 0);
if (err == NSAPI_ERROR_WOULD_BLOCK) {
break;
}
}
sock.set_timeout(MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT);
}
sock.close();
eth.disconnect();
TEST_ASSERT_EQUAL(ECHO_LOOPS, success);
}
// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases) {
GREENTEA_SETUP_UUID(120, "udp_echo", uuid, GREENTEA_UUID_LENGTH);
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("UDP echo", test_udp_echo),
};
Specification specification(test_setup, cases);
int main() {
return !Harness::run(specification);
}

View File

@ -1,242 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* 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.
*/
#if !FEATURE_LWIP
#error [NOT_SUPPORTED] LWIP not supported for this target
#endif
#if DEVICE_EMAC
#error [NOT_SUPPORTED] Not supported for WiFi targets
#endif
#include "mbed.h"
#include "EthernetInterface.h"
#include "UDPSocket.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest.h"
using namespace utest::v1;
#ifndef MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE
#define MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE 64
#endif
#ifndef MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT
#define MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT 500
#endif
#ifndef MBED_CFG_UDP_CLIENT_ECHO_THREADS
#define MBED_CFG_UDP_CLIENT_ECHO_THREADS 3
#endif
const int ECHO_LOOPS = 16;
EthernetInterface net;
SocketAddress udp_addr;
Mutex iomutex;
char uuid[GREENTEA_UUID_LENGTH] = {0};
// Thread safe printf macro
#define TS_PRINTF(...) {\
iomutex.lock();\
printf(__VA_ARGS__);\
iomutex.unlock();\
}
// NOTE: assuming that "id" stays in the single digits
//
// Creates a buffer that first contains the thread's id.
//
// The second part of the buffer contains the test's UUID so the output can be
// associated with individual test runs.
//
// The rest of the buffer is filled with random data so it is unique within the
// CURRENT test run.
//
// Ex. A thread with id "2" and a test with UUID of `33e5002c-9722-4685-817a-709cc69c4701`
// would have a buffer filled with something like `2 33e5002c-9722-4685-817a-709cc69c4701 12594387`
// where `2` is the thread id, `33e5002c-9722-4685-817a-709cc69c4701` is the UUID
// and `12594387` is the random data
void prep_buffer(unsigned int id, char *uuid, char *tx_buffer, size_t tx_size) {
size_t i = 0;
tx_buffer[i++] = '0' + id;
tx_buffer[i++] = ' ';
memcpy(tx_buffer+i, uuid, strlen(uuid));
i += strlen(uuid);
tx_buffer[i++] = ' ';
for (; i<tx_size; ++i) {
tx_buffer[i] = (rand() % 10) + '0';
}
}
// Each echo class is in charge of one parallel transaction
class Echo {
private:
char tx_buffer[MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE];
char rx_buffer[MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE];
UDPSocket sock;
Thread thread;
bool result;
unsigned int id;
char *uuid;
public:
// Limiting stack size to 1k
Echo(): thread(osPriorityNormal, 1024), result(false) {
}
void start(unsigned int id, char *uuid) {
this->id = id;
this->uuid = uuid;
osStatus status = thread.start(callback(this, &Echo::echo));
}
void join() {
osStatus status = thread.join();
TEST_ASSERT_EQUAL(osOK, status);
}
void echo() {
int success = 0;
int err = sock.open(&net);
TEST_ASSERT_EQUAL(0, err);
sock.set_timeout(MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT);
for (unsigned int i = 0; success < ECHO_LOOPS; i++) {
prep_buffer(id, uuid, tx_buffer, sizeof(tx_buffer));
int ret = sock.sendto(udp_addr, tx_buffer, sizeof(tx_buffer));
if (ret >= 0) {
TS_PRINTF("[ID:%01u][%02u] sent %d bytes - %.*s \n", id, i, ret, ret, tx_buffer);
} else {
TS_PRINTF("[ID:%01u][%02u] Network error %d\n", id, i, ret);
continue;
}
SocketAddress temp_addr;
ret = sock.recvfrom(&temp_addr, rx_buffer, sizeof(rx_buffer));
if (ret >= 0) {
TS_PRINTF("[ID:%01u][%02u] recv %d bytes - %.*s \n", id, i, ret, ret, tx_buffer);
} else {
TS_PRINTF("[ID:%01u][%02u] Network error %d\n", id, i, ret);
continue;
}
if ((temp_addr == udp_addr &&
ret == sizeof(tx_buffer) &&
memcmp(rx_buffer, tx_buffer, sizeof(rx_buffer)) == 0)) {
success += 1;
TS_PRINTF("[ID:%01u][%02u] success #%d\n", id, i, success);
continue;
}
// failed, clean out any remaining bad packets
sock.set_timeout(0);
while (true) {
err = sock.recvfrom(NULL, NULL, 0);
if (err == NSAPI_ERROR_WOULD_BLOCK) {
break;
}
}
sock.set_timeout(MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT);
}
result = success == ECHO_LOOPS;
if (result) {
TS_PRINTF("[ID:%01u] Succeeded all %d times!\n", id, success);
} else {
TS_PRINTF("[ID:%01u] Only succeeded %d times out of a required %d.\n", id, success, ECHO_LOOPS);
}
err = sock.close();
if (err) {
TS_PRINTF("[ID:%01u] Failed to close socket!\n", id);
result = false;
}
}
bool get_result() {
return result;
}
};
Echo *echoers[MBED_CFG_UDP_CLIENT_ECHO_THREADS];
void test_udp_echo_parallel() {
int err = net.connect();
TEST_ASSERT_EQUAL(0, err);
printf("UDP client IP Address is %s\n", net.get_ip_address());
greentea_send_kv("target_ip", net.get_ip_address());
char recv_key[] = "host_port";
char ipbuf[60] = {0};
char portbuf[16] = {0};
unsigned int port = 0;
greentea_send_kv("host_ip", " ");
greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf));
greentea_send_kv("host_port", " ");
greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf));
sscanf(portbuf, "%u", &port);
printf("MBED: UDP Server IP address received: %s:%d \n", ipbuf, port);
udp_addr.set_ip_address(ipbuf);
udp_addr.set_port(port);
// Startup echo threads in parallel
for (unsigned int i = 0; i < MBED_CFG_UDP_CLIENT_ECHO_THREADS; i++) {
echoers[i] = new Echo;
echoers[i]->start(i, uuid);
}
bool result = true;
for (unsigned int i = 0; i < MBED_CFG_UDP_CLIENT_ECHO_THREADS; i++) {
echoers[i]->join();
result = result && echoers[i]->get_result();
delete echoers[i];
}
net.disconnect();
TEST_ASSERT(result);
}
// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases) {
GREENTEA_SETUP_UUID(120, "udp_echo", uuid, GREENTEA_UUID_LENGTH);
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("UDP echo parallel", test_udp_echo_parallel),
};
Specification specification(test_setup, cases);
int main() {
return !Harness::run(specification);
}

View File

@ -1,281 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* 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.
*/
#if !FEATURE_LWIP
#error [NOT_SUPPORTED] LWIP not supported for this target
#endif
#if DEVICE_EMAC
#error [NOT_SUPPORTED] Not supported for WiFi targets
#endif
#ifndef MBED_EXTENDED_TESTS
#error [NOT_SUPPORTED] Pressure tests are not supported by default
#endif
#include "mbed.h"
#include "EthernetInterface.h"
#include "UDPSocket.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest.h"
using namespace utest::v1;
#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN
#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN 64
#endif
#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX
#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX 0x80000
#endif
#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT
#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT 100
#endif
#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED
#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED 0x6d626564
#endif
#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG
#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG false
#endif
// Simple xorshift pseudorandom number generator
class RandSeq {
private:
uint32_t x;
uint32_t y;
static const int A = 15;
static const int B = 18;
static const int C = 11;
public:
RandSeq(uint32_t seed=MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED)
: x(seed), y(seed) {}
uint32_t next(void) {
x ^= x << A;
x ^= x >> B;
x ^= y ^ (y >> C);
return x + y;
}
void skip(size_t size) {
for (size_t i = 0; i < size; i++) {
next();
}
}
void buffer(uint8_t *buffer, size_t size) {
RandSeq lookahead = *this;
for (size_t i = 0; i < size; i++) {
buffer[i] = lookahead.next() & 0xff;
}
}
int cmp(uint8_t *buffer, size_t size) {
RandSeq lookahead = *this;
for (size_t i = 0; i < size; i++) {
int diff = buffer[i] - (lookahead.next() & 0xff);
if (diff != 0) {
return diff;
}
}
return 0;
}
};
// Shared buffer for network transactions
uint8_t *buffer;
size_t buffer_size;
// Tries to get the biggest buffer possible on the device. Exponentially
// grows a buffer until heap runs out of space, and uses half to leave
// space for the rest of the program
void generate_buffer(uint8_t **buffer, size_t *size, size_t min, size_t max) {
size_t i = min;
while (i < max) {
void *b = malloc(i);
if (!b) {
i /= 4;
if (i < min) {
i = min;
}
break;
}
free(b);
i *= 2;
}
*buffer = (uint8_t *)malloc(i);
*size = i;
TEST_ASSERT(buffer);
}
void test_udp_packet_pressure() {
generate_buffer(&buffer, &buffer_size,
MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN,
MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX);
printf("MBED: Generated buffer %d\r\n", buffer_size);
EthernetInterface eth;
int err = eth.connect();
TEST_ASSERT_EQUAL(0, err);
printf("MBED: UDPClient IP address is '%s'\n", eth.get_ip_address());
printf("MBED: UDPClient waiting for server IP and port...\n");
greentea_send_kv("target_ip", eth.get_ip_address());
char recv_key[] = "host_port";
char ipbuf[60] = {0};
char portbuf[16] = {0};
unsigned int port = 0;
greentea_send_kv("host_ip", " ");
greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf));
greentea_send_kv("host_port", " ");
greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf));
sscanf(portbuf, "%u", &port);
printf("MBED: Server IP address received: %s:%d \n", ipbuf, port);
UDPSocket sock;
SocketAddress udp_addr(ipbuf, port);
Timer timer;
timer.start();
// Tests exponentially growing sequences
for (size_t size = MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN;
size < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX;
size *= 2) {
err = sock.open(&eth);
TEST_ASSERT_EQUAL(0, err);
printf("UDP: %s:%d streaming %d bytes\r\n", ipbuf, port, size);
sock.set_blocking(false);
// Loop to send/recv all data
RandSeq tx_seq;
RandSeq rx_seq;
size_t rx_count = 0;
size_t tx_count = 0;
int known_time = timer.read_ms();
size_t window = buffer_size;
while (tx_count < size || rx_count < size) {
// Send out packets
if (tx_count < size) {
size_t chunk_size = size - tx_count;
if (chunk_size > window) {
chunk_size = window;
}
tx_seq.buffer(buffer, chunk_size);
int td = sock.sendto(udp_addr, buffer, chunk_size);
if (td > 0) {
if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) {
printf("UDP: tx -> %d\r\n", td);
}
tx_seq.skip(td);
tx_count += td;
} else if (td != NSAPI_ERROR_WOULD_BLOCK) {
// We may fail to send because of buffering issues, revert to
// last good sequence and cut buffer in half
if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) {
window /= 2;
}
if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) {
printf("UDP: Not sent (%d), window = %d\r\n", td, window);
}
}
}
// Prioritize recieving over sending packets to avoid flooding
// the network while handling erronous packets
while (rx_count < size) {
int rd = sock.recvfrom(NULL, buffer, buffer_size);
TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK);
if (rd > 0) {
if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) {
printf("UDP: rx <- %d\r\n", rd);
}
if (rx_seq.cmp(buffer, rd) == 0) {
rx_seq.skip(rd);
rx_count += rd;
known_time = timer.read_ms();
if (window < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX) {
window += MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN;
}
}
} else if (timer.read_ms() - known_time >
MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT) {
// Dropped packet or out of order, revert to last good sequence
// and cut buffer in half
tx_seq = rx_seq;
tx_count = rx_count;
known_time = timer.read_ms();
if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) {
window /= 2;
}
if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) {
printf("UDP: Dropped, window = %d\r\n", window);
}
} else if (rd == NSAPI_ERROR_WOULD_BLOCK) {
break;
}
}
}
err = sock.close();
TEST_ASSERT_EQUAL(0, err);
}
timer.stop();
printf("MBED: Time taken: %fs\r\n", timer.read());
printf("MBED: Speed: %.3fkb/s\r\n",
8*(2*MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX -
MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) / (1000*timer.read()));
eth.disconnect();
}
// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases) {
GREENTEA_SETUP(120, "udp_echo");
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("UDP packet pressure", test_udp_packet_pressure),
};
Specification specification(test_setup, cases);
int main() {
return !Harness::run(specification);
}

View File

@ -1,345 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* 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.
*/
#if !FEATURE_LWIP
#error [NOT_SUPPORTED] LWIP not supported for this target
#endif
#if DEVICE_EMAC
#error [NOT_SUPPORTED] Not supported for WiFi targets
#endif
#ifndef MBED_EXTENDED_TESTS
#error [NOT_SUPPORTED] Parallel pressure tests are not supported by default
#endif
#include "mbed.h"
#include "EthernetInterface.h"
#include "UDPSocket.h"
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest.h"
using namespace utest::v1;
#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN
#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN 64
#endif
#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX
#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX 0x80000
#endif
#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT
#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT 100
#endif
#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED
#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED 0x6d626564
#endif
#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS
#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS 3
#endif
#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG
#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG false
#endif
// Simple xorshift pseudorandom number generator
class RandSeq {
private:
uint32_t x;
uint32_t y;
static const int A = 15;
static const int B = 18;
static const int C = 11;
public:
RandSeq(uint32_t seed=MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED)
: x(seed), y(seed) {}
uint32_t next(void) {
x ^= x << A;
x ^= x >> B;
x ^= y ^ (y >> C);
return x + y;
}
void skip(size_t size) {
for (size_t i = 0; i < size; i++) {
next();
}
}
void buffer(uint8_t *buffer, size_t size) {
RandSeq lookahead = *this;
for (size_t i = 0; i < size; i++) {
buffer[i] = lookahead.next() & 0xff;
}
}
int cmp(uint8_t *buffer, size_t size) {
RandSeq lookahead = *this;
for (size_t i = 0; i < size; i++) {
int diff = buffer[i] - (lookahead.next() & 0xff);
if (diff != 0) {
return diff;
}
}
return 0;
}
};
// Tries to get the biggest buffer possible on the device. Exponentially
// grows a buffer until heap runs out of space, and uses half to leave
// space for the rest of the program
void generate_buffer(uint8_t **buffer, size_t *size, size_t min, size_t max) {
size_t i = min;
while (i < max) {
void *b = malloc(i);
if (!b) {
i /= 8;
if (i < min) {
i = min;
}
break;
}
free(b);
i *= 2;
}
*buffer = (uint8_t *)malloc(i);
*size = i;
TEST_ASSERT(buffer);
}
// Global variables shared between pressure tests
EthernetInterface net;
SocketAddress udp_addr;
Timer timer;
Mutex iomutex;
// Single instance of a pressure test
class PressureTest {
private:
uint8_t *buffer;
size_t buffer_size;
UDPSocket sock;
Thread thread;
public:
PressureTest(uint8_t *buffer, size_t buffer_size)
: buffer(buffer), buffer_size(buffer_size) {
}
void start() {
osStatus status = thread.start(callback(this, &PressureTest::run));
TEST_ASSERT_EQUAL(osOK, status);
}
void join() {
osStatus status = thread.join();
TEST_ASSERT_EQUAL(osOK, status);
}
void run() {
// Tests exponentially growing sequences
for (size_t size = MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN;
size < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX;
size *= 2) {
int err = sock.open(&net);
TEST_ASSERT_EQUAL(0, err);
iomutex.lock();
printf("UDP: %s:%d streaming %d bytes\r\n",
udp_addr.get_ip_address(), udp_addr.get_port(), size);
iomutex.unlock();
sock.set_blocking(false);
// Loop to send/recv all data
RandSeq tx_seq;
RandSeq rx_seq;
size_t rx_count = 0;
size_t tx_count = 0;
int known_time = timer.read_ms();
size_t window = buffer_size;
while (tx_count < size || rx_count < size) {
// Send out packets
if (tx_count < size) {
size_t chunk_size = size - tx_count;
if (chunk_size > window) {
chunk_size = window;
}
tx_seq.buffer(buffer, chunk_size);
int td = sock.sendto(udp_addr, buffer, chunk_size);
if (td > 0) {
if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) {
iomutex.lock();
printf("UDP: tx -> %d\r\n", td);
iomutex.unlock();
}
tx_seq.skip(td);
tx_count += td;
} else if (td != NSAPI_ERROR_WOULD_BLOCK) {
// We may fail to send because of buffering issues, revert to
// last good sequence and cut buffer in half
if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) {
window /= 2;
}
if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) {
iomutex.lock();
printf("UDP: Not sent (%d), window = %d\r\n", td, window);
iomutex.unlock();
}
}
}
// Prioritize recieving over sending packets to avoid flooding
// the network while handling erronous packets
while (rx_count < size) {
int rd = sock.recvfrom(NULL, buffer, buffer_size);
TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK);
if (rd > 0) {
if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) {
iomutex.lock();
printf("UDP: rx <- %d\r\n", rd);
iomutex.unlock();
}
if (rx_seq.cmp(buffer, rd) == 0) {
rx_seq.skip(rd);
rx_count += rd;
known_time = timer.read_ms();
if (window < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX) {
window += MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN;
}
}
} else if (timer.read_ms() - known_time >
MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT) {
// Dropped packet or out of order, revert to last good sequence
// and cut buffer in half
tx_seq = rx_seq;
tx_count = rx_count;
known_time = timer.read_ms();
if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) {
window /= 2;
}
if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) {
iomutex.lock();
printf("UDP: Dropped, window = %d\r\n", window);
iomutex.unlock();
}
} else if (rd == NSAPI_ERROR_WOULD_BLOCK) {
break;
}
}
}
err = sock.close();
TEST_ASSERT_EQUAL(0, err);
}
}
};
PressureTest *pressure_tests[MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS];
void test_udp_packet_pressure_parallel() {
uint8_t *buffer;
size_t buffer_size;
generate_buffer(&buffer, &buffer_size,
MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN,
MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX);
size_t buffer_subsize = buffer_size / MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS;
printf("MBED: Generated buffer %d\r\n", buffer_size);
printf("MBED: Split into %d buffers %d\r\n",
MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS,
buffer_subsize);
int err = net.connect();
TEST_ASSERT_EQUAL(0, err);
printf("MBED: UDPClient IP address is '%s'\n", net.get_ip_address());
printf("MBED: UDPClient waiting for server IP and port...\n");
greentea_send_kv("target_ip", net.get_ip_address());
char recv_key[] = "host_port";
char ipbuf[60] = {0};
char portbuf[16] = {0};
unsigned int port = 0;
greentea_send_kv("host_ip", " ");
greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf));
greentea_send_kv("host_port", " ");
greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf));
sscanf(portbuf, "%u", &port);
printf("MBED: Server IP address received: %s:%d \n", ipbuf, port);
udp_addr.set_ip_address(ipbuf);
udp_addr.set_port(port);
timer.start();
// Startup pressure tests in parallel
for (int i = 0; i < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS; i++) {
pressure_tests[i] = new PressureTest(&buffer[i*buffer_subsize], buffer_subsize);
pressure_tests[i]->start();
}
for (int i = 0; i < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS; i++) {
pressure_tests[i]->join();
delete pressure_tests[i];
}
timer.stop();
printf("MBED: Time taken: %fs\r\n", timer.read());
printf("MBED: Speed: %.3fkb/s\r\n",
MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS*
8*(2*MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX -
MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) / (1000*timer.read()));
net.disconnect();
}
// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases) {
GREENTEA_SETUP(120, "udp_echo");
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("UDP packet pressure parallel", test_udp_packet_pressure_parallel),
};
Specification specification(test_setup, cases);
int main() {
return !Harness::run(specification);
}