diff --git a/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310.cpp b/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310.cpp new file mode 100644 index 0000000000..68c897d8b0 --- /dev/null +++ b/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310.cpp @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2020, 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 "TELIT_ME310.h" +#include "TELIT_ME310_CellularContext.h" +#include "TELIT_ME310_CellularStack.h" +#include "TELIT_ME310_CellularNetwork.h" +#include "AT_CellularNetwork.h" +#include "PinNames.h" +#include "rtos/ThisThread.h" + +using namespace std::chrono_literals; +using namespace mbed; +using namespace rtos; +using namespace events; + +#if !defined(MBED_CONF_TELIT_ME310_PWR) +#define MBED_CONF_TELIT_ME310_PWR NC +#endif + +#if !defined(MBED_CONF_TELIT_ME310_TX) +#define MBED_CONF_TELIT_ME310_TX NC +#endif + +#if !defined(MBED_CONF_TELIT_ME310_RX) +#define MBED_CONF_TELIT_ME310_RX NC +#endif + +#if !defined(MBED_CONF_TELIT_ME310_POLARITY) +#define MBED_CONF_TELIT_ME310_POLARITY 1 // active high +#endif + +static const intptr_t cellular_properties[AT_CellularDevice::PROPERTY_MAX] = { + AT_CellularNetwork::RegistrationModeLAC, // C_EREG + AT_CellularNetwork::RegistrationModeLAC, // C_GREG + AT_CellularNetwork::RegistrationModeLAC, // C_REG + 0, // AT_CGSN_WITH_TYPE + 0, // AT_CGDATA + 1, // AT_CGAUTH + 1, // AT_CNMI + 1, // AT_CSMP + 1, // AT_CMGF + 1, // AT_CSDH + 1, // PROPERTY_IPV4_STACK + 1, // PROPERTY_IPV6_STACK + 1, // PROPERTY_IPV4V6_STACK + 0, // PROPERTY_NON_IP_PDP_TYPE + 1, // PROPERTY_AT_CGEREP, + 1, // PROPERTY_AT_COPS_FALLBACK_AUTO + 6, // PROPERTY_SOCKET_COUNT + 1, // PROPERTY_IP_TCP + 1, // PROPERTY_IP_UDP + 20, // PROPERTY_AT_SEND_DELAY +}; + +TELIT_ME310::TELIT_ME310(FileHandle *fh, PinName pwr, bool active_high) + : AT_CellularDevice(fh), + _active_high(active_high), + _pwr_key(pwr, !_active_high) +{ + set_cellular_properties(cellular_properties); +} + +AT_CellularContext *TELIT_ME310::create_context_impl(ATHandler &at, const char *apn, bool cp_req, bool nonip_req) +{ + return new TELIT_ME310_CellularContext(at, this, apn, cp_req, nonip_req); +} + +nsapi_error_t TELIT_ME310::init() +{ + nsapi_error_t err = AT_CellularDevice::init(); + if (err != NSAPI_ERROR_OK) { + return err; + } + _at.lock(); +#if defined (MBED_CONF_TELIT_ME310_RTS) && defined (MBED_CONF_TELIT_ME310_CTS) + _at.at_cmd_discard("&K3;&C1;&D0", ""); +#else + _at.at_cmd_discard("&K0;&C1;&D0", ""); +#endif + + // AT#QSS=1 + // Enable the Query SIM Status unsolicited indication in the ME. The format of the + // unsolicited indication is the following: + // #QSS: + // The ME informs at + // every SIM status change through the basic unsolicited indication where range is 0...1 + // values: + // - 0: SIM not inserted + // - 1: SIM inserted + _at.at_cmd_discard("#QSS", "=1"); + + // AT#PSNT=1 + // Set command enables unsolicited result code for packet service network type (PSNT) + // having the following format: + // #PSNT: + // values: + // - 0: GPRS network + // - 4: LTE network + // - 5: unknown or not registered + _at.at_cmd_discard("#PSNT", "=1"); + + // AT+CMER=2 + // Set command enables sending of unsolicited result codes from TA to TE in the case of + // indicator state changes. + // Current setting: buffer +CIEV Unsolicited Result Codes in the TA when TA-TE link is + // reserved (e.g. on-line data mode) and flush them to the TE after + // reservation; otherwise forward them directly to the TE + _at.at_cmd_discard("+CMER", "=2"); + + // AT+CMEE=2 + // Set command disables the use of result code +CME ERROR: as an indication of an + // error relating to the +Cxxx command issued. When enabled, device related errors cause the +CME + // ERROR: final result code instead of the default ERROR final result code. ERROR is returned + // normally when the error message is related to syntax, invalid parameters or DTE functionality. + // Current setting: enable and use verbose values + _at.at_cmd_discard("+CMEE", "=2"); + + // AT&W&P + // - AT&W: Execution command stores on profile the complete configuration of the device. If + // parameter is omitted, the command has the same behavior of AT&W0. + // - AT&P: Execution command defines which full profile will be loaded at startup. If parameter + // is omitted, the command has the same behavior as AT&P0 + _at.at_cmd_discard("&W&P", ""); + + return _at.unlock_return_error(); +} + +#if MBED_CONF_TELIT_ME310_PROVIDE_DEFAULT +#include "drivers/BufferedSerial.h" +CellularDevice *CellularDevice::get_default_instance() +{ + static BufferedSerial serial(MBED_CONF_TELIT_ME310_TX, MBED_CONF_TELIT_ME310_RX, MBED_CONF_TELIT_ME310_BAUDRATE); +#if defined (MBED_CONF_TELIT_ME310_RTS) && defined (MBED_CONF_TELIT_ME310_CTS) + serial.set_flow_control(SerialBase::RTSCTS, MBED_CONF_TELIT_ME310_RTS, MBED_CONF_TELIT_ME310_CTS); +#endif + static TELIT_ME310 device(&serial, + MBED_CONF_TELIT_ME310_PWR, + MBED_CONF_TELIT_ME310_POLARITY); + return &device; +} +#endif + +nsapi_error_t TELIT_ME310::hard_power_on() +{ + soft_power_on(); + + return NSAPI_ERROR_OK; +} + +nsapi_error_t TELIT_ME310::soft_power_on() +{ + _pwr_key = _active_high; + ThisThread::sleep_for(500ms); + _pwr_key = !_active_high; + ThisThread::sleep_for(5s); + _pwr_key = _active_high; + ThisThread::sleep_for(5s); + + return NSAPI_ERROR_OK; +} + +nsapi_error_t TELIT_ME310::hard_power_off() +{ + _pwr_key = !_active_high; + ThisThread::sleep_for(10s); + + return NSAPI_ERROR_OK; +} + +nsapi_error_t TELIT_ME310::soft_power_off() +{ + return AT_CellularDevice::soft_power_off(); +} + +AT_CellularNetwork *TELIT_ME310::open_network_impl(ATHandler &at) +{ + return new TELIT_ME310_CellularNetwork(at, *this); +} diff --git a/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310.h b/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310.h new file mode 100644 index 0000000000..f5982e3b4d --- /dev/null +++ b/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020, 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 CELLULAR_TARGETS_TELIT_ME310_TELIT_ME310_H_ +#define CELLULAR_TARGETS_TELIT_ME310_TELIT_ME310_H_ + +#ifdef TARGET_FF_ARDUINO +#ifndef MBED_CONF_TELIT_ME310_TX +#define MBED_CONF_TELIT_ME310_TX D1 +#endif +#ifndef MBED_CONF_TELIT_ME310_RX +#define MBED_CONF_TELIT_ME310_RX D0 +#endif +#endif /* TARGET_FF_ARDUINO */ + +#include "DigitalOut.h" +#include "AT_CellularDevice.h" + +namespace mbed { + +class TELIT_ME310 : public AT_CellularDevice { +public: + /** + * Constructs the Telit ME310 series driver. It is mandatory to provide + * a FileHandle object, the power pin and the polarity of the pin. + */ + TELIT_ME310(FileHandle *fh, PinName pwr, bool active_high); + +protected: // AT_CellularDevice + virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, bool cp_req = false, bool nonip_req = false); + virtual nsapi_error_t init(); + virtual nsapi_error_t hard_power_on(); + virtual nsapi_error_t hard_power_off(); + virtual nsapi_error_t soft_power_on(); + virtual nsapi_error_t soft_power_off(); + virtual AT_CellularNetwork *open_network_impl(ATHandler &at); + +private: + bool _active_high; + DigitalOut _pwr_key; +}; +} // namespace mbed +#endif /* CELLULAR_TARGETS_TELIT_ME310_TELIT_ME310_H_ */ diff --git a/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularContext.cpp b/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularContext.cpp new file mode 100644 index 0000000000..460e19885d --- /dev/null +++ b/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularContext.cpp @@ -0,0 +1,107 @@ +/* + * 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 "TELIT_ME310_CellularContext.h" +#include "TELIT_ME310_CellularStack.h" +#include "CellularLog.h" + +#include "Semaphore.h" + +using namespace mbed_cellular_util; + +namespace mbed { + +TELIT_ME310_CellularContext::TELIT_ME310_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req, bool nonip_req) : + AT_CellularContext(at, device, apn, cp_req, nonip_req) +{ +} + +TELIT_ME310_CellularContext::~TELIT_ME310_CellularContext() +{ +} + +#if !NSAPI_PPP_AVAILABLE +NetworkStack *TELIT_ME310_CellularContext::get_stack() +{ + if (_pdp_type == NON_IP_PDP_TYPE || (_nonip_req && _pdp_type != DEFAULT_PDP_TYPE)) { + tr_error("Requesting stack for NON-IP context! Should request control plane netif: get_cp_netif()"); + return NULL; + } + + if (!_stack) { + _stack = new TELIT_ME310_CellularStack(_at, _cid, (nsapi_ip_stack_t)_pdp_type, *get_device()); + } + + return _stack; +} +#endif // #if !NSAPI_PPP_AVAILABLE + +bool TELIT_ME310_CellularContext::get_context() +{ + bool modem_supports_ipv6 = get_device()->get_property(AT_CellularDevice::PROPERTY_IPV6_PDP_TYPE); + bool modem_supports_ipv4 = get_device()->get_property(AT_CellularDevice::PROPERTY_IPV4_PDP_TYPE); + + _at.cmd_start_stop("+CGDCONT", "?"); + _at.resp_start("+CGDCONT:"); + _cid = -1; + int cid_max = 0; // needed when creating new context + char apn[MAX_ACCESSPOINT_NAME_LENGTH]; + int apn_len = 0; + + while (_at.info_resp()) { + int cid = _at.read_int(); + if (cid > cid_max) { + cid_max = cid; + } + char pdp_type_from_context[10]; + int pdp_type_len = _at.read_string(pdp_type_from_context, sizeof(pdp_type_from_context)); + if (pdp_type_len > 0) { + apn_len = _at.read_string(apn, sizeof(apn)); + if (apn_len >= 0) { + if (_apn && apn_len > 0 && (strcmp(apn, _apn) != 0)) { + continue; + } + + // APN matched -> Check PDP type + pdp_type_t pdp_type = string_to_pdp_type(pdp_type_from_context); + + // Accept exact matching PDP context type or dual PDP context for IPv4/IPv6 only modems + if (get_device()->get_property(pdp_type_t_to_cellular_property(pdp_type)) || + ((pdp_type == IPV4V6_PDP_TYPE && (modem_supports_ipv4 || modem_supports_ipv6)) && !_nonip_req)) { + _pdp_type = pdp_type; + set_new_context(cid); + } + } + } + } + + _at.resp_stop(); + if (_cid == -1) { // no suitable context was found so create a new one + if (!set_new_context(1)) { + return false; + } + } + + // save the apn + if (apn_len > 0 && !_apn) { + memcpy(_found_apn, apn, apn_len + 1); + } + + tr_info("Found PDP context %d", _cid); + return true; +} + +} /* namespace mbed */ diff --git a/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularContext.h b/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularContext.h new file mode 100644 index 0000000000..487ff993a7 --- /dev/null +++ b/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularContext.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020, 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 TELIT_ME310_CELLULARCONTEXT_H_ +#define TELIT_ME310_CELLULARCONTEXT_H_ + +#include "AT_CellularContext.h" + +namespace mbed { + +class TELIT_ME310_CellularContext: public AT_CellularContext { +public: + TELIT_ME310_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req = false, bool nonip_req = false); + virtual ~TELIT_ME310_CellularContext(); +protected: +#if !NSAPI_PPP_AVAILABLE + virtual NetworkStack *get_stack(); +#endif // #if !NSAPI_PPP_AVAILABLE + virtual bool get_context(); +}; + +} /* namespace mbed */ + +#endif // TELIT_ME310_CELLULARCONTEXT_H_ diff --git a/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularNetwork.cpp b/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularNetwork.cpp new file mode 100644 index 0000000000..61fb2748e3 --- /dev/null +++ b/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularNetwork.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019, 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 "TELIT_ME310_CellularNetwork.h" + +using namespace mbed; + +TELIT_ME310_CellularNetwork::TELIT_ME310_CellularNetwork(ATHandler &atHandler, AT_CellularDevice &device) : AT_CellularNetwork(atHandler, device) +{ +} + +TELIT_ME310_CellularNetwork::~TELIT_ME310_CellularNetwork() +{ +} + +nsapi_error_t TELIT_ME310_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opsAct) +{ + switch (opsAct) { + case RAT_GSM: + case RAT_CATM1: + case RAT_NB1: + _op_act = opsAct; + return NSAPI_ERROR_OK; + + default: + _op_act = RAT_UNKNOWN; + return NSAPI_ERROR_UNSUPPORTED; + } +} + + diff --git a/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularNetwork.h b/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularNetwork.h new file mode 100644 index 0000000000..65b6e610fc --- /dev/null +++ b/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularNetwork.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019, 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 TELIT_ME310_CELLULAR_NETWORK_H_ +#define TELIT_ME310_CELLULAR_NETWORK_H_ + +#include "AT_CellularNetwork.h" + +namespace mbed { + +class TELIT_ME310_CellularNetwork : public AT_CellularNetwork { +public: + TELIT_ME310_CellularNetwork(ATHandler &atHandler, AT_CellularDevice &device); + virtual ~ TELIT_ME310_CellularNetwork(); + +protected: + virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat); + +}; + +} // namespace mbed + +#endif // TELIT_ME310_CELLULAR_NETWORK_H_ diff --git a/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularStack.cpp b/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularStack.cpp new file mode 100644 index 0000000000..fa297cc78a --- /dev/null +++ b/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularStack.cpp @@ -0,0 +1,646 @@ +/* + * Copyright (c) 2020, 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 +#include "TELIT_ME310_CellularStack.h" +#include "CellularLog.h" +#include "netsocket/TLSSocket.h" + +static const int sslctxID = 1; + +using namespace mbed; + +TELIT_ME310_CellularStack::TELIT_ME310_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type, AT_CellularDevice &device) : + AT_CellularStack(atHandler, cid, stack_type, device) + , _tls_sec_level(0) +{ + + _at.set_urc_handler("SRING:", mbed::Callback(this, &TELIT_ME310_CellularStack::urc_sring)); + + // TODO: this needs to be handled properly, but now making just a quick hack + // Close all SSL sockets if open. This can happen for example if application processor + // was reset but modem not. Old sockets are still up and running and it prevents + // new SSL configurations and creating new sockets. + for (int i = 1; i <= ME310_SOCKET_MAX; i++) { + _at.clear_error(); + tr_debug("Closing SSL socket %d...", i); + _at.at_cmd_discard("#SSLH", "=", "%d", "0", i); + } + _at.clear_error(); +} + +TELIT_ME310_CellularStack::~TELIT_ME310_CellularStack() +{ +} + +nsapi_error_t TELIT_ME310_CellularStack::socket_listen(nsapi_socket_t handle, int backlog) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t TELIT_ME310_CellularStack::socket_accept(void *server, void **socket, SocketAddress *addr) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t TELIT_ME310_CellularStack::socket_connect(nsapi_socket_t handle, const SocketAddress &address) +{ + CellularSocket *socket = (CellularSocket *)handle; + + if (!is_ipeasy_context_activated(_cid)) { + activate_ipeasy_context(_cid); + } + + int modem_connect_id = -1; + int err = NSAPI_ERROR_NO_CONNECTION; + + int request_connect_id = find_socket_index(socket); + // assert here as its a programming error if the socket container doesn't contain + // specified handle + MBED_ASSERT(request_connect_id != -1); + + _at.lock(); + + // Configure SRING URC + _at.at_cmd_discard("#SCFGEXT", "=", "%d%d%d%d", + request_connect_id + 1, + 1, // SRING URC mode - data amount mode + 0, // Data view mode - text mode + 0); // TCP keepalive - deactivated + if (_at.get_last_error() != NSAPI_ERROR_OK) { + tr_warn("Unable to configure socket %d", request_connect_id); + } + + if (socket->proto == NSAPI_TCP) { + if (socket->tls_socket) { + if (_tls_sec_level == 0) { + _at.unlock(); + return NSAPI_ERROR_AUTH_FAILURE; + } + + _at.at_cmd_discard("#SSLD", "=", "%d%d%s%d", sslctxID, + address.get_port(), + address.get_ip_address(), + 0); // Closure type (0) + if (_at.get_last_error() != NSAPI_ERROR_OK) { + // Hit some sort of error opening the socket + socket->id = -1; + _at.unlock(); + return NSAPI_ERROR_PARAMETER; + } + } else { + _at.at_cmd_discard("#SD", "=", "%d%d%d%s%d%d%d", request_connect_id + 1, 0, address.get_port(), address.get_ip_address(), 0, + 0, 1); + if (_at.get_last_error() != NSAPI_ERROR_OK) { + // Hit some sort of error opening the socket + socket->id = -1; + _at.unlock(); + return NSAPI_ERROR_PARAMETER; + } + } + } + + nsapi_error_t ret_val = _at.get_last_error(); + _at.unlock(); + + if (ret_val == NSAPI_ERROR_OK) { + socket->id = request_connect_id; + socket->remoteAddress = address; + socket->connected = true; + return NSAPI_ERROR_OK; + } + + return err; +} + +void TELIT_ME310_CellularStack::urc_sring() +{ + _at.lock(); + const int sock_id = _at.read_int() - 1; + const int data_bytes_remaining = _at.read_int(); + const nsapi_error_t err = _at.unlock_return_error(); + + if (err != NSAPI_ERROR_OK) { + return; + } + + CellularSocket *sock = find_socket(sock_id); + if (sock) { + sock->pending_bytes = data_bytes_remaining; + if (sock->_cb) { + sock->_cb(sock->_data); + } + } +} + +int TELIT_ME310_CellularStack::get_max_socket_count() +{ + return ME310_SOCKET_MAX; +} + +bool TELIT_ME310_CellularStack::is_protocol_supported(nsapi_protocol_t protocol) +{ + return (protocol == NSAPI_UDP || protocol == NSAPI_TCP); +} + +nsapi_error_t TELIT_ME310_CellularStack::socket_close_impl(int sock_id) +{ + _at.set_at_timeout(ME310_CLOSE_SOCKET_TIMEOUT); + nsapi_error_t err; + CellularSocket *socket = find_socket(sock_id); + if (socket && socket->tls_socket) { + err = _at.at_cmd_discard("#SSLH", "=", "%d%d", sock_id, 0); + if (err == NSAPI_ERROR_OK) { + // Disable TLSSocket settings to prevent reuse on next socket without setting the values + _tls_sec_level = 0; + err = _at.at_cmd_discard("#SSLEN", "=,", "%d%d", sslctxID, 0); + } + } else { + err = _at.at_cmd_discard("#SH", "=", "%d", sock_id + 1); + } + _at.restore_at_timeout(); + + return err; +} + +bool TELIT_ME310_CellularStack::is_ipeasy_context_activated(int context_id) +{ + _at.lock(); + + _at.cmd_start_stop("#SGACT?", ""); + _at.resp_start("#SGACT:"); + + int current_context_id = -1; + int current_stat = -1; + + for (int i = 0; i < ME310_CONTEXT_MAX; i++) { + current_context_id = _at.read_int(); + current_stat = _at.read_int(); + + if (current_context_id == context_id) { + _at.resp_stop(); + _at.unlock(); + return current_stat == ME310_IPEASY_ACTIVATED_CONTEXT; + } + } + + _at.resp_stop(); + _at.unlock(); + return false; +} + +nsapi_error_t TELIT_ME310_CellularStack::activate_ipeasy_context(int context_id) +{ + _at.lock(); + + _at.at_cmd_discard("#SGACT", "=", "%d%d", context_id, ME310_IPEASY_ACTIVATED_CONTEXT); + + return _at.unlock_return_error(); +} + +nsapi_error_t TELIT_ME310_CellularStack::deactivate_ipeasy_context(int context_id) +{ + _at.lock(); + + _at.at_cmd_discard("#SGACT", "=", "%d%d", context_id, ME310_IPEASY_DEACTIVATED_CONTEXT); + + return _at.unlock_return_error(); +} + +nsapi_error_t TELIT_ME310_CellularStack::create_socket_impl(CellularSocket *socket) +{ + int modem_connect_id = -1; + int remote_port = 1; + int err = -1; + + if (!is_ipeasy_context_activated(_cid)) { + tr_debug("IPEasy context not active for %d", _cid); + activate_ipeasy_context(_cid); + } + + int request_connect_id = find_socket_index(socket); + // assert here as its a programming error if the socket container doesn't contain + // specified handle + MBED_ASSERT(request_connect_id != -1); + + // Configure SRING URC + _at.at_cmd_discard("#SCFGEXT", "=", "%d%d%d%d", + request_connect_id + 1, + 1, // SRING URC mode - data amount mode + 0, // Data view mode - text mode + 0); // TCP keepalive - deactivated + if (_at.get_last_error() != NSAPI_ERROR_OK) { + tr_warn("Unable to configure socket %d", request_connect_id); + } + + if (socket->proto == NSAPI_UDP) { + _at.at_cmd_discard("#SD", "=", "%d%d%d%s%d%d%d", request_connect_id + 1, 1, remote_port, + (_ip_ver_sendto == NSAPI_IPv4) ? "127.0.0.1" : "0:0:0:0:0:0:0:1", + 0, socket->localAddress.get_port(), 1); + + if (_at.get_last_error() != NSAPI_ERROR_OK) { + // Hit some sort of error opening the socket + socket->id = -1; + return NSAPI_ERROR_PARAMETER; + } + } else if (socket->proto == NSAPI_TCP) { + _at.at_cmd_discard("#SD", "=", "%d%d%d%s%d%d%d%d", request_connect_id + 1, 0, remote_port, + socket->remoteAddress.get_ip_address(), 0, 0, 1); + + if (_at.get_last_error() != NSAPI_ERROR_OK) { + // Hit some sort of error opening the socket + socket->id = -1; + return NSAPI_ERROR_PARAMETER; + } + } + nsapi_error_t ret_val = _at.get_last_error(); + + if (ret_val == NSAPI_ERROR_OK) { + socket->id = request_connect_id; + } + + return ret_val; +} + +nsapi_size_or_error_t TELIT_ME310_CellularStack::socket_sendto_impl(CellularSocket *socket, const SocketAddress &address, + const void *data, nsapi_size_t size) +{ + tr_debug("TELIT_ME310_CellularStack::socket_sendto_impl()"); + + int sent_len = 0; + bool success = true; + const char *buf = (const char *) data; + nsapi_size_t blk = ME310_MAX_SEND_SIZE; + nsapi_size_t count = size; + int sent_len_before = 0; + int sent_len_after = 0; + + while ((count > 0) && success) { + if (count < blk) { + blk = count; + } + + if (socket->tls_socket) { + sent_len_after = blk; + } else { + // Get the sent count before sending + _at.cmd_start_stop("#SI", "=", "%d", socket->id + 1); + _at.resp_start("#SI:"); + _at.skip_param(); + sent_len_before = _at.read_int(); + _at.resp_stop(); + } + + // Send + if (socket->proto == NSAPI_UDP) { + _at.cmd_start_stop("#SSENDUDPEXT", "=", "%d%d%s%d", socket->id + 1, size, + address.get_ip_address(), address.get_port()); + } else { + if (socket->tls_socket) { + _at.cmd_start_stop("#SSLSENDEXT", "=", "%d%d", socket->id + 1, size); + } else { + _at.cmd_start_stop("#SSENDEXT", "=", "%d%d", socket->id + 1, size); + } + } + + _at.resp_start("> ", true); + _at.write_bytes((uint8_t *)buf, blk); + + _at.cmd_start(CTRL_Z); + _at.cmd_stop(); + _at.resp_start("\r\nOK", true); + _at.resp_stop(); + + if (!socket->tls_socket) { + _at.cmd_start_stop("#SI", "=", "%d", socket->id + 1); + _at.resp_start("#SI:"); + _at.skip_param(); + sent_len_after = _at.read_int(); + _at.resp_stop(); + } + + sent_len = sent_len_after - sent_len_before; + + 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 TELIT_ME310_CellularStack::socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address, + void *buffer, nsapi_size_t size) +{ + tr_debug("TELIT_ME310_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 srecv_size; + Timer timer; + int port = -1; + char ip_address[NSAPI_IP_SIZE + 1]; + + if (socket->pending_bytes == 0) { + _at.process_oob(); // check for SRING URC + if (socket->pending_bytes == 0) { + tr_debug("Socket %d recv would block", socket->id); + return NSAPI_ERROR_WOULD_BLOCK; + } + } + + timer.start(); + while (success && (size > 0)) { + read_blk = ME310_MAX_RECV_SIZE; + if (read_blk > size) { + read_blk = size; + } + if (socket->pending_bytes > 0) { + if (socket->proto == NSAPI_TCP) { + if (socket->tls_socket) { + _at.cmd_start_stop("#SSLRECV", "=", "%d%d", socket->id + 1, read_blk); + } else { + _at.cmd_start_stop("#SRECV", "=", "%d%d", socket->id + 1, read_blk); + } + } else { + _at.cmd_start_stop("#SRECV", "=", "%d%d%d", socket->id + 1, read_blk, 1); + } + + if (socket->tls_socket) { + _at.resp_start("#SSLRECV:"); + } else { + _at.resp_start("#SRECV:"); + } + + if (socket->proto == NSAPI_UDP) { + int data_left = -1; + // UDP has remote_IP and remote_port parameters + _at.read_string(ip_address, sizeof(ip_address)); + port = _at.read_int(); + + // Skip connId + _at.skip_param(); + + srecv_size = _at.read_int(); + data_left = _at.read_int(); + if (srecv_size > size) { + srecv_size = size; + } + + _at.read_bytes((uint8_t *)buffer + count, srecv_size); + } else { + // Skip connId + _at.skip_param(); + + srecv_size = _at.read_int(); + if (srecv_size > size) { + srecv_size = size; + } + + _at.read_bytes((uint8_t *)buffer + count, srecv_size); + } + _at.resp_stop(); + + if (srecv_size > socket->pending_bytes) { + socket->pending_bytes = 0; + } else { + socket->pending_bytes -= srecv_size; + } + + if (srecv_size > 0) { + count += srecv_size; + size -= srecv_size; + } else { + // read() should not fail + success = false; + } + } else if (timer.read_ms() < ME310_SOCKET_TIMEOUT) { + // Wait for URCs + _at.process_oob(); + } else { + if (count == 0) { + // Timeout with nothing received + success = false; + } + break; + } + } + timer.stop(); + + if (!count || (_at.get_last_error() != NSAPI_ERROR_OK)) { + return NSAPI_ERROR_WOULD_BLOCK; + } else { + nsapi_error_size = count; + } + + if (success && address) { + address->set_ip_address(ip_address); + address->set_port(port); + } + + return nsapi_error_size; +} + +#if defined(MBED_CONF_NSAPI_OFFLOAD_TLSSOCKET) && (MBED_CONF_NSAPI_OFFLOAD_TLSSOCKET) + +nsapi_error_t TELIT_ME310_CellularStack::setsockopt(nsapi_socket_t handle, int level, + int optname, const void *optval, unsigned optlen) +{ + CellularSocket *socket = (CellularSocket *)handle; + nsapi_error_t ret = NSAPI_ERROR_OK; + int ssl_enabled = 0; + uint8_t ctrl_z[] = { 0x1A }; + + if (level == NSAPI_TLSSOCKET_LEVEL) { + if (optval) { + _at.lock(); + switch (optname) { + case NSAPI_TLSSOCKET_ENABLE: { + MBED_ASSERT(optlen == sizeof(bool)); + bool *enabled = (bool *)optval; + if (socket->proto == NSAPI_TCP) { + socket->tls_socket = enabled; + + if (enabled) { + _at.at_cmd_discard("#SSLEN", "=", "%d%d", sslctxID, 1); + _at.at_cmd_discard("#SSLSECCFG", "=", "%d%d%d", sslctxID, 0, _tls_sec_level); + _at.at_cmd_discard("#SSLCFG", "=", "%d%d%d%d%d%d", + sslctxID, + _cid, // PDP context ID + 0, // Packet size (0 is default, select automatically) + 90, // Max socket inactivity time (90 is default) + 100, // Default timeout when no timeout is set (100 is default) + 50); // Transmit timeout (50 is default) + + ret = _at.get_last_error(); + } + } else { + tr_error("Trying to set non-TCPSocket as TLSSocket"); + ret = NSAPI_ERROR_PARAMETER; + } + } + break; + + case NSAPI_TLSSOCKET_SET_CACERT: { + _at.cmd_start_stop("#SSLEN", "?"); + _at.resp_start("#SSLEN:"); + + // Skip SSId + _at.skip_param(); + + ssl_enabled = _at.read_int(); + _at.resp_stop(); + + if (ssl_enabled == 0) { + // SSL not enabled, so enable it + _at.at_cmd_discard("#SSLEN", "=", "%d%d", sslctxID, 1); + } + + _at.flush(); + + const char *cacert = (const char *)optval; + int cacert_size = strlen(cacert); + _at.cmd_start_stop("#SSLSECDATA", "=", "%d%d%d%d", sslctxID, + 1, // store data + 1, // CA cert + cacert_size); + _at.resp_start("> ", true); + _at.write_bytes((uint8_t *)cacert, cacert_size); + + _at.write_bytes(ctrl_z, 1); // Send Ctrl+Z + + _at.resp_start("\r\nOK", true); + _at.resp_stop(); + + ret = _at.get_last_error(); + + // Set sec level to "Manage server authentication" if only cacert is in use + if (ret == NSAPI_ERROR_OK && _tls_sec_level == 0) { + _tls_sec_level = 1; + } + } + break; + + case NSAPI_TLSSOCKET_SET_CLCERT: { + _at.cmd_start_stop("#SSLEN", "?"); + _at.resp_start("#SSLEN:"); + + // Skip SSId + _at.skip_param(); + + ssl_enabled = _at.read_int(); + _at.resp_stop(); + + if (ssl_enabled == 0) { + // SSL not enabled, so enable it + _at.at_cmd_discard("#SSLEN", "=", "%d%d", sslctxID, 1); + } + + _at.flush(); + + const char *clcert = (const char *)optval; + int clcert_size = strlen(clcert); + _at.cmd_start_stop("#SSLSECDATA", "=", "%d%d%d%d", sslctxID, + 1, // store data + 0, // client cert + clcert_size); + _at.resp_start("> ", true); + _at.write_bytes((uint8_t *)clcert, clcert_size); + + _at.write_bytes(ctrl_z, 1); // Send Ctrl+Z + + _at.resp_start("\r\nOK", true); + _at.resp_stop(); + + ret = _at.get_last_error(); + + // Set sec level to "Manage server and client authentication if requested by the remote server" + if (ret == NSAPI_ERROR_OK) { + _tls_sec_level = 2; + } + } + break; + + case NSAPI_TLSSOCKET_SET_CLKEY: { + _at.cmd_start_stop("#SSLEN", "?"); + _at.resp_start("#SSLEN:"); + + // Skip SSId + _at.skip_param(); + + ssl_enabled = _at.read_int(); + _at.resp_stop(); + + if (ssl_enabled == 0) { + // SSL not enabled, so enable it + _at.at_cmd_discard("#SSLEN", "=", "%d%d", sslctxID, 1); + } + + _at.flush(); + + const char *clkey = (const char *)optval; + int clkey_size = strlen(clkey); + _at.cmd_start_stop("#SSLSECDATA", "=", "%d%d%d%d", sslctxID, + 1, // store data + 2, // client key + clkey_size); + _at.resp_start("> ", true); + _at.write_bytes((uint8_t *)clkey, clkey_size); + + _at.write_bytes(ctrl_z, 1); // Send Ctrl+Z + + _at.resp_start("\r\nOK", true); + _at.resp_stop(); + + ret = _at.get_last_error(); + + // Set sec level to "Manage server and client authentication if requested by the remote server" + if (ret == NSAPI_ERROR_OK) { + _tls_sec_level = 2; + } + } + break; + + default: + tr_error("Unsupported sockopt (%d)", optname); + ret = NSAPI_ERROR_UNSUPPORTED; + } + _at.unlock(); + } else { + tr_error("No optval!"); + ret = NSAPI_ERROR_PARAMETER; + } + } else { + tr_warning("Unsupported level (%d)", level); + ret = NSAPI_ERROR_UNSUPPORTED; + } + + return ret; +} +#endif \ No newline at end of file diff --git a/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularStack.h b/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularStack.h new file mode 100644 index 0000000000..ee5e65689f --- /dev/null +++ b/features/cellular/framework/targets/TELIT/ME310/TELIT_ME310_CellularStack.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020, 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 TELIT_ME310_CELLULARSTACK_H_ +#define TELIT_ME310_CELLULARSTACK_H_ + +#include "AT_CellularStack.h" +#include "mbed_trace.h" +#include "drivers/Timer.h" + + +namespace mbed { + +#define ME310_SOCKET_MAX 6 +#define ME310_CONTEXT_MAX 6 +#define ME310_CREATE_SOCKET_TIMEOUT 150000 //150 seconds +#define ME310_CLOSE_SOCKET_TIMEOUT 20000 // TCP socket max timeout is >10sec +#define ME310_MAX_RECV_SIZE 1000 +#define ME310_MAX_SEND_SIZE 1023 +#define ME310_SOCKET_BIND_FAIL 556 +#define ME310_IPEASY_ACTIVATED_CONTEXT 1 +#define ME310_IPEASY_DEACTIVATED_CONTEXT 0 +#define ME310_SOCKET_TIMEOUT 1000 +#define CTRL_Z "\x1a" +#define ESC "\x1b" + +class TELIT_ME310_CellularStack : public AT_CellularStack { +public: + TELIT_ME310_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type, AT_CellularDevice &device); + virtual ~TELIT_ME310_CellularStack(); + +protected: // NetworkStack + + 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); + + virtual nsapi_error_t socket_connect(nsapi_socket_t handle, const SocketAddress &address); + +#if defined(MBED_CONF_NSAPI_OFFLOAD_TLSSOCKET) && (MBED_CONF_NSAPI_OFFLOAD_TLSSOCKET) + virtual nsapi_error_t setsockopt(nsapi_socket_t handle, int level, + int optname, const void *optval, unsigned optlen); +#endif + +protected: // AT_CellularStack + + virtual int get_max_socket_count(); + + virtual bool is_protocol_supported(nsapi_protocol_t protocol); + + virtual nsapi_error_t socket_close_impl(int sock_id); + + virtual nsapi_error_t create_socket_impl(CellularSocket *socket); + + 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); + +private: + // URC handler for socket data being received + void urc_sring(); + + bool is_ipeasy_context_activated(int context_id); + nsapi_error_t activate_ipeasy_context(int context_id); + nsapi_error_t deactivate_ipeasy_context(int context_id); + + uint8_t _tls_sec_level; +}; +} // namespace mbed +#endif /* TELIT_ME310_CELLULARSTACK_H_ */ \ No newline at end of file diff --git a/features/cellular/framework/targets/TELIT/ME310/mbed_lib.json b/features/cellular/framework/targets/TELIT/ME310/mbed_lib.json new file mode 100644 index 0000000000..9a16ce0ff1 --- /dev/null +++ b/features/cellular/framework/targets/TELIT/ME310/mbed_lib.json @@ -0,0 +1,38 @@ +{ + "name": "TELIT_ME310", + "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 + }, + "pwr": { + "help": "Power control pin", + "value": null + }, + "polarity": { + "help": "Pin polarity, 1 = Active high, 0 = Active low", + "value": null + }, + "baudrate" : { + "help": "Serial connection baud rate", + "value": 115200 + }, + "provide-default": { + "help": "Provide as default CellularDevice [true/false]", + "value": false + } + } +} +