From 022b99325b24ca22ef072dc7eb1148c025f50f7b Mon Sep 17 00:00:00 2001 From: Reda Maher Date: Mon, 29 Jul 2019 21:15:02 +0200 Subject: [PATCH] Cellular: Support Riot Micro cellular device --- .../targets/RiotMicro/AT/RM1000_AT.cpp | 105 +++++ .../targets/RiotMicro/AT/RM1000_AT.h | 41 ++ .../AT/RM1000_AT_CellularContext.cpp | 54 +++ .../RiotMicro/AT/RM1000_AT_CellularContext.h | 35 ++ .../AT/RM1000_AT_CellularNetwork.cpp | 89 +++++ .../RiotMicro/AT/RM1000_AT_CellularNetwork.h | 41 ++ .../RiotMicro/AT/RM1000_AT_CellularStack.cpp | 374 ++++++++++++++++++ .../RiotMicro/AT/RM1000_AT_CellularStack.h | 97 +++++ .../targets/RiotMicro/AT/mbed_lib.json | 29 ++ 9 files changed, 865 insertions(+) create mode 100644 features/cellular/framework/targets/RiotMicro/AT/RM1000_AT.cpp create mode 100644 features/cellular/framework/targets/RiotMicro/AT/RM1000_AT.h create mode 100644 features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularContext.cpp create mode 100644 features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularContext.h create mode 100644 features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularNetwork.cpp create mode 100644 features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularNetwork.h create mode 100644 features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularStack.cpp create mode 100644 features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularStack.h create mode 100644 features/cellular/framework/targets/RiotMicro/AT/mbed_lib.json diff --git a/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT.cpp b/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT.cpp new file mode 100644 index 0000000000..9ea0163c2d --- /dev/null +++ b/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2018, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "RM1000_AT.h" + +#include "RM1000_AT_CellularContext.h" +#include "RM1000_AT_CellularNetwork.h" + +#include "mbed-trace/mbed_trace.h" +#ifndef TRACE_GROUP +#define TRACE_GROUP "RIOT" +#endif // TRACE_GROUP + +using namespace mbed; +using namespace events; +static const uint16_t retry_timeout[] = {1, 2, 4}; +static const intptr_t cellular_properties[AT_CellularBase::PROPERTY_MAX] = { + AT_CellularNetwork::RegistrationModeLAC,// C_EREG + AT_CellularNetwork::RegistrationModeDisable,// C_GREG + AT_CellularNetwork::RegistrationModeDisable,// C_REG + 0, // AT_CGSN_WITH_TYPE + 0, // AT_CGDATA + 0, // AT_CGAUTH + 0, // AT_CNMI + 0, // AT_CSMP + 0, // AT_CMGF + 0, // AT_CSDH + 1, // PROPERTY_IPV4_STACK + 1, // PROPERTY_IPV6_STACK + 1, // PROPERTY_IPV4V6_STACK + 0, // PROPERTY_NON_IP_PDP_TYPE + 0, // PROPERTY_AT_CGEREP +}; + +RM1000_AT::RM1000_AT(FileHandle *fh) : AT_CellularDevice(fh) +{ + tr_debug("RM1000_AT::RM1000_AT"); + AT_CellularBase::set_cellular_properties(cellular_properties); + set_retry_timeout_array(retry_timeout, sizeof(retry_timeout) / sizeof(retry_timeout[0])); +} + +AT_CellularNetwork *RM1000_AT::open_network_impl(ATHandler &at) +{ + tr_debug("RM1000_AT::open_network_impl"); + return new RM1000_AT_CellularNetwork(at); +} + +AT_CellularContext *RM1000_AT::create_context_impl(ATHandler &at, const char *apn, bool cp_req, bool nonip_req) +{ + tr_debug("RM1000_AT::create_context_impl"); + return new RM1000_AT_CellularContext(at, this, apn, cp_req, nonip_req); +} + +nsapi_error_t RM1000_AT::init() +{ + tr_debug("RM1000_AT::init"); + + _at->lock(); + _at->flush(); + _at->cmd_start("ATE0"); // echo off + _at->cmd_stop_read_resp(); + + _at->cmd_start("AT+SIM=physical"); + _at->cmd_stop_read_resp(); + + _at->set_at_timeout(5000); + _at->cmd_start("AT+CFUN=1"); // set full functionality + _at->cmd_stop_read_resp(); + + _at->cmd_start("AT+VERBOSE=0"); // verbose responses + _at->cmd_stop_read_resp(); + + return _at->unlock_return_error(); +} + +#if MBED_CONF_RM1000_AT_PROVIDE_DEFAULT +#include "UARTSerial.h" +CellularDevice *CellularDevice::get_default_instance() +{ + tr_debug("Calling CellularDevice::get_default_instance from RM1000_AT"); + + static UARTSerial serial(MBED_CONF_RM1000_AT_TX, MBED_CONF_RM1000_AT_RX, MBED_CONF_RM1000_AT_BAUDRATE); +#if defined (MBED_CONF_RM1000_AT_RTS) && defined(MBED_CONF_RM1000_AT_CTS) + tr_debug("RM1000_AT flow control: RTS %d CTS %d", MBED_CONF_RM1000_AT_RTS, MBED_CONF_RM1000_AT_CTS); + serial.set_flow_control(SerialBase::RTSCTS, MBED_CONF_RM1000_AT_RTS, MBED_CONF_RM1000_AT_CTS); +#endif + static RM1000_AT device(&serial); + return &device; +} +#endif + diff --git a/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT.h b/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT.h new file mode 100644 index 0000000000..9ee11acb54 --- /dev/null +++ b/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RM1000_AT_H_ +#define RM1000_AT_H_ + +#include "AT_CellularDevice.h" + +namespace mbed { + +class RM1000_AT : public AT_CellularDevice { +public: + RM1000_AT(FileHandle *fh); + +protected: // AT_CellularDevice + virtual AT_CellularNetwork *open_network_impl(ATHandler &at); + virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, bool cp_req = false, bool nonip_req = false); + + virtual nsapi_error_t init(); + +public: // NetworkInterface + void handle_urc(FileHandle *fh); +}; + +} // namespace mbed + +#endif // RM1000_AT_H_ diff --git a/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularContext.cpp b/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularContext.cpp new file mode 100644 index 0000000000..bd3d2ba44b --- /dev/null +++ b/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularContext.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "RM1000_AT_CellularContext.h" + +#include "APN_db.h" +#include "RM1000_AT_CellularStack.h" +#include "mbed-trace/mbed_trace.h" +#ifndef TRACE_GROUP +#define TRACE_GROUP "RIOT" +#endif // TRACE_GROUP + +namespace mbed { + +RM1000_AT_CellularContext::RM1000_AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req, bool nonip_req) : + AT_CellularContext(at, device, apn, cp_req, nonip_req) +{ + tr_debug("Calling RM1000_AT_CellularContext::RM1000_AT_CellularContext"); +} + +RM1000_AT_CellularContext::~RM1000_AT_CellularContext() +{ + tr_debug("Calling RM1000_AT_CellularContext::~RM1000_AT_CellularContext"); +} + +NetworkStack *RM1000_AT_CellularContext::get_stack() +{ + tr_debug("Calling RM1000_AT_CellularContext::get_stack"); + + if (_pdp_type == NON_IP_PDP_TYPE || _cp_in_use) { + tr_error("Requesting stack for NON-IP context! Should request control plane netif: get_cp_netif()"); + return NULL; + } + if (!_stack) { + _stack = new RM1000_AT_CellularStack(_at, _cid, (nsapi_ip_stack_t)_pdp_type); + } + + return _stack; +} + +} /* namespace mbed */ diff --git a/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularContext.h b/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularContext.h new file mode 100644 index 0000000000..4e997ce9b7 --- /dev/null +++ b/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularContext.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef RM1000_AT_CELLULARCONTEXT_H_ +#define RM1000_AT_CELLULARCONTEXT_H_ + +#include "AT_CellularContext.h" + +namespace mbed { + +class RM1000_AT_CellularContext: public AT_CellularContext { +public: + RM1000_AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req = false, bool nonip_req = false); + virtual ~RM1000_AT_CellularContext(); + +protected: + virtual NetworkStack *get_stack(); +}; + +} /* namespace mbed */ + +#endif // RM1000_AT_CELLULARCONTEXT_H_ diff --git a/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularNetwork.cpp b/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularNetwork.cpp new file mode 100644 index 0000000000..f8c3fd5c1b --- /dev/null +++ b/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularNetwork.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2018, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "rtos.h" +#include "CellularCommon.h" +#include "RM1000_AT_CellularNetwork.h" +#include "platform/mbed_wait_api.h" + +#include "mbed-trace/mbed_trace.h" +#ifndef TRACE_GROUP +#define TRACE_GROUP "RIOT" +#endif // TRACE_GROUP +using namespace mbed; + +// Callback for MODEM faults URC. +void RM1000_AT_CellularNetwork::MODEM_FAULT_URC() +{ + tr_debug("RM1000_AT_CellularNetwork::ASSERTED_URC"); + _connect_status = NSAPI_STATUS_DISCONNECTED; + if (_connection_status_cb) { + _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED); + } +} + +RM1000_AT_CellularNetwork::RM1000_AT_CellularNetwork(ATHandler &atHandler) : AT_CellularNetwork(atHandler) +{ + tr_debug("RM1000_AT_CellularNetwork::RM1000_B0_CellularNetwork"); + _op_act = RAT_UNKNOWN; + _at.set_urc_handler("ASSERTED!", callback(this, &RM1000_AT_CellularNetwork::MODEM_FAULT_URC)); + _at.set_urc_handler("ERRCODE:", callback(this, &RM1000_AT_CellularNetwork::MODEM_FAULT_URC)); + _at.set_urc_handler("Halt the processor", callback(this, &RM1000_AT_CellularNetwork::MODEM_FAULT_URC)); +} + +RM1000_AT_CellularNetwork::~RM1000_AT_CellularNetwork() +{ + tr_debug("RM1000_AT_CellularNetwork::~RM1000_B0_CellularNetwork"); + + _at.set_urc_handler("ASSERTED!", NULL); + _at.set_urc_handler("ERRCODE:", NULL); + _at.set_urc_handler("Halt the processor", NULL); +} + +nsapi_error_t RM1000_AT_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opRat) +{ + nsapi_error_t ret = NSAPI_ERROR_OK; + + tr_debug("RM1000_AT_CellularNetwork::set_access_technology_impl %d", opRat); + + switch (opRat) { + case RAT_NB1: + break; + default: { + _op_act = RAT_UNKNOWN; + ret = NSAPI_ERROR_UNSUPPORTED; + } + } + + return (ret); +} + +nsapi_error_t RM1000_AT_CellularNetwork::set_registration_urc(RegistrationType type, bool urc_on) +{ + tr_debug("RM1000_AT_CellularNetwork::set_registration_urc"); + + int index = (int)type; + MBED_ASSERT(index >= 0 && index < C_MAX); + + RegistrationMode mode = (RegistrationMode)get_property((AT_CellularBase::CellularProperty)type); + if (mode == RegistrationModeDisable) { + return NSAPI_ERROR_UNSUPPORTED; + } else { + return NSAPI_ERROR_OK; /* FIXME use at commands */ + } +} diff --git a/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularNetwork.h b/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularNetwork.h new file mode 100644 index 0000000000..ceb9974d50 --- /dev/null +++ b/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularNetwork.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RM1000_AT_CELLULAR_NETWORK_H_ +#define RM1000_AT_CELLULAR_NETWORK_H_ + +#include "AT_CellularNetwork.h" + +namespace mbed { + +class RM1000_AT_CellularNetwork : public AT_CellularNetwork { +public: + RM1000_AT_CellularNetwork(ATHandler &atHandler); + virtual ~RM1000_AT_CellularNetwork(); + + virtual nsapi_error_t set_registration_urc(RegistrationType type, bool on); + +protected: + virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat); +private: + // URC handlers + void MODEM_FAULT_URC(); +}; + +} // namespace mbed + +#endif // RM1000_AT_CELLULAR_NETWORK_H_ diff --git a/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularStack.cpp b/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularStack.cpp new file mode 100644 index 0000000000..4068e55d3d --- /dev/null +++ b/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularStack.cpp @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2018, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "RM1000_AT_CellularStack.h" + +#include "mbed_poll.h" + +#include "mbed-trace/mbed_trace.h" +#ifndef TRACE_GROUP +#define TRACE_GROUP "RIOT" +#endif // TRACE_GROUP + +using namespace mbed; +using namespace mbed_cellular_util; + +RM1000_AT_CellularStack::RM1000_AT_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type) : AT_CellularStack(atHandler, cid, stack_type) +{ + tr_debug("RM1000_AT_CellularStack::RM1000_AT_CellularStack"); + + // URC handlers for sockets + _at.set_urc_handler("+RUSORCV:", callback(this, &RM1000_AT_CellularStack::RUSORCV_URC)); + _at.set_urc_handler("+RUSOCL:", callback(this, &RM1000_AT_CellularStack::RUSOCL_URC)); +} + +RM1000_AT_CellularStack::~RM1000_AT_CellularStack() +{ + tr_debug("RM1000_AT_CellularStack::~RM1000_AT_CellularStack"); + + _at.set_urc_handler("+RUSORCV:", NULL); + _at.set_urc_handler("+RUSOCL:", NULL); +} + +nsapi_error_t RM1000_AT_CellularStack::socket_listen(nsapi_socket_t handle, int backlog) +{ + tr_debug("RM1000_AT_CellularStack::socket_listen"); + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t RM1000_AT_CellularStack::socket_accept(void *server, void **socket, SocketAddress *addr) +{ + tr_debug("RM1000_AT_CellularStack::socket_accept"); + return NSAPI_ERROR_UNSUPPORTED; +} + +// Callback for Socket Receive URC. +void RM1000_AT_CellularStack::RUSORCV_URC() +{ + int a, b; + CellularSocket *socket; + + a = _at.read_int(); + b = _at.read_int(); + socket = find_socket(a); + if (socket != NULL) { + socket->pending_bytes = b; + // No debug prints here as they can affect timing + // and cause data loss in UARTSerial + if (socket->_cb != NULL) { + socket->_cb(socket->_data); + } + } +} + +// Callback for Socket Close URC. +void RM1000_AT_CellularStack::RUSOCL_URC() +{ + int a; + CellularSocket *socket; + + a = _at.read_int(); + socket = find_socket(a); + clear_socket(socket); +} + +int RM1000_AT_CellularStack::get_max_socket_count() +{ + tr_debug("RM1000_AT_CellularStack::get_max_socket_count"); + return RM1000_MAX_SOCKET; +} + +bool RM1000_AT_CellularStack::is_protocol_supported(nsapi_protocol_t protocol) +{ + return (protocol == NSAPI_UDP || protocol == NSAPI_TCP); +} + +nsapi_error_t RM1000_AT_CellularStack::create_socket_impl(CellularSocket *socket) +{ + tr_debug("RM1000_AT_CellularStack::create_socket_impl"); + + int sock_id = SOCKET_UNUSED; + + _at.lock(); + if (socket->proto == NSAPI_UDP) { + _at.cmd_start("AT+RSOCR=0"); + _at.cmd_stop(); + + _at.resp_start("+RSOCR:"); + sock_id = _at.read_int(); + _at.resp_stop(); + } else if (socket->proto == NSAPI_TCP) { + _at.cmd_start("AT+RSOCR=1"); + _at.cmd_stop(); + + _at.resp_start("+RSOCR:"); + sock_id = _at.read_int(); + _at.resp_stop(); + } // Unsupported protocol is checked in "is_protocol_supported" function + + if ((_at.get_last_error() != NSAPI_ERROR_OK) || (sock_id == -1)) { + _at.unlock(); + tr_error("RM1000_AT_CellularStack::create_socket_impl error sock_id=%d err=%d", sock_id, _at.get_last_error()); + return NSAPI_ERROR_NO_SOCKET; + } + _at.unlock(); + + // Check for duplicate socket id delivered by modem + for (int i = 0; i < RM1000_MAX_SOCKET; i++) { + CellularSocket *sock = _socket[i]; + if (sock && sock != socket && sock->id == sock_id) { + return NSAPI_ERROR_NO_SOCKET; + } + } + + socket->id = sock_id; + + return NSAPI_ERROR_OK; +} + +nsapi_error_t RM1000_AT_CellularStack::socket_connect(nsapi_socket_t handle, const SocketAddress &addr) +{ + tr_debug("RM1000_AT_CellularStack::socket_connect"); + + CellularSocket *socket = (CellularSocket *)handle; + + if (socket) { + if (socket->id == SOCKET_UNUSED) { + nsapi_error_t err = create_socket_impl(socket); + if (err != NSAPI_ERROR_OK) { + return err; + } + } + } else { + return NSAPI_ERROR_DEVICE_ERROR; + } + + _at.lock(); + _at.cmd_start("AT+RSOCO="); + _at.write_int(socket->id); + _at.write_string(addr.get_ip_address(), false); + _at.write_int(addr.get_port()); + _at.cmd_stop(); + _at.resp_start("+RSOCO:"); + int socket_id = _at.read_int(); + _at.resp_stop(); + nsapi_error_t error = _at.get_last_error(); + _at.unlock(); + + if ((error == NSAPI_ERROR_OK) && (socket_id == socket->id)) { + socket->remoteAddress = addr; + socket->connected = true; + return NSAPI_ERROR_OK; + } + + return NSAPI_ERROR_NO_CONNECTION; +} + +nsapi_size_or_error_t RM1000_AT_CellularStack::socket_sendto_impl(CellularSocket *socket, const SocketAddress &address, + const void *data, nsapi_size_t size) +{ + tr_debug("RM1000_AT_CellularStack::socket_sendto_impl"); + + int sent_len = 0; + pollfh fhs; + fhs.fh = _at.get_file_handle(); + fhs.events = POLLIN; + + bool success = true; + const char *buf = (const char *) data; + nsapi_size_t blk = RM1000_MAX_PACKET_SIZE; + nsapi_size_t count = size; + + while ((count > 0) && success) { + if (count < blk) { + blk = count; + } + _at.cmd_start("AT+RSOSND="); + _at.write_int(socket->id); + _at.write_int(blk); + if (socket->proto == NSAPI_UDP) { + _at.write_string(address.get_ip_address(), false); + _at.write_int(address.get_port()); + } + _at.cmd_stop(); + (void)poll(&fhs, 1, 50); + _at.write_bytes((uint8_t *)buf, blk); + + _at.resp_start("+RSOSND:"); + _at.skip_param(); // skip socket id + sent_len = _at.read_int(); + _at.resp_stop(); + + if ((sent_len >= (int) blk) && + (_at.get_last_error() == NSAPI_ERROR_OK)) { + } else { + success = false; + } + + buf += blk; + count -= blk; + } + + if (success && _at.get_last_error() == NSAPI_ERROR_OK) { + return size - count; + } + + return _at.get_last_error(); +} + +nsapi_size_or_error_t RM1000_AT_CellularStack::socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address, + void *buffer, nsapi_size_t size) +{ + tr_debug("RM1000_AT_CellularStack::socket_recvfrom_impl"); + + nsapi_size_or_error_t nsapi_error_size = NSAPI_ERROR_DEVICE_ERROR; + bool success = true; + nsapi_size_t read_blk; + nsapi_size_t count = 0; + nsapi_size_t rsorcv_sz; + char ipAddress[NSAPI_IP_SIZE]; + int port = 0; + Timer timer; + + if (socket->pending_bytes == 0) { + _at.process_oob(); + if (socket->pending_bytes == 0) { + return NSAPI_ERROR_WOULD_BLOCK; + } + } + + timer.start(); + while (success && (size > 0)) { + read_blk = RM1000_MAX_PACKET_SIZE; + if (read_blk > size) { + read_blk = size; + } + if (socket->pending_bytes > 0) { + _at.cmd_start("AT+RSORCV="); + _at.write_int(socket->id); + _at.write_int(read_blk); + _at.cmd_stop(); + + _at.resp_start("+RSORCV:"); + _at.skip_param(); // receiving socket id + rsorcv_sz = _at.read_int(); + if (socket->proto == NSAPI_UDP) { + _at.read_string(ipAddress, sizeof(ipAddress)); + port = _at.read_int(); + } + if (rsorcv_sz > size) { + rsorcv_sz = size; + } + _at.read_bytes((uint8_t *)buffer + count, rsorcv_sz); + _at.resp_stop(); + + // Must use what +RSORCV returns here as it may be less or more than we asked for + if (rsorcv_sz > socket->pending_bytes) { + socket->pending_bytes = 0; + } else { + socket->pending_bytes -= rsorcv_sz; + } + + if (rsorcv_sz > 0) { + count += rsorcv_sz; + size -= rsorcv_sz; + } else { + // read() should not fail + success = false; + } + } else if (timer.read_ms() < SOCKET_TIMEOUT) { + // Wait for URCs + _at.process_oob(); + } else { + if (count == 0) { + // Timeout with nothing received + nsapi_error_size = NSAPI_ERROR_WOULD_BLOCK; + success = false; + } + size = 0; // This simply to cause an exit + } + } + timer.stop(); + + if (!count || (_at.get_last_error() != NSAPI_ERROR_OK)) { + return NSAPI_ERROR_WOULD_BLOCK; + } else { + nsapi_error_size = count; + } + + if (success && socket->proto == NSAPI_UDP && address) { + address->set_ip_address(ipAddress); + address->get_ip_address(); + address->set_port(port); + } + + return nsapi_error_size; +} + +nsapi_error_t RM1000_AT_CellularStack::socket_close_impl(int sock_id) +{ + tr_debug("RM1000_AT_CellularStack::socket_close_impl"); + + _at.cmd_start("AT+RSOCL="); + _at.write_int(sock_id); + _at.cmd_stop_read_resp(); + + return _at.get_last_error(); +} + +// Clear out the storage for a socket +void RM1000_AT_CellularStack::clear_socket(CellularSocket *socket) +{ + if (socket != NULL) { + socket->id = SOCKET_UNUSED; + socket->pending_bytes = 0; + socket->_cb = NULL; + socket->_data = NULL; + } +} + +nsapi_error_t RM1000_AT_CellularStack::gethostbyname(const char *host, SocketAddress *address, nsapi_version_t version, const char *interface_name) +{ + tr_debug("RM1000_AT_CellularStack::gethostbyname"); + + char ipAddress[NSAPI_IP_SIZE]; + nsapi_error_t err = NSAPI_ERROR_NO_CONNECTION; + + _at.lock(); + if (address->set_ip_address(host)) { + err = NSAPI_ERROR_OK; + } else { + // This interrogation can sometimes take longer than the usual 8 seconds + _at.cmd_start("AT+RDNS="); + _at.write_string(host, false); + _at.cmd_stop(); + + _at.set_at_timeout(70000); + _at.resp_start("+RDNS:"); + if (_at.info_resp()) { + _at.read_string(ipAddress, sizeof(ipAddress)); + if (address->set_ip_address(ipAddress)) { + err = NSAPI_ERROR_OK; + } + } + _at.resp_stop(); + _at.restore_at_timeout(); + } + _at.unlock(); + + return err; +} diff --git a/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularStack.h b/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularStack.h new file mode 100644 index 0000000000..5c7302b741 --- /dev/null +++ b/features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularStack.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef RM1000_AT_CELLULARSTACK_H_ +#define RM1000_AT_CELLULARSTACK_H_ + +#include "AT_CellularStack.h" +#include "CellularUtil.h" +#include "mbed_wait_api.h" +#include "drivers/Timer.h" + + +namespace mbed { + +class RM1000_AT_CellularStack : public AT_CellularStack { +public: + RM1000_AT_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type); + virtual ~RM1000_AT_CellularStack(); + + virtual nsapi_error_t gethostbyname(const char *host, + SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC, const char *interface_name = NULL); + +protected: + virtual nsapi_error_t socket_listen(nsapi_socket_t handle, int backlog); + + virtual nsapi_error_t socket_accept(nsapi_socket_t server, + nsapi_socket_t *handle, SocketAddress *address = 0); + +protected: // AT_CellularStack + + /** The profile to use (on board the modem). + */ +#define PROFILE "0" + + /** Socket "unused" value. + */ + static const int SOCKET_UNUSED = -1; + + /** Socket timeout value in milliseconds. + * Note: the sockets layer above will retry the + * call to the functions here when they return NSAPI_ERROR_WOULD_BLOCK + * and the user has set a larger timeout or full blocking. + */ + static const int SOCKET_TIMEOUT = 1000; + + /** Maximum allowed sockets. + */ + static const int RM1000_MAX_SOCKET = 7; + + /** The maximum number of bytes in a packet that can be write/read from + * the AT interface in one go. + */ + static const int RM1000_MAX_PACKET_SIZE = 1024; + + virtual int get_max_socket_count(); + + virtual bool is_protocol_supported(nsapi_protocol_t protocol); + + virtual nsapi_error_t create_socket_impl(CellularSocket *socket); + + virtual nsapi_error_t socket_connect(nsapi_socket_t handle, const SocketAddress &address); + + virtual nsapi_size_or_error_t socket_sendto_impl(CellularSocket *socket, const SocketAddress &address, + const void *data, nsapi_size_t size); + + virtual nsapi_size_or_error_t socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address, + void *buffer, nsapi_size_t size); + + virtual nsapi_error_t socket_close_impl(int sock_id); + +private: + // URC handlers + void RUSORCV_URC(); + void RUSOCL_URC(); + + /** Clear out the storage for a socket. + * + * @param id Cellular Socket. + * @return None + */ + void clear_socket(CellularSocket *socket); +}; +} // namespace mbed +#endif /* RM1000_AT_CELLULARSTACK_H_ */ diff --git a/features/cellular/framework/targets/RiotMicro/AT/mbed_lib.json b/features/cellular/framework/targets/RiotMicro/AT/mbed_lib.json new file mode 100644 index 0000000000..78b3aae718 --- /dev/null +++ b/features/cellular/framework/targets/RiotMicro/AT/mbed_lib.json @@ -0,0 +1,29 @@ +{ + "name": "RM1000_AT", + "config": { + "tx": { + "help": "TX pin for serial connection. D1 assumed if Arduino Form Factor, needs to be set/overwritten otherwise.", + "value": null + }, + "rx": { + "help": "RX pin for serial connection. D0 assumed if Arduino Form Factor, needs to be set/overwritten otherwise.", + "value": null + }, + "rts": { + "help": "RTS pin for serial connection", + "value": null + }, + "cts": { + "help": "CTS pin for serial connection", + "value": null + }, + "baudrate" : { + "help": "Serial connection baud rate", + "value": 230400 + }, + "provide-default": { + "help": "Provide as default CellularDevice [true/false]", + "value": false + } + } +}