Merge pull request #8579 from jarvte/cellular_context

Major refactoring: changing Network inheritance from CellularNetwork to new class CellularContext
pull/8743/head
Anna Bridge 2018-11-14 14:37:19 +00:00 committed by GitHub
commit 4d07bcbd6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
97 changed files with 4190 additions and 3669 deletions

View File

@ -117,6 +117,7 @@ set(unittest-includes-base
"${PROJECT_SOURCE_DIR}/../features/filesystem/littlefs/littlefs"
"${PROJECT_SOURCE_DIR}/../features/cellular/framework/API"
"${PROJECT_SOURCE_DIR}/../features/cellular/framework/AT"
"${PROJECT_SOURCE_DIR}/../features/cellular/framework/device"
"${PROJECT_SOURCE_DIR}/../features/cellular/framework"
"${PROJECT_SOURCE_DIR}/../features/cellular/framework/common"
"${PROJECT_SOURCE_DIR}/../features/lorawan"

View File

@ -0,0 +1,114 @@
/*
* 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 "gtest/gtest.h"
#include <string.h>
#include "AT_CellularContext.h"
#include "EventQueue.h"
#include "ATHandler.h"
#include "AT_CellularDevice.h"
#include "FileHandle_stub.h"
#include "CellularLog.h"
#include "ATHandler_stub.h"
#include "AT_CellularStack.h"
using namespace mbed;
using namespace events;
// AStyle ignored as the definition is not clear due to preprocessor usage
// *INDENT-OFF*
class TestAT_CellularContext : public testing::Test {
protected:
void SetUp()
{
ATHandler_stub::int_count = kRead_int_table_size;
ATHandler_stub::read_string_index = kRead_string_table_size;
ATHandler_stub::resp_stop_success_count = kResp_stop_count_default;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::int_value = -1;
}
void TearDown()
{
}
};
// *INDENT-ON*
class my_stack : public AT_CellularStack {
public:
my_stack(ATHandler &atHandler) : AT_CellularStack(atHandler, 1, IPV4_STACK) {}
virtual int get_max_socket_count()
{
return 1;
}
virtual int get_max_packet_size()
{
return 200;
}
virtual bool is_protocol_supported(nsapi_protocol_t protocol)
{
return true;
}
virtual nsapi_error_t socket_close_impl(int sock_id)
{
return NSAPI_ERROR_OK;
}
virtual nsapi_error_t create_socket_impl(CellularSocket *socket)
{
return NSAPI_ERROR_OK;
}
virtual nsapi_size_or_error_t socket_sendto_impl(CellularSocket *socket, const SocketAddress &address,
const void *data, nsapi_size_t size)
{
return 100;
}
virtual nsapi_size_or_error_t socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address,
void *buffer, nsapi_size_t size)
{
return 100;
}
};
class my_AT_CTX : public AT_CellularContext {
public:
my_AT_CTX(ATHandler &at, CellularDevice *device, const char *apn = MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN) :
AT_CellularContext(at, device, apn) {}
virtual ~my_AT_CTX() {}
};
class my_AT_CTXIPV6 : public AT_CellularContext {
public:
my_AT_CTXIPV6(ATHandler &at, CellularDevice *device, const char *apn = MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN) :
AT_CellularContext(at, device, apn) {}
virtual ~my_AT_CTXIPV6() {}
};
static int network_cb_count;
static void network_cb(nsapi_event_t ev, intptr_t intptr)
{
network_cb_count++;
}
TEST_F(TestAT_CellularContext, Create)
{
EventQueue que;
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
AT_CellularContext *ctx = new AT_CellularContext(at, NULL);
EXPECT_TRUE(ctx != NULL);
delete ctx;
}

View File

@ -0,0 +1,35 @@
####################
# UNIT TESTS
####################
# Add test specific include paths
set(unittest-includes ${unittest-includes}
features/cellular/framework/common/util
../features/cellular/framework/common
../features/cellular/framework/AT
../features/cellular/framework/device
)
# Source files
set(unittest-sources
../features/cellular/framework/AT/AT_CellularContext.cpp
)
# Test files
set(unittest-test-sources
features/cellular/framework/AT/at_cellularcontext/at_cellularcontexttest.cpp
stubs/ATHandler_stub.cpp
stubs/AT_CellularBase_stub.cpp
stubs/EventQueue_stub.cpp
stubs/FileHandle_stub.cpp
stubs/NetworkInterface_stub.cpp
stubs/NetworkStack_stub.cpp
stubs/us_ticker_stub.cpp
stubs/mbed_assert_stub.c
stubs/CellularDevice_stub.cpp
stubs/CellularStateMachine_stub.cpp
stubs/Semaphore_stub.cpp
stubs/CellularUtil_stub.cpp
stubs/equeue_stub.c
)

View File

@ -37,10 +37,10 @@ protected:
TEST_F(TestAT_CellularDevice, Create)
{
EventQueue que;
AT_CellularDevice dev(que);
FileHandle_stub fh1;
AT_CellularDevice dev(&fh1);
CellularDevice *dev2 = new AT_CellularDevice(que);
CellularDevice *dev2 = new AT_CellularDevice(&fh1);
EXPECT_TRUE(dev2 != NULL);
delete dev2;
@ -48,11 +48,10 @@ TEST_F(TestAT_CellularDevice, Create)
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_get_at_handler)
{
EventQueue que;
AT_CellularDevice dev(que);
FileHandle_stub fh1;
FileHandle_stub fh2;
FileHandle_stub fh3;
AT_CellularDevice dev(&fh1);
EXPECT_TRUE(dev.open_network(&fh1));
EXPECT_TRUE(dev.open_sms(&fh2));
@ -66,59 +65,73 @@ TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_get_at_handler)
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_open_network)
{
EventQueue que;
AT_CellularDevice dev(que);
FileHandle_stub fh1;
AT_CellularDevice dev(&fh1);
EXPECT_TRUE(!dev.open_network(NULL));
EXPECT_TRUE(dev.open_network(&fh1));
CellularNetwork *nw = dev.open_network(NULL);
CellularNetwork *nw1 = dev.open_network(&fh1);
EXPECT_TRUE(nw);
EXPECT_TRUE(nw1);
EXPECT_TRUE(nw1 == nw);
}
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_open_sms)
{
EventQueue que;
AT_CellularDevice dev(que);
FileHandle_stub fh1;
AT_CellularDevice dev(&fh1);
EXPECT_TRUE(!dev.open_sms(NULL));
EXPECT_TRUE(dev.open_sms(&fh1));
CellularSMS *sms = dev.open_sms(NULL);
CellularSMS *sms1 = dev.open_sms(&fh1);
EXPECT_TRUE(sms);
EXPECT_TRUE(sms1);
EXPECT_TRUE(sms1 == sms);
}
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_open_power)
{
EventQueue que;
AT_CellularDevice dev(que);
FileHandle_stub fh1;
AT_CellularDevice dev(&fh1);
EXPECT_TRUE(!dev.open_power(NULL));
EXPECT_TRUE(dev.open_power(&fh1));
CellularPower *pwr = dev.open_power(NULL);
CellularPower *pwr1 = dev.open_power(&fh1);
EXPECT_TRUE(pwr);
EXPECT_TRUE(pwr1);
EXPECT_TRUE(pwr1 == pwr);
}
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_open_sim)
{
EventQueue que;
AT_CellularDevice dev(que);
FileHandle_stub fh1;
AT_CellularDevice dev(&fh1);
EXPECT_TRUE(! dev.open_sim(NULL));
EXPECT_TRUE(dev.open_sim(&fh1));
CellularSIM *sim = dev.open_sim(NULL);
CellularSIM *sim1 = dev.open_sim(&fh1);
EXPECT_TRUE(sim);
EXPECT_TRUE(sim1);
EXPECT_TRUE(sim1 == sim);
}
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_open_information)
{
EventQueue que;
AT_CellularDevice dev(que);
FileHandle_stub fh1;
AT_CellularDevice dev(&fh1);
EXPECT_TRUE(!dev.open_information(NULL));
EXPECT_TRUE(dev.open_information(&fh1));
CellularInformation *info = dev.open_information(NULL);
CellularInformation *info1 = dev.open_information(&fh1);
EXPECT_TRUE(info);
EXPECT_TRUE(info1);
EXPECT_TRUE(info1 == info);
}
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_close_network)
{
EventQueue que;
AT_CellularDevice dev(que);
FileHandle_stub fh1;
AT_CellularDevice dev(&fh1);
ATHandler_stub::ref_count = 0;
EXPECT_TRUE(dev.open_network(&fh1));
@ -131,9 +144,8 @@ TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_close_network)
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_close_sms)
{
EventQueue que;
AT_CellularDevice dev(que);
FileHandle_stub fh1;
AT_CellularDevice dev(&fh1);
ATHandler_stub::ref_count = 0;
EXPECT_TRUE(dev.open_sms(&fh1));
@ -146,9 +158,8 @@ TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_close_sms)
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_close_power)
{
EventQueue que;
AT_CellularDevice dev(que);
FileHandle_stub fh1;
AT_CellularDevice dev(&fh1);
ATHandler_stub::ref_count = 0;
EXPECT_TRUE(dev.open_power(&fh1));
@ -161,9 +172,8 @@ TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_close_power)
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_close_sim)
{
EventQueue que;
AT_CellularDevice dev(que);
FileHandle_stub fh1;
AT_CellularDevice dev(&fh1);
ATHandler_stub::ref_count = 0;
int ana = 0;
@ -182,9 +192,8 @@ TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_close_sim)
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_close_information)
{
EventQueue que;
AT_CellularDevice dev(que);
FileHandle_stub fh1;
AT_CellularDevice dev(&fh1);
ATHandler_stub::int_value = 0;
EXPECT_TRUE(dev.open_information(&fh1));
@ -193,6 +202,7 @@ TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_close_information)
AT_CellularBase_stub::handler_value = NULL;
dev.close_information();
EventQueue que;
ATHandler_stub::fh_value = &fh1;
ATHandler at(&fh1, que, 0, ",");
AT_CellularBase_stub::handler_value = &at;
@ -208,9 +218,8 @@ TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_close_information)
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_set_timeout)
{
EventQueue que;
AT_CellularDevice dev(que);
FileHandle_stub fh1;
AT_CellularDevice dev(&fh1);
ATHandler_stub::timeout = 0;
ATHandler_stub::default_timeout = false;
@ -231,9 +240,8 @@ TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_set_timeout)
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_modem_debug_on)
{
EventQueue que;
AT_CellularDevice dev(que);
FileHandle_stub fh1;
AT_CellularDevice dev(&fh1);
ATHandler_stub::debug_on = false;
// no interfaces open so debug toggling should not affect
@ -249,31 +257,16 @@ TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_modem_debug_on)
dev.close_sim();
}
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_get_stack)
{
EventQueue que;
AT_CellularDevice dev(que);
FileHandle_stub fh1;
NetworkStack *stack = dev.get_stack();
EXPECT_TRUE(stack == NULL);
EXPECT_TRUE(dev.open_network(&fh1));
stack = dev.get_stack();
EXPECT_TRUE(stack == NULL); // Not in PPP so also null but this is got from the network class
}
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_get_send_delay)
{
EventQueue que;
AT_CellularDevice dev(que);
FileHandle_stub fh1;
AT_CellularDevice dev(&fh1);
EXPECT_TRUE(0 == dev.get_send_delay());
}
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_init_module)
{
EventQueue que;
AT_CellularDevice dev(que);
EXPECT_TRUE(NSAPI_ERROR_OK == dev.init_module(NULL));
FileHandle_stub fh1;
AT_CellularDevice dev(&fh1);
EXPECT_TRUE(NSAPI_ERROR_OK == dev.init_module());
}

View File

@ -8,7 +8,10 @@ set(unittest-includes ${unittest-includes}
features/cellular/framework/common/util
../features/cellular/framework/common
../features/cellular/framework/AT
../features/cellular/framework/device
../features/frameworks/mbed-client-randlib/mbed-client-randlib
../drivers
../hal
)
# Source files
@ -33,4 +36,17 @@ set(unittest-test-sources
stubs/FileHandle_stub.cpp
stubs/mbed_assert_stub.c
stubs/CellularDevice_stub.cpp
stubs/NetworkStack_stub.cpp
stubs/AT_CellularContext_stub.cpp
stubs/Semaphore_stub.cpp
stubs/UARTSerial_stub.cpp
stubs/SerialBase_stub.cpp
stubs/CellularStateMachine_stub.cpp
)
# defines
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEVICE_SERIAL=1 -DDEVICE_INTERRUPTIN=1 -DMBED_CONF_NSAPI_DEFAULT_CELLULAR_APN=NULL -DMBED_CONF_NSAPI_DEFAULT_CELLULAR_USERNAME=NULL -DMBED_CONF_NSAPI_DEFAULT_CELLULAR_PASSWORD=NULL -DMBED_CONF_NSAPI_DEFAULT_CELLULAR_PLMN=NULL -DMBED_CONF_NSAPI_DEFAULT_CELLULAR_SIM_PIN=NULL")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMDMTXD=NC -DMDMRXD=NC -DMBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE=115200")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEVICE_SERIAL=1 -DDEVICE_INTERRUPTIN=1 -DMBED_CONF_NSAPI_DEFAULT_CELLULAR_APN=NULL -DMBED_CONF_NSAPI_DEFAULT_CELLULAR_USERNAME=NULL -DMBED_CONF_NSAPI_DEFAULT_CELLULAR_PASSWORD=NULL -DMBED_CONF_NSAPI_DEFAULT_CELLULAR_PLMN=NULL -DMBED_CONF_NSAPI_DEFAULT_CELLULAR_SIM_PIN=NULL")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMDMTXD=NC -DMDMRXD=NC -DMBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE=115200")

View File

@ -46,54 +46,12 @@ protected:
{
}
};
// *INDENT-ON*
class my_stack : public AT_CellularStack {
public:
my_stack(ATHandler &atHandler) : AT_CellularStack(atHandler, 1, IPV4_STACK) {}
virtual int get_max_socket_count()
{
return 1;
}
virtual int get_max_packet_size()
{
return 200;
}
virtual bool is_protocol_supported(nsapi_protocol_t protocol)
{
return true;
}
virtual nsapi_error_t socket_close_impl(int sock_id)
{
return NSAPI_ERROR_OK;
}
virtual nsapi_error_t create_socket_impl(CellularSocket *socket)
{
return NSAPI_ERROR_OK;
}
virtual nsapi_size_or_error_t socket_sendto_impl(CellularSocket *socket, const SocketAddress &address,
const void *data, nsapi_size_t size)
{
return 100;
}
virtual nsapi_size_or_error_t socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address,
void *buffer, nsapi_size_t size)
{
return 100;
}
};
class my_AT_CN : public AT_CellularNetwork {
public:
my_AT_CN(ATHandler &atHandler) : AT_CellularNetwork(atHandler) {}
virtual ~my_AT_CN() {}
NetworkStack *get_stack()
{
if (!_stack) {
return new my_stack(get_at_handler());
} else {
return _stack;
}
}
virtual AT_CellularNetwork::RegistrationMode has_registration(RegistrationType reg_type)
{
if (reg_type == C_GREG) {
@ -105,27 +63,12 @@ public:
{
return NSAPI_ERROR_OK;
}
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
if (requested_stack == IPV4_STACK || requested_stack == DEFAULT_STACK) {
return true;
}
return false;
}
};
class my_AT_CNipv6 : public AT_CellularNetwork {
public:
my_AT_CNipv6(ATHandler &atHandler) : AT_CellularNetwork(atHandler) {}
virtual ~my_AT_CNipv6() {}
NetworkStack *get_stack()
{
if (!_stack) {
return new my_stack(get_at_handler());
} else {
return _stack;
}
}
virtual AT_CellularNetwork::RegistrationMode has_registration(RegistrationType reg_type)
{
if (reg_type == C_GREG) {
@ -137,13 +80,6 @@ public:
{
return NSAPI_ERROR_OK;
}
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
if (requested_stack == IPV6_STACK || requested_stack == DEFAULT_STACK) {
return true;
}
return false;
}
};
static int network_cb_count;
@ -163,256 +99,6 @@ TEST_F(TestAT_CellularNetwork, Create)
delete cn;
}
TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_init)
{
EventQueue que;
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
AT_CellularNetwork cn(at);
EXPECT_TRUE(NSAPI_ERROR_OK == cn.init());
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_NO_MEMORY;
EXPECT_TRUE(NSAPI_ERROR_NO_MEMORY == cn.init());
}
TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_set_credentials)
{
EventQueue que;
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
AT_CellularNetwork *cnn = new AT_CellularNetwork(at);
delete cnn;
AT_CellularNetwork cn(at);
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_credentials("apn"));
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_credentials("apn", CellularNetwork::CHAP));
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_credentials("apn", CellularNetwork::CHAP, NULL));
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_credentials("apn", CellularNetwork::CHAP, NULL, NULL));
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_credentials("apn", CellularNetwork::CHAP, NULL, "passwd"));
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_credentials("apn", CellularNetwork::CHAP, "user", NULL));
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_credentials("apn", CellularNetwork::CHAP, "user"));
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_credentials("apn", CellularNetwork::CHAP, "user", "passwd"));
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_credentials("apn", NULL));
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_credentials("apn", NULL, NULL));
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_credentials("apn", NULL, "passwd"));
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_credentials("apn", "user", NULL));
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_credentials("apn", "user"));
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_credentials("apn", "user", "passwd"));
}
TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_activate_context)
{
EventQueue que;
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
AT_CellularNetwork cn(at);
my_AT_CN my_cn(at);
my_AT_CNipv6 my_cnipv6(at);
// get_context return true and new context created. But now stack and so error.
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
EXPECT_TRUE(NSAPI_ERROR_UNSUPPORTED == cn.activate_context());
// get_context return true and new context created, also do_user_authentication called with success.
// But now stack and so error.
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_credentials("apn", CellularNetwork::CHAP, "user", "passwd"));
EXPECT_TRUE(NSAPI_ERROR_UNSUPPORTED == cn.activate_context());
// get_context return true and new context created, also do_user_authentication called with failure.
ATHandler_stub::resp_stop_success_count = 2;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.set_credentials("apn", CellularNetwork::CHAP, "user", "passwd"));
EXPECT_TRUE(NSAPI_ERROR_AUTH_FAILURE == my_cn.activate_context());
// get_context return true and new context created, also do_user_authentication called with success.
// Now there is stack.
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
ATHandler_stub::resp_stop_success_count = kResp_stop_count_default;
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.set_credentials("apn", CellularNetwork::CHAP, "user", "passwd"));
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.activate_context());
// get_context return true and new context created, test delete context
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
ATHandler_stub::resp_stop_success_count = kResp_stop_count_default;
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.set_credentials("apn", CellularNetwork::CHAP, "user", "passwd"));
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.activate_context());
// get_context pdp type gives zero len, fails with no stack
ATHandler_stub::resp_info_true_counter = 1;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
ATHandler_stub::read_string_index = 1;
ATHandler_stub::read_string_table[0] = (char *)"";
ATHandler_stub::int_value = 1;
EXPECT_TRUE(NSAPI_ERROR_UNSUPPORTED == cn.activate_context());
// get_context pdp type gives proper type, apn reading fails
ATHandler_stub::resp_info_true_counter = 1;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
ATHandler_stub::read_string_index = 1;
ATHandler_stub::read_string_table[0] = (char *)"IPV6";
ATHandler_stub::int_value = 1;
EXPECT_TRUE(NSAPI_ERROR_NO_CONNECTION == cn.activate_context());
// get_context pdp type gives proper type, apn does not match, now other contexts so new one created
ATHandler_stub::resp_info_true_counter = 1;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
ATHandler_stub::read_string_index = 2;
ATHandler_stub::read_string_table[0] = (char *)"internet";
ATHandler_stub::read_string_table[1] = (char *)"IP";
ATHandler_stub::int_value = 1;
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.set_credentials("apn", CellularNetwork::CHAP, "user", "passwd"));
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.activate_context());
// get_context pdp type gives proper type, apn match
ATHandler_stub::resp_info_true_counter = 2; // set to 2 so cgact will give that this context is active
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
ATHandler_stub::read_string_index = 2;
ATHandler_stub::read_string_table[0] = (char *)"internet";
ATHandler_stub::read_string_table[1] = (char *)"IPV4V6";
ATHandler_stub::int_value = 1;
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.set_stack_type(IPV4_STACK));
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.set_credentials("internet"));
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.activate_context());
// get_context pdp type gives proper type, apn match
ATHandler_stub::resp_info_true_counter = 1;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
ATHandler_stub::read_string_index = 2;
ATHandler_stub::read_string_table[0] = (char *)"internet";
ATHandler_stub::read_string_table[1] = (char *)"IPV6";
ATHandler_stub::int_value = 1;
EXPECT_TRUE(NSAPI_ERROR_OK == my_cnipv6.set_stack_type(IPV6_STACK));
EXPECT_TRUE(NSAPI_ERROR_OK == my_cnipv6.set_credentials("internet"));
EXPECT_TRUE(NSAPI_ERROR_OK == my_cnipv6.activate_context());
// get_context pdp type gives proper type, apn match
ATHandler_stub::resp_info_true_counter = 1;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
ATHandler_stub::read_string_index = 2;
ATHandler_stub::read_string_table[0] = (char *)"internet";
ATHandler_stub::read_string_table[1] = (char *)"IPV4V6";
ATHandler_stub::int_value = 1;
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.set_stack_type(DEFAULT_STACK));
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.set_credentials("internet"));
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.activate_context());
// get_context pdp type gives proper type, apn match
ATHandler_stub::resp_info_true_counter = 1;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
ATHandler_stub::read_string_index = 2;
ATHandler_stub::read_string_table[0] = (char *)"internet";
ATHandler_stub::read_string_table[1] = (char *)"IPV4V6";
ATHandler_stub::int_value = 1;
EXPECT_TRUE(NSAPI_ERROR_OK == my_cnipv6.set_stack_type(DEFAULT_STACK));
EXPECT_TRUE(NSAPI_ERROR_OK == my_cnipv6.set_credentials("internet"));
EXPECT_TRUE(NSAPI_ERROR_OK == my_cnipv6.activate_context());
// get_context pdp type gives proper type, apn match
ATHandler_stub::resp_info_true_counter = 1;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
ATHandler_stub::read_string_index = 2;
ATHandler_stub::read_string_table[0] = (char *)"internet";
ATHandler_stub::read_string_table[1] = (char *)"IPV6";
ATHandler_stub::int_value = 1;
EXPECT_TRUE(NSAPI_ERROR_OK == my_cnipv6.set_stack_type(DEFAULT_STACK));
EXPECT_TRUE(NSAPI_ERROR_OK == my_cnipv6.set_credentials("internet"));
EXPECT_TRUE(NSAPI_ERROR_OK == my_cnipv6.activate_context());
// get_context pdp type gives proper type, apn match
ATHandler_stub::resp_info_true_counter = 1;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
ATHandler_stub::read_string_index = 2;
ATHandler_stub::read_string_table[0] = (char *)"internet";
ATHandler_stub::read_string_table[1] = (char *)"IP";
ATHandler_stub::int_value = 1;
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.set_stack_type(DEFAULT_STACK));
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.set_credentials("internet"));
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.activate_context());
// get_context pdp type gives proper type, apn match. Test Delete the created context.
ATHandler_stub::resp_info_true_counter = 0;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
ATHandler_stub::int_value = 1;
//ATHandler_stub::nsapi_error_ok_counter = 2;
ATHandler_stub::resp_stop_success_count = 2;
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.set_credentials(NULL, NULL, NULL));
EXPECT_TRUE(NSAPI_ERROR_NO_CONNECTION == my_cn.activate_context());
}
TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_connect)
{
EventQueue que;
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
AT_CellularNetwork cn(at);
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
// no stack so will fail
cn.attach(&network_cb);
network_cb_count = 0;
EXPECT_TRUE(NSAPI_ERROR_UNSUPPORTED == cn.connect("APN", "a", "b"));
EXPECT_TRUE(NSAPI_STATUS_DISCONNECTED == cn.get_connection_status());
EXPECT_TRUE(network_cb_count == 2);
network_cb_count = 0;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_DEVICE_ERROR;
EXPECT_TRUE(NSAPI_ERROR_NO_CONNECTION == cn.connect("APN"));
EXPECT_TRUE(network_cb_count == 2);
EXPECT_TRUE(NSAPI_STATUS_DISCONNECTED == cn.get_connection_status());
my_AT_CN my_cn(at);
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
cn.set_stack_type(IPV4_STACK);
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.connect());
EXPECT_TRUE(network_cb_count == 2);
EXPECT_TRUE(NSAPI_STATUS_GLOBAL_UP == my_cn.get_connection_status());
}
TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_disconnect)
{
EventQueue que;
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
AT_CellularNetwork cn(at);
EXPECT_TRUE(NSAPI_ERROR_OK == cn.disconnect());
}
TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_get_stack)
{
EventQueue que;
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
my_AT_CN my_cn(at);
my_stack *mystack = (my_stack *)my_cn.get_stack();
EXPECT_TRUE(mystack);
delete mystack;
}
TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_set_registration)
{
EventQueue que;
@ -674,130 +360,6 @@ TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_detach)
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_DEVICE_ERROR;
EXPECT_TRUE(NSAPI_ERROR_DEVICE_ERROR == cn.detach());
// connect so we can test callback in detach
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
cn.set_stack_type(IPV4_STACK);
EXPECT_TRUE(NSAPI_ERROR_OK == cn.connect());
EXPECT_TRUE(NSAPI_STATUS_GLOBAL_UP == cn.get_connection_status());
// attach callback
cn.attach(&network_cb);
network_cb_count = 0;
EXPECT_TRUE(NSAPI_ERROR_OK == cn.detach());
EXPECT_TRUE(network_cb_count == 1);
EXPECT_TRUE(NSAPI_STATUS_DISCONNECTED == cn.get_connection_status());
}
TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_get_rate_control)
{
EventQueue que;
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
AT_CellularNetwork cn(at);
int ur = -1;
CellularNetwork::RateControlExceptionReports reports = CellularNetwork::NotAllowedToBeSent;
CellularNetwork::RateControlUplinkTimeUnit timeUnit = CellularNetwork::Unrestricted;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_DEVICE_ERROR;
EXPECT_TRUE(NSAPI_ERROR_DEVICE_ERROR == cn.get_rate_control(reports, timeUnit, ur));
EXPECT_TRUE(reports == CellularNetwork::NotAllowedToBeSent);
EXPECT_TRUE(timeUnit == CellularNetwork::Unrestricted);
EXPECT_TRUE(ur == -1);
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::int_value = 1;
EXPECT_TRUE(NSAPI_ERROR_OK == cn.get_rate_control(reports, timeUnit, ur));
EXPECT_TRUE(reports == CellularNetwork::AllowedToBeSent);
EXPECT_TRUE(timeUnit == CellularNetwork::Minute);
EXPECT_TRUE(ur == 1);
// test second if in get_rate_control
reports = CellularNetwork::NotAllowedToBeSent;
timeUnit = CellularNetwork::Unrestricted;
ur = -1;
ATHandler_stub::int_count = 1;
ATHandler_stub::int_valid_count_table[0] = 1;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
EXPECT_TRUE(NSAPI_ERROR_DEVICE_ERROR == cn.get_rate_control(reports, timeUnit, ur));
EXPECT_TRUE(reports == CellularNetwork::NotAllowedToBeSent);
EXPECT_TRUE(timeUnit == CellularNetwork::Unrestricted);
EXPECT_TRUE(ur == -1);
// test second if in get_rate_control
ATHandler_stub::int_count = 2;
ATHandler_stub::int_valid_count_table[0] = 1;
ATHandler_stub::int_valid_count_table[1] = 1;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
EXPECT_TRUE(NSAPI_ERROR_DEVICE_ERROR == cn.get_rate_control(reports, timeUnit, ur));
EXPECT_TRUE(reports == CellularNetwork::AllowedToBeSent);
EXPECT_TRUE(timeUnit == CellularNetwork::Unrestricted);
EXPECT_TRUE(ur == -1);
// test third if in get_rate_control
ATHandler_stub::int_count = 3;
ATHandler_stub::int_valid_count_table[0] = 3;
ATHandler_stub::int_valid_count_table[1] = 1;
ATHandler_stub::int_valid_count_table[2] = 1;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
EXPECT_TRUE(NSAPI_ERROR_DEVICE_ERROR == cn.get_rate_control(reports, timeUnit, ur));
EXPECT_TRUE(reports == CellularNetwork::AllowedToBeSent);
EXPECT_TRUE(timeUnit == CellularNetwork::Day);
EXPECT_TRUE(ur == -1);
ATHandler_stub::int_count = 4;
ATHandler_stub::int_valid_count_table[0] = 5;
ATHandler_stub::int_valid_count_table[1] = 3;
ATHandler_stub::int_valid_count_table[2] = 1;
ATHandler_stub::int_valid_count_table[3] = 1;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
EXPECT_TRUE(NSAPI_ERROR_OK == cn.get_rate_control(reports, timeUnit, ur));
EXPECT_TRUE(reports == CellularNetwork::AllowedToBeSent);
EXPECT_TRUE(timeUnit == CellularNetwork::Day);
EXPECT_TRUE(ur == 5);
}
TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_get_apn_backoff_timer)
{
EventQueue que;
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
AT_CellularNetwork cn(at);
int time = -1;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_DEVICE_ERROR;
EXPECT_TRUE(NSAPI_ERROR_PARAMETER == cn.get_apn_backoff_timer(time));
EXPECT_TRUE(time == -1);
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
EXPECT_TRUE(NSAPI_ERROR_PARAMETER == cn.get_apn_backoff_timer(time));
EXPECT_TRUE(time == -1);
ATHandler_stub::resp_info_true_counter = 0;
ATHandler_stub::bool_value = false;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
cn.set_credentials("internet", NULL, NULL);
EXPECT_TRUE(NSAPI_ERROR_OK == cn.get_apn_backoff_timer(time));
EXPECT_TRUE(time == -1);
ATHandler_stub::resp_info_true_counter = 0;
ATHandler_stub::bool_value = true;
ATHandler_stub::int_value = 55;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
cn.set_credentials("internet", NULL, NULL);
EXPECT_TRUE(NSAPI_ERROR_OK == cn.get_apn_backoff_timer(time));
EXPECT_TRUE(time == 55);
}
TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_get_ip_address)
{
EventQueue que;
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
AT_CellularNetwork cn(at);
EXPECT_TRUE(!cn.get_ip_address());
}
TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_set_access_technology)
@ -896,103 +458,12 @@ TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_get_ciot_optimization_con
pref = CellularNetwork::PREFERRED_UE_OPT_NO_PREFERENCE;
ATHandler_stub::int_value = 1;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_DEVICE_ERROR;
ATHandler_stub::nsapi_error_ok_counter = 0;
EXPECT_TRUE(NSAPI_ERROR_DEVICE_ERROR == cn.get_ciot_optimization_config(sup, pref));
EXPECT_TRUE(sup == CellularNetwork::SUPPORTED_UE_OPT_NO_SUPPORT);
EXPECT_TRUE(pref == CellularNetwork::PREFERRED_UE_OPT_NO_PREFERENCE);
}
TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_set_stack_type)
{
EventQueue que;
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
AT_CellularNetwork cn(at);
EXPECT_TRUE(NSAPI_ERROR_PARAMETER == cn.set_stack_type(IPV4_STACK));
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_stack_type(DEFAULT_STACK));
}
TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_get_stack_type)
{
EventQueue que;
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
AT_CellularNetwork cn(at);
EXPECT_TRUE(DEFAULT_STACK == cn.get_stack_type());
my_AT_CN my_cn(at);
EXPECT_TRUE(DEFAULT_STACK == my_cn.get_stack_type());
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.set_stack_type(IPV4_STACK));
EXPECT_TRUE(DEFAULT_STACK == my_cn.get_stack_type());
}
TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_get_pdpcontext_params)
{
EventQueue que;
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
AT_CellularNetwork cn(at);
CellularNetwork::pdpContextList_t list;
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_DEVICE_ERROR;
EXPECT_TRUE(NSAPI_ERROR_DEVICE_ERROR == cn.get_pdpcontext_params(list));
// don't got to while loop
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
ATHandler_stub::resp_info_true_counter = 0;
EXPECT_TRUE(NSAPI_ERROR_OK == cn.get_pdpcontext_params(list));
EXPECT_TRUE(NULL == list.get_head());
// go to while loop and check values
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::resp_info_true_counter = 1;
ATHandler_stub::int_count = 9;
ATHandler_stub::int_valid_count_table[8] = 1;
ATHandler_stub::int_valid_count_table[7] = 2;
ATHandler_stub::int_valid_count_table[6] = 3;
ATHandler_stub::int_valid_count_table[5] = 4;
ATHandler_stub::int_valid_count_table[4] = 5;
ATHandler_stub::int_valid_count_table[3] = 6;
ATHandler_stub::int_valid_count_table[2] = 7;
ATHandler_stub::int_valid_count_table[1] = 8;
ATHandler_stub::int_valid_count_table[0] = 9;
ATHandler_stub::read_string_index = 7;
ATHandler_stub::read_string_table[6] = (char *)"internet";
ATHandler_stub::read_string_table[5] = (char *)"1.2.3.4.5.6.7.8.9.10.11.112.13.14.15.16.1.2.3.44.55.6.7.8.9.10.11.12.13.14.15.16";
ATHandler_stub::read_string_table[4] = (char *)"23.33.44.1.2.3.55.123.225.34.11.1.0.0.123.234";
ATHandler_stub::read_string_table[3] = (char *)"1.2.3.4";
ATHandler_stub::read_string_table[2] = (char *)"0.255.0.255";
ATHandler_stub::read_string_table[1] = (char *)"25.66.77.88";
ATHandler_stub::read_string_table[0] = (char *)"004.003.002.001";
EXPECT_TRUE(NSAPI_ERROR_OK == cn.get_pdpcontext_params(list));
CellularNetwork::pdpcontext_params_t *params = list.get_head();
EXPECT_TRUE(params != NULL);
EXPECT_TRUE(params->next == NULL);
EXPECT_TRUE(params->cid == 1);
EXPECT_TRUE(params->bearer_id == 2);
EXPECT_TRUE(params->im_signalling_flag == 3);
EXPECT_TRUE(params->lipa_indication == 4);
EXPECT_TRUE(params->ipv4_mtu == 5);
EXPECT_TRUE(params->wlan_offload == 6);
EXPECT_TRUE(params->local_addr_ind == 7);
EXPECT_TRUE(params->non_ip_mtu == 8);
EXPECT_TRUE(params->serving_plmn_rate_control_value == 9);
EXPECT_TRUE(strcmp(params->apn, "internet") == 0);
EXPECT_TRUE(strcmp(params->local_addr, "102:304:506:708:90A:B70:D0E:F10") == 0);
EXPECT_TRUE(strcmp(params->local_subnet_mask, "102:32C:3706:708:90A:B0C:D0E:F10") == 0);
EXPECT_TRUE(strcmp(params->gateway_addr, "1721:2C01:203:377B:E122:B01:000:7BEA") == 0);
EXPECT_TRUE(strcmp(params->dns_primary_addr, "1.2.3.4") == 0);
EXPECT_TRUE(strcmp(params->dns_secondary_addr, "0.255.0.255") == 0);
EXPECT_TRUE(strcmp(params->p_cscf_prim_addr, "25.66.77.88") == 0);
EXPECT_TRUE(strcmp(params->p_cscf_sec_addr, "004.003.002.001") == 0);
}
TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_get_extended_signal_quality)
{
EventQueue que;
@ -1132,8 +603,6 @@ TEST_F(TestAT_CellularNetwork, test_AT_CellularNetwork_attach)
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
network_cb_count = 0;
cn.attach(&network_cb);
EXPECT_TRUE(NSAPI_ERROR_UNSUPPORTED == cn.connect());
EXPECT_TRUE(network_cb_count == 2); // check that attached callback was called twice
}
TEST_F(TestAT_CellularNetwork, test_get_connection_status)
@ -1147,32 +616,6 @@ TEST_F(TestAT_CellularNetwork, test_get_connection_status)
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
network_cb_count = 0;
cn.attach(&network_cb);
EXPECT_TRUE(NSAPI_ERROR_UNSUPPORTED == cn.connect());
EXPECT_TRUE(network_cb_count == 2); // check that attached callback was called twice
EXPECT_TRUE(NSAPI_STATUS_DISCONNECTED == cn.get_connection_status());
my_AT_CN my_cn(at);
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
ATHandler_stub::bool_value = false;
cn.set_stack_type(IPV4_STACK);
EXPECT_TRUE(NSAPI_ERROR_OK == my_cn.connect());
EXPECT_TRUE(network_cb_count == 2);
EXPECT_TRUE(NSAPI_STATUS_GLOBAL_UP == my_cn.get_connection_status());
}
TEST_F(TestAT_CellularNetwork, test_set_blocking)
{
EventQueue que;
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
AT_CellularNetwork cn(at);
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK;
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_blocking(false));
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_blocking(true));
ATHandler_stub::nsapi_error_value = NSAPI_ERROR_DEVICE_ERROR;
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_blocking(false));
EXPECT_TRUE(NSAPI_ERROR_OK == cn.set_blocking(true));
}

View File

@ -14,7 +14,6 @@ set(unittest-includes ${unittest-includes}
# Source files
set(unittest-sources
../features/cellular/framework/AT/AT_CellularNetwork.cpp
../features/cellular/framework/AT/AT_CellularStack.cpp
../features/cellular/framework/common/CellularUtil.cpp
)
@ -25,8 +24,6 @@ set(unittest-test-sources
stubs/AT_CellularBase_stub.cpp
stubs/EventQueue_stub.cpp
stubs/FileHandle_stub.cpp
stubs/NetworkInterface_stub.cpp
stubs/NetworkStack_stub.cpp
stubs/us_ticker_stub.cpp
stubs/mbed_assert_stub.c
stubs/SocketAddress_stub.cpp

View File

@ -0,0 +1,224 @@
/*
* 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 "AT_CellularContext.h"
using namespace mbed;
AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
AT_CellularBase(at), _ip_stack_type_requested(DEFAULT_STACK), _is_connected(false), _is_blocking(true),
_current_op(OP_INVALID), _device(device), _nw(0), _fh(0)
{
_stack = NULL;
_ip_stack_type = DEFAULT_STACK;
_authentication_type = CellularContext::CHAP;
_connect_status = NSAPI_STATUS_DISCONNECTED;
_is_context_active = false;
_is_context_activated = false;
_apn = apn;
_uname = MBED_CONF_NSAPI_DEFAULT_CELLULAR_USERNAME;
_pwd = MBED_CONF_NSAPI_DEFAULT_CELLULAR_PASSWORD;
_status_cb = NULL;
_cid = -1;
_new_context_set = false;
_next = NULL;
}
AT_CellularContext::~AT_CellularContext()
{
}
void AT_CellularContext::set_file_handle(FileHandle *fh)
{
}
nsapi_error_t AT_CellularContext::connect()
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularContext::set_device_ready()
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularContext::set_sim_ready()
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularContext::register_to_network()
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularContext::attach_to_network()
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularContext::check_operation(nsapi_error_t err, ContextOperation op)
{
return NSAPI_ERROR_OK;
}
uint32_t AT_CellularContext::get_timeout_for_operation(ContextOperation op) const
{
uint32_t timeout = 10 * 60 * 1000; // default timeout is 10 minutes as registration and attach may take time
return timeout;
}
bool AT_CellularContext::is_connected()
{
return true;
}
NetworkStack *AT_CellularContext::get_stack()
{
return NULL;
}
const char *AT_CellularContext::get_ip_address()
{
return NULL;
}
void AT_CellularContext::attach(Callback<void(nsapi_event_t, intptr_t)> status_cb)
{
}
nsapi_error_t AT_CellularContext::set_blocking(bool blocking)
{
return NSAPI_ERROR_OK;
}
void AT_CellularContext::set_plmn(const char *plmn)
{
}
void AT_CellularContext::set_sim_pin(const char *sim_pin)
{
}
nsapi_error_t AT_CellularContext::connect(const char *sim_pin, const char *apn, const char *uname,
const char *pwd)
{
return NSAPI_ERROR_OK;
}
void AT_CellularContext::set_credentials(const char *apn, const char *uname, const char *pwd)
{
}
const char *AT_CellularContext::get_netmask()
{
return NULL;
}
const char *AT_CellularContext::get_gateway()
{
return NULL;
}
bool AT_CellularContext::stack_type_supported(nsapi_ip_stack_t stack_type)
{
return true;
}
nsapi_ip_stack_t AT_CellularContext::get_stack_type()
{
return IPV4V6_STACK;
}
nsapi_ip_stack_t AT_CellularContext::string_to_stack_type(const char *pdp_type)
{
return IPV4V6_STACK;
}
// PDP Context handling
nsapi_error_t AT_CellularContext::delete_current_context()
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularContext::do_user_authentication()
{
return NSAPI_ERROR_OK;
}
bool AT_CellularContext::get_context()
{
return true;
}
bool AT_CellularContext::set_new_context(int cid)
{
return true;
}
nsapi_error_t AT_CellularContext::do_activate_context()
{
return NSAPI_ERROR_OK;
}
void AT_CellularContext::do_connect()
{
}
#if NSAPI_PPP_AVAILABLE
nsapi_error_t AT_CellularContext::open_data_channel()
{
return NSAPI_ERROR_OK;
}
void AT_CellularContext::ppp_status_cb(nsapi_event_t ev, intptr_t ptr)
{
}
#endif //#if NSAPI_PPP_AVAILABLE
nsapi_error_t AT_CellularContext::disconnect()
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularContext::get_apn_backoff_timer(int &backoff_timer)
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularContext::get_rate_control(
CellularContext::RateControlExceptionReports &reports,
CellularContext::RateControlUplinkTimeUnit &timeUnit, int &uplinkRate)
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularContext::get_pdpcontext_params(pdpContextList_t &params_list)
{
return NSAPI_ERROR_OK;
}
// Called by CellularDevice for network and cellular device changes
void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
{
}
void AT_CellularContext::call_network_cb(nsapi_connection_status_t status)
{
}

View File

@ -33,49 +33,6 @@ AT_CellularNetwork::~AT_CellularNetwork()
{
}
nsapi_error_t AT_CellularNetwork::init()
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn,
const char *username, const char *password)
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn,
AuthenticationType type, const char *username, const char *password)
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::connect(const char *apn,
const char *username, const char *password)
{
return connect();
}
nsapi_error_t AT_CellularNetwork::connect()
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::activate_context()
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::open_data_channel()
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::disconnect()
{
return NSAPI_ERROR_OK;
}
void AT_CellularNetwork::attach(Callback<void(nsapi_event_t, intptr_t)> status_cb)
{
}
@ -85,16 +42,6 @@ nsapi_connection_status_t AT_CellularNetwork::get_connection_status() const
return NSAPI_STATUS_LOCAL_UP;
}
nsapi_error_t AT_CellularNetwork::set_blocking(bool blocking)
{
return NSAPI_ERROR_OK;;
}
nsapi_ip_stack_t AT_CellularNetwork::string_to_stack_type(const char *pdp_type)
{
return IPV4_STACK;
}
nsapi_error_t AT_CellularNetwork::set_registration_urc(RegistrationType type, bool urc_on)
{
return NSAPI_ERROR_OK;
@ -126,7 +73,7 @@ AT_CellularNetwork::RegistrationMode AT_CellularNetwork::has_registration(Regist
return RegistrationModeDisable;
}
nsapi_error_t AT_CellularNetwork::set_attach(int timeout)
nsapi_error_t AT_CellularNetwork::set_attach()
{
return NSAPI_ERROR_OK;
}
@ -141,36 +88,6 @@ nsapi_error_t AT_CellularNetwork::detach()
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::get_apn_backoff_timer(int &backoffTime)
{
return NSAPI_ERROR_OK;
}
NetworkStack *AT_CellularNetwork::get_stack()
{
return NULL;
}
const char *AT_CellularNetwork::get_ip_address()
{
return NULL;
}
nsapi_error_t AT_CellularNetwork::set_stack_type(nsapi_ip_stack_t stack_type)
{
return NSAPI_ERROR_OK;
}
nsapi_ip_stack_t AT_CellularNetwork::get_stack_type()
{
return IPV4_STACK;
}
bool AT_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
return false;
}
void AT_CellularNetwork::urc_no_carrier()
{
@ -203,19 +120,6 @@ nsapi_error_t AT_CellularNetwork::get_ciot_optimization_config(Supported_UE_Opt
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::get_rate_control(
CellularNetwork::RateControlExceptionReports &reports,
CellularNetwork::RateControlUplinkTimeUnit &timeUnit, int &uplinkRate)
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::get_pdpcontext_params(pdpContextList_t &params_list)
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::get_extended_signal_quality(int &rxlev, int &ber, int &rscp, int &ecno, int &rsrq, int &rsrp)
{
return NSAPI_ERROR_OK;
@ -241,10 +145,7 @@ nsapi_error_t AT_CellularNetwork::get_operator_names(operator_names_list &op_nam
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::do_user_authentication()
bool AT_CellularNetwork::is_active_context()
{
return NSAPI_ERROR_OK;
return true;
}

View File

@ -26,14 +26,54 @@ MBED_WEAK CellularDevice *CellularDevice::get_default_instance()
return NULL;
}
CellularDevice::CellularDevice() : _network_ref_count(0), _sms_ref_count(0), _power_ref_count(0), _sim_ref_count(0),
_info_ref_count(0)
CellularDevice::CellularDevice(FileHandle *fh) : _network_ref_count(0), _sms_ref_count(0),_power_ref_count(0), _sim_ref_count(0),
_info_ref_count(0), _fh(fh), _queue(5 * EVENTS_EVENT_SIZE), _state_machine(0), _nw(0)
{
}
events::EventQueue *CellularDevice::get_queue() const
CellularDevice::~CellularDevice()
{
}
events::EventQueue *CellularDevice::get_queue()
{
return NULL;
}
void CellularDevice::set_plmn(char const*)
{
}
void CellularDevice::set_sim_pin(char const*)
{
}
CellularContext *CellularDevice::get_context_list() const
{
return NULL;
}
nsapi_error_t CellularDevice::set_device_ready()
{
return NSAPI_ERROR_OK;
}
nsapi_error_t CellularDevice::set_sim_ready()
{
return NSAPI_ERROR_OK;
}
nsapi_error_t CellularDevice::register_to_network()
{
return NSAPI_ERROR_OK;
}
nsapi_error_t CellularDevice::attach_to_network()
{
return NSAPI_ERROR_OK;
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2017, 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 "CellularStateMachine.h"
#include "CellularDevice.h"
namespace mbed {
CellularStateMachine::CellularStateMachine(CellularDevice &device, events::EventQueue &queue) :
_cellularDevice(device), _queue(queue)
{
}
CellularStateMachine::~CellularStateMachine()
{
}
void CellularStateMachine::stop()
{
}
void CellularStateMachine::set_sim_pin(const char *sim_pin)
{
}
void CellularStateMachine::set_plmn(const char *plmn)
{
}
nsapi_error_t CellularStateMachine::run_to_state(CellularStateMachine::CellularState state)
{
return NSAPI_ERROR_OK;
}
bool CellularStateMachine::get_current_status(CellularStateMachine::CellularState &current_state, CellularStateMachine::CellularState &target_state)
{
return true;
}
nsapi_error_t CellularStateMachine::start_dispatch()
{
return NSAPI_ERROR_OK;
}
void CellularStateMachine::set_cellular_callback(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
{
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2017, 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 "SerialBase.h"
namespace mbed {
SerialBase::SerialBase(PinName tx, PinName rx, int baud)
{
}
SerialBase::~SerialBase()
{
}
void SerialBase::baud(int baudrate)
{
}
void SerialBase::format(int bits, Parity parity, int stop_bits)
{
}
int SerialBase::readable()
{
return 0;
}
int SerialBase::writeable()
{
return 0;
}
void SerialBase::attach(Callback<void()> func, IrqType type)
{
}
void SerialBase::_irq_handler(uint32_t id, SerialIrq irq_type)
{
}
int SerialBase::_base_getc()
{
return 0;
}
int SerialBase::_base_putc(int c)
{
return 0;
}
void SerialBase::send_break()
{
}
void SerialBase::lock()
{
}
void SerialBase:: unlock()
{
}
}

View File

@ -0,0 +1,127 @@
/*
* 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 "UARTSerial.h"
namespace mbed {
UARTSerial::UARTSerial(PinName tx, PinName rx, int baud) : SerialBase(tx, rx, baud)
{
}
UARTSerial::~UARTSerial()
{
}
ssize_t UARTSerial::read(void *buffer, size_t length)
{
return 0;
}
ssize_t UARTSerial::write(const void *buffer, size_t length)
{
return 0;
}
off_t UARTSerial::seek(off_t offset, int whence)
{
return -ESPIPE;
}
int UARTSerial::close()
{
return 0;
}
void UARTSerial::dcd_irq()
{
}
void UARTSerial::set_baud(int baud)
{
}
void UARTSerial::set_data_carrier_detect(PinName dcd_pin, bool active_high)
{
}
void UARTSerial::set_format(int bits, Parity parity, int stop_bits)
{
}
int UARTSerial::isatty()
{
return 1;
}
int UARTSerial::sync()
{
return 0;
}
void UARTSerial::sigio(Callback<void()> func)
{
}
ssize_t UARTSerial::write_unbuffered(const char *buf_ptr, size_t length)
{
return 0;
}
bool UARTSerial::hup() const
{
}
void UARTSerial::wake()
{
}
short UARTSerial::poll(short events) const
{
return 0;
}
void UARTSerial::lock()
{
}
void UARTSerial::unlock()
{
}
void UARTSerial::api_lock(void)
{
}
void UARTSerial::api_unlock(void)
{
}
void UARTSerial::rx_irq(void)
{
}
void UARTSerial::tx_irq(void)
{
}
void UARTSerial::wait_ms(uint32_t millisec)
{
}
}

View File

@ -25,6 +25,14 @@
extern "C" {
#endif
struct gpio_irq_s {
uint32_t ch;
};
struct serial_s {
int x;
};
#include "gpio_object.h"
#ifdef __cplusplus

View File

@ -39,11 +39,10 @@
static UARTSerial cellular_serial(MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE);
static CellularDevice *device;
static EventQueue queue(8 * EVENTS_EVENT_SIZE);
static void create_device()
{
device = new CELLULAR_DEVICE(queue);
device = new CELLULAR_DEVICE(&cellular_serial);
TEST_ASSERT(device != NULL);
}
@ -52,32 +51,26 @@ static void open_close_interfaces()
CellularNetwork *nw = device->open_network(&cellular_serial);
TEST_ASSERT(nw != NULL);
device->close_network();
nw = device->open_network(NULL);
TEST_ASSERT(nw == NULL);
CellularSIM *sim = device->open_sim(&cellular_serial);
TEST_ASSERT(sim != NULL);
device->close_sim();
sim = device->open_sim(NULL);
TEST_ASSERT(sim == NULL);
CellularInformation *info = device->open_information(&cellular_serial);
TEST_ASSERT(info != NULL);
device->close_information();
info = device->open_information(NULL);
TEST_ASSERT(info == NULL);
CellularPower *power = device->open_power(&cellular_serial);
TEST_ASSERT(power != NULL);
device->close_power();
power = device->open_power(NULL);
TEST_ASSERT(power == NULL);
CellularSMS *sms = device->open_sms(&cellular_serial);
TEST_ASSERT(sms != NULL);
device->close_sms();
sms = device->open_sms(NULL);
TEST_ASSERT(sms == NULL);
CellularContext *ctx = device->create_context();
TEST_ASSERT(ctx != NULL);
device->delete_context(ctx);
}
static void other_methods()
@ -86,8 +79,6 @@ static void other_methods()
device->set_timeout(5000);
device->modem_debug_on(true);
device->modem_debug_on(false);
NetworkStack *stack = device->get_stack();
TEST_ASSERT(stack == NULL);
CellularNetwork *nw = device->open_network(&cellular_serial);
TEST_ASSERT(nw != NULL);
@ -96,8 +87,6 @@ static void other_methods()
device->set_timeout(5000);
device->modem_debug_on(true);
device->modem_debug_on(false);
stack = device->get_stack();
TEST_ASSERT(stack != NULL);
}
static void delete_device()

View File

@ -39,46 +39,30 @@
#include "AT_CellularInformation.h"
#include "CellularConnectionFSM.h"
#include "CellularContext.h"
#include "CellularDevice.h"
#include "../../cellular_tests_common.h"
#define SIM_TIMEOUT (180*1000)
static UARTSerial cellular_serial(MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE);
static EventQueue queue(2 * EVENTS_EVENT_SIZE);
static CellularConnectionFSM cellular;
static CellularConnectionFSM::CellularState cellular_target_state;
static rtos::Semaphore fsm_semaphore(0);
static bool fsm_callback(int state, int next_state)
{
if (next_state == CellularConnectionFSM::STATE_SIM_PIN) {
TEST_ASSERT(fsm_semaphore.release() == osOK);
return false;
}
return true;
}
static CellularContext *ctx;
static void init_to_sim_state()
{
cellular.set_serial(&cellular_serial);
TEST_ASSERT(cellular.init() == NSAPI_ERROR_OK);
#if defined (MDMRTS) && defined (MDMCTS)
cellular_serial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS);
ctx = CellularContext::get_default_instance();
TEST_ASSERT(ctx != NULL);
ctx->set_sim_pin(MBED_CONF_APP_CELLULAR_SIM_PIN);
#ifdef MBED_CONF_APP_APN
ctx->set_credentials(MBED_CONF_APP_APN);
#endif
cellular.set_callback(&fsm_callback);
TEST_ASSERT(cellular.start_dispatch() == NSAPI_ERROR_OK);
cellular_target_state = CellularConnectionFSM::STATE_SIM_PIN;
TEST_ASSERT(cellular.continue_to_state(cellular_target_state) == NSAPI_ERROR_OK);
TEST_ASSERT(fsm_semaphore.wait(SIM_TIMEOUT) == 1);
TEST_ASSERT(ctx->set_sim_ready() == NSAPI_ERROR_OK);
}
static void test_information_interface()
{
CellularInformation *info = cellular.get_device()->open_information(&cellular_serial);
CellularDevice *dev = CellularDevice::get_default_instance();
CellularInformation *info = dev->open_information();
const int kbuf_size = 100;
char *buf = (char *)malloc(sizeof(char) * kbuf_size);
char *buf = new char[kbuf_size];
TEST_ASSERT(info->get_manufacturer(buf, kbuf_size) == NSAPI_ERROR_OK);
TEST_ASSERT(info->get_model(buf, kbuf_size) == NSAPI_ERROR_OK);
@ -96,9 +80,9 @@ static void test_information_interface()
err = info->get_serial_number(buf, kbuf_size, CellularInformation::SVN);
TEST_ASSERT(err == NSAPI_ERROR_UNSUPPORTED || err == NSAPI_ERROR_OK);
cellular.get_device()->close_information();
dev->close_information();
free(buf);
delete [] buf;
}
using namespace utest::v1;

View File

@ -31,6 +31,10 @@
#error [NOT_SUPPORTED] SIM pin code is needed. Skipping this build.
#endif
#if defined(TARGET_ADV_WISE_1570) || defined(TARGET_MTB_ADV_WISE_1570)
#error [NOT_SUPPORTED] target MTB_ADV_WISE_1570 is too unstable for network tests, IoT network is unstable
#endif
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
@ -38,65 +42,30 @@
#include "mbed.h"
#include "AT_CellularNetwork.h"
#include "CellularConnectionFSM.h"
#include "CellularContext.h"
#include "CellularDevice.h"
#include "../../cellular_tests_common.h"
#include CELLULAR_STRINGIFY(CELLULAR_DEVICE.h)
#define NETWORK_TIMEOUT (180*1000)
static UARTSerial cellular_serial(MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE);
static EventQueue queue(8 * EVENTS_EVENT_SIZE);
static rtos::Semaphore network_semaphore(0);
static CellularConnectionFSM cellular;
static CellularConnectionFSM::CellularState cellular_target_state;
static CELLULAR_DEVICE *device;
static CellularContext *ctx;
static CellularDevice *device;
static CellularNetwork *nw;
static bool fsm_callback(int state, int next_state)
{
if (next_state == cellular_target_state) {
TEST_ASSERT(network_semaphore.release() == osOK);
return false;
}
return true;
}
// test methods that are already run in state machine (CellularConnectionFSM) but as it might change
// we wan't to run these 'manually' also
static void test_network_interface_fsm()
{
#if defined (MDMRTS) && defined (MDMCTS)
cellular_serial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS);
#endif
device = new CELLULAR_DEVICE(queue);
TEST_ASSERT(device != NULL);
CellularNetwork *nw = device->open_network(&cellular_serial);
TEST_ASSERT(nw != NULL);
TEST_ASSERT(nw->init() == NSAPI_ERROR_OK);
delete device;
device = NULL;
}
static void init_network_interface()
{
cellular.set_serial(&cellular_serial);
TEST_ASSERT(cellular.init() == NSAPI_ERROR_OK);
cellular.set_callback(&fsm_callback);
TEST_ASSERT(cellular.start_dispatch() == NSAPI_ERROR_OK);
cellular.set_sim_pin(MBED_CONF_APP_CELLULAR_SIM_PIN);
ctx = CellularContext::get_default_instance();
TEST_ASSERT(ctx != NULL);
ctx->set_sim_pin(MBED_CONF_APP_CELLULAR_SIM_PIN);
#ifdef MBED_CONF_APP_APN
CellularNetwork *network = cellular.get_network();
TEST_ASSERT(network->set_credentials(MBED_CONF_APP_APN) == NSAPI_ERROR_OK);
ctx->set_credentials(MBED_CONF_APP_APN);
#endif
cellular_target_state = CellularConnectionFSM::STATE_REGISTERING_NETWORK;
TEST_ASSERT(cellular.continue_to_state(cellular_target_state) == NSAPI_ERROR_OK);
TEST_ASSERT(network_semaphore.wait(NETWORK_TIMEOUT) == 1);
}
TEST_ASSERT(ctx->register_to_network() == NSAPI_ERROR_OK);
device = CellularDevice::get_default_instance();
TEST_ASSERT(device != NULL);
}
static bool get_network_registration(CellularNetwork::RegistrationType type,
CellularNetwork::RegistrationStatus &status, bool &is_registered)
@ -149,8 +118,8 @@ static void nw_callback(nsapi_event_t ev, intptr_t intptr)
static void test_network_registration()
{
cellular.get_device()->set_timeout(10 * 1000);
nw = cellular.get_network();
device->set_timeout(10 * 1000);
nw = device->open_network();
TEST_ASSERT(nw != NULL);
nw->attach(&nw_callback);
@ -194,97 +163,22 @@ static void test_attach()
TEST_ASSERT(status == CellularNetwork::Attached);
}
static void test_activate_context()
{
TEST_ASSERT(nw->activate_context() == NSAPI_ERROR_OK);
}
static void test_connect()
{
TEST_ASSERT(nw->connect() == NSAPI_ERROR_OK);
char count = 0;
while ((nw->get_connection_status() != NSAPI_STATUS_GLOBAL_UP) && (count++ < 60)) {
wait(1);
}
nsapi_connection_status_t st = nw->get_connection_status();
TEST_ASSERT(st == NSAPI_STATUS_GLOBAL_UP);
}
static void test_credentials()
{
nsapi_error_t err = nw->set_credentials(NULL, "username", "pass");
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_UNSUPPORTED);
err = nw->set_credentials("internet", "user", NULL);
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_UNSUPPORTED);
err = nw->set_credentials("internet", CellularNetwork::NOAUTH, "user", "pass");
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_UNSUPPORTED);
TEST_ASSERT(nw->set_credentials("internet", NULL, "pass") == NSAPI_ERROR_OK);
}
static void test_other()
{
const char *devi = CELLULAR_STRINGIFY(CELLULAR_DEVICE);
TEST_ASSERT(nw->get_3gpp_error() == 0);
CellularNetwork::RateControlExceptionReports reports;
CellularNetwork::RateControlUplinkTimeUnit timeUnit;
int uplinkRate;
// can't test values as they are optional
nsapi_error_t err = nw->get_rate_control(reports, timeUnit, uplinkRate);
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_DEVICE_ERROR);
if (strcmp(devi, "QUECTEL_BG96") != 0 && strcmp(devi, "TELIT_HE910") != 0 && strcmp(devi, "SARA4_PPP") != 0) { // QUECTEL_BG96 does not give any specific reason for device error
if (err == NSAPI_ERROR_DEVICE_ERROR) {
TEST_ASSERT(((AT_CellularNetwork *)nw)->get_device_error().errCode == 100 && // 100 == unknown command for modem
((AT_CellularNetwork *)nw)->get_device_error().errType == 3); // 3 == CME error from the modem
}
}
uplinkRate = -1;
err = nw->get_apn_backoff_timer(uplinkRate);
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_DEVICE_ERROR || err == NSAPI_ERROR_PARAMETER);
if (err == NSAPI_ERROR_DEVICE_ERROR) {
if (strcmp(devi, "QUECTEL_BG96") != 0 && strcmp(devi, "TELIT_HE910") != 0 && strcmp(devi, "SARA4_PPP") != 0) { // QUECTEL_BG96 does not give any specific reason for device error
TEST_ASSERT(((AT_CellularNetwork *)nw)->get_device_error().errCode == 100 && // 100 == unknown command for modem
((AT_CellularNetwork *)nw)->get_device_error().errType == 3); // 3 == CME error from the modem
}
} else if (err == NSAPI_ERROR_PARAMETER) {
TEST_ASSERT(uplinkRate == -1);
} else {
TEST_ASSERT(uplinkRate >= 0);
}
err = nw->set_access_technology(CellularNetwork::RAT_GSM);
nsapi_error_t err = nw->set_access_technology(CellularNetwork::RAT_GSM);
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_UNSUPPORTED);
// scanning of operators requires some delay before operation is allowed(seen with WISE_1570)
wait(5);
// scanning of operators might take a long time
cellular.get_device()->set_timeout(240 * 1000);
device->set_timeout(240 * 1000);
CellularNetwork::operList_t operators;
int uplinkRate = -1;
TEST_ASSERT(nw->scan_plmn(operators, uplinkRate) == NSAPI_ERROR_OK);
cellular.get_device()->set_timeout(10 * 1000);
// all current targets support IPV4
nsapi_ip_stack_t stack_type = IPV4_STACK;
TEST_ASSERT(nw->set_stack_type(stack_type) == NSAPI_ERROR_OK);
TEST_ASSERT(nw->get_stack_type() == stack_type);
CellularNetwork::pdpContextList_t params_list;
err = nw->get_pdpcontext_params(params_list);
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_DEVICE_ERROR);
if (err == NSAPI_ERROR_DEVICE_ERROR) {
if (strcmp(devi, "TELIT_HE910") != 0) { // TELIT_HE910 just gives an error and no specific error number so we can't know is this real error or that modem/network does not support the command
TEST_ASSERT((((AT_CellularNetwork *)nw)->get_device_error().errType == 3) && // 3 == CME error from the modem
((((AT_CellularNetwork *)nw)->get_device_error().errCode == 100) || // 100 == unknown command for modem
(((AT_CellularNetwork *)nw)->get_device_error().errCode == 50))); // 50 == incorrect parameters // seen in wise_1570 for not supported commands
}
} else {
// should have some values, only not optional are apn and bearer id
CellularNetwork::pdpcontext_params_t *params = params_list.get_head();
TEST_ASSERT(params->bearer_id >= 0)
}
device->set_timeout(10 * 1000);
int rxlev = -1, ber = -1, rscp = -1, ecno = -1, rsrq = -1, rsrp = -1;
err = nw->get_extended_signal_quality(rxlev, ber, rscp, ecno, rsrq, rsrp);
@ -328,8 +222,6 @@ static void test_other()
nsapi_connection_status_t st = nw->get_connection_status();
TEST_ASSERT(st == NSAPI_STATUS_DISCONNECTED);
TEST_ASSERT(nw->set_blocking(true) == NSAPI_ERROR_OK);
#ifndef TARGET_UBLOX_C027 // AT command is supported, but excluded as it runs out of memory easily (there can be very many operator names)
if (strcmp(devi, "QUECTEL_BG96") != 0 && strcmp(devi, "SARA4_PPP") != 0) {
// QUECTEL_BG96 timeouts with this one, tested with 3 minute timeout
@ -378,15 +270,6 @@ static void test_other()
}
}
static void test_disconnect()
{
nsapi_connection_status_t st = nw->get_connection_status();
TEST_ASSERT(st == NSAPI_STATUS_GLOBAL_UP);
TEST_ASSERT(nw->disconnect() == NSAPI_ERROR_OK);
// wait to process URC's, received after disconnect
rtos::ThisThread::sleep_for(500);
}
static void test_detach()
{
// in PPP mode there is NO CARRIER waiting so flush it out
@ -412,17 +295,11 @@ static utest::v1::status_t greentea_failure_handler(const Case *const source, co
}
static Case cases[] = {
Case("CellularNetwork state machine methods", test_network_interface_fsm, greentea_failure_handler),
Case("CellularNetwork init", init_network_interface, greentea_failure_handler),
Case("CellularNetwork test registering", test_network_registration, greentea_failure_handler),
Case("CellularNetwork test attach", test_attach, greentea_failure_handler),
Case("CellularNetwork test activate pdp context", test_activate_context, greentea_failure_handler),
Case("CellularNetwork test other functions", test_other, greentea_failure_handler),
Case("CellularNetwork test connect", test_connect, greentea_failure_handler),
Case("CellularNetwork test credentials", test_credentials, greentea_failure_handler),
Case("CellularNetwork test disconnect", test_disconnect, greentea_failure_handler),
Case("CellularNetwork test detach", test_detach, greentea_failure_handler)
};
static utest::v1::status_t test_setup(const size_t number_of_cases)

View File

@ -44,9 +44,7 @@
#define NETWORK_TIMEOUT (180*1000)
static UARTSerial cellular_serial(MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE);
static CELLULAR_DEVICE *cellular_device;
static EventQueue queue(2 * EVENTS_EVENT_SIZE);
static CellularDevice *cellular_device;
static void urc_callback()
{
@ -74,9 +72,9 @@ static void wait_for_power(CellularPower *pwr)
static void test_power_interface()
{
const char *devi = CELLULAR_STRINGIFY(CELLULAR_DEVICE);
cellular_device = new CELLULAR_DEVICE(queue);
cellular_device->set_timeout(5000);
CellularPower *pwr = cellular_device->open_power(&cellular_serial);
cellular_device = CellularDevice::get_default_instance();
cellular_device->set_timeout(9000);
CellularPower *pwr = cellular_device->open_power();
TEST_ASSERT(pwr != NULL);
nsapi_error_t err = pwr->on();
@ -89,6 +87,7 @@ static void test_power_interface()
TEST_ASSERT(err == NSAPI_ERROR_OK);
wait_for_power(pwr);
wait(1);
err = pwr->opt_power_save_mode(0, 0);
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_DEVICE_ERROR);
if (err == NSAPI_ERROR_DEVICE_ERROR) {
@ -98,6 +97,7 @@ static void test_power_interface()
}
}
wait(1);
err = pwr->opt_receive_period(0, CellularPower::EDRXEUTRAN_NB_S1_mode, 3);
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_DEVICE_ERROR);
if (err == NSAPI_ERROR_DEVICE_ERROR) {
@ -109,6 +109,7 @@ static void test_power_interface()
err = pwr->off();
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_UNSUPPORTED);
}
using namespace utest::v1;

View File

@ -37,86 +37,40 @@
#include "mbed.h"
#include "CellularConnectionFSM.h"
#include "CellularContext.h"
#include "CellularDevice.h"
#include "CellularSIM.h"
#include "../../cellular_tests_common.h"
#include CELLULAR_STRINGIFY(CELLULAR_DEVICE.h)
#define NETWORK_TIMEOUT (180*1000)
static UARTSerial cellular_serial(MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE);
static EventQueue queue(8 * EVENTS_EVENT_SIZE);
static rtos::Semaphore network_semaphore(0);
static CellularConnectionFSM cellular;
static CellularConnectionFSM::CellularState cellular_target_state;
static CellularContext *ctx;
static CellularDevice *device;
static char *get_rand_string(char *str, size_t size)
static void init_to_device_ready_state()
{
const char charset[] = "0123456789";
if (size) {
--size;
for (size_t n = 0; n < size; n++) {
int key = rand() % (int)(sizeof charset - 1);
str[n] = charset[key];
}
str[size] = '\0';
}
return str;
}
ctx = CellularContext::get_default_instance();
TEST_ASSERT(ctx != NULL);
TEST_ASSERT(ctx->set_device_ready() == NSAPI_ERROR_OK);
static bool fsm_callback(int state, int next_state)
{
if (next_state == CellularConnectionFSM::STATE_SIM_PIN) {
TEST_ASSERT(network_semaphore.release() == osOK);
return false;
}
return true;
}
static void init_to_sim_state()
{
cellular.set_serial(&cellular_serial);
TEST_ASSERT(cellular.init() == NSAPI_ERROR_OK);
#if defined (MDMRTS) && defined (MDMCTS)
cellular_serial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS);
#endif
cellular.set_callback(&fsm_callback);
TEST_ASSERT(cellular.start_dispatch() == NSAPI_ERROR_OK);
cellular_target_state = CellularConnectionFSM::STATE_SIM_PIN;
TEST_ASSERT(cellular.continue_to_state(cellular_target_state) == NSAPI_ERROR_OK);
TEST_ASSERT(network_semaphore.wait(NETWORK_TIMEOUT) == 1);
device = CellularDevice::get_default_instance();
TEST_ASSERT(device != NULL);
}
static void test_sim_interface()
{
CellularSIM *sim = cellular.get_sim();
CellularSIM *sim = device->open_sim();
TEST_ASSERT(sim != NULL);
// set SIM at time out to 3000
cellular.get_device()->set_timeout(3000);
// set SIM at time out to 9000
device->set_timeout(9000);
wait(4); // we need to wait for some time so that SIM interface is working in all modules.
// 1. test set_pin
nsapi_error_t err = sim->set_pin(MBED_CONF_APP_CELLULAR_SIM_PIN);
MBED_ASSERT(err == NSAPI_ERROR_OK);
// 2. test change pin
char pin[5];
int sanity_count = 0;
while (strcmp(get_rand_string(pin, 5), MBED_CONF_APP_CELLULAR_SIM_PIN) == 0) {
sanity_count++;
TEST_ASSERT(sanity_count < 50);
};
// change pin and change it back
wait(1);
err = sim->change_pin(MBED_CONF_APP_CELLULAR_SIM_PIN, pin);
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_UNSUPPORTED);
wait(1);
err = sim->change_pin(pin, MBED_CONF_APP_CELLULAR_SIM_PIN);
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_UNSUPPORTED);
// 3. test set_pin_query
// 2. test set_pin_query
wait(1);
err = sim->set_pin_query(MBED_CONF_APP_CELLULAR_SIM_PIN, false);
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_UNSUPPORTED);
@ -126,14 +80,14 @@ static void test_sim_interface()
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_UNSUPPORTED);
wait(1);
// 4. test get_sim_state
// 3. test get_sim_state
CellularSIM::SimState state;
err = sim->get_sim_state(state);
TEST_ASSERT(err == NSAPI_ERROR_OK);
TEST_ASSERT(state == CellularSIM::SimStateReady);
wait(1);
// 5. test get_imsi
// 4. test get_imsi
char imsi[16] = {0};
err = sim->get_imsi(imsi);
TEST_ASSERT(err == NSAPI_ERROR_OK);
@ -149,7 +103,7 @@ static utest::v1::status_t greentea_failure_handler(const Case *const source, co
}
static Case cases[] = {
Case("CellularSIM init", init_to_sim_state, greentea_failure_handler),
Case("CellularSIM init", init_to_device_ready_state, greentea_failure_handler),
Case("CellularSIM test interface", test_sim_interface, greentea_failure_handler)
};

View File

@ -31,7 +31,9 @@
#error [NOT_SUPPORTED] SIM pin code is needed. Skipping this build.
#endif
#if defined(TARGET_ADV_WISE_1570) || defined(TARGET_MTB_ADV_WISE_1570)
#error [NOT_SUPPORTED] target MTB_ADV_WISE_1570 does not have SMS functionality
#endif
#include "greentea-client/test_env.h"
#include "unity.h"
@ -40,59 +42,43 @@
#include "mbed.h"
#include "AT_CellularSMS.h"
#include "CellularConnectionFSM.h"
#include "CellularContext.h"
#include "CellularDevice.h"
#include "../../cellular_tests_common.h"
#include CELLULAR_STRINGIFY(CELLULAR_DEVICE.h)
#define NETWORK_TIMEOUT (600*1000)
#define SIM_BUSY 314
static UARTSerial cellular_serial(MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE);
static EventQueue queue(8 * EVENTS_EVENT_SIZE);
static rtos::Semaphore network_semaphore(0);
static CellularConnectionFSM *cellularConnectionFSM;
static CellularConnectionFSM::CellularState cellular_target_state;
static CellularContext *ctx;
static CellularDevice *device;
static CellularSMS *sms;
static char service_center_address[SMS_MAX_PHONE_NUMBER_SIZE];
static int service_address_type;
static bool cellular_status(int state, int next_state)
static void create_context()
{
if (cellular_target_state == state) {
(void)network_semaphore.release();
return false; // return false -> state machine is halted
}
return true;
}
static void createFSM()
{
#if defined (MDMRTS) && defined (MDMCTS)
cellular_serial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS);
#endif
cellularConnectionFSM = new CellularConnectionFSM();
cellularConnectionFSM->set_serial(&cellular_serial);
cellularConnectionFSM->set_callback(&cellular_status);
TEST_ASSERT(cellularConnectionFSM->init() == NSAPI_ERROR_OK);
TEST_ASSERT(cellularConnectionFSM->start_dispatch() == NSAPI_ERROR_OK);
cellularConnectionFSM->set_sim_pin(MBED_CONF_APP_CELLULAR_SIM_PIN);
CellularDevice *device = cellularConnectionFSM->get_device();
device = new CELLULAR_DEVICE(&cellular_serial);
TEST_ASSERT(device != NULL);
device->set_timeout(30000);
device->set_timeout(9000);
ctx = device->create_context();
TEST_ASSERT(ctx != NULL);
ctx->set_sim_pin(MBED_CONF_APP_CELLULAR_SIM_PIN);
#ifdef MBED_CONF_APP_APN
ctx->set_credentials(MBED_CONF_APP_APN);
#endif
}
static void store_service_center_address()
{
// Frist we need to go SIM_PIN state to make sure that we can get service address and device ready to accept AT commands
createFSM();
cellular_target_state = CellularConnectionFSM::STATE_SIM_PIN;
TEST_ASSERT(cellularConnectionFSM->continue_to_state(cellular_target_state) == NSAPI_ERROR_OK);
TEST_ASSERT(network_semaphore.wait(NETWORK_TIMEOUT) == 1); // cellular network searching may take several minutes
// First we need to go SIM_PIN state to make sure that we can get service address and device ready to accept AT commands
create_context();
TEST_ASSERT(ctx->set_sim_ready() == NSAPI_ERROR_OK);
wait(1);
delete device; // will also delete context
delete cellularConnectionFSM;
cellularConnectionFSM = NULL;
wait(3); // some modems needs more time access sim
ATHandler *at_init = new ATHandler(&cellular_serial, queue, 30000, "\r");
at_init->cmd_start("AT+CSCA?");
@ -114,50 +100,60 @@ static void init()
{
// First store current service address
store_service_center_address();
create_context();
createFSM();
CellularNetwork *network = cellularConnectionFSM->get_network();
TEST_ASSERT(network != NULL);
TEST_ASSERT(network->set_credentials(MBED_CONF_APP_APN, NULL, NULL) == NSAPI_ERROR_OK);
cellular_target_state = CellularConnectionFSM::STATE_REGISTERING_NETWORK;
TEST_ASSERT(cellularConnectionFSM->continue_to_state(cellular_target_state) == NSAPI_ERROR_OK);
TEST_ASSERT(network_semaphore.wait(NETWORK_TIMEOUT) == 1); // cellular network searching may take several minutes
sms = cellularConnectionFSM->get_device()->open_sms(&cellular_serial);
TEST_ASSERT(ctx->register_to_network() == NSAPI_ERROR_OK);
sms = device->open_sms(&cellular_serial);
TEST_ASSERT(sms != NULL);
wait(3);
wait(3); // some modems needs more time access sim
}
static void test_sms_initialize_text_mode()
{
TEST_ASSERT(sms->initialize(CellularSMS::CellularSMSMmodeText) == NSAPI_ERROR_OK);
nsapi_error_t err = sms->initialize(CellularSMS::CellularSMSMmodeText);
TEST_ASSERT(err == NSAPI_ERROR_OK || (err == NSAPI_ERROR_DEVICE_ERROR &&
((AT_CellularSMS *)sms)->get_device_error().errCode == SIM_BUSY));
}
static void test_sms_initialize_pdu_mode()
{
TEST_ASSERT(sms->initialize(CellularSMS::CellularSMSMmodePDU) == NSAPI_ERROR_OK);
nsapi_error_t err = sms->initialize(CellularSMS::CellularSMSMmodePDU);
TEST_ASSERT(err == NSAPI_ERROR_OK || (err == NSAPI_ERROR_DEVICE_ERROR &&
((AT_CellularSMS *)sms)->get_device_error().errCode == SIM_BUSY));
}
static void test_set_cscs()
{
TEST_ASSERT(sms->set_cscs("IRA") == NSAPI_ERROR_OK);
TEST_ASSERT(sms->set_cscs("UCS2") == NSAPI_ERROR_OK);
TEST_ASSERT(sms->set_cscs("GSM") == NSAPI_ERROR_OK);
nsapi_error_t err = sms->set_cscs("IRA");
TEST_ASSERT(err == NSAPI_ERROR_OK || (err == NSAPI_ERROR_DEVICE_ERROR &&
((AT_CellularSMS *)sms)->get_device_error().errCode == SIM_BUSY));
err = sms->set_cscs("UCS2");
TEST_ASSERT(err == NSAPI_ERROR_OK || (err == NSAPI_ERROR_DEVICE_ERROR &&
((AT_CellularSMS *)sms)->get_device_error().errCode == SIM_BUSY));
err = sms->set_cscs("GSM");
TEST_ASSERT(err == NSAPI_ERROR_OK || (err == NSAPI_ERROR_DEVICE_ERROR &&
((AT_CellularSMS *)sms)->get_device_error().errCode == SIM_BUSY));
}
static void test_set_csca()
{
TEST_ASSERT(sms->set_csca("55555", 129) == NSAPI_ERROR_OK);
TEST_ASSERT(sms->set_csca("+35855555", 145) == NSAPI_ERROR_OK);
TEST_ASSERT(sms->set_csca(service_center_address, service_address_type) == NSAPI_ERROR_OK);
nsapi_error_t err = sms->set_csca("55555", 129);
TEST_ASSERT(err == NSAPI_ERROR_OK || (err == NSAPI_ERROR_DEVICE_ERROR &&
((AT_CellularSMS *)sms)->get_device_error().errCode == SIM_BUSY));
err = sms->set_csca("+35855555", 145);
TEST_ASSERT(err == NSAPI_ERROR_OK || (err == NSAPI_ERROR_DEVICE_ERROR &&
((AT_CellularSMS *)sms)->get_device_error().errCode == SIM_BUSY));
err = sms->set_csca(service_center_address, service_address_type);
TEST_ASSERT(err == NSAPI_ERROR_OK || (err == NSAPI_ERROR_DEVICE_ERROR &&
((AT_CellularSMS *)sms)->get_device_error().errCode == SIM_BUSY));
}
static void test_set_cpms_me()
{
TEST_ASSERT(sms->set_cpms("ME", "ME", "ME") == NSAPI_ERROR_OK);
nsapi_error_t err = sms->set_cpms("ME", "ME", "ME");
TEST_ASSERT(err == NSAPI_ERROR_OK || (err == NSAPI_ERROR_DEVICE_ERROR &&
((AT_CellularSMS *)sms)->get_device_error().errCode == SIM_BUSY));
}
#ifdef MBED_CONF_APP_CELLULAR_PHONE_NUMBER
@ -224,7 +220,6 @@ static void test_set_extra_sim_wait_time_1000()
#endif
using namespace utest::v1;
static utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason)
@ -233,7 +228,6 @@ static utest::v1::status_t greentea_failure_handler(const Case *const source, co
return STATUS_ABORT;
}
static Case cases[] = {
Case("CellularSMS init", init, greentea_failure_handler),
Case("CellularSMS test ME for storage", test_set_cpms_me, greentea_failure_handler),
@ -256,9 +250,6 @@ static Case cases[] = {
#endif
};
static utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(600, "default_auto");

View File

@ -30,13 +30,17 @@
#error [NOT_SUPPORTED] SIM pin code is needed. Skipping this build.
#endif
#if defined(TARGET_ADV_WISE_1570) || defined(TARGET_MTB_ADV_WISE_1570)
#error [NOT_SUPPORTED] target MTB_ADV_WISE_1570 is too unstable for network tests, IoT network is unstable
#endif
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "mbed.h"
#include "CellularConnectionFSM.h"
#include "CellularContext.h"
#if MBED_CONF_CELLULAR_USE_APN_LOOKUP || MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP
#include "APN_db.h"
@ -48,13 +52,9 @@
#define SOCKET_TIMEOUT (30*1000)
#define ECHO_SERVER_NAME "echo.mbedcloudtesting.com"
#define ECHO_SERVER_UDP_PORT 7
static CellularConnectionFSM::CellularState cellular_target_state;
static UARTSerial cellular_serial(MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE);
static rtos::Semaphore network_semaphore(0);
static CellularConnectionFSM cellular;
#define ECHO_SERVER_UDP_PORT 8877
static CellularContext *ctx;
static SocketAddress echo_server_addr;
static rtos::EventFlags eventFlags;
@ -141,37 +141,20 @@ private:
bool _rx_pending;
};
static void network_callback(nsapi_event_t ev, intptr_t ptr)
{
if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE) {
if (ptr == NSAPI_STATUS_GLOBAL_UP) {
TEST_ASSERT(network_semaphore.release() == osOK);
}
}
}
static void udp_network_stack()
{
cellular.set_serial(&cellular_serial);
TEST_ASSERT(cellular.init() == NSAPI_ERROR_OK);
#if defined (MDMRTS) && defined (MDMCTS)
cellular_serial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS);
#endif
cellular.attach(&network_callback);
TEST_ASSERT(cellular.start_dispatch() == NSAPI_ERROR_OK);
cellular.set_sim_pin(MBED_CONF_APP_CELLULAR_SIM_PIN);
ctx = CellularContext::get_default_instance();
TEST_ASSERT(ctx != NULL);
ctx->set_sim_pin(MBED_CONF_APP_CELLULAR_SIM_PIN);
#ifdef MBED_CONF_APP_APN
CellularNetwork *network = cellular.get_network();
TEST_ASSERT(network->set_credentials(MBED_CONF_APP_APN, MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD) == NSAPI_ERROR_OK);
ctx->set_credentials(MBED_CONF_APP_APN, MBED_CONF_APP_USERNAME, MBED_CONF_APP_PASSWORD);
#endif
cellular_target_state = CellularConnectionFSM::STATE_CONNECTED;
TEST_ASSERT(cellular.continue_to_state(cellular_target_state) == NSAPI_ERROR_OK);
TEST_ASSERT(network_semaphore.wait(NETWORK_TIMEOUT) == 1);
TEST_ASSERT(ctx->connect() == NSAPI_ERROR_OK);
}
static void udp_gethostbyname()
{
TEST_ASSERT(cellular.get_network()->gethostbyname(ECHO_SERVER_NAME, &echo_server_addr) == 0);
TEST_ASSERT(ctx->gethostbyname(ECHO_SERVER_NAME, &echo_server_addr) == 0);
tr_info("Echo server IP: %s", echo_server_addr.get_ip_address());
echo_server_addr.set_port(7);
}
@ -179,7 +162,7 @@ static void udp_gethostbyname()
static void udp_socket_send_receive()
{
EchoSocket echo_socket(4);
TEST_ASSERT(echo_socket.open(cellular.get_network()) == NSAPI_ERROR_OK);
TEST_ASSERT(echo_socket.open(ctx) == NSAPI_ERROR_OK);
echo_socket.set_blocking(true);
echo_socket.set_timeout(SOCKET_TIMEOUT);
echo_socket.test_sendto();
@ -193,7 +176,7 @@ static void udp_socket_send_receive_async()
TEST_ASSERT(!(eventFlags.clear(async_flag) & osFlagsError));
EchoSocket echo_socket(4);
TEST_ASSERT(echo_socket.open(cellular.get_network()) == NSAPI_ERROR_OK);
TEST_ASSERT(echo_socket.open(ctx) == NSAPI_ERROR_OK);
echo_socket.set_async(async_flag);
echo_socket.test_sendto();
echo_socket.test_recvfrom();

View File

@ -24,6 +24,7 @@
},
"target_overrides": {
"*": {
"nsapi.dns-response-wait-time": 30000,
"ppp-cell-iface.apn-lookup": false,
"cellular.use-apn-lookup": false,
"target.features_add": ["LWIP"],

View File

@ -1,364 +0,0 @@
/*
* Copyright (c) 2017, 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 "CellularTargets.h"
#ifdef CELLULAR_DEVICE
#if NSAPI_PPP_AVAILABLE
#include "nsapi_ppp.h"
#endif
#include "CellularConnectionFSM.h"
#include "CellularDevice.h"
#include "EasyCellularConnection.h"
#include "CellularLog.h"
#include "mbed_wait_api.h"
#if USE_APN_LOOKUP
#include "APN_db.h"
#endif //USE_APN_LOOKUP
namespace mbed {
bool EasyCellularConnection::cellular_status(int state, int next_state)
{
tr_info("cellular_status: %s ==> %s", _cellularConnectionFSM->get_state_string((CellularConnectionFSM::CellularState)state),
_cellularConnectionFSM->get_state_string((CellularConnectionFSM::CellularState)next_state));
if (_target_state == state) {
tr_info("Target state reached: %s", _cellularConnectionFSM->get_state_string(_target_state));
(void)_cellularSemaphore.release();
return false; // return false -> state machine is halted
}
// only in case of an error or when connected is reached state and next_state can be the same.
// Release semaphore to return application instead of waiting for semaphore to complete.
if (state == next_state) {
tr_error("cellular_status: state and next_state are same, release semaphore as this is an error in state machine");
_stm_error = true;
(void)_cellularSemaphore.release();
return false; // return false -> state machine is halted
}
return true;
}
void EasyCellularConnection::network_callback(nsapi_event_t ev, intptr_t ptr)
{
if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE) {
if (ptr == NSAPI_STATUS_GLOBAL_UP) {
_is_connected = true;
} else {
_is_connected = false;
}
}
if (_status_cb) {
_status_cb(ev, ptr);
}
}
EasyCellularConnection::EasyCellularConnection(bool debug) :
_is_connected(false), _is_initialized(false), _stm_error(false),
_target_state(CellularConnectionFSM::STATE_POWER_ON),
_cellularSerial(MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE), _cellularSemaphore(0),
_cellularConnectionFSM(0), _credentials_err(NSAPI_ERROR_OK), _status_cb(0)
{
tr_info("EasyCellularConnection()");
#if USE_APN_LOOKUP
_credentials_set = false;
#endif // #if USE_APN_LOOKUP
modem_debug_on(debug);
}
EasyCellularConnection::~EasyCellularConnection()
{
if (_cellularConnectionFSM) {
_cellularConnectionFSM->set_callback(NULL);
_cellularConnectionFSM->attach(NULL);
delete _cellularConnectionFSM;
}
}
nsapi_error_t EasyCellularConnection::init()
{
nsapi_error_t err = NSAPI_ERROR_OK;
_stm_error = false;
if (!_is_initialized) {
#if defined (MDMRTS) && defined (MDMCTS)
_cellularSerial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS);
#endif
_cellularConnectionFSM = new CellularConnectionFSM();
_cellularConnectionFSM->set_serial(&_cellularSerial);
_cellularConnectionFSM->set_callback(callback(this, &EasyCellularConnection::cellular_status));
err = _cellularConnectionFSM->init();
if (err == NSAPI_ERROR_OK) {
err = _cellularConnectionFSM->start_dispatch();
_cellularConnectionFSM->attach(callback(this, &EasyCellularConnection::network_callback));
}
_is_initialized = true;
}
return err;
}
void EasyCellularConnection::set_credentials(const char *apn, const char *uname, const char *pwd)
{
if (apn && strlen(apn) > 0) {
_credentials_err = init();
if (_credentials_err) {
return;
}
CellularNetwork *network = _cellularConnectionFSM->get_network();
if (network) {
_credentials_err = network->set_credentials(apn, uname, pwd);
#if USE_APN_LOOKUP
if (_credentials_err == NSAPI_ERROR_OK) {
_credentials_set = true;
}
#endif // #if USE_APN_LOOKUP
} else {
//if get_network() returns NULL it means there was not enough memory for
//an AT_CellularNetwork element during CellularConnectionFSM initialization
tr_error("There was not enough memory during CellularConnectionFSM initialization");
}
}
}
void EasyCellularConnection::set_sim_pin(const char *sim_pin)
{
if (sim_pin && strlen(sim_pin) > 0) {
if (!_cellularConnectionFSM) {
_credentials_err = init();
if (_credentials_err) {
return;
}
}
_cellularConnectionFSM->set_sim_pin(sim_pin);
}
}
nsapi_error_t EasyCellularConnection::connect(const char *sim_pin, const char *apn, const char *uname, const char *pwd)
{
if (_is_connected) {
return NSAPI_ERROR_IS_CONNECTED;
}
set_credentials(apn, uname, pwd);
if (_credentials_err) {
return _credentials_err;
}
if (sim_pin) {
set_sim_pin(sim_pin);
}
return connect();
}
nsapi_error_t EasyCellularConnection::check_connect()
{
if (_is_connected) {
return NSAPI_ERROR_IS_CONNECTED;
}
// there was an error while setting credentials but it's a void function so check error here...
if (_credentials_err) {
return _credentials_err;
}
nsapi_error_t err = init();
if (err) {
return err;
}
return NSAPI_ERROR_OK;
}
nsapi_error_t EasyCellularConnection::connect()
{
nsapi_error_t err = check_connect();
if (err) {
return err;
}
#if USE_APN_LOOKUP
if (!_credentials_set) {
_target_state = CellularConnectionFSM::STATE_SIM_PIN;
err = _cellularConnectionFSM->continue_to_state(_target_state);
if (err == NSAPI_ERROR_OK) {
int sim_wait = _cellularSemaphore.wait(60 * 1000); // reserve 60 seconds to access to SIM
if (sim_wait != 1 || _stm_error) {
tr_error("NO SIM ACCESS");
err = NSAPI_ERROR_NO_CONNECTION;
} else {
char imsi[MAX_IMSI_LENGTH + 1];
wait(1); // need to wait to access SIM in some modems
err = _cellularConnectionFSM->get_sim()->get_imsi(imsi);
if (err == NSAPI_ERROR_OK) {
const char *apn_config = apnconfig(imsi);
if (apn_config) {
const char *apn = _APN_GET(apn_config);
const char *uname = _APN_GET(apn_config);
const char *pwd = _APN_GET(apn_config);
tr_info("Looked up APN %s", apn);
err = _cellularConnectionFSM->get_network()->set_credentials(apn, uname, pwd);
}
}
}
}
if (err) {
tr_error("APN lookup failed");
return err;
}
}
#endif // USE_APN_LOOKUP
_target_state = CellularConnectionFSM::STATE_CONNECTED;
err = _cellularConnectionFSM->continue_to_state(_target_state);
if (err == NSAPI_ERROR_OK) {
int ret_wait = _cellularSemaphore.wait(10 * 60 * 1000); // cellular network searching may take several minutes
if (ret_wait != 1 || _stm_error) {
tr_info("No cellular connection");
err = NSAPI_ERROR_NO_CONNECTION;
}
}
return err;
}
nsapi_error_t EasyCellularConnection::disconnect()
{
_credentials_err = NSAPI_ERROR_OK;
_is_connected = false;
_is_initialized = false;
_stm_error = false;
#if USE_APN_LOOKUP
_credentials_set = false;
#endif // #if USE_APN_LOOKUP
nsapi_error_t err = NSAPI_ERROR_OK;
if (_cellularConnectionFSM && _cellularConnectionFSM->get_network()) {
err = _cellularConnectionFSM->get_network()->disconnect();
}
if (err == NSAPI_ERROR_OK) {
delete _cellularConnectionFSM;
_cellularConnectionFSM = NULL;
}
return err;
}
bool EasyCellularConnection::is_connected()
{
return _is_connected;
}
const char *EasyCellularConnection::get_ip_address()
{
if (_cellularConnectionFSM) {
CellularNetwork *network = _cellularConnectionFSM->get_network();
if (!network) {
return NULL;
}
return _cellularConnectionFSM->get_network()->get_ip_address();
} else {
return NULL;
}
}
const char *EasyCellularConnection::get_netmask()
{
if (_cellularConnectionFSM) {
CellularNetwork *network = _cellularConnectionFSM->get_network();
if (!network) {
return NULL;
}
return network->get_netmask();
} else {
return NULL;
}
}
const char *EasyCellularConnection::get_gateway()
{
if (_cellularConnectionFSM) {
CellularNetwork *network = _cellularConnectionFSM->get_network();
if (!network) {
return NULL;
}
return network->get_gateway();
} else {
return NULL;
}
}
void EasyCellularConnection::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
{
_status_cb = status_cb;
}
void EasyCellularConnection::modem_debug_on(bool on)
{
if (_cellularConnectionFSM) {
CellularDevice *dev = _cellularConnectionFSM->get_device();
if (dev) {
dev->modem_debug_on(on);
}
}
}
void EasyCellularConnection::set_plmn(const char *plmn)
{
if (plmn && strlen(plmn) > 0) {
if (!_cellularConnectionFSM) {
_credentials_err = init();
if (_credentials_err) {
return;
}
}
_cellularConnectionFSM->set_plmn(plmn);
}
}
NetworkStack *EasyCellularConnection::get_stack()
{
if (_cellularConnectionFSM) {
return _cellularConnectionFSM->get_stack();
} else {
return NULL;
}
}
CellularDevice *EasyCellularConnection::get_device()
{
return _cellularConnectionFSM->get_device();
}
UARTSerial *EasyCellularConnection::get_serial()
{
return &_cellularSerial;
}
} // namespace
#endif // CELLULAR_DEVICE

View File

@ -1,190 +0,0 @@
/*
* Copyright (c) 2017, 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.
*/
#ifndef EASY_CELLULAR_CONNECTION_H
#define EASY_CELLULAR_CONNECTION_H
#include "CellularConnectionFSM.h"
#if defined(CELLULAR_DEVICE) || defined(DOXYGEN_ONLY)
#include "netsocket/CellularBase.h"
#define USE_APN_LOOKUP (MBED_CONF_CELLULAR_USE_APN_LOOKUP || (NSAPI_PPP_AVAILABLE && MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP))
namespace mbed {
/** EasyCellularConnection class
*
* Simplified adapter for cellular connection
*/
class EasyCellularConnection: public CellularBase {
public:
EasyCellularConnection(bool debug = false);
virtual ~EasyCellularConnection();
public:
/** Set the Cellular network credentials
*
* Please check documentation of connect() for default behaviour of APN settings.
*
* @param apn Access point name
* @param uname optionally, Username
* @param pwd optionally, password
*/
virtual void set_credentials(const char *apn, const char *uname = 0,
const char *pwd = 0);
/** Set the pin code for SIM card
*
* @param sim_pin PIN for the SIM card
*/
virtual void set_sim_pin(const char *sim_pin);
/** Start the interface
*
* Attempts to connect to a Cellular network.
*
* @param sim_pin PIN for the SIM card
* @param apn optionally, access point name
* @param uname optionally, Username
* @param pwd optionally, password
* @return NSAPI_ERROR_OK on success, or negative error code on failure
*/
virtual nsapi_error_t connect(const char *sim_pin, const char *apn = 0,
const char *uname = 0,
const char *pwd = 0);
/** Start the interface
*
* Attempts to connect to a Cellular network.
* If the SIM requires a PIN, and it is not set/invalid, NSAPI_ERROR_AUTH_ERROR is returned.
*
* @return NSAPI_ERROR_OK on success, or negative error code on failure
*/
virtual nsapi_error_t connect();
/** Stop the interface
*
* @return 0 on success, or error code on failure
*/
virtual nsapi_error_t disconnect();
/** Check if the connection is currently established or not
*
* @return true/false If the cellular module have successfully acquired a carrier and is
* connected to an external packet data network using PPP, isConnected()
* API returns true and false otherwise.
*/
virtual bool is_connected();
/** Get the local IP address
*
* @return Null-terminated representation of the local IP address
* or null if no IP address has been received
*/
virtual const char *get_ip_address();
/** Get the local network mask
*
* @return Null-terminated representation of the local network mask
* or null if no network mask has been received
*/
virtual const char *get_netmask();
/** Get the local gateways
*
* @return Null-terminated representation of the local gateway
* or null if no network mask has been received
*/
virtual const char *get_gateway();
/** Register callback for status reporting
*
* The specified status callback function will be called on status changes
* on the network. The parameters on the callback are the event type and
* event-type dependent reason parameter.
*
* @param status_cb The callback for status changes
*/
virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
/** Turn modem debug traces on
*
* @param on set true to enable debug traces
*/
void modem_debug_on(bool on);
/** Sets the operator plmn which is used when registering to a network specified by plmn. If plmn is not set then automatic
* registering is used when registering to a cellular network.
*
* @param plmn operator in numeric format. See more from 3GPP TS 27.007 chapter 7.3.
*/
void set_plmn(const char *plmn);
/** Get the cellular device from the cellular state machine
*
* @return cellular device
*/
CellularDevice *get_device();
/** Get the UART serial file handle used by cellular subsystem
*
* @return address of cellular UART serial
*/
UARTSerial *get_serial();
protected:
/** Provide access to the NetworkStack object
*
* @return The underlying NetworkStack object
*/
virtual NetworkStack *get_stack();
private:
/** Callback for cellular status changes
*
* @return true to continue state machine
*/
bool cellular_status(int state, int next_state);
void network_callback(nsapi_event_t ev, intptr_t ptr);
nsapi_error_t init();
nsapi_error_t check_connect();
bool _is_connected;
bool _is_initialized;
bool _stm_error;
#if USE_APN_LOOKUP
bool _credentials_set;
#endif // #if USE_APN_LOOKUP
CellularConnectionFSM::CellularState _target_state;
UARTSerial _cellularSerial;
rtos::Semaphore _cellularSemaphore;
CellularConnectionFSM *_cellularConnectionFSM;
nsapi_error_t _credentials_err;
Callback<void(nsapi_event_t, intptr_t)> _status_cb;
};
} // namespace
#endif // CELLULAR_DEVICE || DOXYGEN
#endif // EASY_CELLULAR_CONNECTION_H
/** @}*/

View File

@ -0,0 +1,252 @@
/*
* 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.
*/
#ifndef _CELLULARCONTEXT_H_
#define _CELLULARCONTEXT_H_
#include "CellularBase.h"
#include "CellularDevice.h"
namespace mbed {
class CellularContext : public CellularBase {
public:
// max simultaneous PDP contexts active
static const int PDP_CONTEXT_COUNT = 4;
/* authentication type when activating or modifying the pdp context */
enum AuthenticationType {
NOAUTH = 0,
PAP,
CHAP
};
/* whether the additional exception reports are allowed to be sent when the maximum uplink rate is reached */
enum RateControlExceptionReports {
NotAllowedToBeSent = 0,
AllowedToBeSent
};
/* specifies the time unit to be used for the maximum uplink rate */
enum RateControlUplinkTimeUnit {
Unrestricted = 0,
Minute,
Hour,
Day,
Week
};
/* PDP Context information */
struct pdpcontext_params_t {
char apn[MAX_ACCESSPOINT_NAME_LENGTH + 1];
char local_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char local_subnet_mask[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char gateway_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char dns_primary_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char dns_secondary_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char p_cscf_prim_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char p_cscf_sec_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
int cid;
int bearer_id;
int im_signalling_flag;
int lipa_indication;
int ipv4_mtu;
int wlan_offload;
int local_addr_ind;
int non_ip_mtu;
int serving_plmn_rate_control_value;
pdpcontext_params_t *next;
pdpcontext_params_t()
{
apn[0] = '\0';
local_addr[0] = '\0';
local_subnet_mask[0] = '\0';
gateway_addr[0] = '\0';
dns_primary_addr[0] = '\0';
dns_secondary_addr[0] = '\0';
p_cscf_prim_addr[0] = '\0';
p_cscf_sec_addr[0] = '\0';
cid = -1;
bearer_id = -1;
im_signalling_flag = -1;
lipa_indication = -1;
ipv4_mtu = -1;
wlan_offload = -1;
local_addr_ind = -1;
non_ip_mtu = -1;
serving_plmn_rate_control_value = -1;
next = NULL;
}
};
typedef CellularList<pdpcontext_params_t> pdpContextList_t;
// pointer for next item when used as a linked list
CellularContext *_next;
protected:
// friend of CellularDevice so that it's the only way to close/delete this class.
friend class CellularDevice;
virtual ~CellularContext() {}
public: // from NetworkInterface
virtual nsapi_error_t set_blocking(bool blocking) = 0;
virtual NetworkStack *get_stack() = 0;
virtual const char *get_ip_address() = 0;
virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb) = 0;
virtual nsapi_error_t connect() = 0;
virtual nsapi_error_t disconnect() = 0;
// from CellularBase
virtual void set_plmn(const char *plmn) = 0;
virtual void set_sim_pin(const char *sim_pin) = 0;
virtual nsapi_error_t connect(const char *sim_pin, const char *apn = 0, const char *uname = 0,
const char *pwd = 0) = 0;
virtual void set_credentials(const char *apn, const char *uname = 0, const char *pwd = 0) = 0;
virtual const char *get_netmask() = 0;
virtual const char *get_gateway() = 0;
virtual bool is_connected() = 0;
static CellularContext *get_default_instance();
// Operations, can be sync/async. Also Connect() is this kind of operations, inherited from NetworkInterface above.
/** Start the interface
*
* Power on the device and does the initializations for communication with the modem..
* By default this API is synchronous. API can be set to asynchronous with method set_blocking(...).
* In synchronous and asynchronous mode application can get result in from callback which is set with
* attach(...)
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on case of memory failure
*/
virtual nsapi_error_t set_device_ready() = 0;
/** Start the interface
*
* Attempts to open the sim.
* By default this API is synchronous. API can be set to asynchronous with method set_blocking(...).
* In synchronous and asynchronous mode application can get result in from callback which is set with
* attach(...)
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on case of memory failure
*/
virtual nsapi_error_t set_sim_ready() = 0;
/** Start the interface
*
* Attempts to register the device to cellular network.
* By default this API is synchronous. API can be set to asynchronous with method set_blocking(...).
* In synchronous and asynchronous mode application can get result in from callback which is set with
* attach(...)
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on case of memory failure
*/
virtual nsapi_error_t register_to_network() = 0;
/** Start the interface
*
* Attempts to attach the device to cellular network.
* By default this API is synchronous. API can be set to asynchronous with method set_blocking(...).
* In synchronous and asynchronous mode application can get result in from callback which is set with
* attach(...)
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on case of memory failure
*/
virtual nsapi_error_t attach_to_network() = 0;
// PDP Context specific functions
/** Get APN rate control.
*
* @remark optional params are not updated if not received from network, so use good defaults
* @param reports Additional exception reports at maximum rate reached are allowed to be sent [optional]
* @param time_unit Uplink time unit with values 0=unrestricted, 1=minute, 2=hour, 3=day, 4=week [optional]
* @param uplink_rate Maximum number of messages per timeUnit [optional]
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_DEVICE_ERROR on case of failure
*/
virtual nsapi_error_t get_rate_control(CellularContext::RateControlExceptionReports &reports,
CellularContext::RateControlUplinkTimeUnit &time_unit, int &uplink_rate) = 0;
/** Get the relevant information for an active non secondary PDP context.
*
* @remark optional params are not updated if not received from network.
* @param params_list reference to linked list, which is filled on successful call
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on memory failure
* NSAPI_ERROR_DEVICE_ERROR on other failures
*/
virtual nsapi_error_t get_pdpcontext_params(pdpContextList_t &params_list) = 0;
/** Get backoff timer value
*
* @param backoff_timer Backoff timer value associated with PDP APN in seconds
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_PARAMETER if no access point is set or found when activating context
* NSAPI_ERROR_DEVICE_ERROR on failure
*/
virtual nsapi_error_t get_apn_backoff_timer(int &backoff_timer) = 0;
/** Set the file handle used to communicate with the modem. Can be used to change default file handle.
*
* @param fh file handle for communicating with the modem
*/
virtual void set_file_handle(FileHandle *fh) = 0;
protected: // Device specific implementations might need these so protected
enum ContextOperation {
OP_INVALID = -1,
OP_DEVICE_READY = 0,
OP_SIM_READY = 1,
OP_REGISTER = 2,
OP_ATTACH = 3,
OP_CONNECT = 4,
OP_MAX = 5
};
/** Status callback function will be called on status changes on the network or CellularDevice
* by the CellularDevice.
*
* @param ev event type
* @param ptr event-type dependent reason parameter
*/
virtual void cellular_callback(nsapi_event_t ev, intptr_t ptr) = 0;
// member variables needed in target override methods
NetworkStack *_stack; // must be pointer because of PPP
nsapi_ip_stack_t _ip_stack_type;
CellularContext::AuthenticationType _authentication_type;
nsapi_connection_status_t _connect_status;
cell_callback_data_t _cb_data;
Callback<void(nsapi_event_t, intptr_t)> _status_cb;
int _cid;
bool _new_context_set;
bool _is_context_active;
bool _is_context_activated; // did we activate the context
const char *_apn;
const char *_uname;
const char *_pwd;
};
} // namespace mbed
#endif /* _CELLULARCONTEXT_H_ */

View File

@ -19,11 +19,7 @@
#define CELLULAR_DEVICE_H_
#include "CellularTargets.h"
#include "EventQueue.h"
#include "nsapi_types.h"
#include "PlatformMutex.h"
class NetworkStack;
#include "CellularStateMachine.h"
namespace mbed {
@ -32,8 +28,12 @@ class CellularSMS;
class CellularSIM;
class CellularInformation;
class CellularNetwork;
class CellularContext;
class FileHandle;
const int MAX_PIN_SIZE = 8;
const int MAX_PLMN_SIZE = 16;
/**
* Class CellularDevice
*
@ -50,55 +50,144 @@ public:
*/
static CellularDevice *get_default_instance();
/** Get event queue that can be chained to main event queue. EventQueue is created in get_default_instance() or
* given to CELLULAR_DEVICE (for example TELIT_HE910 class).
* @return event queue
*/
virtual events::EventQueue *get_queue() const;
/** Default constructor
*
* @param fh File handle used in communication with the modem.
*/
CellularDevice();
CellularDevice(FileHandle *fh);
/** virtual Destructor
*/
virtual ~CellularDevice() {}
virtual ~CellularDevice();
/** Creates a new CellularContext interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle. If null then the default
* file handle is used.
* @param apn access point to use with context, can be null.
*
* @return new instance of class CellularContext or NULL in case of failure
*
*/
virtual CellularContext *create_context(FileHandle *fh = NULL, const char *apn = NULL) = 0;
/** Deletes the given CellularContext instance
*
* @param context CellularContext to delete
*/
virtual void delete_context(CellularContext *context) = 0;
/** Stop the current operation. Operations: set_device_ready, set_sim_ready, register_to_network, attach_to_network
*
*/
void stop();
/** Get event queue that can be chained to main event queue.
* @return event queue
*/
virtual events::EventQueue *get_queue();
/** Set the pin code for SIM card
*
* @param sim_pin PIN for the SIM card
*/
void set_sim_pin(const char *sim_pin);
/** Plmn to use when registering to cellular network.
* If plmn is set then registering is forced to this plmn. If plmn is not set then automatic
* registering is used when registering to a cellular network. Does not start any operations.
*
* @param plmn plmn used when registering to cellular network
*/
void set_plmn(const char *plmn);
/** Start the interface
*
* Power on the device and does the initializations for communication with the modem..
* By default this API is synchronous. API can be set to asynchronous with method set_blocking(...).
* In synchronous and asynchronous mode application can get result in from callback which is set with
* attach(...)
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on case of memory failure
*/
nsapi_error_t set_device_ready();
/** Start the interface
*
* Attempts to open the sim.
* By default this API is synchronous. API can be set to asynchronous with method set_blocking(...).
* In synchronous and asynchronous mode application can get result in from callback which is set with
* attach(...)
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on case of memory failure
*/
nsapi_error_t set_sim_ready();
/** Start the interface
*
* Attempts to register the device to cellular network.
* By default this API is synchronous. API can be set to asynchronous with method set_blocking(...).
* In synchronous and asynchronous mode application can get result in from callback which is set with
* attach(...)
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on case of memory failure
*/
nsapi_error_t register_to_network();
/** Start the interface
*
* Attempts to attach the device to cellular network.
* By default this API is synchronous. API can be set to asynchronous with method set_blocking(...).
* In synchronous and asynchronous mode application can get result in from callback which is set with
* attach(...)
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on case of memory failure
*/
nsapi_error_t attach_to_network();
public:
/** Create new CellularNetwork interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle.
* @param fh file handle used in communication to modem. Can be for example UART handle. If null then the default
* file handle is used.
* @return New instance of interface CellularNetwork.
*/
virtual CellularNetwork *open_network(FileHandle *fh) = 0;
virtual CellularNetwork *open_network(FileHandle *fh = NULL) = 0;
/** Create new CellularSMS interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle.
* @param fh file handle used in communication to modem. Can be for example UART handle. If null then the default
* file handle is used.
* @return New instance of interface CellularSMS.
*/
virtual CellularSMS *open_sms(FileHandle *fh) = 0;
virtual CellularSMS *open_sms(FileHandle *fh = NULL) = 0;
/** Create new CellularPower interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle.
* @param fh file handle used in communication to modem. Can be for example UART handle. If null then the default
* file handle is used.
* @return New instance of interface CellularPower.
*/
virtual CellularPower *open_power(FileHandle *fh) = 0;
virtual CellularPower *open_power(FileHandle *fh = NULL) = 0;
/** Create new CellularSIM interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle.
* @param fh file handle used in communication to modem. Can be for example UART handle. If null then the default
* file handle is used.
* @return New instance of interface CellularSIM.
*/
virtual CellularSIM *open_sim(FileHandle *fh) = 0;
virtual CellularSIM *open_sim(FileHandle *fh = NULL) = 0;
/** Create new CellularInformation interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle.
* @param fh file handle used in communication to modem. Can be for example UART handle. If null then the default
* file handle is used.
* @return New instance of interface CellularInformation.
*/
virtual CellularInformation *open_information(FileHandle *fh) = 0;
virtual CellularInformation *open_information(FileHandle *fh = NULL) = 0;
/** Closes the opened CellularNetwork by deleting the CellularNetwork instance.
*/
@ -132,28 +221,47 @@ public:
*/
virtual void modem_debug_on(bool on) = 0;
/** Get network stack.
*
* @return network stack
*/
virtual NetworkStack *get_stack() = 0;
/** Initialize cellular module must be called right after module is ready.
* For example, when multiple modules are supported in a single AT driver this function detects
* and adapts to an actual module at runtime.
*
* @param fh file handle used in communication to modem.
*
* @return 0 on success
*/
virtual nsapi_error_t init_module(FileHandle *fh) = 0;
virtual nsapi_error_t init_module() = 0;
/** Get the linked list of CellularContext instances
*
* @return Pointer to first item in linked list
*/
virtual CellularContext *get_context_list() const;
protected:
friend class AT_CellularNetwork;
friend class AT_CellularContext;
/** Cellular callback to be attached to Network and CellularStateMachine classes.
* CellularContext calls this when in PPP mode to provide network changes.
* This method will broadcast to every interested classes:
* CellularContext (might be many) and CellularStateMachine if available.
*/
void cellular_callback(nsapi_event_t ev, intptr_t ptr);
int _network_ref_count;
int _sms_ref_count;
int _power_ref_count;
int _sim_ref_count;
int _info_ref_count;
FileHandle *_fh;
events::EventQueue _queue;
CellularStateMachine *_state_machine;
private:
nsapi_error_t start_state_machine(CellularStateMachine::CellularState target_state);
nsapi_error_t create_state_machine();
CellularNetwork *_nw;
char _sim_pin[MAX_PIN_SIZE + 1];
char _plmn[MAX_PLMN_SIZE + 1];
PlatformMutex _mutex;
};
} // namespace mbed

View File

@ -18,8 +18,9 @@
#ifndef CELLULAR_NETWORK_H_
#define CELLULAR_NETWORK_H_
#include "NetworkInterface.h"
#include "CellularList.h"
#include "Callback.h"
#include "nsapi_types.h"
namespace mbed {
@ -35,7 +36,7 @@ const int MAX_OPERATOR_NAME_SHORT = 8;
*
* An abstract interface for connecting to a network and getting information from it.
*/
class CellularNetwork : public NetworkInterface {
class CellularNetwork {
protected:
// friend of CellularDevice so that it's the only way to close/delete this class.
friend class CellularDevice;
@ -77,7 +78,8 @@ public:
RegisteredSMSOnlyRoaming,
AttachedEmergencyOnly,
RegisteredCSFBNotPreferredHome,
RegisteredCSFBNotPreferredRoaming = 10
RegisteredCSFBNotPreferredRoaming,
AlreadyRegistered = 11 // our our definition when modem says that we are not registered but we have active PDP Context
};
/* Network registration type */
@ -94,28 +96,6 @@ public:
Attached,
};
/* whether the additional exception reports are allowed to be sent when the maximum uplink rate is reached */
enum RateControlExceptionReports {
NotAllowedToBeSent = 0,
AllowedToBeSent
};
/* specifies the time unit to be used for the maximum uplink rate */
enum RateControlUplinkTimeUnit {
Unrestricted = 0,
Minute,
Hour,
Day,
Week
};
/* authentication type when activating or modifying the pdp context */
enum AuthenticationType {
NOAUTH = 0,
PAP,
CHAP
};
enum RadioAccessTechnology {
RAT_GSM,
RAT_GSM_COMPACT,
@ -159,51 +139,6 @@ public:
typedef CellularList<operator_t> operList_t;
/* PDP Context information */
struct pdpcontext_params_t {
char apn[MAX_ACCESSPOINT_NAME_LENGTH + 1];
char local_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char local_subnet_mask[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char gateway_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char dns_primary_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char dns_secondary_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char p_cscf_prim_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
char p_cscf_sec_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT + 1];
int cid;
int bearer_id;
int im_signalling_flag;
int lipa_indication;
int ipv4_mtu;
int wlan_offload;
int local_addr_ind;
int non_ip_mtu;
int serving_plmn_rate_control_value;
pdpcontext_params_t *next;
pdpcontext_params_t()
{
apn[0] = '\0';
local_addr[0] = '\0';
local_subnet_mask[0] = '\0';
gateway_addr[0] = '\0';
dns_primary_addr[0] = '\0';
dns_secondary_addr[0] = '\0';
p_cscf_prim_addr[0] = '\0';
p_cscf_sec_addr[0] = '\0';
cid = -1;
bearer_id = -1;
im_signalling_flag = -1;
lipa_indication = -1;
ipv4_mtu = -1;
wlan_offload = -1;
local_addr_ind = -1;
non_ip_mtu = -1;
serving_plmn_rate_control_value = -1;
next = NULL;
}
};
typedef CellularList<pdpcontext_params_t> pdpContextList_t;
struct operator_names_t {
char numeric[MAX_OPERATOR_NAME_SHORT + 1];
char alpha[MAX_OPERATOR_NAME_LONG + 1];
@ -248,14 +183,6 @@ public:
}
};
/** Does all the needed initializations that can fail
*
* @remark must be called immediately after constructor.
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on memory failure
*/
virtual nsapi_error_t init() = 0;
/** Request registering to network.
*
* @param plmn format is in numeric format or 0 for automatic network registration
@ -286,38 +213,12 @@ public:
virtual nsapi_error_t set_registration_urc(RegistrationType type, bool on) = 0;
/** Set the cellular network APN and credentials
*
* @param apn Optional name of the network to connect to
* @param username Optional username for the APN
* @param password Optional password fot the APN
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on memory failure
*/
virtual nsapi_error_t set_credentials(const char *apn,
const char *username = 0, const char *password = 0) = 0;
/** Set the cellular network APN and credentials
*
* @param apn Name of the network to connect to
* @param type Authentication type to use
* @param username Optional username for the APN
* @param password Optional password fot the APN
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on memory failure
*/
virtual nsapi_error_t set_credentials(const char *apn, AuthenticationType type,
const char *username = 0, const char *password = 0) = 0;
/** Request attach to network.
*
* @deprecated Parameter timeout will be deprecated. Use mbed-os/features/cellular/framework/API/CellularDevice.h set_timeout instead.
* @param timeout milliseconds to wait for attach response
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_DEVICE_ERROR on failure
*/
MBED_DEPRECATED_SINCE("mbed-os-5.9", "Parameter timeout will be deprecated. Use mbed-os/features/cellular/framework/API/CellularDevice.h set_timeout instead.")
virtual nsapi_error_t set_attach(int timeout = 10 * 1000) = 0;
virtual nsapi_error_t set_attach() = 0;
/** Request attach status from network.
*
@ -334,27 +235,6 @@ public:
*/
virtual nsapi_error_t detach() = 0;
/** Get APN rate control.
*
* @remark optional params are not updated if not received from network, so use good defaults
* @param reports Additional exception reports at maximum rate reached are allowed to be sent [optional]
* @param time_unit Uplink time unit with values 0=unrestricted, 1=minute, 2=hour, 3=day, 4=week [optional]
* @param uplink_rate Maximum number of messages per timeUnit [optional]
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_DEVICE_ERROR on case of failure
*/
virtual nsapi_error_t get_rate_control(CellularNetwork::RateControlExceptionReports &reports,
CellularNetwork::RateControlUplinkTimeUnit &time_unit, int &uplink_rate) = 0;
/** Get backoff timer value
*
* @param backoff_timer Backoff timer value associated with PDP APN in seconds
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_PARAMETER if no access point is set or found when activating context
* NSAPI_ERROR_DEVICE_ERROR on failure
*/
virtual nsapi_error_t get_apn_backoff_timer(int &backoff_timer) = 0;
/** Sets radio access technology.
*
* @param rat Radio access technology
@ -395,70 +275,6 @@ public:
virtual nsapi_error_t get_ciot_optimization_config(Supported_UE_Opt &supported_opt,
Preferred_UE_Opt &preferred_opt) = 0;
/** Start the interface. Attempts to connect to a cellular network.
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_CONNECTION if fails to find suitable context to activate or activation failed (if not already activated)
* NSAPI_ERROR_UNSUPPORTED if NetworkStack was not found or cellular device does not support authentication
* NSAPI_ERROR_AUTH_FAILURE if password and username were provided and authentication to network failed
* Also if PPP mode
* NSAPI_ERROR_DEVICE_ERROR on failure and check more error from nsapi_ppp_connect(...)
*/
virtual nsapi_error_t connect() = 0;
/** Start the interface. Attempts to connect to a cellular network.
*
* @param apn Optional name of the network to connect to
* @param username Optional username for your APN
* @param password Optional password for your APN
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_CONNECTION if fails to find suitable context to activate or activation failed (if not already activated)
* NSAPI_ERROR_UNSUPPORTED if NetworkStack was not found
* NSAPI_ERROR_AUTH_FAILURE if password and username were provided and authentication to network failed
* NSAPI_ERROR_NO_MEMORY on memory failure
* Also if PPP mode
* NSAPI_ERROR_DEVICE_ERROR on failure and check more error from nsapi_ppp_connect(...)
*/
virtual nsapi_error_t connect(const char *apn,
const char *username = 0, const char *password = 0) = 0;
/** Finds the correct PDP context and activates it. If correct PDP context is not found, one is created.
* Given APN (or not given) and stack type (IPv4/IPv6/dual) are influencing when finding the PDP context.
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_CONNECTION if fails to find suitable context to activate or activation failed (if not already activated)
* NSAPI_ERROR_UNSUPPORTED if NetworkStack was not found
* NSAPI_ERROR_AUTH_FAILURE if password and username were provided and authentication to network failed
*/
virtual nsapi_error_t activate_context() = 0;
/**
* Set the pdn type to be used
*
* @param stack_type the stack type to be used.
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_PARAMETER if modem does not support the given stack_type
*/
virtual nsapi_error_t set_stack_type(nsapi_ip_stack_t stack_type) = 0;
/**
* Get the pdn type in use
*
* @return stack type
*/
virtual nsapi_ip_stack_t get_stack_type() = 0;
/** Get the relevant information for an active non secondary PDP context.
*
* @remark optional params are not updated if not received from network.
* @param params_list reference to linked list, which is filled on successful call
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_NO_MEMORY on memory failure
* NSAPI_ERROR_DEVICE_ERROR on other failures
*/
virtual nsapi_error_t get_pdpcontext_params(pdpContextList_t &params_list) = 0;
/** Get extended signal quality parameters.
*
* @param rxlev signal strength level
@ -511,14 +327,6 @@ public:
*/
virtual nsapi_connection_status_t get_connection_status() const = 0;
/** Set blocking status of connect() which by default should be blocking
*
* @param blocking true if connect is blocking
* @return NSAPI_ERROR_OK
* if PPP mode check errors from nsapi_ppp_set_blocking(...)
*/
virtual nsapi_error_t set_blocking(bool blocking) = 0;
/** Read operator names
*
* @param op_names on successful return contains linked list of operator names.
@ -528,6 +336,12 @@ public:
*/
virtual nsapi_error_t get_operator_names(operator_names_list &op_names) = 0;
/** Check if there is any PDP context active
*
* @return true is any context is active, false otherwise or in case of error
*/
virtual bool is_active_context() = 0;
/** Gets current network registration parameters:
* type, status, access technology, cell_id, lac, active_time, periodic_tau.
*

View File

@ -0,0 +1,911 @@
/*
* 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 "AT_CellularContext.h"
#include "AT_CellularNetwork.h"
#include "AT_CellularStack.h"
#include "CellularLog.h"
#include "CellularUtil.h"
#include "CellularSIM.h"
#include "UARTSerial.h"
#include "mbed_wait_api.h"
#define NETWORK_TIMEOUT 30 * 60 * 1000 // 30 minutes
#define DEVICE_TIMEOUT 5 * 60 * 1000 // 5 minutes
#if NSAPI_PPP_AVAILABLE
#include "nsapi_ppp.h"
#endif
#define USE_APN_LOOKUP (MBED_CONF_CELLULAR_USE_APN_LOOKUP || (NSAPI_PPP_AVAILABLE && MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP))
#if USE_APN_LOOKUP
#include "APN_db.h"
#endif //USE_APN_LOOKUP
using namespace mbed_cellular_util;
using namespace mbed;
AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
AT_CellularBase(at), _ip_stack_type_requested(DEFAULT_STACK), _is_connected(false), _is_blocking(true),
_current_op(OP_INVALID), _device(device), _nw(0), _fh(0)
{
tr_debug("AT_CellularContext::AT_CellularContext(): apn: %s", apn);
_stack = NULL;
_ip_stack_type = DEFAULT_STACK;
_authentication_type = CellularContext::CHAP;
_connect_status = NSAPI_STATUS_DISCONNECTED;
_is_context_active = false;
_is_context_activated = false;
_apn = apn;
_uname = NULL;
_pwd = NULL;
_status_cb = NULL;
_cid = -1;
_new_context_set = false;
_next = NULL;
}
AT_CellularContext::~AT_CellularContext()
{
(void)disconnect();
if (_nw) {
_device->close_network();
}
}
void AT_CellularContext::set_file_handle(FileHandle *fh)
{
_fh = fh;
_at.set_file_handle(_fh);
}
nsapi_error_t AT_CellularContext::connect()
{
if (_is_connected) {
return NSAPI_ERROR_IS_CONNECTED;
}
nsapi_error_t err = _device->attach_to_network();
_cb_data.error = check_operation(err, OP_CONNECT);
if (_is_blocking) {
if (_cb_data.error == NSAPI_ERROR_OK || _cb_data.error == NSAPI_ERROR_ALREADY) {
do_connect();
}
} else {
if (_cb_data.error == NSAPI_ERROR_ALREADY) {
// device is already attached, to be async we must use queue to connect and give proper callbacks
int id = _device->get_queue()->call_in(0, this, &AT_CellularContext::do_connect);
if (id == 0) {
return NSAPI_ERROR_NO_MEMORY;
}
return NSAPI_ERROR_OK;
}
}
return _cb_data.error;
}
nsapi_error_t AT_CellularContext::set_device_ready()
{
nsapi_error_t err = _device->set_device_ready();
return check_operation(err, OP_DEVICE_READY);
}
nsapi_error_t AT_CellularContext::set_sim_ready()
{
nsapi_error_t err = _device->set_sim_ready();
return check_operation(err, OP_SIM_READY);
}
nsapi_error_t AT_CellularContext::register_to_network()
{
nsapi_error_t err = _device->register_to_network();
return check_operation(err, OP_REGISTER);
}
nsapi_error_t AT_CellularContext::attach_to_network()
{
nsapi_error_t err = _device->attach_to_network();
return check_operation(err, OP_ATTACH);
}
nsapi_error_t AT_CellularContext::check_operation(nsapi_error_t err, ContextOperation op)
{
_current_op = op;
if (err == NSAPI_ERROR_IN_PROGRESS || err == NSAPI_ERROR_OK) {
if (_is_blocking) {
int sema_err = _semaphore.wait(get_timeout_for_operation(op)); // cellular network searching may take several minutes
if (sema_err != 1) {
tr_warning("No cellular connection");
return NSAPI_ERROR_TIMEOUT;
}
return NSAPI_ERROR_OK;
}
}
return err;
}
uint32_t AT_CellularContext::get_timeout_for_operation(ContextOperation op) const
{
uint32_t timeout = NETWORK_TIMEOUT; // default timeout is 30 minutes as registration and attach may take time
if (op == OP_SIM_READY || op == OP_DEVICE_READY) {
timeout = DEVICE_TIMEOUT; // use 5 minutes for device ready and sim
}
return timeout;
}
bool AT_CellularContext::is_connected()
{
return _is_connected;
}
NetworkStack *AT_CellularContext::get_stack()
{
#if NSAPI_PPP_AVAILABLE
// use lwIP/PPP if modem does not have IP stack
if (!_stack) {
_stack = nsapi_ppp_get_stack();
}
#endif
return _stack;
}
const char *AT_CellularContext::get_netmask()
{
return NULL;
}
const char *AT_CellularContext::get_gateway()
{
return NULL;
}
const char *AT_CellularContext::get_ip_address()
{
#if NSAPI_PPP_AVAILABLE
return nsapi_ppp_get_ip_addr(_at.get_file_handle());
#else
if (!_stack) {
_stack = get_stack();
}
if (_stack) {
return _stack->get_ip_address();
}
return NULL;
#endif
}
void AT_CellularContext::attach(Callback<void(nsapi_event_t, intptr_t)> status_cb)
{
_status_cb = status_cb;
}
nsapi_error_t AT_CellularContext::set_blocking(bool blocking)
{
nsapi_error_t err = NSAPI_ERROR_OK;
#if NSAPI_PPP_AVAILABLE
err = nsapi_ppp_set_blocking(blocking);
#endif
_is_blocking = blocking;
return err;
}
void AT_CellularContext::set_plmn(const char *plmn)
{
_device->set_plmn(plmn);
}
void AT_CellularContext::set_sim_pin(const char *sim_pin)
{
_device->set_sim_pin(sim_pin);
}
nsapi_error_t AT_CellularContext::connect(const char *sim_pin, const char *apn, const char *uname,
const char *pwd)
{
set_sim_pin(sim_pin);
set_credentials(apn, uname, pwd);
return connect();
}
void AT_CellularContext::set_credentials(const char *apn, const char *uname, const char *pwd)
{
_apn = apn;
_uname = uname;
_pwd = pwd;
}
bool AT_CellularContext::stack_type_supported(nsapi_ip_stack_t stack_type)
{
if (stack_type == _ip_stack_type) {
return true;
} else {
return false;
}
}
nsapi_ip_stack_t AT_CellularContext::get_stack_type()
{
return _ip_stack_type;
}
nsapi_ip_stack_t AT_CellularContext::string_to_stack_type(const char *pdp_type)
{
nsapi_ip_stack_t stack = DEFAULT_STACK;
int len = strlen(pdp_type);
if (len == 6 && memcmp(pdp_type, "IPV4V6", len) == 0) {
stack = IPV4V6_STACK;
} else if (len == 4 && memcmp(pdp_type, "IPV6", len) == 0) {
stack = IPV6_STACK;
} else if (len == 2 && memcmp(pdp_type, "IP", len) == 0) {
stack = IPV4_STACK;
}
return stack;
}
// PDP Context handling
nsapi_error_t AT_CellularContext::delete_current_context()
{
tr_info("Delete context %d", _cid);
_at.clear_error();
_at.cmd_start("AT+CGDCONT=");
_at.write_int(_cid);
_at.cmd_stop_read_resp();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
_cid = -1;
_new_context_set = false;
}
return _at.get_last_error();
}
nsapi_error_t AT_CellularContext::do_user_authentication()
{
// if user has defined user name and password we need to call CGAUTH before activating or modifying context
if (_pwd && _uname) {
if (!is_supported(AT_CGAUTH)) {
return NSAPI_ERROR_UNSUPPORTED;
}
_at.cmd_start("AT+CGAUTH=");
_at.write_int(_cid);
_at.write_int(_authentication_type);
_at.write_string(_uname);
_at.write_string(_pwd);
_at.cmd_stop_read_resp();
if (_at.get_last_error() != NSAPI_ERROR_OK) {
return NSAPI_ERROR_AUTH_FAILURE;
}
}
return NSAPI_ERROR_OK;
}
bool AT_CellularContext::get_context()
{
if (_apn) {
tr_debug("APN in use: %s", _apn);
} else {
tr_debug("NO APN");
}
_at.cmd_start("AT+CGDCONT?");
_at.cmd_stop();
_at.resp_start("+CGDCONT:");
_cid = -1;
int cid_max = 0; // needed when creating new context
char apn[MAX_ACCESSPOINT_NAME_LENGTH];
int apn_len = 0;
bool modem_supports_ipv6 = stack_type_supported(IPV6_STACK);
bool modem_supports_ipv4 = stack_type_supported(IPV4_STACK);
while (_at.info_resp()) {
int cid = _at.read_int();
if (cid > cid_max) {
cid_max = cid;
}
char pdp_type_from_context[10];
int pdp_type_len = _at.read_string(pdp_type_from_context, sizeof(pdp_type_from_context) - 1);
if (pdp_type_len > 0) {
apn_len = _at.read_string(apn, sizeof(apn) - 1);
if (apn_len >= 0) {
if (_apn && (strcmp(apn, _apn) != 0)) {
continue;
}
nsapi_ip_stack_t pdp_stack = string_to_stack_type(pdp_type_from_context);
// Accept dual PDP context for IPv4/IPv6 only modems
if (pdp_stack != DEFAULT_STACK && (stack_type_supported(pdp_stack) || pdp_stack == IPV4V6_STACK)) {
if (_ip_stack_type_requested == IPV4_STACK) {
if (pdp_stack == IPV4_STACK || pdp_stack == IPV4V6_STACK) {
_ip_stack_type = _ip_stack_type_requested;
_cid = cid;
break;
}
} else if (_ip_stack_type_requested == IPV6_STACK) {
if (pdp_stack == IPV6_STACK || pdp_stack == IPV4V6_STACK) {
_ip_stack_type = _ip_stack_type_requested;
_cid = cid;
break;
}
} else {
// requested dual stack or stack is not specified
// If dual PDP need to check for IPV4 or IPV6 modem support. Prefer IPv6.
if (pdp_stack == IPV4V6_STACK) {
if (modem_supports_ipv6) {
_ip_stack_type = IPV6_STACK;
_cid = cid;
break;
} else if (modem_supports_ipv4) {
_ip_stack_type = IPV4_STACK;
_cid = cid;
break;
}
// If PDP is IPV4 or IPV6 they are already checked if supported
} else {
_ip_stack_type = pdp_stack;
_cid = cid;
if (pdp_stack == IPV6_STACK) {
break;
}
if (pdp_stack == IPV4_STACK && !modem_supports_ipv6) {
break;
}
}
}
}
}
}
}
_at.resp_stop();
if (_cid == -1) { // no suitable context was found so create a new one
if (!set_new_context(cid_max + 1)) {
return false;
}
}
// save the apn
if (apn_len > 0 && !_apn) {
memcpy(_found_apn, apn, apn_len + 1);
}
tr_debug("Context id %d", _cid);
return true;
}
bool AT_CellularContext::set_new_context(int cid)
{
nsapi_ip_stack_t tmp_stack = _ip_stack_type_requested;
if (tmp_stack == DEFAULT_STACK) {
bool modem_supports_ipv6 = stack_type_supported(IPV6_STACK);
bool modem_supports_ipv4 = stack_type_supported(IPV4_STACK);
if (modem_supports_ipv6 && modem_supports_ipv4) {
tmp_stack = IPV4V6_STACK;
} else if (modem_supports_ipv6) {
tmp_stack = IPV6_STACK;
} else if (modem_supports_ipv4) {
tmp_stack = IPV4_STACK;
}
}
char pdp_type[8 + 1] = {0};
switch (tmp_stack) {
case IPV4_STACK:
strncpy(pdp_type, "IP", sizeof(pdp_type));
break;
case IPV6_STACK:
strncpy(pdp_type, "IPV6", sizeof(pdp_type));
break;
case IPV4V6_STACK:
strncpy(pdp_type, "IPV6", sizeof(pdp_type)); // try first IPV6 and then fall-back to IPv4
break;
default:
break;
}
//apn: "If the value is null or omitted, then the subscription value will be requested."
bool success = false;
_at.cmd_start("AT+CGDCONT=");
_at.write_int(cid);
_at.write_string(pdp_type);
_at.write_string(_apn);
_at.cmd_stop_read_resp();
success = (_at.get_last_error() == NSAPI_ERROR_OK);
// Fall back to ipv4
if (!success && tmp_stack == IPV4V6_STACK) {
_at.clear_error();
tmp_stack = IPV4_STACK;
_at.cmd_start("AT+FCLASS=0;+CGDCONT=");
_at.write_int(cid);
_at.write_string("IP");
_at.write_string(_apn);
_at.cmd_stop_read_resp();
success = (_at.get_last_error() == NSAPI_ERROR_OK);
}
if (success) {
_ip_stack_type = tmp_stack;
_cid = cid;
_new_context_set = true;
tr_info("New PDP context id %d was created", _cid);
}
return success;
}
nsapi_error_t AT_CellularContext::do_activate_context()
{
_at.lock();
nsapi_error_t err = NSAPI_ERROR_OK;
// try to find or create context with suitable stack
if (get_context()) {
#if NSAPI_PPP_AVAILABLE
_at.unlock();
// in PPP we don't activate any context but leave it to PPP stack
return err;
#endif // NSAPI_PPP_AVAILABLE
// try to authenticate user before activating or modifying context
err = do_user_authentication();
} else {
err = NSAPI_ERROR_NO_CONNECTION;
}
if (err != NSAPI_ERROR_OK) {
_at.unlock();
tr_error("Failed to activate network context! (%d)", err);
call_network_cb(NSAPI_STATUS_DISCONNECTED);
return err;
}
// do check for stack to validate that we have support for stack
if (!get_stack()) {
_at.unlock();
tr_error("No cellular stack!");
return NSAPI_ERROR_UNSUPPORTED;
}
_is_context_active = false;
_is_context_activated = false;
_at.cmd_start("AT+CGACT?");
_at.cmd_stop();
_at.resp_start("+CGACT:");
while (_at.info_resp()) {
int context_id = _at.read_int();
int context_activation_state = _at.read_int();
if (context_id == _cid && context_activation_state == 1) {
_is_context_active = true;
}
}
_at.resp_stop();
if (!_is_context_active) {
tr_info("Activate PDP context %d", _cid);
_at.cmd_start("AT+CGACT=1,");
_at.write_int(_cid);
_at.cmd_stop_read_resp();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
_is_context_activated = true;
}
}
err = (_at.get_last_error() == NSAPI_ERROR_OK) ? NSAPI_ERROR_OK : NSAPI_ERROR_NO_CONNECTION;
// If new PDP context was created and failed to activate, delete it
if (err != NSAPI_ERROR_OK && _new_context_set) {
delete_current_context();
} else if (err == NSAPI_ERROR_OK) {
_is_context_active = true;
}
_at.unlock();
return err;
}
void AT_CellularContext::do_connect()
{
call_network_cb(NSAPI_STATUS_CONNECTING);
if (!_is_context_active) {
_cb_data.error = do_activate_context();
#if !NSAPI_PPP_AVAILABLE
// in PPP mode we did not activate any context, just searched the correct _cid
if (_status_cb) {
_status_cb((nsapi_event_t)CellularActivatePDPContext, (intptr_t )&_cb_data);
}
#endif // !NSAPI_PPP_AVAILABLE
}
if (_cb_data.error != NSAPI_ERROR_OK) {
call_network_cb(NSAPI_STATUS_DISCONNECTED);
_is_connected = false;
return;
}
#if NSAPI_PPP_AVAILABLE
if (_cb_data.error == NSAPI_ERROR_OK) {
_at.lock();
_cb_data.error = open_data_channel();
_at.unlock();
if (_cb_data.error != NSAPI_ERROR_OK) {
tr_error("Failed to open data channel!");
call_network_cb(NSAPI_STATUS_DISCONNECTED);
_is_connected = false;
}
}
#else
_is_connected = true;
call_network_cb(NSAPI_STATUS_GLOBAL_UP);
#endif
}
#if NSAPI_PPP_AVAILABLE
nsapi_error_t AT_CellularContext::open_data_channel()
{
tr_info("Open data channel in PPP mode");
if (is_supported(AT_CGDATA)) {
_at.cmd_start("AT+CGDATA=\"PPP\",");
_at.write_int(_cid);
} else {
MBED_ASSERT(_cid >= 0 && _cid <= 99);
_at.cmd_start("ATD*99***");
_at.use_delimiter(false);
_at.write_int(_cid);
_at.write_string("#", false);
_at.use_delimiter(true);
}
_at.cmd_stop();
_at.resp_start("CONNECT", true);
if (_at.get_last_error()) {
tr_error("Failed to CONNECT");
return _at.get_last_error();
}
_at.set_is_filehandle_usable(false);
/* Initialize PPP
* If blocking: mbed_ppp_init() is a blocking call, it will block until
connected, or timeout after 30 seconds*/
return nsapi_ppp_connect(_at.get_file_handle(), callback(this, &AT_CellularContext::ppp_status_cb), _uname, _pwd, _ip_stack_type);
}
void AT_CellularContext::ppp_status_cb(nsapi_event_t ev, intptr_t ptr)
{
tr_debug("AT_CellularContext::ppp_status_cb, network_callback called with event: %d, ptr: %d", ev, ptr);
if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE && ptr == NSAPI_STATUS_GLOBAL_UP) {
_is_connected = true;
} else {
_is_connected = false;
}
_connect_status = (nsapi_connection_status_t)ptr;
// call device's callback, it will broadcast this to here (cellular_callback)
_device->cellular_callback(ev, ptr);
}
#endif //#if NSAPI_PPP_AVAILABLE
nsapi_error_t AT_CellularContext::disconnect()
{
if (!_nw || !_is_connected) {
return NSAPI_ERROR_NO_CONNECTION;
}
#if NSAPI_PPP_AVAILABLE
nsapi_error_t err = nsapi_ppp_disconnect(_at.get_file_handle());
if (err != NSAPI_ERROR_OK) {
tr_error("Cellular disconnect failed!");
// continue even in failure due to ppp disconnect in any case releases filehandle
}
// after ppp disconnect if we wan't to use same at handler we need to set filehandle again to athandler so it
// will set the correct sigio and nonblocking
_at.lock();
_at.set_file_handle(_at.get_file_handle());
_at.set_is_filehandle_usable(true);
//_at.sync(); // consume extra characters after ppp disconnect, also it may take a while until modem listens AT commands
_at.unlock();
#endif // NSAPI_PPP_AVAILABLE
_at.lock();
// deactivate a context only if we have activated
if (_is_context_activated) {
_is_context_active = false;
size_t active_contexts_count = 0;
_at.cmd_start("AT+CGACT?");
_at.cmd_stop();
_at.resp_start("+CGACT:");
while (_at.info_resp()) {
int context_id = _at.read_int();
int context_activation_state = _at.read_int();
if (context_activation_state == 1) {
active_contexts_count++;
if (context_id == _cid) {
_is_context_active = true;
}
}
}
_at.resp_stop();
CellularNetwork::RadioAccessTechnology rat = CellularNetwork::RAT_GSM;
// always return NSAPI_ERROR_OK
CellularNetwork::registration_params_t reg_params;
_nw->get_registration_params(reg_params);
rat = reg_params._act;
// 3GPP TS 27.007:
// For EPS, if an attempt is made to disconnect the last PDN connection, then the MT responds with ERROR
if (_is_context_active && (rat < CellularNetwork::RAT_E_UTRAN || active_contexts_count > 1)) {
_at.cmd_start("AT+CGACT=0,");
_at.write_int(_cid);
_at.cmd_stop_read_resp();
}
}
if (!_at.get_last_error()) {
_is_connected = false;
call_network_cb(NSAPI_STATUS_DISCONNECTED);
}
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularContext::get_apn_backoff_timer(int &backoff_timer)
{
// If apn is set
if (_apn) {
_at.lock();
_at.cmd_start("AT+CABTRDP=");
_at.write_string(_apn);
_at.cmd_stop();
_at.resp_start("+CABTRDP:");
if (_at.info_resp()) {
_at.skip_param();
backoff_timer = _at.read_int();
}
_at.resp_stop();
return _at.unlock_return_error();
}
return NSAPI_ERROR_PARAMETER;
}
nsapi_error_t AT_CellularContext::get_rate_control(
CellularContext::RateControlExceptionReports &reports,
CellularContext::RateControlUplinkTimeUnit &timeUnit, int &uplinkRate)
{
_at.lock();
_at.cmd_start("AT+CGAPNRC=");
_at.write_int(_cid);
_at.cmd_stop();
_at.resp_start("+CGAPNRC:");
_at.read_int();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
bool comma_found = true;
int next_element = _at.read_int();
if (next_element >= 0) {
reports = (RateControlExceptionReports)next_element;
tr_debug("reports %d", reports);
next_element = _at.read_int();
} else {
comma_found = false;
}
if (comma_found && next_element >= 0) {
timeUnit = (RateControlUplinkTimeUnit)next_element;
tr_debug("time %d", timeUnit);
next_element = _at.read_int();
} else {
comma_found = false;
}
if (comma_found && next_element >= 0) {
uplinkRate = next_element;
tr_debug("rate %d", uplinkRate);
}
}
_at.resp_stop();
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularContext::get_pdpcontext_params(pdpContextList_t &params_list)
{
const int ipv6_subnet_size = 128;
const int max_ipv6_size = 64;
char *ipv6_and_subnetmask = new char[ipv6_subnet_size];
char *temp = new char[max_ipv6_size];
_at.lock();
_at.cmd_start("AT+CGCONTRDP=");
_at.write_int(_cid);
_at.cmd_stop();
_at.resp_start("+CGCONTRDP:");
pdpcontext_params_t *params = NULL;
while (_at.info_resp()) { // response can be zero or many +CGDCONT lines
params = params_list.add_new();
params->cid = _at.read_int();
params->bearer_id = _at.read_int();
_at.read_string(params->apn, sizeof(params->apn));
// rest are optional params
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->local_addr, sizeof(params->local_addr), params->local_subnet_mask, sizeof(params->local_subnet_mask));
ipv6_and_subnetmask[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->gateway_addr, sizeof(params->gateway_addr), temp, max_ipv6_size);
prefer_ipv6(params->gateway_addr, sizeof(params->gateway_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->dns_primary_addr, sizeof(params->dns_primary_addr), temp, max_ipv6_size);
prefer_ipv6(params->dns_primary_addr, sizeof(params->dns_primary_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->dns_secondary_addr, sizeof(params->dns_secondary_addr), temp, max_ipv6_size);
prefer_ipv6(params->dns_secondary_addr, sizeof(params->dns_secondary_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->p_cscf_prim_addr, sizeof(params->p_cscf_prim_addr), temp, max_ipv6_size);
prefer_ipv6(params->p_cscf_prim_addr, sizeof(params->p_cscf_prim_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->p_cscf_sec_addr, sizeof(params->p_cscf_sec_addr), temp, max_ipv6_size);
prefer_ipv6(params->p_cscf_sec_addr, sizeof(params->p_cscf_sec_addr), temp, max_ipv6_size);
params->im_signalling_flag = _at.read_int();
params->lipa_indication = _at.read_int();
params->ipv4_mtu = _at.read_int();
params->wlan_offload = _at.read_int();
params->local_addr_ind = _at.read_int();
params->non_ip_mtu = _at.read_int();
params->serving_plmn_rate_control_value = _at.read_int();
}
_at.resp_stop();
delete [] temp;
delete [] ipv6_and_subnetmask;
return _at.unlock_return_error();
}
// Called by CellularDevice for network and cellular device changes
void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
{
if (ev >= NSAPI_EVENT_CELLULAR_STATUS_BASE && ev <= NSAPI_EVENT_CELLULAR_STATUS_END) {
cell_callback_data_t* data = (cell_callback_data_t*)ptr;
cellular_connection_status_t st = (cellular_connection_status_t)ev;
_cb_data.error = data->error;
tr_debug("AT_CellularContext::cellular_callback, network_callback called with event: %d, err: %d, data: %d", ev, data->error, data->status_data);
#if USE_APN_LOOKUP
if (st == CellularSIMStatusChanged && data->status_data == CellularSIM::SimStateReady &&
_cb_data.error == NSAPI_ERROR_OK) {
if (!_apn) {
char imsi[MAX_IMSI_LENGTH + 1];
wait(1); // need to wait to access SIM in some modems
_cb_data.error = _device->open_sim()->get_imsi(imsi);
if (_cb_data.error == NSAPI_ERROR_OK) {
const char *apn_config = apnconfig(imsi);
if (apn_config) {
const char *apn = _APN_GET(apn_config);
const char *uname = _APN_GET(apn_config);
const char *pwd = _APN_GET(apn_config);
tr_info("Looked up APN %s", apn);
set_credentials(apn, uname, pwd);
}
} else {
tr_error("APN lookup failed");
_device->stop();
if (_is_blocking) {
// operation failed, release semaphore
_semaphore.release();
}
}
_device->close_sim();
}
}
#endif // USE_APN_LOOKUP
if (!_nw && st == CellularDeviceReady && data->error == NSAPI_ERROR_OK) {
_nw = _device->open_network(_fh);
}
if (_is_blocking) {
if (data->error != NSAPI_ERROR_OK) {
// operation failed, release semaphore
_semaphore.release();
} else {
if ((st == CellularDeviceReady && _current_op == OP_DEVICE_READY) ||
(st == CellularSIMStatusChanged && _current_op == OP_SIM_READY &&
data->status_data == CellularSIM::SimStateReady)) {
// target reached, release semaphore
_semaphore.release();
} else if (st == CellularRegistrationStatusChanged && (data->status_data == CellularNetwork::RegisteredHomeNetwork ||
data->status_data == CellularNetwork::RegisteredRoaming || data->status_data == CellularNetwork::AlreadyRegistered) && _current_op == OP_REGISTER) {
// target reached, release semaphore
_semaphore.release();
} else if (st == CellularAttachNetwork && (_current_op == OP_ATTACH || _current_op == OP_CONNECT) &&
data->status_data == CellularNetwork::Attached) {
// target reached, release semaphore
_semaphore.release();
}
}
} else {
// non blocking
if (st == CellularAttachNetwork && _current_op == OP_CONNECT && data->error == NSAPI_ERROR_OK &&
data->status_data == CellularNetwork::Attached) {
// forward to application
if (_status_cb) {
_status_cb(ev, ptr);
}
do_connect();
return;
}
}
} else {
tr_debug("AT_CellularContext::cellular_callback, network_callback called with event: %d, ptr: %d", ev, ptr);
#if NSAPI_PPP_AVAILABLE
if (_is_blocking) {
if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE && ptr == NSAPI_STATUS_GLOBAL_UP) {
_cb_data.error = NSAPI_ERROR_OK;
_semaphore.release();
} else if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE && ptr == NSAPI_STATUS_DISCONNECTED) {
_cb_data.error = NSAPI_ERROR_NO_CONNECTION;
_semaphore.release();
}
}
#endif
}
// forward to application
if (_status_cb) {
_status_cb(ev, ptr);
}
}
void AT_CellularContext::call_network_cb(nsapi_connection_status_t status)
{
if (_connect_status != status) {
_connect_status = status;
if (_status_cb) {
_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connect_status);
}
}
}

View File

@ -0,0 +1,125 @@
/*
* 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.
*/
#ifndef AT_CELLULARCONTEXT_H_
#define AT_CELLULARCONTEXT_H_
#include "CellularContext.h"
#include "AT_CellularBase.h"
#include "Semaphore.h"
const int MAX_APN_LENGTH = 63 + 1;
namespace mbed {
class AT_CellularContext : public CellularContext, public AT_CellularBase {
public:
AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn = 0);
virtual ~AT_CellularContext();
// from CellularBase/NetworkInterface
virtual nsapi_error_t set_blocking(bool blocking);
virtual NetworkStack *get_stack();
virtual const char *get_ip_address();
virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
virtual nsapi_error_t connect();
virtual nsapi_error_t disconnect();
virtual bool is_connected();
// from CellularBase
virtual void set_plmn(const char *plmn);
virtual void set_sim_pin(const char *sim_pin);
virtual nsapi_error_t connect(const char *sim_pin, const char *apn = 0, const char *uname = 0,
const char *pwd = 0);
virtual void set_credentials(const char *apn, const char *uname = 0, const char *pwd = 0);
virtual const char *get_netmask();
virtual const char *get_gateway();
// from CellularContext
virtual nsapi_error_t get_pdpcontext_params(pdpContextList_t &params_list);
virtual nsapi_error_t get_rate_control(CellularContext::RateControlExceptionReports &reports,
CellularContext::RateControlUplinkTimeUnit &time_unit, int &uplink_rate);
virtual nsapi_error_t get_apn_backoff_timer(int &backoff_timer);
virtual nsapi_error_t set_device_ready();
virtual nsapi_error_t set_sim_ready();
virtual nsapi_error_t register_to_network();
virtual nsapi_error_t attach_to_network();
virtual void set_file_handle(FileHandle *fh);
protected:
virtual void cellular_callback(nsapi_event_t ev, intptr_t ptr);
/** Does the authentication for the PDP Context if user name and password are provided.
* Can be overridden by the modem target if 3GPP default implementation if not an option
*
* @return NSAPI_ERROR_OK if no credentials provided or authentication was successful
* NSAPI_ERROR_AUTH_FAILURE if authentication failed
* NSAPI_ERROR_DEVICE_ERROR if communication with the modemm failed
*/
virtual nsapi_error_t do_user_authentication();
/** Activates PDP context or in PPP mode opens data channel.
* Can be overridden by the modem target if 3GPP default implementation if not an option
*/
virtual void do_connect();
/** Check if modem supports the given stack type. Can be overridden by the modem.
*
* @return true if supported
*/
virtual bool stack_type_supported(nsapi_ip_stack_t stack_type);
/** Get the operation specific timeout. Used in synchronous mode when setting the maximum
* waiting time. Modem specific implementation can override this to provide different timeouts.
*
* @param op current operation
* @return timeout in milliseconds
*/
virtual uint32_t get_timeout_for_operation(ContextOperation op) const;
/** Helper method to call callback function if it is provided
*
* @param status connection status which is parameter in callback function
*/
void call_network_cb(nsapi_connection_status_t status);
private:
#if NSAPI_PPP_AVAILABLE
nsapi_error_t open_data_channel();
void ppp_status_cb(nsapi_event_t ev, intptr_t ptr);
#endif // #if NSAPI_PPP_AVAILABLE
nsapi_error_t do_activate_context();
bool set_new_context(int cid);
bool get_context();
nsapi_error_t delete_current_context();
nsapi_ip_stack_t string_to_stack_type(const char *pdp_type);
nsapi_ip_stack_t get_stack_type();
nsapi_error_t check_operation(nsapi_error_t err, ContextOperation op);
private:
nsapi_ip_stack_t _ip_stack_type_requested;
bool _is_connected;
bool _is_blocking;
ContextOperation _current_op;
char _found_apn[MAX_APN_LENGTH];
CellularDevice *_device;
CellularNetwork *_nw;
FileHandle *_fh;
rtos::Semaphore _semaphore;
};
} // namespace mbed
#endif // AT_CELLULARCONTEXT_H_

View File

@ -21,27 +21,49 @@
#include "AT_CellularPower.h"
#include "AT_CellularSIM.h"
#include "AT_CellularSMS.h"
#include "AT_CellularContext.h"
#include "AT_CellularStack.h"
#include "CellularLog.h"
#include "ATHandler.h"
#include "UARTSerial.h"
#include "FileHandle.h"
using namespace events;
using namespace mbed;
#define DEFAULT_AT_TIMEOUT 1000 // at default timeout in milliseconds
AT_CellularDevice::AT_CellularDevice(EventQueue &queue) :
_atHandlers(0), _network(0), _sms(0), _sim(0), _power(0), _information(0), _queue(queue),
_default_timeout(DEFAULT_AT_TIMEOUT), _modem_debug_on(false)
AT_CellularDevice::AT_CellularDevice(FileHandle *fh) : CellularDevice(fh), _atHandlers(0), _network(0), _sms(0),
_sim(0), _power(0), _information(0), _context_list(0), _default_timeout(DEFAULT_AT_TIMEOUT),
_modem_debug_on(false)
{
}
AT_CellularDevice::~AT_CellularDevice()
{
delete _state_machine;
// make sure that all is deleted even if somewhere close was not called and reference counting is messed up.
_network_ref_count = 1;
_sms_ref_count = 1;
_power_ref_count = 1;
_sim_ref_count = 1;
_info_ref_count = 1;
close_network();
close_sms();
close_power();
close_sim();
close_information();
AT_CellularContext* curr = _context_list;
AT_CellularContext* next;
while (curr) {
next = (AT_CellularContext*)curr->_next;
delete curr;
curr = next;
}
ATHandler *atHandler = _atHandlers;
while (atHandler) {
ATHandler *old = atHandler;
@ -50,16 +72,11 @@ AT_CellularDevice::~AT_CellularDevice()
}
}
events::EventQueue *AT_CellularDevice::get_queue() const
{
return &_queue;
}
// each parser is associated with one filehandle (that is UART)
ATHandler *AT_CellularDevice::get_at_handler(FileHandle *fileHandle)
{
if (!fileHandle) {
return NULL;
fileHandle = _fh;
}
ATHandler *atHandler = _atHandlers;
while (atHandler) {
@ -107,6 +124,58 @@ void AT_CellularDevice::release_at_handler(ATHandler *at_handler)
}
}
CellularContext *AT_CellularDevice::get_context_list() const
{
return _context_list;
}
CellularContext *AT_CellularDevice::create_context(FileHandle *fh, const char *apn)
{
ATHandler *atHandler = get_at_handler(fh);
if (atHandler) {
AT_CellularContext *ctx = create_context_impl(*atHandler, apn);
AT_CellularContext* curr = _context_list;
if (_context_list == NULL) {
_context_list = ctx;
return ctx;
}
AT_CellularContext* prev;
while (curr) {
prev = curr;
curr = (AT_CellularContext*)curr->_next;
}
prev->_next = ctx;
return ctx;
}
return NULL;
}
AT_CellularContext *AT_CellularDevice::create_context_impl(ATHandler &at, const char *apn)
{
return new AT_CellularContext(at, this, apn);
}
void AT_CellularDevice::delete_context(CellularContext *context)
{
AT_CellularContext* curr = _context_list;
AT_CellularContext* prev = NULL;
while (curr) {
if (curr == context) {
if (prev == NULL) {
_context_list = (AT_CellularContext*)curr->_next;
} else {
prev->_next = curr->_next;
}
}
prev = curr;
curr = (AT_CellularContext*)curr->_next;
}
delete (AT_CellularContext*)context;
}
CellularNetwork *AT_CellularDevice::open_network(FileHandle *fh)
{
if (!_network) {
@ -278,7 +347,7 @@ void AT_CellularDevice::set_timeout(int timeout)
}
}
uint16_t AT_CellularDevice::get_send_delay()
uint16_t AT_CellularDevice::get_send_delay() const
{
return 0;
}
@ -294,15 +363,7 @@ void AT_CellularDevice::modem_debug_on(bool on)
}
}
NetworkStack *AT_CellularDevice::get_stack()
{
if (!_network) {
return NULL;
}
return _network->get_stack();
}
nsapi_error_t AT_CellularDevice::init_module(FileHandle *fh)
nsapi_error_t AT_CellularDevice::init_module()
{
return NSAPI_ERROR_OK;
}

View File

@ -28,6 +28,7 @@ class AT_CellularNetwork;
class AT_CellularPower;
class AT_CellularSIM;
class AT_CellularSMS;
class AT_CellularContext;
/**
* Class AT_CellularDevice
@ -37,33 +38,21 @@ class AT_CellularSMS;
*/
class AT_CellularDevice : public CellularDevice {
public:
AT_CellularDevice(events::EventQueue &queue);
AT_CellularDevice(FileHandle *fh);
virtual ~AT_CellularDevice();
protected:
ATHandler *_atHandlers;
virtual CellularContext *create_context(FileHandle *fh = NULL, const char *apn = NULL);
virtual void delete_context(CellularContext *context);
ATHandler *get_at_handler(FileHandle *fh);
virtual CellularNetwork *open_network(FileHandle *fh = NULL);
/** Releases the given at_handler. If last reference to at_hander then it's deleted.
*
* @param at_handler
*/
void release_at_handler(ATHandler *at_handler);
virtual CellularSMS *open_sms(FileHandle *fh = NULL);
public: // CellularDevice
virtual CellularPower *open_power(FileHandle *fh = NULL);
virtual events::EventQueue *get_queue() const;
virtual CellularSIM *open_sim(FileHandle *fh = NULL);
virtual CellularNetwork *open_network(FileHandle *fh);
virtual CellularSMS *open_sms(FileHandle *fh);
virtual CellularPower *open_power(FileHandle *fh);
virtual CellularSIM *open_sim(FileHandle *fh);
virtual CellularInformation *open_information(FileHandle *fh);
virtual CellularInformation *open_information(FileHandle *fh = NULL);
virtual void close_network();
@ -77,15 +66,31 @@ public: // CellularDevice
virtual void set_timeout(int timeout);
virtual uint16_t get_send_delay();
virtual uint16_t get_send_delay() const;
virtual void modem_debug_on(bool on);
virtual NetworkStack *get_stack();
virtual nsapi_error_t init_module();
virtual nsapi_error_t init_module(FileHandle *fh);
ATHandler *_atHandlers;
ATHandler *get_at_handler(FileHandle *fh);
/** Releases the given at_handler. If last reference to at_hander then it's deleted.
*
* @param at_handler
*/
void release_at_handler(ATHandler *at_handler);
/** Creates new instance of AT_CellularContext or if overridden, modem specific implementation.
*
* @param at ATHandler reference for communication with the modem.
* @param apn access point to use with context
* @return new instance of class AT_CellularContext
*
*/
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn);
protected:
/** Create new instance of AT_CellularNetwork or if overridden, modem specific implementation.
*
* @param at ATHandler reference for communication with the modem.
@ -121,14 +126,14 @@ protected:
*/
virtual AT_CellularInformation *open_information_impl(ATHandler &at);
virtual CellularContext *get_context_list() const;
AT_CellularNetwork *_network;
AT_CellularSMS *_sms;
AT_CellularSIM *_sim;
AT_CellularPower *_power;
AT_CellularInformation *_information;
protected:
events::EventQueue &_queue;
AT_CellularContext *_context_list;
int _default_timeout;
bool _modem_debug_on;
};

View File

@ -17,7 +17,6 @@
#include <stdlib.h>
#include "AT_CellularNetwork.h"
#include "nsapi_ppp.h"
#include "CellularUtil.h"
#include "CellularLog.h"
#include "CellularCommon.h"
@ -39,20 +38,34 @@ static const at_reg_t at_reg[] = {
};
AT_CellularNetwork::AT_CellularNetwork(ATHandler &atHandler) : AT_CellularBase(atHandler),
_stack(NULL), _apn(NULL), _uname(NULL), _pwd(NULL), _ip_stack_type_requested(DEFAULT_STACK),
_ip_stack_type(DEFAULT_STACK), _cid(-1), _connection_status_cb(NULL), _op_act(RAT_UNKNOWN),
_authentication_type(CHAP), _connect_status(NSAPI_STATUS_DISCONNECTED), _new_context_set(false),
_is_context_active(false)
_connection_status_cb(NULL), _op_act(RAT_UNKNOWN), _connect_status(NSAPI_STATUS_DISCONNECTED)
{
_urc_funcs[C_EREG] = callback(this, &AT_CellularNetwork::urc_cereg);
_urc_funcs[C_GREG] = callback(this, &AT_CellularNetwork::urc_cgreg);
_urc_funcs[C_REG] = callback(this, &AT_CellularNetwork::urc_creg);
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
if (has_registration((RegistrationType)type) != RegistrationModeDisable) {
_at.set_urc_handler(at_reg[type].urc_prefix, _urc_funcs[type]);
}
}
_at.set_urc_handler("NO CARRIER", callback(this, &AT_CellularNetwork::urc_no_carrier));
// additional urc to get better disconnect info for application. Not critical.
_at.set_urc_handler("+CGEV:", callback(this, &AT_CellularNetwork::urc_cgev));
_at.lock();
_at.cmd_start("AT+CGEREP=1");// discard unsolicited result codes when MT TE link is reserved (e.g. in on line data mode); otherwise forward them directly to the TE
_at.cmd_stop_read_resp();
_at.unlock();
}
AT_CellularNetwork::~AT_CellularNetwork()
{
#if NSAPI_PPP_AVAILABLE
(void)disconnect();
#else
delete _stack;
#endif // NSAPI_PPP_AVAILABLE
_at.lock();
_at.cmd_start("AT+CGEREP=0");// buffer unsolicited result codes in the MT; if MT result code buffer is full, the oldest ones can be discarded. No codes are forwarded to the TE
_at.cmd_stop_read_resp();
_at.unlock();
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
if (has_registration((RegistrationType)type) != RegistrationModeDisable) {
@ -62,42 +75,6 @@ AT_CellularNetwork::~AT_CellularNetwork()
_at.remove_urc_handler("NO CARRIER");
_at.remove_urc_handler("+CGEV:");
free_credentials();
}
nsapi_error_t AT_CellularNetwork::init()
{
_urc_funcs[C_EREG] = callback(this, &AT_CellularNetwork::urc_cereg);
_urc_funcs[C_GREG] = callback(this, &AT_CellularNetwork::urc_cgreg);
_urc_funcs[C_REG] = callback(this, &AT_CellularNetwork::urc_creg);
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
if (has_registration((RegistrationType)type) != RegistrationModeDisable) {
if (_at.set_urc_handler(at_reg[type].urc_prefix, _urc_funcs[type]) != NSAPI_ERROR_OK) {
return NSAPI_ERROR_NO_MEMORY;
}
}
}
return _at.set_urc_handler("NO CARRIER", callback(this, &AT_CellularNetwork::urc_no_carrier));
}
void AT_CellularNetwork::free_credentials()
{
if (_uname) {
free(_uname);
_uname = NULL;
}
if (_pwd) {
free(_pwd);
_pwd = NULL;
}
if (_apn) {
free(_apn);
_apn = NULL;
}
}
void AT_CellularNetwork::urc_no_carrier()
@ -160,17 +137,22 @@ void AT_CellularNetwork::read_reg_params_and_compare(RegistrationType type)
if (_at.get_last_error() == NSAPI_ERROR_OK && _connection_status_cb) {
tr_debug("type: %d, status: %d, lac: %d, cellID: %d, act: %d", type, reg_params._status, reg_params._lac, reg_params._cell_id, reg_params._act);
_reg_params._type = type;
cell_callback_data_t data;
data.error = NSAPI_ERROR_OK;
if (reg_params._act != _reg_params._act) {
_reg_params._act = reg_params._act;
_connection_status_cb((nsapi_event_t)CellularRadioAccessTechnologyChanged, _reg_params._act);
data.status_data = reg_params._act;
_connection_status_cb((nsapi_event_t)CellularRadioAccessTechnologyChanged, (intptr_t)&data);
}
if (reg_params._status != _reg_params._status) {
_reg_params._status = reg_params._status;
_connection_status_cb((nsapi_event_t)CellularRegistrationStatusChanged, _reg_params._status);
data.status_data = reg_params._status;
_connection_status_cb((nsapi_event_t)CellularRegistrationStatusChanged, (intptr_t)&data);
}
if (reg_params._cell_id != -1 && reg_params._cell_id != _reg_params._cell_id) {
_reg_params._cell_id = reg_params._cell_id;
_connection_status_cb((nsapi_event_t)CellularCellIDChanged, _reg_params._cell_id);
data.status_data = reg_params._cell_id;
_connection_status_cb((nsapi_event_t)CellularCellIDChanged, (intptr_t)&data);
}
}
}
@ -193,278 +175,6 @@ void AT_CellularNetwork::urc_cgreg()
read_reg_params_and_compare(C_GREG);
}
nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn,
const char *username, const char *password)
{
free_credentials();
size_t len;
if (apn && (len = strlen(apn)) > 0) {
_apn = (char *)malloc(len * sizeof(char) + 1);
if (_apn) {
memcpy(_apn, apn, len + 1);
} else {
return NSAPI_ERROR_NO_MEMORY;
}
}
if (username && (len = strlen(username)) > 0) {
if (!is_supported(AT_CGAUTH)) { // APN authentication is needed with username/password
return NSAPI_ERROR_UNSUPPORTED;
}
_uname = (char *)malloc(len * sizeof(char) + 1);
if (_uname) {
memcpy(_uname, username, len + 1);
} else {
return NSAPI_ERROR_NO_MEMORY;
}
}
if (password && (len = strlen(password)) > 0) {
_pwd = (char *)malloc(len * sizeof(char) + 1);
if (_pwd) {
memcpy(_pwd, password, len + 1);
} else {
return NSAPI_ERROR_NO_MEMORY;
}
}
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn,
AuthenticationType type, const char *username, const char *password)
{
nsapi_error_t err = set_credentials(apn, username, password);
if (err) {
return err;
}
_authentication_type = type;
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::connect(const char *apn,
const char *username, const char *password)
{
nsapi_error_t err = set_credentials(apn, username, password);
if (err) {
return err;
}
return connect();
}
nsapi_error_t AT_CellularNetwork::delete_current_context()
{
tr_info("Delete context %d", _cid);
_at.clear_error();
_at.cmd_start("AT+CGDCONT=");
_at.write_int(_cid);
_at.cmd_stop_read_resp();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
_cid = -1;
_new_context_set = false;
}
return _at.get_last_error();
}
nsapi_error_t AT_CellularNetwork::activate_context()
{
_at.lock();
nsapi_error_t err = NSAPI_ERROR_OK;
// try to find or create context with suitable stack
if (!get_context()) {
err = NSAPI_ERROR_NO_CONNECTION;
}
if (err != NSAPI_ERROR_OK) {
_at.unlock();
tr_error("Failed to activate network context! (%d)", err);
call_network_cb(NSAPI_STATUS_DISCONNECTED);
return err;
}
// do check for stack to validate that we have support for stack
_stack = get_stack();
if (!_stack) {
tr_error("No cellular stack!");
return NSAPI_ERROR_UNSUPPORTED;
}
_is_context_active = false;
_at.cmd_start("AT+CGACT?");
_at.cmd_stop();
_at.resp_start("+CGACT:");
while (_at.info_resp()) {
int context_id = _at.read_int();
int context_activation_state = _at.read_int();
if (context_id == _cid && context_activation_state == 1) {
_is_context_active = true;
}
}
_at.resp_stop();
if (!_is_context_active) {
// authenticate before activating or modifying context
nsapi_error_t err = do_user_authentication();
if (err != NSAPI_ERROR_OK) {
tr_error("Cellular authentication failed!");
return err;
}
tr_info("Activate PDP context %d", _cid);
_at.cmd_start("AT+CGACT=1,");
_at.write_int(_cid);
_at.cmd_stop_read_resp();
}
err = (_at.get_last_error() == NSAPI_ERROR_OK) ? NSAPI_ERROR_OK : NSAPI_ERROR_NO_CONNECTION;
// If new PDP context was created and failed to activate, delete it
if (err != NSAPI_ERROR_OK && _new_context_set) {
delete_current_context();
} else if (err == NSAPI_ERROR_OK) {
_is_context_active = true;
}
_at.unlock();
return err;
}
nsapi_error_t AT_CellularNetwork::connect()
{
call_network_cb(NSAPI_STATUS_CONNECTING);
nsapi_error_t err = NSAPI_ERROR_OK;
if (!_is_context_active) {
err = activate_context();
}
if (err) {
call_network_cb(NSAPI_STATUS_DISCONNECTED);
return err;
}
#if NSAPI_PPP_AVAILABLE
_at.lock();
err = open_data_channel();
_at.unlock();
if (err != NSAPI_ERROR_OK) {
tr_error("Failed to open data channel!");
call_network_cb(NSAPI_STATUS_DISCONNECTED);
return err;
}
#else
// additional urc to get better disconnect info for application. Not critical so not returning an error in case of failure
err = _at.set_urc_handler("+CGEV:", callback(this, &AT_CellularNetwork::urc_cgev));
if (err == NSAPI_ERROR_OK) {
_at.lock();
_at.cmd_start("AT+CGEREP=1");
_at.cmd_stop_read_resp();
_at.unlock();
}
call_network_cb(NSAPI_STATUS_GLOBAL_UP);
#endif
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::open_data_channel()
{
#if NSAPI_PPP_AVAILABLE
tr_info("Open data channel in PPP mode");
if (is_supported(AT_CGDATA)) {
_at.cmd_start("AT+CGDATA=\"PPP\",");
_at.write_int(_cid);
} else {
MBED_ASSERT(_cid >= 0 && _cid <= 99);
_at.cmd_start("ATD*99***");
_at.use_delimiter(false);
_at.write_int(_cid);
_at.write_string("#", false);
_at.use_delimiter(true);
}
_at.cmd_stop();
_at.resp_start("CONNECT", true);
if (_at.get_last_error()) {
tr_error("Failed to CONNECT");
return _at.get_last_error();
}
_at.set_is_filehandle_usable(false);
/* Initialize PPP
* If blocking: mbed_ppp_init() is a blocking call, it will block until
connected, or timeout after 30 seconds*/
return nsapi_ppp_connect(_at.get_file_handle(), callback(this, &AT_CellularNetwork::ppp_status_cb), NULL, NULL, _ip_stack_type);
#else
return NSAPI_ERROR_OK;
#endif // #if NSAPI_PPP_AVAILABLE
}
/**
* User initiated disconnect
*
* Disconnects from PPP connection only and brings down the underlying network
* interface
*/
nsapi_error_t AT_CellularNetwork::disconnect()
{
#if NSAPI_PPP_AVAILABLE
nsapi_error_t err = nsapi_ppp_disconnect(_at.get_file_handle());
// after ppp disconnect if we wan't to use same at handler we need to set filehandle again to athandler so it
// will set the correct sigio and nonblocking
_at.lock();
_at.set_file_handle(_at.get_file_handle());
_at.set_is_filehandle_usable(true);
_at.unlock();
return err;
#else
_at.lock();
_is_context_active = false;
size_t active_contexts_count = 0;
_at.cmd_start("AT+CGACT?");
_at.cmd_stop();
_at.resp_start("+CGACT:");
while (_at.info_resp()) {
int context_id = _at.read_int();
int context_activation_state = _at.read_int();
if (context_activation_state == 1) {
active_contexts_count++;
if (context_id == _cid) {
_is_context_active = true;
}
}
}
_at.resp_stop();
// 3GPP TS 27.007:
// For EPS, if an attempt is made to disconnect the last PDN connection, then the MT responds with ERROR
if (_is_context_active && (_reg_params._act < RAT_E_UTRAN || active_contexts_count > 1)) {
_at.cmd_start("AT+CGACT=0,");
_at.write_int(_cid);
_at.cmd_stop_read_resp();
}
_at.restore_at_timeout();
_at.remove_urc_handler("+CGEV:");
call_network_cb(NSAPI_STATUS_DISCONNECTED);
return _at.unlock_return_error();
#endif
}
void AT_CellularNetwork::call_network_cb(nsapi_connection_status_t status)
{
if (_connect_status != status) {
@ -485,224 +195,6 @@ nsapi_connection_status_t AT_CellularNetwork::get_connection_status() const
return _connect_status;
}
nsapi_error_t AT_CellularNetwork::set_blocking(bool blocking)
{
#if NSAPI_PPP_AVAILABLE
return nsapi_ppp_set_blocking(blocking);
#else
return NSAPI_ERROR_OK;
#endif
}
#if NSAPI_PPP_AVAILABLE
void AT_CellularNetwork::ppp_status_cb(nsapi_event_t event, intptr_t parameter)
{
_connect_status = (nsapi_connection_status_t)parameter;
if (_connection_status_cb) {
_connection_status_cb(event, parameter);
}
}
#endif
nsapi_error_t AT_CellularNetwork::do_user_authentication()
{
// if user has defined user name and password we need to call CGAUTH before activating or modifying context
if (_pwd && _uname) {
if (!is_supported(AT_CGAUTH)) {
return NSAPI_ERROR_UNSUPPORTED;
}
_at.cmd_start("AT+CGAUTH=");
_at.write_int(_cid);
_at.write_int(_authentication_type);
_at.write_string(_uname);
_at.write_string(_pwd);
_at.cmd_stop_read_resp();
if (_at.get_last_error() != NSAPI_ERROR_OK) {
return NSAPI_ERROR_AUTH_FAILURE;
}
}
return NSAPI_ERROR_OK;
}
bool AT_CellularNetwork::set_new_context(int cid)
{
nsapi_ip_stack_t tmp_stack = _ip_stack_type_requested;
if (tmp_stack == DEFAULT_STACK) {
bool modem_supports_ipv6 = get_modem_stack_type(IPV6_STACK);
bool modem_supports_ipv4 = get_modem_stack_type(IPV4_STACK);
if (modem_supports_ipv6 && modem_supports_ipv4) {
tmp_stack = IPV4V6_STACK;
} else if (modem_supports_ipv6) {
tmp_stack = IPV6_STACK;
} else if (modem_supports_ipv4) {
tmp_stack = IPV4_STACK;
}
}
char pdp_type[8 + 1] = {0};
switch (tmp_stack) {
case IPV4_STACK:
strncpy(pdp_type, "IP", sizeof(pdp_type));
break;
case IPV6_STACK:
strncpy(pdp_type, "IPV6", sizeof(pdp_type));
break;
case IPV4V6_STACK:
strncpy(pdp_type, "IPV6", sizeof(pdp_type)); // try first IPV6 and then fall-back to IPv4
break;
default:
break;
}
//apn: "If the value is null or omitted, then the subscription value will be requested."
bool success = false;
_at.cmd_start("AT+CGDCONT=");
_at.write_int(cid);
_at.write_string(pdp_type);
_at.write_string(_apn);
_at.cmd_stop_read_resp();
success = (_at.get_last_error() == NSAPI_ERROR_OK);
// 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");
_at.write_string(_apn);
_at.cmd_stop_read_resp();
success = (_at.get_last_error() == NSAPI_ERROR_OK);
}
if (success) {
_ip_stack_type = tmp_stack;
_cid = cid;
_new_context_set = true;
tr_info("New PDP context id %d was created", _cid);
}
return success;
}
bool AT_CellularNetwork::get_context()
{
if (_apn) {
tr_debug("APN in use: %s", _apn);
} else {
tr_debug("NO APN");
}
_at.cmd_start("AT+CGDCONT?");
_at.cmd_stop();
_at.resp_start("+CGDCONT:");
_cid = -1;
int cid_max = 0; // needed when creating new context
char apn[MAX_ACCESSPOINT_NAME_LENGTH];
int apn_len = 0;
bool modem_supports_ipv6 = get_modem_stack_type(IPV6_STACK);
bool modem_supports_ipv4 = get_modem_stack_type(IPV4_STACK);
while (_at.info_resp()) {
int cid = _at.read_int();
if (cid > cid_max) {
cid_max = cid;
}
char pdp_type_from_context[10];
int pdp_type_len = _at.read_string(pdp_type_from_context, sizeof(pdp_type_from_context) - 1);
if (pdp_type_len > 0) {
apn_len = _at.read_string(apn, sizeof(apn) - 1);
if (apn_len >= 0) {
if (_apn && (strcmp(apn, _apn) != 0)) {
continue;
}
nsapi_ip_stack_t pdp_stack = string_to_stack_type(pdp_type_from_context);
// Accept dual PDP context for IPv4/IPv6 only modems
if (pdp_stack != DEFAULT_STACK && (get_modem_stack_type(pdp_stack) || pdp_stack == IPV4V6_STACK)) {
if (_ip_stack_type_requested == IPV4_STACK) {
if (pdp_stack == IPV4_STACK || pdp_stack == IPV4V6_STACK) {
_ip_stack_type = _ip_stack_type_requested;
_cid = cid;
break;
}
} else if (_ip_stack_type_requested == IPV6_STACK) {
if (pdp_stack == IPV6_STACK || pdp_stack == IPV4V6_STACK) {
_ip_stack_type = _ip_stack_type_requested;
_cid = cid;
break;
}
} else {
// requested dual stack or stack is not specified
// If dual PDP need to check for IPV4 or IPV6 modem support. Prefer IPv6.
if (pdp_stack == IPV4V6_STACK) {
if (modem_supports_ipv6) {
_ip_stack_type = IPV6_STACK;
_cid = cid;
break;
} else if (modem_supports_ipv4) {
_ip_stack_type = IPV4_STACK;
_cid = cid;
break;
}
// If PDP is IPV4 or IPV6 they are already checked if supported
} else {
_ip_stack_type = pdp_stack;
_cid = cid;
if (pdp_stack == IPV6_STACK) {
break;
}
if (pdp_stack == IPV4_STACK && !modem_supports_ipv6) {
break;
}
}
}
}
}
}
}
_at.resp_stop();
if (_cid == -1) { // no suitable context was found so create a new one
if (!set_new_context(cid_max + 1)) {
return false;
}
}
// save the apn
if (apn_len > 0 && !_apn) {
_apn = (char *)malloc(apn_len * sizeof(char) + 1);
if (_apn) {
memcpy(_apn, apn, apn_len + 1);
} else {
return false;
}
}
tr_debug("Context id %d", _cid);
return true;
}
nsapi_ip_stack_t AT_CellularNetwork::string_to_stack_type(const char *pdp_type)
{
nsapi_ip_stack_t stack = DEFAULT_STACK;
int len = strlen(pdp_type);
if (len == 6 && memcmp(pdp_type, "IPV4V6", len) == 0) {
stack = IPV4V6_STACK;
} else if (len == 4 && memcmp(pdp_type, "IPV6", len) == 0) {
stack = IPV6_STACK;
} else if (len == 2 && memcmp(pdp_type, "IP", len) == 0) {
stack = IPV4_STACK;
}
return stack;
}
nsapi_error_t AT_CellularNetwork::set_registration_urc(RegistrationType type, bool urc_on)
{
int index = (int)type;
@ -758,7 +250,7 @@ nsapi_error_t AT_CellularNetwork::set_registration(const char *plmn)
}
} else {
tr_debug("Manual network registration to %s", plmn);
_at.cmd_start("AT+COPS=4,2,");
_at.cmd_start("AT+COPS=1,2,");
_at.write_string(plmn);
_at.cmd_stop_read_resp();
}
@ -815,7 +307,7 @@ AT_CellularNetwork::RegistrationMode AT_CellularNetwork::has_registration(Regist
return RegistrationModeLAC;
}
nsapi_error_t AT_CellularNetwork::set_attach(int /*timeout*/)
nsapi_error_t AT_CellularNetwork::set_attach()
{
_at.lock();
@ -863,76 +355,6 @@ nsapi_error_t AT_CellularNetwork::detach()
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_apn_backoff_timer(int &backoff_timer)
{
// If apn is set
if (_apn) {
_at.lock();
_at.cmd_start("AT+CABTRDP=");
_at.write_string(_apn);
_at.cmd_stop();
_at.resp_start("+CABTRDP:");
if (_at.info_resp()) {
_at.skip_param();
backoff_timer = _at.read_int();
}
_at.resp_stop();
return _at.unlock_return_error();
}
return NSAPI_ERROR_PARAMETER;
}
NetworkStack *AT_CellularNetwork::get_stack()
{
#if NSAPI_PPP_AVAILABLE
// use lwIP/PPP if modem does not have IP stack
if (!_stack) {
_stack = nsapi_ppp_get_stack();
}
#endif
return _stack;
}
const char *AT_CellularNetwork::get_ip_address()
{
#if NSAPI_PPP_AVAILABLE
return nsapi_ppp_get_ip_addr(_at.get_file_handle());
#else
if (!_stack) {
_stack = get_stack();
}
if (_stack) {
return _stack->get_ip_address();
}
return NULL;
#endif
}
nsapi_error_t AT_CellularNetwork::set_stack_type(nsapi_ip_stack_t stack_type)
{
if (get_modem_stack_type(stack_type)) {
_ip_stack_type_requested = stack_type;
return NSAPI_ERROR_OK;
} else {
return NSAPI_ERROR_PARAMETER;
}
}
nsapi_ip_stack_t AT_CellularNetwork::get_stack_type()
{
return _ip_stack_type;
}
bool AT_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
if (requested_stack == _ip_stack_type) {
return true;
} else {
return false;
}
}
nsapi_error_t AT_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opsAct)
{
return NSAPI_ERROR_UNSUPPORTED;
@ -966,15 +388,6 @@ nsapi_error_t AT_CellularNetwork::scan_plmn(operList_t &operators, int &opsCount
while (_at.info_elem('(')) {
op = operators.add_new();
if (!op) {
tr_warn("Could not allocate new operator");
_at.resp_stop();
_at.unlock();
operators.delete_all();
opsCount = 0;
return NSAPI_ERROR_NO_MEMORY;
}
op->op_status = (operator_t::Status)_at.read_int();
_at.read_string(op->op_long, sizeof(op->op_long));
_at.read_string(op->op_short, sizeof(op->op_short));
@ -1001,10 +414,11 @@ nsapi_error_t AT_CellularNetwork::scan_plmn(operList_t &operators, int &opsCount
nsapi_error_t AT_CellularNetwork::set_ciot_optimization_config(Supported_UE_Opt supported_opt,
Preferred_UE_Opt preferred_opt)
{
_at.lock();
_at.cmd_start("AT+CCIOTOPT=");
_at.write_int(_cid);
_at.write_int(0); // disable urc
_at.write_int(supported_opt);
_at.write_int(preferred_opt);
_at.cmd_stop_read_resp();
@ -1032,138 +446,6 @@ nsapi_error_t AT_CellularNetwork::get_ciot_optimization_config(Supported_UE_Opt
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_rate_control(
CellularNetwork::RateControlExceptionReports &reports,
CellularNetwork::RateControlUplinkTimeUnit &timeUnit, int &uplinkRate)
{
_at.lock();
_at.cmd_start("AT+CGAPNRC=");
_at.write_int(_cid);
_at.cmd_stop();
_at.resp_start("+CGAPNRC:");
_at.read_int();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
bool comma_found = true;
int next_element = _at.read_int();
if (next_element >= 0) {
reports = (RateControlExceptionReports)next_element;
tr_debug("reports %d", reports);
next_element = _at.read_int();
} else {
comma_found = false;
}
if (comma_found && next_element >= 0) {
timeUnit = (RateControlUplinkTimeUnit)next_element;
tr_debug("time %d", timeUnit);
next_element = _at.read_int();
} else {
comma_found = false;
}
if (comma_found && next_element >= 0) {
uplinkRate = next_element;
tr_debug("rate %d", uplinkRate);
}
}
_at.resp_stop();
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_pdpcontext_params(pdpContextList_t &params_list)
{
const int ipv6_subnet_size = 128;
const int max_ipv6_size = 64;
char *ipv6_and_subnetmask = (char *)malloc(ipv6_subnet_size);
if (!ipv6_and_subnetmask) {
return NSAPI_ERROR_NO_MEMORY;
}
char *temp = (char *)malloc(max_ipv6_size);
if (!temp) {
free(ipv6_and_subnetmask);
return NSAPI_ERROR_NO_MEMORY;
}
_at.lock();
_at.cmd_start("AT+CGCONTRDP=");
_at.write_int(_cid);
_at.cmd_stop();
_at.resp_start("+CGCONTRDP:");
pdpcontext_params_t *params = NULL;
while (_at.info_resp()) { // response can be zero or many +CGDCONT lines
params = params_list.add_new();
if (!params) {
tr_warn("Could not allocate new pdpcontext_params_t");
_at.resp_stop();
_at.unlock();
params_list.delete_all();
free(temp);
free(ipv6_and_subnetmask);
return NSAPI_ERROR_NO_MEMORY;
}
params->cid = _at.read_int();
params->bearer_id = _at.read_int();
_at.read_string(params->apn, sizeof(params->apn));
// rest are optional params
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->local_addr, sizeof(params->local_addr), params->local_subnet_mask, sizeof(params->local_subnet_mask));
ipv6_and_subnetmask[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->gateway_addr, sizeof(params->gateway_addr), temp, max_ipv6_size);
prefer_ipv6(params->gateway_addr, sizeof(params->gateway_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->dns_primary_addr, sizeof(params->dns_primary_addr), temp, max_ipv6_size);
prefer_ipv6(params->dns_primary_addr, sizeof(params->dns_primary_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->dns_secondary_addr, sizeof(params->dns_secondary_addr), temp, max_ipv6_size);
prefer_ipv6(params->dns_secondary_addr, sizeof(params->dns_secondary_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->p_cscf_prim_addr, sizeof(params->p_cscf_prim_addr), temp, max_ipv6_size);
prefer_ipv6(params->p_cscf_prim_addr, sizeof(params->p_cscf_prim_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->p_cscf_sec_addr, sizeof(params->p_cscf_sec_addr), temp, max_ipv6_size);
prefer_ipv6(params->p_cscf_sec_addr, sizeof(params->p_cscf_sec_addr), temp, max_ipv6_size);
params->im_signalling_flag = _at.read_int();
params->lipa_indication = _at.read_int();
params->ipv4_mtu = _at.read_int();
params->wlan_offload = _at.read_int();
params->local_addr_ind = _at.read_int();
params->non_ip_mtu = _at.read_int();
params->serving_plmn_rate_control_value = _at.read_int();
}
_at.resp_stop();
free(temp);
free(ipv6_and_subnetmask);
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_extended_signal_quality(int &rxlev, int &ber, int &rscp, int &ecno, int &rsrq, int &rsrp)
{
_at.lock();
@ -1256,13 +538,6 @@ nsapi_error_t AT_CellularNetwork::get_operator_names(operator_names_list &op_nam
operator_names_t *names = NULL;
while (_at.info_resp()) {
names = op_names.add_new();
if (!names) {
tr_warn("Could not allocate new operator_names_t");
_at.resp_stop();
_at.unlock();
op_names.delete_all();
return NSAPI_ERROR_NO_MEMORY;
}
_at.read_string(names->numeric, sizeof(names->numeric));
_at.read_string(names->alpha, sizeof(names->alpha));
}
@ -1271,6 +546,29 @@ nsapi_error_t AT_CellularNetwork::get_operator_names(operator_names_list &op_nam
return _at.unlock_return_error();
}
bool AT_CellularNetwork::is_active_context()
{
_at.lock();
bool active_found = false;
// read active contexts
_at.cmd_start("AT+CGACT?");
_at.cmd_stop();
_at.resp_start("+CGACT:");
while (_at.info_resp()) {
(void)_at.read_int(); // discard context id
if (_at.read_int() == 1) { // check state
tr_debug("Found active context");
active_found = true;
break;
}
}
_at.resp_stop();
_at.unlock();
return active_found;
}
nsapi_error_t AT_CellularNetwork::get_registration_params(registration_params_t &reg_params)
{
reg_params = _reg_params;

View File

@ -20,7 +20,6 @@
#include "CellularNetwork.h"
#include "AT_CellularBase.h"
#include "NetworkStack.h"
namespace mbed {
@ -33,7 +32,7 @@ namespace mbed {
/**
* Class AT_CellularNetwork
*
* Class for connecting to a network and getting information from it.
* Class for attaching to a network and getting information from it.
*/
class AT_CellularNetwork : public CellularNetwork, public AT_CellularBase {
@ -44,52 +43,22 @@ public:
// declare friend so it can access stack
friend class AT_CellularDevice;
public: // NetworkInterface
virtual nsapi_error_t set_credentials(const char *apn,
const char *username = 0, const char *password = 0);
virtual nsapi_error_t set_credentials(const char *apn, AuthenticationType type,
const char *username = 0, const char *password = 0);
virtual nsapi_error_t connect(const char *apn,
const char *username = 0, const char *password = 0);
virtual nsapi_error_t connect();
virtual nsapi_error_t disconnect();
protected:
virtual NetworkStack *get_stack();
public: // CellularNetwork
virtual nsapi_error_t init();
virtual nsapi_error_t activate_context();
virtual nsapi_error_t set_registration(const char *plmn = 0);
virtual nsapi_error_t get_network_registering_mode(NWRegisteringMode &mode);
virtual nsapi_error_t set_attach(int timeout = 10 * 1000);
virtual nsapi_error_t set_attach();
virtual nsapi_error_t get_attach(AttachStatus &status);
virtual nsapi_error_t detach();
virtual nsapi_error_t get_rate_control(CellularNetwork::RateControlExceptionReports &reports,
CellularNetwork::RateControlUplinkTimeUnit &time_unit, int &uplink_rate);
virtual nsapi_error_t get_apn_backoff_timer(int &backoff_timer);
virtual void attach(Callback<void(nsapi_event_t, intptr_t)> status_cb);
virtual nsapi_connection_status_t get_connection_status() const;
virtual nsapi_error_t set_blocking(bool blocking);
virtual const char *get_ip_address();
virtual nsapi_error_t set_access_technology(RadioAccessTechnology rat);
virtual nsapi_error_t scan_plmn(operList_t &operators, int &ops_count);
@ -100,12 +69,6 @@ public: // CellularNetwork
virtual nsapi_error_t get_ciot_optimization_config(Supported_UE_Opt &supported_opt,
Preferred_UE_Opt &preferred_opt);
virtual nsapi_error_t set_stack_type(nsapi_ip_stack_t stack_type);
virtual nsapi_ip_stack_t get_stack_type();
virtual nsapi_error_t get_pdpcontext_params(pdpContextList_t &params_list);
virtual nsapi_error_t get_extended_signal_quality(int &rxlev, int &ber, int &rscp, int &ecno, int &rsrq, int &rsrp);
virtual nsapi_error_t get_signal_quality(int &rssi, int &ber);
@ -118,17 +81,13 @@ public: // CellularNetwork
virtual nsapi_error_t get_operator_names(operator_names_list &op_names);
virtual bool is_active_context();
virtual nsapi_error_t get_registration_params(registration_params_t &reg_params);
virtual nsapi_error_t get_registration_params(RegistrationType type, registration_params_t &reg_params);
protected:
/** Check if modem supports the given stack type.
*
* @return true if supported
*/
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
/** Check if modem supports given registration type.
*
* @param reg_type enum RegistrationType
@ -149,13 +108,6 @@ protected:
*/
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology op_rat);
/** APN user authentication
*
* @return NSAPI_ERROR_OK on success
* NSAPI_ERROR_UNSUPPORTED on authentication not supported by cellular device
* NSAPI_ERROR_AUTH_FAILURE on authentication to network failed
*/
virtual nsapi_error_t do_user_authentication();
private:
// "NO CARRIER" urc
void urc_no_carrier();
@ -164,19 +116,6 @@ private:
void urc_cgreg();
void urc_cgev();
nsapi_ip_stack_t string_to_stack_type(const char *pdp_type);
void free_credentials();
nsapi_error_t open_data_channel();
bool get_context();
bool set_new_context(int cid);
nsapi_error_t delete_current_context();
// calls network callback only if status was changed, updates local connection status
void call_network_cb(nsapi_connection_status_t status);
void read_reg_params_and_compare(RegistrationType type);
void read_reg_params(registration_params_t &reg_params);
@ -185,27 +124,15 @@ private:
// Returns periodic tau(Table 10.5.163a/3GPP TS 24.008: GPRS Timer 3 information element) in seconds
int calculate_periodic_tau(const char *periodic_tau_string, int periodic_tau_length);
#if NSAPI_PPP_AVAILABLE
void ppp_status_cb(nsapi_event_t, intptr_t);
#endif
// calls network callback only if status was changed, updates local connection status
void call_network_cb(nsapi_connection_status_t status);
protected:
NetworkStack *_stack;
char *_apn;
char *_uname;
char *_pwd;
nsapi_ip_stack_t _ip_stack_type_requested;
nsapi_ip_stack_t _ip_stack_type;
int _cid;
Callback<void(nsapi_event_t, intptr_t)> _connection_status_cb;
RadioAccessTechnology _op_act;
AuthenticationType _authentication_type;
nsapi_connection_status_t _connect_status;
bool _new_context_set;
bool _is_context_active;
registration_params_t _reg_params;
mbed::Callback<void()> _urc_funcs[C_MAX];
};

View File

@ -294,11 +294,8 @@ char *AT_CellularSMS::create_pdu(const char *phone_number, const char *message,
// message 7-bit padded and it will be converted to hex so it will take twice as much space
totalPDULength += (message_length - (message_length / 8)) * 2;
char *pdu = (char *)calloc(totalPDULength, sizeof(char));
if (!pdu) {
return NULL;
}
char *pdu = new char[totalPDULength];
memset(pdu, 0, totalPDULength);
int x = 0;
// See more how to create PDU from 3GPP specification 23040
// first two define that we use service center number which is set with +CSCA
@ -386,7 +383,7 @@ char *AT_CellularSMS::create_pdu(const char *phone_number, const char *message,
// we might need to send zero length sms
if (message_length) {
if (pack_7_bit_gsm_and_hex(message, message_length, pdu + x, paddingBits) == 0) {
free(pdu);
delete [] pdu;
return NULL;
}
}
@ -501,7 +498,7 @@ nsapi_size_or_error_t AT_CellularSMS::send_sms(const char *phone_number, const c
_at.cmd_start(ESC);
_at.cmd_stop();
_at.unlock();
free(pdu_str);
delete [] pdu_str;
return msg_write_len;
}
@ -511,7 +508,7 @@ nsapi_size_or_error_t AT_CellularSMS::send_sms(const char *phone_number, const c
_at.resp_start("+CMGS:");
_at.resp_stop();
}
free(pdu_str);
delete [] pdu_str;
remaining_len -= concatenated_sms_length;
if (_at.get_last_error() != NSAPI_ERROR_OK) {
return _at.unlock_return_error();
@ -667,7 +664,8 @@ nsapi_size_or_error_t AT_CellularSMS::read_sms(sms_info_t *sms, char *buf, char
msg_len = _at.read_int();
if (msg_len > 0) {
pduSize = msg_len * 2 + 20; // *2 as it's hex encoded and +20 as service center number is not included in size given by CMGR
pdu = (char *)calloc(pduSize, sizeof(char));
pdu = new char[pduSize];
memset(pdu, 0, pduSize);
if (!pdu) {
_at.resp_stop();
return NSAPI_ERROR_NO_MEMORY;
@ -678,12 +676,12 @@ nsapi_size_or_error_t AT_CellularSMS::read_sms(sms_info_t *sms, char *buf, char
if (msg_len >= 0) { // we need to allow zero length messages
index += msg_len;
} else {
free(pdu);
delete [] pdu;
_at.resp_stop();
return -1;
}
}
free(pdu);
delete [] pdu;
}
}
}
@ -1062,7 +1060,8 @@ nsapi_error_t AT_CellularSMS::list_messages()
_at.skip_param(2); // <stat>,[<alpha>]
length = _at.read_int();
length = length * 2 + 20; // *2 as it's hex encoded and +20 as service center number is not included in size given by CMGL
pdu = (char *)calloc(length, sizeof(char));
pdu = new char[length];
memset(pdu, 0, length);
if (!pdu) {
delete info;
_at.resp_stop();
@ -1086,7 +1085,7 @@ nsapi_error_t AT_CellularSMS::list_messages()
delete info;
info = NULL;
}
free(pdu);
delete [] pdu;
pdu = NULL;
}
@ -1194,7 +1193,7 @@ uint16_t AT_CellularSMS::pack_7_bit_gsm_and_hex(const char *str, uint16_t len, c
return 0;
}
// convert to 7bit gsm first
char *gsm_str = (char *)malloc(len);
char *gsm_str = new char[len];
if (!gsm_str) {
return 0;
}
@ -1236,7 +1235,7 @@ uint16_t AT_CellularSMS::pack_7_bit_gsm_and_hex(const char *str, uint16_t len, c
i++;
}
free(gsm_str);
delete [] gsm_str;
return i;
}

View File

@ -21,17 +21,34 @@
#include <stdint.h>
#include "nsapi_types.h"
struct cell_callback_data_t {
nsapi_error_t error; /* possible error code */
int status_data; /* cellular_event_status related enum or other info in int format. Check cellular_event_status comments.*/
bool final_try; /* This flag is true if state machine is used and this was the last try. State machine does goes to idle. */
cell_callback_data_t()
{
error = NSAPI_ERROR_OK;
status_data = -1;
final_try = false;
}
};
/**
* Cellular specific event changes.
* Connect and disconnect are handled via NSAPI_EVENT_CONNECTION_STATUS_CHANGE
* All enum types have struct *cell_callback_data_t in intptr_t with possible error code in cell_callback_data_t.error.
* Most enum values also have some enum in cell_callback_data_t.enumeration, check comments below.
*/
typedef enum cellular_event_status {
CellularDeviceReady = NSAPI_EVENT_CELLULAR_STATUS_BASE, /* Modem is powered and ready to receive commands. No additional info in callback intptr_t. */
CellularSIMStatusChanged = NSAPI_EVENT_CELLULAR_STATUS_BASE + 1, /* SIM state changed, call SIM state. enum SimState as additional info callback intptr_t. See enum SimState in ../API/CellularSIM.h */
CellularRegistrationStatusChanged = NSAPI_EVENT_CELLULAR_STATUS_BASE + 2, /* Registering status changed. enum RegistrationStatus as additional info callback intptr_t. See enum RegistrationStatus in ../API/CellularNetwork.h */
CellularRegistrationTypeChanged = NSAPI_EVENT_CELLULAR_STATUS_BASE + 3, /* Registration type changed. enum RegistrationType as additional info callback intptr_t. See enum RegistrationType in ../API/CellularNetwork.h */
CellularCellIDChanged = NSAPI_EVENT_CELLULAR_STATUS_BASE + 4, /* Network Cell ID have changed. int cellid as additional info callback intptr_t. */
CellularRadioAccessTechnologyChanged = NSAPI_EVENT_CELLULAR_STATUS_BASE + 5, /* Network roaming status have changed. enum RadioAccessTechnology as additional info callback intptr_t. See enum RadioAccessTechnology in ../API/CellularNetwork.h */
CellularDeviceReady = NSAPI_EVENT_CELLULAR_STATUS_BASE, /* Modem is powered and ready to receive commands. cell_callback_data_t.status_data will be -1 */
CellularSIMStatusChanged = NSAPI_EVENT_CELLULAR_STATUS_BASE + 1, /* SIM state changed. cell_callback_data_t.status_data will be enum SimState. See enum SimState in ../API/CellularSIM.h*/
CellularRegistrationStatusChanged = NSAPI_EVENT_CELLULAR_STATUS_BASE + 2, /* Registering status changed. cell_callback_data_t.status_data will be enum RegistrationStatus. See enum RegistrationStatus in ../API/CellularNetwork.h*/
CellularRegistrationTypeChanged = NSAPI_EVENT_CELLULAR_STATUS_BASE + 3, /* Registration type changed. cell_callback_data_t.status_data will be enum RegistrationType. See enum RegistrationType in ../API/CellularNetwork.h*/
CellularCellIDChanged = NSAPI_EVENT_CELLULAR_STATUS_BASE + 4, /* Network Cell ID have changed. cell_callback_data_t.status_data will be int cellid*/
CellularRadioAccessTechnologyChanged = NSAPI_EVENT_CELLULAR_STATUS_BASE + 5, /* Network roaming status have changed. cell_callback_data_t.status_data will be enum RadioAccessTechnology See enum RadioAccessTechnology in ../API/CellularNetwork.h*/
CellularAttachNetwork = NSAPI_EVENT_CELLULAR_STATUS_BASE + 6, /* cell_callback_data_t.status_data will be enum AttachStatus. See enum AttachStatus in ../API/CellularNetwork.h */
CellularActivatePDPContext = NSAPI_EVENT_CELLULAR_STATUS_BASE + 7, /* NSAPI_ERROR_OK in cell_callback_data_t.error on successfully PDP Context activated or negative error */
} cellular_connection_status_t;
#endif // CELLULAR_COMMON_

View File

@ -0,0 +1,38 @@
/*
* 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 "CellularContext.h"
namespace mbed {
#ifdef CELLULAR_DEVICE
MBED_WEAK CellularContext *CellularContext::get_default_instance()
{
// Uses default APN, uname, password from mbed_app.json
static CellularDevice *dev = CellularDevice::get_default_instance();
if (!dev) {
return NULL;
}
static CellularContext *context = dev->create_context();
return context;
}
#else
MBED_WEAK CellularContext *CellularContext::get_default_instance()
{
return NULL;
}
#endif // CELLULAR_DEVICE
} // namespace mbed

View File

@ -16,8 +16,13 @@
*/
#include "CellularDevice.h"
#include "EventQueue.h"
#include "CellularContext.h"
#include "CellularSIM.h"
#include "CellularUtil.h"
#include "CellularLog.h"
#include "CellularTargets.h"
#include "EventQueue.h"
#include "UARTSerial.h"
#ifdef CELLULAR_DEVICE
#include CELLULAR_STRINGIFY(CELLULAR_DEVICE.h)
@ -28,8 +33,14 @@ namespace mbed {
#ifdef CELLULAR_DEVICE
MBED_WEAK CellularDevice *CellularDevice::get_default_instance()
{
static events::EventQueue event_queue(4 * EVENTS_EVENT_SIZE);
static CELLULAR_DEVICE device(event_queue);
static UARTSerial serial(MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE);
#if DEVICE_SERIAL_FC
if (MDMRTS != NC && MDMCTS != NC) {
tr_info("_USING flow control, MDMRTS: %d MDMCTS: %d", MDMRTS, MDMCTS);
serial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS);
}
#endif
static CELLULAR_DEVICE device(&serial);
return &device;
}
#else
@ -39,14 +50,151 @@ MBED_WEAK CellularDevice *CellularDevice::get_default_instance()
}
#endif // CELLULAR_DEVICE
CellularDevice::CellularDevice() : _network_ref_count(0), _sms_ref_count(0), _power_ref_count(0), _sim_ref_count(0),
_info_ref_count(0)
CellularDevice::CellularDevice(FileHandle *fh) : _network_ref_count(0), _sms_ref_count(0), _power_ref_count(0), _sim_ref_count(0),
_info_ref_count(0), _fh(fh), _queue(5 * EVENTS_EVENT_SIZE), _state_machine(0), _nw(0)
{
set_sim_pin(NULL);
set_plmn(NULL);
}
CellularDevice::~CellularDevice()
{
}
events::EventQueue *CellularDevice::get_queue() const
void CellularDevice::stop()
{
MBED_ASSERT(_state_machine);
_state_machine->stop();
}
events::EventQueue *CellularDevice::get_queue()
{
return &_queue;
}
CellularContext *CellularDevice::get_context_list() const
{
return NULL;
}
void CellularDevice::set_sim_pin(const char *sim_pin)
{
if (sim_pin) {
strncpy(_sim_pin, sim_pin, sizeof(_sim_pin));
_sim_pin[sizeof(_sim_pin) - 1] = '\0';
} else {
memset(_sim_pin, 0, sizeof(_sim_pin));
}
}
void CellularDevice::set_plmn(const char *plmn)
{
if (plmn) {
strncpy(_plmn, plmn, sizeof(_plmn));
_plmn[sizeof(_plmn) - 1] = '\0';
} else {
memset(_plmn, 0, sizeof(_plmn));
}
}
nsapi_error_t CellularDevice::set_device_ready()
{
return start_state_machine(CellularStateMachine::STATE_DEVICE_READY);
}
nsapi_error_t CellularDevice::set_sim_ready()
{
return start_state_machine(CellularStateMachine::STATE_SIM_PIN);
}
nsapi_error_t CellularDevice::register_to_network()
{
return start_state_machine(CellularStateMachine::STATE_REGISTERING_NETWORK);
}
nsapi_error_t CellularDevice::attach_to_network()
{
return start_state_machine(CellularStateMachine::STATE_ATTACHING_NETWORK);
}
nsapi_error_t CellularDevice::create_state_machine()
{
if (!_state_machine) {
_state_machine = new CellularStateMachine(*this, *get_queue());
_state_machine->set_cellular_callback(callback(this, &CellularDevice::cellular_callback));
return _state_machine->start_dispatch();
}
return NSAPI_ERROR_OK;
}
nsapi_error_t CellularDevice::start_state_machine(CellularStateMachine::CellularState target_state)
{
_mutex.lock();
nsapi_error_t err = create_state_machine();
if (err) {
return err;
}
CellularStateMachine::CellularState current_state, targeted_state;
bool is_running = _state_machine->get_current_status(current_state, targeted_state);
if (current_state >= target_state) { // can stm be in this state but failed?
_mutex.unlock();
return NSAPI_ERROR_ALREADY;
} else if (is_running && targeted_state >= target_state) {
_mutex.unlock();
return NSAPI_ERROR_IN_PROGRESS;
}
err = _state_machine->run_to_state(target_state);
_mutex.unlock();
return err;
}
void CellularDevice::cellular_callback(nsapi_event_t ev, intptr_t ptr)
{
if (ev >= NSAPI_EVENT_CELLULAR_STATUS_BASE && ev <= NSAPI_EVENT_CELLULAR_STATUS_END) {
cell_callback_data_t *ptr_data = (cell_callback_data_t *)ptr;
tr_debug("Device: network_callback called with event: %d, err: %d, data: %d", ev, ptr_data->error, ptr_data->status_data);
cellular_connection_status_t cell_ev = (cellular_connection_status_t)ev;
if (cell_ev == CellularRegistrationStatusChanged && _state_machine) {
// broadcast only network registration changes to state machine
_state_machine->cellular_event_changed(ev, ptr);
}
if (cell_ev == CellularDeviceReady && ptr_data->error == NSAPI_ERROR_OK) {
// Here we can create mux and give new filehandles as mux reserves the one what was in use.
// if mux we would need to set new filehandle:_state_machine->set_filehandle( get fh from mux);
_nw = open_network(_fh);
// Attach to network so we can get update status from the network
_nw->attach(callback(this, &CellularDevice::cellular_callback));
if (strlen(_plmn)) {
_state_machine->set_plmn(_plmn);
}
} else if (cell_ev == CellularSIMStatusChanged && ptr_data->error == NSAPI_ERROR_OK &&
ptr_data->status_data == CellularSIM::SimStatePinNeeded) {
if (strlen(_sim_pin)) {
_state_machine->set_sim_pin(_sim_pin);
}
}
} else {
tr_debug("Device: network_callback called with event: %d, ptr: %d", ev, ptr);
if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE && ptr == NSAPI_STATUS_DISCONNECTED) {
// we have been disconnected, reset state machine so that application can start connect sequence again
if (_state_machine) {
_state_machine->reset();
}
}
}
// broadcast network and cellular changes to state machine and CellularContext.
CellularContext *curr = get_context_list();
while (curr) {
curr->cellular_callback(ev, ptr);
curr = curr->_next;
}
}
} // namespace mbed

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Arm Limited and affiliates.
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -15,17 +15,17 @@
* limitations under the License.
*/
#include "CellularConnectionFSM.h"
#ifdef CELLULAR_DEVICE
#include "CellularStateMachine.h"
#include "CellularDevice.h"
#include "CellularPower.h"
#include "CellularSIM.h"
#include "CellularLog.h"
#include "Thread.h"
#include "UARTSerial.h"
#ifndef MBED_TRACE_MAX_LEVEL
#define MBED_TRACE_MAX_LEVEL TRACE_LEVEL_INFO
#endif
#include "CellularLog.h"
#include "CellularCommon.h"
#include "CellularDevice.h"
#include "CellularUtil.h"
// timeout to wait for AT responses
#define TIMEOUT_POWER_ON (1*1000)
@ -39,14 +39,17 @@
#define RETRY_COUNT_DEFAULT 3
const int STM_STOPPED = -99;
namespace mbed {
CellularConnectionFSM::CellularConnectionFSM() :
_serial(0), _state(STATE_INIT), _next_state(_state), _status_callback(0), _event_status_cb(0), _network(0), _power(0), _sim(0),
_queue(8 * EVENTS_EVENT_SIZE), _queue_thread(0), _cellularDevice(0), _retry_count(0), _event_timeout(-1),
_at_queue(0), _event_id(0), _plmn(0), _command_success(false), _plmn_network_found(false)
CellularStateMachine::CellularStateMachine(CellularDevice &device, events::EventQueue &queue) :
_cellularDevice(device), _state(STATE_INIT), _next_state(_state), _target_state(_state),
_event_status_cb(0), _network(0), _power(0), _sim(0), _queue(queue), _queue_thread(0), _sim_pin(0),
_retry_count(0), _event_timeout(-1), _event_id(-1), _plmn(0), _command_success(false),
_plmn_network_found(false), _is_retry(false), _cb_data(), _current_event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE),
_active_context(false)
{
memset(_sim_pin, 0, sizeof(_sim_pin));
#if MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY == 0
_start_time = 0;
#else
@ -65,97 +68,59 @@ CellularConnectionFSM::CellularConnectionFSM() :
_retry_timeout_array[7] = 128; // if around two minutes was not enough then let's wait much longer
_retry_timeout_array[8] = 600;
_retry_timeout_array[9] = TIMEOUT_NETWORK_MAX;
_retry_array_length = MAX_RETRY_ARRAY_SIZE;
_retry_array_length = RETRY_ARRAY_SIZE;
}
CellularConnectionFSM::~CellularConnectionFSM()
CellularStateMachine::~CellularStateMachine()
{
stop();
}
void CellularConnectionFSM::stop()
void CellularStateMachine::reset()
{
_queue.cancel(_event_id);
_queue.break_dispatch();
_state = STATE_INIT;
_event_timeout = -1;
_event_id = -1;
_plmn_network_found = false;
_is_retry = false;
_active_context = false;
enter_to_state(STATE_INIT);
}
void CellularStateMachine::stop()
{
if (_queue_thread) {
_queue.break_dispatch();
_queue_thread->terminate();
delete _queue_thread;
_queue_thread = NULL;
}
if (_at_queue) {
_at_queue->chain(NULL);
_at_queue = NULL;
}
reset();
_event_id = STM_STOPPED;
if (_power) {
_cellularDevice->close_power();
_cellularDevice.close_power();
_power = NULL;
}
if (_network) {
_cellularDevice->close_network();
_network = NULL;
}
if (_sim) {
_cellularDevice->close_sim();
_cellularDevice.close_sim();
_sim = NULL;
}
_state = STATE_INIT;
_next_state = _state;
if (_network) {
_cellularDevice.close_network();
_network = NULL;
}
}
nsapi_error_t CellularConnectionFSM::init()
bool CellularStateMachine::power_on()
{
tr_info("CELLULAR_DEVICE: %s", CELLULAR_STRINGIFY(CELLULAR_DEVICE));
_cellularDevice = CellularDevice::get_default_instance();
if (!_cellularDevice) {
stop();
return NSAPI_ERROR_NO_MEMORY;
}
_power = _cellularDevice->open_power(_serial);
if (!_power) {
stop();
return NSAPI_ERROR_NO_MEMORY;
}
_network = _cellularDevice->open_network(_serial);
if (!_network) {
stop();
return NSAPI_ERROR_NO_MEMORY;
}
_sim = _cellularDevice->open_sim(_serial);
if (!_sim) {
stop();
return NSAPI_ERROR_NO_MEMORY;
}
_at_queue = _cellularDevice->get_queue();
if (!_at_queue) {
stop();
return NSAPI_ERROR_NO_MEMORY;
}
_at_queue->chain(&_queue);
_retry_count = 0;
_state = STATE_INIT;
_next_state = STATE_INIT;
return _network->init();
}
bool CellularConnectionFSM::power_on()
{
nsapi_error_t err = _power->on();
if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED) {
_cb_data.error = _power->on();
if (_cb_data.error != NSAPI_ERROR_OK && _cb_data.error != NSAPI_ERROR_UNSUPPORTED) {
tr_warn("Cellular start failed. Power off/on.");
err = _power->off();
if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED) {
_cb_data.error = _power->off();
if (_cb_data.error != NSAPI_ERROR_OK && _cb_data.error != NSAPI_ERROR_UNSUPPORTED) {
tr_error("Cellular power down failing after failed power up attempt!");
}
return false;
@ -163,46 +128,49 @@ bool CellularConnectionFSM::power_on()
return true;
}
void CellularConnectionFSM::set_sim_pin(const char *sim_pin)
void CellularStateMachine::set_sim_pin(const char *sim_pin)
{
strncpy(_sim_pin, sim_pin, sizeof(_sim_pin));
_sim_pin[sizeof(_sim_pin) - 1] = '\0';
_sim_pin = sim_pin;
}
void CellularConnectionFSM::set_plmn(const char *plmn)
void CellularStateMachine::set_plmn(const char *plmn)
{
_plmn = plmn;
}
bool CellularConnectionFSM::open_sim()
bool CellularStateMachine::open_sim()
{
if (!_sim) {
// can only fail with allocation with new and then it's critical error
_sim = _cellularDevice.open_sim();
}
CellularSIM::SimState state = CellularSIM::SimStateUnknown;
// wait until SIM is readable
// here you could add wait(secs) if you know start delay of your SIM
if (_sim->get_sim_state(state) != NSAPI_ERROR_OK) {
_cb_data.error = _sim->get_sim_state(state);
if (_cb_data.error != NSAPI_ERROR_OK) {
tr_info("Waiting for SIM (err while reading)...");
if (_event_status_cb) {
_event_status_cb((nsapi_event_t)CellularSIMStatusChanged, state);
}
return false;
}
// report current state so callback can set sim pin if needed
if (_event_status_cb) {
_event_status_cb((nsapi_event_t)CellularSIMStatusChanged, state);
_cb_data.status_data = state;
_event_status_cb((nsapi_event_t)CellularSIMStatusChanged, (intptr_t)&_cb_data);
}
if (state == CellularSIM::SimStatePinNeeded) {
if (strlen(_sim_pin)) {
tr_info("SIM pin required, entering pin");
nsapi_error_t err = _sim->set_pin(_sim_pin);
if (err) {
tr_error("SIM pin set failed with: %d, bailing out...", err);
tr_info("Entering PIN to open SIM");
_cb_data.error = _sim->set_pin(_sim_pin);
if (_cb_data.error) {
tr_error("SIM pin set failed with: %d", _cb_data.error);
}
} else {
// No sim pin provided even it's needed, stop state machine
tr_error("PIN required but No SIM pin provided.");
_retry_count = MAX_RETRY_ARRAY_SIZE;
_retry_count = RETRY_ARRAY_SIZE;
return false;
}
}
@ -210,7 +178,7 @@ bool CellularConnectionFSM::open_sim()
return state == CellularSIM::SimStateReady;
}
bool CellularConnectionFSM::is_registered()
bool CellularStateMachine::is_registered()
{
CellularNetwork::RegistrationStatus status;
bool is_registered = false;
@ -224,18 +192,20 @@ bool CellularConnectionFSM::is_registered()
}
}
return is_registered;
_cb_data.status_data = status;
return is_registered || _active_context;
}
bool CellularConnectionFSM::get_network_registration(CellularNetwork::RegistrationType type,
CellularNetwork::RegistrationStatus &status, bool &is_registered)
bool CellularStateMachine::get_network_registration(CellularNetwork::RegistrationType type,
CellularNetwork::RegistrationStatus &status, bool &is_registered)
{
is_registered = false;
bool is_roaming = false;
CellularNetwork::registration_params_t reg_params;
nsapi_error_t err = _network->get_registration_params(type, reg_params);
if (err != NSAPI_ERROR_OK) {
if (err != NSAPI_ERROR_UNSUPPORTED) {
_cb_data.error = _network->get_registration_params(type, reg_params);
if (_cb_data.error != NSAPI_ERROR_OK) {
if (_cb_data.error != NSAPI_ERROR_UNSUPPORTED) {
tr_warn("Get network registration failed (type %d)!", type);
}
return false;
@ -243,19 +213,19 @@ bool CellularConnectionFSM::get_network_registration(CellularNetwork::Registrati
status = reg_params._status;
switch (status) {
case CellularNetwork::RegisteredRoaming:
is_roaming = true;
is_roaming = true;// @suppress("No break at end of case")
// fall-through
case CellularNetwork::RegisteredHomeNetwork:
is_registered = true;
break;
case CellularNetwork::RegisteredSMSOnlyRoaming:
is_roaming = true;
is_roaming = true;// @suppress("No break at end of case")
// fall-through
case CellularNetwork::RegisteredSMSOnlyHome:
tr_warn("SMS only network registration!");
break;
case CellularNetwork::RegisteredCSFBNotPreferredRoaming:
is_roaming = true;
is_roaming = true; // @suppress("No break at end of case")
// fall-through
case CellularNetwork::RegisteredCSFBNotPreferredHome:
tr_warn("Not preferred network registration!");
@ -278,31 +248,36 @@ bool CellularConnectionFSM::get_network_registration(CellularNetwork::Registrati
return true;
}
void CellularConnectionFSM::report_failure(const char *msg)
void CellularStateMachine::report_failure(const char *msg)
{
tr_error("Cellular network failed: %s", msg);
if (_status_callback) {
_status_callback(_state, _next_state);
tr_error("Cellular stm failed with: %s", msg);
_event_id = -1;
if (_event_status_cb) {
_cb_data.final_try = true;
_event_status_cb(_current_event, (intptr_t)&_cb_data);
}
tr_error("Target state %s was not reached. Returning from state: %s", get_state_string(_target_state), get_state_string(_state));
}
const char *CellularConnectionFSM::get_state_string(CellularState state)
const char *CellularStateMachine::get_state_string(CellularState state) const
{
#if MBED_CONF_MBED_TRACE_ENABLE
static const char *strings[] = { "Init", "Power", "Device ready", "SIM pin", "Registering network", "Manual registering", "Attaching network", "Activating PDP Context", "Connecting network", "Connected"};
static const char *strings[STATE_MAX_FSM_STATE] = { "Init", "Power", "Device ready", "SIM pin", "Registering network", "Manual registering", "Attaching network"};
return strings[state];
#else
return NULL;
#endif // #if MBED_CONF_MBED_TRACE_ENABLE
}
bool CellularConnectionFSM::is_registered_to_plmn()
bool CellularStateMachine::is_registered_to_plmn()
{
int format;
CellularNetwork::operator_t op;
nsapi_error_t err = _network->get_operator_params(format, op);
if (err == NSAPI_ERROR_OK) {
_cb_data.error = _network->get_operator_params(format, op);
if (_cb_data.error == NSAPI_ERROR_OK) {
if (format == 2) {
// great, numeric format we can do comparison for that
if (strcmp(op.op_num, _plmn) == 0) {
@ -313,8 +288,8 @@ bool CellularConnectionFSM::is_registered_to_plmn()
// format was alpha, get operator names to do the comparing
CellularNetwork::operator_names_list names_list;
nsapi_error_t err = _network->get_operator_names(names_list);
if (err == NSAPI_ERROR_OK) {
_cb_data.error = _network->get_operator_names(names_list);
if (_cb_data.error == NSAPI_ERROR_OK) {
CellularNetwork::operator_names_t *op_names = names_list.get_head();
bool found_match = false;
while (op_names) {
@ -344,64 +319,38 @@ bool CellularConnectionFSM::is_registered_to_plmn()
return false;
}
nsapi_error_t CellularConnectionFSM::continue_from_state(CellularState state)
{
tr_info("Continue state from %s to %s", get_state_string((CellularConnectionFSM::CellularState)_state),
get_state_string((CellularConnectionFSM::CellularState)state));
_state = state;
_next_state = state;
_retry_count = 0;
if (!_queue.call_in(0, callback(this, &CellularConnectionFSM::event))) {
stop();
return NSAPI_ERROR_NO_MEMORY;
}
return NSAPI_ERROR_OK;
}
nsapi_error_t CellularConnectionFSM::continue_to_state(CellularState state)
{
MBED_ASSERT(_cellularDevice);
_retry_count = 0;
if (state < _state) {
_state = state;
} else {
// update next state so that we don't continue from previous state
_state = _next_state;
}
if (!_queue.call_in(0, callback(this, &CellularConnectionFSM::event))) {
stop();
return NSAPI_ERROR_NO_MEMORY;
}
return NSAPI_ERROR_OK;
}
void CellularConnectionFSM::enter_to_state(CellularState state)
void CellularStateMachine::enter_to_state(CellularState state)
{
_next_state = state;
_retry_count = 0;
_command_success = false;
_cb_data.error = NSAPI_ERROR_OK;
_cb_data.status_data = -1;
_cb_data.final_try = false;
}
void CellularConnectionFSM::retry_state_or_fail()
void CellularStateMachine::retry_state_or_fail()
{
if (++_retry_count < MAX_RETRY_ARRAY_SIZE) {
tr_debug("Retry State %s, retry %d/%d", get_state_string(_state), _retry_count, MAX_RETRY_ARRAY_SIZE);
if (++_retry_count < RETRY_ARRAY_SIZE) {
tr_debug("Retry State %s, retry %d/%d", get_state_string(_state), _retry_count, RETRY_ARRAY_SIZE);
_event_timeout = _retry_timeout_array[_retry_count];
_is_retry = true;
} else {
report_failure(get_state_string(_state));
return;
}
}
void CellularConnectionFSM::state_init()
void CellularStateMachine::state_init()
{
// we should check that if power is already on then we can jump to device ready state
_cellularDevice->set_timeout(TIMEOUT_POWER_ON);
_cellularDevice.set_timeout(TIMEOUT_POWER_ON);
tr_info("Cellular state init (timeout %d ms)", TIMEOUT_POWER_ON);
nsapi_error_t err = _power->is_device_ready();
if (err != NSAPI_ERROR_OK) {
if (!_power) {
_power = _cellularDevice.open_power();
}
_cb_data.error = _power->is_device_ready();
if (_cb_data.error != NSAPI_ERROR_OK) {
_event_timeout = _start_time;
tr_info("Init state, waiting %d ms before POWER state)", _start_time);
enter_to_state(STATE_POWER_ON);
@ -411,9 +360,9 @@ void CellularConnectionFSM::state_init()
}
}
void CellularConnectionFSM::state_power_on()
void CellularStateMachine::state_power_on()
{
_cellularDevice->set_timeout(TIMEOUT_POWER_ON);
_cellularDevice.set_timeout(TIMEOUT_POWER_ON);
tr_info("Cellular power ON (timeout %d ms)", TIMEOUT_POWER_ON);
if (power_on()) {
enter_to_state(STATE_DEVICE_READY);
@ -423,44 +372,52 @@ void CellularConnectionFSM::state_power_on()
}
}
bool CellularConnectionFSM::device_ready()
bool CellularStateMachine::device_ready()
{
if (_cellularDevice->init_module(_serial) != NSAPI_ERROR_OK) {
tr_info("Cellular device ready");
if (_cellularDevice.init_module() != NSAPI_ERROR_OK) {
return false;
}
tr_info("Cellular device ready");
if (_event_status_cb) {
_event_status_cb((nsapi_event_t)CellularDeviceReady, 0);
_event_status_cb((nsapi_event_t)CellularDeviceReady, (intptr_t)&_cb_data);
}
_power->remove_device_ready_urc_cb(mbed::callback(this, &CellularConnectionFSM::ready_urc_cb));
_cellularDevice->close_power();
_power->remove_device_ready_urc_cb(mbed::callback(this, &CellularStateMachine::ready_urc_cb));
_cellularDevice.close_power();
_power = NULL;
return true;
}
void CellularConnectionFSM::state_device_ready()
void CellularStateMachine::state_device_ready()
{
_cellularDevice->set_timeout(TIMEOUT_POWER_ON);
if (_power->set_at_mode() == NSAPI_ERROR_OK) {
_cellularDevice.set_timeout(TIMEOUT_POWER_ON);
_cb_data.error = _power->set_at_mode();
if (_cb_data.error == NSAPI_ERROR_OK) {
if (device_ready()) {
enter_to_state(STATE_SIM_PIN);
} else {
retry_state_or_fail();
}
} else {
if (_retry_count == 0) {
(void)_power->set_device_ready_urc_cb(mbed::callback(this, &CellularConnectionFSM::ready_urc_cb));
_power->set_device_ready_urc_cb(mbed::callback(this, &CellularStateMachine::ready_urc_cb));
}
retry_state_or_fail();
}
}
void CellularConnectionFSM::state_sim_pin()
void CellularStateMachine::state_sim_pin()
{
_cellularDevice->set_timeout(TIMEOUT_SIM_PIN);
_cellularDevice.set_timeout(TIMEOUT_SIM_PIN);
tr_info("Sim state (timeout %d ms)", TIMEOUT_SIM_PIN);
if (open_sim()) {
if (!_network) {
_network = _cellularDevice.open_network();
}
bool success = false;
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
if (!_network->set_registration_urc((CellularNetwork::RegistrationType)type, true)) {
_cb_data.error = _network->set_registration_urc((CellularNetwork::RegistrationType)type, true);
if (!_cb_data.error) {
success = true;
}
}
@ -469,6 +426,9 @@ void CellularConnectionFSM::state_sim_pin()
retry_state_or_fail();
return;
}
_active_context = false;
_active_context = _network->is_active_context(); // check if context was already activated
if (_plmn) {
enter_to_state(STATE_MANUAL_REGISTERING_NETWORK);
} else {
@ -479,134 +439,186 @@ void CellularConnectionFSM::state_sim_pin()
}
}
void CellularConnectionFSM::state_registering()
void CellularStateMachine::state_registering()
{
_cellularDevice->set_timeout(TIMEOUT_NETWORK);
_cellularDevice.set_timeout(TIMEOUT_NETWORK);
if (is_registered()) {
tr_info("Sending Registration changed from plmn");
_cb_data.status_data = CellularNetwork::AlreadyRegistered;
_cb_data.error = NSAPI_ERROR_OK;
_event_status_cb(_current_event, (intptr_t)&_cb_data);
// we are already registered, go to attach
enter_to_state(STATE_ATTACHING_NETWORK);
} else {
_cellularDevice->set_timeout(TIMEOUT_REGISTRATION);
_cellularDevice.set_timeout(TIMEOUT_REGISTRATION);
if (!_command_success) {
_command_success = (_network->set_registration() == NSAPI_ERROR_OK);
_cb_data.error = _network->set_registration();
_command_success = (_cb_data.error == NSAPI_ERROR_OK);
}
retry_state_or_fail();
}
}
// only used when _plmn is set
void CellularConnectionFSM::state_manual_registering_network()
void CellularStateMachine::state_manual_registering_network()
{
_cellularDevice->set_timeout(TIMEOUT_REGISTRATION);
_cellularDevice.set_timeout(TIMEOUT_REGISTRATION);
tr_info("state_manual_registering_network");
if (!_plmn_network_found) {
if (is_registered() && is_registered_to_plmn()) {
// we have to send registration changed event as network thinks that we are not registered even we have active PDP context
tr_info("Sending REgistration changed from plmn");
_cb_data.status_data = CellularNetwork::AlreadyRegistered;
_cb_data.error = NSAPI_ERROR_OK;
_event_status_cb(_current_event, (intptr_t)&_cb_data);
_plmn_network_found = true;
enter_to_state(STATE_ATTACHING_NETWORK);
} else {
if (!_command_success) {
_command_success = (_network->set_registration(_plmn) == NSAPI_ERROR_OK);
_cb_data.error = _network->set_registration(_plmn);
_command_success = (_cb_data.error == NSAPI_ERROR_OK);
}
retry_state_or_fail();
}
}
}
void CellularConnectionFSM::state_attaching()
void CellularStateMachine::state_attaching()
{
_cellularDevice->set_timeout(TIMEOUT_CONNECT);
if (_network->set_attach() == NSAPI_ERROR_OK) {
_cellularDevice->close_sim();
_cellularDevice.set_timeout(TIMEOUT_CONNECT);
_cb_data.error = _network->set_attach();
tr_info("CellularStateMachine::state_attaching(): %d", _cb_data.error);
if (_cb_data.error == NSAPI_ERROR_OK) {
_cellularDevice.close_sim();
_sim = NULL;
enter_to_state(STATE_ACTIVATING_PDP_CONTEXT);
if (_event_status_cb) {
_cb_data.status_data = CellularNetwork::Attached;
_event_status_cb(_current_event, (intptr_t)&_cb_data);
}
} else {
retry_state_or_fail();
}
}
void CellularConnectionFSM::state_activating_pdp_context()
void CellularStateMachine::continue_from_state(CellularState state)
{
_cellularDevice->set_timeout(TIMEOUT_CONNECT);
tr_info("Activate PDP Context (timeout %d ms)", TIMEOUT_CONNECT);
if (_network->activate_context() == NSAPI_ERROR_OK) {
// when using modems stack connect is synchronous
_next_state = STATE_CONNECTING_NETWORK;
_mutex.lock();
tr_info("Continue state from %s to %s", get_state_string((CellularStateMachine::CellularState)_state),
get_state_string((CellularStateMachine::CellularState)state));
_state = state;
enter_to_state(state);
_event_id = _queue.call_in(0, this, &CellularStateMachine::event);
if (!_event_id) {
_event_id = -1;
_cb_data.error = NSAPI_ERROR_NO_MEMORY;
report_failure("Failed to call queue.");
stop();
}
_mutex.unlock();
}
nsapi_error_t CellularStateMachine::run_to_state(CellularStateMachine::CellularState state)
{
_mutex.lock();
// call pre_event via queue so that it's in same thread and it's safe to decisions
int id = _queue.call_in(0, this, &CellularStateMachine::pre_event, state);
if (!id) {
stop();
_mutex.unlock();
return NSAPI_ERROR_NO_MEMORY;
}
_mutex.unlock();
return NSAPI_ERROR_OK;
}
void CellularStateMachine::pre_event(CellularState state)
{
tr_debug("CellularStateMachine::pre_event, state: %s, _target_state: %s, _event_id: %d", get_state_string(state), get_state_string(_target_state), _event_id);
if (_target_state < state) {
// new wanted state will not be achieved with current _target_state so update it
_target_state = state;
} else {
retry_state_or_fail();
// wanted state is already / will be achieved, return without launching new event
return;
}
// if _event_id is -1 it means that new event is not going to be launched so we must launch new event
if (_event_id == -1) {
if (!_cb_data.final_try) {
// update next state so that we don't continue from previous state if state machine was paused and then started again.
// but only if earlier try did not finish to failure, then we must continue from that state
_state = _next_state;
}
enter_to_state(_next_state);
_event_id = _queue.call_in(0, this, &CellularStateMachine::event);
if (!_event_id) {
_event_id = -1;
report_failure("Failed to call queue.");
stop();
}
}
}
void CellularConnectionFSM::state_connect_to_network()
bool CellularStateMachine::get_current_status(CellularStateMachine::CellularState &current_state, CellularStateMachine::CellularState &target_state)
{
_cellularDevice->set_timeout(TIMEOUT_CONNECT);
tr_info("Connect to cellular network (timeout %d ms)", TIMEOUT_CONNECT);
if (_network->connect() == NSAPI_ERROR_OK) {
_cellularDevice->set_timeout(TIMEOUT_NETWORK);
tr_debug("Connected to cellular network, set at timeout (timeout %d ms)", TIMEOUT_NETWORK);
// when using modems stack connect is synchronous
_next_state = STATE_CONNECTED;
} else {
retry_state_or_fail();
}
bool is_running;
_mutex.lock();
current_state = _state;
target_state = _target_state;
is_running = _event_id != -1;
_mutex.unlock();
return is_running;
}
void CellularConnectionFSM::state_connected()
{
_cellularDevice->set_timeout(TIMEOUT_NETWORK);
tr_debug("Cellular ready! (timeout %d ms)", TIMEOUT_NETWORK);
if (_status_callback) {
_status_callback(_state, _next_state);
}
}
void CellularConnectionFSM::event()
void CellularStateMachine::event()
{
tr_debug("CellularStateMachine::event(): %s", get_state_string(_state));
_event_timeout = -1;
_is_retry = false;
switch (_state) {
case STATE_INIT:
_current_event = (nsapi_event_t)CellularDeviceReady;
state_init();
break;
case STATE_POWER_ON:
_current_event = (nsapi_event_t)CellularDeviceReady;
state_power_on();
break;
case STATE_DEVICE_READY:
_current_event = (nsapi_event_t)CellularDeviceReady;
state_device_ready();
break;
case STATE_SIM_PIN:
_current_event = (nsapi_event_t)CellularSIMStatusChanged;
state_sim_pin();
break;
case STATE_REGISTERING_NETWORK:
_current_event = (nsapi_event_t)CellularRegistrationStatusChanged;
state_registering();
break;
case STATE_MANUAL_REGISTERING_NETWORK:
_current_event = (nsapi_event_t)CellularRegistrationStatusChanged;
state_manual_registering_network();
break;
case STATE_ATTACHING_NETWORK:
_current_event = (nsapi_event_t)CellularAttachNetwork;
state_attaching();
break;
case STATE_ACTIVATING_PDP_CONTEXT:
state_activating_pdp_context();
break;
case STATE_CONNECTING_NETWORK:
state_connect_to_network();
break;
case STATE_CONNECTED:
state_connected();
break;
default:
MBED_ASSERT(0);
break;
}
if ((_target_state == _state && _cb_data.error == NSAPI_ERROR_OK && !_is_retry) || _event_id == STM_STOPPED) {
tr_info("Target state reached: %s, _cb_data.error: %d, _event_id: %d", get_state_string(_target_state), _cb_data.error, _event_id);
_event_id = -1;
return;
}
if (_next_state != _state || _event_timeout >= 0) {
if (_next_state != _state) { // state exit condition
tr_info("Cellular state from %s to %s", get_state_string((CellularConnectionFSM::CellularState)_state),
get_state_string((CellularConnectionFSM::CellularState)_next_state));
if (_status_callback) {
if (!_status_callback(_state, _next_state)) {
return;
}
}
tr_info("Cellular state from %s to %s", get_state_string((CellularStateMachine::CellularState)_state),
get_state_string((CellularStateMachine::CellularState)_next_state));
} else {
tr_info("Cellular event in %d seconds", _event_timeout);
}
@ -614,23 +626,20 @@ void CellularConnectionFSM::event()
if (_event_timeout == -1) {
_event_timeout = 0;
}
_event_id = _queue.call_in(_event_timeout * 1000, callback(this, &CellularConnectionFSM::event));
_event_id = _queue.call_in(_event_timeout * 1000, callback(this, &CellularStateMachine::event));
if (!_event_id) {
_cb_data.error = NSAPI_ERROR_NO_MEMORY;
report_failure("Cellular event failure!");
return;
}
}
}
nsapi_error_t CellularConnectionFSM::start_dispatch()
nsapi_error_t CellularStateMachine::start_dispatch()
{
MBED_ASSERT(!_queue_thread);
_queue_thread = new rtos::Thread(osPriorityNormal, 2048, NULL, "cellular_fsm");
if (!_queue_thread) {
stop();
return NSAPI_ERROR_NO_MEMORY;
}
_queue_thread = new rtos::Thread(osPriorityNormal, 2048, NULL, "stm_queue");
if (_queue_thread->start(callback(&_queue, &events::EventQueue::dispatch_forever)) != osOK) {
stop();
return NSAPI_ERROR_NO_MEMORY;
@ -639,34 +648,24 @@ nsapi_error_t CellularConnectionFSM::start_dispatch()
return NSAPI_ERROR_OK;
}
void CellularConnectionFSM::set_serial(UARTSerial *serial)
void CellularStateMachine::set_cellular_callback(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
{
_serial = serial;
}
void CellularConnectionFSM::set_callback(mbed::Callback<bool(int, int)> status_callback)
{
_status_callback = status_callback;
}
void CellularConnectionFSM::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
{
MBED_ASSERT(_network);
_event_status_cb = status_cb;
if (status_cb) {
_network->attach(callback(this, &CellularConnectionFSM::network_callback));
} else {
_network->attach(NULL);
}
}
void CellularConnectionFSM::network_callback(nsapi_event_t ev, intptr_t ptr)
void CellularStateMachine::cellular_event_changed(nsapi_event_t ev, intptr_t ptr)
{
tr_info("FSM: network_callback called with event: %d, intptr: %d, _state: %s", ev, ptr, get_state_string(_state));
cell_callback_data_t *data = (cell_callback_data_t *)ptr;
if (ev >= NSAPI_EVENT_CELLULAR_STATUS_BASE && ev <= NSAPI_EVENT_CELLULAR_STATUS_END) {
tr_debug("FSM: cellular_event_changed called with event: %d, err: %d, data: %d _state: %s", ev, data->error, data->status_data, get_state_string(_state));
} else {
tr_debug("FSM: cellular_event_changed called with event: %d, ptr: %d _state: %s", ev, ptr, get_state_string(_state));
}
if ((cellular_connection_status_t)ev == CellularRegistrationStatusChanged &&
(_state == STATE_REGISTERING_NETWORK || _state == STATE_MANUAL_REGISTERING_NETWORK)) {
// expect packet data so only these states are valid
if (ptr == CellularNetwork::RegisteredHomeNetwork || ptr == CellularNetwork::RegisteredRoaming) {
if ((data->status_data == CellularNetwork::RegisteredHomeNetwork || data->status_data == CellularNetwork::RegisteredRoaming) && data->error == NSAPI_ERROR_OK) {
if (_plmn) {
if (is_registered_to_plmn()) {
if (!_plmn_network_found) {
@ -681,52 +680,25 @@ void CellularConnectionFSM::network_callback(nsapi_event_t ev, intptr_t ptr)
}
}
}
if (_event_status_cb) {
_event_status_cb(ev, ptr);
}
}
void CellularConnectionFSM::ready_urc_cb()
void CellularStateMachine::ready_urc_cb()
{
tr_debug("Device ready URC func called");
if (_state == STATE_DEVICE_READY && _power->set_at_mode() == NSAPI_ERROR_OK) {
tr_debug("State was STATE_DEVICE_READY and at mode ready, cancel state and move to next");
_queue.cancel(_event_id);
if (device_ready()) {
_queue.cancel(_event_id);
continue_from_state(STATE_SIM_PIN);
} else {
continue_from_state(STATE_DEVICE_READY);
}
}
}
events::EventQueue *CellularConnectionFSM::get_queue()
void CellularStateMachine::set_retry_timeout_array(uint16_t timeout[], int array_len)
{
return &_queue;
}
CellularNetwork *CellularConnectionFSM::get_network()
{
return _network;
}
CellularDevice *CellularConnectionFSM::get_device()
{
return _cellularDevice;
}
CellularSIM *CellularConnectionFSM::get_sim()
{
return _sim;
}
NetworkStack *CellularConnectionFSM::get_stack()
{
return _cellularDevice->get_stack();
}
void CellularConnectionFSM::set_retry_timeout_array(uint16_t timeout[], int array_len)
{
_retry_array_length = array_len > MAX_RETRY_ARRAY_SIZE ? MAX_RETRY_ARRAY_SIZE : array_len;
_retry_array_length = array_len > RETRY_ARRAY_SIZE ? RETRY_ARRAY_SIZE : array_len;
for (int i = 0; i < _retry_array_length; i++) {
_retry_timeout_array[i] = timeout[i];
@ -735,4 +707,3 @@ void CellularConnectionFSM::set_retry_timeout_array(uint16_t timeout[], int arra
} // namespace
#endif // CELLULAR_DEVICE

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Arm Limited and affiliates.
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -14,39 +14,43 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _CELLULAR_STATEMACHINE_H_
#define _CELLULAR_STATEMACHINE_H_
#ifndef _CELLULAR_CONNECTION_FSM_H
#define _CELLULAR_CONNECTION_FSM_H
#include "CellularTargets.h"
#if defined(CELLULAR_DEVICE) || defined(DOXYGEN_ONLY)
#include "UARTSerial.h"
#include "NetworkInterface.h"
#include "EventQueue.h"
#include "Thread.h"
#include "CellularNetwork.h"
#include "CellularPower.h"
#include "CellularSIM.h"
#include "CellularCommon.h"
#include "PlatformMutex.h"
namespace rtos {
class Thread;
}
namespace mbed {
class CellularPower;
class CellularSIM;
class CellularDevice;
const int PIN_SIZE = 8;
const int MAX_RETRY_ARRAY_SIZE = 10;
const int RETRY_ARRAY_SIZE = 10;
/** CellularConnectionFSM class
/** CellularStateMachine class
*
* Finite State Machine for connecting to cellular network
* Finite State Machine for attaching to cellular network. Used by CellularDevice.
*/
class CellularConnectionFSM {
public:
CellularConnectionFSM();
virtual ~CellularConnectionFSM();
class CellularStateMachine {
private:
// friend of CellularDevice so that it's the only way to close/delete this class.
friend class CellularDevice;
friend class AT_CellularDevice;
/** Constructor
*
* @param device reference to CellularDevice
* @param queue reference to queue used in state transitions
*/
CellularStateMachine(CellularDevice &device, events::EventQueue &queue);
~CellularStateMachine();
public:
/** Cellular connection states
*/
enum CellularState {
@ -57,75 +61,32 @@ public:
STATE_REGISTERING_NETWORK,
STATE_MANUAL_REGISTERING_NETWORK,
STATE_ATTACHING_NETWORK,
STATE_ACTIVATING_PDP_CONTEXT,
STATE_CONNECTING_NETWORK,
STATE_CONNECTED
STATE_MAX_FSM_STATE
};
public:
/** Initialize cellular device
* @remark Must be called before any other methods
* @return see nsapi_error_t, 0 on success
*/
nsapi_error_t init();
/** Set serial connection for cellular device
* @param serial UART driver
*/
void set_serial(UARTSerial *serial);
/** Set callback for state update
* @param status_callback function to call on state changes
*/
void set_callback(mbed::Callback<bool(int, int)> status_callback);
/** Register callback for status reporting
/** Register cellular specific for status changes
*
* The specified status callback function will be called on status changes
* on the network. The parameters on the callback are the event type and
* event-type dependent reason parameter.
* The specified status callback function will be called on device status changes.
* The parameters on the callback are the event type and event-type dependent reason parameter.
*
* @param status_cb The callback for status changes
*/
virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
/** Get event queue that can be chained to main event queue (or use start_dispatch)
* @return event queue
*/
events::EventQueue *get_queue();
void set_cellular_callback(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb);
/** Start event queue dispatching
* @return see nsapi_error_t, 0 on success
*/
nsapi_error_t start_dispatch();
/** Stop event queue dispatching and close cellular interfaces. After calling stop(), init() must be called
* before any other methods.
/** Stop event queue dispatching and close cellular interfaces.
*/
void stop();
/** Get cellular network interface
* @return network interface, NULL on failure
*/
CellularNetwork *get_network();
/** Get cellular device interface
* @return device interface, NULL on failure
*/
CellularDevice *get_device();
/** Get cellular sim interface. SIM interface is released when moving from STATE_ATTACHING_NETWORK to STATE_ACTIVATING_PDP_CONTEXT.
* After SIM interface is closed, this method returns NULL, and any instances fetched using this method are invalid.
* SIM interface can be created again using CellularDevice, which you can get with the method get_device().
* @return sim interface, NULL on failure
*/
CellularSIM *get_sim();
/** Change cellular connection to the target state
* @param state to continue. Default is to connect.
/** Runs state machine to connected state unless callback method set with set_state_callback return false to stop.
*
* @return see nsapi_error_t, 0 on success
*/
nsapi_error_t continue_to_state(CellularState state = STATE_CONNECTED);
nsapi_error_t run_to_state(CellularState state);
/** Set cellular device SIM PIN code
* @param sim_pin PIN code
@ -152,8 +113,27 @@ public:
* @param state state which is returned in string format
* @return string format of the given state
*/
const char *get_state_string(CellularState state);
const char *get_state_string(CellularState state) const;
/** Get the current status of the state machine. Thread safe.
*
* @param current_state
* @param target_state
* @return true if state machine is running, false is not
*
*/
bool get_current_status(CellularStateMachine::CellularState &current_state, CellularStateMachine::CellularState &target_state);
/** CellularDevice updates about network events and cellular events
*
* @param ev Event type
* @param ptr Event type specific data
*/
void cellular_event_changed(nsapi_event_t ev, intptr_t ptr);
/** Reset the state machine to init state. After reset state machine can be used again to run to wanted state.
*/
void reset();
private:
bool power_on();
bool open_sim();
@ -169,54 +149,46 @@ private:
void state_registering();
void state_manual_registering_network();
void state_attaching();
void state_activating_pdp_context();
void state_connect_to_network();
void state_connected();
void enter_to_state(CellularState state);
void retry_state_or_fail();
void network_callback(nsapi_event_t ev, intptr_t ptr);
nsapi_error_t continue_from_state(CellularState state);
void continue_from_state(CellularState state);
bool is_registered_to_plmn();
private:
friend class EasyCellularConnection;
NetworkStack *get_stack();
private:
void report_failure(const char *msg);
void event();
void ready_urc_cb();
void pre_event(CellularState state);
UARTSerial *_serial;
CellularDevice &_cellularDevice;
CellularState _state;
CellularState _next_state;
CellularState _target_state;
Callback<bool(int, int)> _status_callback;
Callback<void(nsapi_event_t, intptr_t)> _event_status_cb;
CellularNetwork *_network;
CellularPower *_power;
CellularSIM *_sim;
events::EventQueue _queue;
events::EventQueue &_queue;
rtos::Thread *_queue_thread;
CellularDevice *_cellularDevice;
char _sim_pin[PIN_SIZE + 1];
const char *_sim_pin;
int _retry_count;
int _start_time;
int _event_timeout;
uint16_t _retry_timeout_array[MAX_RETRY_ARRAY_SIZE];
uint16_t _retry_timeout_array[RETRY_ARRAY_SIZE];
int _retry_array_length;
events::EventQueue *_at_queue;
char _st_string[20];
int _event_id;
const char *_plmn;
bool _command_success;
bool _plmn_network_found;
bool _is_retry;
cell_callback_data_t _cb_data;
nsapi_event_t _current_event;
bool _active_context; // Is there any active context?
PlatformMutex _mutex;
};
} // namespace
#endif // CELLULAR_DEVICE || DOXYGEN
#endif // _CELLULAR_CONNECTION_FSM_H
#endif /* _CELLULAR_STATEMACHINE_H_ */

View File

@ -17,16 +17,18 @@
#include "GEMALTO_CINTERION_CellularNetwork.h"
#include "GEMALTO_CINTERION_Module.h"
#include "AT_CellularInformation.h"
#include "GEMALTO_CINTERION_CellularContext.h"
#include "GEMALTO_CINTERION.h"
#include "AT_CellularInformation.h"
#include "CellularLog.h"
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)
GEMALTO_CINTERION::GEMALTO_CINTERION(FileHandle *fh) : AT_CellularDevice(fh)
{
}
@ -39,9 +41,14 @@ AT_CellularNetwork *GEMALTO_CINTERION::open_network_impl(ATHandler &at)
return new GEMALTO_CINTERION_CellularNetwork(at);
}
nsapi_error_t GEMALTO_CINTERION::init_module(FileHandle *fh)
AT_CellularContext *GEMALTO_CINTERION::create_context_impl(ATHandler &at, const char *apn)
{
CellularInformation *information = open_information(fh);
return new GEMALTO_CINTERION_CellularContext(at, this, apn);
}
nsapi_error_t GEMALTO_CINTERION::init_module()
{
CellularInformation *information = open_information();
if (!information) {
return NSAPI_ERROR_NO_MEMORY;
}
@ -55,7 +62,7 @@ nsapi_error_t GEMALTO_CINTERION::init_module(FileHandle *fh)
return GEMALTO_CINTERION_Module::detect_model(model);
}
uint16_t GEMALTO_CINTERION::get_send_delay()
uint16_t GEMALTO_CINTERION::get_send_delay() const
{
return RESPONSE_TO_SEND_DELAY;
}

View File

@ -25,15 +25,15 @@ namespace mbed {
class GEMALTO_CINTERION : public AT_CellularDevice {
public:
GEMALTO_CINTERION(events::EventQueue &queue);
GEMALTO_CINTERION(FileHandle *fh);
virtual ~GEMALTO_CINTERION();
protected: // AT_CellularDevice
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
public: // CellularDevice
virtual nsapi_error_t init_module(FileHandle *fh);
virtual uint16_t get_send_delay();
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn);
public:
virtual nsapi_error_t init_module();
virtual uint16_t get_send_delay() const;
};
} // namespace mbed

View File

@ -0,0 +1,50 @@
/*
* 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 "GEMALTO_CINTERION_CellularContext.h"
#include "GEMALTO_CINTERION_CellularStack.h"
#include "GEMALTO_CINTERION_Module.h"
namespace mbed {
GEMALTO_CINTERION_CellularContext::GEMALTO_CINTERION_CellularContext(ATHandler &at, CellularDevice *device,
const char *apn) : AT_CellularContext(at, device, apn)
{
}
GEMALTO_CINTERION_CellularContext::~GEMALTO_CINTERION_CellularContext()
{
}
#if !NSAPI_PPP_AVAILABLE
NetworkStack *GEMALTO_CINTERION_CellularContext::get_stack()
{
if (!_stack) {
_stack = new GEMALTO_CINTERION_CellularStack(_at, _apn, _cid, _ip_stack_type);
}
return _stack;
}
#endif // NSAPI_PPP_AVAILABLE
bool GEMALTO_CINTERION_CellularContext::stack_type_supported(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);
}
} /* namespace mbed */

View File

@ -0,0 +1,38 @@
/*
* 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.
*/
#ifndef GEMALTO_CINTERION_CELLULARCONTEXT_H_
#define GEMALTO_CINTERION_CELLULARCONTEXT_H_
#include "AT_CellularContext.h"
namespace mbed {
class GEMALTO_CINTERION_CellularContext: public AT_CellularContext {
public:
GEMALTO_CINTERION_CellularContext(ATHandler &at, CellularDevice *device, const char *apn);
virtual ~GEMALTO_CINTERION_CellularContext();
protected:
#if !NSAPI_PPP_AVAILABLE
virtual NetworkStack *get_stack();
#endif // NSAPI_PPP_AVAILABLE
virtual bool stack_type_supported(nsapi_ip_stack_t requested_stack);
};
} /* namespace mbed */
#endif // GEMALTO_CINTERION_CELLULARCONTEXT_H_

View File

@ -16,7 +16,6 @@
*/
#include "GEMALTO_CINTERION_CellularNetwork.h"
#include "GEMALTO_CINTERION_CellularStack.h"
#include "GEMALTO_CINTERION_Module.h"
using namespace mbed;
@ -29,24 +28,6 @@ GEMALTO_CINTERION_CellularNetwork::~GEMALTO_CINTERION_CellularNetwork()
{
}
#if !NSAPI_PPP_AVAILABLE
NetworkStack *GEMALTO_CINTERION_CellularNetwork::get_stack()
{
if (!_stack) {
_stack = new GEMALTO_CINTERION_CellularStack(_at, _apn, _cid, _ip_stack_type);
}
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);
}
AT_CellularNetwork::RegistrationMode GEMALTO_CINTERION_CellularNetwork::has_registration(RegistrationType reg_type)
{
if (GEMALTO_CINTERION_Module::get_model() == GEMALTO_CINTERION_Module::ModelEMS31) {

View File

@ -28,14 +28,7 @@ public:
virtual ~GEMALTO_CINTERION_CellularNetwork();
protected:
#if !NSAPI_PPP_AVAILABLE
virtual NetworkStack *get_stack();
#endif // NSAPI_PPP_AVAILABLE
virtual RegistrationMode has_registration(RegistrationType reg_type);
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opsAct);
};

View File

@ -65,6 +65,8 @@ 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;
@ -163,9 +165,7 @@ nsapi_error_t GEMALTO_CINTERION_CellularStack::socket_close_impl(int sock_id)
_at.write_int(sock_id);
_at.write_string("srvType");
_at.write_string("none");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_stop_read_resp();
_at.restore_at_timeout();

View File

@ -18,6 +18,7 @@
#include "SARA4_PPP.h"
#include "SARA4_PPP_CellularNetwork.h"
#include "SARA4_PPP_CellularPower.h"
#include "SARA4_PPP_CellularContext.h"
using namespace mbed;
using namespace events;
@ -28,7 +29,7 @@ static const AT_CellularBase::SupportedFeature unsupported_features[] = {
AT_CellularBase::SUPPORTED_FEATURE_END_MARK
};
SARA4_PPP::SARA4_PPP(EventQueue &queue) : AT_CellularDevice(queue)
SARA4_PPP::SARA4_PPP(FileHandle *fh) : AT_CellularDevice(fh)
{
AT_CellularBase::set_unsupported_features(unsupported_features);
}
@ -47,3 +48,7 @@ AT_CellularPower *SARA4_PPP::open_power_impl(ATHandler &at)
return new SARA4_PPP_CellularPower(at);
}
AT_CellularContext *SARA4_PPP::create_context_impl(ATHandler &at, const char *apn)
{
return new SARA4_PPP_CellularContext(at, this, apn);
}

View File

@ -25,12 +25,13 @@ namespace mbed {
class SARA4_PPP : public AT_CellularDevice {
public:
SARA4_PPP(events::EventQueue &queue);
SARA4_PPP(FileHandle *fh);
virtual ~SARA4_PPP();
public: // CellularDevice
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
virtual AT_CellularPower *open_power_impl(ATHandler &at);
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn);
};
} // namespace mbed

View File

@ -0,0 +1,35 @@
/*
* 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 "SARA4_PPP_CellularContext.h"
namespace mbed {
SARA4_PPP_CellularContext::SARA4_PPP_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
AT_CellularContext(at, device, apn)
{
}
SARA4_PPP_CellularContext::~SARA4_PPP_CellularContext()
{
}
bool SARA4_PPP_CellularContext::stack_type_supported(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
} /* namespace mbed */

View File

@ -0,0 +1,35 @@
/*
* 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.
*/
#ifndef SARA4_PPP_CELLULARCONTEXT_H_
#define SARA4_PPP_CELLULARCONTEXT_H_
#include "AT_CellularContext.h"
namespace mbed {
class SARA4_PPP_CellularContext: public AT_CellularContext {
public:
SARA4_PPP_CellularContext(ATHandler &at, CellularDevice *device, const char *apn);
virtual ~SARA4_PPP_CellularContext();
protected:
virtual bool stack_type_supported(nsapi_ip_stack_t requested_stack);
};
} /* namespace mbed */
#endif // SARA4_PPP_CELLULARCONTEXT_H_

View File

@ -27,11 +27,6 @@ SARA4_PPP_CellularNetwork::~SARA4_PPP_CellularNetwork()
{
}
bool SARA4_PPP_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
AT_CellularNetwork::RegistrationMode SARA4_PPP_CellularNetwork::has_registration(RegistrationType reg_type)
{
return (reg_type == C_REG || reg_type == C_GREG) ? RegistrationModeLAC : RegistrationModeDisable;

View File

@ -28,8 +28,6 @@ public:
virtual ~SARA4_PPP_CellularNetwork();
protected:
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
virtual RegistrationMode has_registration(RegistrationType rat);
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat);

View File

@ -18,7 +18,7 @@
#include "QUECTEL_BC95_CellularNetwork.h"
#include "QUECTEL_BC95_CellularPower.h"
#include "QUECTEL_BC95_CellularSIM.h"
#include "QUECTEL_BC95_CellularContext.h"
#include "QUECTEL_BC95.h"
#define CONNECT_DELIM "\r\n"
@ -36,7 +36,7 @@ static const AT_CellularBase::SupportedFeature unsupported_features[] = {
AT_CellularBase::SUPPORTED_FEATURE_END_MARK
};
QUECTEL_BC95::QUECTEL_BC95(EventQueue &queue) : AT_CellularDevice(queue)
QUECTEL_BC95::QUECTEL_BC95(FileHandle *fh) : AT_CellularDevice(fh)
{
AT_CellularBase::set_unsupported_features(unsupported_features);
}
@ -59,3 +59,8 @@ AT_CellularSIM *QUECTEL_BC95::open_sim_impl(ATHandler &at)
{
return new QUECTEL_BC95_CellularSIM(at);
}
AT_CellularContext *QUECTEL_BC95::create_context_impl(ATHandler &at, const char *apn)
{
return new QUECTEL_BC95_CellularContext(at, this, apn);
}

View File

@ -24,13 +24,14 @@ namespace mbed {
class QUECTEL_BC95 : public AT_CellularDevice {
public:
QUECTEL_BC95(events::EventQueue &queue);
QUECTEL_BC95(FileHandle *fh);
virtual ~QUECTEL_BC95();
protected: // AT_CellularDevice
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
virtual AT_CellularPower *open_power_impl(ATHandler &at);
virtual AT_CellularSIM *open_sim_impl(ATHandler &at);
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn);
public: // NetworkInterface
void handle_urc(FileHandle *fh);

View File

@ -0,0 +1,44 @@
/*
* 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 "QUECTEL_BC95_CellularContext.h"
#include "QUECTEL_BC95_CellularStack.h"
namespace mbed {
QUECTEL_BC95_CellularContext::QUECTEL_BC95_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
AT_CellularContext(at, device, apn)
{
}
QUECTEL_BC95_CellularContext::~QUECTEL_BC95_CellularContext()
{
}
NetworkStack *QUECTEL_BC95_CellularContext::get_stack()
{
if (!_stack) {
_stack = new QUECTEL_BC95_CellularStack(_at, _cid, _ip_stack_type);
}
return _stack;
}
bool QUECTEL_BC95_CellularContext::stack_type_supported(nsapi_ip_stack_t stack_type)
{
return stack_type == IPV4_STACK ? true : false;
}
} /* namespace mbed */

View File

@ -0,0 +1,36 @@
/*
* 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.
*/
#ifndef QUECTEL_BC95_CELLULARCONTEXT_H_
#define QUECTEL_BC95_CELLULARCONTEXT_H_
#include "AT_CellularContext.h"
namespace mbed {
class QUECTEL_BC95_CellularContext: public AT_CellularContext {
public:
QUECTEL_BC95_CellularContext(ATHandler &at, CellularDevice *device, const char *apn);
virtual ~QUECTEL_BC95_CellularContext();
protected:
virtual NetworkStack *get_stack();
virtual bool stack_type_supported(nsapi_ip_stack_t stack_type);
};
} /* namespace mbed */
#endif // QUECTEL_BC95_CELLULARCONTEXT_H_

View File

@ -16,7 +16,6 @@
*/
#include "QUECTEL_BC95_CellularNetwork.h"
#include "QUECTEL_BC95_CellularStack.h"
using namespace mbed;
@ -29,19 +28,6 @@ QUECTEL_BC95_CellularNetwork::~QUECTEL_BC95_CellularNetwork()
{
}
NetworkStack *QUECTEL_BC95_CellularNetwork::get_stack()
{
if (!_stack) {
_stack = new QUECTEL_BC95_CellularStack(_at, _cid, _ip_stack_type);
}
return _stack;
}
bool QUECTEL_BC95_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
AT_CellularNetwork::RegistrationMode QUECTEL_BC95_CellularNetwork::has_registration(RegistrationType reg_tech)
{
return (reg_tech == C_EREG) ? RegistrationModeLAC : RegistrationModeDisable;

View File

@ -28,12 +28,7 @@ public:
virtual ~QUECTEL_BC95_CellularNetwork();
protected:
virtual NetworkStack *get_stack();
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat);
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
virtual RegistrationMode has_registration(RegistrationType reg_type);
};
} // namespace mbed

View File

@ -15,9 +15,12 @@
* limitations under the License.
*/
#include "QUECTEL/BG96/QUECTEL_BG96.h"
#include "QUECTEL/BG96/QUECTEL_BG96_CellularNetwork.h"
#include "QUECTEL/BG96/QUECTEL_BG96_CellularStack.h"
#include "QUECTEL_BG96.h"
#include "QUECTEL_BG96_CellularNetwork.h"
#include "QUECTEL_BG96_CellularStack.h"
#include "QUECTEL_BG96_CellularSIM.h"
#include "QUECTEL_BG96_CellularPower.h"
#include "QUECTEL_BG96_CellularContext.h"
using namespace mbed;
using namespace events;
@ -34,7 +37,7 @@ static const AT_CellularBase::SupportedFeature unsupported_features[] = {
AT_CellularBase::SUPPORTED_FEATURE_END_MARK
};
QUECTEL_BG96::QUECTEL_BG96(EventQueue &queue) : AT_CellularDevice(queue)
QUECTEL_BG96::QUECTEL_BG96(FileHandle *fh) : AT_CellularDevice(fh)
{
AT_CellularBase::set_unsupported_features(unsupported_features);
}
@ -47,3 +50,19 @@ AT_CellularNetwork *QUECTEL_BG96::open_network_impl(ATHandler &at)
{
return new QUECTEL_BG96_CellularNetwork(at);
}
AT_CellularSIM *QUECTEL_BG96::open_sim_impl(ATHandler &at)
{
return new QUECTEL_BG96_CellularSIM(at);
}
AT_CellularPower *QUECTEL_BG96::open_power_impl(ATHandler &at)
{
return new QUECTEL_BG96_CellularPower(at);
}
AT_CellularContext *QUECTEL_BG96::create_context_impl(ATHandler &at, const char *apn)
{
return new QUECTEL_BG96_CellularContext(at, this, apn);
}

View File

@ -24,13 +24,15 @@ namespace mbed {
class QUECTEL_BG96 : public AT_CellularDevice {
public:
QUECTEL_BG96(events::EventQueue &queue);
QUECTEL_BG96(FileHandle *fh);
virtual ~QUECTEL_BG96();
protected: // AT_CellularDevice
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
public: // NetworkInterface
virtual AT_CellularSIM *open_sim_impl(ATHandler &at);
virtual AT_CellularPower *open_power_impl(ATHandler &at);
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn);
public:
void handle_urc(FileHandle *fh);
};
} // namespace mbed

View File

@ -0,0 +1,68 @@
/*
* 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 "QUECTEL_BG96_CellularContext.h"
#include "QUECTEL_BG96_CellularStack.h"
namespace mbed {
QUECTEL_BG96_CellularContext::QUECTEL_BG96_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
AT_CellularContext(at, device, apn)
{
}
QUECTEL_BG96_CellularContext::~QUECTEL_BG96_CellularContext()
{
}
bool QUECTEL_BG96_CellularContext::stack_type_supported(nsapi_ip_stack_t stack_type)
{
if (stack_type == IPV4_STACK) {
return true;
}
return false;
}
NetworkStack *QUECTEL_BG96_CellularContext::get_stack()
{
if (!_stack) {
_stack = new QUECTEL_BG96_CellularStack(_at, _cid, _ip_stack_type);
}
return _stack;
}
nsapi_error_t QUECTEL_BG96_CellularContext::do_user_authentication()
{
if (_pwd && _uname) {
_at.cmd_start("AT+QICSGP=");
_at.write_int(_cid);
_at.write_int(1); // IPv4
_at.write_string(_apn);
_at.write_string(_uname);
_at.write_string(_pwd);
_at.write_int(_authentication_type);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() != NSAPI_ERROR_OK) {
return NSAPI_ERROR_AUTH_FAILURE;
}
}
return NSAPI_ERROR_OK;
}
} /* namespace mbed */

View File

@ -0,0 +1,37 @@
/*
* 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.
*/
#ifndef QUECTEL_BG96_CELLULARCONTEXT_H_
#define QUECTEL_BG96_CELLULARCONTEXT_H_
#include "AT_CellularContext.h"
namespace mbed {
class QUECTEL_BG96_CellularContext: public AT_CellularContext {
public:
QUECTEL_BG96_CellularContext(ATHandler &at, CellularDevice *device, const char *apn);
virtual ~QUECTEL_BG96_CellularContext();
protected:
virtual bool stack_type_supported(nsapi_ip_stack_t stack_type);
virtual NetworkStack *get_stack();
virtual nsapi_error_t do_user_authentication();
};
} /* namespace mbed */
#endif // QUECTEL_BG96_CELLULARCONTEXT_H_

View File

@ -28,23 +28,6 @@ QUECTEL_BG96_CellularNetwork::~QUECTEL_BG96_CellularNetwork()
{
}
bool QUECTEL_BG96_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
if (requested_stack == IPV4_STACK) {
return true;
}
return false;
}
NetworkStack *QUECTEL_BG96_CellularNetwork::get_stack()
{
if (!_stack) {
_stack = new QUECTEL_BG96_CellularStack(_at, _cid, _ip_stack_type);
}
return _stack;
}
nsapi_error_t QUECTEL_BG96_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opsAct)
{
_at.lock();
@ -89,22 +72,3 @@ nsapi_error_t QUECTEL_BG96_CellularNetwork::set_access_technology_impl(RadioAcce
return _at.unlock_return_error();
}
nsapi_error_t QUECTEL_BG96_CellularNetwork::do_user_authentication()
{
if (_pwd && _uname) {
_at.cmd_start("AT+QICSGP=");
_at.write_int(_cid);
_at.write_int(1); // IPv4
_at.write_string(_apn);
_at.write_string(_uname);
_at.write_string(_pwd);
_at.write_int(_authentication_type);
_at.cmd_stop_read_resp();
if (_at.get_last_error() != NSAPI_ERROR_OK) {
return NSAPI_ERROR_AUTH_FAILURE;
}
}
return NSAPI_ERROR_OK;
}

View File

@ -28,13 +28,7 @@ public:
virtual ~QUECTEL_BG96_CellularNetwork();
protected:
virtual NetworkStack *get_stack();
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat);
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
virtual nsapi_error_t do_user_authentication();
};
} // namespace mbed

View File

@ -15,9 +15,10 @@
* limitations under the License.
*/
#include "QUECTEL/UG96/QUECTEL_UG96.h"
#include "QUECTEL/UG96/QUECTEL_UG96_CellularNetwork.h"
#include "QUECTEL/UG96/QUECTEL_UG96_CellularPower.h"
#include "QUECTEL_UG96.h"
#include "QUECTEL_UG96_CellularNetwork.h"
#include "QUECTEL_UG96_CellularPower.h"
#include "QUECTEL_UG96_CellularContext.h"
using namespace mbed;
using namespace events;
@ -29,7 +30,7 @@ using namespace events;
#define MAX_STARTUP_TRIALS 5
#define MAX_RESET_TRIALS 5
QUECTEL_UG96::QUECTEL_UG96(EventQueue &queue) : AT_CellularDevice(queue)
QUECTEL_UG96::QUECTEL_UG96(FileHandle *fh) : AT_CellularDevice(fh)
{
}
@ -46,3 +47,8 @@ AT_CellularPower *QUECTEL_UG96::open_power_impl(ATHandler &at)
{
return new QUECTEL_UG96_CellularPower(at);
}
AT_CellularContext *QUECTEL_UG96::create_context_impl(ATHandler &at, const char *apn)
{
return new QUECTEL_UG96_CellularContext(at, this, apn);
}

View File

@ -32,12 +32,13 @@ namespace mbed {
class QUECTEL_UG96 : public AT_CellularDevice {
public:
QUECTEL_UG96(events::EventQueue &queue);
QUECTEL_UG96(FileHandle *fh);
virtual ~QUECTEL_UG96();
protected: // AT_CellularDevice
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
virtual AT_CellularPower *open_power_impl(ATHandler &at);
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn);
public: // NetworkInterface
void handle_urc(FileHandle *fh);

View File

@ -0,0 +1,56 @@
/*
* 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 "QUECTEL_UG96_CellularContext.h"
namespace mbed {
QUECTEL_UG96_CellularContext::QUECTEL_UG96_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
AT_CellularContext(at, device, apn)
{
}
QUECTEL_UG96_CellularContext::~QUECTEL_UG96_CellularContext()
{
}
bool QUECTEL_UG96_CellularContext::stack_type_supported(nsapi_ip_stack_t stack_type)
{
return stack_type == IPV4_STACK ? true : false;
}
nsapi_error_t QUECTEL_UG96_CellularContext::do_user_authentication()
{
if (_pwd && _uname) {
_at.cmd_start("AT+QICSGP=");
_at.write_int(_cid);
_at.write_int(1); // context type 1=IPv4
_at.write_string(_apn);
_at.write_string(_uname);
_at.write_string(_pwd);
_at.write_int(_authentication_type);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() != NSAPI_ERROR_OK) {
return NSAPI_ERROR_AUTH_FAILURE;
}
}
return NSAPI_ERROR_OK;
}
} /* namespace mbed */

View File

@ -0,0 +1,36 @@
/*
* 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.
*/
#ifndef QUECTEL_UG96_CELLULARCONTEXT_H_
#define QUECTEL_UG96_CELLULARCONTEXT_H_
#include "AT_CellularContext.h"
namespace mbed {
class QUECTEL_UG96_CellularContext: public AT_CellularContext {
public:
QUECTEL_UG96_CellularContext(ATHandler &at, CellularDevice *device, const char *apn);
virtual ~QUECTEL_UG96_CellularContext();
protected:
virtual bool stack_type_supported(nsapi_ip_stack_t stack_type);
virtual nsapi_error_t do_user_authentication();
};
} /* namespace mbed */
#endif // QUECTEL_UG96_CELLULARCONTEXT_H_

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
#include "QUECTEL/UG96/QUECTEL_UG96_CellularNetwork.h"
#include "QUECTEL_UG96_CellularNetwork.h"
using namespace mbed;
@ -27,11 +27,6 @@ QUECTEL_UG96_CellularNetwork::~QUECTEL_UG96_CellularNetwork()
{
}
bool QUECTEL_UG96_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
AT_CellularNetwork::RegistrationMode QUECTEL_UG96_CellularNetwork::has_registration(RegistrationType reg_type)
{
return (reg_type == C_REG || reg_type == C_GREG) ? RegistrationModeLAC : RegistrationModeDisable;
@ -42,24 +37,3 @@ nsapi_error_t QUECTEL_UG96_CellularNetwork::set_access_technology_impl(RadioAcce
_op_act = RAT_UNKNOWN;
return NSAPI_ERROR_UNSUPPORTED;
}
nsapi_error_t QUECTEL_UG96_CellularNetwork::do_user_authentication()
{
if (_pwd && _uname) {
_at.cmd_start("AT+QICSGP=");
_at.write_int(_cid);
_at.write_int(1); // context type 1=IPv4
_at.write_string(_apn);
_at.write_string(_uname);
_at.write_string(_pwd);
_at.write_int(_authentication_type);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() != NSAPI_ERROR_OK) {
return NSAPI_ERROR_AUTH_FAILURE;
}
}
return NSAPI_ERROR_OK;
}

View File

@ -28,13 +28,8 @@ public:
virtual ~QUECTEL_UG96_CellularNetwork();
protected:
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
virtual RegistrationMode has_registration(RegistrationType rat);
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat);
virtual nsapi_error_t do_user_authentication();
};
} // namespace mbed

View File

@ -18,6 +18,7 @@
#include "TELIT_HE910.h"
#include "TELIT_HE910_CellularPower.h"
#include "TELIT_HE910_CellularNetwork.h"
#include "TELIT_HE910_CellularContext.h"
using namespace mbed;
using namespace events;
@ -28,7 +29,7 @@ static const AT_CellularBase::SupportedFeature unsupported_features[] = {
AT_CellularBase::SUPPORTED_FEATURE_END_MARK
};
TELIT_HE910::TELIT_HE910(EventQueue &queue) : AT_CellularDevice(queue)
TELIT_HE910::TELIT_HE910(FileHandle *fh) : AT_CellularDevice(fh)
{
AT_CellularBase::set_unsupported_features(unsupported_features);
}
@ -47,7 +48,12 @@ AT_CellularPower *TELIT_HE910::open_power_impl(ATHandler &at)
return new TELIT_HE910_CellularPower(at);
}
uint16_t TELIT_HE910::get_send_delay()
AT_CellularContext *TELIT_HE910::create_context_impl(ATHandler &at, const char *apn)
{
return new TELIT_HE910_CellularContext(at, this, apn);
}
uint16_t TELIT_HE910::get_send_delay() const
{
return DEFAULT_DELAY_BETWEEN_AT_COMMANDS;
}

View File

@ -27,15 +27,16 @@ namespace mbed {
class TELIT_HE910 : public AT_CellularDevice {
public:
TELIT_HE910(events::EventQueue &queue);
TELIT_HE910(FileHandle *fh);
virtual ~TELIT_HE910();
protected: // AT_CellularDevice
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
virtual AT_CellularPower *open_power_impl(ATHandler &at);
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn);
public: // from CellularDevice
virtual uint16_t get_send_delay();
virtual uint16_t get_send_delay() const;
};
} // namespace mbed
#endif /* CELLULAR_TARGETS_TELIT_HE910_TELIT_HE910_H_ */

View File

@ -0,0 +1,35 @@
/*
* 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 "TELIT_HE910_CellularContext.h"
namespace mbed {
TELIT_HE910_CellularContext::TELIT_HE910_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
AT_CellularContext(at, device, apn)
{
}
TELIT_HE910_CellularContext::~TELIT_HE910_CellularContext()
{
}
bool TELIT_HE910_CellularContext::stack_type_supported(nsapi_ip_stack_t stack_type)
{
return stack_type == IPV4_STACK ? true : false;
}
} /* namespace mbed */

View File

@ -0,0 +1,35 @@
/*
* 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.
*/
#ifndef TELIT_HE910_CELLULARCONTEXT_H_
#define TELIT_HE910_CELLULARCONTEXT_H_
#include "AT_CellularContext.h"
namespace mbed {
class TELIT_HE910_CellularContext: public AT_CellularContext {
public:
TELIT_HE910_CellularContext(ATHandler &at, CellularDevice *device, const char *apn);
virtual ~TELIT_HE910_CellularContext();
protected:
virtual bool stack_type_supported(nsapi_ip_stack_t stack_type);
};
} /* namespace mbed */
#endif // TELIT_HE910_CELLULARCONTEXT_H_

View File

@ -27,11 +27,6 @@ TELIT_HE910_CellularNetwork::~TELIT_HE910_CellularNetwork()
{
}
bool TELIT_HE910_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
AT_CellularNetwork::RegistrationMode TELIT_HE910_CellularNetwork::has_registration(RegistrationType reg_type)
{
return (reg_type == C_REG || reg_type == C_GREG) ? RegistrationModeLAC : RegistrationModeDisable;

View File

@ -28,11 +28,7 @@ public:
virtual ~TELIT_HE910_CellularNetwork();
protected:
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
virtual RegistrationMode has_registration(RegistrationType rat);
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat);
};

View File

@ -18,6 +18,7 @@
#include "UBLOX_AT.h"
#include "UBLOX_AT_CellularNetwork.h"
#include "UBLOX_AT_CellularPower.h"
#include "UBLOX_AT_CellularContext.h"
using namespace mbed;
using namespace events;
@ -29,7 +30,7 @@ static const AT_CellularBase::SupportedFeature unsupported_features[] = {
};
#endif
UBLOX_AT::UBLOX_AT(EventQueue &queue) : AT_CellularDevice(queue)
UBLOX_AT::UBLOX_AT(FileHandle *fh) : AT_CellularDevice(fh)
{
#ifdef TARGET_UBLOX_C030_R410M
AT_CellularBase::set_unsupported_features(unsupported_features);
@ -49,3 +50,8 @@ AT_CellularPower *UBLOX_AT::open_power_impl(ATHandler &at)
{
return new UBLOX_AT_CellularPower(at);
}
AT_CellularContext *UBLOX_AT::create_context_impl(ATHandler &at, const char *apn)
{
return new UBLOX_AT_CellularContext(at, this, apn);
}

View File

@ -24,13 +24,13 @@ namespace mbed {
class UBLOX_AT : public AT_CellularDevice {
public:
UBLOX_AT(events::EventQueue &queue);
UBLOX_AT(FileHandle *fh);
virtual ~UBLOX_AT();
protected: // AT_CellularDevice
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
virtual AT_CellularPower *open_power_impl(ATHandler &at);
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn);
public: // NetworkInterface
void handle_urc(FileHandle *fh);
};

View File

@ -0,0 +1,286 @@
/*
* 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"
namespace mbed {
UBLOX_AT_CellularContext::UBLOX_AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
AT_CellularContext(at, device, apn)
{
// The authentication to use
_auth = NSAPI_SECURITY_UNKNOWN;
}
UBLOX_AT_CellularContext::~UBLOX_AT_CellularContext()
{
}
NetworkStack *UBLOX_AT_CellularContext::get_stack()
{
if (!_stack) {
_stack = new UBLOX_AT_CellularStack(_at, _cid, _ip_stack_type);
}
return _stack;
}
bool UBLOX_AT_CellularContext::stack_type_supported(nsapi_ip_stack_t stack_type)
{
return stack_type == IPV4_STACK ? true : false;
}
void UBLOX_AT_CellularContext::do_connect()
{
_at.lock();
_cb_data.error = NSAPI_ERROR_NO_CONNECTION;
// Attempt to establish a connection
#ifdef TARGET_UBLOX_C030_R410M
_cb_data.error = NSAPI_ERROR_OK;
#else
_cb_data.error = open_data_channel();
#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) {
call_network_cb(_connect_status);
}
}
nsapi_error_t UBLOX_AT_CellularContext::open_data_channel()
{
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.cmd_start("AT+UPSND=" PROFILE ",8");
_at.cmd_stop();
_at.resp_start("+UPSND:");
_at.read_int();
_at.read_int();
active = _at.read_int();
_at.resp_stop();
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) ? _auth : NSAPI_SECURITY_NONE;
} else {
_auth = NSAPI_SECURITY_NONE;
}
success = activate_profile(_apn, _uname, _pwd);
} 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)
{
bool activated = false;
bool success = false;
// Set up the APN
if (apn) {
success = false;
_at.cmd_start("AT+UPSD=0,1,");
_at.write_string(apn);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
success = true;
}
}
// Set up the UserName
if (success && username) {
success = false;
_at.cmd_start("AT+UPSD=" PROFILE ",2,");
_at.write_string(username);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
success = true;
}
}
// Set up the Password
if (success && password) {
success = false;
_at.cmd_start("AT+UPSD=" PROFILE ",3,");
_at.write_string(password);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
success = true;
}
}
if (success) {
_at.cmd_start("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
// Set up the authentication protocol
// 0 = none
// 1 = PAP (Password Authentication Protocol)
// 2 = CHAP (Challenge Handshake Authentication Protocol)
for (int protocol = nsapi_security_to_modem_security(NSAPI_SECURITY_NONE);
success && (protocol <= nsapi_security_to_modem_security(NSAPI_SECURITY_CHAP)); protocol++) {
if ((_auth == NSAPI_SECURITY_UNKNOWN) || (nsapi_security_to_modem_security(_auth) == protocol)) {
_at.cmd_start("AT+UPSD=0,6,");
_at.write_int(protocol);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
// Activate, wait upto 30 seconds for the connection to be made
_at.set_at_timeout(30000);
_at.cmd_start("AT+UPSDA=0,3");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.restore_at_timeout();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
activated = true;
}
}
}
}
}
return activated;
}
// Convert nsapi_security_t to the modem security numbers
int UBLOX_AT_CellularContext::nsapi_security_to_modem_security(nsapi_security_t nsapi_security)
{
int modem_security = 3;
switch (nsapi_security) {
case NSAPI_SECURITY_NONE:
modem_security = 0;
break;
case NSAPI_SECURITY_PAP:
modem_security = 1;
break;
case NSAPI_SECURITY_CHAP:
modem_security = 2;
break;
case NSAPI_SECURITY_UNKNOWN:
modem_security = 3;
break;
default:
modem_security = 3;
break;
}
return modem_security;
}
// Disconnect the on board IP stack of the modem.
bool UBLOX_AT_CellularContext::disconnect_modem_stack()
{
bool success = false;
if (get_ip_address() != NULL) {
_at.cmd_start("AT+UPSDA=" PROFILE ",4");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
success = true;
}
}
return success;
}
nsapi_error_t UBLOX_AT_CellularContext::get_imsi(char* imsi)
{
_at.lock();
_at.cmd_start("AT+CIMI");
_at.cmd_stop();
_at.resp_start();
int len = _at.read_string(imsi, MAX_IMSI_LENGTH);
if (len > 0) {
imsi[len] = '\0';
}
_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);
}
}
const char *UBLOX_AT_CellularContext::get_gateway()
{
return get_ip_address();
}
} /* namespace mbed */

View File

@ -0,0 +1,88 @@
/*
* 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.
*/
#ifndef UBLOX_AT_CELLULARCONTEXT_H_
#define UBLOX_AT_CELLULARCONTEXT_H_
#include "AT_CellularContext.h"
namespace mbed {
class UBLOX_AT_CellularContext: public AT_CellularContext {
public:
UBLOX_AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn);
virtual ~UBLOX_AT_CellularContext();
virtual void do_connect();
virtual const char *get_gateway();
protected:
virtual NetworkStack *get_stack();
virtual bool stack_type_supported(nsapi_ip_stack_t stack_type);
private:
/** Length of IMSI buffer.
*/
static const int MAX_IMSI_LENGTH = 15;
/** The type of authentication to use.
*/
nsapi_security_t _auth;
/** Connect the on board IP stack of the modem.
*
* @return True if successful, otherwise false.
*/
nsapi_error_t open_data_channel();
/** Activate one of the on-board modem's connection profiles.
*
* @param apn The APN to use.
* @param username The user name to use.
* @param password The password to use.
* @param auth The authentication method to use
* (NSAPI_SECURITY_NONE, NSAPI_SECURITY_PAP,
* NSAPI_SECURITY_CHAP or NSAPI_SECURITY_UNKNOWN).
* @return True if successful, otherwise false.
*/
bool activate_profile(const char* apn, const char* username, const char* password);
/** Convert nsapi_security_t to the modem security numbers.
*
* @param nsapi_security Security protocol.
* @return Modem security numbers.
*/
int nsapi_security_to_modem_security(nsapi_security_t nsapi_security);
/** Disconnect the on board IP stack of the modem.
*
* @return True if successful, otherwise false.
*/
bool disconnect_modem_stack();
/** Read IMSI of modem.
*/
nsapi_error_t get_imsi(char* imsi);
/** Get the next set of credentials from the database.
*/
void get_next_credentials(char ** config);
};
} /* namespace mbed */
#endif // UBLOX_AT_CELLULARCONTEXT_H_

View File

@ -16,15 +16,12 @@
*/
#include "UBLOX_AT_CellularNetwork.h"
#include "UBLOX_AT_CellularStack.h"
using namespace mbed;
UBLOX_AT_CellularNetwork::UBLOX_AT_CellularNetwork(ATHandler &atHandler) : AT_CellularNetwork(atHandler)
{
_op_act = RAT_UNKNOWN;
// The authentication to use
_auth = NSAPI_SECURITY_UNKNOWN;
}
UBLOX_AT_CellularNetwork::~UBLOX_AT_CellularNetwork()
@ -34,19 +31,6 @@ UBLOX_AT_CellularNetwork::~UBLOX_AT_CellularNetwork()
}
}
NetworkStack *UBLOX_AT_CellularNetwork::get_stack()
{
if (!_stack) {
_stack = new UBLOX_AT_CellularStack(_at, _cid, _ip_stack_type);
}
return _stack;
}
bool UBLOX_AT_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
AT_CellularNetwork::RegistrationMode UBLOX_AT_CellularNetwork::has_registration(RegistrationType reg_type)
{
return (reg_type == C_REG || reg_type == C_GREG) ? RegistrationModeLAC : RegistrationModeDisable;
@ -85,230 +69,3 @@ nsapi_error_t UBLOX_AT_CellularNetwork::set_access_technology_impl(RadioAccessTe
return NSAPI_ERROR_OK;
}
nsapi_error_t UBLOX_AT_CellularNetwork::connect()
{
_at.lock();
nsapi_error_t err = NSAPI_ERROR_NO_CONNECTION;
// Attempt to establish a connection
#ifdef TARGET_UBLOX_C030_R410M
err = NSAPI_ERROR_OK;
#else
err = open_data_channel();
#endif
if (err != 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 (_connection_status_cb) {
_connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connect_status);
}
return err;
}
nsapi_error_t UBLOX_AT_CellularNetwork::open_data_channel()
{
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.cmd_start("AT+UPSND=" PROFILE ",8");
_at.cmd_stop();
_at.resp_start("+UPSND:");
_at.read_int();
_at.read_int();
active = _at.read_int();
_at.resp_stop();
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) ? _auth : NSAPI_SECURITY_NONE;
} else {
_auth = NSAPI_SECURITY_NONE;
}
success = activate_profile(_apn, _uname, _pwd);
} 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_CellularNetwork::activate_profile(const char *apn,
const char *username,
const char *password)
{
bool activated = false;
bool success = false;
// Set up the APN
if (apn) {
success = false;
_at.cmd_start("AT+UPSD=0,1,");
_at.write_string(apn);
_at.cmd_stop_read_resp();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
success = true;
}
}
// Set up the UserName
if (success && username) {
success = false;
_at.cmd_start("AT+UPSD=" PROFILE ",2,");
_at.write_string(username);
_at.cmd_stop_read_resp();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
success = true;
}
}
// Set up the Password
if (success && password) {
success = false;
_at.cmd_start("AT+UPSD=" PROFILE ",3,");
_at.write_string(password);
_at.cmd_stop_read_resp();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
success = true;
}
}
if (success) {
_at.cmd_start("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"");
_at.cmd_stop_read_resp();
// Set up the authentication protocol
// 0 = none
// 1 = PAP (Password Authentication Protocol)
// 2 = CHAP (Challenge Handshake Authentication Protocol)
for (int protocol = nsapi_security_to_modem_security(NSAPI_SECURITY_NONE);
success && (protocol <= nsapi_security_to_modem_security(NSAPI_SECURITY_CHAP)); protocol++) {
if ((_auth == NSAPI_SECURITY_UNKNOWN) || (nsapi_security_to_modem_security(_auth) == protocol)) {
_at.cmd_start("AT+UPSD=0,6,");
_at.write_int(protocol);
_at.cmd_stop_read_resp();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
// Activate, wait upto 30 seconds for the connection to be made
_at.set_at_timeout(30000);
_at.cmd_start("AT+UPSDA=0,3");
_at.cmd_stop_read_resp();
_at.restore_at_timeout();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
activated = true;
}
}
}
}
}
return activated;
}
// Convert nsapi_security_t to the modem security numbers
int UBLOX_AT_CellularNetwork::nsapi_security_to_modem_security(nsapi_security_t nsapi_security)
{
int modem_security = 3;
switch (nsapi_security) {
case NSAPI_SECURITY_NONE:
modem_security = 0;
break;
case NSAPI_SECURITY_PAP:
modem_security = 1;
break;
case NSAPI_SECURITY_CHAP:
modem_security = 2;
break;
case NSAPI_SECURITY_UNKNOWN:
modem_security = 3;
break;
default:
modem_security = 3;
break;
}
return modem_security;
}
// Disconnect the on board IP stack of the modem.
bool UBLOX_AT_CellularNetwork::disconnect_modem_stack()
{
bool success = false;
if (get_ip_address() != NULL) {
_at.cmd_start("AT+UPSDA=" PROFILE ",4");
_at.cmd_stop_read_resp();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
success = true;
}
}
return success;
}
nsapi_error_t UBLOX_AT_CellularNetwork::get_imsi(char *imsi)
{
_at.lock();
_at.cmd_start("AT+CIMI");
_at.cmd_stop();
_at.resp_start();
int len = _at.read_string(imsi, MAX_IMSI_LENGTH);
if (len > 0) {
imsi[len] = '\0';
}
_at.resp_stop();
return _at.unlock_return_error();
}
// Get the next set of credentials, based on IMSI.
void UBLOX_AT_CellularNetwork::get_next_credentials(char **config)
{
if (*config) {
_apn = _APN_GET(*config);
_uname = _APN_GET(*config);
_pwd = _APN_GET(*config);
}
}
const char *UBLOX_AT_CellularNetwork::get_gateway()
{
return get_ip_address();
}

View File

@ -19,7 +19,6 @@
#define UBLOX_AT_CELLULAR_NETWORK_H_
#include "AT_CellularNetwork.h"
#include "APN_db.h"
namespace mbed {
@ -28,67 +27,9 @@ public:
UBLOX_AT_CellularNetwork(ATHandler &atHandler);
virtual ~UBLOX_AT_CellularNetwork();
virtual nsapi_error_t connect();
virtual const char *get_gateway();
protected:
virtual NetworkStack *get_stack();
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat);
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
virtual RegistrationMode has_registration(RegistrationType rat);
private:
/** Length of IMSI buffer.
*/
static const int MAX_IMSI_LENGTH = 15;
/** The type of authentication to use.
*/
nsapi_security_t _auth;
/** Connect the on board IP stack of the modem.
*
* @return True if successful, otherwise false.
*/
nsapi_error_t open_data_channel();
/** Activate one of the on-board modem's connection profiles.
*
* @param apn The APN to use.
* @param username The user name to use.
* @param password The password to use.
* @param auth The authentication method to use
* (NSAPI_SECURITY_NONE, NSAPI_SECURITY_PAP,
* NSAPI_SECURITY_CHAP or NSAPI_SECURITY_UNKNOWN).
* @return True if successful, otherwise false.
*/
bool activate_profile(const char *apn, const char *username, const char *password);
/** Convert nsapi_security_t to the modem security numbers.
*
* @param nsapi_security Security protocol.
* @return Modem security numbers.
*/
int nsapi_security_to_modem_security(nsapi_security_t nsapi_security);
/** Disconnect the on board IP stack of the modem.
*
* @return True if successful, otherwise false.
*/
bool disconnect_modem_stack();
/** Read IMSI of modem.
*/
nsapi_error_t get_imsi(char *imsi);
/** Get the next set of credentials from the database.
*/
void get_next_credentials(char **config);
};
} // namespace mbed

View File

@ -193,12 +193,9 @@ nsapi_size_or_error_t UBLOX_AT_CellularStack::socket_sendto_impl(CellularSocket
const void *data, nsapi_size_t size)
{
int sent_len = 0;
uint8_t ch = 0, cont = 50;
pollfh fhs;
fhs.fh = _at.get_file_handle();
fhs.events = POLLIN;
int pollCount;
if (socket->proto == NSAPI_UDP) {
if (size > UBLOX_MAX_PACKET_SIZE) {
@ -210,7 +207,7 @@ nsapi_size_or_error_t UBLOX_AT_CellularStack::socket_sendto_impl(CellularSocket
_at.write_int(address.get_port());
_at.write_int(size);
_at.cmd_stop();
pollCount = poll(&fhs, 1, 50);
(void)poll(&fhs, 1, 50);
_at.write_bytes((uint8_t *)data, size);
_at.resp_start("+USOST:");
@ -235,7 +232,7 @@ nsapi_size_or_error_t UBLOX_AT_CellularStack::socket_sendto_impl(CellularSocket
_at.write_int(socket->id);
_at.write_int(blk);
_at.cmd_stop();
pollCount = poll(&fhs, 1, 50);
(void)poll(&fhs, 1, 50);
_at.write_bytes((uint8_t *)buf, blk);
_at.resp_start("+USOWR:");

View File

@ -18,6 +18,7 @@
#include "UBLOX_PPP.h"
#include "UBLOX_PPP_CellularNetwork.h"
#include "UBLOX_PPP_CellularPower.h"
#include "UBLOX_PPP_CellularContext.h"
using namespace mbed;
using namespace events;
@ -29,7 +30,7 @@ static const AT_CellularBase::SupportedFeature unsupported_features[] = {
};
#endif
UBLOX_PPP::UBLOX_PPP(EventQueue &queue) : AT_CellularDevice(queue)
UBLOX_PPP::UBLOX_PPP(FileHandle *fh) : AT_CellularDevice(fh)
{
#ifdef TARGET_UBLOX_C027
AT_CellularBase::set_unsupported_features(unsupported_features);
@ -49,3 +50,8 @@ AT_CellularPower *UBLOX_PPP::open_power_impl(ATHandler &at)
{
return new UBLOX_PPP_CellularPower(at);
}
AT_CellularContext *UBLOX_PPP::create_context_impl(ATHandler &at, const char *apn)
{
return new UBLOX_PPP_CellularContext(at, this, apn);
}

View File

@ -24,16 +24,13 @@ namespace mbed {
class UBLOX_PPP : public AT_CellularDevice {
public:
UBLOX_PPP(events::EventQueue &queue);
UBLOX_PPP(FileHandle *fh);
virtual ~UBLOX_PPP();
protected: // AT_CellularDevice
virtual AT_CellularNetwork *open_network_impl(ATHandler &at);
virtual AT_CellularPower *open_power_impl(ATHandler &at);
};
MBED_DEPRECATED_SINCE("mbed-os-5.9", "This API will be deprecated, Use UBLOX_PPP instead of UBLOX_LISA_U.")
class UBLOX_LISA_U : public UBLOX_PPP {
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn);
};
} // namespace mbed

View File

@ -0,0 +1,35 @@
/*
* 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_PPP_CellularContext.h"
namespace mbed {
UBLOX_PPP_CellularContext::UBLOX_PPP_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
AT_CellularContext(at, device, apn)
{
}
UBLOX_PPP_CellularContext::~UBLOX_PPP_CellularContext()
{
}
bool UBLOX_PPP_CellularContext::stack_type_supported(nsapi_ip_stack_t stack_type)
{
return stack_type == IPV4_STACK ? true : false;
}
} /* namespace mbed */

View File

@ -0,0 +1,35 @@
/*
* 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.
*/
#ifndef UBLOX_PPP_CELLULARCONTEXT_H_
#define UBLOX_PPP_CELLULARCONTEXT_H_
#include "AT_CellularContext.h"
namespace mbed {
class UBLOX_PPP_CellularContext: public AT_CellularContext {
public:
UBLOX_PPP_CellularContext(ATHandler &at, CellularDevice *device, const char *apn);
virtual ~UBLOX_PPP_CellularContext();
protected:
virtual bool stack_type_supported(nsapi_ip_stack_t stack_type);
};
} /* namespace mbed */
#endif // UBLOX_PPP_CELLULARCONTEXT_H_

View File

@ -27,11 +27,6 @@ UBLOX_PPP_CellularNetwork::~UBLOX_PPP_CellularNetwork()
{
}
bool UBLOX_PPP_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
AT_CellularNetwork::RegistrationMode UBLOX_PPP_CellularNetwork::has_registration(RegistrationType reg_type)
{
return (reg_type == C_REG || reg_type == C_GREG) ? RegistrationModeLAC : RegistrationModeDisable;

View File

@ -28,17 +28,10 @@ public:
virtual ~UBLOX_PPP_CellularNetwork();
protected:
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
virtual RegistrationMode has_registration(RegistrationType rat);
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat);
};
MBED_DEPRECATED_SINCE("mbed-os-5.9", "This API will be deprecated, Use UBLOX_PPP_CellularNetwork instead of UBLOX_LISA_U_CellularNetwork.")
class UBLOX_LISA_U_CellularNetwork : public UBLOX_PPP_CellularNetwork {
};
} // namespace mbed
#endif // UBLOX_PPP_CELLULAR_NETWORK_H_

View File

@ -34,10 +34,6 @@ public: //from CellularPower
virtual nsapi_error_t off();
};
MBED_DEPRECATED_SINCE("mbed-os-5.9", "This API will be deprecated, Use UBLOX_PPP_CellularPower instead of UBLOX_LISA_U_CellularPower.")
class UBLOX_LISA_U_CellularPower : public UBLOX_PPP_CellularPower {
};
} // namespace mbed
#endif // UBLOX_PPP_CELLULARPOWER_H_

View File

@ -45,6 +45,12 @@ public:
virtual void set_credentials(const char *apn, const char *uname = 0,
const char *pwd = 0) = 0;
/** Set the plmn. PLMN controls to what network device registers.
*
* @param plmn user to force what network to register.
*/
virtual void set_plmn(const char *plmn) = 0;
/** Set the PIN code for SIM card.
*
* @param sim_pin PIN for the SIM card.

View File

@ -129,7 +129,9 @@ MBED_WEAK NetworkInterface *NetworkInterface::get_target_default_instance()
#ifdef MBED_CONF_NSAPI_DEFAULT_CELLULAR_SIM_PIN
cellular->set_sim_pin(MBED_CONF_NSAPI_DEFAULT_CELLULAR_SIM_PIN);
#endif
#ifdef MBED_CONF_NSAPI_DEFAULT_CELLULAR_PLMN
cellular->set_plmn(MBED_CONF_NSAPI_DEFAULT_CELLULAR_PLMN);
#endif
return cellular;
}
#elif defined(MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE)

View File

@ -60,10 +60,14 @@ void OnboardCellularInterface::modem_power_down()
}
#endif
#endif // CELLULAR_DEVICE
#ifdef ONBOARD_CELLULAR_INTERFACE_AVAILABLE
#ifdef CELLULAR_DEVICE
MBED_WEAK CellularBase *CellularBase::get_target_default_instance()
{
return CellularContext::get_default_instance();
}
#elif defined ONBOARD_CELLULAR_INTERFACE_AVAILABLE
MBED_WEAK CellularBase *CellularBase::get_target_default_instance()
{
static OnboardCellularInterface cellular;

View File

@ -16,9 +16,41 @@
#ifndef ONBOARD_CELLULAR_INTERFACE_
#define ONBOARD_CELLULAR_INTERFACE_
#include "EasyCellularConnection.h"
#include "CellularContext.h"
#ifdef CELLULAR_DEVICE
typedef mbed::EasyCellularConnection OnboardCellularInterface;
using namespace mbed;
MBED_DEPRECATED_SINCE("mbed-os-5.9", "This API will be deprecated, use CellularBase::get_default_instance() instead.")
class OnboardCellularInterface : public CellularBase
{
public:
OnboardCellularInterface() {
context = CellularContext::get_default_instance();
MBED_ASSERT(context != NULL);
}
public: // from NetworkInterface
virtual nsapi_error_t set_blocking(bool blocking) {return context->set_blocking(blocking);}
virtual NetworkStack *get_stack() {return context->get_stack();}
virtual const char *get_ip_address() {return context->get_ip_address();}
virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb) {context->attach(status_cb);}
virtual nsapi_error_t connect() {return context->connect();}
virtual nsapi_error_t disconnect() {return context->disconnect();}
// from CellularBase
virtual void set_plmn(const char *plmn) {context->set_plmn(plmn);}
virtual void set_sim_pin(const char *sim_pin) {context->set_sim_pin(sim_pin);}
virtual nsapi_error_t connect(const char *sim_pin, const char *apn = 0, const char *uname = 0,
const char *pwd = 0)
{return context->connect(sim_pin, apn, uname, pwd);}
virtual void set_credentials(const char *apn, const char *uname = 0, const char *pwd = 0)
{context->set_credentials(apn, uname, pwd);}
virtual const char *get_netmask() {return context->get_netmask();}
virtual const char *get_gateway() {return context->get_gateway();}
virtual bool is_connected() {return context->is_connected();}
private:
CellularContext *context;
};
#define ONBOARD_CELLULAR_INTERFACE_AVAILABLE
#elif MODEM_ON_BOARD && MODEM_ON_BOARD_UART && NSAPI_PPP_AVAILABLE

View File

@ -6,6 +6,7 @@
"default-wifi-ssid": null,
"default-wifi-password": null,
"default-wifi-security": "NONE",
"default-cellular-plmn": null,
"default-cellular-sim-pin": null,
"default-cellular-apn": null,
"default-cellular-username": null,

View File

@ -261,6 +261,8 @@ typedef enum {
P_73 = WAKE,
P_74 = NC,
P_75 = NC,
MDMRTS = NC,
MDMCTS = NC,
} PinName;