Cellular: Added support for the Gemalto/BGS2 cellular module

pull/7677/head
Ari Parkkila 2018-08-17 00:27:59 -07:00
parent 761e01f55c
commit a14ac31f68
7 changed files with 158 additions and 73 deletions

View File

@ -276,10 +276,10 @@ nsapi_size_or_error_t AT_CellularStack::socket_sendto(nsapi_socket_t handle, con
ret_val = socket_sendto_impl(socket, addr, data, size);
if (ret_val <= 0) {
tr_error("Error sending to: %s error code: %d", addr.get_ip_address(), ret_val);
} else {
if (ret_val > 0) {
tr_info("Success sending %d Bytes to: %s", ret_val, addr.get_ip_address());
} else if (ret_val != NSAPI_ERROR_WOULD_BLOCK) {
tr_error("Error sending to: %s error code: %d", addr.get_ip_address(), ret_val);
}
_at.unlock();

View File

@ -17,6 +17,7 @@
#include "GEMALTO_CINTERION_CellularNetwork.h"
#include "GEMALTO_CINTERION_CellularStack.h"
#include "GEMALTO_CINTERION_Module.h"
using namespace mbed;
@ -28,6 +29,7 @@ GEMALTO_CINTERION_CellularNetwork::~GEMALTO_CINTERION_CellularNetwork()
{
}
#if !NSAPI_PPP_AVAILABLE
NetworkStack *GEMALTO_CINTERION_CellularNetwork::get_stack()
{
if (!_stack) {
@ -35,14 +37,21 @@ NetworkStack *GEMALTO_CINTERION_CellularNetwork::get_stack()
}
return _stack;
}
#endif // NSAPI_PPP_AVAILABLE
bool GEMALTO_CINTERION_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
if (GEMALTO_CINTERION_Module::get_model() == GEMALTO_CINTERION_Module::ModelBGS2) {
return (requested_stack == IPV4_STACK);
}
return (requested_stack == IPV4_STACK || requested_stack == IPV6_STACK);
}
bool GEMALTO_CINTERION_CellularNetwork::has_registration(RegistrationType reg_type)
{
if (GEMALTO_CINTERION_Module::get_model() == GEMALTO_CINTERION_Module::ModelBGS2) {
return (reg_type == C_REG || reg_type == C_GREG);
}
return (reg_type == C_REG || reg_type == C_GREG || reg_type == C_EREG);
}

View File

@ -28,7 +28,9 @@ public:
virtual ~GEMALTO_CINTERION_CellularNetwork();
protected:
#if !NSAPI_PPP_AVAILABLE
virtual NetworkStack *get_stack();
#endif // NSAPI_PPP_AVAILABLE
virtual bool has_registration(RegistrationType reg_type);

View File

@ -17,9 +17,10 @@
#include <stdlib.h>
#include "GEMALTO_CINTERION_CellularStack.h"
#include "GEMALTO_CINTERION_Module.h"
#include "CellularLog.h"
// defines as per ELS61-E2_ATC_V01.000
// defines as per ELS61-E2_ATC_V01.000 and BGS2-W_ATC_V00.100
#define SOCKET_MAX 10
#define UDP_PACKET_SIZE 1460
#define FAILURE_TIMEOUT (30*1000) // failure timeout in milliseconds on modem side
@ -84,6 +85,9 @@ void GEMALTO_CINTERION_CellularStack::urc_sisw()
if (urc_code == 1) { // ready
if (sock->_cb) {
sock->tx_ready = true;
if (GEMALTO_CINTERION_Module::get_model() == GEMALTO_CINTERION_Module::ModelBGS2) {
sock->started = true;
}
sock->_cb(sock->_data);
}
} else if (urc_code == 2) { // socket closed
@ -133,6 +137,10 @@ bool GEMALTO_CINTERION_CellularStack::is_protocol_supported(nsapi_protocol_t pro
nsapi_error_t GEMALTO_CINTERION_CellularStack::socket_close_impl(int sock_id)
{
CellularSocket *socket = find_socket(sock_id);
if (!socket) {
return NSAPI_ERROR_NO_SOCKET;
}
_at.set_at_timeout(FAILURE_TIMEOUT);
_at.cmd_start("AT^SISC=");
_at.write_int(sock_id);
@ -140,10 +148,53 @@ nsapi_error_t GEMALTO_CINTERION_CellularStack::socket_close_impl(int sock_id)
_at.resp_start();
_at.resp_stop();
_at.restore_at_timeout();
socket->started = false;
socket->created = false;
socket->tx_ready = false;
socket->rx_avail = false;
tr_debug("Closed socket %d (err %d)", sock_id, _at.get_last_error());
return _at.get_last_error();
}
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());
} else {
std::sprintf(sock_addr, "sockudp://%s:%u;port=%u", address->get_ip_address(), address->get_port(), 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); // socket may already be open on modem if app and modem are not in sync, as a recovery, try to close the socket so open succeeds the next time
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();
}
// 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)
@ -224,32 +275,9 @@ nsapi_error_t GEMALTO_CINTERION_CellularStack::create_socket_impl(CellularSocket
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;
if (GEMALTO_CINTERION_Module::get_model() != GEMALTO_CINTERION_Module::ModelBGS2) {
return socket_open_defer(socket);
}
socket->created = true;
tr_debug("Socket %d created (err %d)", socket->id, _at.get_last_error());
return _at.get_last_error();
}
@ -264,9 +292,33 @@ nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_sendto_impl(Cellul
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) {
tr_error("Send addr %s, prev addr %s", address.get_ip_address(), socket->remoteAddress.get_ip_address());
if (address != socket->remoteAddress) {
if (socket->started) {
socket_close_impl(socket->id);
_at.clear_error();
}
// socket->started = false;
if (socket_open_defer(socket, &address) != NSAPI_ERROR_OK) {
tr_error("Failed to open socket %d", socket->id);
return NSAPI_ERROR_NO_SOCKET;
}
socket->remoteAddress = address;
// return NSAPI_ERROR_WOULD_BLOCK;
_at.resp_start("^SISW:");
int sock_id = _at.read_int();
int urc_code = _at.read_int();
tr_debug("TX ready: socket=%d, urc=%d (err=%d)", sock_id, urc_code, _at.get_last_error());
(void)sock_id;
(void)urc_code;
socket->created = true;
socket->started = true;
socket->tx_ready = true;
}
}
if (!socket->started || !socket->tx_ready) {
tr_debug("Socket %d would block", socket->id);
tr_debug("Socket %d would block (started %d, tx %d)", socket->id, socket->started, socket->tx_ready);
return NSAPI_ERROR_WOULD_BLOCK;
}
@ -279,18 +331,19 @@ 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);
_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());
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());
}
_at.write_string(socket_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();
sisw_retry:
_at.resp_start("^SISW:");
if (!_at.info_resp()) {
tr_error("Socket %d send failure", socket->id);
@ -311,6 +364,11 @@ nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_sendto_impl(Cellul
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.write_bytes((uint8_t *)data, accept_len);
@ -375,36 +433,41 @@ nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_recvfrom_impl(Cell
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 (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) {
tr_error("Socket %d recvfrom addr!", socket->id);
return NSAPI_ERROR_DEVICE_ERROR;
}
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
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
}
}
} else {
if (address) {
*address = socket->remoteAddress;
}
}
@ -412,7 +475,7 @@ nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_recvfrom_impl(Cell
_at.resp_stop();
tr_debug("Socket %d, recvfrom %s, %d bytes (err %d)", socket->id, ip_address, len, _at.get_last_error());
tr_debug("Socket %d, recvfrom %s, %d bytes (err %d)", socket->id, address, len, _at.get_last_error());
return (_at.get_last_error() == NSAPI_ERROR_OK) ? recv_len : NSAPI_ERROR_DEVICE_ERROR;
}

View File

@ -51,6 +51,7 @@ private:
void urc_sisw();
void urc_sisr();
bool create_connection_profile();
nsapi_error_t socket_open_defer(CellularSocket *socket, const SocketAddress *address = NULL);
const char *_apn;
};

View File

@ -23,20 +23,29 @@
using namespace mbed;
// supported features as per ELS61-E2_ATC_V01.000
// unsupported 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
};
// unsupported features as per EMS31-US_ATC_V4.9.5
static const AT_CellularBase::SupportedFeature unsupported_features_bgs2[] = {
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) {
if (memcmp(model, "ELS61", sizeof("ELS61") - 1) == 0) {
_model = ModelELS61;
unsupported_features = unsupported_features_els61;
} else if (memcmp(model, "BGS2", sizeof("BGS2") - 1) == 0) {
_model = ModelBGS2;
unsupported_features = unsupported_features_bgs2;
} else {
tr_error("Cinterion model unsupported %s", model);
return NSAPI_ERROR_UNSUPPORTED;

View File

@ -31,7 +31,8 @@ public:
*/
enum Model {
ModelUnknown = 0,
ModelELS61
ModelELS61,
ModelBGS2,
};
static nsapi_error_t detect_model(const char *model);
static Model get_model();