Merge pull request #8295 from AriParkkila/cell-cinterion

Cellular: Update Cinterion AT drivers
pull/8222/merge
Cruz Monrreal 2018-10-15 10:10:23 -05:00 committed by GitHub
commit a9f43239be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 109 additions and 60 deletions

View File

@ -581,6 +581,7 @@ bool AT_CellularNetwork::set_new_context(int cid)
// Fall back to ipv4
if (!success && tmp_stack == IPV4V6_STACK) {
tmp_stack = IPV4_STACK;
_at.clear_error();
_at.cmd_start("AT+FCLASS=0;+CGDCONT=");
_at.write_int(cid);
_at.write_string("IP");

View File

@ -24,6 +24,8 @@
using namespace mbed;
using namespace events;
const uint16_t RESPONSE_TO_SEND_DELAY = 100; // response-to-send delay in milliseconds at bit-rate over 9600
GEMALTO_CINTERION::GEMALTO_CINTERION(EventQueue &queue) : AT_CellularDevice(queue)
{
}
@ -52,3 +54,8 @@ nsapi_error_t GEMALTO_CINTERION::init_module(FileHandle *fh)
}
return GEMALTO_CINTERION_Module::detect_model(model);
}
uint16_t GEMALTO_CINTERION::get_send_delay()
{
return RESPONSE_TO_SEND_DELAY;
}

View File

@ -30,8 +30,10 @@ public:
protected: // AT_CellularDevice
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
public:
public: // CellularDevice
virtual nsapi_error_t init_module(FileHandle *fh);
virtual uint16_t get_send_delay();
};
} // namespace mbed

View File

@ -41,14 +41,10 @@ NetworkStack *GEMALTO_CINTERION_CellularNetwork::get_stack()
bool GEMALTO_CINTERION_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
#if NSAPI_PPP_AVAILABLE
return (requested_stack == IPV4_STACK || requested_stack == IPV6_STACK);
#else
if (GEMALTO_CINTERION_Module::get_model() == GEMALTO_CINTERION_Module::ModelBGS2) {
return (requested_stack == IPV4_STACK);
}
return (requested_stack == IPV4_STACK || requested_stack == IPV6_STACK);
#endif
}
AT_CellularNetwork::RegistrationMode GEMALTO_CINTERION_CellularNetwork::has_registration(RegistrationType reg_type)

View File

@ -39,6 +39,9 @@ GEMALTO_CINTERION_CellularStack::GEMALTO_CINTERION_CellularStack(ATHandler &atHa
GEMALTO_CINTERION_CellularStack::~GEMALTO_CINTERION_CellularStack()
{
_at.remove_urc_handler("^SIS:", mbed::Callback<void()>(this, &GEMALTO_CINTERION_CellularStack::urc_sis));
_at.remove_urc_handler("^SISW:", mbed::Callback<void()>(this, &GEMALTO_CINTERION_CellularStack::urc_sisw));
_at.remove_urc_handler("^SISR:", mbed::Callback<void()>(this, &GEMALTO_CINTERION_CellularStack::urc_sisr));
}
GEMALTO_CINTERION_CellularStack::CellularSocket *GEMALTO_CINTERION_CellularStack::find_socket(int sock_id)
@ -62,14 +65,14 @@ void GEMALTO_CINTERION_CellularStack::urc_sis()
int urc_code = _at.read_int();
CellularSocket *sock = find_socket(sock_id);
if (sock) {
if (urc_code == 5) { // data available
// 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;
sock->tx_ready = true;
sock->_cb(sock->_data);
}
} else if (urc_code == 2) { // socket closed
sock->created = false;
}
}
}
@ -88,8 +91,6 @@ void GEMALTO_CINTERION_CellularStack::urc_sisw()
}
sock->_cb(sock->_data);
}
} else if (urc_code == 2) { // socket closed
sock->created = false;
}
}
}
@ -105,8 +106,6 @@ void GEMALTO_CINTERION_CellularStack::urc_sisr()
sock->rx_avail = true;
sock->_cb(sock->_data);
}
} else if (urc_code == 2) { // socket closed
sock->created = false;
}
}
}
@ -114,12 +113,23 @@ void GEMALTO_CINTERION_CellularStack::urc_sisr()
nsapi_error_t GEMALTO_CINTERION_CellularStack::socket_stack_init()
{
_at.lock();
if (create_connection_profile()) {
int connection_profile_id = CONNECTION_PROFILE_ID;
nsapi_error_t err = create_connection_profile(connection_profile_id);
if (!err) {
_at.set_urc_handler("^SIS:", mbed::Callback<void()>(this, &GEMALTO_CINTERION_CellularStack::urc_sis));
_at.set_urc_handler("^SISW:", mbed::Callback<void()>(this, &GEMALTO_CINTERION_CellularStack::urc_sisw));
_at.set_urc_handler("^SISR:", mbed::Callback<void()>(this, &GEMALTO_CINTERION_CellularStack::urc_sisr));
} else { // recovery cleanup
// close all Internet and connection profiles
for (int i = 0; i < SOCKET_MAX; i++) {
_at.clear_error();
socket_close_impl(i);
}
_at.clear_error();
close_connection_profile(connection_profile_id);
}
return _at.unlock_return_error();
_at.unlock();
return err;
}
int GEMALTO_CINTERION_CellularStack::get_max_socket_count()
@ -134,22 +144,24 @@ 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);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.restore_at_timeout();
socket->started = false;
socket->created = false;
socket->tx_ready = false;
socket->rx_avail = false;
_at.clear_error(); // clear SISS even though SISC fails
_at.cmd_start("AT^SISS=");
_at.write_int(sock_id);
_at.write_string("srvType");
_at.write_string("none");
_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();
@ -267,7 +279,7 @@ nsapi_error_t GEMALTO_CINTERION_CellularStack::create_socket_impl(CellularSocket
_at.resp_stop();
}
tr_debug("Internet service %d created (err %d)", internet_service_id, _at.get_last_error());
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);
@ -287,13 +299,17 @@ nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_sendto_impl(Cellul
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());
tr_debug("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();
}
if (create_socket_impl(socket) != NSAPI_ERROR_OK) {
tr_error("Failed to create socket %d", socket->id);
return NSAPI_ERROR_NO_SOCKET;
}
if (socket_open_defer(socket, &address) != NSAPI_ERROR_OK) {
tr_error("Failed to open socket %d", socket->id);
return NSAPI_ERROR_NO_SOCKET;
@ -381,11 +397,8 @@ nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_recvfrom_impl(Cell
{
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;
}
// we must use this flag, otherwise ^SISR URC can come while we are reading response and there is
// no way to detect if that is really an URC or response
if (!socket->rx_avail) {
_at.process_oob(); // check for ^SISR URC
if (!socket->rx_avail) {
@ -394,6 +407,11 @@ nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_recvfrom_impl(Cell
}
}
if (size > UDP_PACKET_SIZE) {
tr_debug("Socket recvfrom size %d > %d", size, UDP_PACKET_SIZE);
size = UDP_PACKET_SIZE;
}
_at.cmd_start("AT^SISR=");
_at.write_int(socket->id);
_at.write_int(size);
@ -468,30 +486,27 @@ 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, address, len, _at.get_last_error());
tr_debug("Socket %d, recvfrom %s, %d bytes (err %d)", socket->id, socket->remoteAddress.get_ip_address(), len, _at.get_last_error());
return (_at.get_last_error() == NSAPI_ERROR_OK) ? recv_len : NSAPI_ERROR_DEVICE_ERROR;
return (_at.get_last_error() == NSAPI_ERROR_OK) ? ( recv_len ? recv_len : NSAPI_ERROR_WOULD_BLOCK ) : NSAPI_ERROR_DEVICE_ERROR;
}
// setup internet connection profile for sockets
bool GEMALTO_CINTERION_CellularStack::create_connection_profile()
nsapi_error_t GEMALTO_CINTERION_CellularStack::create_connection_profile(int connection_profile_id)
{
if (GEMALTO_CINTERION_Module::get_model() == GEMALTO_CINTERION_Module::ModelEMS31) {
// EMS31 connection has only DNS settings and there is no need to modify those here for now
return true;
return NSAPI_ERROR_OK;
}
char conParamType[12];
char conParamType[sizeof("GPRS0") + 1];
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;
bool found_connection = false;
_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));
@ -500,17 +515,10 @@ bool GEMALTO_CINTERION_CellularStack::create_connection_profile()
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;
found_connection = true;
break;
}
}
}
@ -519,8 +527,8 @@ bool GEMALTO_CINTERION_CellularStack::create_connection_profile()
}
_at.resp_stop();
if (!foundConnection) {
tr_debug("Socket conType %s", conParamType);
// connection profile is bound to a PDP context and it can not be changed
if (!found_connection) {
_at.cmd_start("AT^SICS=");
_at.write_int(connection_profile_id);
_at.write_string("conType");
@ -528,25 +536,59 @@ bool GEMALTO_CINTERION_CellularStack::create_connection_profile()
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
}
if (!foundAPN && _apn) {
tr_debug("Socket APN %s", _apn ? _apn : "");
if (_apn && strlen(_apn) > 0) {
_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();
}
// set maximum inactivity timeout
_at.cmd_start("AT^SICS=");
_at.write_int(connection_profile_id);
_at.write_string("apn");
_at.write_string(_apn);
_at.write_string("inactTO");
_at.write_int(0xffff); // 2^16-1
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
// use URC mode ON
_at.cmd_start("AT^SCFG=\"Tcp/withURCs\",\"on\"");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
}
// use URC mode
_at.cmd_start("AT^SCFG=\"Tcp/withURCs\",\"on\"");
tr_debug("Connection profile %d, stack_type %d (err %d)", connection_profile_id, _stack_type, _at.get_last_error());
return _at.get_last_error();
}
void GEMALTO_CINTERION_CellularStack::close_connection_profile(int connection_profile_id)
{
if (GEMALTO_CINTERION_Module::get_model() == GEMALTO_CINTERION_Module::ModelEMS31) {
return;
}
// To clear connection profile need to detach from packet data.
// After detach modem sends PDP disconnected event to network class,
// which propagates network disconnected to upper layer to start reconnecting.
_at.cmd_start("AT+CGATT=0");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.clear_error();
_at.cmd_start("AT^SICS=");
_at.write_int(connection_profile_id);
_at.write_string("conType");
_at.write_string("none");
_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;
_at.clear_error();
}

View File

@ -55,7 +55,8 @@ private:
void urc_sisr();
// sockets need a connection profile, one profile is enough to support single stack sockets
bool create_connection_profile();
nsapi_error_t create_connection_profile(int connection_profile_id);
void close_connection_profile(int connection_profile_id);
// socket open need to be deferred until sendto due to BGS2 does not support UDP server endpoint
nsapi_error_t socket_open_defer(CellularSocket *socket, const SocketAddress *address = NULL);