Skip to content

Cellular: Gemalto TCP Socket support #8440

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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=");
Expand Down Expand Up @@ -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();
}

Expand All @@ -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) {
Expand Down Expand Up @@ -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:
Expand All @@ -359,29 +388,30 @@ nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_sendto_impl(Cellul
_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());

Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand Down Expand Up @@ -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
}
}
Expand Down Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,18 @@ class GEMALTO_CINTERION_CellularStack : public AT_CellularStack {
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);

// 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);
Expand Down