2018-08-29 06:31:35 +00:00
|
|
|
/*
|
|
|
|
* 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 "CellularDevice.h"
|
2018-09-14 10:32:10 +00:00
|
|
|
#include "CellularContext.h"
|
2018-08-29 06:31:35 +00:00
|
|
|
#include "CellularUtil.h"
|
2018-08-29 06:31:35 +00:00
|
|
|
#include "CellularLog.h"
|
2019-02-21 15:34:27 +00:00
|
|
|
#include "events/EventQueue.h"
|
2020-06-24 07:29:26 +00:00
|
|
|
#include "events/mbed_shared_queues.h"
|
2018-08-29 06:31:35 +00:00
|
|
|
|
|
|
|
namespace mbed {
|
|
|
|
|
|
|
|
MBED_WEAK CellularDevice *CellularDevice::get_default_instance()
|
|
|
|
{
|
2018-12-20 13:48:31 +00:00
|
|
|
return get_target_default_instance();
|
2018-08-29 06:31:35 +00:00
|
|
|
}
|
2018-12-20 13:48:31 +00:00
|
|
|
|
|
|
|
MBED_WEAK CellularDevice *CellularDevice::get_target_default_instance()
|
2018-08-29 06:31:35 +00:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-01-15 09:11:44 +00:00
|
|
|
CellularDevice::CellularDevice() :
|
2019-12-18 08:09:13 +00:00
|
|
|
_network_ref_count(0),
|
2019-11-15 13:51:17 +00:00
|
|
|
#if MBED_CONF_CELLULAR_USE_SMS
|
|
|
|
_sms_ref_count(0),
|
|
|
|
#endif //MBED_CONF_CELLULAR_USE_SMS
|
2020-01-15 09:11:44 +00:00
|
|
|
_info_ref_count(0), _queue(10 * EVENTS_EVENT_SIZE), _state_machine(0),
|
2019-07-02 14:28:26 +00:00
|
|
|
_status_cb(), _nw(0)
|
2019-12-18 08:09:13 +00:00
|
|
|
#ifdef MBED_CONF_RTOS_PRESENT
|
|
|
|
, _queue_thread(osPriorityNormal, 2048, NULL, "cellular_queue")
|
|
|
|
#endif // MBED_CONF_RTOS_PRESENT
|
2018-08-29 06:31:35 +00:00
|
|
|
{
|
2018-11-09 07:14:37 +00:00
|
|
|
set_sim_pin(NULL);
|
|
|
|
set_plmn(NULL);
|
2019-12-18 08:09:13 +00:00
|
|
|
|
|
|
|
#ifdef MBED_CONF_RTOS_PRESENT
|
|
|
|
if (_queue_thread.start(callback(&_queue, &events::EventQueue::dispatch_forever)) != osOK) {
|
|
|
|
tr_error("Failed to start thread");
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
_queue.chain(mbed_event_queue());
|
|
|
|
#endif
|
2018-08-29 06:31:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CellularDevice::~CellularDevice()
|
|
|
|
{
|
2019-01-23 13:38:28 +00:00
|
|
|
tr_debug("CellularDevice destruct");
|
2019-04-08 06:05:54 +00:00
|
|
|
delete _state_machine;
|
2018-08-29 06:31:35 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 13:16:03 +00:00
|
|
|
events::EventQueue *CellularDevice::get_queue()
|
2018-08-29 06:31:35 +00:00
|
|
|
{
|
2018-11-01 13:16:03 +00:00
|
|
|
return &_queue;
|
2018-08-29 06:31:35 +00:00
|
|
|
}
|
|
|
|
|
2019-03-12 10:05:52 +00:00
|
|
|
void CellularDevice::get_retry_timeout_array(uint16_t *timeout, int &array_len) const
|
|
|
|
{
|
|
|
|
if (_state_machine && timeout) {
|
|
|
|
_state_machine->get_retry_timeout_array(timeout, array_len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-29 06:31:35 +00:00
|
|
|
void CellularDevice::set_sim_pin(const char *sim_pin)
|
|
|
|
{
|
2018-09-14 10:32:10 +00:00
|
|
|
if (sim_pin) {
|
|
|
|
strncpy(_sim_pin, sim_pin, sizeof(_sim_pin));
|
|
|
|
_sim_pin[sizeof(_sim_pin) - 1] = '\0';
|
|
|
|
} else {
|
|
|
|
memset(_sim_pin, 0, sizeof(_sim_pin));
|
|
|
|
}
|
2018-08-29 06:31:35 +00:00
|
|
|
}
|
|
|
|
|
2018-11-13 16:50:35 +00:00
|
|
|
void CellularDevice::set_plmn(const char *plmn)
|
2018-08-29 06:31:35 +00:00
|
|
|
{
|
2018-09-14 10:32:10 +00:00
|
|
|
if (plmn) {
|
|
|
|
strncpy(_plmn, plmn, sizeof(_plmn));
|
|
|
|
_plmn[sizeof(_plmn) - 1] = '\0';
|
|
|
|
} else {
|
|
|
|
memset(_plmn, 0, sizeof(_plmn));
|
2018-08-29 06:31:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsapi_error_t CellularDevice::set_device_ready()
|
|
|
|
{
|
2018-09-14 10:32:10 +00:00
|
|
|
return start_state_machine(CellularStateMachine::STATE_DEVICE_READY);
|
2018-08-29 06:31:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsapi_error_t CellularDevice::set_sim_ready()
|
|
|
|
{
|
2018-09-14 10:32:10 +00:00
|
|
|
return start_state_machine(CellularStateMachine::STATE_SIM_PIN);
|
2018-08-29 06:31:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsapi_error_t CellularDevice::register_to_network()
|
|
|
|
{
|
2018-09-14 10:32:10 +00:00
|
|
|
return start_state_machine(CellularStateMachine::STATE_REGISTERING_NETWORK);
|
2018-08-29 06:31:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsapi_error_t CellularDevice::attach_to_network()
|
|
|
|
{
|
2018-09-14 10:32:10 +00:00
|
|
|
return start_state_machine(CellularStateMachine::STATE_ATTACHING_NETWORK);
|
2018-08-29 06:31:35 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 13:16:03 +00:00
|
|
|
nsapi_error_t CellularDevice::create_state_machine()
|
2018-08-29 06:31:35 +00:00
|
|
|
{
|
2018-11-09 13:31:37 +00:00
|
|
|
nsapi_error_t err = NSAPI_ERROR_OK;
|
2018-09-14 10:32:10 +00:00
|
|
|
if (!_state_machine) {
|
2020-01-15 09:11:44 +00:00
|
|
|
_nw = open_network();
|
2019-04-08 06:05:54 +00:00
|
|
|
// Attach to network so we can get update status from the network
|
|
|
|
_nw->attach(callback(this, &CellularDevice::stm_callback));
|
|
|
|
_state_machine = new CellularStateMachine(*this, *get_queue(), *_nw);
|
2019-03-01 07:08:03 +00:00
|
|
|
_state_machine->set_cellular_callback(callback(this, &CellularDevice::stm_callback));
|
|
|
|
if (strlen(_plmn)) {
|
|
|
|
_state_machine->set_plmn(_plmn);
|
|
|
|
}
|
|
|
|
if (strlen(_sim_pin)) {
|
|
|
|
_state_machine->set_sim_pin(_sim_pin);
|
|
|
|
}
|
2018-09-14 10:32:10 +00:00
|
|
|
}
|
2019-07-18 10:58:53 +00:00
|
|
|
err = _state_machine->start_dispatch();
|
|
|
|
if (err) {
|
|
|
|
tr_error("Start state machine failed.");
|
|
|
|
delete _state_machine;
|
|
|
|
_state_machine = NULL;
|
|
|
|
return err;
|
|
|
|
}
|
2018-11-09 13:31:37 +00:00
|
|
|
return err;
|
2018-08-29 06:31:35 +00:00
|
|
|
}
|
|
|
|
|
2018-09-14 10:32:10 +00:00
|
|
|
nsapi_error_t CellularDevice::start_state_machine(CellularStateMachine::CellularState target_state)
|
2018-08-29 06:31:35 +00:00
|
|
|
{
|
2018-09-14 10:32:10 +00:00
|
|
|
_mutex.lock();
|
2018-11-01 13:16:03 +00:00
|
|
|
nsapi_error_t err = create_state_machine();
|
|
|
|
if (err) {
|
2019-02-18 07:53:53 +00:00
|
|
|
_mutex.unlock();
|
2018-11-01 13:16:03 +00:00
|
|
|
return err;
|
|
|
|
}
|
2018-08-29 06:31:35 +00:00
|
|
|
|
2018-09-14 10:32:10 +00:00
|
|
|
CellularStateMachine::CellularState current_state, targeted_state;
|
2018-08-29 06:31:35 +00:00
|
|
|
|
2018-09-14 10:32:10 +00:00
|
|
|
bool is_running = _state_machine->get_current_status(current_state, targeted_state);
|
2018-08-29 06:31:35 +00:00
|
|
|
|
2018-09-14 10:32:10 +00:00
|
|
|
if (current_state >= target_state) { // can stm be in this state but failed?
|
|
|
|
_mutex.unlock();
|
|
|
|
return NSAPI_ERROR_ALREADY;
|
|
|
|
} else if (is_running && targeted_state >= target_state) {
|
|
|
|
_mutex.unlock();
|
|
|
|
return NSAPI_ERROR_IN_PROGRESS;
|
|
|
|
}
|
2018-08-29 06:31:35 +00:00
|
|
|
|
2018-11-01 13:16:03 +00:00
|
|
|
err = _state_machine->run_to_state(target_state);
|
2018-09-14 10:32:10 +00:00
|
|
|
_mutex.unlock();
|
2018-08-29 06:31:35 +00:00
|
|
|
|
2018-09-14 10:32:10 +00:00
|
|
|
return err;
|
2018-08-29 06:31:35 +00:00
|
|
|
}
|
|
|
|
|
2018-11-27 06:05:41 +00:00
|
|
|
void CellularDevice::attach(Callback<void(nsapi_event_t, intptr_t)> status_cb)
|
|
|
|
{
|
|
|
|
_status_cb = status_cb;
|
|
|
|
}
|
|
|
|
|
2019-03-01 07:08:03 +00:00
|
|
|
void CellularDevice::stm_callback(nsapi_event_t ev, intptr_t ptr)
|
|
|
|
{
|
|
|
|
cellular_callback(ev, ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CellularDevice::cellular_callback(nsapi_event_t ev, intptr_t ptr, CellularContext *ctx)
|
2018-08-29 06:31:35 +00:00
|
|
|
{
|
2018-09-14 10:32:10 +00:00
|
|
|
if (ev >= NSAPI_EVENT_CELLULAR_STATUS_BASE && ev <= NSAPI_EVENT_CELLULAR_STATUS_END) {
|
|
|
|
cellular_connection_status_t cell_ev = (cellular_connection_status_t)ev;
|
2019-05-10 06:35:44 +00:00
|
|
|
cell_callback_data_t *ptr_data = (cell_callback_data_t *)ptr;
|
|
|
|
(void)ptr_data; // avoid compile warning, used only for debugging
|
2019-04-05 09:44:13 +00:00
|
|
|
if (cell_ev == CellularStateRetryEvent) {
|
|
|
|
tr_debug("callback: CellularStateRetryEvent, err: %d, data: %d, retrycount: %d", ptr_data->error, ptr_data->status_data, *(const int *)ptr_data->data);
|
|
|
|
} else {
|
|
|
|
tr_debug("callback: %d, err: %d, data: %d", ev, ptr_data->error, ptr_data->status_data);
|
|
|
|
}
|
2018-09-14 10:32:10 +00:00
|
|
|
if (cell_ev == CellularRegistrationStatusChanged && _state_machine) {
|
|
|
|
// broadcast only network registration changes to state machine
|
|
|
|
_state_machine->cellular_event_changed(ev, ptr);
|
2018-08-29 06:31:35 +00:00
|
|
|
}
|
|
|
|
} else {
|
2018-11-15 13:22:03 +00:00
|
|
|
tr_debug("callback: %d, ptr: %d", ev, ptr);
|
2018-10-29 12:05:08 +00:00
|
|
|
if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE && ptr == NSAPI_STATUS_DISCONNECTED) {
|
|
|
|
// we have been disconnected, reset state machine so that application can start connect sequence again
|
|
|
|
if (_state_machine) {
|
2019-03-01 07:08:03 +00:00
|
|
|
CellularStateMachine::CellularState current_state, targeted_state;
|
|
|
|
bool is_running = _state_machine->get_current_status(current_state, targeted_state);
|
|
|
|
if (!is_running) {
|
|
|
|
_state_machine->reset();
|
|
|
|
}
|
2018-10-29 12:05:08 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-29 06:31:35 +00:00
|
|
|
}
|
2018-09-14 10:32:10 +00:00
|
|
|
|
|
|
|
// broadcast network and cellular changes to state machine and CellularContext.
|
|
|
|
CellularContext *curr = get_context_list();
|
|
|
|
while (curr) {
|
2019-03-01 07:08:03 +00:00
|
|
|
if (ctx) {
|
|
|
|
if (ctx == curr) {
|
|
|
|
curr->cellular_callback(ev, ptr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
curr->cellular_callback(ev, ptr);
|
|
|
|
}
|
2018-09-14 10:32:10 +00:00
|
|
|
curr = curr->_next;
|
2018-08-29 06:31:35 +00:00
|
|
|
}
|
2018-11-27 06:05:41 +00:00
|
|
|
|
2019-03-01 07:08:03 +00:00
|
|
|
// forward to callback function if set by attach(...).
|
2018-11-27 06:05:41 +00:00
|
|
|
if (_status_cb) {
|
|
|
|
_status_cb(ev, ptr);
|
|
|
|
}
|
2018-08-29 06:31:35 +00:00
|
|
|
}
|
|
|
|
|
2018-11-29 08:54:27 +00:00
|
|
|
nsapi_error_t CellularDevice::shutdown()
|
|
|
|
{
|
2019-08-02 09:19:58 +00:00
|
|
|
if (_state_machine) {
|
|
|
|
_state_machine->stop();
|
|
|
|
}
|
2018-11-29 08:54:27 +00:00
|
|
|
CellularContext *curr = get_context_list();
|
|
|
|
while (curr) {
|
2019-08-29 11:24:07 +00:00
|
|
|
if (curr->is_connected()) {
|
|
|
|
curr->disconnect();
|
|
|
|
}
|
2018-11-29 08:54:27 +00:00
|
|
|
curr->cellular_callback(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED);
|
|
|
|
curr = (CellularContext *)curr->_next;
|
|
|
|
}
|
|
|
|
return NSAPI_ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2019-04-03 10:11:59 +00:00
|
|
|
void CellularDevice::set_retry_timeout_array(const uint16_t timeout[], int array_len)
|
|
|
|
{
|
|
|
|
if (create_state_machine() == NSAPI_ERROR_OK) {
|
|
|
|
_state_machine->set_retry_timeout_array(timeout, array_len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-14 10:32:10 +00:00
|
|
|
} // namespace mbed
|