mbed-os/connectivity/drivers/cellular/UBLOX/AT/UBLOX_AT_CellularContext.cpp

371 lines
10 KiB
C++

/*
* 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 "UBLOX_AT_CellularContext.h"
#include "UBLOX_AT_CellularStack.h"
#include "APN_db.h"
#include "CellularLog.h"
#include "rtos/ThisThread.h"
using namespace std::chrono_literals;
namespace mbed {
UBLOX_AT_CellularContext::UBLOX_AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn, bool cp_req, bool nonip_req) :
AT_CellularContext(at, device, apn, cp_req, nonip_req)
{
// The authentication to use
_auth = NOAUTH;
}
UBLOX_AT_CellularContext::~UBLOX_AT_CellularContext()
{
}
NetworkStack *UBLOX_AT_CellularContext::get_stack()
{
if (_pdp_type == NON_IP_PDP_TYPE || _cp_in_use) {
tr_error("Requesting stack for NON-IP context! Should request control plane netif: get_cp_netif()");
return NULL;
}
if (!_stack) {
_stack = new UBLOX_AT_CellularStack(_at, _cid, (nsapi_ip_stack_t)_pdp_type, *get_device());
}
return _stack;
}
void UBLOX_AT_CellularContext::do_connect()
{
_at.lock();
_cb_data.error = NSAPI_ERROR_NO_CONNECTION;
// Attempt to establish a connection
#ifndef UBX_MDM_SARA_R41XM
_cb_data.error = define_context();
#elif UBX_MDM_SARA_R410M
_at.cmd_start_stop("+CGACT", "?");
_at.resp_start("+CGACT:");
_cid = _at.read_int();
_at.skip_param(1);
_at.resp_stop();
_is_connected = true;
_is_context_active = true;
_is_context_activated = true;
_cb_data.error = NSAPI_ERROR_OK;
#elif UBX_MDM_SARA_R412M
CellularNetwork::RadioAccessTechnology rat = read_radio_technology();
if (rat == CellularNetwork::RadioAccessTechnology::RAT_EGPRS) {
if (!_is_context_active) {
_at.set_at_timeout(150s);
_at.at_cmd_discard("+CGACT", "=", "%d%d", 1, 1);
_at.cmd_start_stop("+CGACT", "?");
_at.resp_start("+CGACT:");
_at.skip_param(1);
_is_context_activated = _at.read_int();
_at.resp_stop();
_at.restore_at_timeout();
if (_is_context_activated == true) {
_cid = 1;
_is_connected = true;
_is_context_active = true;
_cb_data.error = NSAPI_ERROR_OK;
}
}
} else if (rat == CellularNetwork::RadioAccessTechnology::RAT_CATM1 || rat == CellularNetwork::RadioAccessTechnology::RAT_NB1) {
_at.cmd_start_stop("+CGACT", "?");
_at.resp_start("+CGACT:");
_cid = _at.read_int();
_at.skip_param(1);
_at.resp_stop();
_is_connected = true;
_is_context_active = true;
_is_context_activated = true;
_cb_data.error = NSAPI_ERROR_OK;
}
#endif
if (_cb_data.error != NSAPI_ERROR_OK) {
// If new PSD context was created and failed to activate, delete it
if (_new_context_set) {
disconnect_modem_stack();
}
_connect_status = NSAPI_STATUS_DISCONNECTED;
} else {
_connect_status = NSAPI_STATUS_GLOBAL_UP;
}
_at.unlock();
if (_status_cb) {
_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connect_status);
}
}
#ifndef UBX_MDM_SARA_R41XM
void UBLOX_AT_CellularContext::do_disconnect()
{
disconnect_modem_stack();
AT_CellularContext::do_disconnect();
}
#endif
#ifndef UBX_MDM_SARA_R41XM
nsapi_error_t UBLOX_AT_CellularContext::define_context()
{
bool success = false;
int active = 0;
char *config = NULL;
nsapi_error_t err = NSAPI_ERROR_NO_CONNECTION;
char imsi[MAX_IMSI_LENGTH + 1];
// do check for stack to validate that we have support for stack
_stack = get_stack();
if (!_stack) {
return err;
}
_at.lock();
_at.cmd_start_stop("+UPSND", "=", "%d%d", PROFILE, 8);
_at.resp_start("+UPSND:");
_at.skip_param(2);
active = _at.read_int();
_at.resp_stop();
_at.unlock();
if (active == 0) {
// If the caller hasn't entered an APN, try to find it
if (_apn == NULL) {
err = get_imsi(imsi);
if (err == NSAPI_ERROR_OK) {
config = (char *)apnconfig(imsi);
}
}
// Attempt to connect
do {
get_next_credentials(&config);
if (_uname && _pwd) {
_auth = (*_uname && *_pwd) ? _authentication_type : NOAUTH;
} else {
_auth = NOAUTH;
}
success = activate_profile(_apn, _uname, _pwd, _auth);
} while (!success && config && *config);
} else {
// If the profile is already active, we're good
success = true;
}
err = (_at.get_last_error() == NSAPI_ERROR_OK) ? NSAPI_ERROR_OK : NSAPI_ERROR_NO_CONNECTION;
return err;
}
bool UBLOX_AT_CellularContext::activate_profile(const char *apn,
const char *username,
const char *password,
AuthenticationType auth)
{
bool activated = false;
bool success = false;
// Set up the APN
if (apn) {
success = false;
if (_at.at_cmd_discard("+UPSD", "=", "%d%d%s", PROFILE, 1, apn) == NSAPI_ERROR_OK) {
success = true;
}
}
// Set up the UserName
if (success && username) {
success = false;
if (_at.at_cmd_discard("+UPSD", "=", "%d%d%s", PROFILE, 2, username) == NSAPI_ERROR_OK) {
success = true;
}
}
// Set up the Password
if (success && password) {
success = false;
if (_at.at_cmd_discard("+UPSD", "=", "%d%d%s", PROFILE, 3, password) == NSAPI_ERROR_OK) {
success = true;
}
}
if (success) {
_at.at_cmd_discard("+UPSD", "=", "%d%d%s", PROFILE, 7, "0.0.0.0");
if (_at.at_cmd_discard("+UPSD", "=", "%d%d%d", PROFILE, 6, nsapi_security_to_modem_security(auth)) == NSAPI_ERROR_OK) {
// Activate, wait upto 30 seconds for the connection to be made
_at.set_at_timeout(30s);
nsapi_error_t err = _at.at_cmd_discard("+UPSDA", "=", "%d%d", PROFILE, 3);
_at.restore_at_timeout();
if (err == NSAPI_ERROR_OK) {
auto end_time = rtos::Kernel::Clock::now() + 3min;
do {
_at.lock();
_at.cmd_start_stop("+UPSND", "=", "%d%d", PROFILE, 8);
_at.resp_start("+UPSND:");
_at.skip_param(2);
_at.read_int() ? activated = true : activated = false;
_at.resp_stop();
_at.unlock();
if (activated) { //If context is activated, exit while loop and return status
break;
}
rtos::ThisThread::sleep_for(5s); //Wait for 5 seconds and then try again
} while (rtos::Kernel::Clock::now() < end_time);
}
}
}
return activated;
}
#endif
// Convert nsapi_security_t to the modem security numbers
int UBLOX_AT_CellularContext::nsapi_security_to_modem_security(AuthenticationType nsapi_security)
{
int modem_security = 3;
switch (nsapi_security) {
case NOAUTH:
modem_security = 0;
break;
case PAP:
modem_security = 1;
break;
case CHAP:
modem_security = 2;
break;
#ifndef UBX_MDM_SARA_R41XM
case AUTOMATIC:
modem_security = 3;
break;
default:
modem_security = 3;
break;
#else
default:
modem_security = 0;
break;
#endif
}
return modem_security;
}
// Disconnect the on board IP stack of the modem.
bool UBLOX_AT_CellularContext::disconnect_modem_stack()
{
SocketAddress addr;
if (get_ip_address(&addr) == NSAPI_ERROR_OK) {
if (_at.at_cmd_discard("+UPSDA", "=", "%d%d", PROFILE, 4) == NSAPI_ERROR_OK) {
return true;
}
}
return false;
}
nsapi_error_t UBLOX_AT_CellularContext::get_imsi(char *imsi)
{
_at.lock();
_at.cmd_start_stop("+CIMI", "");
_at.resp_start();
_at.read_string(imsi, MAX_IMSI_LENGTH + 1);
_at.resp_stop();
return _at.unlock_return_error();
}
// Get the next set of credentials, based on IMSI.
void UBLOX_AT_CellularContext::get_next_credentials(char **config)
{
if (*config) {
_apn = _APN_GET(*config);
_uname = _APN_GET(*config);
_pwd = _APN_GET(*config);
}
}
nsapi_error_t UBLOX_AT_CellularContext::get_gateway(SocketAddress *addr)
{
return get_ip_address(addr);
}
const char *UBLOX_AT_CellularContext::get_apn()
{
return _apn;
}
const char *UBLOX_AT_CellularContext::get_uname()
{
return _uname;
}
const char *UBLOX_AT_CellularContext::get_pwd()
{
return _pwd;
}
CellularContext::AuthenticationType UBLOX_AT_CellularContext::get_auth()
{
return _authentication_type;
}
#ifdef UBX_MDM_SARA_R412M
CellularNetwork::RadioAccessTechnology UBLOX_AT_CellularContext::read_radio_technology()
{
int act;
CellularNetwork::RadioAccessTechnology rat;
_at.at_cmd_int("+URAT", "?", act);
switch (act) {
case 0:
rat = CellularNetwork::RadioAccessTechnology::RAT_GSM;
break;
case 1:
rat = CellularNetwork::RadioAccessTechnology::RAT_GSM;
break;
case 2:
rat = CellularNetwork::RadioAccessTechnology::RAT_UTRAN;
break;
case 7:
rat = CellularNetwork::RadioAccessTechnology::RAT_CATM1;
break;
case 8:
rat = CellularNetwork::RadioAccessTechnology::RAT_NB1;
break;
case 9:
rat = CellularNetwork::RadioAccessTechnology::RAT_EGPRS;
break;
default:
rat = CellularNetwork::RadioAccessTechnology::RAT_UNKNOWN;
break;
}
return rat;
}
#endif // #ifdef UBX_MDM_SARA_R412M
} /* namespace mbed */