mirror of
https://github.com/espressif/openthread.git
synced 2026-09-12 20:20:04 +00:00
[simulation] add simulation tests framework for tcat (#9724)
This commit adds simulation framework for tcat based on posix udp sockets.
This commit is contained in:
@@ -60,6 +60,7 @@ jobs:
|
||||
- name: Bootstrap
|
||||
run: |
|
||||
sudo apt-get --no-install-recommends install -y expect ninja-build lcov socat
|
||||
pip install bleak
|
||||
- name: Run RCP Mode
|
||||
run: |
|
||||
ulimit -c unlimited
|
||||
|
||||
@@ -247,6 +247,7 @@ jobs:
|
||||
- name: Bootstrap
|
||||
run: |
|
||||
sudo apt-get --no-install-recommends install -y expect ninja-build lcov socat
|
||||
pip install bleak
|
||||
- name: Run
|
||||
run: |
|
||||
ulimit -c unlimited
|
||||
|
||||
@@ -254,6 +254,7 @@ jobs:
|
||||
- name: Bootstrap
|
||||
run: |
|
||||
sudo apt-get --no-install-recommends install -y expect ninja-build lcov socat
|
||||
pip install bleak
|
||||
- name: Run RCP Mode
|
||||
run: |
|
||||
ulimit -c unlimited
|
||||
|
||||
@@ -26,50 +26,191 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform-simulation.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <openthread/platform/ble.h>
|
||||
|
||||
#include "openthread/error.h"
|
||||
#include "utils/code_utils.h"
|
||||
|
||||
#define PLAT_BLE_MSG_DATA_MAX 2048
|
||||
static uint8_t sBleBuffer[PLAT_BLE_MSG_DATA_MAX];
|
||||
|
||||
static int sFd = -1;
|
||||
|
||||
static const uint16_t kPortBase = 10000;
|
||||
static uint16_t sPort = 0;
|
||||
struct sockaddr_in sSockaddr;
|
||||
|
||||
static void initFds(void)
|
||||
{
|
||||
int fd;
|
||||
int one = 1;
|
||||
struct sockaddr_in sockaddr;
|
||||
|
||||
memset(&sockaddr, 0, sizeof(sockaddr));
|
||||
|
||||
sPort = (uint16_t)(kPortBase + gNodeId);
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = htons(sPort);
|
||||
sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
|
||||
otEXPECT_ACTION((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1, perror("socket(sFd)"));
|
||||
|
||||
otEXPECT_ACTION(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != -1,
|
||||
perror("setsockopt(sFd, SO_REUSEADDR)"));
|
||||
otEXPECT_ACTION(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) != -1,
|
||||
perror("setsockopt(sFd, SO_REUSEPORT)"));
|
||||
|
||||
otEXPECT_ACTION(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != -1, perror("bind(sFd)"));
|
||||
|
||||
// Fd is successfully initialized.
|
||||
sFd = fd;
|
||||
|
||||
exit:
|
||||
if (sFd == -1)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static void deinitFds(void)
|
||||
{
|
||||
if (sFd != -1)
|
||||
{
|
||||
close(sFd);
|
||||
sFd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
otError otPlatBleEnable(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
initFds();
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError otPlatBleDisable(otInstance *aInstance)
|
||||
{
|
||||
deinitFds();
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError otPlatBleGapAdvStart(otInstance *aInstance, uint16_t aInterval)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aInterval);
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError otPlatBleGapAdvStop(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError otPlatBleGapDisconnect(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError otPlatBleGattMtuGet(otInstance *aInstance, uint16_t *aMtu)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aMtu);
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
*aMtu = PLAT_BLE_MSG_DATA_MAX - 1;
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError otPlatBleGattServerIndicate(otInstance *aInstance, uint16_t aHandle, const otBleRadioPacket *aPacket)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aHandle);
|
||||
|
||||
ssize_t rval;
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
otEXPECT_ACTION(sFd != -1, error = OT_ERROR_INVALID_STATE);
|
||||
rval = sendto(sFd, (const char *)aPacket->mValue, aPacket->mLength, 0, (struct sockaddr *)&sSockaddr,
|
||||
sizeof(sSockaddr));
|
||||
if (rval == -1)
|
||||
{
|
||||
perror("BLE simulation sendto failed.");
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void platformBleDeinit(void) { deinitFds(); }
|
||||
|
||||
void platformBleUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aTimeout);
|
||||
OT_UNUSED_VARIABLE(aWriteFdSet);
|
||||
|
||||
if (aReadFdSet != NULL && sFd != -1)
|
||||
{
|
||||
FD_SET(sFd, aReadFdSet);
|
||||
|
||||
if (aMaxFd != NULL && *aMaxFd < sFd)
|
||||
{
|
||||
*aMaxFd = sFd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void platformBleProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aWriteFdSet);
|
||||
|
||||
otEXPECT(sFd != -1);
|
||||
|
||||
if (FD_ISSET(sFd, aReadFdSet))
|
||||
{
|
||||
socklen_t len = sizeof(sSockaddr);
|
||||
ssize_t rval;
|
||||
memset(&sSockaddr, 0, sizeof(sSockaddr));
|
||||
rval = recvfrom(sFd, sBleBuffer, sizeof(sBleBuffer), 0, (struct sockaddr *)&sSockaddr, &len);
|
||||
if (rval > 0)
|
||||
{
|
||||
otBleRadioPacket myPacket;
|
||||
myPacket.mValue = sBleBuffer;
|
||||
myPacket.mLength = (uint16_t)rval;
|
||||
myPacket.mPower = 0;
|
||||
otPlatBleGattServerOnWriteRequest(
|
||||
aInstance, 0,
|
||||
&myPacket); // TODO consider passing otPlatBleGattServerOnWriteRequest as a callback function
|
||||
}
|
||||
else if (rval == 0)
|
||||
{
|
||||
// socket is closed, which should not happen
|
||||
assert(false);
|
||||
}
|
||||
else if (errno != EINTR && errno != EAGAIN)
|
||||
{
|
||||
perror("recvfrom BLE simulation failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
OT_TOOL_WEAK void otPlatBleGattServerOnWriteRequest(otInstance *aInstance,
|
||||
uint16_t aHandle,
|
||||
const otBleRadioPacket *aPacket)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aHandle);
|
||||
OT_UNUSED_VARIABLE(aPacket);
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
assert(false);
|
||||
/* In case of rcp there is a problem with linking to otPlatBleGattServerOnWriteRequest
|
||||
* which is available in FTD/MTD library.
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ void platformRadioDeinit(void);
|
||||
void platformRadioReceive(otInstance *aInstance, uint8_t *aBuf, uint16_t aBufLength);
|
||||
|
||||
/**
|
||||
* Updates the file descriptor sets with file descriptors used by the radio driver.
|
||||
* Updates the file descriptor sets with file descriptors used by the BLE radio driver.
|
||||
*
|
||||
* @param[in,out] aReadFdSet A pointer to the read file descriptors.
|
||||
* @param[in,out] aWriteFdSet A pointer to the write file descriptors.
|
||||
@@ -341,4 +341,31 @@ void platformInfraIfProcess(otInstance *aInstance, const fd_set *aReadFdSet, con
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
|
||||
/**
|
||||
* Shuts down the BLE service used by OpenThread.
|
||||
*
|
||||
*/
|
||||
void platformBleDeinit(void);
|
||||
|
||||
/**
|
||||
* Updates the file descriptor sets with file descriptors used by the radio driver.
|
||||
*
|
||||
* @param[in,out] aReadFdSet A pointer to the read file descriptors.
|
||||
* @param[in,out] aWriteFdSet A pointer to the write file descriptors.
|
||||
* @param[in,out] aTimeout A pointer to the timeout.
|
||||
* @param[in,out] aMaxFd A pointer to the max file descriptor.
|
||||
*
|
||||
*/
|
||||
void platformBleUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd);
|
||||
|
||||
/**
|
||||
* Performs BLE driver processing.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aReadFdSet A pointer to the read file descriptors.
|
||||
* @param[in] aWriteFdSet A pointer to the write file descriptors.
|
||||
*
|
||||
*/
|
||||
void platformBleProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet);
|
||||
|
||||
#endif // PLATFORM_SIMULATION_H_
|
||||
|
||||
@@ -296,6 +296,10 @@ void otSysProcessDrivers(otInstance *aInstance)
|
||||
platformInfraIfUpdateFdSet(&read_fds, &write_fds, &max_fd);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
|
||||
platformBleUpdateFdSet(&read_fds, &write_fds, &timeout, &max_fd);
|
||||
#endif
|
||||
|
||||
if (otTaskletsArePending(aInstance))
|
||||
{
|
||||
timeout.tv_sec = 0;
|
||||
@@ -308,6 +312,9 @@ void otSysProcessDrivers(otInstance *aInstance)
|
||||
{
|
||||
platformUartProcess();
|
||||
platformRadioProcess(aInstance, &read_fds, &write_fds);
|
||||
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
|
||||
platformBleProcess(aInstance, &read_fds, &write_fds);
|
||||
#endif
|
||||
}
|
||||
else if (errno != EINTR)
|
||||
{
|
||||
|
||||
@@ -109,6 +109,7 @@ OT_POSIX_SIM_COMMON_OPTIONS=(
|
||||
"-DOT_SRP_CLIENT=ON"
|
||||
"-DOT_SRP_SERVER=ON"
|
||||
"-DOT_UPTIME=ON"
|
||||
"-DOT_BLE_TCAT=ON"
|
||||
)
|
||||
readonly OT_POSIX_SIM_COMMON_OPTIONS
|
||||
|
||||
|
||||
Executable
+61
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/expect -f
|
||||
#
|
||||
# Copyright (c) 2022, The OpenThread Authors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the copyright holder nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
source "tests/scripts/expect/_common.exp"
|
||||
|
||||
spawn_node 1 "cli"
|
||||
|
||||
switch_node 1
|
||||
send "tcat start\n"
|
||||
expect_line "Done"
|
||||
|
||||
spawn python "tools/tcat_ble_client/bbtc.py" --simulation 1 --cert_path "tools/tcat_ble_client/auth"
|
||||
set py_client "$spawn_id"
|
||||
expect_line "Done"
|
||||
send "commission\n"
|
||||
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
|
||||
expect_line "\tVALUE:\t0x00"
|
||||
|
||||
send "thread start\n"
|
||||
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
|
||||
expect_line "\tVALUE:\t0x00"
|
||||
|
||||
send "exit\n"
|
||||
expect eof
|
||||
|
||||
switch_node 1
|
||||
send "tcat stop\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "networkkey\n"
|
||||
expect_line "fda7c771a27202e232ecd04cf934f476"
|
||||
expect_line "Done"
|
||||
|
||||
wait_for "state" "leader"
|
||||
expect_line "Done"
|
||||
Vendored
+4
-1
@@ -94,6 +94,7 @@
|
||||
|
||||
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
|
||||
#define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
|
||||
#define MBEDTLS_GCM_C
|
||||
#endif
|
||||
|
||||
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
|
||||
@@ -132,7 +133,9 @@
|
||||
#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
|
||||
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
|
||||
#define MBEDTLS_SSL_MAX_CONTENT_LEN 2000 /**< Maxium fragment length in bytes */
|
||||
#elif OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
|
||||
#define MBEDTLS_SSL_MAX_CONTENT_LEN 900 /**< Maxium fragment length in bytes */
|
||||
#else
|
||||
#define MBEDTLS_SSL_MAX_CONTENT_LEN 768 /**< Maxium fragment length in bytes */
|
||||
|
||||
Regular → Executable
+12
-5
@@ -34,6 +34,7 @@ import logging
|
||||
from ble.ble_connection_constants import BBTC_SERVICE_UUID, BBTC_TX_CHAR_UUID, \
|
||||
BBTC_RX_CHAR_UUID, SERVER_COMMON_NAME
|
||||
from ble.ble_stream import BleStream
|
||||
from ble.udp_stream import UdpStream
|
||||
from ble.ble_stream_secure import BleStreamSecure
|
||||
from ble import ble_scanner
|
||||
from cli.cli import CLI
|
||||
@@ -47,10 +48,12 @@ async def main():
|
||||
|
||||
parser = argparse.ArgumentParser(description='Device parameters')
|
||||
parser.add_argument('--debug', help='Enable debug logs', action='store_true')
|
||||
parser.add_argument('--cert_path', help='Path to certificate chain and key', action='store', default='auth')
|
||||
group = parser.add_mutually_exclusive_group()
|
||||
group.add_argument('--mac', type=str, help='Device MAC address', action='store')
|
||||
group.add_argument('--name', type=str, help='Device name', action='store')
|
||||
group.add_argument('--scan', help='Scan all available devices', action='store_true')
|
||||
group.add_argument('--simulation', help='Connect to simulation node id', action='store')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.debug:
|
||||
@@ -63,12 +66,11 @@ async def main():
|
||||
|
||||
if not (device is None):
|
||||
print(f'Connecting to {device}')
|
||||
ble_stream = await BleStream.create(device.address, BBTC_SERVICE_UUID, BBTC_TX_CHAR_UUID, BBTC_RX_CHAR_UUID)
|
||||
ble_sstream = BleStreamSecure(ble_stream)
|
||||
ble_sstream = BleStreamSecure(device)
|
||||
ble_sstream.load_cert(
|
||||
certfile=path.join('auth', 'commissioner_cert.pem'),
|
||||
keyfile=path.join('auth', 'commissioner_key.pem'),
|
||||
cafile=path.join('auth', 'ca_cert.pem'),
|
||||
certfile=path.join(args.cert_path, 'commissioner_cert.pem'),
|
||||
keyfile=path.join(args.cert_path, 'commissioner_key.pem'),
|
||||
cafile=path.join(args.cert_path, 'ca_cert.pem'),
|
||||
)
|
||||
|
||||
print('Setting up secure channel...')
|
||||
@@ -96,11 +98,16 @@ async def get_device_by_args(args):
|
||||
device = None
|
||||
if args.mac:
|
||||
device = await ble_scanner.find_first_by_mac(args.mac)
|
||||
device = await BleStream.create(device.address, BBTC_SERVICE_UUID, BBTC_TX_CHAR_UUID, BBTC_RX_CHAR_UUID)
|
||||
elif args.name:
|
||||
device = await ble_scanner.find_first_by_name(args.name)
|
||||
device = await BleStream.create(device.address, BBTC_SERVICE_UUID, BBTC_TX_CHAR_UUID, BBTC_RX_CHAR_UUID)
|
||||
elif args.scan:
|
||||
tcat_devices = await ble_scanner.scan_tcat_devices()
|
||||
device = select_device_by_user_input(tcat_devices)
|
||||
device = await BleStream.create(device.address, BBTC_SERVICE_UUID, BBTC_TX_CHAR_UUID, BBTC_RX_CHAR_UUID)
|
||||
elif args.simulation:
|
||||
device = UdpStream("127.0.0.1", int(args.simulation))
|
||||
|
||||
return device
|
||||
|
||||
|
||||
@@ -30,15 +30,13 @@ import asyncio
|
||||
import ssl
|
||||
import logging
|
||||
|
||||
from .ble_stream import BleStream
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BleStreamSecure:
|
||||
|
||||
def __init__(self, ble_stream: BleStream):
|
||||
self.ble_stream = ble_stream
|
||||
def __init__(self, stream):
|
||||
self.stream = stream
|
||||
self.ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
|
||||
self.incoming = ssl.MemoryBIO()
|
||||
self.outgoing = ssl.MemoryBIO()
|
||||
@@ -67,12 +65,12 @@ class BleStreamSecure:
|
||||
# SSLWantWrite means ssl wants to send data over the link,
|
||||
# but might need a receive first
|
||||
except ssl.SSLWantWriteError:
|
||||
output = await self.ble_stream.recv(4096)
|
||||
output = await self.stream.recv(4096)
|
||||
if output:
|
||||
self.incoming.write(output)
|
||||
data = self.outgoing.read()
|
||||
if data:
|
||||
await self.ble_stream.send(data)
|
||||
await self.stream.send(data)
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
# SSLWantRead means ssl wants to receive data from the link,
|
||||
@@ -80,8 +78,8 @@ class BleStreamSecure:
|
||||
except ssl.SSLWantReadError:
|
||||
data = self.outgoing.read()
|
||||
if data:
|
||||
await self.ble_stream.send(data)
|
||||
output = await self.ble_stream.recv(4096)
|
||||
await self.stream.send(data)
|
||||
output = await self.stream.recv(4096)
|
||||
if output:
|
||||
self.incoming.write(output)
|
||||
await asyncio.sleep(0.1)
|
||||
@@ -89,14 +87,14 @@ class BleStreamSecure:
|
||||
async def send(self, bytes):
|
||||
self.ssl_object.write(bytes)
|
||||
encode = self.outgoing.read(4096)
|
||||
await self.ble_stream.send(encode)
|
||||
await self.stream.send(encode)
|
||||
|
||||
async def recv(self, buffersize, timeout=1):
|
||||
end_time = asyncio.get_event_loop().time() + timeout
|
||||
data = await self.ble_stream.recv(buffersize)
|
||||
data = await self.stream.recv(buffersize)
|
||||
while not data and asyncio.get_event_loop().time() < end_time:
|
||||
await asyncio.sleep(0.1)
|
||||
data = await self.ble_stream.recv(buffersize)
|
||||
data = await self.stream.recv(buffersize)
|
||||
if not data:
|
||||
logger.warning('No response when response expected.')
|
||||
return b''
|
||||
@@ -108,10 +106,10 @@ class BleStreamSecure:
|
||||
break
|
||||
# if recv called before entire message was received from the link
|
||||
except ssl.SSLWantReadError:
|
||||
more = await self.ble_stream.recv(buffersize)
|
||||
more = await self.stream.recv(buffersize)
|
||||
while not more:
|
||||
await asyncio.sleep(0.1)
|
||||
more = await self.ble_stream.recv(buffersize)
|
||||
more = await self.stream.recv(buffersize)
|
||||
self.incoming.write(more)
|
||||
return decode
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
"""
|
||||
Copyright (c) 2024, The OpenThread Authors.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
from itertools import count, takewhile
|
||||
from typing import Iterator
|
||||
import logging
|
||||
import time
|
||||
from asyncio import sleep
|
||||
import socket
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UdpStream:
|
||||
BASE_PORT = 10000
|
||||
|
||||
def __init__(self, address, node_id):
|
||||
self.__receive_buffer = b''
|
||||
self.__last_recv_time = None
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self.address = (address, self.BASE_PORT + node_id)
|
||||
|
||||
async def send(self, data):
|
||||
logger.debug(f'sending {data}')
|
||||
self.socket.sendto(data, self.address)
|
||||
return len(data)
|
||||
|
||||
async def recv(self, bufsize):
|
||||
message = self.socket.recv(bufsize)
|
||||
logger.debug(f'retrieved {message}')
|
||||
return message
|
||||
Reference in New Issue
Block a user