From 761e01f55ce96e6a5fa18d9afd324080ea8dda2c Mon Sep 17 00:00:00 2001 From: Ari Parkkila Date: Wed, 1 Aug 2018 00:24:37 -0700 Subject: [PATCH] Cellular: Gemalto Cinterion support for ELS61 --- .../GEMALTO/CINTERION/GEMALTO_CINTERION.cpp | 63 +++ .../GEMALTO/CINTERION/GEMALTO_CINTERION.h | 38 ++ .../GEMALTO_CINTERION_CellularNetwork.cpp | 53 ++ .../GEMALTO_CINTERION_CellularNetwork.h | 42 ++ .../GEMALTO_CINTERION_CellularStack.cpp | 491 ++++++++++++++++++ .../GEMALTO_CINTERION_CellularStack.h | 60 +++ .../CINTERION/GEMALTO_CINTERION_Module.cpp | 52 ++ .../CINTERION/GEMALTO_CINTERION_Module.h | 45 ++ 8 files changed, 844 insertions(+) create mode 100644 features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION.cpp create mode 100644 features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION.h create mode 100644 features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularNetwork.cpp create mode 100644 features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularNetwork.h create mode 100644 features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularStack.cpp create mode 100644 features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularStack.h create mode 100644 features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_Module.cpp create mode 100644 features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_Module.h diff --git a/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION.cpp b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION.cpp new file mode 100644 index 0000000000..4b9a94131c --- /dev/null +++ b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION.cpp @@ -0,0 +1,63 @@ +/* + * 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 "GEMALTO_CINTERION_CellularNetwork.h" +#include "GEMALTO_CINTERION_Module.h" +#include "AT_CellularInformation.h" +#include "GEMALTO_CINTERION.h" +#include "CellularLog.h" + +using namespace mbed; +using namespace events; + +GEMALTO_CINTERION::GEMALTO_CINTERION(EventQueue &queue) : AT_CellularDevice(queue) +{ +} + +GEMALTO_CINTERION::~GEMALTO_CINTERION() +{ +} + +CellularNetwork *GEMALTO_CINTERION::open_network(FileHandle *fh) +{ + if (!_network) { + ATHandler *atHandler = get_at_handler(fh); + if (atHandler) { + _network = new GEMALTO_CINTERION_CellularNetwork(*get_at_handler(fh)); + if (!_network) { + release_at_handler(atHandler); + } + } + } + return _network; +} + +nsapi_error_t GEMALTO_CINTERION::init_module(FileHandle *fh) +{ + CellularInformation *information = open_information(fh); + if (!information) { + return NSAPI_ERROR_NO_MEMORY; + } + char model[sizeof("ELS61") + 1]; // sizeof need to be long enough to hold just the model text + nsapi_error_t ret = information->get_model(model, sizeof(model)); + close_information(); + if (ret != NSAPI_ERROR_OK) { + tr_error("Cellular model not found!"); + return NSAPI_ERROR_DEVICE_ERROR; + } + return GEMALTO_CINTERION_Module::detect_model(model); +} diff --git a/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION.h b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION.h new file mode 100644 index 0000000000..e8bf822831 --- /dev/null +++ b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION.h @@ -0,0 +1,38 @@ +/* + * 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 GEMALTO_CINTERION_H_ +#define GEMALTO_CINTERION_H_ + +#include "AT_CellularDevice.h" + +namespace mbed { + +class GEMALTO_CINTERION : public AT_CellularDevice { +public: + + GEMALTO_CINTERION(events::EventQueue &queue); + virtual ~GEMALTO_CINTERION(); + +public: // CellularDevice + virtual CellularNetwork *open_network(FileHandle *fh); + virtual nsapi_error_t init_module(FileHandle *fh); +}; + +} // namespace mbed + +#endif // GEMALTO_CINTERION_H_ diff --git a/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularNetwork.cpp b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularNetwork.cpp new file mode 100644 index 0000000000..aad7304e79 --- /dev/null +++ b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularNetwork.cpp @@ -0,0 +1,53 @@ +/* + * 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 "GEMALTO_CINTERION_CellularNetwork.h" +#include "GEMALTO_CINTERION_CellularStack.h" + +using namespace mbed; + +GEMALTO_CINTERION_CellularNetwork::GEMALTO_CINTERION_CellularNetwork(ATHandler &atHandler) : AT_CellularNetwork(atHandler) +{ +} + +GEMALTO_CINTERION_CellularNetwork::~GEMALTO_CINTERION_CellularNetwork() +{ +} + +NetworkStack *GEMALTO_CINTERION_CellularNetwork::get_stack() +{ + if (!_stack) { + _stack = new GEMALTO_CINTERION_CellularStack(_at, _apn, _cid, _ip_stack_type); + } + return _stack; +} + +bool GEMALTO_CINTERION_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack) +{ + return (requested_stack == IPV4_STACK || requested_stack == IPV6_STACK); +} + +bool GEMALTO_CINTERION_CellularNetwork::has_registration(RegistrationType reg_type) +{ + return (reg_type == C_REG || reg_type == C_GREG || reg_type == C_EREG); +} + +nsapi_error_t GEMALTO_CINTERION_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opsAct) +{ + _op_act = RAT_UNKNOWN; + return NSAPI_ERROR_UNSUPPORTED; +} diff --git a/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularNetwork.h b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularNetwork.h new file mode 100644 index 0000000000..61ad008101 --- /dev/null +++ b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularNetwork.h @@ -0,0 +1,42 @@ +/* + * 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 GEMALTO_CINTERION_CELLULAR_NETWORK_H_ +#define GEMALTO_CINTERION_CELLULAR_NETWORK_H_ + +#include "AT_CellularNetwork.h" + +namespace mbed { + +class GEMALTO_CINTERION_CellularNetwork : public AT_CellularNetwork { +public: + GEMALTO_CINTERION_CellularNetwork(ATHandler &atHandler); + virtual ~GEMALTO_CINTERION_CellularNetwork(); + +protected: + virtual NetworkStack *get_stack(); + + virtual bool has_registration(RegistrationType reg_type); + + virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack); + + virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opsAct); +}; + +} // namespace mbed + +#endif // GEMALTO_CINTERION_CELLULAR_NETWORK_H_ diff --git a/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularStack.cpp b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularStack.cpp new file mode 100644 index 0000000000..e0342a01ed --- /dev/null +++ b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularStack.cpp @@ -0,0 +1,491 @@ +/* + * 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 "GEMALTO_CINTERION_CellularStack.h" +#include "CellularLog.h" + +// defines as per ELS61-E2_ATC_V01.000 +#define SOCKET_MAX 10 +#define UDP_PACKET_SIZE 1460 +#define FAILURE_TIMEOUT (30*1000) // failure timeout in milliseconds on modem side + +/* + * Use connection profile 0 and Internet service profiles starting from 0 for sockets. + */ +#define CONNECTION_PROFILE_ID 0 + +using namespace mbed; + +GEMALTO_CINTERION_CellularStack::GEMALTO_CINTERION_CellularStack(ATHandler &atHandler, const char *apn, + int cid, nsapi_ip_stack_t stack_type) : AT_CellularStack(atHandler, cid, stack_type), _apn(apn) +{ +} + +GEMALTO_CINTERION_CellularStack::~GEMALTO_CINTERION_CellularStack() +{ +} + +GEMALTO_CINTERION_CellularStack::CellularSocket *GEMALTO_CINTERION_CellularStack::find_socket(int sock_id) +{ + CellularSocket *sock = NULL; + for (int i = 0; i < SOCKET_MAX; i++) { + if (_socket[i] && _socket[i]->id == sock_id) { + sock = _socket[i]; + break; + } + } + if (!sock) { + tr_error("Socket not found %d", sock_id); + } + return sock; +} + +void GEMALTO_CINTERION_CellularStack::urc_sis() +{ + int sock_id = _at.read_int(); + int urc_code = _at.read_int(); + //tr_debug("Socket ready: id=%d, urc=%d", sock_id, urc_code); + CellularSocket *sock = find_socket(sock_id); + if (sock) { + if (urc_code == 5) { // data available + if (sock->_cb) { + sock->started = true; + sock->tx_ready = true; + sock->_cb(sock->_data); + } + } else if (urc_code == 2) { // socket closed + sock->created = false; + } + } +} + +void GEMALTO_CINTERION_CellularStack::urc_sisw() +{ + int sock_id = _at.read_int(); + int urc_code = _at.read_int(); + //tr_debug("TX event: socket=%d, urc=%d", sock_id, urc_code); + CellularSocket *sock = find_socket(sock_id); + if (sock) { + if (urc_code == 1) { // ready + if (sock->_cb) { + sock->tx_ready = true; + sock->_cb(sock->_data); + } + } else if (urc_code == 2) { // socket closed + sock->created = false; + } + } +} + +void GEMALTO_CINTERION_CellularStack::urc_sisr() +{ + int sock_id = _at.read_int(); + int urc_code = _at.read_int(); + //tr_debug("RX event: socket=%d, urc=%d", sock_id, urc_code); + CellularSocket *sock = find_socket(sock_id); + if (sock) { + if (urc_code == 1) { // data available + if (sock->_cb) { + sock->rx_avail = true; + sock->_cb(sock->_data); + } + } else if (urc_code == 2) { // socket closed + sock->created = false; + } + } +} + +nsapi_error_t GEMALTO_CINTERION_CellularStack::socket_stack_init() +{ + _at.lock(); + if (create_connection_profile()) { + _at.set_urc_handler("^SIS:", mbed::Callback(this, &GEMALTO_CINTERION_CellularStack::urc_sis)); + _at.set_urc_handler("^SISW:", mbed::Callback(this, &GEMALTO_CINTERION_CellularStack::urc_sisw)); + _at.set_urc_handler("^SISR:", mbed::Callback(this, &GEMALTO_CINTERION_CellularStack::urc_sisr)); + } + return _at.unlock_return_error(); +} + +int GEMALTO_CINTERION_CellularStack::get_max_socket_count() +{ + return SOCKET_MAX; +} + +bool GEMALTO_CINTERION_CellularStack::is_protocol_supported(nsapi_protocol_t protocol) +{ + return (protocol == NSAPI_UDP); +} + +nsapi_error_t GEMALTO_CINTERION_CellularStack::socket_close_impl(int sock_id) +{ + _at.set_at_timeout(FAILURE_TIMEOUT); + _at.cmd_start("AT^SISC="); + _at.write_int(sock_id); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + _at.restore_at_timeout(); + tr_debug("Closed socket %d (err %d)", sock_id, _at.get_last_error()); + return _at.get_last_error(); +} + +// To open socket: +// 1. Select URC mode or polling mode with AT^SCFG +// 2. create a GPRS connection profile with AT^SICS (must have PDP) +// 3. create service profile with AT^SISS and map connectionID to serviceID +// 4. open internet session with AT^SISO (ELS61 tries to attach to a packet domain) +nsapi_error_t GEMALTO_CINTERION_CellularStack::create_socket_impl(CellularSocket *socket) +{ + int connection_profile_id = CONNECTION_PROFILE_ID; + + // setup internet session profile + int internet_service_id = socket->id; + bool foundSrvType = false; + bool foundConIdType = false; + _at.cmd_start("AT^SISS?"); + _at.cmd_stop(); + _at.resp_start("^SISS:"); + /* + * Profile is a list of tag-value map: + * ^SISS: , , + * [^SISS: ...] + */ + while (_at.info_resp()) { + int id = _at.read_int(); + if (id == internet_service_id) { + char paramTag[16]; + int paramTagLen = _at.read_string(paramTag, sizeof(paramTag)); + if (paramTagLen > 0) { + //tr_debug("paramTag %s", paramTag); + char paramValue[100 + 1]; // APN may be up to 100 chars + int paramValueLen = _at.read_string(paramValue, sizeof(paramValue)); + if (paramValueLen >= 0) { + //tr_debug("paramValue %s", paramValue); + if (strcmp(paramTag, "srvType") == 0) { + if (strcmp(paramValue, "Socket") == 0) { + tr_debug("srvType %s", paramValue); + foundSrvType = true; + } + } + if (strcmp(paramTag, "address") == 0) { + if (strncmp(paramValue, "sock", sizeof("sock")) == 0) { + tr_debug("address %s", paramValue); + foundSrvType = true; + } + } + if (strcmp(paramTag, "conId") == 0) { + char buf[10]; + std::sprintf(buf, "%d", connection_profile_id); + tr_debug("conId %s", paramValue); + if (strcmp(paramValue, buf) == 0) { + foundConIdType = true; + } + } + } + } + } + } + _at.resp_stop(); + + if (!foundSrvType) { + _at.cmd_start("AT^SISS="); + _at.write_int(internet_service_id); + _at.write_string("srvType"); + _at.write_string("Socket"); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + } + + if (!foundConIdType) { + _at.cmd_start("AT^SISS="); + _at.write_int(internet_service_id); + _at.write_string("conId"); + _at.write_int(connection_profile_id); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + } + + tr_debug("Internet service %d created (err %d)", internet_service_id, _at.get_last_error()); + + char sock_addr[sizeof("sockudp://") + sizeof(":") + sizeof("65535") + 1]; + std::sprintf(sock_addr, "sockudp://:%u", socket->localAddress.get_port()); + _at.cmd_start("AT^SISS="); + _at.write_int(socket->id); + _at.write_string("address", false); + _at.write_string(sock_addr); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + + + _at.cmd_start("AT^SISO="); + _at.write_int(socket->id); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + if (_at.get_last_error()) { + tr_error("Socket %d open failed!", socket->id); + _at.clear_error(); + socket_close_impl(socket->id); + return NSAPI_ERROR_NO_SOCKET; + } + + socket->created = true; + tr_debug("Socket %d created (err %d)", socket->id, _at.get_last_error()); + + return _at.get_last_error(); +} + +nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_sendto_impl(CellularSocket *socket, + const SocketAddress &address, const void *data, nsapi_size_t size) +{ + tr_debug("Socket %d, sendto %s, len %d", socket->id, address.get_ip_address(), size); + + int ip_version = address.get_ip_version(); + if ((ip_version == NSAPI_IPv4 && _stack_type != IPV4_STACK) || + (ip_version == NSAPI_IPv6 && _stack_type != IPV6_STACK)) { + tr_warn("No IP route for %s", address.get_ip_address()); + return NSAPI_ERROR_NO_SOCKET; + } + + if (!socket->started || !socket->tx_ready) { + tr_debug("Socket %d would block", socket->id); + return NSAPI_ERROR_WOULD_BLOCK; + } + + if (size > UDP_PACKET_SIZE) { + tr_warn("Sending UDP packet size %d (max %d)", size, UDP_PACKET_SIZE); + size = UDP_PACKET_SIZE; + } + + _at.set_at_timeout(FAILURE_TIMEOUT); + _at.cmd_start("AT^SISW="); + _at.write_int(socket->id); + _at.write_int(size); + _at.write_int(0); + char ip_address[sizeof("[1111:2222:3333:4444:5555:6666:7777:8888]:12345") + 1]; + if (address.get_ip_version() == NSAPI_IPv4) { + std::sprintf(ip_address, "%s", address.get_ip_address()); + } else { + std::sprintf(ip_address, "[%s]", address.get_ip_address()); + } + char socket_address[sizeof(ip_address) + sizeof(":") + sizeof("65535") + 1]; + std::sprintf(socket_address, "%s:%u", ip_address, address.get_port()); + _at.write_string(socket_address); + _at.cmd_stop(); + + _at.resp_start("^SISW:"); + if (!_at.info_resp()) { + tr_error("Socket %d send failure", socket->id); + _at.restore_at_timeout(); + return NSAPI_ERROR_DEVICE_ERROR; + } + _at.restore_at_timeout(); + int socket_id = _at.read_int(); + if (socket_id != socket->id) { + tr_error("Socket id %d != %d", socket_id, socket->id); + return NSAPI_ERROR_DEVICE_ERROR; + } + int accept_len = _at.read_int(); + if (accept_len == -1) { + tr_error("Socket %d send failed", socket->id); + return NSAPI_ERROR_DEVICE_ERROR; + } + int unack_len = _at.read_int(); + if (unack_len != 0) { + tr_warn("Socket %d unack_len %d", socket->id, unack_len); + } + + _at.write_bytes((uint8_t *)data, accept_len); + _at.resp_stop(); + + tr_debug("Socket %d sendto %s, %d bytes (err %d)", socket->id, address.get_ip_address(), accept_len, _at.get_last_error()); + + if (_at.get_last_error() == NSAPI_ERROR_OK) { + socket->tx_ready = false; + } + + return (_at.get_last_error() == NSAPI_ERROR_OK) ? accept_len : NSAPI_ERROR_DEVICE_ERROR; +} + +nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address, + void *buffer, nsapi_size_t size) +{ + tr_debug("Socket %d recvfrom %d bytes", socket->id, size); + + if (size > UDP_PACKET_SIZE) { + tr_debug("Socket recvfrom size %d > %d", size, UDP_PACKET_SIZE); + size = UDP_PACKET_SIZE; + } + + if (!socket->rx_avail) { + _at.process_oob(); // check for ^SISR URC + if (!socket->rx_avail) { + tr_debug("Socket %d would block", socket->id); + return NSAPI_ERROR_WOULD_BLOCK; + } + } + + _at.cmd_start("AT^SISR="); + _at.write_int(socket->id); + _at.write_int(size); + _at.cmd_stop(); + + _at.resp_start("^SISR:"); + if (!_at.info_resp()) { + tr_error("Socket %d not responding", socket->id); + return NSAPI_ERROR_DEVICE_ERROR; + } + int socket_id = _at.read_int(); + if (socket_id != socket->id) { + tr_error("Socket recvfrom id %d != %d", socket_id, socket->id); + return NSAPI_ERROR_DEVICE_ERROR; + } + nsapi_size_or_error_t len = _at.read_int(); + if (len == 0) { + tr_warn("Socket %d no data", socket->id); + _at.resp_stop(); + return NSAPI_ERROR_WOULD_BLOCK; + } + if (len == -1) { + tr_error("Socket %d recvfrom failed!", socket->id); + return NSAPI_ERROR_DEVICE_ERROR; + } + socket->rx_avail = false; + if (len >= (nsapi_size_or_error_t)size) { + int remain_len = _at.read_int(); + if (remain_len > 0) { + socket->rx_avail = true; + } + } + char ip_address[sizeof("[1111:2222:3333:4444:5555:6666:7777:8888]:12345") + 1]; + int ip_len = _at.read_string(ip_address, sizeof(ip_address)); + tr_error("ip %s", ip_address); + if (ip_len <= 0) { + tr_error("Socket %d recvfrom addr!", socket->id); + return NSAPI_ERROR_DEVICE_ERROR; + } + if (address) { + char *ip_start = ip_address; + char *ip_stop; + char *port_start; + if (_stack_type == IPV6_STACK) { + ip_start++; // skip '[' + ip_stop = strchr(ip_address, ']'); + if (ip_stop) { + port_start = strchr(ip_stop, ':'); + } + } else { + ip_stop = strchr(ip_address, ':'); + port_start = ip_stop; + } + if (ip_stop && port_start) { + char tmp_ch = *ip_stop; + *ip_stop = '\0'; // split IP and port + address->set_ip_address(ip_start); + port_start++; // skip ':' + int port = std::strtol(port_start, NULL, 10); + address->set_port(port); + tr_debug("IP address %s:%d", address->get_ip_address(), address->get_port()); + *ip_stop = tmp_ch; // restore original IP string + } + } + + nsapi_size_or_error_t recv_len = _at.read_bytes((uint8_t *)buffer, len); + + _at.resp_stop(); + + tr_debug("Socket %d, recvfrom %s, %d bytes (err %d)", socket->id, ip_address, len, _at.get_last_error()); + + return (_at.get_last_error() == NSAPI_ERROR_OK) ? recv_len : NSAPI_ERROR_DEVICE_ERROR; +} + +// setup internet connection profile for sockets +bool GEMALTO_CINTERION_CellularStack::create_connection_profile() +{ + char conParamType[12]; + std::sprintf(conParamType, "GPRS%d", (_stack_type == IPV4_STACK) ? 0 : 6); + _at.cmd_start("AT^SICS?"); + _at.cmd_stop(); + bool foundConnection = false; + bool foundAPN = false; + int connection_profile_id = CONNECTION_PROFILE_ID; + _at.resp_start("^SICS:"); + while (_at.info_resp()) { + int id = _at.read_int(); + tr_debug("SICS %d", id); + if (id == connection_profile_id) { + char paramTag[16]; + int paramTagLen = _at.read_string(paramTag, sizeof(paramTag)); + if (paramTagLen > 0) { + tr_debug("paramTag %s", paramTag); + char paramValue[100 + 1]; // APN may be up to 100 chars + int paramValueLen = _at.read_string(paramValue, sizeof(paramValue)); + if (paramValueLen >= 0) { + tr_debug("paramValue %s", paramValue); + if (strcmp(paramTag, "conType") == 0) { + tr_debug("conType %s", paramValue); + if (strcmp(paramValue, conParamType) == 0) { + foundConnection = true; + } + } + if (strcmp(paramTag, "apn") == 0) { + tr_debug("apn %s", paramValue); + if (strcmp(paramValue, _apn ? _apn : "") == 0) { + foundAPN = true; + } + } + } + } + } + } + _at.resp_stop(); + + if (!foundConnection) { + tr_debug("Socket conType %s", conParamType); + _at.cmd_start("AT^SICS="); + _at.write_int(connection_profile_id); + _at.write_string("conType"); + _at.write_string(conParamType); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + } + + if (!foundAPN && _apn) { + tr_debug("Socket APN %s", _apn ? _apn : ""); + _at.cmd_start("AT^SICS="); + _at.write_int(connection_profile_id); + _at.write_string("apn"); + _at.write_string(_apn); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + } + + // use URC mode + _at.cmd_start("AT^SCFG=\"Tcp/withURCs\",\"on\""); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + + tr_debug("Connection profile %d created, stack_type %d (err %d)", connection_profile_id, _stack_type, _at.get_last_error()); + return _at.get_last_error() == NSAPI_ERROR_OK; +} diff --git a/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularStack.h b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularStack.h new file mode 100644 index 0000000000..c8e26ad280 --- /dev/null +++ b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularStack.h @@ -0,0 +1,60 @@ +/* + * 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 GEMALTO_CINTERION_CELLULAR_STACK_H_ +#define GEMALTO_CINTERION_CELLULAR_STACK_H_ + +#include "AT_CellularStack.h" + +namespace mbed { + +class GEMALTO_CINTERION_CellularStack : public AT_CellularStack { +public: + GEMALTO_CINTERION_CellularStack(ATHandler &atHandler, const char *apn, int cid, nsapi_ip_stack_t stack_type); + virtual ~GEMALTO_CINTERION_CellularStack(); + +protected: + + virtual nsapi_error_t socket_stack_init(); + + 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: + CellularSocket *find_socket(int sock_id); + void urc_sis(); + void urc_sisw(); + void urc_sisr(); + bool create_connection_profile(); + + const char *_apn; +}; + +} // namespace mbed + +#endif /* GEMALTO_CINTERION_CELLULAR_STACK_H_ */ diff --git a/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_Module.cpp b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_Module.cpp new file mode 100644 index 0000000000..006a57bcf3 --- /dev/null +++ b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_Module.cpp @@ -0,0 +1,52 @@ +/* + * 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 "AT_CellularBase.h" +#include "GEMALTO_CINTERION_Module.h" +#include "CellularLog.h" + +using namespace mbed; + +// supported features as per ELS61-E2_ATC_V01.000 +static const AT_CellularBase::SupportedFeature unsupported_features_els61[] = { + AT_CellularBase::AT_CGSN_WITH_TYPE, + AT_CellularBase::SUPPORTED_FEATURE_END_MARK +}; + +GEMALTO_CINTERION_Module::Model GEMALTO_CINTERION_Module::_model; + +nsapi_error_t GEMALTO_CINTERION_Module::detect_model(const char *model) +{ + static const AT_CellularBase::SupportedFeature *unsupported_features; + if (strcmp(model, "ELS61") == 0) { + _model = ModelELS61; + unsupported_features = unsupported_features_els61; + } else { + tr_error("Cinterion model unsupported %s", model); + return NSAPI_ERROR_UNSUPPORTED; + } + tr_info("Cinterion model %s (%d)", model, _model); + AT_CellularBase::set_unsupported_features(unsupported_features); + return NSAPI_ERROR_OK; +} + +GEMALTO_CINTERION_Module::Model GEMALTO_CINTERION_Module::get_model() +{ + return _model; +} diff --git a/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_Module.h b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_Module.h new file mode 100644 index 0000000000..08fcc156c3 --- /dev/null +++ b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_Module.h @@ -0,0 +1,45 @@ +/* + * 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 GEMALTO_CINTERION_MODULE_H_ +#define GEMALTO_CINTERION_MODULE_H_ + +#include "nsapi_types.h" + +namespace mbed { + +class FileHandle; + +class GEMALTO_CINTERION_Module { +public: + /** Actual model of cellular module is needed to make AT command adaptation at runtime + * to support many different models in one cellular driver. + */ + enum Model { + ModelUnknown = 0, + ModelELS61 + }; + static nsapi_error_t detect_model(const char *model); + static Model get_model(); + +private: + static Model _model; +}; + +} // namespace mbed + +#endif // GEMALTO_CINTERION_MODULE_H_