diff --git a/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularStack.cpp b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularStack.cpp index 1b7dc3a5c1..feedb79edf 100644 --- a/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularStack.cpp +++ b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularStack.cpp @@ -65,8 +65,6 @@ void GEMALTO_CINTERION_CellularStack::urc_sis() int urc_code = _at.read_int(); CellularSocket *sock = find_socket(sock_id); if (sock) { - // Currently only UDP is supported so there is need to handle only some error codes here, - // and others are detected on sendto/recvfrom responses. if (urc_code == 5) { // The service is ready to use (ELS61 and EMS31). if (sock->_cb) { sock->started = true; @@ -81,12 +79,17 @@ void GEMALTO_CINTERION_CellularStack::urc_sisw() { int sock_id = _at.read_int(); int urc_code = _at.read_int(); + sisw_urc_handler(sock_id, urc_code); +} + +void GEMALTO_CINTERION_CellularStack::sisw_urc_handler(int sock_id, int urc_code) +{ CellularSocket *sock = find_socket(sock_id); if (sock) { if (urc_code == 1) { // ready if (sock->_cb) { sock->tx_ready = true; - if (GEMALTO_CINTERION_Module::get_model() == GEMALTO_CINTERION_Module::ModelBGS2) { + if (sock->proto == NSAPI_TCP || GEMALTO_CINTERION_Module::get_model() == GEMALTO_CINTERION_Module::ModelBGS2) { sock->started = true; } sock->_cb(sock->_data); @@ -99,6 +102,11 @@ void GEMALTO_CINTERION_CellularStack::urc_sisr() { int sock_id = _at.read_int(); int urc_code = _at.read_int(); + sisr_urc_handler(sock_id, urc_code); +} + +void GEMALTO_CINTERION_CellularStack::sisr_urc_handler(int sock_id, int urc_code) +{ CellularSocket *sock = find_socket(sock_id); if (sock) { if (urc_code == 1) { // data available @@ -139,7 +147,7 @@ int GEMALTO_CINTERION_CellularStack::get_max_socket_count() bool GEMALTO_CINTERION_CellularStack::is_protocol_supported(nsapi_protocol_t protocol) { - return (protocol == NSAPI_UDP); + return (protocol == NSAPI_UDP || protocol == NSAPI_TCP); } nsapi_error_t GEMALTO_CINTERION_CellularStack::socket_close_impl(int sock_id) @@ -170,11 +178,20 @@ nsapi_error_t GEMALTO_CINTERION_CellularStack::socket_close_impl(int sock_id) nsapi_error_t GEMALTO_CINTERION_CellularStack::socket_open_defer(CellularSocket *socket, const SocketAddress *address) { // host address (IPv4) and local+remote port is needed only for BGS2 which does not support UDP server socket - char sock_addr[sizeof("sockudp://") - 1 + NSAPI_IPv4_SIZE + sizeof(":12345;port=12345") - 1 + 1]; - if (GEMALTO_CINTERION_Module::get_model() != GEMALTO_CINTERION_Module::ModelBGS2) { - std::sprintf(sock_addr, "sockudp://%s:%u", address ? address->get_ip_address() : "", socket->localAddress.get_port()); + char sock_addr[sizeof("sockudp://") - 1 + NSAPI_IPv6_SIZE + sizeof("[]:12345;port=12345") - 1 + 1]; + + if (socket->proto == NSAPI_UDP) { + if (GEMALTO_CINTERION_Module::get_model() != GEMALTO_CINTERION_Module::ModelBGS2) { + std::sprintf(sock_addr, "sockudp://%s:%u", address ? address->get_ip_address() : "", socket->localAddress.get_port()); + } else { + std::sprintf(sock_addr, "sockudp://%s:%u;port=%u", address->get_ip_address(), address->get_port(), socket->localAddress.get_port()); + } } else { - std::sprintf(sock_addr, "sockudp://%s:%u;port=%u", address->get_ip_address(), address->get_port(), socket->localAddress.get_port()); + if (address->get_ip_version() == NSAPI_IPv4) { + std::sprintf(sock_addr, "socktcp://%s:%u", address->get_ip_address(), address->get_port()); + } else { + std::sprintf(sock_addr, "socktcp://[%s]:%u", address->get_ip_address(), address->get_port()); + } } _at.cmd_start("AT^SISS="); @@ -281,9 +298,12 @@ nsapi_error_t GEMALTO_CINTERION_CellularStack::create_socket_impl(CellularSocket tr_debug("Internet service %d (err %d)", internet_service_id, _at.get_last_error()); - if (GEMALTO_CINTERION_Module::get_model() != GEMALTO_CINTERION_Module::ModelBGS2) { - return socket_open_defer(socket); + if (socket->proto == NSAPI_UDP) { + if (GEMALTO_CINTERION_Module::get_model() != GEMALTO_CINTERION_Module::ModelBGS2) { + return socket_open_defer(socket); + } } + return _at.get_last_error(); } @@ -292,13 +312,16 @@ nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_sendto_impl(Cellul { 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->proto == NSAPI_UDP) { + const 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 (GEMALTO_CINTERION_Module::get_model() == GEMALTO_CINTERION_Module::ModelBGS2) { + + if (socket->proto == NSAPI_UDP && GEMALTO_CINTERION_Module::get_model() == GEMALTO_CINTERION_Module::ModelBGS2) { tr_debug("Send addr %s, prev addr %s", address.get_ip_address(), socket->remoteAddress.get_ip_address()); if (address != socket->remoteAddress) { if (socket->started) { @@ -340,16 +363,22 @@ nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_sendto_impl(Cellul _at.cmd_start("AT^SISW="); _at.write_int(socket->id); _at.write_int(size); + if (GEMALTO_CINTERION_Module::get_model() != GEMALTO_CINTERION_Module::ModelBGS2) { _at.write_int(0); - char socket_address[NSAPI_IPv6_SIZE + sizeof("[]:12345") - 1 + 1]; - if (address.get_ip_version() == NSAPI_IPv4) { - std::sprintf(socket_address, "%s:%u", address.get_ip_address(), address.get_port()); - } else { - std::sprintf(socket_address, "[%s]:%u", address.get_ip_address(), address.get_port()); + + // UDP requires Udp_RemClient + if (socket->proto == NSAPI_UDP) { + char socket_address[NSAPI_IPv6_SIZE + sizeof("[]:12345") - 1 + 1]; + if (address.get_ip_version() == NSAPI_IPv4) { + std::sprintf(socket_address, "%s:%u", address.get_ip_address(), address.get_port()); + } else { + std::sprintf(socket_address, "[%s]:%u", address.get_ip_address(), address.get_port()); + } + _at.write_string(socket_address); } - _at.write_string(socket_address); } + _at.cmd_stop(); sisw_retry: @@ -359,29 +388,30 @@ sisw_retry: _at.restore_at_timeout(); return NSAPI_ERROR_DEVICE_ERROR; } - _at.restore_at_timeout(); int socket_id = _at.read_int(); if (socket_id != socket->id) { + // We might have read the SISW URC so let's try to handle it + const int urc_code = _at.read_int(); + const int extra = _at.read_int(); + if (urc_code != -1 && extra == -1) { + sisw_urc_handler(socket_id, urc_code); + goto sisw_retry; + } + _at.restore_at_timeout(); 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); + _at.restore_at_timeout(); 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); - if (GEMALTO_CINTERION_Module::get_model() != GEMALTO_CINTERION_Module::ModelBGS2) { - // assume that an URC was received when unackData is not received - _at.resp_stop(); - goto sisw_retry; - } - } + _at.skip_param(); // unackData _at.write_bytes((uint8_t *)data, accept_len); _at.resp_stop(); + _at.restore_at_timeout(); tr_debug("Socket %d sendto %s, %d bytes (err %d)", socket->id, address.get_ip_address(), accept_len, _at.get_last_error()); @@ -417,16 +447,25 @@ nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_recvfrom_impl(Cell _at.write_int(size); _at.cmd_stop(); +sisr_retry: _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) { + const int urc_code = _at.read_int(); + const int extra = _at.read_int(); // should be -1 if URC + if (urc_code != -1 && extra == -1) { + sisr_urc_handler(socket_id, urc_code); + goto sisr_retry; + } 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); @@ -444,7 +483,9 @@ nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_recvfrom_impl(Cell socket->rx_avail = true; } } - if (GEMALTO_CINTERION_Module::get_model() != GEMALTO_CINTERION_Module::ModelBGS2) { + + // UDP Udp_RemClient + if (socket->proto == NSAPI_UDP && GEMALTO_CINTERION_Module::get_model() != GEMALTO_CINTERION_Module::ModelBGS2) { char ip_address[NSAPI_IPv6_SIZE + sizeof("[]:12345") - 1 + 1]; int ip_len = _at.read_string(ip_address, sizeof(ip_address)); if (ip_len <= 0) { @@ -472,7 +513,7 @@ nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_recvfrom_impl(Cell 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()); + tr_debug("IP address %s, port %d", address->get_ip_address(), address->get_port()); *ip_stop = tmp_ch; // restore original IP string } } @@ -592,3 +633,29 @@ void GEMALTO_CINTERION_CellularStack::close_connection_profile(int connection_pr _at.clear_error(); } + +nsapi_error_t GEMALTO_CINTERION_CellularStack::socket_connect(nsapi_socket_t handle, const SocketAddress &address) +{ + int err = NSAPI_ERROR_DEVICE_ERROR; + + struct CellularSocket *socket = (struct CellularSocket *)handle; + if (!socket) { + return err; + } + + _at.lock(); + err = create_socket_impl(socket); + if (err != NSAPI_ERROR_OK) { + _at.unlock(); + return err; + } + err = socket_open_defer(socket, &address); + _at.unlock(); + + if (err == NSAPI_ERROR_OK) { + socket->remoteAddress = address; + socket->connected = true; + } + + return err; +} diff --git a/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularStack.h b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularStack.h index df4c388ce9..aab3c436e3 100644 --- a/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularStack.h +++ b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION_CellularStack.h @@ -45,6 +45,8 @@ protected: virtual nsapi_size_or_error_t socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address, void *buffer, nsapi_size_t size); + virtual nsapi_error_t socket_connect(nsapi_socket_t handle, const SocketAddress &address); + private: // find the socket handle based on socket identifier CellularSocket *find_socket(int sock_id); @@ -52,7 +54,9 @@ private: // socket URC handlers as per Cinterion AT manuals void urc_sis(); void urc_sisw(); + void sisw_urc_handler(int sock_id, int urc_code); void urc_sisr(); + void sisr_urc_handler(int sock_id, int urc_code); // sockets need a connection profile, one profile is enough to support single stack sockets nsapi_error_t create_connection_profile(int connection_profile_id);