Merge pull request #6496 from jarvte/async_cellular

standard non-blocking NetworkInterface::connect
pull/6620/head
Martin Kojtal 2018-04-12 12:02:32 +02:00 committed by GitHub
commit a463b075db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 1327 additions and 1220 deletions

View File

@ -12,6 +12,10 @@ This is the Github repo for Mbed cellular connectivity:
common Common and utility sources
targets Vendor specific cellular module adaptations
TESTS Cellular Greentea test
UNITTESTS Cellular unit test
## Known limitations
**Please note that this is a first release of Cellular framework and is subject to further development in future.**
@ -24,7 +28,9 @@ You can find currently supported cellular modules in the `framework/targets/` fo
## Cellular configuration
You can change cellular defaults in the `mbed_app.json` configuration file:
You can change cellular defaults in the `mbed_lib.json` configuration file.
You can also override cellular defaults in the `mbed_app.json` configuration file:
"config": {
"cellular_plmn": {
@ -62,6 +68,14 @@ You can define the debug tracing level in the `mbed_app.json` configuration file
}
}
## Greentea tests
The `TESTS` folder contains Greentea tests for cellular specific classes. You need to give relevant configuration file with `--app-config` parameter, e.g.:
mbed test -n features-cellular-tests-* --app-config features\cellular\TESTS\socket\udp\template_mbed_app.json -vv
Note that Greentea tests use SIM PIN so you need to change that or your SIM card may get locked.
## Unit tests
The `UNITTESTS` folder contains unit tests for cellular specific classes. Unit tests are based on the stubbing method.

View File

@ -1,82 +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 CELLULAR_TESTS_H
#define CELLULAR_TESTS_H
#include "CellularUtil.h" // for CELLULAR_ helper macros
#include "CellularTargets.h"
#ifdef CELLULAR_DEVICE
#include "mbed_events.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "CellularLog.h"
#include CELLULAR_STRINGIFY(CELLULAR_DEVICE.h)
extern EventQueue queue;
extern CELLULAR_DEVICE cellularDevice;
extern UARTSerial serial;
extern CellularNetwork *network;
extern CellularSMS *sms;
extern CellularPower *pwr;
extern CellularSIM *sim;
/**
* TEST CASES DEFINED HERE AND in main.cpp
*/
// power
void test_create_power(void);
// SIM
void test_get_sim_state(void);
void test_set_pin(void);
void test_change_pin(void);
// sms
void test_sms_init(void);
// network
void test_attach(void);
void test_connect(void);
void test_get_ip_address(void);
void test_disconnect(void);
// stack
void test_socket_open(void);
void test_socket_bind(void);
/*
void test_socket_set_blocking();
void test_socket_send_receive_blocking();
*/
void test_socket_set_non_blocking();
void test_socket_send_receive_non_blocking();
void test_socket_close(void);
// Test closing all interface via device
void test_close_interfaces(void);
#endif // CELLULAR_DEVICE
#endif // CELLULAR_TESTS_H

View File

@ -1,107 +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 "CellularTests.h"
#if !defined(MBED_CONF_NSAPI_PRESENT)
#error [NOT_SUPPORTED] A json configuration file is needed. Skipping this build.
#endif
#ifndef CELLULAR_DEVICE
#error [NOT_SUPPORTED] CELLULAR_DEVICE must be defined for this test
#endif
EventQueue queue(32 * EVENTS_EVENT_SIZE);
Thread t;
CELLULAR_DEVICE cellularDevice(queue);
UARTSerial serial(MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE);
CellularNetwork *network = NULL;
CellularPower *pwr = NULL;
CellularSIM *sim = NULL;
CellularSMS *sms = NULL;
using namespace utest::v1;
// using namespace mbed;
utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason)
{
greentea_case_failure_abort_handler(source, reason);
return STATUS_CONTINUE;
}
Case cases[] = {
// power test
Case("Create power", test_create_power, greentea_failure_handler),
#ifdef MBED_CONF_APP_CELLULAR_SIM_PIN
// sim test
Case("test get SIM state", test_get_sim_state, greentea_failure_handler),
Case("SIM set pin", test_set_pin, greentea_failure_handler),
Case("SIM change pin", test_change_pin, greentea_failure_handler),
#endif
// network tests
Case("attach", test_attach, greentea_failure_handler),
// SMS tests
Case("SMS init", test_sms_init, greentea_failure_handler),
// network tests
Case("connect", test_connect, greentea_failure_handler),
Case("get_ip_address", test_get_ip_address, greentea_failure_handler),
// stack tests
Case("open", test_socket_open, greentea_failure_handler),
Case("bind", test_socket_bind, greentea_failure_handler),
// Case("set socket blocking", test_socket_set_blocking, greentea_failure_handler),
// Case("socket send receive in blocking mode", test_socket_send_receive_blocking, greentea_failure_handler),
Case("set socket non blocking", test_socket_set_non_blocking, greentea_failure_handler),
Case("socket send receive in non blocking mode", test_socket_send_receive_non_blocking, greentea_failure_handler),
Case("close", test_socket_close, greentea_failure_handler),
// network tests
Case("disconnect", test_disconnect, greentea_failure_handler),
// test closing of all interface, must be the last test case
Case("Close all Interfaces", test_close_interfaces, greentea_failure_handler)
};
utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(300, "default_auto");
return verbose_test_setup_handler(number_of_cases);
}
Specification specification(test_setup, cases);
void test_close_interfaces()
{
// SMS is already closed in it's test
cellularDevice.close_network();
cellularDevice.close_sim();
cellularDevice.close_power();
}
int main()
{
#if defined (MDMRTS) && defined (MDMCTS)
serial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS);
#endif
pwr = cellularDevice.open_power(&serial);
sim = cellularDevice.open_sim(&serial);
sms = cellularDevice.open_sms(&serial);
network = cellularDevice.open_network(&serial);
t.start(callback(&queue, &EventQueue::dispatch_forever));
return Harness::run(specification);
}

View File

@ -1,104 +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 "CellularTests.h"
#ifdef CELLULAR_DEVICE
using namespace mbed;
static bool wait_register()
{
tr_info("Try registering to network...");
if (network->set_registration() != NSAPI_ERROR_OK) {
tr_error("Network registration request failed.");
return false;
}
CellularNetwork::RegistrationStatus status;
for (int i=0; i<180; i++) {
tr_info("Register to network %d...", i);
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
if (network->get_registration_status((CellularNetwork::RegistrationType)type, status) == NSAPI_ERROR_OK) {
tr_info("status %d...", status);
switch (status) {
case CellularNetwork::RegisteredRoaming:
// fall-through
case CellularNetwork::RegisteredHomeNetwork:
tr_info("Registered to network.");
return true;
case CellularNetwork::RegisteredSMSOnlyRoaming:
// fall-through
case CellularNetwork::RegisteredSMSOnlyHome:
tr_warn("SMS only network registration!");
return true;
case CellularNetwork::RegisteredCSFBNotPreferredRoaming:
// fall-through
case CellularNetwork::RegisteredCSFBNotPreferredHome:
tr_warn("Not preferred network registration!");
return true;
case CellularNetwork::AttachedEmergencyOnly:
tr_warn("Emergency only network registration!");
return true;
case CellularNetwork::RegistrationDenied:
tr_warn("Network registration denied!");
wait(i);
break;
case CellularNetwork::NotRegistered:
case CellularNetwork::Unknown:
case CellularNetwork::SearchingNetwork:
default:
break;
}
}
}
wait(1);
}
return false;
}
void test_attach()
{
cellularDevice.set_timeout(120*1000); // 120 second timeout for at commands after power is up. It might take time to register, attach and connect
tr_info("Register to network.");
TEST_ASSERT(wait_register());
tr_info("Attach to network.");
nsapi_error_t err = network->set_attach();
TEST_ASSERT(!err);
CellularNetwork::AttachStatus status;
err = network->get_attach(status);
TEST_ASSERT(!err);
}
void test_connect()
{
nsapi_error_t err = network->connect();
TEST_ASSERT(!err);
}
void test_get_ip_address()
{
const char *ip = network->get_ip_address();
TEST_ASSERT(ip && ip[0]);
tr_info("IP: %s\r\n", ip);
}
void test_disconnect()
{
nsapi_error_t err = network->disconnect();
TEST_ASSERT(!err);
}
#endif // CELLULAR_DEVICE

View File

@ -1,52 +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 "CellularTests.h"
#ifdef CELLULAR_DEVICE
using namespace mbed;
static bool start_cellular_at(CellularPower *pwr)
{
nsapi_error_t err = pwr->off();
if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED) {
return false;
}
err = pwr->on();
if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED) {
return false;
}
tr_info("Wait for cellular device 180 seconds...");
for (int i = 0; i < 180; i++) {
if (pwr->set_at_mode() == NSAPI_ERROR_OK) {
return true;
}
wait(1);
}
return false;
}
void test_create_power()
{
TEST_ASSERT(start_cellular_at(pwr));
tr_info("Cellular device is ready!");
}
// TODO: tests still missing for off, sleep, opt_power_save_mode, opt_receive_period
#endif // CELLULAR_DEVICE

View File

@ -1,90 +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 "CellularTests.h"
#ifdef CELLULAR_DEVICE
#ifdef MBED_CONF_APP_CELLULAR_SIM_PIN
using namespace mbed;
void test_get_sim_state()
{
wait(1);
CellularSIM::SimState state = CellularSIM::SimStateUnknown;
tr_info("Wait SIM for 180 seconds...");
for (int i = 0; i < 180; i++) {
CellularSIM::SimState tmp_state;
if ((sim->get_sim_state(tmp_state) == NSAPI_ERROR_OK) && tmp_state != CellularSIM::SimStateUnknown) {
state = tmp_state;
break;
}
}
TEST_ASSERT_MESSAGE(state == CellularSIM::SimStateReady || state == CellularSIM::SimStatePinNeeded ||
state == CellularSIM::SimStatePukNeeded, "Invalid SIM state");
}
// creates PIN which is different than one defined in MBED_CONF_APP_CELLULAR_SIM_PIN
static void create_random_pin(char* random_pin)
{
char s[11];
do {
sprintf(s,"%d", rand());
} while (strncmp(s, MBED_CONF_APP_CELLULAR_SIM_PIN, 4) == 0);
strncpy(random_pin, s, 4);
random_pin[4] = '\0';
}
void test_set_pin()
{
// run test only if sim is not in ready state as then sim interface will return NSAPI_ERROR_OK
nsapi_error_t err;
CellularSIM::SimState state = CellularSIM::SimStateUnknown;
if ((sim->get_sim_state(state) == NSAPI_ERROR_OK) && (state != CellularSIM::SimStateReady)) {
char random_pin[5];
create_random_pin(random_pin);
err = sim->set_pin(random_pin);
TEST_ASSERT_MESSAGE(err != 0, "Setting random pin should fail");
}
err = sim->set_pin(MBED_CONF_APP_CELLULAR_SIM_PIN);
char err_msg[60];
sprintf(err_msg, "Setting correct pin: %s failed with: %d", MBED_CONF_APP_CELLULAR_SIM_PIN, err);
TEST_ASSERT_MESSAGE(err == 0, err_msg);
}
void test_change_pin()
{
char random_pin[5];
create_random_pin(random_pin);
nsapi_error_t err = sim->change_pin(MBED_CONF_APP_CELLULAR_SIM_PIN, random_pin);
char err_msg[60];
sprintf(err_msg, "Change from original pin failed with: %d", err);
TEST_ASSERT_MESSAGE(err == NSAPI_ERROR_OK, err_msg);
err = sim->change_pin(random_pin, MBED_CONF_APP_CELLULAR_SIM_PIN);
sprintf(err_msg, "Change back original pin failed with: %d", err);
TEST_ASSERT_MESSAGE(err == NSAPI_ERROR_OK, err_msg);
}
#endif
#endif // CELLULAR_DEVICE

View File

@ -1,46 +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 "CellularTests.h"
#ifdef CELLULAR_DEVICE
using namespace mbed;
void test_sms_init()
{
// for some weird reason if we don't wait for few seconds we get SIM Busy error in initialize even is SIM is ready...
wait(3);
// check SIM state as we have tested sim and it might not be ready
for (int i = 0; i < MAX_SIM_READY_WAITING_TIME; i++) {
CellularSIM::SimState state;
if (sim->get_sim_state(state) == NSAPI_ERROR_OK && state == CellularSIM::SimStateReady) {
break;
}
wait(1);
}
nsapi_error_t err = sms->initialize(CellularSMS::CellularSMSMmodeText);
char err_msg[60];
sprintf(err_msg, "SMS initialize failed with: %d", err);
cellularDevice.close_sms();
sms = NULL;
TEST_ASSERT_MESSAGE(!err, err_msg);
}
#endif // CELLULAR_DEVICE

View File

@ -1,120 +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 "CellularTests.h"
#ifdef CELLULAR_DEVICE
using namespace mbed;
static UDPSocket socket;
#define SERVER_IP_ADDR "52.215.34.155"
#define SERVER_UDP_PORT 7
static rtos::Semaphore sock_event;
void test_socket_open()
{
nsapi_error_t err = socket.open(network);
TEST_ASSERT(err == NSAPI_ERROR_OK);
}
void test_socket_bind()
{
nsapi_error_t err = socket.bind(3030);
TEST_ASSERT(!err);
}
/*
void test_socket_set_blocking()
{
//socket.set_blocking(true);
socket.set_timeout(5000);
}
void test_socket_send_receive_blocking()
{
char receive_buffer[CELLULAR_MTU] = {0};
char send_buffer[] = { 'H', 'e', 'l', 'l', 'u', 'l', 'a', 'r', '!' };
int send_count = 0;
int send_tries = 1;
int max_send_tries = 3;
// Send to echo server
while (send_tries <= max_send_tries) {
tr_info("ONE!!!");
send_count = socket.sendto(SERVER_IP_ADDR, SERVER_UDP_PORT, send_buffer, sizeof(send_buffer));
TEST_ASSERT_MESSAGE(send_count == sizeof(send_buffer), "Sent count doesnt match sent buffer!");
send_tries++;
// Read response
SocketAddress address;
int receive_count = 0;
// 2 tries. First recv attempt should be blocked and wait for a max 5 seconds for socket read flag
int recv_tries = 2;
while (recv_tries >= 0) {
tr_info("RECV!!!");
receive_count = socket.recvfrom(&address, receive_buffer, sizeof(receive_buffer));
if (receive_count > 0) {
break;
}
recv_tries--;
wait(1);
}
TEST_ASSERT_MESSAGE(receive_count == send_count, "Receive and Sent count dont match!");
TEST_ASSERT_MESSAGE(strncmp(send_buffer, receive_buffer, send_count) == 0, "Sent data doesn't match received data while in ECHO");
}
}
*/
static void socket_sigio_cb()
{
sock_event.release();
}
void test_socket_set_non_blocking()
{
socket.set_blocking(false);
socket.sigio(socket_sigio_cb);
}
void test_socket_send_receive_non_blocking()
{
char receive_buffer[1500] = {0};
char send_buffer[] = { 'H', 'e', 'l', 'l', 'u', 'l', 'a', 'r', '!' };
// Send to echo server
int send_count = socket.sendto(SERVER_IP_ADDR, SERVER_UDP_PORT, send_buffer, sizeof(send_buffer));
TEST_ASSERT(send_count == sizeof(send_buffer));
int32_t event;
event = sock_event.wait(10000);
TEST_ASSERT_MESSAGE( event>=1, "No Socket event within 10 seconds");
// Read response
SocketAddress address;
int receive_count = socket.recvfrom(&address, receive_buffer, sizeof(receive_buffer));
TEST_ASSERT_MESSAGE(receive_count == send_count, "Receive and Sent count dont match!");
TEST_ASSERT_MESSAGE(strncmp(send_buffer, receive_buffer, send_count) == 0, "Sent data doesn't match received data while in ECHO");
}
void test_socket_close()
{
nsapi_error_t err = socket.close();
TEST_ASSERT(!err);
}
#endif // CELLULAR_DEVICE

View File

@ -0,0 +1,203 @@
/*
* 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.
*/
#if !defined(MBED_CONF_NSAPI_PRESENT)
#error [NOT_SUPPORTED] A json configuration file is needed. Skipping this build.
#endif
#include "CellularUtil.h" // for CELLULAR_ helper macros
#include "CellularTargets.h"
#ifndef CELLULAR_DEVICE
#error [NOT_SUPPORTED] CELLULAR_DEVICE must be defined
#endif
#ifndef MBED_CONF_APP_CELLULAR_SIM_PIN
#error [NOT_SUPPORTED] SIM pin code is needed. Skipping this build.
#endif
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "mbed.h"
#include "CellularConnectionFSM.h"
#if MBED_CONF_CELLULAR_USE_APN_LOOKUP || MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP
#include "APN_db.h"
#endif //MBED_CONF_CELLULAR_USE_APN_LOOKUP || MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP
#include "CellularLog.h"
#define NETWORK_TIMEOUT (180*1000)
#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;
static SocketAddress echo_server_addr;
class EchoSocket : public UDPSocket {
public:
EchoSocket(int size) : UDPSocket(), _async_flag(0), _data(0), _size(size) {
}
virtual ~EchoSocket() {
delete _data;
}
void set_async(int async) {
_async_flag = async;
if (_async_flag) {
set_blocking(false);
sigio(callback(this, &EchoSocket::async_callback));
} else {
set_blocking(true);
set_timeout(SOCKET_TIMEOUT);
sigio(NULL);
}
}
void test_sendto(const char *const hostname = NULL) {
_data = new uint8_t[_size];
for (int i=0; i<_size; i++) {
_data[i] = (uint8_t)rand();
}
// clear pending events
while ((EchoSocket::eventFlags.wait_any(_async_flag, SOCKET_TIMEOUT) & (osFlagsError | _async_flag)) == _async_flag);
if (hostname) {
TEST_ASSERT(sendto(hostname, ECHO_SERVER_UDP_PORT, _data, _size) == _size);
} else {
TEST_ASSERT(sendto(echo_server_addr, _data, _size) == _size);
}
}
void test_recvfrom() {
if (_async_flag) {
TEST_ASSERT((EchoSocket::eventFlags.wait_any(_async_flag, SOCKET_TIMEOUT) & (osFlagsError | _async_flag)) == _async_flag);
}
uint8_t *buf = new uint8_t[_size];
memset(buf, 0, _size);
SocketAddress recv_address;
TEST_ASSERT(recvfrom(&recv_address, buf, _size) == _size);
TEST_ASSERT(recv_address == echo_server_addr);
TEST_ASSERT(memcmp(_data, buf, _size) == 0);
delete buf;
delete _data;
_data = 0;
}
private:
void async_callback() {
EchoSocket::eventFlags.set(_async_flag);
}
uint8_t *_data;
int _size;
uint32_t _async_flag; // 0 for blocking socket, signal bit for async
static rtos::EventFlags eventFlags;
};
rtos::EventFlags EchoSocket::eventFlags;
static void network_callback(nsapi_event_t ev, intptr_t ptr)
{
if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE) {
if (ptr == NSAPI_STATUS_GLOBAL_UP) {
MBED_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);
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);
}
static void udp_gethostbyname()
{
TEST_ASSERT(cellular.get_network()->gethostbyname(ECHO_SERVER_NAME, &echo_server_addr) == 0);
tr_info("HOST: %s", echo_server_addr.get_ip_address());
echo_server_addr.set_port(7);
wait(1);
}
static void udp_socket_send_receive()
{
EchoSocket echo_socket(4);
TEST_ASSERT(echo_socket.open(cellular.get_network()) == NSAPI_ERROR_OK);
echo_socket.set_async(0);
echo_socket.test_sendto();
echo_socket.test_recvfrom();
TEST_ASSERT(echo_socket.close() == NSAPI_ERROR_OK);
wait(1);
}
static void udp_socket_send_receive_async()
{
EchoSocket echo_socket(4);
TEST_ASSERT(echo_socket.open(cellular.get_network()) == NSAPI_ERROR_OK);
echo_socket.set_async(1);
echo_socket.test_sendto();
echo_socket.test_recvfrom();
TEST_ASSERT(echo_socket.close() == NSAPI_ERROR_OK);
wait(1);
}
using namespace utest::v1;
static utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason)
{
greentea_case_failure_abort_handler(source, reason);
return STATUS_ABORT;
}
static Case cases[] = {
Case("UDP network stack", udp_network_stack, greentea_failure_handler),
Case("UDP gethostbyname", udp_gethostbyname, greentea_failure_handler),
Case("UDP socket send/receive", udp_socket_send_receive, greentea_failure_handler),
Case("UDP socket send/receive async", udp_socket_send_receive_async, greentea_failure_handler),
//Case("UDP socket multiple simultaneous", udp_socket_multiple_simultaneous, greentea_failure_handler),
};
static utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(10*60, "default_auto"); // network registration may take up to 180 seconds, DNS query a couple of minutes, etc.
return verbose_test_setup_handler(number_of_cases);
}
static Specification specification(test_setup, cases);
int main()
{
mbed_trace_init();
return Harness::run(specification);
}

View File

@ -1,30 +1,39 @@
{
"config": {
"sock-type": "UDP",
"network-interface":{
"help": "Options are ETHERNET,CELLULAR",
"value": "CELLULAR"
},
"cellular_sim_pin": {
"help": "PIN code",
"value": "\"1234\""
},
"apn": {
"help": "The APN string to use for this SIM/network, set to 0 if none",
"value": 0
},
"username": {
"help": "The user name string to use for this APN, set to zero if none",
"value": 0
},
"password": {
"help": "The password string to use for this APN, set to 0 if none",
"value": 0
},
"trace-level": {
"help": "Options are TRACE_LEVEL_ERROR,TRACE_LEVEL_WARN,TRACE_LEVEL_INFO,TRACE_LEVEL_DEBUG",
"macro_name": "MBED_TRACE_MAX_LEVEL",
"value": "TRACE_LEVEL_INFO"
}
},
},
"target_overrides": {
"*": {
"ppp-cell-iface.apn-lookup": false,
"cellular.use-apn-lookup": false,
"target.features_add": ["LWIP", "COMMON_PAL"],
"mbed-trace.enable": true,
"mbed-trace.enable": false,
"lwip.ipv4-enabled": true,
"lwip.ethernet-enabled": false,
"lwip.ipv6-enabled": true,
"lwip.tcp-enabled": false,
"lwip.ppp-enabled": true,
"lwip.tcp-enabled": true,
"lwip.ethernet-enabled": false,
"platform.stdio-convert-newlines": true,
"platform.stdio-baud-rate": 115200,
"platform.default-serial-baud-rate": 115200
}
}

View File

@ -195,8 +195,8 @@ void Test_AT_CellularNetwork::test_AT_CellularNetwork_set_access_technology()
ATHandler at(&fh1, que, 0, ",");
AT_CellularNetwork cn(at);
CHECK(NSAPI_ERROR_UNSUPPORTED == cn.set_access_technology(CellularNetwork::operator_t::RAT_UNKNOWN));
CHECK(NSAPI_ERROR_UNSUPPORTED == cn.set_access_technology(CellularNetwork::operator_t::RAT_GSM_COMPACT));
CHECK(NSAPI_ERROR_UNSUPPORTED == cn.set_access_technology(CellularNetwork::RAT_UNKNOWN));
CHECK(NSAPI_ERROR_UNSUPPORTED == cn.set_access_technology(CellularNetwork::RAT_GSM_COMPACT));
}
void Test_AT_CellularNetwork::test_AT_CellularNetwork_scan_plmn()

View File

@ -287,7 +287,7 @@ void Test_ATHandler::test_ATHandler_cmd_start()
ATHandler at(&fh1, que, 0, ",");
mbed_poll_stub::revents_value = POLLOUT;
mbed_poll_stub::int_value = 1;
fh1.size_value = 1;
fh1.size_value = 3;
at.cmd_start("s");
mbed_poll_stub::revents_value = POLLIN;
mbed_poll_stub::int_value = 0;
@ -303,12 +303,13 @@ void Test_ATHandler::test_ATHandler_write_int()
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
fh1.size_value = -1;
at.write_int(4);
at.clear_error();
mbed_poll_stub::revents_value = POLLOUT;
mbed_poll_stub::int_value = 1;
fh1.size_value = 1;
fh1.size_value = 6;
at.write_int(4);
at.write_int(2147483647);
@ -331,7 +332,7 @@ void Test_ATHandler::test_ATHandler_write_string()
at.clear_error();
mbed_poll_stub::revents_value = POLLOUT;
mbed_poll_stub::int_value = 1;
fh1.size_value = 1;
fh1.size_value = -1;
at.cmd_start("s");
at.write_string("help", true);
CHECK(NSAPI_ERROR_DEVICE_ERROR == at.get_last_error());
@ -339,7 +340,7 @@ void Test_ATHandler::test_ATHandler_write_string()
at.clear_error();
mbed_poll_stub::revents_value = POLLOUT;
mbed_poll_stub::int_value = 1;
fh1.size_value = 3;
fh1.size_value = -1;
at.write_string("help", true);
CHECK(NSAPI_ERROR_DEVICE_ERROR == at.get_last_error());
@ -357,6 +358,7 @@ void Test_ATHandler::test_ATHandler_cmd_stop()
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
fh1.size_value = -1;
at.cmd_stop();
at.write_string("help", true);
@ -371,6 +373,7 @@ void Test_ATHandler::test_ATHandler_write_bytes()
FileHandle_stub fh1;
ATHandler at(&fh1, que, 0, ",");
fh1.size_value = -1;
uint8_t data[] = "data";
at.write_bytes(data, 4);

View File

@ -79,9 +79,10 @@ void ATHandler::set_file_handle(FileHandle *fh)
{
}
void ATHandler::set_urc_handler(const char *urc, mbed::Callback<void()> cb)
nsapi_error_t ATHandler::set_urc_handler(const char *urc, mbed::Callback<void()> cb)
{
ATHandler_stub::callback = cb;
return NSAPI_ERROR_OK;
}
nsapi_error_t ATHandler::get_last_error() const

View File

@ -33,6 +33,11 @@ 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)
{
@ -56,6 +61,11 @@ 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;
@ -100,11 +110,17 @@ 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(bool urc_on)
nsapi_error_t AT_CellularNetwork::set_registration_urc(RegistrationType type, bool urc_on)
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::get_network_registering_mode(NWRegisteringMode& mode)
{
mode = NWModeAutomatic;
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::set_registration(const char *plmn)
{
return NSAPI_ERROR_OK;
@ -171,16 +187,22 @@ void AT_CellularNetwork::urc_no_carrier()
}
nsapi_error_t AT_CellularNetwork::set_access_technology_impl(operator_t::RadioAccessTechnology opsAct)
nsapi_error_t AT_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opsAct)
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::set_access_technology(operator_t::RadioAccessTechnology opAct)
nsapi_error_t AT_CellularNetwork::set_access_technology(RadioAccessTechnology opAct)
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::get_access_technology(RadioAccessTechnology& rat)
{
rat = RAT_CATM1;
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::scan_plmn(operList_t &operators, int &opsCount)
{
return NSAPI_ERROR_OK;

View File

@ -64,3 +64,13 @@ nsapi_error_t AT_CellularPower::opt_receive_period(int mode, EDRXAccessTechnolog
{
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularPower::set_device_ready_urc_cb(mbed::Callback<void()> callback)
{
return NSAPI_ERROR_OK;
}
void AT_CellularPower::remove_device_ready_urc_cb(mbed::Callback<void()> callback){
}

View File

@ -29,7 +29,7 @@ static uint8_t filehandle_stub_table_pos = 0;
class FileHandle_stub : public FileHandle
{
public:
size_t size_value;
ssize_t size_value;
FileHandle_stub() {size_value = 0;}
@ -47,9 +47,11 @@ public:
}
virtual ssize_t write(const void *buffer, size_t size){
if( size_value ) {
if (size_value > 0) {
size_value--;
return size;
} else if (size_value < 0) {
return -1;
}
return 0;
}

View File

@ -23,11 +23,13 @@
#define MBED_TRACE_MAX_LEVEL TRACE_LEVEL_INFO
#endif
#include "CellularLog.h"
#include "CellularCommon.h"
// timeout to wait for AT responses
#define TIMEOUT_POWER_ON (1*1000)
#define TIMEOUT_SIM_PIN (1*1000)
#define TIMEOUT_NETWORK (10*1000)
#define TIMEOUT_CONNECT (60*1000)
#define TIMEOUT_REGISTRATION (180*1000)
// maximum time when retrying network register, attach and connect in seconds ( 20minutes )
@ -35,42 +37,65 @@
#define RETRY_COUNT_DEFAULT 3
namespace mbed {
namespace mbed
{
CellularConnectionFSM::CellularConnectionFSM() :
_serial(0), _state(STATE_INIT), _next_state(_state), _status_callback(0), _network(0), _power(0), _sim(0),
_queue(8 * EVENTS_EVENT_SIZE), _queue_thread(0), _retry_count(0), _state_retry_count(0), _at_queue(8 * EVENTS_EVENT_SIZE)
_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(8 * EVENTS_EVENT_SIZE), _event_id(0)
{
memset(_sim_pin, 0, sizeof(_sim_pin));
#if MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY == 0
_start_time = 0;
#else
// so that not every device don't start at the exact same time (for example after power outage)
_start_time = rand() % (MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY);
#endif // MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY
// set initial retry values in seconds
_retry_timeout_array[0] = 1;
_retry_timeout_array[0] = 1; // double time on each retry in order to keep network happy
_retry_timeout_array[1] = 2;
_retry_timeout_array[2] = 4;
_retry_timeout_array[3] = 16;
_retry_timeout_array[4] = 32;
_retry_timeout_array[5] = 60;
_retry_timeout_array[6] = 120;
_retry_timeout_array[7] = 360;
_retry_timeout_array[3] = 8;
_retry_timeout_array[4] = 16;
_retry_timeout_array[5] = 32;
_retry_timeout_array[6] = 64;
_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;
_cellularDevice = new CELLULAR_DEVICE(_at_queue);
}
CellularConnectionFSM::~CellularConnectionFSM()
{
stop();
delete _cellularDevice;
}
void CellularConnectionFSM::stop()
{
tr_info("CellularConnectionUtil::stop");
if (_cellularDevice) {
_cellularDevice->close_power();
_cellularDevice->close_network();
}
if (_queue_thread) {
_queue_thread->terminate();
delete _queue_thread;
_queue_thread = NULL;
}
}
nsapi_error_t CellularConnectionFSM::init()
{
tr_info("CELLULAR_DEVICE: %s", CELLULAR_STRINGIFY(CELLULAR_DEVICE));
_cellularDevice = new CELLULAR_DEVICE(_at_queue);
if (!_cellularDevice) {
stop();
return NSAPI_ERROR_NO_MEMORY;
}
_power = _cellularDevice->open_power(_serial);
if (!_power) {
stop();
@ -90,18 +115,15 @@ nsapi_error_t CellularConnectionFSM::init()
_at_queue.chain(&_queue);
tr_info("init done...");
return NSAPI_ERROR_OK;
_retry_count = 0;
_state = STATE_INIT;
_next_state = STATE_INIT;
return _network->init();
}
bool CellularConnectionFSM::open_power(FileHandle *fh)
bool CellularConnectionFSM::power_on()
{
if (!_power) {
_power = _cellularDevice->open_power(fh);
if (!_power) {
return false;
}
}
nsapi_error_t err = _power->on();
if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED) {
tr_warn("Cellular start failed. Power off/on.");
@ -117,6 +139,7 @@ bool CellularConnectionFSM::open_power(FileHandle *fh)
void CellularConnectionFSM::set_sim_pin(const char * sim_pin)
{
strncpy(_sim_pin, sim_pin, sizeof(_sim_pin));
_sim_pin[sizeof(_sim_pin)-1] = '\0';
}
bool CellularConnectionFSM::open_sim()
@ -124,53 +147,45 @@ bool CellularConnectionFSM::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
while (_sim->get_sim_state(state) != NSAPI_ERROR_OK || state == CellularSIM::SimStateUnknown) {
tr_info("Waiting for SIM (state %d)...", state);
if (_sim->get_sim_state(state) != NSAPI_ERROR_OK) {
tr_info("Waiting for SIM (err while reading)...");
return false;
}
tr_info("Initial SIM state: %d", state);
if (strlen(_sim_pin)) {
nsapi_error_t err;
if (state == CellularSIM::SimStatePinNeeded) {
tr_info("SIM pin required, entering pin: %s", _sim_pin);
err = _sim->set_pin(_sim_pin);
if (err) {
tr_error("SIM pin set failed with: %d, bailing out...", err);
return false;
}
// here you could add wait(secs) if you know delay of changing PIN on your SIM
for (int i = 0; i < MAX_SIM_READY_WAITING_TIME; i++) {
if (_sim->get_sim_state(state) == NSAPI_ERROR_OK && state == CellularSIM::SimStateReady) {
break;
switch (state) {
case CellularSIM::SimStateReady:
tr_info("SIM Ready");
break;
case CellularSIM::SimStatePinNeeded: {
if (strlen(_sim_pin)) {
tr_info("SIM pin required, entering pin: %s", _sim_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("SIM state: %d", state);
return false;
} else {
tr_warn("PIN required but No SIM pin provided.");
}
}
} else {
tr_info("No SIM pin provided.");
break;
case CellularSIM::SimStatePukNeeded:
tr_info("SIM PUK code needed...");
break;
case CellularSIM::SimStateUnknown:
tr_info("SIM, unknown state...");
break;
default:
MBED_ASSERT(1);
break;
}
if (_event_status_cb) {
_event_status_cb((nsapi_event_t)CellularSIMStatusChanged, state);
}
return state == CellularSIM::SimStateReady;
}
void CellularConnectionFSM::device_ready()
{
CellularInformation *info = _cellularDevice->open_information(_serial);
char device_info_buf[2048]; // may be up to 2048 according to 3GPP
if (info->get_manufacturer(device_info_buf, sizeof(device_info_buf)) == NSAPI_ERROR_OK) {
tr_info("Cellular device manufacturer: %s", device_info_buf);
}
if (info->get_model(device_info_buf, sizeof(device_info_buf)) == NSAPI_ERROR_OK) {
tr_info("Cellular device model: %s", device_info_buf);
}
if (info->get_revision(device_info_buf, sizeof(device_info_buf)) == NSAPI_ERROR_OK) {
tr_info("Cellular device revision: %s", device_info_buf);
}
}
bool CellularConnectionFSM::set_network_registration(char *plmn)
{
if (_network->set_registration(plmn) != NSAPI_ERROR_OK) {
@ -180,6 +195,23 @@ bool CellularConnectionFSM::set_network_registration(char *plmn)
return true;
}
bool CellularConnectionFSM::is_registered()
{
CellularNetwork::RegistrationStatus status;
bool is_registered = false;
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
if (get_network_registration((CellularNetwork::RegistrationType) type, status, is_registered)) {
tr_debug("get_network_registration: type=%d, status=%d", type, status);
if (is_registered) {
break;
}
}
}
return is_registered;
}
bool CellularConnectionFSM::get_network_registration(CellularNetwork::RegistrationType type,
CellularNetwork::RegistrationStatus &status, bool &is_registered)
{
@ -195,19 +227,19 @@ bool CellularConnectionFSM::get_network_registration(CellularNetwork::Registrati
switch (status) {
case CellularNetwork::RegisteredRoaming:
is_roaming = true;
// fall-through
// fall-through
case CellularNetwork::RegisteredHomeNetwork:
is_registered = true;
break;
case CellularNetwork::RegisteredSMSOnlyRoaming:
is_roaming = true;
// fall-through
// fall-through
case CellularNetwork::RegisteredSMSOnlyHome:
tr_warn("SMS only network registration!");
break;
case CellularNetwork::RegisteredCSFBNotPreferredRoaming:
is_roaming = true;
// fall-through
// fall-through
case CellularNetwork::RegisteredCSFBNotPreferredHome:
tr_warn("Not preferred network registration!");
break;
@ -255,10 +287,46 @@ void CellularConnectionFSM::report_failure(const char* msg)
}
}
const char* CellularConnectionFSM::get_state_string(CellularState state)
{
static const char *strings[] = { "Init", "Power", "Device ready", "SIM pin", "Registering network", "Attaching network", "Connecting network", "Connected"};
return strings[state];
}
nsapi_error_t CellularConnectionFSM::is_automatic_registering(bool& auto_reg)
{
CellularNetwork::NWRegisteringMode mode;
nsapi_error_t err = _network->get_network_registering_mode(mode);
if (err == NSAPI_ERROR_OK) {
tr_debug("automatic registering mode: %d", mode);
auto_reg = (mode == CellularNetwork::NWModeAutomatic);
}
return err;
}
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)
{
_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();
@ -268,223 +336,200 @@ nsapi_error_t CellularConnectionFSM::continue_to_state(CellularState state)
return NSAPI_ERROR_OK;
}
void CellularConnectionFSM::enter_to_state(CellularState state)
{
_next_state = state;
_retry_count = 0;
}
void CellularConnectionFSM::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);
_event_timeout = _retry_timeout_array[_retry_count];
} else {
report_failure(get_state_string(_state));
return;
}
}
void CellularConnectionFSM::state_init()
{
_event_timeout = _start_time;
tr_info("Init state, waiting %d ms before POWER state)", _start_time);
enter_to_state(STATE_POWER_ON);
}
void CellularConnectionFSM::state_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);
} else {
// retry to power on device
retry_state_or_fail();
}
}
bool CellularConnectionFSM::device_ready()
{
tr_info("Cellular device ready");
if (_event_status_cb) {
_event_status_cb((nsapi_event_t)CellularDeviceReady, 0);
}
_power->remove_device_ready_urc_cb(mbed::callback(this, &CellularConnectionFSM::ready_urc_cb));
bool success = false;
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
if (!_network->set_registration_urc((CellularNetwork::RegistrationType)type, true)) {
success = true;
}
}
if (!success) {
tr_error("Failed to set any URC's for registration");
report_failure(get_state_string(_state));
return false;
}
return true;
}
void CellularConnectionFSM::state_device_ready()
{
_cellularDevice->set_timeout(TIMEOUT_POWER_ON);
if (_power->set_at_mode() == NSAPI_ERROR_OK) {
if (device_ready()) {
enter_to_state(STATE_SIM_PIN);
}
} else {
if (_retry_count == 0) {
(void)_power->set_device_ready_urc_cb(mbed::callback(this, &CellularConnectionFSM::ready_urc_cb));
}
retry_state_or_fail();
}
}
void CellularConnectionFSM::state_sim_pin()
{
_cellularDevice->set_timeout(TIMEOUT_SIM_PIN);
tr_info("Sim state (timeout %d ms)", TIMEOUT_SIM_PIN);
if (open_sim()) {
enter_to_state(STATE_REGISTERING_NETWORK);
} else {
retry_state_or_fail();
}
}
void CellularConnectionFSM::state_registering()
{
_cellularDevice->set_timeout(TIMEOUT_NETWORK);
if (is_registered()) {
// we are already registered, go to attach
enter_to_state(STATE_ATTACHING_NETWORK);
} else {
bool auto_reg = false;
nsapi_error_t err = is_automatic_registering(auto_reg);
if (err == NSAPI_ERROR_OK && !auto_reg) { // when we support plmn add this : || plmn
// automatic registering is not on, set registration and retry
_cellularDevice->set_timeout(TIMEOUT_REGISTRATION);
set_network_registration();
}
retry_state_or_fail();
}
}
void CellularConnectionFSM::state_attaching()
{
_cellularDevice->set_timeout(TIMEOUT_CONNECT);
CellularNetwork::AttachStatus attach_status;
if (get_attach_network(attach_status)) {
if (attach_status == CellularNetwork::Attached) {
enter_to_state(STATE_CONNECTING_NETWORK);
} else {
set_attach_network();
retry_state_or_fail();
}
} else {
retry_state_or_fail();
}
}
void CellularConnectionFSM::state_connect_to_network()
{
_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();
}
}
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()
{
nsapi_error_t err;
int event_timeout = -1;
_event_timeout = -1;
switch (_state) {
case STATE_INIT:
event_timeout = _start_time;
tr_info("INIT state, waiting %d ms before POWER state)", _start_time);
_next_state = STATE_POWER_ON;
state_init();
break;
case STATE_POWER_ON:
_cellularDevice->set_timeout(TIMEOUT_POWER_ON);
tr_info("Cellular power ON (timeout %d ms)", TIMEOUT_POWER_ON);
if (open_power(_serial)) {
_next_state = STATE_DEVICE_READY;
_retry_count = 0;
} else {
if (++_retry_count <= RETRY_COUNT_DEFAULT) {
tr_warn("Power ON retry %d", _retry_count);
event_timeout = 3 * 1000;
} else {
report_failure("Power");
return;
}
}
state_power_on();
break;
case STATE_DEVICE_READY:
_cellularDevice->set_timeout(TIMEOUT_POWER_ON);
if (_power->set_at_mode() == NSAPI_ERROR_OK) {
tr_info("Cellular device ready");
_next_state = STATE_SIM_PIN;
_retry_count = 0;
device_ready();
} else {
tr_info("Waiting for cellular device (retry %d/%d, timeout %d ms)", _retry_count, RETRY_COUNT_DEFAULT,
TIMEOUT_POWER_ON);
if (_retry_count++ <= RETRY_COUNT_DEFAULT) {
event_timeout = 3 * 1000;
} else {
report_failure("Power");
return;
}
}
state_device_ready();
break;
case STATE_SIM_PIN:
_cellularDevice->set_timeout(TIMEOUT_SIM_PIN);
tr_info("Start cellular (timeout %d ms)", TIMEOUT_SIM_PIN);
if (open_sim()) {
_next_state = STATE_REGISTERING_NETWORK;
_retry_count = 0;
_state_retry_count = 0;
tr_info("Check for network registration");
} else {
if (_retry_count++ <= RETRY_COUNT_DEFAULT) {
tr_warn("Waiting for SIM %d/%d", _retry_count, RETRY_COUNT_DEFAULT);
event_timeout = 3 * 1000;
} else {
report_failure("Entering SIM PIN");
return;
}
}
state_sim_pin();
break;
case STATE_REGISTERING_NETWORK:
_cellularDevice->set_timeout(TIMEOUT_NETWORK);
CellularNetwork::RegistrationStatus status;
bool is_registered;
_next_state = STATE_REGISTER_NETWORK;
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
if (get_network_registration((CellularNetwork::RegistrationType) type, status, is_registered)) {
tr_debug("get_network_registration: type=%d, status=%d", type, status);
if (is_registered) {
tr_info("Registered to cellular network (type %d, status %d)", type, status);
_next_state = STATE_ATTACHING_NETWORK;
_retry_count = 0;
_state_retry_count = 0;
event_timeout = 0;
tr_info("Check cellular network attach state");
break;
} else {
if (_retry_count < 180) {
event_timeout = 1000;
_next_state = STATE_REGISTERING_NETWORK;
tr_info("Waiting for registration %d/180 (type %d, status %d)", _retry_count, type, status);
} else {
tr_info("Start cellular registration");
_next_state = STATE_REGISTER_NETWORK;
_retry_count = 0;
break;
}
}
}
}
if (_next_state == STATE_REGISTERING_NETWORK) {
_retry_count++;
}
break;
case STATE_REGISTER_NETWORK:
_cellularDevice->set_timeout(TIMEOUT_REGISTRATION);
tr_info("Register to cellular network (timeout %d ms)", TIMEOUT_REGISTRATION);
if (set_network_registration()) {
_next_state = STATE_REGISTERING_NETWORK;
_retry_count = 0;
if (_state_retry_count > RETRY_COUNT_DEFAULT) {
report_failure("Registration retry");
return;
}
_state_retry_count++;
} else {
if (_retry_count < _retry_array_length) {
event_timeout = _retry_timeout_array[_retry_count] * 1000;
_retry_count++;
} else {
report_failure("Registration");
return;
}
}
state_registering();
break;
case STATE_ATTACHING_NETWORK:
_cellularDevice->set_timeout(TIMEOUT_NETWORK);
CellularNetwork::AttachStatus attach_status;
if (get_attach_network(attach_status)) {
if (attach_status == CellularNetwork::Attached) {
_next_state = STATE_CONNECT_NETWORK;
_retry_count = 0;
} else {
_next_state = STATE_ATTACH_NETWORK;
_retry_count = 0;
}
} else {
if (_retry_count++ <= RETRY_COUNT_DEFAULT) {
event_timeout = 1 * 1000;
} else {
report_failure("Attaching");
return;
}
}
state_attaching();
break;
case STATE_ATTACH_NETWORK:
_cellularDevice->set_timeout(TIMEOUT_NETWORK);
tr_info("Attach to cellular network (timeout %d ms)", TIMEOUT_NETWORK);
if (set_attach_network()) {
_next_state = STATE_ATTACHING_NETWORK;
_retry_count = 0;
if (_state_retry_count >= RETRY_COUNT_DEFAULT) {
report_failure("Attach retry");
return;
}
_state_retry_count++;
tr_info("Cellular network attaching");
} else {
if (_retry_count < _retry_array_length) {
event_timeout = _retry_timeout_array[_retry_count] * 1000;
_retry_count++;
} else {
report_failure("Attach");
return;
}
}
break;
case STATE_CONNECT_NETWORK:
_cellularDevice->set_timeout(TIMEOUT_NETWORK);
tr_info("Connect to cellular network (timeout %d ms)", TIMEOUT_NETWORK);
err = _network->connect();
if (!err) {
_next_state = STATE_CONNECTED;
} else {
if (_retry_count < _retry_array_length) {
event_timeout = _retry_timeout_array[_retry_count] * 1000;
_retry_count++;
} else {
report_failure("Network Connect");
return;
}
}
case STATE_CONNECTING_NETWORK:
state_connect_to_network();
break;
case STATE_CONNECTED:
_cellularDevice->set_timeout(TIMEOUT_NETWORK);
tr_debug("Cellular ready! (timeout %d ms)", TIMEOUT_NETWORK);
if (_status_callback) {
if (!_status_callback(_state, _next_state)) {
return;
}
}
state_connected();
break;
default:
MBED_ASSERT(0);
break;
}
if (_next_state != _state || event_timeout >= 0) {
if (_next_state != _state || _event_timeout >= 0) {
if (_next_state != _state) { // state exit condition
tr_info("Cellular state from %d to %d", _state, _next_state);
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;
}
}
} else {
if (event_timeout == 0) {
static int retry_count = 0;
if (++retry_count <= 3) {
tr_info("Cellular event retry %d", retry_count);
} else {
report_failure("Cellular connection failed!");
return;
}
} else {
tr_info("Cellular event in %d milliseconds", event_timeout);
}
tr_info("Cellular event in %d seconds", _event_timeout);
}
_state = _next_state;
if (event_timeout == -1) {
event_timeout = 0;
if (_event_timeout == -1) {
_event_timeout = 0;
}
if (!_queue.call_in(event_timeout, callback(this, &CellularConnectionFSM::event))) {
_event_id = _queue.call_in(_event_timeout*1000, callback(this, &CellularConnectionFSM::event));
if (!_event_id) {
report_failure("Cellular event failure!");
return;
}
@ -493,12 +538,9 @@ void CellularConnectionFSM::event()
nsapi_error_t CellularConnectionFSM::start_dispatch()
{
tr_info("CellularConnectionUtil::start");
tr_info("Create cellular thread");
MBED_ASSERT(!_queue_thread);
_queue_thread = new rtos::Thread;
_queue_thread = new rtos::Thread(osPriorityNormal, 2048);
if (!_queue_thread) {
stop();
return NSAPI_ERROR_NO_MEMORY;
@ -508,21 +550,9 @@ nsapi_error_t CellularConnectionFSM::start_dispatch()
return NSAPI_ERROR_NO_MEMORY;
}
tr_info("CellularConnectionUtil::started");
return NSAPI_ERROR_OK;
}
void CellularConnectionFSM::stop()
{
tr_info("CellularConnectionUtil::stop");
_cellularDevice->close_power();
_cellularDevice->close_network();
if (_queue_thread) {
_queue_thread->terminate();
_queue_thread = NULL;
}
}
void CellularConnectionFSM::set_serial(UARTSerial *serial)
{
_serial = serial;
@ -533,6 +563,41 @@ void CellularConnectionFSM::set_callback(mbed::Callback<bool(int, int)> status_c
_status_callback = status_callback;
}
void CellularConnectionFSM::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
{
_event_status_cb = status_cb;
_network->attach(callback(this, &CellularConnectionFSM::network_callback));
}
void CellularConnectionFSM::network_callback(nsapi_event_t ev, intptr_t ptr)
{
tr_info("FSM: network_callback called with event: %d, intptr: %d", ev, ptr);
if ((cellular_connection_status_t)ev == CellularRegistrationStatusChanged && _state == STATE_REGISTERING_NETWORK) {
// expect packet data so only these states are valid
if (ptr == CellularNetwork::RegisteredHomeNetwork && CellularNetwork::RegisteredRoaming) {
_queue.cancel(_event_id);
continue_from_state(STATE_ATTACHING_NETWORK);
}
}
if (_event_status_cb) {
_event_status_cb(ev, ptr);
}
}
void CellularConnectionFSM::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()) {
continue_from_state(STATE_SIM_PIN);
}
}
}
events::EventQueue *CellularConnectionFSM::get_queue()
{
return &_queue;

View File

@ -29,10 +29,9 @@
#include "CellularNetwork.h"
#include "CellularPower.h"
#include "CellularSIM.h"
#include "CellularUtil.h"
// modem type is defined as CELLULAR_DEVICE macro
#define _CELLULAR_STRINGIFY(a) #a
#define CELLULAR_STRINGIFY(a) _CELLULAR_STRINGIFY(a)
#include CELLULAR_STRINGIFY(CELLULAR_DEVICE.h)
namespace mbed {
@ -58,12 +57,10 @@ public:
STATE_POWER_ON,
STATE_DEVICE_READY,
STATE_SIM_PIN,
STATE_REGISTER_NETWORK,
STATE_REGISTERING_NETWORK,
STATE_ATTACH_NETWORK,
STATE_ATTACHING_NETWORK,
STATE_CONNECT_NETWORK,
STATE_CONNECTED,
STATE_CONNECTING_NETWORK,
STATE_CONNECTED
};
public:
@ -83,6 +80,16 @@ public:
*/
void set_callback(mbed::Callback<bool(int, int)> status_callback);
/** 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);
/** Get event queue that can be chained to main event queue (or use start_dispatch)
* @return event queue
*/
@ -131,28 +138,47 @@ public:
*/
void set_retry_timeout_array(uint16_t timeout[], int array_len);
const char* get_state_string(CellularState state);
private:
bool open_power(FileHandle *fh);
bool power_on();
bool open_sim();
bool get_network_registration(CellularNetwork::RegistrationType type, CellularNetwork::RegistrationStatus &status, bool &is_registered);
bool set_network_registration(char *plmn = 0);
bool get_attach_network(CellularNetwork::AttachStatus &status);
bool set_attach_network();
bool is_registered();
bool device_ready();
nsapi_error_t is_automatic_registering(bool& auto_reg);
// state functions to keep state machine simple
void state_init();
void state_power_on();
void state_device_ready();
void state_sim_pin();
void state_registering();
void state_attaching();
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);
private:
friend class EasyCellularConnection;
NetworkStack *get_stack();
private:
void device_ready();
void report_failure(const char* msg);
void event();
void ready_urc_cb();
UARTSerial *_serial;
CellularState _state;
CellularState _next_state;
Callback<bool(int, int)> _status_callback;
Callback<void(nsapi_event_t, intptr_t)> _event_status_cb;
CellularNetwork *_network;
CellularPower *_power;
@ -162,11 +188,14 @@ private:
CellularDevice *_cellularDevice;
char _sim_pin[PIN_SIZE+1];
int _retry_count;
int _state_retry_count;
int _start_time;
int _event_timeout;
uint16_t _retry_timeout_array[MAX_RETRY_ARRAY_SIZE];
int _retry_array_length;
events::EventQueue _at_queue;
char _st_string[20];
int _event_id;
};
} // namespace

View File

@ -37,26 +37,35 @@ namespace mbed {
bool EasyCellularConnection::cellular_status(int state, int next_state)
{
tr_info("cellular_status %d=>%d", state, 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) {
if (state == CellularConnectionFSM::STATE_CONNECTED) {
tr_info("Target state reached: %s", _cellularConnectionFSM.get_state_string(_target_state));
MBED_ASSERT(_cellularSemaphore.release() == osOK);
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;
}
tr_info("Target state reached: %d", _target_state);
MBED_ASSERT(_cellularSemaphore.release() == osOK);
return false;
} else {
_is_connected = false;
}
return true;
if (_status_cb) {
_status_cb(ev, ptr);
}
}
EasyCellularConnection::EasyCellularConnection(bool debug) :
_is_connected(false), _is_initialized(false), _target_state(CellularConnectionFSM::STATE_POWER_ON), _cellularSerial(
MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE), _cellularSemaphore(0), _cellularConnectionFSM(), _credentials_err(
NSAPI_ERROR_OK)
NSAPI_ERROR_OK), _status_cb(0)
{
tr_info("EasyCellularConnection()");
#if USE_APN_LOOKUP
@ -84,6 +93,7 @@ nsapi_error_t EasyCellularConnection::init()
if (err == NSAPI_ERROR_OK) {
err = _cellularConnectionFSM.start_dispatch();
_cellularConnectionFSM.attach(callback(this, &EasyCellularConnection::network_callback));
}
_is_initialized = true;
}
@ -257,10 +267,7 @@ const char *EasyCellularConnection::get_gateway()
void EasyCellularConnection::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
{
CellularNetwork *network = _cellularConnectionFSM.get_network();
if (network) {
network->attach(status_cb);
}
_status_cb = status_cb;
}
void EasyCellularConnection::modem_debug_on(bool on)

View File

@ -16,7 +16,6 @@
*/
#ifndef EASY_CELLULAR_CONNECTION_H
#define EASY_CELLULAR_CONNECTION_H
#include "CellularConnectionFSM.h"
@ -117,6 +116,10 @@ public:
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
*/
@ -142,6 +145,7 @@ private:
* @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();
@ -156,6 +160,7 @@ private:
rtos::Semaphore _cellularSemaphore;
CellularConnectionFSM _cellularConnectionFSM;
nsapi_error_t _credentials_err;
Callback<void(nsapi_event_t, intptr_t)> _status_cb;
};
} // namespace

View File

@ -83,19 +83,19 @@ public:
*/
virtual void close_network() = 0;
/** Closes the opened CellularNetwork by deleting the CellularSMS instance.
/** Closes the opened CellularSMS by deleting the CellularSMS instance.
*/
virtual void close_sms() = 0;
/** Closes the opened CellularNetwork by deleting the CellularPower instance.
/** Closes the opened CellularPower by deleting the CellularPower instance.
*/
virtual void close_power() = 0;
/** Closes the opened CellularNetwork by deleting the CellularSIM instance.
/** Closes the opened CellularSIM by deleting the CellularSIM instance.
*/
virtual void close_sim() = 0;
/** Closes the opened CellularNetwork by deleting the CellularInformation instance.
/** Closes the opened CellularInformation by deleting the CellularInformation instance.
*/
virtual void close_information() = 0;

View File

@ -116,16 +116,7 @@ public:
CHAP
};
// 3GPP TS 27.007 - 7.3 PLMN selection +COPS
struct operator_t {
enum Status {
Unknown,
Available,
Current,
Forbiden
};
enum RadioAccessTechnology {
enum RadioAccessTechnology {
RAT_GSM,
RAT_GSM_COMPACT,
RAT_UTRAN,
@ -139,6 +130,14 @@ public:
RAT_UNKNOWN
};
// 3GPP TS 27.007 - 7.3 PLMN selection +COPS
struct operator_t {
enum Status {
Unknown,
Available,
Current,
Forbiden
};
Status op_status;
char op_long[MAX_OPERATOR_NAME_LONG+1];
@ -200,6 +199,23 @@ public:
};
typedef CellularList<pdpcontext_params_t> pdpContextList_t;
/* Network registering mode */
enum NWRegisteringMode {
NWModeAutomatic = 0, // automatic registering
NWModeManual, // manual registering with plmn
NWModeDeRegister, // deregister from network
NWModeSetOnly, // set only <format> (for read command +COPS?), do not attempt registration/deregistration
NWModeManualAutomatic // if manual fails, fallback to automatic
};
/** Does all the needed initializations that can fail
*
* @remark must be called immediately after constructor.
* @return zero on success
*/
virtual nsapi_error_t init() = 0;
/** Request registering to network.
*
* @param plmn format is in numeric format or 0 for automatic network registration
@ -207,6 +223,24 @@ public:
*/
virtual nsapi_error_t set_registration(const char *plmn = 0) = 0;
/** Get the current network registering mode
*
* @param mode on successful return contains the current network registering mode
* @return zero on success
*/
virtual nsapi_error_t get_network_registering_mode(NWRegisteringMode& mode) = 0;
/** Activate/deactivate listening of network events for the given RegistrationType.
* This should be called after network class is created and ready to receive AT commands.
* After successful call network class starts to get information about network changes like
* registration statue, access technology, cell id...
*
* @param type RegistrationType to set urc on/off
* @param on Controls are urc' active or not
* @return zero on success
*/
virtual nsapi_error_t set_registration_urc(RegistrationType type, bool on) = 0;
/** Gets the network registration status.
*
* @param type see RegistrationType values
@ -270,10 +304,17 @@ public:
/** Sets radio access technology.
*
* @param op_rat Radio access technology
* @return zero on success
* @param rat Radio access technology
* @return zero on success
*/
virtual nsapi_error_t set_access_technology(operator_t::RadioAccessTechnology op_rat) = 0;
virtual nsapi_error_t set_access_technology(RadioAccessTechnology rat) = 0;
/** Get current radio access technology.
*
* @param rat Radio access technology
* @return zero on success
*/
virtual nsapi_error_t get_access_technology(RadioAccessTechnology& rat) = 0;
/** Scans for operators module can reach.
*
@ -317,6 +358,13 @@ public:
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 zero on success
*/
virtual nsapi_error_t activate_context() = 0;
/**
* Set the pdn type to be used
*

View File

@ -18,8 +18,10 @@
#define CELLULAR_API_CELLULARPOWER_H_
#include "nsapi_types.h"
#include "Callback.h"
namespace mbed {
namespace mbed
{
/**
* Class CellularPower
@ -118,6 +120,21 @@ public:
* @return zero on success
*/
virtual nsapi_error_t opt_receive_period(int mode, EDRXAccessTechnology act_type, uint8_t edrx_value) = 0;
/** Set URC callback function for device specific ready urc. URC is defined in device specific
* power API. Used in startup sequence to listen when device is ready
* for using at commands and possible sim.
*
* @param callback Callback function called when urc received
* @return zero on success
*/
virtual nsapi_error_t set_device_ready_urc_cb(mbed::Callback<void()> callback) = 0;
/** Removes the device ready urc from the list of urc's.
*
* @param callback callback to remove from the list of urc's
*/
virtual void remove_device_ready_urc_cb(mbed::Callback<void()> callback) = 0;
};
} // namespace mbed

View File

@ -88,17 +88,18 @@ ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, int timeout, const char
clear_error();
if (output_delimiter) {
_output_delimiter_length = strlen(output_delimiter);
_output_delimiter = new char[_output_delimiter_length];
for (unsigned i=0; i<_output_delimiter_length; i++) {
_output_delimiter[i] = output_delimiter[i];
_output_delimiter = new char[strlen(output_delimiter) + 1];
if (!_output_delimiter) {
MBED_ASSERT(0);
} else {
memcpy(_output_delimiter, output_delimiter, strlen(output_delimiter) + 1);
}
} else {
_output_delimiter = NULL;
_output_delimiter_length = 0;
_output_delimiter = NULL;
}
reset_buffer();
memset(_recv_buff, 0, sizeof(_recv_buff));
memset(_info_resp_prefix, 0, sizeof(_info_resp_prefix));
_current_scope = NotSet;
@ -153,21 +154,65 @@ void ATHandler::set_file_handle(FileHandle *fh)
_fileHandle = fh;
}
void ATHandler::set_urc_handler(const char *prefix, mbed::Callback<void()> callback)
nsapi_error_t ATHandler::set_urc_handler(const char *prefix, mbed::Callback<void()> callback)
{
struct oob_t *oob = new struct oob_t;
oob->matching_to_received = true;
size_t prefix_len = strlen(prefix);
if (prefix_len > _oob_string_max_length) {
_oob_string_max_length = prefix_len;
if (_oob_string_max_length > _max_resp_length) {
_max_resp_length = _oob_string_max_length;
}
if (find_urc_handler(prefix, callback)) {
tr_warn("URC already added with prefix: %s", prefix);
return NSAPI_ERROR_OK;
}
oob->prefix = prefix;
oob->cb = callback;
oob->next = _oobs;
_oobs = oob;
struct oob_t *oob = new struct oob_t;
if (!oob) {
return NSAPI_ERROR_NO_MEMORY;
} else {
size_t prefix_len = strlen(prefix);
if (prefix_len > _oob_string_max_length) {
_oob_string_max_length = prefix_len;
if (_oob_string_max_length > _max_resp_length) {
_max_resp_length = _oob_string_max_length;
}
}
oob->prefix = prefix;
oob->prefix_len = prefix_len;
oob->cb = callback;
oob->next = _oobs;
_oobs = oob;
}
return NSAPI_ERROR_OK;
}
void ATHandler::remove_urc_handler(const char *prefix, mbed::Callback<void()> callback)
{
struct oob_t *current = _oobs;
struct oob_t *prev = NULL;
while (current) {
if (strcmp(prefix, current->prefix) == 0 && current->cb == callback) {
if (prev) {
prev->next = current->next;
} else {
_oobs = current->next;
}
delete current;
break;
}
prev = current;
current = prev->next;
}
}
bool ATHandler::find_urc_handler(const char *prefix, mbed::Callback<void()> callback)
{
struct oob_t *oob = _oobs;
while (oob) {
if (strcmp(prefix, oob->prefix) == 0 && oob->cb == callback) {
return true;
}
oob = oob->next;
}
return false;
}
void ATHandler::event()
@ -234,6 +279,7 @@ void ATHandler::process_oob()
timer.start();
do {
if (match_urc()) {
timer.reset();
if (_fileHandle->readable() || (_recv_pos < _recv_len)) {
continue;
}
@ -242,8 +288,10 @@ void ATHandler::process_oob()
// If no match found, look for CRLF and consume everything up to CRLF
if (mem_str(_recv_buff, _recv_len, CRLF, CRLF_LENGTH)) {
consume_to_tag(CRLF, true);
timer.reset();
} else {
if (_fileHandle->readable()) {
timer.reset();
fill_buffer();
} else {
#ifdef MBED_CONF_RTOS_PRESENT
@ -251,7 +299,7 @@ void ATHandler::process_oob()
#endif
}
}
} while (timer.read_ms() < 20); // URC's are very short so 20ms should be enough
} while (timer.read_ms() < 100); // URC's are very short
}
tr_debug("process_oob exit");
@ -272,7 +320,8 @@ void ATHandler::set_filehandle_sigio()
void ATHandler::reset_buffer()
{
tr_debug("%s", __func__);
_recv_pos = 0; _recv_len = 0;
_recv_pos = 0;
_recv_len = 0;
}
void ATHandler::rewind_buffer()
@ -438,7 +487,9 @@ ssize_t ATHandler::read_string(char *buf, size_t size, bool read_even_stop_tag)
break;
} else if (c == '\"') {
match_pos = 0;
len--;
if (len > 0) {
len--;
}
continue;
} else if (_stop_tag->len && c == _stop_tag->tag[match_pos]) {
match_pos++;
@ -561,10 +612,10 @@ bool ATHandler::match_urc()
rewind_buffer();
size_t prefix_len = 0;
for (struct oob_t *oob = _oobs; oob; oob = oob->next) {
prefix_len = strlen(oob->prefix);
prefix_len = oob->prefix_len;
if (_recv_len >= prefix_len) {
if (match(oob->prefix, prefix_len)) {
tr_debug("URC! %s", oob->prefix);
tr_debug("URC! %s\n", oob->prefix);
set_scope(InfoType);
if (oob->cb) {
oob->cb();
@ -651,11 +702,9 @@ void ATHandler::set_3gpp_error(int err, DeviceErrorType error_type)
void ATHandler::at_error(bool error_code_expected, DeviceErrorType error_type)
{
int32_t err = -1;
if (error_code_expected && (error_type == DeviceErrorTypeErrorCMS || error_type == DeviceErrorTypeErrorCME)) {
set_scope(InfoType);
err = read_int();
int32_t err = read_int();
if (err != -1) {
set_3gpp_error(err, error_type);
@ -952,9 +1001,7 @@ void ATHandler::cmd_start(const char* cmd)
}
}
tr_debug("AT> %s", cmd);
at_debug("AT cmd %s (err %d)\n", cmd, _last_err);
if (_last_err != NSAPI_ERROR_OK) {
return;
@ -967,7 +1014,7 @@ void ATHandler::cmd_start(const char* cmd)
void ATHandler::write_int(int32_t param)
{
tr_debug("write_int: %d", param);
at_debug("AT int %d\n", param);
// do common checks before sending subparameter
if (check_cmd_send() == false) {
return;
@ -984,7 +1031,7 @@ void ATHandler::write_int(int32_t param)
void ATHandler::write_string(const char* param, bool useQuotations)
{
tr_debug("write_string: %s, %d", param, useQuotations);
at_debug("AT str %s (with quotes %d)\n", param, useQuotations);
// do common checks before sending subparameter
if (check_cmd_send() == false) {
return;
@ -1005,37 +1052,43 @@ void ATHandler::write_string(const char* param, bool useQuotations)
void ATHandler::cmd_stop()
{
at_debug("AT stop %s (err %d)\n", _output_delimiter, _last_err);
if (_last_err != NSAPI_ERROR_OK) {
return;
}
// Finish with CR
(void)write(_output_delimiter, _output_delimiter_length);
(void)write(_output_delimiter, strlen(_output_delimiter));
}
size_t ATHandler::write_bytes(const uint8_t *data, size_t len)
{
at_debug("AT write bytes %d (err %d)\n", len, _last_err);
if (_last_err != NSAPI_ERROR_OK) {
return 0;
}
ssize_t write_len = write(data, len);
return write_len < 0 ? 0 : (size_t)write_len;
return write(data, len);
}
ssize_t ATHandler::write(const void *data, size_t len)
size_t ATHandler::write(const void *data, size_t len)
{
pollfh fhs;
fhs.fh = _fileHandle;
fhs.events = POLLOUT;
ssize_t write_len = -1;
int count = poll(&fhs, 1, _at_timeout);
if (count > 0 && (fhs.revents & POLLOUT)) {
write_len = _fileHandle->write(data, len);
}
if (write_len < 0 || (size_t)write_len != len) {
set_error(NSAPI_ERROR_DEVICE_ERROR);
size_t write_len = 0;
for (; write_len < len; ) {
int count = poll(&fhs, 1, _at_timeout);
if (count <= 0 || !(fhs.revents & POLLOUT)) {
set_error(NSAPI_ERROR_DEVICE_ERROR);
return 0;
}
ssize_t ret = _fileHandle->write((uint8_t*)data + write_len, len - write_len);
if (ret < 0) {
set_error(NSAPI_ERROR_DEVICE_ERROR);
return 0;
}
write_len += (size_t)ret;
}
return write_len;

View File

@ -29,7 +29,8 @@
#include "Callback.h"
#include "EventQueue.h"
namespace mbed {
namespace mbed
{
class FileHandle;
@ -106,11 +107,20 @@ public:
nsapi_error_t unlock_return_error();
/** Set the urc callback for urc. If urc is found when parsing AT responses, then call if called.
* If urc is already set then it's not set twice.
*
* @param prefix Register urc prefix for callback. Urc could be for example "+CMTI: "
* @param callback Callback, which is called if urc is found in AT response
* @return NSAPI_ERROR_OK or NSAPI_ERROR_NO_MEMORY if no memory
*/
nsapi_error_t set_urc_handler(const char *prefix, mbed::Callback<void()> callback);
/** Remove urc handler from linked list of urc's
*
* @param prefix Register urc prefix for callback. Urc could be for example "+CMTI: "
* @param callback Callback, which is called if urc is found in AT response
*/
void set_urc_handler(const char *prefix, mbed::Callback<void()> callback);
void remove_urc_handler(const char *prefix, mbed::Callback<void()> callback);
ATHandler *_nextATHandler; // linked list
@ -184,16 +194,14 @@ private:
device_err_t _last_at_err;
uint16_t _oob_string_max_length;
char *_output_delimiter;
uint8_t _output_delimiter_length;
struct oob_t {
bool matching_to_received;
const char *prefix;
int prefix_len;
mbed::Callback<void()> cb;
oob_t *next;
};
oob_t *_oobs;
bool _response_terminated;
uint32_t _at_timeout;
uint32_t _previous_at_timeout;
@ -205,7 +213,7 @@ private:
bool _processing;
int32_t _ref_count;
//*************************************
//*************************************
public:
/** Starts the command writing by clearing the last error and writing the given command.
@ -450,7 +458,7 @@ private:
void set_3gpp_error(int err, DeviceErrorType error_type);
bool check_cmd_send();
ssize_t write(const void *data, size_t len);
size_t write(const void *data, size_t len);
/** Copy content of one char buffer to another buffer and sets NULL terminator
*
@ -471,6 +479,9 @@ private:
* @return pointer to first occurrence of src in dest
*/
const char* mem_str(const char* dest, size_t dest_len, const char* src, size_t src_len);
// check is urc is already added
bool find_urc_handler(const char *prefix, mbed::Callback<void()> callback);
};
} // namespace mbed

View File

@ -41,7 +41,6 @@ AT_CellularDevice::~AT_CellularDevice()
ATHandler *old = atHandler;
atHandler = atHandler->_nextATHandler;
delete old;
old = NULL;
}
}
@ -90,7 +89,6 @@ void AT_CellularDevice::release_at_handler(ATHandler* at_handler)
prev->_nextATHandler = atHandler->_nextATHandler;
}
delete atHandler;
atHandler = NULL;
break;
} else {
prev = atHandler;

View File

@ -20,6 +20,7 @@
#include "nsapi_ppp.h"
#include "CellularUtil.h"
#include "CellularLog.h"
#include "CellularCommon.h"
using namespace std;
using namespace mbed_cellular_util;
@ -28,21 +29,21 @@ using namespace mbed;
struct at_reg_t {
const CellularNetwork::RegistrationType type;
const char *const cmd;
const char *const urc_prefix;
};
static const at_reg_t at_reg[] = {
{ CellularNetwork::C_EREG, "AT+CEREG" },
{ CellularNetwork::C_GREG, "AT+CGREG" },
{ CellularNetwork::C_REG, "AT+CREG" },
{ CellularNetwork::C_EREG, "AT+CEREG", "+CEREG:"},
{ CellularNetwork::C_GREG, "AT+CGREG", "+CGREG:"},
{ CellularNetwork::C_REG, "AT+CREG", "+CREG:"}
};
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(operator_t::RAT_UNKNOWN), _authentication_type(CHAP), _last_reg_type(C_REG),
_connect_status(NSAPI_STATUS_DISCONNECTED), _new_context_set(false)
_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), _cell_id(-1), _connect_status(NSAPI_STATUS_DISCONNECTED), _new_context_set(false),
_is_context_active(false), _reg_status(NotRegistered), _current_act(RAT_UNKNOWN)
{
_at.set_urc_handler("NO CARRIER", callback(this, &AT_CellularNetwork::urc_no_carrier));
}
AT_CellularNetwork::~AT_CellularNetwork()
@ -50,6 +51,23 @@ AT_CellularNetwork::~AT_CellularNetwork()
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)) {
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) {
@ -73,6 +91,48 @@ void AT_CellularNetwork::urc_no_carrier()
}
}
void AT_CellularNetwork::read_reg_params_and_compare(RegistrationType type)
{
RegistrationStatus reg_status = NotRegistered;
int lac = -1, cell_id = -1, act = -1;
read_reg_params(type, reg_status, lac, cell_id, act);
if (_at.get_last_error() == NSAPI_ERROR_OK && _connection_status_cb) {
tr_debug("stat: %d, lac: %d, cellID: %d, act: %d", reg_status, lac, cell_id, act);
if (act != -1 && (RadioAccessTechnology)act != _current_act) {
_current_act = (RadioAccessTechnology)act;
_connection_status_cb((nsapi_event_t)CellularRadioAccessTechnologyChanged, _current_act);
}
if (reg_status != _reg_status) {
_reg_status = reg_status;
_connection_status_cb((nsapi_event_t)CellularRegistrationStatusChanged, _reg_status);
}
if (cell_id != -1 && cell_id != _cell_id) {
_cell_id = cell_id;
_connection_status_cb((nsapi_event_t)CellularCellIDChanged, _cell_id);
}
}
}
void AT_CellularNetwork::urc_creg()
{
tr_debug("urc_creg");
read_reg_params_and_compare(C_REG);
}
void AT_CellularNetwork::urc_cereg()
{
tr_debug("urc_cereg");
read_reg_params_and_compare(C_EREG);
}
void AT_CellularNetwork::urc_cgreg()
{
tr_debug("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)
{
@ -149,15 +209,10 @@ nsapi_error_t AT_CellularNetwork::delete_current_context()
return _at.get_last_error();
}
nsapi_error_t AT_CellularNetwork::connect()
nsapi_error_t AT_CellularNetwork::activate_context()
{
_at.lock();
_connect_status = NSAPI_STATUS_CONNECTING;
if (_connection_status_cb) {
_connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_CONNECTING);
}
nsapi_error_t err = set_context_to_be_activated();
if (err != NSAPI_ERROR_OK) {
_at.unlock();
@ -171,18 +226,58 @@ nsapi_error_t AT_CellularNetwork::connect()
return err;
}
err = open_data_channel();
if (err != NSAPI_ERROR_OK) {
// do check for stack to validate that we have support for stack
_stack = get_stack();
if (!_stack) {
return err;
}
// If new PDP context was created and failed to activate, delete it
if (_new_context_set) {
delete_current_context();
_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();
_at.unlock();
if (!_is_context_active) {
tr_info("Activate PDP context");
_at.cmd_start("AT+CGACT=1,");
_at.write_int(_cid);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
}
tr_error("Failed to open data channel!");
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();
}
_at.unlock();
return err;
}
nsapi_error_t AT_CellularNetwork::connect()
{
_connect_status = NSAPI_STATUS_CONNECTING;
if (_connection_status_cb) {
_connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_CONNECTING);
}
nsapi_error_t err = NSAPI_ERROR_OK;
if (!_is_context_active) {
err = activate_context();
}
if (err) {
_connect_status = NSAPI_STATUS_DISCONNECTED;
if (_connection_status_cb) {
_connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED);
@ -191,9 +286,19 @@ nsapi_error_t AT_CellularNetwork::connect()
return err;
}
#if NSAPI_PPP_AVAILABLE
_at.lock();
err = open_data_channel();
_at.unlock();
#if !NSAPI_PPP_AVAILABLE
if (err != NSAPI_ERROR_OK) {
tr_error("Failed to open data channel!");
_connect_status = NSAPI_STATUS_DISCONNECTED;
if (_connection_status_cb) {
_connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED);
}
return err;
}
#else
_connect_status = NSAPI_STATUS_GLOBAL_UP;
if (_connection_status_cb) {
_connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_GLOBAL_UP);
@ -205,8 +310,6 @@ nsapi_error_t AT_CellularNetwork::connect()
nsapi_error_t AT_CellularNetwork::open_data_channel()
{
//old way: _at.send("ATD*99***%d#", _cid) && _at.recv("CONNECT");
nsapi_error_t err = NSAPI_ERROR_NO_CONNECTION;
#if NSAPI_PPP_AVAILABLE
tr_info("Open data channel in PPP mode");
_at.cmd_start("AT+CGDATA=\"PPP\",");
@ -218,43 +321,12 @@ nsapi_error_t AT_CellularNetwork::open_data_channel()
tr_warn("Failed to CONNECT");
}
/* Initialize PPP
* mbed_ppp_init() is a blocking call, it will block until
* connected, or timeout after 30 seconds*/
err = nsapi_ppp_connect(_at.get_file_handle(), callback(this, &AT_CellularNetwork::ppp_status_cb), _uname, _pwd, _ip_stack_type);
* 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
// do check for stack to validate that we have support for stack
_stack = get_stack();
if (!_stack) {
return err;
}
bool 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;
tr_debug("PDP context %d is active.", _cid);
break;
}
}
_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();
_at.resp_start();
_at.resp_stop();
}
err = (_at.get_last_error() == NSAPI_ERROR_OK) ? NSAPI_ERROR_OK : NSAPI_ERROR_NO_CONNECTION;
#endif
return err;
return NSAPI_ERROR_OK;
#endif // #if NSAPI_PPP_AVAILABLE
}
/**
@ -300,11 +372,10 @@ nsapi_error_t AT_CellularNetwork::set_blocking(bool blocking)
#if NSAPI_PPP_AVAILABLE
return nsapi_ppp_set_blocking(blocking);
#else
return NSAPI_ERROR_UNSUPPORTED;
return NSAPI_ERROR_OK;
#endif
}
#if NSAPI_PPP_AVAILABLE
void AT_CellularNetwork::ppp_status_cb(nsapi_event_t event, intptr_t parameter)
{
@ -316,8 +387,6 @@ void AT_CellularNetwork::ppp_status_cb(nsapi_event_t event, intptr_t parameter)
}
#endif
nsapi_error_t AT_CellularNetwork::set_context_to_be_activated()
{
// try to find or create context with suitable stack
@ -522,38 +591,47 @@ nsapi_ip_stack_t AT_CellularNetwork::string_to_stack_type(const char* pdp_type)
return stack;
}
nsapi_error_t AT_CellularNetwork::set_registration_urc(bool urc_on)
nsapi_error_t AT_CellularNetwork::set_registration_urc(RegistrationType type, bool urc_on)
{
for (unsigned int i = 0; i < sizeof(at_reg)/sizeof(at_reg[0]); i++) {
if (has_registration(at_reg[i].type)) {
_last_reg_type = at_reg[i].type;
if (urc_on) {
_at.cmd_start(at_reg[i].cmd);
_at.write_string("=2", false);
_at.cmd_stop();
} else {
_at.cmd_start(at_reg[i].cmd);
_at.write_string("=0", false);
_at.cmd_stop();
}
int index = (int)type;
MBED_ASSERT(index >= 0 && index < C_MAX);
_at.resp_start();
_at.resp_stop();
if (!has_registration(type)) {
return NSAPI_ERROR_UNSUPPORTED;
} else {
_at.lock();
if (urc_on) {
_at.cmd_start(at_reg[index].cmd);
_at.write_string("=2", false);
_at.cmd_stop();
} else {
_at.cmd_start(at_reg[index].cmd);
_at.write_string("=0", false);
_at.cmd_stop();
}
_at.resp_start();
_at.resp_stop();
return _at.unlock_return_error();
}
return _at.get_last_error();
}
nsapi_error_t AT_CellularNetwork::get_network_registering_mode(NWRegisteringMode& mode)
{
_at.lock();
_at.cmd_start("AT+COPS?");
_at.cmd_stop();
_at.resp_start("+COPS:");
mode = (NWRegisteringMode)_at.read_int();
_at.resp_stop();
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::set_registration(const char *plmn)
{
_at.lock();
nsapi_error_t ret = set_registration_urc(false);
if (ret) {
tr_error("Setting registration URC failed!");
_at.clear_error(); // allow temporary failures here
}
if (!plmn) {
tr_debug("Automatic network registration");
_at.cmd_start("AT+COPS?");
@ -580,40 +658,13 @@ nsapi_error_t AT_CellularNetwork::set_registration(const char *plmn)
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_registration_status(RegistrationType type, RegistrationStatus &status)
void AT_CellularNetwork::read_reg_params(RegistrationType type, RegistrationStatus &reg_status, int &lac, int &cell_id, int &act)
{
int i = (int)type;
MBED_ASSERT(i >= 0 && i < C_MAX);
const char *rsp[] = { "+CEREG:", "+CGREG:", "+CREG:"};
const int LAC_LENGTH = 5, CELL_ID_LENGTH = 9;
char lac_string[LAC_LENGTH] = {0}, cell_id_string[CELL_ID_LENGTH] = {0};
bool lac_read = false, cell_id_read = false;
_cell_id = -1;
_lac = -1;
_at.lock();
if (!has_registration(at_reg[i].type)) {
_at.unlock();
return NSAPI_ERROR_UNSUPPORTED;
}
_at.cmd_start(at_reg[i].cmd);
_at.write_string("=2", false);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start(at_reg[i].cmd);
_at.write_string("?", false);
_at.cmd_stop();
_at.resp_start(rsp[i]);
_at.read_int(); // ignore urc mode subparam
status = (RegistrationStatus)_at.read_int();
reg_status = (RegistrationStatus)_at.read_int();
int len = _at.read_string(lac_string, LAC_LENGTH);
if (memcmp(lac_string, "ffff", LAC_LENGTH-1) && len >= 0) {
@ -625,38 +676,55 @@ nsapi_error_t AT_CellularNetwork::get_registration_status(RegistrationType type,
cell_id_read = true;
}
_at.resp_stop();
_at.cmd_start(at_reg[i].cmd);
_at.write_string("=0", false);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
nsapi_error_t ret = _at.get_last_error();
_at.unlock();
act = _at.read_int();
if (lac_read) {
_lac = hex_str_to_int(lac_string, LAC_LENGTH);
tr_debug("lac %s %d", lac_string, _lac );
lac = hex_str_to_int(lac_string, LAC_LENGTH);
tr_debug("lac %s %d", lac_string, lac );
}
if (cell_id_read) {
_cell_id = hex_str_to_int(cell_id_string, CELL_ID_LENGTH);
tr_debug("cell_id %s %d", cell_id_string, _cell_id );
cell_id = hex_str_to_int(cell_id_string, CELL_ID_LENGTH);
tr_debug("cell_id %s %d", cell_id_string, cell_id );
}
}
nsapi_error_t AT_CellularNetwork::get_registration_status(RegistrationType type, RegistrationStatus &status)
{
int i = (int)type;
MBED_ASSERT(i >= 0 && i < C_MAX);
if (!has_registration(at_reg[i].type)) {
return NSAPI_ERROR_UNSUPPORTED;
}
return ret;
_at.lock();
const char *rsp[] = { "+CEREG:", "+CGREG:", "+CREG:"};
_at.cmd_start(at_reg[i].cmd);
_at.write_string("?", false);
_at.cmd_stop();
_at.resp_start(rsp[i]);
(void)_at.read_int(); // ignore urc mode subparam
int lac = -1, cell_id = -1, act = -1;
read_reg_params(type, status, lac, cell_id, act);
_at.resp_stop();
_reg_status = status;
if (cell_id != -1) {
_cell_id = cell_id;
}
if (act != -1) {
_current_act = (RadioAccessTechnology)act;
}
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_cell_id(int &cell_id)
{
RegistrationStatus tmp;
nsapi_error_t error = get_registration_status(_last_reg_type, tmp);
cell_id = _cell_id;
return error;
return _cell_id;
}
bool AT_CellularNetwork::has_registration(RegistrationType reg_type)
@ -702,13 +770,11 @@ nsapi_error_t AT_CellularNetwork::get_attach(AttachStatus &status)
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_apn_backoff_timer(int &backoff_timer)
{
_at.lock();
// If apn is set
if (_apn) {
_at.lock();
_at.cmd_start("AT+CABTRDP=");
_at.write_string(_apn);
_at.cmd_stop();
@ -718,9 +784,10 @@ nsapi_error_t AT_CellularNetwork::get_apn_backoff_timer(int &backoff_timer)
backoff_timer = _at.read_int();
}
_at.resp_stop();
return _at.unlock_return_error();
}
return _at.unlock_return_error();
return NSAPI_ERROR_PARAMETER;
}
NetworkStack *AT_CellularNetwork::get_stack()
@ -751,14 +818,12 @@ const char *AT_CellularNetwork::get_ip_address()
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()
@ -775,14 +840,20 @@ bool AT_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
}
}
nsapi_error_t AT_CellularNetwork::set_access_technology_impl(operator_t::RadioAccessTechnology opsAct)
nsapi_error_t AT_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opsAct)
{
return NSAPI_ERROR_UNSUPPORTED;
}
nsapi_error_t AT_CellularNetwork::set_access_technology(operator_t::RadioAccessTechnology opAct)
nsapi_error_t AT_CellularNetwork::get_access_technology(RadioAccessTechnology& rat)
{
if (opAct == operator_t::RAT_UNKNOWN) {
rat = _current_act;
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::set_access_technology(RadioAccessTechnology opAct)
{
if (opAct == RAT_UNKNOWN) {
return NSAPI_ERROR_UNSUPPORTED;
}
@ -816,10 +887,10 @@ nsapi_error_t AT_CellularNetwork::scan_plmn(operList_t &operators, int &opsCount
// Optional - try read an int
ret = _at.read_int();
op->op_rat = (ret == error_code) ? operator_t::RAT_UNKNOWN:(operator_t::RadioAccessTechnology)ret;
op->op_rat = (ret == error_code) ? RAT_UNKNOWN:(RadioAccessTechnology)ret;
if ((_op_act == operator_t::RAT_UNKNOWN) ||
((op->op_rat != operator_t::RAT_UNKNOWN) && (op->op_rat == _op_act))) {
if ((_op_act == RAT_UNKNOWN) ||
((op->op_rat != RAT_UNKNOWN) && (op->op_rat == _op_act))) {
idx++;
} else {
operators.delete_last();
@ -1053,7 +1124,6 @@ int AT_CellularNetwork::get_3gpp_error()
return _at.get_3gpp_error();
}
nsapi_error_t AT_CellularNetwork::get_operator_params(int &format, operator_t &operator_params)
{
_at.lock();
@ -1066,22 +1136,18 @@ nsapi_error_t AT_CellularNetwork::get_operator_params(int &format, operator_t &o
format = _at.read_int();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
switch (format) {
case 0:
_at.read_string(operator_params.op_long, sizeof(operator_params.op_long));
break;
case 1:
_at.read_string(operator_params.op_short, sizeof(operator_params.op_short));
break;
default:
_at.read_string(operator_params.op_num, sizeof(operator_params.op_num));
break;
}
operator_params.op_rat = (operator_t::RadioAccessTechnology)_at.read_int();
operator_params.op_rat = (RadioAccessTechnology)_at.read_int();
}
_at.resp_stop();

View File

@ -60,8 +60,14 @@ 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 get_registration_status(RegistrationType type, RegistrationStatus &status);
virtual nsapi_error_t set_attach(int timeout = 10*1000);
@ -81,7 +87,8 @@ public: // CellularNetwork
virtual const char *get_ip_address();
virtual nsapi_error_t set_access_technology(operator_t::RadioAccessTechnology op_rat);
virtual nsapi_error_t set_access_technology(RadioAccessTechnology rat);
virtual nsapi_error_t get_access_technology(RadioAccessTechnology& rat);
virtual nsapi_error_t scan_plmn(operList_t &operators, int &ops_count);
@ -107,6 +114,8 @@ public: // CellularNetwork
virtual nsapi_error_t get_operator_params(int &format, operator_t &operator_params);
virtual nsapi_error_t set_registration_urc(RegistrationType type, bool on);
protected:
/** Check if modem supports the given stack type.
@ -128,11 +137,15 @@ protected:
*
* @return zero on success
*/
virtual nsapi_error_t set_access_technology_impl(operator_t::RadioAccessTechnology op_rat);
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology op_rat);
private:
// "NO CARRIER" urc
void urc_no_carrier();
void urc_creg();
void urc_cereg();
void urc_cgreg();
nsapi_error_t set_context_to_be_activated();
nsapi_ip_stack_t string_to_stack_type(const char* pdp_type);
@ -141,9 +154,12 @@ private:
nsapi_error_t open_data_channel();
bool get_context();
bool set_new_context(int cid);
nsapi_error_t set_registration_urc(bool on);
nsapi_error_t delete_current_context();
void read_reg_params_and_compare(RegistrationType type);
void read_reg_params(RegistrationType type, RegistrationStatus &reg_status, int &lac, int &cell_id, int &act);
#if NSAPI_PPP_AVAILABLE
void ppp_status_cb(nsapi_event_t, intptr_t);
#endif
@ -157,13 +173,15 @@ protected:
nsapi_ip_stack_t _ip_stack_type;
int _cid;
Callback<void(nsapi_event_t, intptr_t)> _connection_status_cb;
operator_t::RadioAccessTechnology _op_act;
RadioAccessTechnology _op_act;
AuthenticationType _authentication_type;
int _lac;
int _cell_id;
RegistrationType _last_reg_type;
nsapi_connection_status_t _connect_status;
bool _new_context_set;
bool _is_context_active;
RegistrationStatus _reg_status;
RadioAccessTechnology _current_act;
mbed::Callback<void()> _urc_funcs[C_MAX];
};
} // namespace mbed

View File

@ -18,6 +18,7 @@
#include "AT_CellularPower.h"
#include "CellularUtil.h"
#include "CellularLog.h"
#include "CellularTargets.h"
#include "nsapi_types.h"
static const int PSMTimerBits = 5;
@ -231,3 +232,12 @@ nsapi_error_t AT_CellularPower::opt_receive_period(int mode, EDRXAccessTechnolog
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularPower::set_device_ready_urc_cb(mbed::Callback<void()> callback)
{
return NSAPI_ERROR_UNSUPPORTED;
}
void AT_CellularPower::remove_device_ready_urc_cb(mbed::Callback<void()> callback)
{
}

View File

@ -48,6 +48,10 @@ public:
virtual nsapi_error_t opt_power_save_mode(int periodic_time, int active_time);
virtual nsapi_error_t opt_receive_period(int mode, EDRXAccessTechnology act_type, uint8_t edrx_value);
virtual nsapi_error_t set_device_ready_urc_cb(mbed::Callback<void()> callback);
virtual void remove_device_ready_urc_cb(mbed::Callback<void()> callback);
};
} // namespace mbed

View File

@ -176,9 +176,6 @@ const int GSM_TO_ASCII_TABLE_SIZE = sizeof(gsm_to_ascii)/sizeof(gsm_to_ascii[0])
AT_CellularSMS::AT_CellularSMS(ATHandler &at) : AT_CellularBase(at), _cb(0), _mode(CellularSMSMmodeText),
_use_8bit_encoding(false), _sim_wait_time(0), _sms_message_ref_number(1), _sms_info(NULL)
{
/* URCs, handled out of band */
_at.set_urc_handler("+CMTI:", callback(this, &AT_CellularSMS::cmti_urc));
_at.set_urc_handler("+CMT:", callback(this, &AT_CellularSMS::cmt_urc));
}
AT_CellularSMS::~AT_CellularSMS()
@ -258,6 +255,11 @@ nsapi_error_t AT_CellularSMS::set_csdh(int show_header)
nsapi_error_t AT_CellularSMS::initialize(CellularSMSMmode mode)
{
if (_at.set_urc_handler("+CMTI:", callback(this, &AT_CellularSMS::cmti_urc)) ||
_at.set_urc_handler("+CMT:", callback(this, &AT_CellularSMS::cmt_urc))) {
return NSAPI_ERROR_NO_MEMORY;
}
_at.lock();
set_cnmi(); //set new SMS indication
set_cmgf(mode); //set message format/PDU
@ -350,8 +352,6 @@ char* AT_CellularSMS::create_pdu(const char* phone_number, const char* message,
pdu[x++] = '0';
}
// possible to use 16 bit identifier, can't be defined yet from outside
bool use_16_bit_identifier = false;
uint8_t udhlen = 0;
// Length can be update after we have created PDU, store position for later use.
int lengthPos = x;
@ -361,34 +361,17 @@ char* AT_CellularSMS::create_pdu(const char* phone_number, const char* message,
if (msg_parts > 1) { // concatenated, must use UDH
// user data header length in chars
pdu[x++] = '0';
if (use_16_bit_identifier) {
udhlen = 7; // udh length in chars (6) + udhl length in chars
pdu[x++] = '6';
} else {
udhlen = 6; // udh length in chars (5) + udhl length in chars
pdu[x++] = '5';
}
udhlen = 6; // udh length in chars (5) + udhl length in chars
pdu[x++] = '5';
// Information element identifier
pdu[x++] = '0';
if (use_16_bit_identifier) {
pdu[x++] = '8';
} else {
pdu[x++] = '0';
}
pdu[x++] = '0';
// Information element data length
pdu[x++] = '0';
if (use_16_bit_identifier) {
pdu[x++] = '4';
} else {
pdu[x++] = '3';
}
pdu[x++] = '3';
// A reference number (must be the same for all parts of the same larger messages)
int_to_hex_str(_sms_message_ref_number&0xFF, pdu+x);
x +=2;
if (use_16_bit_identifier) {
int_to_hex_str((_sms_message_ref_number>>16)&0xFF, pdu+x);
x +=2;
}
// How many parts does this message have?
int_to_hex_str(msg_parts, pdu+x);
x +=2;
@ -676,13 +659,13 @@ nsapi_size_or_error_t AT_CellularSMS::read_sms_from_index(int msg_index, char* b
nsapi_size_or_error_t AT_CellularSMS::read_sms(sms_info_t* sms, char* buf, char* phone_num, char* time_stamp)
{
// +CMGR: <stat>,[<alpha>],<length><CR><LF><pdu>
int index = -1;
int index;
if (sms->parts == sms->parts_added) {
char *pdu; // we need a temp buffer as payload is hexencoded ---> can't use buf as it might be enough for message but not hexenconded pdu.
int status = -1;
int msg_len = 0;
int status;
int msg_len;
index = 0;
int pduSize = 0;
int pduSize;
for (int i = 0; i < sms->parts; i++) {
wait_ms(_sim_wait_time);
@ -1210,13 +1193,16 @@ uint16_t AT_CellularSMS::pack_7_bit_gsm_and_hex(const char* str, uint16_t len, c
uint8_t shift;
char tmp;
if (len == 0) {
return 0;
}
// convert to 7bit gsm first
char* gsm_str = (char*)malloc(len);
if (!gsm_str) {
return 0;
}
for (uint16_t y = 0; y < len; y++) {
for (int x=0; x < GSM_TO_ASCII_TABLE_SIZE; x++) {
for (int x=0; x < GSM_TO_ASCII_TABLE_SIZE; x++) {
if (gsm_to_ascii[x] == str[y]) {
gsm_str[y] = x;
}

View File

@ -68,7 +68,7 @@ const char * AT_CellularStack::get_ip_address()
// in case stack type is not IPV4 only, try to look also for IPV6 address
if (_stack_type != IPV4_STACK) {
len = _at.read_string(_ip, PDP_IPV6_SIZE-1);
(void)_at.read_string(_ip, PDP_IPV6_SIZE-1);
}
}
@ -92,6 +92,7 @@ nsapi_error_t AT_CellularStack::socket_open(nsapi_socket_t *handle, nsapi_protoc
if (!_socket) {
_socket = new CellularSocket*[max_socket_count];
if (!_socket) {
tr_error("No memory to open socket!");
return NSAPI_ERROR_NO_SOCKET;
}
_socket_count = max_socket_count;
@ -109,9 +110,11 @@ nsapi_error_t AT_CellularStack::socket_open(nsapi_socket_t *handle, nsapi_protoc
}
if (index == -1) {
tr_error("No socket found!");
return NSAPI_ERROR_NO_SOCKET;
}
tr_info("Socket open index: %d", index);
// create local socket structure, socket on modem is created when app calls sendto/recvfrom
_socket[index] = new CellularSocket;
CellularSocket *psock;
@ -135,31 +138,35 @@ nsapi_error_t AT_CellularStack::socket_close(nsapi_socket_t handle)
return err;
}
int sock_id = socket->id;
bool sock_created = socket->created;
int max_socket_count = get_max_socket_count();
int index = -1;
for (int i = 0; i < max_socket_count; i++) {
if (_socket[i] && _socket[i]->id == sock_id) {
if (_socket[i] == socket) {
index = i;
break;
}
}
tr_info("Close socket index: %d id: %d created: %d", index, sock_id, socket->created);
if (index == -1) {
tr_error("No socket found to be closed");
return err;
}
_socket[index] = NULL;
delete socket;
err = NSAPI_ERROR_OK;
// Close the socket on the modem if it was created
_at.lock();
err = socket_close_impl(sock_id);
if (sock_created) {
err = socket_close_impl(sock_id);
}
_at.unlock();
delete socket;
socket = NULL;
return err;
}

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 CELLULAR_COMMON_
#define CELLULAR_COMMON_
#include <stdint.h>
#include "nsapi_types.h"
/**
* Cellular specific event changes.
* Connect and disconnect are handled via NSAPI_EVENT_CONNECTION_STATUS_CHANGE
*/
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 */
} cellular_connection_status_t;
#endif // CELLULAR_COMMON_

View File

@ -168,7 +168,7 @@ void separate_ip_addresses(char* orig, char* ip, size_t ip_size, char* ip2, size
if (ip2 && (ip2_size > strlen(temp))) {
memcpy(ip2, temp, strlen(temp));
ip2[strlen(temp)] = '\0';
} else {
} else if (ip2) {
ip2[0] = '\0';
}
} else {

View File

@ -22,7 +22,7 @@ using namespace mbed;
QUECTEL_BC95_CellularNetwork::QUECTEL_BC95_CellularNetwork(ATHandler &atHandler) : AT_CellularNetwork(atHandler)
{
_op_act = operator_t::RAT_NB1;
_op_act = RAT_NB1;
}
QUECTEL_BC95_CellularNetwork::~QUECTEL_BC95_CellularNetwork()
@ -47,11 +47,11 @@ bool QUECTEL_BC95_CellularNetwork::has_registration(RegistrationType reg_tech)
return (reg_tech == C_EREG);
}
nsapi_error_t QUECTEL_BC95_CellularNetwork::set_access_technology_impl(operator_t::RadioAccessTechnology opRat)
nsapi_error_t QUECTEL_BC95_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opRat)
{
if (opRat != operator_t::RAT_NB1) {
if (opRat != RAT_NB1) {
//TODO: Set as unknown or force to NB1?
_op_act = operator_t::RAT_UNKNOWN;
_op_act = RAT_UNKNOWN;
return NSAPI_ERROR_UNSUPPORTED;
}

View File

@ -31,7 +31,7 @@ public:
protected:
virtual NetworkStack *get_stack();
virtual nsapi_error_t set_access_technology_impl(operator_t::RadioAccessTechnology opRat);
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat);
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);

View File

@ -17,6 +17,7 @@
#include "QUECTEL_BC95_CellularStack.h"
#include "CellularUtil.h"
#include "CellularLog.h"
using namespace mbed;
using namespace mbed_cellular_util;
@ -78,12 +79,14 @@ nsapi_error_t QUECTEL_BC95_CellularStack::socket_close_impl(int sock_id)
_at.resp_start();
_at.resp_stop();
tr_info("Close socket: %d error: %d", sock_id, _at.get_last_error());
return _at.get_last_error();
}
nsapi_error_t QUECTEL_BC95_CellularStack::create_socket_impl(CellularSocket *socket)
{
int sock_id;
int sock_id = -1;
bool socketOpenWorking = false;
if (socket->proto == NSAPI_UDP) {
@ -117,6 +120,7 @@ nsapi_error_t QUECTEL_BC95_CellularStack::create_socket_impl(CellularSocket *soc
}
if (!socketOpenWorking) {
tr_error("Socket create failed!");
return NSAPI_ERROR_NO_SOCKET;
}
@ -124,10 +128,13 @@ nsapi_error_t QUECTEL_BC95_CellularStack::create_socket_impl(CellularSocket *soc
for (int i = 0; i < BC95_SOCKET_MAX; i++) {
CellularSocket *sock = _socket[i];
if (sock && sock->created && sock->id == sock_id) {
tr_error("Duplicate socket index: %d created:%d, sock_id: %d", i, sock->created, sock_id);
return NSAPI_ERROR_NO_SOCKET;
}
}
tr_info("Socket create id: %d", sock_id);
socket->id = sock_id;
socket->created = true;
@ -139,9 +146,10 @@ nsapi_size_or_error_t QUECTEL_BC95_CellularStack::socket_sendto_impl(CellularSoc
{
int sent_len = 0;
char hexstr[BC95_MAX_PACKET_SIZE*2 + 1] = {0};
char_str_to_hex_str((const char*)data, size, hexstr);
char *hexstr = new char[BC95_MAX_PACKET_SIZE*2+1];
int hexlen = char_str_to_hex_str((const char*)data, size, hexstr);
// NULL terminated for write_string
hexstr[hexlen] = 0;
_at.cmd_start("AT+NSOST=");
_at.write_int(socket->id);
_at.write_string(address.get_ip_address(), false);
@ -155,6 +163,8 @@ nsapi_size_or_error_t QUECTEL_BC95_CellularStack::socket_sendto_impl(CellularSoc
sent_len = _at.read_int();
_at.resp_stop();
delete hexstr;
if (_at.get_last_error() == NSAPI_ERROR_OK) {
return sent_len;
}
@ -168,7 +178,7 @@ nsapi_size_or_error_t QUECTEL_BC95_CellularStack::socket_recvfrom_impl(CellularS
nsapi_size_or_error_t recv_len=0;
int port;
char ip_address[NSAPI_IP_SIZE];
char hexstr[BC95_MAX_PACKET_SIZE*2 + 1];
char *hexstr = new char[BC95_MAX_PACKET_SIZE*2+1];
_at.cmd_start("AT+NSORF=");
_at.write_int(socket->id);
@ -180,12 +190,13 @@ nsapi_size_or_error_t QUECTEL_BC95_CellularStack::socket_recvfrom_impl(CellularS
_at.read_string(ip_address, sizeof(ip_address));
port = _at.read_int();
recv_len = _at.read_int();
_at.read_string(hexstr, sizeof(hexstr));
int hexlen = _at.read_string(hexstr, BC95_MAX_PACKET_SIZE*2+1);
// remaining length
_at.skip_param();
_at.resp_stop();
if (!recv_len || (recv_len == -1) || (_at.get_last_error() != NSAPI_ERROR_OK)) {
delete hexstr;
return NSAPI_ERROR_WOULD_BLOCK;
}
@ -194,9 +205,10 @@ nsapi_size_or_error_t QUECTEL_BC95_CellularStack::socket_recvfrom_impl(CellularS
address->set_port(port);
}
if (recv_len > 0) {
hex_str_to_char_str((const char*) hexstr, recv_len*2, (char*)buffer);
if (hexlen > 0) {
hex_str_to_char_str((const char*) hexstr, hexlen, (char*)buffer);
}
delete hexstr;
return recv_len;
}

View File

@ -20,15 +20,8 @@
#include "AT_CellularDevice.h"
namespace mbed {
#ifdef TARGET_MCU_K64F
#define CELLULAR_SERIAL_TX PTC17
#define CELLULAR_SERIAL_RX PTC16
#else
#define CELLULAR_SERIAL_TX PC_1
#define CELLULAR_SERIAL_RX PC_0
#endif
namespace mbed
{
class QUECTEL_BG96 : public AT_CellularDevice
{

View File

@ -47,12 +47,12 @@ NetworkStack *QUECTEL_BG96_CellularNetwork::get_stack()
return _stack;
}
nsapi_error_t QUECTEL_BG96_CellularNetwork::set_access_technology_impl(operator_t::RadioAccessTechnology opsAct)
nsapi_error_t QUECTEL_BG96_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opsAct)
{
_at.lock();
switch (opsAct) {
case operator_t::RAT_CATM1:
case RAT_CATM1:
_at.cmd_start("AT+QCFG=\"nwscanseq\",020301");
_at.cmd_stop();
_at.resp_start();
@ -66,7 +66,7 @@ nsapi_error_t QUECTEL_BG96_CellularNetwork::set_access_technology_impl(operator_
_at.resp_start();
_at.resp_stop();
break;
case operator_t::RAT_NB1:
case RAT_NB1:
_at.cmd_start("AT+QCFG=\"nwscanseq\",030201");
_at.cmd_stop();
_at.resp_start();
@ -80,10 +80,10 @@ nsapi_error_t QUECTEL_BG96_CellularNetwork::set_access_technology_impl(operator_
_at.resp_start();
_at.resp_stop();
break;
case operator_t::RAT_GSM:
case operator_t::RAT_GSM_COMPACT:
case operator_t::RAT_UTRAN:
case operator_t::RAT_EGPRS:
case RAT_GSM:
case RAT_GSM_COMPACT:
case RAT_UTRAN:
case RAT_EGPRS:
_at.cmd_start("AT+QCFG=\"nwscanseq\",010203");
_at.cmd_stop();
_at.resp_start();
@ -107,7 +107,7 @@ nsapi_error_t QUECTEL_BG96_CellularNetwork::set_access_technology_impl(operator_
_at.resp_start();
_at.resp_stop();
_at.unlock();
_op_act = operator_t::RAT_UNKNOWN;
_op_act = RAT_UNKNOWN;
return NSAPI_ERROR_UNSUPPORTED;
}

View File

@ -31,7 +31,7 @@ public:
protected:
virtual NetworkStack *get_stack();
virtual nsapi_error_t set_access_technology_impl(operator_t::RadioAccessTechnology opRat);
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat);
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
};

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.
*/
#include "QUECTEL_BG96_CellularPower.h"
#define DEVICE_READY_URC "CPIN:"
using namespace mbed;
QUECTEL_BG96_CellularPower::QUECTEL_BG96_CellularPower(ATHandler &atHandler) : AT_CellularPower(atHandler)
{
}
nsapi_error_t QUECTEL_BG96_CellularPower::set_device_ready_urc_cb(mbed::Callback<void()> callback)
{
return _at.set_urc_handler(DEVICE_READY_URC, callback);
}
void QUECTEL_BG96_CellularPower::remove_device_ready_urc_cb(mbed::Callback<void()> callback)
{
_at.remove_urc_handler(DEVICE_READY_URC, callback);
}

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 QUECTEL_BG96_CELLULAR_POWER_H_
#define QUECTEL_BG96_CELLULAR_POWER_H_
#include "AT_CellularPower.h"
namespace mbed
{
class QUECTEL_BG96_CellularPower : public AT_CellularPower
{
public:
QUECTEL_BG96_CellularPower(ATHandler &atHandler);
public: //from CellularPower
virtual nsapi_error_t set_device_ready_urc_cb(mbed::Callback<void()> callback);
virtual void remove_device_ready_urc_cb(mbed::Callback<void()> callback);
};
} // namespace mbed
#endif // QUECTEL_BG96_CELLULAR_POWER_H_

View File

@ -99,7 +99,7 @@ void QUECTEL_BG96_CellularStack::handle_open_socket_response(int &modem_connect_
}
nsapi_error_t QUECTEL_BG96_CellularStack::create_socket_impl(CellularSocket *socket)
{
int modem_connect_id;
int modem_connect_id = -1;
int request_connect_id = socket->id;
int remote_port = 0;
int err = -1;
@ -246,7 +246,9 @@ nsapi_size_or_error_t QUECTEL_BG96_CellularStack::socket_recvfrom_impl(CellularS
recv_len = _at.read_int();
_at.read_string(ip_address, sizeof(ip_address));
port = _at.read_int();
_at.read_bytes((uint8_t*)buffer, recv_len);
if (recv_len > 0) {
_at.read_bytes((uint8_t*)buffer, recv_len);
}
_at.resp_stop();
if (!recv_len || (_at.get_last_error() != NSAPI_ERROR_OK)) {

View File

@ -37,8 +37,8 @@ bool TELIT_HE910_CellularNetwork::has_registration(RegistrationType reg_type)
return (reg_type == C_REG || reg_type == C_GREG);
}
nsapi_error_t TELIT_HE910_CellularNetwork::set_access_technology_impl(operator_t::RadioAccessTechnology opRat)
nsapi_error_t TELIT_HE910_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opRat)
{
_op_act = operator_t::RAT_UNKNOWN;
_op_act = RAT_UNKNOWN;
return NSAPI_ERROR_UNSUPPORTED;
}

View File

@ -34,7 +34,7 @@ protected:
virtual bool has_registration(RegistrationType rat);
virtual nsapi_error_t set_access_technology_impl(operator_t::RadioAccessTechnology opRat);
virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat);
};
} // namespace mbed

View File

@ -37,8 +37,8 @@ bool UBLOX_PPP_CellularNetwork::has_registration(RegistrationType reg_type)
return (reg_type == C_REG || reg_type == C_GREG);
}
nsapi_error_t UBLOX_PPP_CellularNetwork::set_access_technology_impl(operator_t::RadioAccessTechnology opRat)
nsapi_error_t UBLOX_PPP_CellularNetwork::set_access_technology_impl(RadioAccessTechnology opRat)
{
_op_act = operator_t::RAT_UNKNOWN;
_op_act = RAT_UNKNOWN;
return NSAPI_ERROR_UNSUPPORTED;
}

View File

@ -33,7 +33,7 @@ protected:
virtual bool has_registration(RegistrationType rat);
virtual nsapi_error_t set_access_technology_impl(operator_t::RadioAccessTechnology opRat);
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.")

View File

@ -73,13 +73,15 @@ enum nsapi_error {
/** Enum of event types
*
*
* Event callbacks are accompanied with an event-dependent parameter passed as an intptr_t.
*
* @enum nsapi_event
*/
typedef enum nsapi_event {
NSAPI_EVENT_CONNECTION_STATUS_CHANGE = 0 /*!< network connection status has changed, the parameter = new status (nsapi_connection_status_t) */
NSAPI_EVENT_CONNECTION_STATUS_CHANGE = 0, /*!< network connection status has changed, the parameter = new status (nsapi_connection_status_t) */
NSAPI_EVENT_CELLULAR_STATUS_BASE = 0x1000, /*!< Cellular modem status has changed, See the enum values from enum cellular_connection_status_t in /features/cellular/framework/common/CellularCommon.h */
NSAPI_EVENT_CELLULAR_STATUS_END = 0x1FFF /*!< cellular modem status has changed, See the enum values from enum cellular_connection_status_t in /features/cellular/framework/common/CellularCommon.h */
} nsapi_event_t;