Initial cellular feature

pull/6082/head
Ari Parkkila 2018-02-09 13:24:27 +02:00
parent a137444754
commit 863ec3c3cc
68 changed files with 12531 additions and 0 deletions

View File

@ -0,0 +1,513 @@
/*
* 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 <mbed.h>
#include "CellularConnectionUtil.h"
#ifndef MBED_TRACE_MAX_LEVEL
#define MBED_TRACE_MAX_LEVEL TRACE_LEVEL_INFO
#endif
#include "CellularLog.h"
/*#define log_debug printf
#define log_info printf
#define log_warn printf
#define log_error printf
*/
// 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_REGISTRATION (180*1000)
static EventQueue at_queue(8 * EVENTS_EVENT_SIZE);
static CELLULAR_DEVICE cellularDevice(at_queue);
#define ENUM_MACRO(name, v1, v2, v3, v4, v5, v6, v7)\
enum name { v1, v2, v3, v4, v5, v6, v7};\
const char *name##Strings[] = { #v1, #v2, #v3, #v4, #v5, #v6, #v7};
CellularConnectionUtil::CellularConnectionUtil() : _serial(0), _state(STATE_POWER_ON), _next_state(_state), _status_callback(0), _network(0), _power(0), _queue(8 * EVENTS_EVENT_SIZE), _queue_thread(0), _cellularDevice(&cellularDevice)
{
}
CellularConnectionUtil::~CellularConnectionUtil()
{
stop();
}
bool CellularConnectionUtil::open_power(FileHandle *fh)
{
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) {
log_warn("Cellular start failed. Power off/on.");
err = _power->off();
if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED) {
log_error("Cellular power down failed!");
}
return false;
}
return true;
}
bool CellularConnectionUtil::open_sim()
{
#ifdef MBED_CONF_APP_CELLULAR_SIM_PIN
nsapi_error_t err;
static CellularSIM *sim;
if (!sim) {
sim = _cellularDevice->open_sim(_serial);
}
if (!sim) {
return false;
}
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) {
log_debug("Waiting for SIM (state %d)...", state);
return false;
}
if (state == CellularSIM::SimStatePinNeeded) {
log_info("SIM pin required, entering pin: %s", MBED_CONF_APP_CELLULAR_SIM_PIN);
err = sim->set_pin(MBED_CONF_APP_CELLULAR_SIM_PIN);
if (err) {
log_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;
}
log_debug("SIM state: %d", state);
return false;
}
}
return state == CellularSIM::SimStateReady;
#else
log_info("Continue without SIM.");
return true;
#endif
}
bool CellularConnectionUtil::run_self_tests()
{
CellularInformation *info = _cellularDevice->open_information(_serial);
char buf[2048];
if (info->get_manufacturer(buf, sizeof(buf)) == NSAPI_ERROR_OK) {
log_info("Cellular device manufacturer: %s", buf);
}
if (info->get_model(buf, sizeof(buf)) == NSAPI_ERROR_OK) {
log_info("Cellular device model: %s", buf);
}
if (info->get_revision(buf, sizeof(buf)) == NSAPI_ERROR_OK) {
log_info("Cellular device revision: %s", buf);
}
return true;
}
bool CellularConnectionUtil::open_network()
{
if (!_network) {
_network = _cellularDevice->open_network(_serial);
}
return (_network != NULL);
}
bool CellularConnectionUtil::set_network_registration(char *plmn)
{
if (_network->set_registration(plmn) != NSAPI_ERROR_OK) {
log_error("Failed to set network registration.");
return false;
}
return true;
}
bool CellularConnectionUtil::get_network_registration(CellularNetwork::RegistrationType type, CellularNetwork::RegistrationStatus &status, bool &is_registered)
{
is_registered = false;
bool is_roaming = false;
if (_network->get_registration_status(type, status) != NSAPI_ERROR_OK) {
return false;
}
switch (status) {
case CellularNetwork::RegisteredRoaming:
is_roaming = true;
// fall-through
case CellularNetwork::RegisteredHomeNetwork:
is_registered = true;
break;
case CellularNetwork::RegisteredSMSOnlyRoaming:
is_roaming = true;
// fall-through
case CellularNetwork::RegisteredSMSOnlyHome:
log_warn("SMS only network registration!");
is_registered = true;
break;
case CellularNetwork::RegisteredCSFBNotPreferredRoaming:
is_roaming = true;
// fall-through
case CellularNetwork::RegisteredCSFBNotPreferredHome:
log_warn("Not preferred network registration!");
is_registered = true;
break;
case CellularNetwork::AttachedEmergencyOnly:
case CellularNetwork::RegistrationDenied:
case CellularNetwork::NotRegistered:
case CellularNetwork::Unknown:
case CellularNetwork::SearchingNetwork:
default:
break;
}
if (is_roaming) {
log_warn("Roaming cellular network!");
}
return true;
}
bool CellularConnectionUtil::get_attach_network(CellularNetwork::AttachStatus &status)
{
nsapi_error_t err = _network->get_attach(status);
if (err != NSAPI_ERROR_OK) {
return false;
}
return true;
}
bool CellularConnectionUtil::set_attach_network()
{
nsapi_error_t attach_err = _network->set_attach();
if (attach_err != NSAPI_ERROR_OK) {
return false;
}
return true;
}
void CellularConnectionUtil::report_failure(const char* msg)
{
log_error("Cellular network failed: %s", msg);
if (_status_callback) {
_status_callback(_state, _next_state);
}
}
bool CellularConnectionUtil::continue_with_state(CellularState state)
{
_state = state;
if (!_queue.call_in(0, callback(this, &CellularConnectionUtil::event))) {
stop();
return NSAPI_ERROR_NO_MEMORY;
}
return NSAPI_ERROR_OK;
}
void CellularConnectionUtil::event()
{
nsapi_error_t err;
int event_timeout = -1;
switch (_state) {
case STATE_POWER_ON:
cellularDevice.set_timeout(TIMEOUT_POWER_ON);
log_info("Cellular power ON (timeout %d ms)", TIMEOUT_POWER_ON);
if (open_power(_serial)) {
_next_state = STATE_SELF_TEST;
} else {
static int retry_count;
if (++retry_count < 10) {
log_warn("Power ON retry %d", retry_count);
event_timeout = 1000;
} else {
report_failure("Power");
return;
}
}
break;
case STATE_SELF_TEST:
cellularDevice.set_timeout(TIMEOUT_POWER_ON);
log_info("Cellular self-test (timeout %d ms)", TIMEOUT_POWER_ON);
if (_power->set_at_mode() == NSAPI_ERROR_OK) {
_next_state = STATE_START_CELLULAR;
run_self_tests();
} else {
static int retry_count = 0;
if (++retry_count < 10) {
log_warn("Waiting for cellular %d", retry_count);
event_timeout = 1000;
} else {
report_failure("Power");
return;
}
}
break;
case STATE_START_CELLULAR:
cellularDevice.set_timeout(TIMEOUT_NETWORK);
log_info("Start cellular (timeout %d ms)", TIMEOUT_NETWORK);
open_network();
_next_state = STATE_SIM_PIN;
break;
case STATE_SIM_PIN:
cellularDevice.set_timeout(TIMEOUT_SIM_PIN);
log_info("Start cellular (timeout %d ms)", TIMEOUT_SIM_PIN);
if (open_sim()) {
_next_state = STATE_REGISTERING_NETWORK;
log_info("Check for network registration");
} else {
static int retry_count;
if (++retry_count < 10) {
log_warn("Waiting for SIM %d", retry_count);
event_timeout = 1000;
} else {
report_failure("Entering SIM PIN");
return;
}
}
break;
case STATE_REGISTERING_NETWORK:
cellularDevice.set_timeout(TIMEOUT_NETWORK);
CellularNetwork::RegistrationStatus status;
bool is_registered;
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
if (get_network_registration((CellularNetwork::RegistrationType)type, status, is_registered)) {
if (is_registered) {
log_info("Registered to cellular network (status %d)", status);
_next_state = STATE_ATTACH_NETWORK;
log_info("Check cellular network attach state");
event_timeout = 0;
break;
} else {
if (status == CellularNetwork::RegistrationDenied) {
static int backoff_timeout = 1;
log_warn("Network registration denied! Retry after %d seconds.", backoff_timeout);
event_timeout = backoff_timeout * 1000;
backoff_timeout *= 2;
_next_state = STATE_REGISTERING_NETWORK;
break;
} else if (status == CellularNetwork::NotRegistered) {
log_info("(STATE_REGISTERING_NETWORK), not registered");
if (event_timeout == -1) {
_next_state = STATE_REGISTER_NETWORK;
event_timeout = 0;
}
} else {
static int retry_count;
if (++retry_count < 18) {
log_info("Waiting for registration");
event_timeout = 1*1000;
_next_state = STATE_REGISTERING_NETWORK;
} else {
if (event_timeout == -1) {
log_info("Start cellular registration");
_next_state = STATE_REGISTER_NETWORK;
}
}
}
}
}
}
if (_state == _next_state && event_timeout == -1) {
event_timeout = 0;
}
break;
case STATE_REGISTER_NETWORK:
cellularDevice.set_timeout(TIMEOUT_REGISTRATION);
log_info("Register to cellular network (timeout %d ms)", TIMEOUT_REGISTRATION);
if (set_network_registration()) {
_next_state = STATE_REGISTERING_NETWORK;
} else {
static int retry_count;
if (++retry_count < 3) {
event_timeout = 1000;
} else {
report_failure("Registration");
return;
}
}
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;
} else {
_next_state = STATE_ATTACH_NETWORK;
}
} else {
event_timeout = 0;
}
break;
case STATE_ATTACH_NETWORK:
cellularDevice.set_timeout(TIMEOUT_NETWORK);
log_info("Attach to cellular network (timeout %d ms)", TIMEOUT_NETWORK);
if (set_attach_network()) {
_next_state = STATE_ATTACHING_NETWORK;
log_info("Cellular network attaching");
} else {
event_timeout = 0;
}
break;
case STATE_CONNECT_NETWORK:
cellularDevice.set_timeout(TIMEOUT_NETWORK);
log_info("Connect to cellular network (timeout %d ms)", TIMEOUT_NETWORK);
// Set APN
//network->set_credentials("internet");
err = _network->connect();
if (!err) {
_next_state = STATE_READY;
} else {
report_failure("Network connect");
return;
}
break;
case STATE_READY:
cellularDevice.set_timeout(TIMEOUT_NETWORK);
log_debug("Cellular ready! (timeout %d ms)", TIMEOUT_NETWORK);
if (_status_callback) {
_status_callback(_state, _next_state);
}
break;
default:
MBED_ASSERT(0);
break;
}
if (_next_state != _state || event_timeout >= 0) {
if (_next_state != _state) {
log_info("Cellular state from %d to %d", _state, _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) {
log_info("Cellular event retry %d", retry_count);
} else {
report_failure("Cellular connection failed!");
return;
}
} else {
log_info("Cellular event in %d milliseconds", event_timeout);
}
}
_state = _next_state;
if (event_timeout == -1) {
event_timeout = 0;
}
if (!_queue.call_in(event_timeout, callback(this, &CellularConnectionUtil::event))) {
report_failure("Cellular event failure!");
return;
}
}
}
bool CellularConnectionUtil::start(bool start_dispatch)
{
log_info("CellularConnectionUtil::start");
_power = _cellularDevice->open_power(_serial);
if (!_power) {
stop();
return false;
}
_network = _cellularDevice->open_network(_serial);
if (!_network) {
stop();
return false;
}
if (!_queue.call_in(0, callback(this, &CellularConnectionUtil::event))) {
stop();
return false;
}
at_queue.chain(&_queue);
if (start_dispatch) {
log_info("Create cellular thread");
_queue_thread = new Thread();
if (!_queue_thread) {
stop();
return false;
}
if (_queue_thread->start(callback(&_queue, &EventQueue::dispatch_forever)) != osOK) {
stop();
return false;
}
}
log_info("CellularConnectionUtil::started");
return true;
}
void CellularConnectionUtil::stop()
{
log_info("CellularConnectionUtil::stop");
_cellularDevice->close_power();
_cellularDevice->close_network();
if (_queue_thread) {
_queue_thread->terminate();
_queue_thread = NULL;
}
}
void CellularConnectionUtil::set_serial(UARTSerial *serial)
{
_serial = serial;
}
void CellularConnectionUtil::set_callback(mbed::Callback<int(int, int)> status_callback)
{
_status_callback = status_callback;
}
EventQueue *CellularConnectionUtil::get_queue()
{
return &_queue;
}
CellularNetwork* CellularConnectionUtil::get_network()
{
if (_state != STATE_READY) {
return NULL;
}
return _network;
}
CellularDevice* CellularConnectionUtil::get_device()
{
if (_cellularDevice) {
return _cellularDevice;
} else {
return NULL;
}
}

View File

@ -0,0 +1,90 @@
/*
* 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_CONNECTION_UTIL_H
#define _CELLULAR_CONNECTION_UTIL_H
#include <UARTSerial.h>
#include <NetworkInterface.h>
#include <EventQueue.h>
#include "CellularNetwork.h"
#include "CellularPower.h"
// modem type is defined as CELLULAR_DEVICE macro
#define _CELLULAR_STRINGIFY(a) #a
#define CELLULAR_STRINGIFY(a) _CELLULAR_STRINGIFY(a)
#include "CellularTargets.h"
#include CELLULAR_STRINGIFY(CELLULAR_DEVICE.h)
class CellularConnectionUtil
{
public:
enum CellularState {
STATE_POWER_ON = 0,
STATE_SELF_TEST = 1,
STATE_START_CELLULAR = 2,
STATE_SIM_PIN = 3,
STATE_REGISTER_NETWORK = 4,
STATE_REGISTERING_NETWORK = 5,
STATE_ATTACH_NETWORK = 7,
STATE_ATTACHING_NETWORK = 8,
STATE_CONNECT_NETWORK = 9,
STATE_READY = 10,
};
public:
CellularConnectionUtil();
virtual ~CellularConnectionUtil();
void set_serial(UARTSerial *serial);
void set_callback(mbed::Callback<int(int, int)> status_callback);
EventQueue* get_queue();
bool start(bool start_dispatch = true);
void stop();
CellularNetwork* get_network();
CellularDevice* get_device();
bool continue_with_state(CellularState state);
protected:
bool open_power(FileHandle *fh);
bool open_sim();
bool open_network();
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();
private:
bool run_self_tests();
void report_failure(const char* msg);
void event();
UARTSerial *_serial;
CellularState _state;
CellularState _next_state;
mbed::Callback<int(int, int)> _status_callback;
CellularNetwork *_network;
CellularPower *_power;
EventQueue _queue;
Thread *_queue_thread;
CellularDevice *_cellularDevice;
};
#endif /* _CELLULAR_CONNECTION_UTIL_H */

View File

@ -0,0 +1,115 @@
/* Copyright (c) 2017 ARM Limited
*
* 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 <mbed.h>
#include "CellularConnectionUtil.h"
#include "CellularTargets.h"
#include "CellularUtil.h"
#include "CellularConnectionUtil.h"
#include "EasyCellularConnection.h"
#include "CellularLog.h"
static CellularConnectionUtil cellularConnection;
static rtos::Semaphore cellularSemaphore(0);
static UARTSerial cellularSerial(MDMTXD, MDMRXD, MBED_CONF_APP_CELLULAR_SERIAL_SPEED);
static int cellular_status(int state, int next_state)
{
if (state == CellularConnectionUtil::STATE_READY) {
MBED_ASSERT(cellularSemaphore.release() == osOK);
}
return 1;
}
EasyCellularConnection::EasyCellularConnection()
{
log_info("EasyCellularConnection start");
#if defined (MDMRTS) && defined (MDMCTS)
log_info("Serial RTS/CTS flow control in use");
cellularSerial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS);
#endif
cellularConnection.set_serial(&cellularSerial);
cellularConnection.set_callback(callback(cellular_status));
}
EasyCellularConnection::~EasyCellularConnection()
{
cellularConnection.stop();
}
void EasyCellularConnection::set_credentials(const char *apn, const char *uname, const char *pwd)
{
}
/* if (cellularConnection.start()) {
int ret_wait = cellularSemaphore.wait(180*1000);
if (ret_wait == 1) {
network_interface = cellularConnection.get_network();
if (network_interface) {
connect_success = true;
}
if (log_messages) {
printf("[EasyConnect] Cellular connection %s!\n", connect_success?"succesful":"failed");
}
}
}*/
void EasyCellularConnection::set_sim_pin(const char *sim_pin)
{
//go_to_state();
}
nsapi_error_t EasyCellularConnection::connect(const char *sim_pin, const char *apn, const char *uname, const char *pwd)
{
return 0;
}
nsapi_error_t EasyCellularConnection::connect()
{
return 0;
}
nsapi_error_t EasyCellularConnection::disconnect()
{
return 0;
}
bool EasyCellularConnection::is_connected()
{
return 0;
}
const char *EasyCellularConnection::get_ip_address()
{
return 0;
}
const char *EasyCellularConnection::get_netmask()
{
return 0;
}
const char *EasyCellularConnection::get_gateway()
{
return 0;
}
NetworkStack *EasyCellularConnection::get_stack()
{
return 0;
}

View File

@ -0,0 +1,119 @@
/* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef EASY_CELLULAR_CONNECTION_H
#define EASY_CELLULAR_CONNECTION_H
#include "netsocket/CellularBase.h"
/** ExampleCellularBase class
*
* A simplified example about how to use cellular
*/
class EasyCellularConnection: public CellularBase {
public:
EasyCellularConnection();
virtual ~EasyCellularConnection();
public:
/** Set the Cellular network credentials
*
* Please check documentation of connect() for default behaviour of APN settings.
*
* @param apn Access point name
* @param uname optionally, Username
* @param pwd optionally, password
*/
virtual void set_credentials(const char *apn, const char *uname = 0,
const char *pwd = 0);
/** Set the pin code for SIM card
*
* @param sim_pin PIN for the SIM card
*/
virtual void set_sim_pin(const char *sim_pin);
/** Start the interface
*
* Attempts to connect to a Cellular network.
*
* @param sim_pin PIN for the SIM card
* @param apn optionally, access point name
* @param uname optionally, Username
* @param pwd optionally, password
* @return NSAPI_ERROR_OK on success, or negative error code on failure
*/
virtual nsapi_error_t connect(const char *sim_pin, const char *apn = 0,
const char *uname = 0,
const char *pwd = 0);
/** Start the interface
*
* Attempts to connect to a Cellular network.
* If the SIM requires a PIN, and it is not set/invalid, NSAPI_ERROR_AUTH_ERROR is returned.
*
* @return NSAPI_ERROR_OK on success, or negative error code on failure
*/
virtual nsapi_error_t connect();
/** Stop the interface
*
* @return 0 on success, or error code on failure
*/
virtual nsapi_error_t disconnect();
/** Check if the connection is currently established or not
*
* @return true/false If the cellular module have successfully acquired a carrier and is
* connected to an external packet data network using PPP, isConnected()
* API returns true and false otherwise.
*/
virtual bool is_connected();
/** Get the local IP address
*
* @return Null-terminated representation of the local IP address
* or null if no IP address has been received
*/
virtual const char *get_ip_address();
/** Get the local network mask
*
* @return Null-terminated representation of the local network mask
* or null if no network mask has been received
*/
virtual const char *get_netmask();
/** Get the local gateways
*
* @return Null-terminated representation of the local gateway
* or null if no network mask has been received
*/
virtual const char *get_gateway();
protected:
/** Provide access to the NetworkStack object
*
* @return The underlying NetworkStack object
*/
virtual NetworkStack *get_stack();
};
#endif // EASY_CELLULAR_CONNECTION_H
/** @}*/

View File

@ -0,0 +1,121 @@
/*
* 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_DEVICE_H_
#define CELLULAR_DEVICE_H_
#include "FileHandle.h"
#include "CellularSIM.h"
#include "CellularNetwork.h"
#include "CellularSMS.h"
#include "CellularPower.h"
#include "CellularMultiplexer.h"
#include "CellularInformation.h"
namespace mbed {
/**
* Class CellularDevice
*
* An abstract interface that defines opening and closing of cellular interfaces.
* Deleting/Closing of opened interfaces can be done only via this class.
*/
class CellularDevice
{
public:
/** virtual Destructor
*/
virtual ~CellularDevice() {}
public:
/** Create new CellularNetwork interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle.
* @return New instance of interface CellularNetwork.
*/
virtual CellularNetwork *open_network(FileHandle *fh) = 0;
/** Create new CellularSMS interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle.
* @return New instance of interface CellularSMS.
*/
virtual CellularSMS *open_sms(FileHandle *fh) = 0;
/** Create new CellularPower interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle.
* @return New instance of interface CellularPower.
*/
virtual CellularPower *open_power(FileHandle *fh) = 0;
/** Create new CellularSIM interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle.
* @return New instance of interface CellularSIM.
*/
virtual CellularSIM *open_sim(FileHandle *fh) = 0;
/** Create new CellularMultiplexer interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle.
* @return New instance of interface CellularMultiplexer.
*/
virtual CellularMultiplexer *open_multiplexer(FileHandle *fh) = 0;
/** Create new CellularInformation interface.
*
* @param fh file handle used in communication to modem. Can be for example UART handle.
* @return New instance of interface CellularInformation.
*/
virtual CellularInformation *open_information(FileHandle *fh) = 0;
/** Closes the opened CellularNetwork by deleting the CellularNetwork instance.
*/
virtual void close_network() = 0;
/** Closes the opened CellularNetwork by deleting the CellularSMS instance.
*/
virtual void close_sms() = 0;
/** Closes the opened CellularNetwork by deleting the CellularPower instance.
*/
virtual void close_power() = 0;
/** Closes the opened CellularNetwork by deleting the CellularSIM instance.
*/
virtual void close_sim() = 0;
/** Closes the opened CellularNetwork by deleting the CellularMultiplexer instance.
*/
virtual void close_multiplexer() = 0;
/** Closes the opened CellularNetwork by deleting the CellularInformation instance.
*/
virtual void close_information() = 0;
/** Set the default response timeout.
*
* @param timeout milliseconds to wait response from modem
*/
virtual void set_timeout(int timeout) = 0;
};
} // namespace mbed
#endif // CELLULAR_DEVICE_H_

View File

@ -0,0 +1,69 @@
/*
* 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_INFORMATION_H_
#define CELLULAR_INFORMATION_H_
#include <stddef.h>
#include "nsapi_types.h"
namespace mbed {
/**
* Class CellularInformation
*
* An abstract interface that provides information about cellular device.
*/
class CellularInformation
{
protected:
// friend of CellularDevice so that it's the only way to close/delete this class.
friend class CellularDevice;
/** virtual Destructor
*/
virtual ~CellularInformation() {};
public:
/** Request manufacturer identification of cellular device
*
* @param buf manufacturer identification
* @param buf_size max length of manufacturer identification is 2048 characters
* @return on success read character count, on failure negative error code
*/
virtual nsapi_size_or_error_t get_manufacturer(char *buf, size_t buf_size) = 0;
/** Request model identification of cellular device
*
* @param buf model identification
* @param buf_size max length of model identification is 2048 characters
* @return on success read character count, on failure negative error code
*/
virtual nsapi_size_or_error_t get_model(char *buf, size_t buf_size) = 0;
/** Request revision identification of cellular device
*
* @param buf revision identification
* @param buf_size max length of revision identification is 2048 characters
* @return on success read character count, on failure negative error code
*/
virtual nsapi_size_or_error_t get_revision(char *buf, size_t buf_size) = 0;
};
} // namespace mbed
#endif // CELLULAR_INFORMATION_H_

View File

@ -0,0 +1,51 @@
/*
* 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_MULTIPLEXER_H_
#define CELLULAR_MULTIPLEXER_H_
#include "nsapi_types.h"
namespace mbed {
/**
* Class CellularMultiplexer
*
* An abstract interface that provides a way to start multiplexer mode in modem.
*/
class CellularMultiplexer
{
protected:
// friend of CellularDevice so that it's the only way to close/delete this class.
friend class CellularDevice;
/** virtual Destructor
*/
virtual ~CellularMultiplexer() {};
public:
/** Starts modem multiplexer mode specified by 3GPP TS 27.010.
*
* @return zero on success, negative error code on failure
*/
virtual nsapi_error_t multiplexer_mode_start() = 0;
};
} // namespace mbed
#endif // CELLULAR_MULTIPLEXER_H_

View File

@ -0,0 +1,382 @@
/*
* 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_NETWORK_H_
#define CELLULAR_NETWORK_H_
#include "CellularInterface.h"
#include "NetworkInterface.h"
#include "CellularList.h"
namespace mbed {
/**
* Class CellularNetwork
*
* An abstract interface for connecting to a network and getting information from it.
*/
class CellularNetwork : public NetworkInterface
{
protected:
// friend of CellularDevice so that it's the only way to close/delete this class.
friend class CellularDevice;
/**
* virtual Destructor
*/
virtual ~CellularNetwork() {}
public:
/* Definition for Supported CIoT EPS optimizations type. */
enum Supported_UE_Opt {
SUPPORTED_UE_OPT_NO_SUPPORT = 0, /* No support. */
SUPPORTED_UE_OPT_CONTROL_PLANE, /* Support for control plane CIoT EPS optimization. */
SUPPORTED_UE_OPT_USER_PLANE, /* Support for user plane CIoT EPS optimization. */
SUPPORTED_UE_OPT_BOTH, /* Support for both control plane CIoT EPS optimization and user plane CIoT EPS
optimization. */
SUPPORTED_UE_OPT_MAX
};
/* Definition for Preferred CIoT EPS optimizations type. */
enum Preferred_UE_Opt {
PREFERRED_UE_OPT_NO_PREFERENCE = 0, /* No preference. */
PREFERRED_UE_OPT_CONTROL_PLANE, /* Preference for control plane CIoT EPS optimization. */
PREFERRED_UE_OPT_USER_PLANE, /* Preference for user plane CIoT EPS optimization. */
PREFERRED_UE_OPT_MAX
};
/* Network registration status */
enum RegistrationStatus {
NotRegistered = 0,
RegisteredHomeNetwork,
SearchingNetwork,
RegistrationDenied,
Unknown,
RegisteredRoaming,
RegisteredSMSOnlyHome,
RegisteredSMSOnlyRoaming,
AttachedEmergencyOnly,
RegisteredCSFBNotPreferredHome,
RegisteredCSFBNotPreferredRoaming = 10
};
/* Network registration type */
enum RegistrationType {
C_EREG = 0,
C_GREG,
C_REG,
C_MAX
};
/* device attach status to network */
enum AttachStatus {
Detached = 0,
Attached,
};
/* whether the additional exception reports are allowed to be sent when the maximum uplink rate is reached */
enum RateControlExceptionReports {
NotAllowedToBeSent = 0,
AllowedToBeSent
};
/* specifies the time unit to be used for the maximum uplink rate */
enum RateControlUplinkTimeUnit {
Unrestricted = 0,
Minute,
Hour,
Day,
Week
};
/* authentication type when activating or modifying the pdp context */
enum AuthenticationType {
NOAUTH = 0,
PAP,
CHAP
};
// 3GPP TS 27.007 - 7.3 PLMN selection +COPS
struct operator_t {
enum Status {
Unknown,
Available,
Current,
Forbiden
};
enum RadioAccessTechnology {
RAT_GSM,
RAT_GSM_COMPACT,
RAT_UTRAN,
RAT_EGPRS,
RAT_HSDPA,
RAT_HSUPA,
RAT_HSDPA_HSUPA,
RAT_E_UTRAN,
RAT_CATM1,
RAT_NB1,
RAT_UNKNOWN
};
Status op_status;
char op_long[16+9];
char op_short[8+4];
char op_num[8+4];
RadioAccessTechnology op_rat;
operator_t *next;
operator_t() {
op_status = Unknown;
op_rat = RAT_UNKNOWN;
next = NULL;
}
};
typedef CellularList<operator_t> operList_t;
/* PDP Context information */
struct pdpcontext_params_t {
char apn[100+1];
char local_addr[63+1];
char local_subnet_mask[63+1];
char gateway_addr[63+1];
char dns_primary_addr[63+1];
char dns_secondary_addr[63+1];
char p_cscf_prim_addr[63+1];
char p_cscf_sec_addr[63+1];
int cid;
int bearer_id;
int im_signalling_flag;
int lipa_indication;
int ipv4_mtu;
int wlan_offload;
int local_addr_ind;
int non_ip_mtu;
int serving_plmn_rate_control_value;
pdpcontext_params_t* next;
pdpcontext_params_t() {
apn[0] = '\0';
local_addr[0] = '\0';
local_subnet_mask[0] = '\0';
gateway_addr[0] = '\0';
dns_primary_addr[0] = '\0';
dns_secondary_addr[0] = '\0';
p_cscf_prim_addr[0] = '\0';
p_cscf_sec_addr[0] = '\0';
cid = -1;
bearer_id = -1;
im_signalling_flag = -1;
lipa_indication = -1;
ipv4_mtu = -1;
wlan_offload = -1;
local_addr_ind = -1;
non_ip_mtu = -1;
serving_plmn_rate_control_value = -1;
next = NULL;
}
};
typedef CellularList<pdpcontext_params_t> pdpContextList_t;
/** Request registering to network.
*
* @param plmn format is in numeric format or 0 for automatic network registration
* @return zero on success
*/
virtual nsapi_error_t set_registration(char *plmn = 0) = 0;
/** Gets the network registration status.
*
* @param type see RegistrationType values
* @param status see RegistrationStatus values
* @return zero on success
*/
virtual nsapi_error_t get_registration_status(RegistrationType type, RegistrationStatus &status) = 0;
/** Set the cellular network APN and credentials
*
* @param apn Optional name of the network to connect to
* @param username Optional username for the APN
* @param password Optional password fot the APN
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t set_credentials(const char *apn,
const char *username = 0, const char *password = 0) = 0;
/** Set the cellular network APN and credentials
*
* @param apn Name of the network to connect to
* @param type Authentication type to use
* @param username Optional username for the APN
* @param password Optional password fot the APN
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t set_credentials(const char *apn, AuthenticationType type,
const char *username = 0, const char *password = 0) = 0;
/** Request attach to network.
*
* @param timeout milliseconds to wait for attach response
* @return zero on success
*/
virtual nsapi_error_t set_attach(int timeout = 10*1000) = 0;
/** Request attach status from network.
*
* @param status see AttachStatus values
* @return zero on success
*/
virtual nsapi_error_t get_attach(AttachStatus &status) = 0;
/** Get APN rate control.
*
* @remark optional params are not updated if not received from network, so use good defaults
* @param reports Additional exception reports at maximum rate reached are allowed to be sent [optional]
* @param time_unit Uplink time unit with values 0=unrestricted, 1=minute, 2=hour, 3=day, 4=week [optional]
* @param uplink_rate Maximum number of messages per timeUnit [optional]
* @return zero on success
*/
virtual nsapi_error_t get_rate_control(CellularNetwork::RateControlExceptionReports &reports,
CellularNetwork::RateControlUplinkTimeUnit &time_unit, int &uplink_rate) = 0;
/** Get backoff timer value
*
* @param backoff_time Backoff timer value associated with PDP APN in seconds
* @return zero on success
*/
virtual nsapi_error_t get_backoff_time(int &backoff_time) = 0;
/** Sets radio access technology.
*
* @param op_rat Radio access technology
* @return zero on success
*/
virtual nsapi_error_t set_access_technology(operator_t::RadioAccessTechnology op_rat) = 0;
/** Scans for operators module can reach.
*
* @param operators Container of reachable operators and their access technologies
* @param ops_count Number of found operators
* @return zero on success
*/
virtual nsapi_error_t scan_plmn(operList_t &operators, int &ops_count) = 0;
/** Set CIoT optimizations.
*
* @param supported_opt Supported CIoT EPS optimizations.
* @param preferred_opt Preferred CIoT EPS optimizations.
* @return zero on success
*/
virtual nsapi_error_t set_ciot_optimization_config(Supported_UE_Opt supported_opt,
Preferred_UE_Opt preferred_opt) = 0;
/** Get CIoT optimizations.
*
* @param supported_opt Supported CIoT EPS optimizations.
* @param preferred_opt Preferred CIoT EPS optimizations.
* @return zero on success
*/
virtual nsapi_error_t get_ciot_optimization_config(Supported_UE_Opt& supported_opt,
Preferred_UE_Opt& preferred_opt) = 0;
/** Start the interface. Attempts to connect to a cellular network.
*
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t connect() = 0;
/** Start the interface. Attempts to connect to a cellular network.
*
* @param apn Optional name of the network to connect to
* @param username Optional username for your APN
* @param password Optional password for your APN
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t connect(const char *apn,
const char *username = 0, const char *password = 0) = 0;
/**
* Set the pdn type to be used
*
* @param stack_type the stack type to be used.
*
* @return NSAPI_ERROR_OK on success
*/
virtual nsapi_error_t set_stack_type(nsapi_ip_stack_t stack_type) = 0;
/**
* Get the pdn type in use
*
* @return stack type
*/
virtual nsapi_ip_stack_t get_stack_type() = 0;
/** Get the relevant information for an active non secondary PDP context.
*
* @remark optional params are not updated if not received from network.
* @param params_list reference to linked list which is filled on successful call
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t get_pdpcontext_params(pdpContextList_t& params_list) = 0;
/** Get extended signal quality parameters.
*
* @param rxlev signal strength level
* @param ber bit error rate
* @param rscp signal code power
* @param ecno ratio of the received energy per PN chip to the total received power spectral density
* @param rsrq signal received quality
* @param rsrp signal received power
* @return NSAPI_ERROR_OK on success, negative error code on failure
*/
virtual nsapi_error_t get_extended_signal_quality(int &rxlev, int &ber, int &rscp, int &ecno, int &rsrq, int &rsrp) = 0;
/** Get signal quality parameters.
*
* @param rssi signal strength level
* @param ber bit error rate
* @return NSAPI_ERROR_OK on success, negative error code on failure
*/
virtual nsapi_error_t get_signal_quality(int &rssi, int &ber) = 0;
/** Get cell id.
*
* @param cell_id cell id
* @return NSAPI_ERROR_OK on success, negative error code on failure
*/
virtual nsapi_error_t get_cell_id(int &cell_id) = 0;
/** Get the last 3GPP error code
* @return see 3GPP TS 27.007 error codes
*/
virtual uint8_t get_3gpp_error() = 0;
/** Get the operator params
*
* @param format format of the operator field
* @param operator_params applicable operator param fields filled
* @return NSAPI_ERROR_OK on success, negative error code on failure
*/
virtual nsapi_error_t get_operator_params(int &format, operator_t &operator_params) = 0;
};
} // namespace mbed
#endif // CELLULAR_NETWORK_H_

View File

@ -0,0 +1,130 @@
/*
* 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_API_CELLULARPOWER_H_
#define CELLULAR_API_CELLULARPOWER_H_
#include "nsapi_types.h"
namespace mbed {
/**
* Class CellularPower
*
* An abstract interface for connecting to a network and getting information from it.
*/
class CellularPower
{
protected:
// friend of CellularDevice so that it's the only way to close/delete this class.
friend class CellularDevice;
/**
* virtual Destructor
*/
virtual ~CellularPower() {}
public:
/* Access technology used in method opt_receive_period */
enum EDRXAccessTechnology {
EDRXGSM_EC_GSM_IoT_mode = 1,
EDRXGSM_A_Gb_mode,
EDRXUTRAN_Iu_mode,
EDRXEUTRAN_WB_S1_mode,
EDRXEUTRAN_NB_S1_mode
};
/** Set cellular device power on. Default implementation is empty.
* Device power on/off is modem/board specific behavior and must be done on inherited class if needed.
* Power on is done by toggling power pin/button.
*
* @remark set_at_mode must be called to initialise modem
*
* @remark Should not be called if MUX is enabled and started. If called then start-up sequence must be done again.
* @return zero on success
*/
virtual nsapi_error_t on() = 0;
/** Set cellular device power off. Default implementation is empty.
* Device power on/off is modem/board specific behavior and must be done on inherited class if needed.
* Power off is done by toggling power pin/button.
*
* @remark Should not be called if MUX is enabled and started. If called then start-up sequence must be done again.
*
* @return zero on success
*/
virtual nsapi_error_t off() = 0;
/** Set AT command mode. Blocking until success or failure.
*
* @remark must be called after power on to prepare correct AT mode
*
* @return zero on success
*/
virtual nsapi_error_t set_at_mode() = 0;
/** Set cellular device power level by enabling/disabling functionality.
*
* @param func_level:
* 0 minimum functionality
* 1 full functionality. Enable (turn on) the transmit and receive RF circuits for all supported radio access technologies.
* For MTs supporting +CSRA, this equals the RATs indicated by the response of +CSRA=?. Current +CSRA setting is ignored.
* It is not required that the MT transmit and receive RF circuits are in a disabled state for this setting to have effect.
* 2 disable (turn off) MT transmit RF circuits only
* 3 disable (turn off) MT receive RF circuits only
* 4 disable (turn off) both MT transmit and receive RF circuits
*
* @remark See 3GPP TS 27.007 CFUN for more details
* @remark Should not be called if MUX is enabled and started. If called then start-up sequence must be done again.
*
* @return zero on success
*/
virtual nsapi_error_t set_power_level(int func_level) = 0;
/** Reset and wake-up cellular device.
*
* @remark Should not be called if MUX is enabled and started. If called then start-up sequence must be done again.
*
* @return zero on success
*/
virtual nsapi_error_t reset() = 0;
/** Opt for power save setting on cellular device. If both parameters are zero then disables PSM.
*
* @remark See 3GPP TS 27.007 PSM for details
*
* @param periodic_time Timeout in seconds IoT subsystem is not expecting messaging
* @param active_time Timeout in seconds IoT subsystem waits for response
* @return zero on success
*/
virtual nsapi_error_t opt_power_save_mode(int periodic_time, int active_time) = 0;
/** Opt for discontinuous reception on cellular device.
*
* @remark See 3GPP TS 27.007 eDRX for details.
*
* @param mode disable or enable the use of eDRX
* @param act_type type of access technology
* @param edrx_value requested edxr value. Extended DRX parameters information element.
*
* @return zero on success
*/
virtual nsapi_error_t opt_receive_period(int mode, EDRXAccessTechnology act_type, uint8_t edrx_value) = 0;
};
} // namespace mbed
#endif /* CELLULAR_API_CELLULARPOWER_H_ */

View File

@ -0,0 +1,85 @@
/*
* 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_SIM_H_
#define CELLULAR_SIM_H_
#include "nsapi_types.h"
namespace mbed {
const int MAX_SIM_READY_WAITING_TIME = 30;
/**
* Class CellularSIM
*
* An abstract interface for SIM card handling.
*/
class CellularSIM
{
protected:
// friend of CellularDevice so that it's the only way to close/delete this class.
friend class CellularDevice;
/**
* virtual Destructor
*/
virtual ~CellularSIM() {};
public:
/* enumeration for possible SIM states */
enum SimState {
SimStateReady = 0,
SimStatePinNeeded,
SimStatePukNeeded,
SimStateUnknown
};
/** Open the SIM card by setting the pin code for SIM.
*
* @param sim_pin PIN for the SIM card
* @return zero on success
*/
virtual nsapi_error_t set_pin(const char *sim_pin) = 0;
/**Change sim pin code.
*
* @param sim_pin Current PIN for sim
* @param new_pin New PIN for sim
* @return zero on success
*/
virtual nsapi_error_t change_pin(const char *sim_pin, const char *new_pin) = 0;
/** Change is pin query needed after boot
*
* @param sim_pin Valid PIN for SIM card
* @param query_pin False is PIN query not needed, True if PIN query needed after boot.
* @return zero on success
*/
virtual nsapi_error_t set_pin_query(const char *sim_pin, bool query_pin) = 0;
/** Get sim card's state
*
* @param state current state of SIM
* @return zero on success
*/
virtual nsapi_error_t get_sim_state(SimState &state) = 0;
};
} // namespace mbed
#endif // CELLULAR_SIM_H_

View File

@ -0,0 +1,155 @@
/*
* 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_SMS_H_
#define CELLULAR_SMS_H_
#include "Callback.h"
#include "nsapi_types.h"
namespace mbed {
// including trailing '\0'
const uint16_t SMS_MAX_SIZE_WITH_CONCATENATION = 4096 + 1;
const uint16_t SMS_MAX_PHONE_NUMBER_SIZE = 20 + 1;
const uint16_t SMS_MAX_TIME_STAMP_SIZE = 20 + 1;
const uint16_t SMS_MAX_SIZE_8BIT_SINGLE_SMS_SIZE = 140;
const uint16_t SMS_MAX_SIZE_GSM7_SINGLE_SMS_SIZE = 160;
const uint16_t SMS_SIM_WAIT_TIME_MILLISECONDS = 200;
const int SMS_ERROR_MULTIPART_ALL_PARTS_NOT_READ = -5001;
/**
* Class CellularSMS
*
* An abstract interface for SMS sending and reading.
*/
class CellularSMS
{
protected:
// friend of CellularDevice so that it's the only way to close/delete this class.
friend class CellularDevice;
/**
* virtual Destructor
*/
virtual ~CellularSMS() {};
public:
/* Enumeration for possible SMS modes, PDU and Text */
enum CellularSMSMmode {
CellularSMSMmodePDU = 0,
CellularSMSMmodeText
};
/** Does all the necessary initializations needed for receiving and sending sms.
*
* @param mode enumeration for choosing the correct mode: text/pdu
* @return zero on success
*/
virtual nsapi_error_t initialize(CellularSMSMmode mode) = 0;
/** Send the SMS with the given parameters
*
* @param phone_number Phone number where to send sms
* @param message SMS message content
* @param msg_len Length of the message
* @return possible error code or length of the sent sms
*/
virtual nsapi_size_or_error_t send_sms(const char* phone_number, const char* message, int msg_len) = 0;
/** Gets the oldest received sms.
*
* @param buf preallocated buffer for sms message content
* @param buf_len length of allocated buf
* @param phone_num preallocated buffer for phone number where sms was sent
* @param phone_len length of allocated phone_num buffer
* @param time_stamp preallocated buffer for TP-Service Centre Time Stamp (format: yy/MM/dd,hh:mm:ss-+zz). +-zz is timezone.
* The unit of time zone is a quarter of an hour relative to GMT. For example +32 would be GMT+8.
* @param time_len length of allocated time_stamp buffer
* @param buf_size if method return error NSAPI_ERROR_NO_MEMORY because the given buf was not big enough this will
* hold the size which is enough. Otherwise zero.
* @return possible error code or size of buf. Will return SMS_ERROR_MULTIPART_ALL_PARTS_NOT_READ
* if sms was multipart but not all parts are present/failed to read.
*/
virtual nsapi_size_or_error_t get_sms(char* buf, uint16_t buf_len, char* phone_num, uint16_t phone_len,
char* time_stamp, uint16_t time_len, int *buf_size) = 0;
/** Callback which is called when new sms is received. SMS can be fetched via method get_sms().
*
* @remark In PDU mode there can be multipart sms and callback is called for every received part.
*
* @param func Callback function which is called when new sms is received.
*/
virtual void set_sms_callback(Callback<void()> func) = 0;
/** CPMS preferred message storage
*
* @param memr memory from which messages are read and deleted
* "SM" - SIM SMS memory storage (default)
* "ME" - NVM SMS storage
* @param memw memory to which writing and sending operations are made
* "SM" - SIM SMS memory storage (default)
* "ME" - NVM SMS storage
* @param mems memory to which received SMs are preferred to be stored
* "SM" - SIM SMS memory storage (default)
* "ME" - NVM SMS storage
*
* @return 1 for success, 0 for failure
*/
virtual nsapi_error_t set_cpms(const char *memr, const char *memw, const char *mems) = 0;
/** CSCA - set Service Center Address
*
* @param sca Service Center Address to be used for mobile originated SMS transmissions.
* @param type 129 - national numbering scheme, 145 - international numbering scheme (contains the character "+")
*
* @return 1 for success, 0 for failure
*/
virtual nsapi_error_t set_csca(const char *sca, int type) = 0;
/** Set command sets the current character set used by the device. "GSM", "IRA",....
*
* @remark Current implementation support only ASCII so choose the correct character set.
*
* @param chr_set preferred character set list (comma separated). Modem might not support the wanted character set
* so chr_set list is looped from start until supported set is found. Used character set index is returned.
* See more from 3GPP TS 27.005.
* @return Used character set index from the given list in case of success. Otherwise negative errorcode.
*/
virtual nsapi_size_or_error_t set_cscs(const char *chr_set) = 0;
/** Deletes all messages from the currently set memory/SIM
*
* @return possible error code
*/
virtual nsapi_error_t delete_all_messages() = 0;
/** Some modems need extra time between AT commands and responses or there will be error -314, SIM busy.
* If SIM busy errors are an issue this time should be increased. It can also be set to zero to make
* operations faster and more energy efficient if no errors will follow. By default wait time is zero.
*
* @param sim_wait_time
*/
virtual void set_extra_sim_wait_time(int sim_wait_time) = 0;
};
} // namespace mbed
#endif // CELLULAR_SMS_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,471 @@
/*
* 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 AT_HANDLER_H_
#define AT_HANDLER_H_
#include "platform/mbed_retarget.h"
#include "stdio.h"
#include "EventQueue.h"
#include "PlatformMutex.h"
#include "nsapi_types.h"
#include "PlatformMutex.h"
#include "Callback.h"
#include "EventQueue.h"
namespace mbed {
class FileHandle;
/**
* If application calls associated FileHandle only from single thread context
* then locking between AT command and response is not needed. However,
* note that many cellular functions are called indirectly e.g. via socket API.
* If you are unsure then AT_HANDLER_MUTEX must be defined.
*/
#define AT_HANDLER_MUTEX
extern const char *OK;
extern const char *CRLF;
#define BUFF_SIZE 16
/* AT Error types enumeration */
enum DeviceErrorType {
DeviceErrorTypeNoError = 0,
DeviceErrorTypeError, // AT ERROR
DeviceErrorTypeErrorCMS, // AT ERROR CMS
DeviceErrorTypeErrorCME // AT ERROR CME
};
/* struct used when getting at response error. Defines error code and type */
struct device_err_t {
DeviceErrorType errType;
int errCode;
};
/** Class ATHandler
*
* Class for sending AT commands and parsing AT responses.
*/
class ATHandler
{
public:
/** Constructor
*
* @param fh file handle used for reading AT responses and writing AT commands
* @param queue Event queue used to transfer sigio events to this thread
* @param timeout Timeout when reading for AT response
* @param output_delimiter Default delimiter used when parsing at responses
*/
ATHandler(FileHandle *fh, events::EventQueue &queue, int timeout, const char *output_delimiter = "\r");
~ATHandler();
/** Return used file handle.
*
* @return used file handle
*/
FileHandle *get_file_handle();
/** Set file handle which is used for reading AT responses and writing AT commands
*
* @param fh file handle used for reading AT responses and writing AT commands
*/
void set_file_handle(FileHandle *fh);
/** Locks the mutex for file handle if AT_HANDLER_MUTEX is defined.
*/
void lock();
/** Unlocks the mutex for file handle if AT_HANDLER_MUTEX is defined.
*/
void unlock();
/** Locks the mutex for file handle if AT_HANDLER_MUTEX is defined and returns the last error.
*
* @return last error which happened when parsing AT responses
*/
nsapi_error_t unlock_return_error();
/** Set the urc callback for urc. If urc is found when parsing AT responses then call if called.
*
* @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);
ATHandler *_nextATHandler; // linked list
/** returns the last error while parsing AT responses.
*
* @return last error
*/
nsapi_error_t get_last_error() const;
/** returns the last device error while parsing AT responses. Actually AT error (CME/CMS).
*
* @return last error struct device_err_t
*/
device_err_t get_last_device_error() const;
/** Increase reference count. Used for counting references to this instance.
*/
void inc_ref_count();
/** Decrease reference count. Used for counting references to this instance.
*/
void dec_ref_count();
/** Get the current reference count. Used for counting references to this instance.
*
* @return current reference count
*/
int get_ref_count();
/** Set timeout in milliseconds for AT commands
*
* @param timeout_milliseconds Timeout in milliseconds
* @param default_timeout Store as default timeout
*/
void set_at_timeout(uint32_t timeout_milliseconds, bool default_timeout = false);
/** Restore timeout to previous timeout. Handy if there is a need to change timeout temporarily.
*/
void restore_at_timeout();
/** Clear pending error flag. By default error is cleared only in lock().
*/
void clear_error();
/** Tries to find oob's from the AT response. Call the urc callback if one is found.
*/
void process_oob();
/** Set sigio for the current file handle. Sigio event goes through eventqueue so that it's handled in current thread.
*/
void set_filehandle_sigio();
/**
* Flushes the underlying stream
*/
void flush();
protected:
void event();
#ifdef AT_HANDLER_MUTEX
PlatformMutex _fileHandleMutex;
#endif
FileHandle *_fileHandle;
private:
void set_error(nsapi_error_t err);
void set_oobs_matching_param(bool);
events::EventQueue &_queue;
nsapi_error_t _last_err;
nsapi_error_t _last_3gpp_error;
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;
mbed::Callback<void()> cb;
oob_t *next;
};
oob_t *_oobs;
bool _response_terminated;
uint32_t _at_timeout;
uint32_t _previous_at_timeout;
bool _fh_sigio_set;
bool _processing;
int32_t _ref_count;
//*************************************
public:
/** Starts the command writing by clearing the last error and writing the given command.
* In case of failure when writing the last error is set to NSAPI_ERROR_DEVICE_ERROR.
*
* @param cmd AT command to be written to modem
*/
void cmd_start(const char* cmd);
/** Writes integer type AT command subparameter. Starts with the delimiter if not the first param after cmd_start.
* In case of failure when writing the last error is set to NSAPI_ERROR_DEVICE_ERROR.
*
* @param param int to be written to modem as AT command subparameter
*/
void write_int(int32_t param);
/** Writes string type AT command subparamater. Quotes are added to surround the given string.
* Starts with the delimiter if not the first param after cmd_start.
* In case of failure when writing the last error is set to NSAPI_ERROR_DEVICE_ERROR.
*
* @param param string to be written to modem as AT command subparameter
* @param useQuotations flag indicating if the string should be or not included in quotation marks
*/
void write_string(const char* param, bool useQuotations = true);
/** Stops the AT command by writing command line terminator CR to mark command as finished.
*/
void cmd_stop();
/** Write bytes without any subparameter delimiters, such as comma.
* In case of failure when writing the last error is set to NSAPI_ERROR_DEVICE_ERROR.
*
* @param data bytes to be written to modem
* @param len length of data string
*
* @return number of characters successfully written
*/
size_t write_bytes(uint8_t *data, size_t len);
/** Sets the stop tag for the current scope(response/information response/element)
* Parameter's reading routines will stop the reading when such tag is found and will set the found flag.
* Consume routines will read everything until such tag is found.
*
* @param stop_tag_seq string to be set as stop tag
*/
void set_stop_tag(const char *stop_tag_seq);
/** Sets the delimiter between parameters or between elements of the information response.
* Parameter's reading routines will stop when such char is read.
*
* @param delimiter char to be set as _delimiter
*/
void set_delimiter(char delimiter);
/** Consumes the reading buffer up to the delimiter or stop_tag
*
* @param count number of parameters to be skipped
*/
void skip_param(uint32_t count = 1);
/** Consumes the given length from the reading buffer
*
* @param len length to be consumed from reading buffer
* @param count number of parameters to be skipped
*/
void skip_param(ssize_t len, uint32_t count);
/** Reads given number of bytes from receiving buffer without checking any subparameter delimiters, such as comma.
*
* @param buf output buffer for the read
* @param len maximum number of bytes to read
* @return number of successfully read bytes or -1 in case of error
*/
ssize_t read_bytes(uint8_t *buf, size_t len);
/** Reads chars from reading buffer. Terminates with null. Skips the quotation marks.
* Stops on delimiter or stop tag.
*
* @param str output buffer for the read
* @param size maximum number of chars to output
* @param read_even_stop_tag if true then try to read even the stop tag was found previously
* @return length of output string or -1 in case of read timeout before delimiter or stop tag is found
*/
ssize_t read_string(char *str, size_t size, bool read_even_stop_tag = false);
/** Reads as string and converts result to integer. Supports only positive integers.
*
* @return the positive integer or -1 in case of error.
*/
int32_t read_int();
/** This looks for necessary matches: prefix, OK, ERROR, URCs and sets the correct scope.
*
* @param prefix string to be matched from receiving buffer. If not NULL and match succeeds, then scope
* will be set as information response(info_type)
* @param stop flag to indicate if we go to information response scope or not.
* (needed when nothing is expected to be received anymore after the prefix match:
* sms case: "> ", bc95 reboot case)
*/
void resp_start(const char *prefix = NULL, bool stop = false);
/** Ends all scopes starting from current scope.
* Consumes everything until the scope's stop tag is found, then
* goes to next scope, until response scope is ending.
* Possible sequence:
* element scope -> information response scope -> response scope
*/
void resp_stop();
/** Looks for matching the prefix given to resp_start() call.
* If needed it ends the scope of a previous information response.
* Sets the information response scope if new prefix is found and response scope if prefix is not found.
*
* @return true if new information response is found, false otherwise
*/
bool info_resp();
/** Looks for matching the start tag.
* If needed it ends the scope of a previous element.
* Sets the element scope if start tag is found and information response scope if start tag is not found.
*
* @param start_tag tag to be matched to begin parsing an element of an information response
* @return true if new element is found, false otherwise
*/
bool info_elem(char start_tag);
/** Consumes the received content until current stop tag is found.
*
* @return true if stop tag is found, false otherwise
*/
bool consume_to_stop_tag();
/** Sets _debug_on flag.
*
* @param enable value to be set for _debug_on flag
*/
void enable_debug(bool enable);
/** Return the last 3GPP error code.
* @return last 3GPP error code
*/
uint8_t get_3gpp_error();
private:
// should fit any prefix and int
char _recv_buff[BUFF_SIZE];
// reading position
size_t _recv_len;
// reading length
size_t _recv_pos;
// resp_type: the part of the response that doesn't include the information response(+CMD1,+CMD2..)
// ends with OK or (CME)(CMS)ERROR
// info_type: the information response part of the response: starts with +CMD1 and ends with CRLF
// information response contains parameters or subsets of parameters(elements), both separated by comma
// elem_type: subsets of parameters that are part of information response, its parameters are separated by comma
enum ScopeType {RespType, InfoType, ElemType, NotSet};
void set_scope(ScopeType scope_type, const char* stop_tag = NULL);
ScopeType _current_scope;
struct tag_t {
char tag[7];
size_t len;
bool found;
};
// tag to stop response scope
tag_t _resp_stop;
// tag to stop information response scope
tag_t _info_stop;
// tag to stop element scope
tag_t _elem_stop;
// reference to the stop tag of current scope(resp/info/elem)
tag_t *_stop_tag;
// delimiter between parameters and also used for delimiting elements of information response
char _delimiter;
// set true on prefix match -> indicates start of an information response or of an element
bool _prefix_matched;
// set true on urc match
bool _urc_matched;
// set true on (CME)(CMS)ERROR
bool _error_found;
// Max length of OK,(CME)(CMS)ERROR and URCs
size_t _max_resp_length;
// prefix set during resp_start and used to try matching possible information responses
char _info_resp_prefix[BUFF_SIZE];
bool _debug_on;
bool _cmd_start;
// Gets char from receiving buffer.
// Resets and fills the buffer if all are already read (receiving position equals receiving length).
int16_t get_char();
// Sets to 0 the reading position, reading length and the whole buffer content.
void reset_buffer();
// Reading position set to 0 and buffer's unread content moved to beginning
void rewind_buffer();
// Reads from serial to receiving buffer.
// Returns on first successful read OR on timeout.
void fill_buffer();
void set_tag(tag_t* tag_dest, const char *tag_seq);
// Rewinds the receiving buffer and compares it against given str.
bool match(const char* str, size_t size);
// Iterates URCs and check if they match the receiving buffer content.
// If URC match sets the scope to information response and after urc's cb returns
// finishes the information response scope(consumes to CRLF).
bool match_urc();
// Checks if any of the error strings are matching the receiving buffer content.
bool match_error();
// Checks is current char in buffer matches ch and consumes it,
// if no match lets the buffer unchanged.
bool consume_char(char ch);
// Consumes the received content until tag is found.
// Consumes the tag only if consume_tag flag is true.
bool consume_to_tag(const char *tag, bool consume_tag);
// Checks if receiving buffer contains OK, ERROR, URC or given prefix.
void resp(const char *prefix, bool check_urc);
ScopeType get_scope();
// Consumes to information response stop tag which is CRLF. Sets scope to response.
void information_response_stop();
// Consumes to element stop tag. Sets scope to information response
void information_response_element_stop();
// Reads the error code if expected and sets it as last error.
void at_error(bool error_code, DeviceErrorType error_type);
/** Convert AT error code to 3GPP error codes
* @param err AT error code read from CME/CMS ERROR responses
* @param error_type error type (CMS/CME/ERROR)
*/
void set_3gpp_error(uint8_t err, DeviceErrorType error_type);
bool check_cmd_send();
bool write_char(char c);
/** Copy content of one char buffer to another buffer and sets NULL terminator
*
* @param dest destination char buffer
* @param src source char buffer
* @param src_len number of bytes to copy
*
*/
void set_string(char *dest, const char *src, size_t src_len);
/** Finds occurence of one char buffer inside another char buffer.
*
* @param dest destination char buffer
* @param dest_len length of dest
* @param src string to be searched for
* @param src_len length of string to be searched for
*
* @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);
};
} // namespace mbed
#endif //AT_HANDLER_H_

View File

@ -0,0 +1,36 @@
/*
* 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 "AT_CellularBase.h"
using namespace mbed;
AT_CellularBase::AT_CellularBase(ATHandler& at) : _at(at)
{
}
ATHandler& AT_CellularBase::get_at_handler()
{
return _at;
}
device_err_t AT_CellularBase::get_device_error() const
{
return _at.get_last_device_error();
}

View File

@ -0,0 +1,53 @@
/*
* 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 AT_CELLULAR_BASE_H_
#define AT_CELLULAR_BASE_H_
#include "ATHandler.h"
namespace mbed {
/**
* Class AT_CellularBase
*
* A base class for AT-classes.
*/
class AT_CellularBase
{
public:
AT_CellularBase(ATHandler& at);
/** Getter for at handler. Common method for all AT-classes.
*
* @return reference to ATHandler
*/
ATHandler& get_at_handler();
/** Gets the device error which happened when using AT commands/responses. This is at error
* returned by the device. Returned CME/CMS errors can be found from 3gpp documents 27007 and 27005.
*
* @return at error (CME/CMS) while communication with the device
*/
device_err_t get_device_error() const;
protected:
ATHandler& _at;
};
} // namespace mbed
#endif /* AT_CELLULAR_BASE_H_ */

View File

@ -0,0 +1,248 @@
/*
* 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 "AT_CellularDevice.h"
using namespace events;
using namespace mbed;
#define DEFAULT_AT_TIMEOUT 1000 // at default timeout in milliseconds
AT_CellularDevice::AT_CellularDevice(EventQueue &queue) :
_atHandlers(0), _network(0), _sms(0), _sim(0), _power(0), _multiplexer(0), _information(0), _queue(queue), _default_timeout(DEFAULT_AT_TIMEOUT)
{
}
AT_CellularDevice::~AT_CellularDevice()
{
close_network();
close_sms();
close_power();
close_sim();
close_multiplexer();
close_information();
ATHandler *atHandler = _atHandlers;
while (atHandler) {
ATHandler *old = atHandler;
atHandler = atHandler->_nextATHandler;
delete old;
old = NULL;
}
}
// each parser is associated with one filehandle (that is UART or a MUX channel)
ATHandler* AT_CellularDevice::get_at_handler(FileHandle *fileHandle)
{
if (!fileHandle) {
return NULL;
}
ATHandler *atHandler = _atHandlers;
while (atHandler) {
if (atHandler->get_file_handle() == fileHandle) {
atHandler->inc_ref_count();
return atHandler;
}
atHandler = atHandler->_nextATHandler;
}
atHandler = new ATHandler(fileHandle, _queue, _default_timeout);
if (atHandler) {
atHandler->_nextATHandler = _atHandlers;
_atHandlers = atHandler;
}
return atHandler;
}
void AT_CellularDevice::release_at_handler(ATHandler* at_handler)
{
if (!at_handler) {
return;
}
at_handler->dec_ref_count();
if (at_handler->get_ref_count() == 0) {
// we can delete this at_handler
ATHandler *atHandler = _atHandlers;
ATHandler *prev = NULL;
while (atHandler) {
if (atHandler == at_handler) {
if (prev == NULL) {
_atHandlers = _atHandlers->_nextATHandler;
}
else {
prev->_nextATHandler = atHandler->_nextATHandler;
}
delete atHandler;
atHandler = NULL;
break;
} else {
prev = atHandler;
atHandler =atHandler->_nextATHandler;
}
}
}
}
CellularNetwork *AT_CellularDevice::open_network(FileHandle *fh)
{
if (!_network) {
ATHandler *atHandler = get_at_handler(fh);
if (atHandler) {
_network = new AT_CellularNetwork(*atHandler);
if (!_network) {
release_at_handler(atHandler);
}
}
}
return _network;
}
CellularSMS *AT_CellularDevice::open_sms(FileHandle *fh)
{
if (!_sms) {
ATHandler *atHandler = get_at_handler(fh);
if (atHandler) {
_sms = new AT_CellularSMS(*atHandler);
if (!_sms) {
release_at_handler(atHandler);
}
}
}
return _sms;
}
CellularSIM *AT_CellularDevice::open_sim(FileHandle *fh)
{
if (!_sim) {
ATHandler *atHandler = get_at_handler(fh);
if (atHandler) {
_sim = new AT_CellularSIM(*atHandler);
if (!_sim) {
release_at_handler(atHandler);
}
}
}
return _sim;
}
CellularPower *AT_CellularDevice::open_power(FileHandle *fh)
{
if (!_power) {
ATHandler *atHandler = get_at_handler(fh);
if (atHandler) {
_power = new AT_CellularPower(*atHandler);
if (!_power) {
release_at_handler(atHandler);
}
}
}
return _power;
}
CellularMultiplexer *AT_CellularDevice::open_multiplexer(FileHandle *fh)
{
if (!_multiplexer) {
ATHandler *atHandler = get_at_handler(fh);
if (atHandler) {
_multiplexer = new AT_CellularMultiplexer(*atHandler);
if (!_multiplexer) {
release_at_handler(atHandler);
}
}
}
return _multiplexer;
}
CellularInformation *AT_CellularDevice::open_information(FileHandle *fh)
{
if (!_information) {
ATHandler *atHandler = get_at_handler(fh);
if (atHandler) {
_information = new AT_CellularInformation(*atHandler);
if (!_information) {
release_at_handler(atHandler);
}
}
}
return _information;
}
void AT_CellularDevice::close_network()
{
if (_network) {
release_at_handler(&_network->get_at_handler());
delete _network;
_network = NULL;
}
}
void AT_CellularDevice::close_sms()
{
if (_sms) {
release_at_handler(&_sms->get_at_handler());
delete _sms;
_sms = NULL;
}
}
void AT_CellularDevice::close_power()
{
if (_power) {
release_at_handler(&_power->get_at_handler());
delete _power;
_power = NULL;
}
}
void AT_CellularDevice::close_sim()
{
if (_sim) {
release_at_handler(&_sim->get_at_handler());
delete _sim;
_sim = NULL;
}
}
void AT_CellularDevice::close_multiplexer()
{
if (_multiplexer) {
release_at_handler(&_multiplexer->get_at_handler());
delete _multiplexer;
_multiplexer = NULL;
}
}
void AT_CellularDevice::close_information()
{
if (_information) {
release_at_handler(&_information->get_at_handler());
delete _information;
_information = NULL;
}
}
void AT_CellularDevice::set_timeout(int timeout)
{
_default_timeout = timeout;
ATHandler *atHandler = _atHandlers;
while (atHandler) {
atHandler->set_at_timeout(_default_timeout, true); // set as default timeout
atHandler = atHandler->_nextATHandler;
}
}

View File

@ -0,0 +1,144 @@
/*
* 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 AT_CELLULAR_DEVICE_H_
#define AT_CELLULAR_DEVICE_H_
#include "CellularDevice.h"
#include "AT_CellularNetwork.h"
#include "AT_CellularSIM.h"
#include "AT_CellularSMS.h"
#include "AT_CellularPower.h"
#include "AT_CellularMultiplexer.h"
#include "AT_CellularInformation.h"
#include "ATHandler.h"
namespace mbed {
class AT_CellularDevice : public CellularDevice
{
public:
AT_CellularDevice(events::EventQueue &queue);
virtual ~AT_CellularDevice();
protected:
ATHandler *_atHandlers;
/** Get the athandler. If the given fh is already used with existing athandler, instance to that athander is returned.
* Otherwise new athander is created.
*
* @param fh FileHandle to be used with the ATHandler
* @return pointer to ATHandler
*/
ATHandler *get_at_handler(FileHandle *fh);
/** Releases the given at_handler. If last reference to at_hander then it's deleted.
*
* @param at_handler
*/
void release_at_handler(ATHandler* at_handler);
public: // CellularDevice
/** Create new CellularNetwork interface.
*
* @param fh filehandle used in communication to modem. Can be for example UART handle.
* @return New instance of interface CellularNetwork.
*/
virtual CellularNetwork *open_network(FileHandle *fh);
/** Create new CellularSMS interface.
*
* @param fh filehandle used in communication to modem. Can be for example UART handle.
* @return New instance of interface CellularSMS.
*/
virtual CellularSMS *open_sms(FileHandle *fh);
/** Create new CellularPower interface.
*
* @param fh filehandle used in communication to modem. Can be for example UART handle.
* @return New instance of interface CellularPower.
*/
virtual CellularPower *open_power(FileHandle *fh);
/** Create new CellularSIM interface.
*
* @param fh filehandle used in communication to modem. Can be for example UART handle.
* @return New instance of interface CellularSIM.
*/
virtual CellularSIM *open_sim(FileHandle *fh);
/** Create new CellularMultiplexer interface.
*
* @param fh filehandle used in communication to modem. Can be for example UART handle.
* @return New instance of interface CellularMultiplexer.
*/
virtual CellularMultiplexer *open_multiplexer(FileHandle *fh);
/** Create new CellularInformation interface.
*
* @param fh filehandle used in communication to modem. Can be for example UART handle.
* @return New instance of interface CellularInformation.
*/
virtual CellularInformation *open_information(FileHandle *fh);
/** Closes the opened CellularNetwork by deleting the CellularNetwork instance.
*/
virtual void close_network();
/** Closes the opened CellularNetwork by deleting the CellularSMS instance.
*/
virtual void close_sms();
/** Closes the opened CellularNetwork by deleting the CellularPower instance.
*/
virtual void close_power();
/** Closes the opened CellularNetwork by deleting the CellularSIM instance.
*/
virtual void close_sim();
/** Closes the opened CellularNetwork by deleting the CellularMultiplexer instance.
*/
virtual void close_multiplexer();
/** Closes the opened CellularNetwork by deleting the CellularInformation instance.
*/
virtual void close_information();
/** Set the default response timeout.
*
* @param timeout milliseconds to wait response from modem
*/
virtual void set_timeout(int timeout);
protected:
AT_CellularNetwork *_network;
AT_CellularSMS *_sms;
AT_CellularSIM *_sim;
AT_CellularPower* _power;
AT_CellularMultiplexer* _multiplexer;
AT_CellularInformation* _information;
protected:
events::EventQueue &_queue;
int _default_timeout;
};
} // namespace mbed
#endif // AT_CELLULAR_DEVICE_H_

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "AT_CellularInformation.h"
using namespace mbed;
AT_CellularInformation::AT_CellularInformation(ATHandler &at) : AT_CellularBase(at)
{
}
AT_CellularInformation::~AT_CellularInformation()
{
}
nsapi_error_t AT_CellularInformation::get_manufacturer(char *buf, size_t buf_size)
{
return get_info("AT+CGMI", buf, buf_size);
}
nsapi_error_t AT_CellularInformation::get_model(char *buf, size_t buf_size)
{
return get_info("AT+CGMM", buf, buf_size);
}
nsapi_error_t AT_CellularInformation::get_revision(char *buf, size_t buf_size)
{
return get_info("AT+CGMR", buf, buf_size);
}
nsapi_error_t AT_CellularInformation::get_info(const char *cmd, char *buf, size_t buf_size)
{
_at.lock();
_at.cmd_start(cmd);
_at.cmd_stop();
_at.resp_start();
_at.read_string(buf, buf_size-1); // stop tag OK\r\n
_at.resp_stop();
return _at.unlock_return_error();
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2018, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef AT_CELLULAR_INFORMATION_H_
#define AT_CELLULAR_INFORMATION_H_
#include "CellularInformation.h"
#include "AT_CellularBase.h"
namespace mbed {
class AT_CellularInformation : public CellularInformation, public AT_CellularBase
{
public:
AT_CellularInformation(ATHandler &atHandler);
virtual ~AT_CellularInformation();
public:
/** Request manufacturer identification of cellular device
*
* @param buf manufacturer identification
* @param buf_size max length of manufacturer identification is 2048 characters
* @return on success read character count, on failure negative error code
*/
virtual nsapi_size_or_error_t get_manufacturer(char *buf, size_t buf_size);
/** Request model identification of cellular device
*
* @param buf model identification
* @param buf_size max length of model identification is 2048 characters
* @return on success read character count, on failure negative error code
*/
virtual nsapi_size_or_error_t get_model(char *buf, size_t buf_size);
/** Request revision identification of cellular device
*
* @param buf revision identification
* @param buf_size max length of revision identification is 2048 characters
* @return on success read character count, on failure negative error code
*/
virtual nsapi_size_or_error_t get_revision(char *buf, size_t buf_size);
protected:
/** Request information text from cellular device
*
* @param cmd 3gpp command string
* @param buf manufacturer identification
* @param buf_size max length of manufacturer identification is 2048 characters
* @return on success read character count, on failure negative error code
*/
nsapi_error_t get_info(const char *cmd, char *buf, size_t buf_size);
};
} // namespace mbed
#endif // AT_CELLULAR_INFORMATION_H_

View File

@ -0,0 +1,43 @@
/*
* 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 "AT_CellularMultiplexer.h"
#include "CellularLog.h"
using namespace mbed;
AT_CellularMultiplexer::AT_CellularMultiplexer(ATHandler &at) : AT_CellularBase(at)
{
}
AT_CellularMultiplexer::~AT_CellularMultiplexer()
{
}
nsapi_error_t AT_CellularMultiplexer::multiplexer_mode_start()
{
log_info("multiplexer_mode_start()");
_at.lock();
_at.cmd_start("AT+CMUX=0");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
return _at.unlock_return_error();
}

View File

@ -0,0 +1,41 @@
/*
* 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 AT_CELLULAR_MULTIPLEXER_H_
#define AT_CELLULAR_MULTIPLEXER_H_
#include "CellularMultiplexer.h"
#include "AT_CellularBase.h"
namespace mbed {
class AT_CellularMultiplexer : public CellularMultiplexer, public AT_CellularBase
{
public:
AT_CellularMultiplexer(ATHandler &atHandler);
virtual ~AT_CellularMultiplexer();
public:
/** Starts modem multiplexer mode specified by 3GPP TS 27.010.
*
* @return zero on success, negative error code on failure
*/
virtual nsapi_error_t multiplexer_mode_start();
};
} // namespace mbed
#endif /* AT_CELLULAR_MULTIPLEXER_H_ */

View File

@ -0,0 +1,888 @@
/*
* 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 <stdlib.h>
#include "AT_CellularNetwork.h"
#include "nsapi_ppp.h"
#include "CellularUtil.h"
#include "CellularLog.h"
using namespace std;
using namespace mbed_cellular_util;
using namespace mbed;
AT_CellularNetwork::AT_CellularNetwork(ATHandler &atHandler) : AT_CellularBase(atHandler),
_stack(NULL), _uname(NULL), _pwd(NULL), _ip_stack_type_requested(DEFAULT_STACK), _ip_stack_type(DEFAULT_STACK), _cid(-1),
_op_act(operator_t::RAT_UNKNOWN), _authentication_type(CHAP), _last_reg_type(C_REG)
{
_at.set_urc_handler("NO CARRIER", callback(this, &AT_CellularNetwork::urc_no_carrier));
memset(_apn, 0, MAX_APN_LENGTH);
#ifdef MBED_CONF_APP_CELLULAR_APN
strncpy(_apn, MBED_CONF_APP_CELLULAR_APN, MAX_APN_LENGTH);
log_debug("Using APN [%s] from json", _apn);
#endif
}
AT_CellularNetwork::~AT_CellularNetwork()
{
}
void AT_CellularNetwork::urc_no_carrier()
{
if (_connection_status_cb) {
_connection_status_cb(NSAPI_ERROR_CONNECTION_LOST);
}
}
nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn,
const char *username, const char *password)
{
strncpy(_apn, apn, MAX_APN_LENGTH);
_uname = username;
_pwd = password;
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn,
AuthenticationType type, const char *username, const char *password)
{
strncpy(_apn, apn, MAX_APN_LENGTH);
_uname = username;
_pwd = password;
_authentication_type = type;
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularNetwork::connect(const char *apn,
const char *username, const char *password)
{
strncpy(_apn, apn, MAX_APN_LENGTH);
_uname = username;
_pwd = password;
return connect();
}
nsapi_error_t AT_CellularNetwork::connect()
{
_at.lock();
nsapi_error_t err = set_context_to_be_activated();
if (err != NSAPI_ERROR_OK) {
_at.unlock();
log_error("Failed to activate network context!");
return err;
}
err = open_data_channel();
if (err != NSAPI_ERROR_OK) {
_at.unlock();
log_error("Failed to open data channel!");
return err;
}
_at.unlock();
return NSAPI_ERROR_OK;
}
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
log_info("Open data channel in PPP mode");
_at.cmd_start("AT+CGDATA=\"PPP\",");
_at.write_int(_cid);
_at.cmd_stop();
_at.resp_start("CONNECT", true);
if (_at.get_last_error()) {
log_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(), _connection_status_cb, _uname, _pwd, _ip_stack_type);
#else
// do check for stack to validate that we have support for stack
_stack = get_stack();
if (!_stack) {
return err;
}
log_info("Activate PDP context");
_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;
}
/**
* User initiated disconnect
*
* Disconnects from PPP connection only and brings down the underlying network
* interface
*/
nsapi_error_t AT_CellularNetwork::disconnect()
{
#if NSAPI_PPP_AVAILABLE
return nsapi_ppp_disconnect(_at.get_file_handle());
#else
return NSAPI_ERROR_OK;
#endif
}
void AT_CellularNetwork::connection_status_cb(Callback<void(nsapi_error_t)> cb)
{
_connection_status_cb = cb;
}
nsapi_error_t AT_CellularNetwork::set_context_to_be_activated()
{
// try to find or create context with suitable stack
if (!get_context(_ip_stack_type_requested)) {
return NSAPI_ERROR_NO_CONNECTION;
}
// if user has defined user name and password we need to call CGAUTH before activating or modifying context
if (_pwd && _uname) {
_at.cmd_start("AT+CGAUTH=");
_at.write_int(_cid);
_at.write_int(_authentication_type);
_at.write_string(_uname);
_at.write_string(_pwd);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() != NSAPI_ERROR_OK) {
return NSAPI_ERROR_AUTH_FAILURE;
}
}
return _at.get_last_error();
}
bool AT_CellularNetwork::set_new_context(nsapi_ip_stack_t stack, int cid)
{
nsapi_ip_stack_t tmp_stack = stack;
char pdp_type[8+1] = {0};
switch (stack) {
case IPV4_STACK:
strncpy(pdp_type, "IP", sizeof(pdp_type));
break;
case IPV6_STACK:
strncpy(pdp_type, "IPV6", sizeof(pdp_type));
break;
case IPV4V6_STACK:
strncpy(pdp_type, "IPV4V6", sizeof(pdp_type));
break;
default:
strncpy(pdp_type, "", sizeof(pdp_type));
break;
}
//apn: "If the value is null or omitted, then the subscription value will be requested."
bool success = false;
_at.cmd_start("AT+CGDCONT=");
_at.write_int(cid);
_at.write_string(pdp_type);
_at.write_string(_apn);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
success = (_at.get_last_error() == NSAPI_ERROR_OK);
// Fall back to ipv4
if (!success && tmp_stack == IPV4V6_STACK) {
tmp_stack = IPV4_STACK;
_at.cmd_start("AT+FCLASS=0;+CGDCONT=");
_at.write_int(cid);
_at.write_string("IP");
_at.write_string(_apn);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
success = (_at.get_last_error() == NSAPI_ERROR_OK);
}
if (success) {
_ip_stack_type = tmp_stack;
_cid = cid;
}
return success;
}
bool AT_CellularNetwork::get_context(nsapi_ip_stack_t requested_stack)
{
_at.cmd_start("AT+CGDCONT?");
_at.cmd_stop();
_at.resp_start("+CGDCONT:");
_cid = -1;
int cid_max = 0; // needed when creating new context
char apn[MAX_APN_LENGTH] = {0};
int apn_len = 0;
while (_at.info_resp()) {
int cid = _at.read_int();
if (cid > cid_max) {
cid_max = cid;
}
char pdp_type_from_context[10];
int pdp_type_len = _at.read_string(pdp_type_from_context, sizeof(pdp_type_from_context) - 1);
if (pdp_type_len > 0) {
apn_len = _at.read_string(apn, sizeof(apn) - 1);
if (apn_len >= 0) {
if (strlen(_apn) && strcmp(apn, _apn) != 0 ) {
continue;
}
nsapi_ip_stack_t pdp_stack = string_to_stack_type(pdp_type_from_context);
if (pdp_stack != DEFAULT_STACK) {
if (get_modem_stack_type(pdp_stack)) {
if (requested_stack == IPV4_STACK) {
if (pdp_stack == IPV4_STACK || pdp_stack == IPV4V6_STACK) {
_ip_stack_type = pdp_stack;
_cid = cid;
break;
}
} else if (requested_stack == IPV6_STACK) {
if (pdp_stack == IPV6_STACK || pdp_stack == IPV4V6_STACK) {
_ip_stack_type = pdp_stack;
_cid = cid;
break;
}
} else { // accept any but prefer to IPv6
if (pdp_stack == IPV6_STACK || pdp_stack == IPV4V6_STACK) {
_ip_stack_type = pdp_stack;
_cid = cid;
break;
}
if (_ip_stack_type == DEFAULT_STACK) {
_ip_stack_type = pdp_stack;
_cid = cid;
}
}
}
}
}
}
}
_at.resp_stop();
if (_cid == -1) { // no suitable context was found so create a new one
if (!set_new_context(_ip_stack_type, cid_max+1)) {
return false;
}
}
// save the apn
if (apn_len > 0 && !strlen(_apn)) {
strncpy(_apn, apn, MAX_APN_LENGTH);
}
log_debug("Context id %d", _cid);
return true;
}
nsapi_ip_stack_t AT_CellularNetwork::string_to_stack_type(const char* pdp_type)
{
nsapi_ip_stack_t stack = DEFAULT_STACK;
int len = strlen(pdp_type);
if (len == 6 && memcmp(pdp_type, "IPV4V6", len) == 0) {
stack = IPV4V6_STACK;
} else if (len == 4 && memcmp(pdp_type, "IPV6", len) == 0) {
stack = IPV6_STACK;
} else if (len == 2 && memcmp(pdp_type, "IP", len) == 0) {
stack = IPV4_STACK;
}
return stack;
}
nsapi_error_t AT_CellularNetwork::set_registration_urc(bool urc_on)
{
RegistrationType reg_types[] = {C_EREG, C_GREG, C_REG};
const char *cmd_on[] = {"AT+CEREG=2", "AT+CGREG=2", "AT+CREG=2"};
const char *cmd_off[] = {"AT+CEREG=0", "AT+CGREG=0", "AT+CREG=0"};
for (uint8_t i=0; i<sizeof(reg_types)/sizeof(reg_types[0]); i++) {
if (has_registration(reg_types[i])) {
_last_reg_type = reg_types[i];
if (urc_on) {
_at.cmd_start(cmd_on[i]);
_at.cmd_stop();
} else {
_at.cmd_start(cmd_off[i]);
_at.cmd_stop();
}
_at.resp_start();
_at.resp_stop();
}
}
return _at.get_last_error();
}
nsapi_error_t AT_CellularNetwork::set_registration(char *plmn)
{
_at.lock();
nsapi_error_t ret = set_registration_urc(false);
if (ret) {
log_error("Setting registration URC failed!");
return ret;
}
if (!plmn) {
log_debug("Automatic network registration");
_at.cmd_start("AT+COPS=0");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
} else {
log_debug("Manual network registration to %s", plmn);
_at.cmd_start("AT+COPS=4,2,");
_at.write_string(plmn);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
}
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_registration_status(RegistrationType type, RegistrationStatus &status)
{
int i = (int)type;
MBED_ASSERT(i >= 0 && i < C_MAX);
RegistrationType reg_types[] = { C_EREG, C_GREG, C_REG};
const char *cmd[] = { "AT+CEREG", "AT+CGREG", "AT+CREG"};
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(reg_types[i])) {
_at.unlock();
return NSAPI_ERROR_UNSUPPORTED;
}
_at.cmd_start(cmd[i]);
_at.write_string("=2", false);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start(cmd[i]);
_at.write_string("?", false);
_at.cmd_stop();
_at.resp_start(rsp[i]);
_at.read_int(); // ignore urc mode subparam
status = (RegistrationStatus)_at.read_int();
int len = _at.read_string(lac_string, LAC_LENGTH);
if (memcmp(lac_string, "ffff", LAC_LENGTH-1) && len >= 0) {
lac_read = true;
}
len = _at.read_string(cell_id_string, CELL_ID_LENGTH);
if (memcmp(cell_id_string, "ffffffff", CELL_ID_LENGTH-1) && len >= 0) {
cell_id_read = true;
}
_AcT = (operator_t::RadioAccessTechnology)_at.read_int();
_at.resp_stop();
_at.cmd_start(cmd[i]);
_at.write_string("=0", false);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
nsapi_error_t ret = _at.get_last_error();
_at.unlock();
if (lac_read) {
_lac = hex_str_to_int(lac_string, LAC_LENGTH);
log_debug("lac %s %d", lac_string, _lac );
}
if (cell_id_read) {
_cell_id = hex_str_to_int(cell_id_string, CELL_ID_LENGTH);
log_debug("cell_id %s %d", cell_id_string, _cell_id );
}
return ret;
}
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;
}
bool AT_CellularNetwork::has_registration(RegistrationType reg_type)
{
(void)reg_type;
return true;
}
nsapi_error_t AT_CellularNetwork::set_attach(int timeout)
{
_at.lock();
_at.cmd_start("AT+CGATT?");
_at.cmd_stop();
_at.resp_start("+CGATT:");
int attached_state = _at.read_int();
_at.resp_stop();
if (attached_state != 1) {
log_debug("Network attach");
_at.cmd_start("AT+CGATT=1");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
}
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_attach(AttachStatus &status)
{
_at.lock();
_at.cmd_start("AT+CGATT?");
_at.cmd_stop();
_at.resp_start("+CGATT:");
if (_at.info_resp()) {
int attach_status = _at.read_int();
status = (attach_status == 1) ? Attached : Detached;
}
_at.resp_stop();
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_backoff_time(int &backoffTime)
{
_at.lock();
// If apn is set
if (strlen(_apn)) {
_at.cmd_start("AT+CABTRDP=");
_at.write_string(_apn);
_at.cmd_stop();
_at.resp_start("+CABTRDP:");
if (_at.info_resp()) {
_at.skip_param();
backoffTime = _at.read_int();
}
_at.resp_stop();
}
return _at.unlock_return_error();
}
NetworkStack *AT_CellularNetwork::get_stack()
{
// use lwIP/PPP if modem does not have IP stack
#if NSAPI_PPP_AVAILABLE
_stack = nsapi_ppp_get_stack();
#else
_stack = NULL;
#endif
return _stack;
}
const char *AT_CellularNetwork::get_ip_address()
{
#if NSAPI_PPP_AVAILABLE
return nsapi_ppp_get_ip_addr(_at.get_file_handle());
#else
if (!_stack) {
_stack = get_stack();
}
if (_stack) {
return _stack->get_ip_address();
}
return NULL;
#endif
}
nsapi_error_t AT_CellularNetwork::set_stack_type(nsapi_ip_stack_t stack_type)
{
if (get_modem_stack_type(stack_type)) {
_ip_stack_type_requested = stack_type;
return NSAPI_ERROR_OK;
} else {
return NSAPI_ERROR_PARAMETER;
}
}
nsapi_ip_stack_t AT_CellularNetwork::get_stack_type()
{
return _ip_stack_type;
}
bool AT_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
if (requested_stack == _ip_stack_type) {
return true;
} else {
return false;
}
}
nsapi_error_t AT_CellularNetwork::set_access_technology_impl(operator_t::RadioAccessTechnology opsAct)
{
return NSAPI_ERROR_UNSUPPORTED;
}
nsapi_error_t AT_CellularNetwork::set_access_technology(operator_t::RadioAccessTechnology opAct)
{
if (opAct == operator_t::RAT_UNKNOWN) {
return NSAPI_ERROR_UNSUPPORTED;
}
_op_act = opAct;
return set_access_technology_impl(opAct);
}
nsapi_error_t AT_CellularNetwork::scan_plmn(operList_t &operators, int &opsCount)
{
int idx = 0;
_at.lock();
_at.cmd_start("AT+COPS=?");
_at.cmd_stop();
_at.resp_start("+COPS:");
int ret, error_code = -1;
operator_t *op = NULL;
while (_at.info_elem('(')) {
op = operators.add_new();
op->op_status = (operator_t::Status)_at.read_int();
_at.read_string(op->op_long, sizeof(op->op_long));
_at.read_string(op->op_short, sizeof(op->op_short));
_at.read_string(op->op_num, sizeof(op->op_num));
// Optional - try read an int
ret = _at.read_int();
op->op_rat = (ret == error_code) ? operator_t::RAT_UNKNOWN:(operator_t::RadioAccessTechnology)ret;
if ((_op_act == operator_t::RAT_UNKNOWN) ||
((op->op_rat != operator_t::RAT_UNKNOWN) && (op->op_rat == _op_act))) {
idx++;
} else {
operators.delete_last();
}
}
_at.resp_stop();
opsCount = idx;
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::set_ciot_optimization_config(Supported_UE_Opt supported_opt,
Preferred_UE_Opt preferred_opt)
{
_at.lock();
_at.cmd_start("AT+CCIOTOPT=");
_at.write_int(_cid);
_at.write_int(supported_opt);
_at.write_int(preferred_opt);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_ciot_optimization_config(Supported_UE_Opt& supported_opt,
Preferred_UE_Opt& preferred_opt)
{
_at.lock();
_at.cmd_start("AT+CCIOTOPT?");
_at.cmd_stop();
_at.resp_start("+CCIOTOPT:");
_at.read_int();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
supported_opt = (Supported_UE_Opt)_at.read_int();
preferred_opt = (Preferred_UE_Opt)_at.read_int();
}
_at.resp_stop();
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_rate_control(
CellularNetwork::RateControlExceptionReports &reports,
CellularNetwork::RateControlUplinkTimeUnit &timeUnit, int &uplinkRate)
{
_at.lock();
_at.cmd_start("AT+CGAPNRC=");
_at.write_int(_cid);
_at.cmd_stop();
_at.resp_start("+CGAPNRC:");
_at.read_int();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
bool comma_found = true;
int next_element = _at.read_int();
if (next_element >= 0) {
reports = (RateControlExceptionReports)next_element;
log_debug("reports %d",reports);
next_element = _at.read_int();
} else {
comma_found = false;
}
if (comma_found && next_element >= 0) {
timeUnit = (RateControlUplinkTimeUnit)next_element;
log_debug("time %d",timeUnit);
next_element = _at.read_int();
} else {
comma_found = false;
}
if (comma_found && next_element >= 0) {
uplinkRate = next_element;
log_debug("rate %d",uplinkRate);
}
}
_at.resp_stop();
nsapi_error_t ret = _at.get_last_error();
_at.unlock();
return (ret == NSAPI_ERROR_OK) ? NSAPI_ERROR_OK : NSAPI_ERROR_PARAMETER;
}
nsapi_error_t AT_CellularNetwork::get_pdpcontext_params(pdpContextList_t& params_list)
{
const int ipv6_subnet_size = 128;
const int max_ipv6_size = 64;
char* ipv6_and_subnetmask = (char*)malloc(ipv6_subnet_size);
if (!ipv6_and_subnetmask) {
return NSAPI_ERROR_NO_MEMORY;
}
char* temp = (char*)malloc(max_ipv6_size);
if (!temp) {
free(ipv6_and_subnetmask);
return NSAPI_ERROR_NO_MEMORY;
}
_at.lock();
_at.cmd_start("AT+CGCONTRDP=");
_at.write_int(_cid);
_at.cmd_stop();
_at.resp_start("+CGCONTRDP:");
pdpcontext_params_t *params = NULL;
while (_at.info_resp()) { // response can be zero or many +CGDCONT lines
params = params_list.add_new();
if (!params) {
log_warn("Could not allocate new pdpcontext_params_t");
params_list.delete_all();
_at.resp_stop();
free(temp);
free(ipv6_and_subnetmask);
return NSAPI_ERROR_NO_MEMORY;
}
params->cid = _at.read_int();
params->bearer_id = _at.read_int();
_at.read_string(params->apn, sizeof(params->apn));
// rest are optional params
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->local_addr, sizeof(params->local_addr), params->local_subnet_mask, sizeof(params->local_subnet_mask));
ipv6_and_subnetmask[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->gateway_addr, sizeof(params->gateway_addr), temp, max_ipv6_size);
prefer_ipv6(params->gateway_addr, sizeof(params->gateway_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->dns_primary_addr, sizeof(params->dns_primary_addr), temp, max_ipv6_size);
prefer_ipv6(params->dns_primary_addr, sizeof(params->dns_primary_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->dns_secondary_addr, sizeof(params->dns_secondary_addr), temp, max_ipv6_size);
prefer_ipv6(params->dns_secondary_addr, sizeof(params->dns_secondary_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->p_cscf_prim_addr, sizeof(params->p_cscf_prim_addr), temp, max_ipv6_size);
prefer_ipv6(params->p_cscf_prim_addr, sizeof(params->p_cscf_prim_addr), temp, max_ipv6_size);
ipv6_and_subnetmask[0] = '\0';
temp[0] = '\0';
_at.read_string(ipv6_and_subnetmask, ipv6_subnet_size);
separate_ip_addresses(ipv6_and_subnetmask, params->p_cscf_sec_addr, sizeof(params->p_cscf_sec_addr), temp, max_ipv6_size);
prefer_ipv6(params->p_cscf_sec_addr, sizeof(params->p_cscf_sec_addr), temp, max_ipv6_size);
params->im_signalling_flag = _at.read_int();
params->lipa_indication = _at.read_int();
params->ipv4_mtu = _at.read_int();
params->wlan_offload = _at.read_int();
params->local_addr_ind = _at.read_int();
params->non_ip_mtu = _at.read_int();
params->serving_plmn_rate_control_value = _at.read_int();
}
_at.resp_stop();
free(temp);
free(ipv6_and_subnetmask);
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_extended_signal_quality(int &rxlev, int &ber, int &rscp, int &ecno, int &rsrq, int &rsrp)
{
_at.lock();
_at.cmd_start("AT+CESQ");
_at.cmd_stop();
_at.resp_start("+CESQ:");
rxlev = _at.read_int();
ber = _at.read_int();
rscp = _at.read_int();
ecno = _at.read_int();
rsrq = _at.read_int();
rsrp = _at.read_int();
_at.resp_stop();
if (rxlev < 0 || ber < 0 || rscp < 0 || ecno < 0 || rsrq < 0 || rsrp < 0) {
_at.unlock();
return NSAPI_ERROR_DEVICE_ERROR;
}
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_signal_quality(int &rssi, int &ber)
{
_at.lock();
_at.cmd_start("AT+CSQ");
_at.cmd_stop();
_at.resp_start("+CSQ:");
rssi = _at.read_int();
ber = _at.read_int();
_at.resp_stop();
if (rssi < 0 || ber < 0) {
_at.unlock();
return NSAPI_ERROR_DEVICE_ERROR;
}
return _at.unlock_return_error();
}
/** Get the last 3GPP error code
* @return see 3GPP TS 27.007 error codes
*/
uint8_t 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();
_at.cmd_start("AT+COPS?");
_at.cmd_stop();
_at.resp_start("+COPS: ");
_at.read_int(); //ignore mode
format = _at.read_int();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
switch (format) {
case 0:
_at.read_string(operator_params.op_long, 16+9);
break;
case 1:
_at.read_string(operator_params.op_short, 8+4);
break;
default:
_at.read_string(operator_params.op_num, 8+4);
break;
}
operator_params.op_rat = (operator_t::RadioAccessTechnology)_at.read_int();
}
_at.resp_stop();
return _at.unlock_return_error();
}

View File

@ -0,0 +1,300 @@
/*
* 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 AT_CELLULAR_NETWORK_H_
#define AT_CELLULAR_NETWORK_H_
#include "CellularNetwork.h"
#include "AT_CellularBase.h"
#include "NetworkStack.h"
namespace mbed {
#define AT_NETWORK_TRIALS 5
#define MAX_APN_LENGTH 63
class AT_CellularNetwork : public CellularNetwork, public AT_CellularBase
{
public:
AT_CellularNetwork(ATHandler &atHandler);
virtual ~AT_CellularNetwork();
public: // NetworkInterface
/** Set the cellular network APN and credentials
*
* @param apn Optional name of the network to connect to
* @param username Optional username for the APN
* @param password Optional password fot the APN
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t set_credentials(const char *apn,
const char *username = 0, const char *password = 0);
/** Set the cellular network APN and credentials
*
* @param apn Name of the network to connect to
* @param type Authentication type to use
* @param username Optional username for the APN
* @param password Optional password fot the APN
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t set_credentials(const char *apn, AuthenticationType type,
const char *username = 0, const char *password = 0);
/** Start the interface. Attempts to connect to a cellular network.
*
* @param apn Optional name of the network to connect to
* @param username Optional username for your APN
* @param password Optional password for your APN
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t connect(const char *apn,
const char *username = 0, const char *password = 0);
/** Start the interface. Attempts to connect to a cellular network.
*
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t connect();
/** Stop the interface
*
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t disconnect();
/** Provide access to the NetworkStack object
*
* @return The underlying NetworkStack object
*/
virtual NetworkStack *get_stack();
public: // CellularNetwork
/** Request registering to network.
*
* @param plmn format is in numeric format or 0 for automatic network registration
* @return zero on success
*/
virtual nsapi_error_t set_registration(char *plmn = 0);
/**
* Gets the network registration status.
* @param type see RegistrationType values
* @param status see RegistrationStatus values
* @return zero on success
*/
virtual nsapi_error_t get_registration_status(RegistrationType type, RegistrationStatus &status);
/** Request attach to network.
*
* @param timeout milliseconds to wait for attach response
* @return zero on success
*/
virtual nsapi_error_t set_attach(int timeout = 10*1000);
/** Request attach status from network.
*
* @param status see AttachStatus values
* @return zero on success
*/
virtual nsapi_error_t get_attach(AttachStatus &status);
/** Get APN rate control.
*
* @remark optional params are not updated if not received from network, so use good defaults
*
* @param reports Additional exception reports at maximum rate reached are allowed to be sent [optional]
* @param time_unit Uplink time unit with values 0=unrestricted, 1=minute, 2=hour, 3=day, 4=week [optional]
* @param uplink_rate Maximum number of messages per timeUnit [optional]
* @return zero on success
*/
virtual nsapi_error_t get_rate_control(CellularNetwork::RateControlExceptionReports &reports,
CellularNetwork::RateControlUplinkTimeUnit &time_unit, int &uplink_rate);
/** Get backoff timer value
*
* @param backoff_time Backoff timer value associated with PDP APN in seconds
* @return zero on success
*/
virtual nsapi_error_t get_backoff_time(int &backoff_time);
/** Get notified if the connection gets lost
*
* @param cb user defined callback
*/
void connection_status_cb(Callback<void(nsapi_error_t)> cb);
/** Get the local IP address
*
* @return Null-terminated representation of the local IP address
* or null if no IP address has been received
*/
virtual const char *get_ip_address();
/** Sets radio access technology.
*
* @param op_rat Radio access technology
* @return zero on success
*/
virtual nsapi_error_t set_access_technology(operator_t::RadioAccessTechnology op_rat);
/** Scans for operators module can reach.
*
* @param operators Container of reachable operators and their access technologies
* @param ops_count Number of found operators
* @return zero on success
*/
virtual nsapi_error_t scan_plmn(operList_t &operators, int &ops_count);
/** Set CIoT optimizations.
*
* @param supported_opt Supported CIoT EPS optimizations.
* @param preferred_opt Preferred CIoT EPS optimizations.
* @return zero on success
*/
virtual nsapi_error_t set_ciot_optimization_config(Supported_UE_Opt supported_opt,
Preferred_UE_Opt preferred_opt);
/** Get CIoT optimizations.
*
* @param supported_opt Supported CIoT EPS optimizations.
* @param preferred_opt Preferred CIoT EPS optimizations.
* @return zero on success
*/
virtual nsapi_error_t get_ciot_optimization_config(Supported_UE_Opt& supported_opt,
Preferred_UE_Opt& preferred_opt);
/** Set the pdn type to be used
*
* @param stack_type the stack type to be used.
* @return NSAPI_ERROR_OK on success
*/
virtual nsapi_error_t set_stack_type(nsapi_ip_stack_t stack_type);
/** Get the pdn type in use
*
* @return stack type
*/
virtual nsapi_ip_stack_t get_stack_type();
/** Get the relevant information for an active non secondary PDP context.
*
* @remark optional params are not updated if not received from network.
*
* @param params_list reference to linked list which is filled on successful call
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t get_pdpcontext_params(pdpContextList_t& params_list);
/** Get extended signal quality parameters.
*
* @param rxlev signal strength level
* @param ber bit error rate
* @param rscp signal code power
* @param ecno ratio of the received energy per PN chip to the total received power spectral density
* @param rsrq signal received quality
* @param rsrp signal received power
* @return NSAPI_ERROR_OK on success, negative error code on failure
*/
virtual nsapi_error_t get_extended_signal_quality(int &rxlev, int &ber, int &rscp, int &ecno, int &rsrq, int &rsrp);
/** Get signal quality parameters.
*
* @param rssi signal strength level
* @param ber bit error rate
* @return NSAPI_ERROR_OK on success, negative error code on failure
*/
virtual nsapi_error_t get_signal_quality(int &rssi, int &ber);
/** Get cell id.
*
* @param cell_id cell id
* @return NSAPI_ERROR_OK on success, negative error code on failure
*/
virtual nsapi_error_t get_cell_id(int &cell_id);
/** Get the last 3GPP error code
* @return see 3GPP TS 27.007 error codes
*/
virtual uint8_t get_3gpp_error();
/** Get the operator params
*
* @param format format of the operator field
* @param operator_params applicable operator param fields filled
* @return NSAPI_ERROR_OK on success, negative error code on failure
*/
virtual nsapi_error_t get_operator_params(int &format, operator_t &operator_params);
protected:
/** Check if modem supports the given stack type.
*
* @return true if supported
*/
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
/** Check if modem supports given registration type.
*
* @param reg_type enum RegistrationType
* @return true if given registration type is supported by modem
*/
virtual bool has_registration(RegistrationType reg_type);
/** Sets access technology to be scanned.
*
* @param op_rat Access technology
*
* @return zero on success
*/
virtual nsapi_error_t set_access_technology_impl(operator_t::RadioAccessTechnology op_rat);
private:
// "NO CARRIER" urc
void urc_no_carrier();
nsapi_error_t set_context_to_be_activated();
nsapi_ip_stack_t string_to_stack_type(const char* pdp_type);
nsapi_error_t open_data_channel();
bool get_context(nsapi_ip_stack_t supported_stack);
bool set_new_context(nsapi_ip_stack_t stack, int cid);
nsapi_error_t set_registration_urc(bool on);
protected:
NetworkStack *_stack;
char _apn[MAX_APN_LENGTH];
const char *_uname;
const char *_pwd;
nsapi_ip_stack_t _ip_stack_type_requested;
nsapi_ip_stack_t _ip_stack_type;
int _cid;
Callback<void(nsapi_error_t)> _connection_status_cb;
operator_t::RadioAccessTechnology _op_act;
AuthenticationType _authentication_type;
int _lac;
int _cell_id;
operator_t::RadioAccessTechnology _AcT;
RegistrationType _last_reg_type;
};
} // namespace mbed
#endif // AT_CELLULAR_NETWORK_H_

View File

@ -0,0 +1,232 @@
/*
* 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 "AT_CellularPower.h"
#include "CellularUtil.h"
#include "CellularLog.h"
static const int PSMTimerBits = 5;
using namespace mbed_cellular_util;
using namespace mbed;
AT_CellularPower::AT_CellularPower(ATHandler &at) : AT_CellularBase(at)
{
}
AT_CellularPower::~AT_CellularPower()
{
}
nsapi_error_t AT_CellularPower::on()
{
return NSAPI_ERROR_UNSUPPORTED;
}
nsapi_error_t AT_CellularPower::off()
{
return NSAPI_ERROR_UNSUPPORTED;
}
nsapi_error_t AT_CellularPower::set_at_mode()
{
_at.lock();
_at.flush();
_at.cmd_start("ATE0"); // echo off
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start("AT+CMEE=1"); // verbose responses
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularPower::set_power_level(int func_level)
{
_at.lock();
_at.cmd_start("AT+CFUN=");
_at.write_int(func_level);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularPower::reset()
{
_at.lock();
_at.cmd_start("AT+CFUN=");// reset to full power levels
_at.write_int(1);
_at.write_int(1);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularPower::opt_power_save_mode(int periodic_time, int active_time)
{
_at.lock();
if (periodic_time == 0 && active_time == 0) {
// disable PSM
_at.cmd_start("AT+CPSMS=");
_at.write_int(0);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
} else {
/**
Table 10.5.163a/3GPP TS 24.008: GPRS Timer 3 information element
Bits 5 to 1 represent the binary coded timer value.
Bits 6 to 8 defines the timer value unit for the GPRS timer as follows:
8 7 6
0 0 0 value is incremented in multiples of 10 minutes
0 0 1 value is incremented in multiples of 1 hour
0 1 0 value is incremented in multiples of 10 hours
0 1 1 value is incremented in multiples of 2 seconds
1 0 0 value is incremented in multiples of 30 seconds
1 0 1 value is incremented in multiples of 1 minute
1 1 0 value is incremented in multiples of 320 hours (NOTE 1)
1 1 1 value indicates that the timer is deactivated (NOTE 2).
*/
char pt[8+1];// timer value encoded as 3GPP IE
const int ie_value_max = 0x1f;
uint32_t periodic_timer = 0;
if (periodic_time <= 2*ie_value_max) { // multiples of 2 seconds
periodic_timer = periodic_time/2;
strcpy(pt, "01100000");
} else {
if (periodic_time <= 30*ie_value_max) { // multiples of 30 seconds
periodic_timer = periodic_time/30;
strcpy(pt, "10000000");
} else {
if (periodic_time <= 60*ie_value_max) { // multiples of 1 minute
periodic_timer = periodic_time/60;
strcpy(pt, "10100000");
} else {
if (periodic_time <= 10*60*ie_value_max) { // multiples of 10 minutes
periodic_timer = periodic_time/(10*60);
strcpy(pt, "00000000");
} else {
if (periodic_time <= 60*60*ie_value_max) { // multiples of 1 hour
periodic_timer = periodic_time/(60*60);
strcpy(pt, "00100000");
} else {
if (periodic_time <= 10*60*60*ie_value_max) { // multiples of 10 hours
periodic_timer = periodic_time/(10*60*60);
strcpy(pt, "01000000");
} else { // multiples of 320 hours
int t = periodic_time / (320*60*60);
if (t > ie_value_max) {
t = ie_value_max;
}
periodic_timer = t;
strcpy(pt, "11000000");
}
}
}
}
}
}
uint_to_binary_str(periodic_timer, &pt[3], sizeof(pt)-3, PSMTimerBits);
pt[8] = '\0';
/**
Table 10.5.172/3GPP TS 24.008: GPRS Timer information element
Bits 5 to 1 represent the binary coded timer value.
Bits 6 to 8 defines the timer value unit for the GPRS timer as follows:
8 7 6
0 0 0 value is incremented in multiples of 2 seconds
0 0 1 value is incremented in multiples of 1 minute
0 1 0 value is incremented in multiples of decihours
1 1 1 value indicates that the timer is deactivated.
Other values shall be interpreted as multiples of 1 minute in this version of the protocol.
*/
char at[8+1];
uint32_t active_timer; // timer value encoded as 3GPP IE
if (active_time <= 2*ie_value_max) { // multiples of 2 seconds
active_timer = active_time/2;
strcpy(at, "00000000");
} else {
if (active_time <= 60*ie_value_max) { // multiples of 1 minute
active_timer = (1<<5) | (active_time/60);
strcpy(at, "00100000");
} else { // multiples of decihours
int t = active_time / (6*60);
if (t > ie_value_max) {
t = ie_value_max;
}
active_timer = t;
strcpy(at, "01000000");
}
}
uint_to_binary_str(active_timer, &at[3], sizeof(at)-3, PSMTimerBits);
pt[8] = '\0';
// request for both GPRS and LTE
_at.cmd_start("AT+CPSMS=");
_at.write_int(1);
_at.write_string(pt);
_at.write_string(at);
_at.write_string(pt);
_at.write_string(at);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
if (_at.get_last_error() != NSAPI_ERROR_OK) {
log_warn("Power save mode not enabled!");
} else {
// network may not agree with power save options but
// that should be fine as timeout is not longer than requested
}
}
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularPower::opt_receive_period(int mode, EDRXAccessTechnology act_type, uint8_t edrx_value)
{
char edrx[5];
uint_to_binary_str(edrx_value, edrx, 5, 4);
edrx[4] = '\0';
_at.lock();
_at.cmd_start("AT+CEDRXS=");
_at.write_int(mode);
_at.write_int(act_type);
_at.write_string(edrx);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
return _at.unlock_return_error();
}

View File

@ -0,0 +1,112 @@
/*
* 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 AT_CELLULAR_POWER_H_
#define AT_CELLULAR_POWER_H_
#include "CellularPower.h"
#include "AT_CellularBase.h"
namespace mbed {
class AT_CellularPower : public CellularPower, public AT_CellularBase
{
public:
AT_CellularPower(ATHandler &atHandler);
virtual ~AT_CellularPower();
public:
/** Set cellular device power on. Default implementation is empty.
* Device power on/off is modem/board specific behavior and must be done on inherited class if needed.
* Power on is done by toggling power pin/button.
*
* @remark set_at_mode must be called to initialise modem
* @remark Should not be called if MUX is enabled and started. If called then start-up sequence must be done again.
*
* @return zero on success
*/
virtual nsapi_error_t on();
/** Set cellular device power off. Default implementation is empty.
* Device power on/off is modem/board specific behavior and must be done on inherited class if needed.
* Power off is done by toggling power pin/button.
*
* @remark Should not be called if MUX is enabled and started. If called then start-up sequence must be done again.
*
* @return zero on success
*/
virtual nsapi_error_t off();
/** Set AT command mode. Blocking until success or failure.
*
* @remark must be called after power on to prepare correct AT mode
*
* @return zero on success
*/
virtual nsapi_error_t set_at_mode();
/** Set cellular device power level by enabling/disabling functionality.
*
* @param func_level:
* 0 minimum functionality
* 1 full functionality. Enable (turn on) the transmit and receive RF circuits for all supported radio access technologies.
* For MTs supporting +CSRA, this equals the RATs indicated by the response of +CSRA=?. Current +CSRA setting is ignored.
* It is not required that the MT transmit and receive RF circuits are in a disabled state for this setting to have effect.
* 2 disable (turn off) MT transmit RF circuits only
* 3 disable (turn off) MT receive RF circuits only
* 4 disable (turn off) both MT transmit and receive RF circuits
*
* @remark See 3GPP TS 27.007 CFUN for more details
* @remark Should not be called if MUX is enabled and started. If called then start-up sequence must be done again.
*
* @return zero on success
*/
virtual nsapi_error_t set_power_level(int func_level);
/** Reset and wake-up cellular device.
*
* @remark Should not be called if MUX is enabled and started. If called then start-up sequence must be done again.
*
* @return zero on success
*/
virtual nsapi_error_t reset();
/** Opt for power save setting on cellular device. If both parameters are zero then disables PSM.
*
* @remark See 3GPP TS 27.007 PSM for details
*
* @param periodic_time Timeout in seconds IoT subsystem is not expecting messaging
* @param active_time Timeout in seconds IoT subsystem waits for response
* @return zero on success
*/
virtual nsapi_error_t opt_power_save_mode(int periodic_time, int active_time);
/** Opt for discontinuous reception on cellular device.
*
* @remark See 3GPP TS 27.007 eDRX for details.
*
* @param mode disable or enable the use of eDRX
* @param act_type type of access technology
* @param edrx_value requested edxr value. Extended DRX parameters information element.
* @return zero on success
*/
virtual nsapi_error_t opt_receive_period(int mode, EDRXAccessTechnology act_type, uint8_t edrx_value);
};
} // namespace mbed
#endif /* AT_CELLULAR_POWER_H_ */

View File

@ -0,0 +1,114 @@
/*
* 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 "AT_CellularSIM.h"
#include "CellularLog.h"
using namespace mbed;
AT_CellularSIM::AT_CellularSIM(ATHandler &at) : AT_CellularBase(at)
{
}
AT_CellularSIM::~AT_CellularSIM()
{
}
nsapi_error_t AT_CellularSIM::get_sim_state(SimState &state)
{
char simstr[16];
_at.lock();
_at.flush();
_at.cmd_start("AT+CPIN?");
_at.cmd_stop();
_at.resp_start("+CPIN:");
ssize_t len = _at.read_string(simstr, sizeof (simstr));
if (len != -1) {
if (len >= 5 && memcmp(simstr, "READY", 5) == 0) {
state = SimStateReady;
} else if (len >= 6 && memcmp(simstr, "SIM PIN", 6) == 0) {
state = SimStatePinNeeded;
} else if (len >= 6 && memcmp(simstr, "SIM PUK", 6) == 0) {
state = SimStatePukNeeded;
} else {
simstr[len] = '\0';
log_error("Unknown SIM state %s", simstr);
state = SimStateUnknown;
}
} else {
log_warn("SIM not readable.");
state = SimStateUnknown; // SIM may not be ready yet or +CPIN may be unsupported command
}
_at.resp_stop();
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularSIM::set_pin(const char *sim_pin)
{
// if SIM is already in ready state then settings the PIN
// will return error so let's check the state before settings the pin.
SimState state;
if (get_sim_state(state) == NSAPI_ERROR_OK && state == SimStateReady) {
return NSAPI_ERROR_OK;
}
_at.lock();
_at.cmd_start("AT+CPIN=");
_at.write_string(sim_pin);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularSIM::change_pin(const char *sim_pin, const char *new_pin)
{
_at.lock();
_at.cmd_start("AT+CPWD=");
_at.write_string("SC");
_at.write_string(sim_pin);
_at.write_string(new_pin);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularSIM::set_pin_query(const char *sim_pin, bool query_pin)
{
_at.lock();
if (query_pin) {
/* use the SIM locked */
_at.cmd_start("AT+CLCK=");
_at.write_string("SC");
_at.write_int(1);
_at.write_string(sim_pin);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
} else {
/* use the SIM unlocked */
_at.cmd_start("AT+CLCK=");
_at.write_string("SC");
_at.write_int(0);
_at.write_string(sim_pin);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
}
return _at.unlock_return_error();
}

View File

@ -0,0 +1,67 @@
/*
* 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 AT_CELLULAR_SIM_H_
#define AT_CELLULAR_SIM_H_
#include "CellularSIM.h"
#include "AT_CellularBase.h"
namespace mbed {
class AT_CellularSIM : public CellularSIM, public AT_CellularBase
{
public:
AT_CellularSIM(ATHandler &atHandler);
virtual ~AT_CellularSIM();
public:
/** Open the SIM card by setting the pin code for SIM.
*
* @param sim_pin PIN for the SIM card
* @return zero on success
*/
virtual nsapi_error_t set_pin(const char *sim_pin);
/**Change sim pin code.
*
* @param sim_pin Current PIN for sim
* @param new_pin New PIN for sim
* @return zero on success
*/
virtual nsapi_error_t change_pin(const char *sim_pin, const char *new_pin);
/** Change is pin query needed after boot
*
* @param sim_pin Valid PIN for SIM card
* @param query_pin False is PIN query not needed, True if PIN query needed after boot.
* @return zero on success
*/
virtual nsapi_error_t set_pin_query(const char *sim_pin, bool query_pin);
/** Get sim card's state
*
* @param state current state of SIM
* @return zero on success
*/
virtual nsapi_error_t get_sim_state(SimState &state);
};
} // namespace mbed
#endif // AT_CELLULAR_SIM_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,245 @@
/*
* 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 AT_CELLULAR_SMS_H_
#define AT_CELLULAR_SMS_H_
#include "CellularSMS.h"
#include "AT_CellularBase.h"
#include <Callback.h>
#include <time.h>
namespace mbed {
class AT_CellularSMS: public CellularSMS, public AT_CellularBase
{
public:
AT_CellularSMS(ATHandler &atHandler);
virtual ~AT_CellularSMS();
public:
// from CellularSMS
/** Does all the necessary initializations needed for receiving and sending sms.
*
* @param mode enumeration for choosing the correct mode: text/pdu
* @return zero on success
*/
virtual nsapi_error_t initialize(CellularSMSMmode mode);
/** Send the SMS with the given parameters
*
* @param phone_number Phone number where to send sms
* @param message SMS message content
* @param msg_len Length of the message
* @return possible error code or length of the sent sms
*/
virtual nsapi_size_or_error_t send_sms(const char* phone_number, const char* message, int msg_len);
/** Gets the oldest received sms.
*
* @param buf preallocated buffer for sms message content
* @param buf_len length of allocated buf
* @param phone_num preallocated buffer for phone number where sms was sent
* @param phone_len length of allocated phone_num buffer
* @param time_stamp preallocated buffer for TP-Service Centre Time Stamp (format: yy/MM/dd,hh:mm:ss-+zz). +-zz is timezone.
* The unit of time zone is a quarter of an hour relative to GMT. For example +32 would be GMT+8.
* @param time_len length of allocated time_stamp buffer
* @param buf_size if method return error NSAPI_ERROR_NO_MEMORY because the given buf was not big enough this will
* hold the size which is enough. Otherwise zero.
* @return possible error code or size of buf. Will return SMS_ERROR_MULTIPART_ALL_PARTS_NOT_READ
* if sms was multipart but not all parts are present/failed to read.
*/
virtual nsapi_size_or_error_t get_sms(char* buf, uint16_t buf_len, char* phone_num, uint16_t phone_len,
char* time_stamp, uint16_t time_len, int *buf_size);
/** Callback which is called when new sms is received. SMS can be fetched via method get_sms().
*
* @remark In PDU mode there can be multipart sms and callback is called for every received part.
*
* @param func Callback function which is called when new sms is received.
*/
virtual void set_sms_callback(Callback<void()> func);
/** CPMS preferred message storage
*
* @param memr memory from which messages are read and deleted
* "SM" - SIM SMS memory storage (default)
* "ME" - NVM SMS storage
* @param memw memory to which writing and sending operations are made
* "SM" - SIM SMS memory storage (default)
* "ME" - NVM SMS storage
* @param mems memory to which received SMs are preferred to be stored
* "SM" - SIM SMS memory storage (default)
* "ME" - NVM SMS storage
*
* @return zero for success
*/
virtual nsapi_error_t set_cpms(const char *memr, const char *memw, const char *mems);
/** CSCA - set Service Center Address
*
* @param sca Service Center Address to be used for mobile originated SMS transmissions.
* @param type 129 - national numbering scheme, 145 - international numbering scheme (contains the character "+")
*
* @return zero for success
*/
virtual nsapi_error_t set_csca(const char *sca, int type);
/** Set command sets the current character set used by the device. "GSM", "IRA",....
*
* @remark Current implementation support only ASCII so choose the correct character set.
*
* @param chr_set preferred character set list (comma separated). Modem might not support the wanted character set
* so chr_set list is looped from start until supported set is found. Used character set index is returned.
* See more from 3GPP TS 27.005.
* @return Used character set index from the given list in case of success. Otherwise negative errorcode.
*/
virtual nsapi_size_or_error_t set_cscs(const char *chr_set);
/** Deletes all messages from the currently set memory/SIM
*
* @return zero for success
*/
virtual nsapi_error_t delete_all_messages();
/** Some modems need extra time between AT commands and responses or there will be error -314, SIM busy.
* If SIM busy errors are an issue this time should be increased. It can also be set to zero to make
* operations faster and more energy efficient if no errors will follow. By default wait time is zero.
*
* @param sim_wait_time
*/
virtual void set_extra_sim_wait_time(int sim_wait_time);
private:
struct sms_info_t {
char date[SMS_MAX_TIME_STAMP_SIZE];
uint16_t msg_index[50]; // can hold up to 50 concatenated msg parts, indexes are in correct order. So max sms size is 50*140 = 7kb
uint16_t msg_size;
uint8_t parts;
uint8_t parts_added;
uint16_t msg_ref_number;
struct sms_info_t *next_info;
sms_info_t() : msg_size(0), parts(1), parts_added(1), msg_ref_number(0), next_info(0){};
};
// application callback function for received sms
Callback<void()> _cb;
CellularSMSMmode _mode;
bool _use_8bit_encoding;
uint32_t _sim_wait_time;
uint16_t _sms_message_ref_number;
sms_info_t *_sms_info;
// SMS urc's
void cmt_urc();
void cmti_urc();
/** Set command selects the format of messages used with send, list, read and write commands.
*
* @param msg_format 0 PDU mode, 1 text mode
* @return zero for success
*/
nsapi_error_t set_cmgf(int msg_format);
/** Select message service (AT+CSMS select message service)
*
* @param msg_service 0 or 1. See more from 3GPP TS 27.005
*
* @return zero for success
*/
nsapi_error_t set_csms(int msg_service);
/* Set how receiving of new messages from the network is indicated to the TE.
*
* @return zero for success
*/
nsapi_error_t set_cnmi();
/** Set Text Mode Parameters
*
* @param fo See more from 3GPP TS 27.005 for all params.
* @param vp
* @param pid
* @param dcs
* @return zero for success
*/
nsapi_error_t set_csmp(int fo, int vp, int pid, int dcs);
/** CSDH - Set command controls whether detailed header information is shown in text mode (AT+CMGF=1) result codes.
*
* @param show_header 1 to show detailed header in text mode, 0 for not showing.
* @return zero for success
*/
nsapi_error_t set_csdh(int show_header);
/** Delete SMS in the given message position(s) in the storage
*
* @param sms struct containing index array to delete
* @return zero for success
*/
nsapi_error_t delete_sms(sms_info_t* sms);
/**
* Internal helper methods
*/
nsapi_error_t list_messages();
int read_sms_params(char *, char *);
void free_linked_list();
void add_info(sms_info_t* info, int index, int part_number);
int read_udh_from_pdu(const char* pdu, sms_info_t *info, int &part_number, int &parts, int &padding_bits);
nsapi_size_or_error_t get_data_from_pdu(const char* pdu, sms_info_t *info, int *part_number,
char *phone_number = NULL, char *msg = NULL);
nsapi_size_or_error_t read_pdu_payload(const char* pdu, int scheme, char *msg, int padding_bits, bool last_part);
sms_info_t* get_oldest_sms_index();
bool create_time(const char* time_string, time_t* time);
int compare_time_strings(const char* time_string_1, const char* time_string_2);
char* create_pdu(const char* phone_number, const char* message, uint8_t message_length, uint8_t msg_parts,
uint8_t msg_part_number);
nsapi_size_or_error_t read_sms_from_index(int msg_index, char* buf, uint16_t len, char* phone_num,
char* time_stamp);
nsapi_size_or_error_t read_sms(sms_info_t* sms, char* buf, char* phone_num, char* time_stamp);
/** Packs the given str from ascii to 7bit gsm format and converts it to hex to the given buf.
*
* @param str string which is to be converted
* @param len length of the str buffer
* @param buf preallocated buffer which holds the converted string in hex format after successful call
* @param number_of_padding_bit padding bits needed to keep the octet boundary
* @return length of buffer buf or zero on failure
*/
uint16_t pack_7_bit_gsm_and_hex(const char* str, uint16_t len, char *buf, int number_of_padding_bit);
/** Unpacks the given hex- and 7-bit gsm encoded str to ascii string
*
* @param str string which converted to ascii string to buf
* @param len length of the str divided by two as str is hexencoded
* @param buf preallocated destination buffer
* @param padding_bits number of padding bits which were needed to hold the octet boundary
* @param last_part true is last part of the encoded message
* @return length of the destination buffer buf
*
*/
uint16_t unpack_7_bit_gsm_to_str(const char* str, int len, char *buf, int padding_bits,
bool last_part);
};
} // namespace mbed
#endif // AT_CELLULAR_SMS_H_

View File

@ -0,0 +1,278 @@
/*
* 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 "AT_CellularStack.h"
#include "CellularUtil.h"
#include "CellularLog.h"
using namespace mbed_cellular_util;
using namespace mbed;
AT_CellularStack::AT_CellularStack(ATHandler &at, int cid, nsapi_ip_stack_t stack_type) : AT_CellularBase(at), _socket(NULL),_socket_count(0),_cid(cid), _stack_type(stack_type)
{
}
AT_CellularStack::~AT_CellularStack()
{
for (int i = 0; i < _socket_count; i++) {
if (_socket[i]) {
delete _socket[i];
}
}
delete [] _socket;
}
/** NetworkStack
*/
const char * AT_CellularStack::get_ip_address()
{
_at.lock();
_at.cmd_start("AT+CGPADDR=");
_at.write_int(_cid);
_at.cmd_stop();
_at.resp_start("+CGPADDR:");
if (_at.info_resp()) {
_at.skip_param();
int len = _at.read_string(_ip, NSAPI_IPv4_SIZE-1);
if (len == -1) {
_ip[0] = '\0';
_at.unlock();
// no IPV4 address, return
return NULL;
}
// 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);
}
}
_at.resp_stop();
_at.unlock();
// we have at least IPV4 address
convert_ipv6(_ip);
return _ip;
}
nsapi_error_t AT_CellularStack::socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto)
{
if (!is_protocol_supported(proto)) {
return NSAPI_ERROR_UNSUPPORTED;
}
int max_socket_count = get_max_socket_count();
if (!_socket) {
_socket = new CellularSocket*[max_socket_count];
if (!_socket) {
return NSAPI_ERROR_NO_SOCKET;
}
_socket_count = max_socket_count;
for (int i = 0; i < max_socket_count; i++) {
_socket[i] = 0;
}
}
int index = -1;
for (int i = 0; i < max_socket_count; i++) {
if (!_socket[i]) {
index = i;
break;
}
}
if (index == -1) {
return NSAPI_ERROR_NO_SOCKET;
}
// create local socket structure, socket on modem is created when app calls sendto/recvfrom
_socket[index] = new CellularSocket;
CellularSocket *psock;
psock = _socket[index];
memset(psock, 0, sizeof(CellularSocket));
SocketAddress addr(0, get_dynamic_ip_port());
psock->id = index;
psock->localAddress = addr;
psock->proto = proto;
*handle = psock;
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularStack::socket_close(nsapi_socket_t handle)
{
int err = NSAPI_ERROR_DEVICE_ERROR;
struct CellularSocket *socket = (struct CellularSocket *)handle;
int sock_id = socket->id;
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) {
index = i;
break;
}
}
if (index != -1) {
_socket[index] = NULL;
err = NSAPI_ERROR_OK;
}
_at.lock();
//_atHandler.setTimeout(...)
err = socket_close_impl(sock_id);
_at.unlock();
delete socket;
return err;
}
nsapi_error_t AT_CellularStack::socket_bind(nsapi_socket_t handle, const SocketAddress &addr)
{
struct CellularSocket *socket = (CellularSocket *)handle;
socket->localAddress = addr;
_at.lock();
if (!socket->created) {
create_socket_impl(socket);
}
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularStack::socket_listen(nsapi_socket_t handle, int backlog)
{
return 0;
}
nsapi_error_t AT_CellularStack::socket_connect(nsapi_socket_t handle, const SocketAddress &addr)
{
CellularSocket *socket = (CellularSocket *)handle;
socket->remoteAddress = addr;
socket->connected = true;
return NSAPI_ERROR_OK;
}
nsapi_error_t AT_CellularStack::socket_accept(void *server, void **socket, SocketAddress *addr)
{
return 0;
}
nsapi_size_or_error_t AT_CellularStack::socket_send(nsapi_socket_t handle, const void *data, unsigned size)
{
CellularSocket *socket = (CellularSocket *)handle;
if (!socket->connected) {
return NSAPI_ERROR_DEVICE_ERROR;
}
return socket_sendto(handle, socket->remoteAddress, data, size);
}
nsapi_size_or_error_t AT_CellularStack::socket_sendto(nsapi_socket_t handle, const SocketAddress &addr, const void *data, unsigned size)
{
CellularSocket *socket = (CellularSocket *)handle;
nsapi_size_or_error_t ret_val = NSAPI_ERROR_OK;
if (!socket->created) {
_at.lock();
ret_val = create_socket_impl(socket);
_at.unlock();
if (ret_val != NSAPI_ERROR_OK) {
return ret_val;
}
}
unsigned max_packet_size = get_max_packet_size();
/* Check parameters */
if (addr.get_ip_version() == NSAPI_UNSPEC ||
size > max_packet_size) {
return NSAPI_ERROR_DEVICE_ERROR;
}
_at.lock();
ret_val = socket_sendto_impl(socket, addr, data, size);
_at.unlock();
return ret_val;
}
nsapi_size_or_error_t AT_CellularStack::socket_recv(nsapi_socket_t handle, void *data, unsigned size)
{
return socket_recvfrom(handle, NULL, data, size);
}
nsapi_size_or_error_t AT_CellularStack::socket_recvfrom(nsapi_socket_t handle, SocketAddress *addr, void *buffer, unsigned size)
{
CellularSocket *socket = (CellularSocket *)handle;
nsapi_size_or_error_t ret_val = NSAPI_ERROR_OK;
if (!socket->created) {
_at.lock();
ret_val = create_socket_impl(socket);
_at.unlock();
if (ret_val != NSAPI_ERROR_OK) {
return ret_val;
}
}
unsigned max_packet_size = get_max_packet_size();
/* Check parameters */
if (size < max_packet_size) {
log_warn("Socket receive buffer smaller than max packet size! size:%d max_packet_size:%d", size, max_packet_size);
}
_at.lock();
ret_val = socket_recvfrom_impl(socket, addr, buffer, size);
_at.unlock();
return ret_val;
}
void AT_CellularStack::socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data)
{
CellularSocket *socket = (CellularSocket *)handle;
socket->_cb = callback;
socket->_data = data;
}

View File

@ -0,0 +1,310 @@
/*
* 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 AT_CELLULAR_STACK_H_
#define AT_CELLULAR_STACK_H_
#include "AT_CellularBase.h"
#include "NetworkStack.h"
namespace mbed {
// <PDP_addr_1> and <PDP_addr_2>: each is a string type that identifies the MT in the address space applicable to the PDP.
// The string is given as dot-separated numeric (0-255) parameter of the form:
// a1.a2.a3.a4 for IPv4 and
// a1.a2.a3.a4.a5.a6.a7.a8.a9.a10.a11.a12.a13.a14.a15.a16 for IPv6.
#define PDP_IPV6_SIZE 63+1
/**
* Class AT_CellularStack.
*
* Implements NetworkStack and introduces interface for modem specific stack implementations.
*/
class AT_CellularStack : public NetworkStack, public AT_CellularBase
{
public:
AT_CellularStack(ATHandler &at, int cid, nsapi_ip_stack_t stack_type);
virtual ~AT_CellularStack();
public: // NetworkStack
/** Get the local IP address
*
* @return Null-terminated representation of the local IP address
* or null if not yet connected
*/
virtual const char *get_ip_address();
/** Opens a socket
*
* Creates a network socket and stores it in the specified handle.
* The handle must be passed to following calls on the socket.
*
* A stack may have a finite number of sockets, in this case
* NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
*
* @param handle Destination for the handle to a newly created socket
* @param proto Protocol of socket to open, NSAPI_TCP or NSAPI_UDP
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto);
/** Close the socket
*
* Closes any open connection and deallocates any memory associated
* with the socket.
*
* @param handle Socket handle
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_close(nsapi_socket_t handle);
/** Bind a specific address to a socket
*
* Binding a socket specifies the address and port on which to recieve
* data. If the IP address is zeroed, only the port is bound.
*
* @param handle Socket handle
* @param address Local address to bind
* @return 0 on success, negative error code on failure.
*/
virtual nsapi_error_t socket_bind(nsapi_socket_t handle, const SocketAddress &address);
/** Listen for connections on a TCP socket
*
* Marks the socket as a passive socket that can be used to accept
* incoming connections.
*
* @param handle Socket handle
* @param backlog Number of pending connections that can be queued
* simultaneously
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_listen(nsapi_socket_t handle, int backlog);
/** Connects TCP socket to a remote host
*
* Initiates a connection to a remote server specified by the
* indicated address.
*
* @param handle Socket handle
* @param address The SocketAddress of the remote host
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_connect(nsapi_socket_t handle, const SocketAddress &address);
/** Accepts a connection on a TCP socket
*
* The server socket must be bound and set to listen for connections.
* On a new connection, creates a network socket and stores it in the
* specified handle. The handle must be passed to following calls on
* the socket.
*
* A stack may have a finite number of sockets, in this case
* NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
*
* This call is non-blocking. If accept would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param server Socket handle to server to accept from
* @param handle Destination for a handle to the newly created socket
* @param address Destination for the remote address or NULL
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_accept(nsapi_socket_t server,
nsapi_socket_t *handle, SocketAddress *address=0);
/** Send data over a TCP socket
*
* The socket must be connected to a remote host. Returns the number of
* bytes sent from the buffer.
*
* This call is non-blocking. If send would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Socket handle
* @param data Buffer of data to send to the host
* @param size Size of the buffer in bytes
* @return Number of sent bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_send(nsapi_socket_t handle,
const void *data, nsapi_size_t size);
/** Receive data over a TCP socket
*
* The socket must be connected to a remote host. Returns the number of
* bytes received into the buffer.
*
* This call is non-blocking. If recv would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Socket handle
* @param data Destination buffer for data received from the host
* @param size Size of the buffer in bytes
* @return Number of received bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_recv(nsapi_socket_t handle,
void *data, nsapi_size_t size);
/** Send a packet over a UDP socket
*
* Sends data to the specified address. Returns the number of bytes
* sent from the buffer.
*
* This call is non-blocking. If sendto would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Socket handle
* @param address The SocketAddress of the remote host
* @param data Buffer of data to send to the host
* @param size Size of the buffer in bytes
* @return Number of sent bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_sendto(nsapi_socket_t handle, const SocketAddress &address,
const void *data, nsapi_size_t size);
/** Receive a packet over a UDP socket
*
* Receives data and stores the source address in address if address
* is not NULL. Returns the number of bytes received into the buffer.
*
* This call is non-blocking. If recvfrom would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param handle Socket handle
* @param address Destination for the source address or NULL
* @param buffer Destination buffer for data received from the host
* @param size Size of the buffer in bytes
* @return Number of received bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_recvfrom(nsapi_socket_t handle, SocketAddress *address,
void *buffer, nsapi_size_t size);
/** Register a callback on state change of the socket
*
* The specified callback will be called on state changes such as when
* the socket can recv/send/accept successfully and on when an error
* occurs. The callback may also be called spuriously without reason.
*
* The callback may be called in an interrupt context and should not
* perform expensive operations such as recv/send calls.
*
* @param handle Socket handle
* @param callback Function to call on state change
* @param data Argument to pass to callback
*/
virtual void socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data);
protected:
class CellularSocket
{
public:
// Socket id from cellular device
int id;
// Being connected means remote ip address and port are set
bool connected;
nsapi_protocol_t proto;
SocketAddress remoteAddress;
SocketAddress localAddress;
void (*_cb)(void *);
void *_data;
bool created;
bool rx_avail; // used to synchronise reading from modem
};
/**
* Gets maximum number of sockets modem supports
*/
virtual int get_max_socket_count() = 0;
/**
* Gets maximum packet size
*/
virtual int get_max_packet_size() = 0;
/**
* Checks if modem supports the given protocol
*
* @param protocol Protocol type
*/
virtual bool is_protocol_supported(nsapi_protocol_t protocol) = 0;
/**
* Implements modem specific AT command set for socket closing
*
* @param sock_id Socket id
*/
virtual nsapi_error_t socket_close_impl(int sock_id) = 0;
/**
* Implements modem specific AT command set for creating socket
*
* @param socket Cellular socket handle
*/
virtual nsapi_error_t create_socket_impl(CellularSocket *socket) = 0;
/**
* Implements modem specific AT command set for sending data
*
* @param socket Cellular socket handle
* @param address The SocketAddress of the remote host
* @param data Buffer of data to send to the host
* @param size Size of the buffer in bytes
* @return Number of sent bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_sendto_impl(CellularSocket *socket, const SocketAddress &address,
const void *data, nsapi_size_t size) = 0;
/**
* Implements modem specific AT command set for receiving data
*
* @param socket Socket handle
* @param address Destination for the source address or NULL
* @param buffer Destination buffer for data received from the host
* @param size Size of the buffer in bytes
* @return Number of received bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address,
void *buffer, nsapi_size_t size) = 0;
// socket container
CellularSocket **_socket;
// number of socket slots allocated in socket container
int _socket_count;
// IP address
char _ip[PDP_IPV6_SIZE];
// PDP context id
int _cid;
// stack type from PDP context
nsapi_ip_stack_t _stack_type;
};
} // namespace mbed
#endif // AT_CELLULAR_STACK_H_

View File

@ -0,0 +1,102 @@
/*
* 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_LIST_H_
#define CELLULAR_LIST_H_
#include <stddef.h>
namespace mbed {
/** Class CellularList
*
* Templated linked list class for common usage.
*
*/
template <class T> class CellularList
{
private:
T *_head, *_tail;
public:
CellularList()
{
_head=NULL;
_tail=NULL;
}
T* add_new()
{
T *temp=new T;
if (!temp) {
return NULL;
}
temp->next = NULL;
if (_head == NULL) {
_head = temp;
} else {
_tail->next=temp;
}
_tail = temp;
return _tail;
}
void delete_last()
{
T* previous = NULL;
T *current=_head;
if (!current) {
return;
}
while (current->next != NULL) {
previous=current;
current=current->next;
}
if (previous) {
_tail=previous;
previous->next=NULL;
} else {
_head = NULL;
_tail = NULL;
}
delete current;
}
void delete_all()
{
T *temp = _head;
while (temp) {
_head = _head->next;
delete temp;
temp = _head;
}
}
T *get_head()
{
return _head;
}
};
} // namespace mbed
#endif // CELLULAR_LIST_H_

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) , 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 <stdarg.h>
#include <stddef.h>
#include "CellularLog.h"
#include "us_ticker_api.h"
#include "serial_api.h"
#include "rtos/Mutex.h"
extern serial_t stdio_uart;
extern int stdio_uart_inited;
namespace mbed {
uint32_t cellular_log_time = us_ticker_read() / 1000L;
/**
* Local mutex object for synchronization
*/
static rtos::Mutex mutex;
/**
* Lock provided for serial printing used by trace library
*/
static void serial_lock()
{
mutex.lock();
}
/**
* Releasing lock provided for serial printing used by trace library
*/
static void serial_unlock()
{
mutex.unlock();
}
void log_init(PinName tx, PinName rx, int baud)
{
#ifdef FEATURE_COMMON_PAL
mbed_trace_mutex_wait_function_set(serial_lock);
mbed_trace_mutex_release_function_set(serial_unlock);
mbed_trace_init();
#else
/*UARTSerial trace_serial(tx, rx, baud);
FILE *trace = fdopen(&trace_serial, "w");*/
serial_init(&stdio_uart, tx, rx);
serial_baud(&stdio_uart, baud);
stdio_uart_inited = 1;
#endif
log_info("\r\n\r\n**************************************");
log_info("Hellular says Cellular Hello!");
log_info("Build time %s %s", __DATE__, __TIME__);
}
} // namespace mbed

View File

@ -0,0 +1,82 @@
/*
* 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_LOG_H_
#define CELLULAR_LOG_H_
#include <stdint.h>
#ifdef FEATURE_COMMON_PAL
#include <stdarg.h>
#endif // FEATURE_COMMON_PAL
#include "PinNames.h"
#include "us_ticker_api.h"
#include "mbed_debug.h"
namespace mbed {
/** this print is some deep information for debug purpose */
#define TRACE_LEVEL_DEBUG 0x10
/** Info print, for general purpose prints */
#define TRACE_LEVEL_INFO 0x08
/** warning prints, which shouldn't causes any huge problems */
#define TRACE_LEVEL_WARN 0x04
/** Error prints, which causes probably problems, e.g. out of mem. */
#define TRACE_LEVEL_ERROR 0x02
/** special level for cmdline. Behaviours like "plain mode" */
#define TRACE_LEVEL_CMD 0x01
#define TRACE_GROUP "cellular"
#ifndef MBED_TRACE_MAX_LEVEL
#define MBED_TRACE_MAX_LEVEL TRACE_LEVEL_ERROR
#endif
#ifdef FEATURE_COMMON_PAL
#include "mbed-trace/mbed_trace.h"
#define log_debug tr_debug
#define log_info tr_info
#define log_warn tr_warn
#define log_error tr_error
#else
extern uint32_t cellular_log_time;
#if (MBED_TRACE_MAX_LEVEL >= TRACE_LEVEL_DEBUG)
#define log_debug(format, ...) do { debug("DEBUG" " [" TRACE_GROUP " %ums] " format "\r\n", (us_ticker_read()-cellular_log_time) / 1000L, ## __VA_ARGS__); } while (0)
#else
#define log_debug(...)
#endif
#if (MBED_TRACE_MAX_LEVEL >= TRACE_LEVEL_INFO)
#define log_info(format, ...) do { debug("INFO" " [" TRACE_GROUP " %ums] " format "\r\n", (us_ticker_read()-cellular_log_time) / 1000L, ## __VA_ARGS__); } while (0)
#else
#define log_info(...)
#endif
#if (MBED_TRACE_MAX_LEVEL >= TRACE_LEVEL_WARN)
#define log_warn(format, ...) do { debug("WARN" " [" TRACE_GROUP " %ums] " format "\r\n", (us_ticker_read()-cellular_log_time) / 1000L, ## __VA_ARGS__); } while (0)
#else
#define log_warn(...)
#endif
#if (MBED_TRACE_MAX_LEVEL >= TRACE_LEVEL_ERROR)
#define log_error(format, ...) do { debug("ERROR" " [" TRACE_GROUP " %ums] " format "\r\n", (us_ticker_read()-cellular_log_time) / 1000L, ## __VA_ARGS__); } while (0)
#else
#define log_error(...)
#endif
#endif
extern void log_init(PinName tx, PinName rx, int baud);
} // namespace mbed
#endif // CELLULAR_LOG_H_

View File

@ -0,0 +1,47 @@
/*
* 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_TARGETS_H_
#define CELLULAR_TARGETS_H_
namespace mbed {
#define UART 1
#define MUX 2
#ifndef CELLULAR_DEVICE
#if defined(TARGET_ADV_WISE_1570) || defined(TARGET_MTB_ADV_WISE_1570)
#define CELLULAR_DEVICE QUECTEL_BC95
#elif TARGET_MTS_DRAGONFLY_F411RE
#define CELLULAR_DEVICE TELIT_HE910
#elif TARGET_MTB_MTS_DRAGONFLY
#define CELLULAR_DEVICE TELIT_HE910
#elif TARGET_UBLOX_C030
#define CELLULAR_DEVICE UBLOX_C027
#elif TARGET_UBLOX_C027
#define CELLULAR_DEVICE UBLOX_C027
#else
#error Cellular target not defined, see cellular/targets.h
//#define CELLULAR_TARGET <target-modem>
//#define MDMTXD <pin-name>
//#define MDMRXD <pin-name>
#endif
#endif
} // namespace mbed
#endif // CELLULAR_TARGETS_H_

View File

@ -0,0 +1,326 @@
/*
* Copyright (c) , 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 "CellularUtil.h"
#include <string.h>
#include <stdlib.h>
namespace mbed_cellular_util {
void convert_ipv6(char* ip)
{
if (!ip) {
return;
}
int len = strlen(ip);
int pos = 0;
int i;
for (i = 0; i < len; i++) {
if (ip[i] == '.') {
pos++;
}
if (pos > 3) {
break;
}
}
// more that 3 periods mean that it was ipv6 but in format of a1.a2.a3.a4.a5.a6.a7.a8.a9.a10.a11.a12.a13.a14.a15.a16
// we need to convert it to hexadecimal format separated with colons
if (pos > 3) {
pos = 0;
int ip_pos = 0;
char b;
bool set_colon = false;
for (i = 0; i < len; i++) {
if (ip[i] == '.') {
b = (char)strtol (ip+ip_pos, NULL, 10); // convert to char to int so we can change it to hex string
pos += char_str_to_hex_str(&b, 1, ip+pos, !set_colon); // omit leading zeroes with using set_colon flag
if (set_colon) {
ip[pos++] = ':';
set_colon = false;
} else {
set_colon = true;
}
ip_pos = i+1; // skip the '.'
}
// handle the last part which does not end with '.' but '\0'
if (i == len -1) {
b = (char)strtol(ip+ip_pos, NULL, 10);
pos += char_str_to_hex_str(&b, 1, ip+pos, !set_colon);
ip[pos] = '\0';
}
}
}
}
// For example "32.1.13.184.0.0.205.48.0.0.0.0.0.0.0.0"
void separate_ip4like_addresses(char* orig, char* ip, size_t ip_size, char* ip2, size_t ip2_size)
{
// ipv4-like notation
int len = strlen(orig);
int count = 0, i = 0, pos = 0;
char *temp;
for (; i < len; i++) {
if (orig[i] == '.') {
count++;
if (count == 4) {
pos = i;
} else if (count == 16) {
pos = i;
}
}
}
if (count == 3) { // normal ipv4, copy to ip
if (ip_size > strlen(orig)) {
memcpy(ip, orig, strlen(orig));
ip[strlen(orig)] = '\0';
} else {
ip[0] = '\0';
}
if (ip2) {
ip2[0] = '\0';
}
} else if (count == 7) { // ipv4 and subnet mask. Need to separate those.
temp = &orig[pos];
if ((uint8_t)ip_size > temp-orig) {
memcpy(ip, orig, temp-orig);
ip[temp-orig] = '\0';
}
temp++; // skip the '.'
if (ip2 && (ip2_size > strlen(temp))) {
memcpy(ip2, temp, strlen(temp));
ip2[strlen(temp)] = '\0';
}
} else if (count == 15) { // only one ipv6 address in ipv4-like notation
if (ip_size > strlen(orig)) {
memcpy(ip, orig, strlen(orig));
ip[strlen(orig)] = '\0';
convert_ipv6(ip);
} else {
ip[0] = '\0';
}
if (ip2) {
ip2[0] = '\0';
}
} else if (count == 31){ // ipv6 + ipv6subnet mask in ipv4-like notation separated by dot '.'
temp = &orig[pos];
if ((uint8_t)ip_size > temp-orig) {
memcpy(ip, orig, temp-orig);
ip[temp-orig] = '\0';
convert_ipv6(ip);
}
temp++; // skip the '.'
if (ip2 && (ip2_size > strlen(temp))) {
memcpy(ip2, temp, strlen(temp));
ip2[strlen(temp)] = '\0';
convert_ipv6(ip2);
}
}
}
void separate_ip_addresses(char* orig, char* ip, size_t ip_size, char* ip2, size_t ip2_size)
{
// orig can include ipv4, ipv6, both or two ip4/ipv6 addresses.
// also format depends on possible AT+CGPIAF
if (!orig || !ip) {
if (ip) {
ip[0] = '\0';
}
if (ip2) {
ip2[0] = '\0';
}
return;
}
// 1. try to found ':'. If it's found then we know that possible addresses are separated with space
char *temp;
temp = strchr(orig, ':');
if (temp != NULL) {
// found ':'
temp = strstr(orig, " ");
// found space as separator and it wasn't in beginning --> contains 2 ip addresses
if (temp && temp != orig) {
if ((uint8_t)ip_size > temp-orig) {
memcpy(ip, orig, temp-orig);
ip[temp-orig] = '\0';
} else {
ip[0] = '\0';
}
temp++; // skip the space
if (ip2 && (ip2_size > strlen(temp))) {
memcpy(ip2, temp, strlen(temp));
ip2[strlen(temp)] = '\0';
} else {
ip2[0] = '\0';
}
} else {
// Space was the first char or no space found ---> only one ip, copy to ip
size_t size = strlen(orig);
if (temp) {
size = strlen(temp);
}
if (ip_size > size) {
memcpy(ip, orig, size);
ip[size] = '\0';
} else {
ip[0] = '\0';
}
if (ip2) {
ip2[0] = '\0';
}
}
} else {
temp = strstr(orig, " ");
// found space as separator and it wasn't in beginning --> contains 2 ip addresses
if (temp && temp != orig) {
separate_ip4like_addresses(temp++, ip2, ip2_size, NULL, 0);
orig[temp-orig-1] = '\0';
separate_ip4like_addresses(orig, ip, ip_size, NULL, 0);
orig[temp-orig-1] = ' '; // put space back to keep orig as original
}
else {
separate_ip4like_addresses(orig, ip, ip_size, ip2, ip2_size);
}
}
}
void prefer_ipv6(char* ip, size_t ip_size, char* ip2, size_t ip2_size)
{
if (!ip || !ip2) {
return;
}
// assume that that ipv6 is already in formatted to use ':'
// 1. try to found ':'. If it's found then we know that this is ipv6
char *temp;
temp = strchr(ip, ':');
if (temp) {
// ip has ipv6 address, we can leave
return;
} else {
// ip was not ipv6, check if ip2 is
temp = strchr(ip2, ':');
if (temp) {
// ipv6 was found in ip2 but not in ip ---> we must swap them. Sadly ip and ip2 might not be pointers
// so we can't just swap them, must use copy.
if (strlen(ip) < ip2_size && strlen(ip2) < ip_size && strlen(ip) < 64) {
char tmp[64];
strncpy(tmp, ip, strlen(ip));
tmp[strlen(ip)] = '\0';
strncpy(ip, ip2, strlen(ip2));
ip[strlen(ip2)] = '\0';
strncpy(ip2, tmp, strlen(tmp));
ip2[strlen(tmp)] = '\0';
}
}
}
}
void int_to_hex_str(uint8_t num, char* buf)
{
char charNum = num;
char_str_to_hex_str(&charNum, 1, buf);
}
int hex_str_to_int(const char *hex_string, int hex_string_length)
{
const int base = 16;
int character_as_integer, integer_output = 0;
for (int i=0;i<hex_string_length && hex_string[i] != '\0';i++) {
if (hex_string[i] >= '0' && hex_string[i] <= '9') {
character_as_integer = hex_string[i] - '0';
} else if (hex_string[i] >= 'A' && hex_string[i] <= 'F') {
character_as_integer = hex_string[i] - 'A' + 10;
} else {
character_as_integer = hex_string[i] - 'a' + 10;
}
integer_output *= base;
integer_output += character_as_integer;
}
return integer_output;
}
int hex_str_to_char_str(const char* str, uint16_t len, char *buf)
{
int strcount = 0;
for (int i = 0; i+1 < len; i += 2) {
int upper = hex_str_to_int(str+i, 1);
int lower = hex_str_to_int(str+i+1, 1);
buf[strcount] = ((upper<<4) & 0xF0) | (lower & 0x0F);
strcount++;
}
return strcount;
}
void uint_to_binary_str(uint32_t num, char* str, int str_size, int bit_cnt)
{
if (!str || str_size < bit_cnt) {
return;
}
int tmp, pos = 0;
for (int i = 31; i >= 0; i--) {
tmp = num >> i;
if (i < bit_cnt) {
if (tmp&1) {
str[pos] = 1 + '0';
} else {
str[pos] = 0 + '0';
}
pos++;
}
}
}
int char_str_to_hex_str(const char* str, uint16_t len, char *buf, bool omit_leading_zero)
{
if (!str || !buf) {
return 0;
}
char *ptr = buf;
int i=0;
while (i < len) {
if (omit_leading_zero == true && i == 0 && !(str[i]>>4 & 0x0F)) {
*ptr++ = hex_values[(str[i]) & 0x0F];
} else {
*ptr++ = hex_values[((str[i])>>4) & 0x0F];
*ptr++ = hex_values[(str[i]) & 0x0F];
}
i++;
}
return ptr-buf;
}
uint16_t get_dynamic_ip_port()
{
static uint16_t port;
port++;
if (port < 49152) {
port = 49152;
}
return port;
}
} // namespace mbed_cellular_util

View File

@ -0,0 +1,116 @@
/*
* 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_UTIL_H_
#define CELLULAR_UTIL_H_
#include <stddef.h>
#include <stdint.h>
namespace mbed_cellular_util {
// some helper macros
#define EMPTY_CHECK(val) (val ## 1)
#define EMPTY(val) (EMPTY_CHECK(val) == 1)
#define _CELLULAR_STRINGIFY(a) #a
#define CELLULAR_STRINGIFY(a) _CELLULAR_STRINGIFY(a)
static const char hex_values[] = "0123456789ABCDEF";
/** Converts the given ip address to proper IPv6 address if needed.
* Conversion is done only if it's NOT IPv4 and separated with colons.
* AT command +CGPADDR can give IP address in format of a1.a2.a3.a4.a5.a6.a7.a8.a9.a10.a11.a12.a13.a14.a15.a16 for IPv6
* where ax are in decimal format. In this case function converts decimals to hex with separated with colons.
*
* @param ip ip address which can be IPv4 or IPv6 in different formats from AT command +CGPADDR. Converted result uses same buffer.
*/
void convert_ipv6(char* ip);
/** Separates ip addresses from the given 'orig' string. 'orig' may contain zero, one or two ip addresses in various formats.
* See AT command +CGPIAF from 3GPP TS 27.007 for details. Does also needed conversions for ipv6 addresses.
*
* @param orig original string which contains zero, one or two ip addressees in various formats
* @param ip preallocated buffer which might contain ip address after return
* @param ip_size size of preallocated buffer ip
* @param ip2 preallocated buffer which might contain ip address after return
* @param ip2_size size of preallocated buffer ip2
*
*/
void separate_ip_addresses(char* orig, char* ip, size_t ip_size, char* ip2, size_t ip2_size);
/** Swaps the arrays if param ip does not contain ipv6 address but param ip2 does.
*
* @param ip ip address
* @param ip_size size of buffer ip
* @param ip2 ip address
* @param ip2_size size of buffer ip2
*/
void prefer_ipv6(char* ip, size_t ip_size, char* ip2, size_t ip2_size);
/** Converts the given int to two hex characters
*
* @param num number to be converted to hex string
* @param buf preallocated buffer which will contain 2 char length hex value
*/
void int_to_hex_str(uint8_t num, char* buf);
/** Converts the given buffer 'str' to hex buffer 'buf. First 'len' char's are converted to two hex bytes.
*
* @param str char buffer which is to be converted to hex
* @param len how many chars from str are to be converted
* @param buf destination buffer for hex converted chars. Buffer should be double the size of str to fit hex-encoded string.
* @param omit_leading_zero if true then possible leading zeroes are omitted
*/
int char_str_to_hex_str(const char* str, uint16_t len, char *buf, bool omit_leading_zero = false);
/** Converts the given hex string to integer
*
* @param hex_string hex string from where chars are converted to int
* @param hex_string_length length of the param hex_string
* @return hex_string converted to int
*/
int hex_str_to_int(const char *hex_string, int hex_string_length);
/** Converts the given hex string str to char string to buf
*
* @param str hex string which is converted to char string to buf
* @param len length of the param str/how many hex are converted
* @param buf preallocated buffer where result conversion is stored
* @return length of the buf
*/
int hex_str_to_char_str(const char* str, uint16_t len, char *buf);
/** Converts the given uint to binary string. Fills the given str starting from [0] with the number of bits defined by bit_cnt
* For example uint_to_binary_string(9, str, 10) would fill str "0000001001"
* For example uint_to_binary_string(9, str, 3) would fill str "001"
*
* @param num uint to converts to binary string
* @param str buffer for converted binary string
* @param str_size size of the str buffer
* @param bit_cnt defines how many bits are filled to buffer started from lsb
*/
void uint_to_binary_str(uint32_t num, char* str, int str_size, int bit_cnt);
/** Get dynamic port for socket
*
* @return next port number above 49152
*/
uint16_t get_dynamic_ip_port();
} // namespace mbed_cellular_util
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,565 @@
/*
* Copyright (c) 2006-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 MUX_H
#define MUX_H
#include <stdbool.h>
#include "FileHandle.h"
#include "PlatformMutex.h"
#include "Semaphore.h"
#include "EventQueue.h"
#define MUX_DLCI_INVALID_ID 0 /* Invalid DLCI ID. Used to invalidate MuxDataService object. */
#define MUX_CRC_TABLE_LEN 256u /* CRC table length in number of bytes. */
#ifndef MBED_CONF_MUX_DLCI_COUNT
#define MBED_CONF_MUX_DLCI_COUNT 3u /* Number of supported DLCI IDs. */
#endif
#ifndef MBED_CONF_MUX_BUFFER_SIZE
#define MBED_CONF_MUX_BUFFER_SIZE 31u /* Size of TX/Rx buffers in number of bytes. */
#endif
/* More RAM needs to allocated if more than 4 DLCI ID to be supported see @ref tx_callback_context for details. */
MBED_STATIC_ASSERT(MBED_CONF_MUX_DLCI_COUNT <= 4u, "");
/* @todo:
I assume that we need to export some kind of #defines for EVENT_SIZE and MAX_EVENT_COUNT (max number of events that can
be queued at the same time by the module inside EventQueue, so that the application designer can calculate the RAM
storage requirements correctly at compile time.
*/
namespace mbed {
class MuxDataService : public FileHandle
{
friend class Mux;
public:
/** Enqueue user data for transmission.
*
* @note: This is API is only meant to be used for the multiplexer (user) data service tx. Supplied buffer can be
* reused/freed upon call return.
*
* @param buffer Begin of the user data.
* @param size The number of bytes to write.
* @return The number of bytes written.
*/
virtual ssize_t write(const void* buffer, size_t size);
/** Read user data into a buffer.
*
* @note: This is API is only meant to be used for the multiplexer (user) data service rx.
*
* @param buffer The buffer to read in to.
* @param size The number of bytes to read.
* @return The number of bytes read, -EAGAIN if no data available for read.
*/
virtual ssize_t read(void *buffer, size_t size);
/** Not supported by the implementation. */
virtual off_t seek(off_t offset, int whence = SEEK_SET);
/** Not supported by the implementation. */
virtual int close();
/** Register a callback on completion of enqueued write and read operations.
*
* @note: The registered callback is called within thread context supplied in eventqueue_attach.
*
* @param func Function to call upon event generation.
*/
virtual void sigio(Callback<void()> func);
/** Constructor. */
MuxDataService() : _dlci(MUX_DLCI_INVALID_ID) {};
private:
/* Deny copy constructor. */
MuxDataService(const MuxDataService& obj);
/* Deny assignment operator. */
MuxDataService& operator=(const MuxDataService& obj);
uint8_t _dlci; /* DLCI number. Valid range 1 - 63. */
Callback<void()> _sigio_cb; /* Registered signal callback. */
};
class Mux
{
friend class MuxDataService;
public:
/* Definition for multiplexer establishment status type. */
enum MuxEstablishStatus {
MUX_ESTABLISH_SUCCESS = 0, /* Peer accepted the request. */
MUX_ESTABLISH_REJECT, /* Peer rejected the request. */
MUX_ESTABLISH_TIMEOUT, /* Timeout occurred for the request. */
MUX_ESTABLISH_MAX /* Enumeration upper bound. */
};
/* @ref MuxEstablishStatus type assigned to _shared_memory variable, which has sizeof(uint8_t) storage class. Enforce
expected behaviour compile time. */
MBED_STATIC_ASSERT(sizeof(MuxEstablishStatus) == sizeof(uint8_t), "");
/* Definition for multiplexer establishment return code type. */
enum MuxReturnStatus {
MUX_STATUS_SUCCESS = 0,
MUX_STATUS_INPROGRESS,
MUX_STATUS_INVALID_RANGE,
MUX_STATUS_MUX_NOT_OPEN,
MUX_STATUS_NO_RESOURCE,
MUX_STATUS_MAX
};
/** Module init. */
static void module_init();
/** Establish the multiplexer control channel.
*
* @note: Relevant request specific parameters are fixed at compile time within multiplexer component.
* @note: Call returns when response from the peer is received, timeout or write error occurs.
*
* @param status Operation completion code.
*
* @return MUX_STATUS_SUCCESS Operation completed, check status for completion code.
* @return MUX_STATUS_INPROGRESS Operation not started, control channel open already in progress.
* @return MUX_STATUS_NO_RESOURCE Operation not started, multiplexer control channel already open.
*/
static MuxReturnStatus mux_start(MuxEstablishStatus &status);
/** Establish a DLCI.
*
* @note: Relevant request specific parameters are fixed at compile time within multiplexer component.
* @note: Call returns when response from the peer is received or timeout occurs.
*
* @warning: Not allowed to be called from callback context.
*
* @param dlci_id ID of the DLCI to establish. Valid range 1 - 63.
* @param status Operation completion code.
* @param obj Valid object upon status having MUX_ESTABLISH_SUCCESS, NULL upon failure.
*
* @return MUX_STATUS_SUCCESS Operation completed, check status for completion code.
* @return MUX_STATUS_INPROGRESS Operation not started, DLCI establishment already in progress.
* @return MUX_STATUS_INVALID_RANGE Operation not started, DLCI ID not in valid range.
* @return MUX_STATUS_MUX_NOT_OPEN Operation not started, no established multiplexer control channel exists.
* @return MUX_STATUS_NO_RESOURCE Operation not started, dlci_id, or all available DLCI ID resources,
* already in use.
*/
static MuxReturnStatus dlci_establish(uint8_t dlci_id, MuxEstablishStatus &status, FileHandle **obj);
/** Attach serial interface to the object.
*
* @param serial Serial interface to be used.
*/
static void serial_attach(FileHandle *serial);
/** Attach EventQueue interface to the object.
*
* @param event_queue Event queue interface to be used.
*/
static void eventqueue_attach(events::EventQueue *event_queue);
private:
/* Definition for Rx event type. */
enum RxEvent {
RX_READ = 0,
RX_RESUME,
RX_EVENT_MAX
};
/* Definition for Tx state machine. */
enum TxState {
TX_IDLE = 0,
TX_RETRANSMIT_ENQUEUE,
TX_RETRANSMIT_DONE,
TX_INTERNAL_RESP,
TX_NORETRANSMIT,
TX_STATE_MAX
};
/* Definition for Rx state machine. */
enum RxState {
RX_FRAME_START = 0,
RX_HEADER_READ,
RX_TRAILER_READ,
RX_SUSPEND,
RX_STATE_MAX
};
/* Definition for frame type within rx path. */
enum FrameRxType {
FRAME_RX_TYPE_SABM = 0,
FRAME_RX_TYPE_UA,
FRAME_RX_TYPE_DM,
FRAME_RX_TYPE_DISC,
FRAME_RX_TYPE_UIH,
FRAME_RX_TYPE_NOT_SUPPORTED,
FRAME_RX_TYPE_MAX
};
/* Definition for frame type within tx path. */
enum FrameTxType {
FRAME_TX_TYPE_SABM = 0,
FRAME_TX_TYPE_DM,
FRAME_TX_TYPE_UIH,
FRAME_TX_TYPE_MAX
};
/** Registered time-out expiration event. */
static void on_timeout();
/** Registered deferred call event in safe (thread context) supplied in eventqueue_attach. */
static void on_deferred_call();
/** Registered sigio callback from FileHandle. */
static void on_sigio();
/** Calculate fcs.
*
* @param buffer Input buffer.
* @param input_len Input length in number of bytes.
*
* @return Calculated fcs.
*/
static uint8_t fcs_calculate(const uint8_t *buffer, uint8_t input_len);
/** Construct sabm request message.
*
* @param dlci_id ID of the DLCI to establish
*/
static void sabm_request_construct(uint8_t dlci_id);
/** Construct dm response message.
*/
static void dm_response_construct();
/** Construct user information frame.
*
* @param dlci_id ID of the DLCI to establish
* @param buffer
* @param size
*/
static void user_information_construct(uint8_t dlci_id, const void *buffer, size_t size);
/** Do write operation if pending data available.
*/
static void write_do();
/** Generate Rx event.
*
* @param event Rx event
*/
static void rx_event_do(RxEvent event);
/** Rx event frame start read state.
*
* @return Number of bytes read, -EAGAIN if no data available.
*/
static ssize_t on_rx_read_state_frame_start();
/** Rx event header read state.
*
* @return Number of bytes read, -EAGAIN if no data available.
*/
static ssize_t on_rx_read_state_header_read();
/** Rx event trailer read state.
*
* @return Number of bytes read, -EAGAIN if no data available.
*/
static ssize_t on_rx_read_state_trailer_read();
/** Rx event suspend read state.
*
* @return Number of bytes read, -EAGAIN if no data available.
*/
static ssize_t on_rx_read_state_suspend();
/** Process received SABM frame. */
static void on_rx_frame_sabm();
/** Process received UA frame. */
static void on_rx_frame_ua();
/** Process received DM frame. */
static void on_rx_frame_dm();
/** Process received DISC frame. */
static void on_rx_frame_disc();
/** Process received UIH frame. */
static void on_rx_frame_uih();
/** Process received frame, which is not supported. */
static void on_rx_frame_not_supported();
/** Process valid received frame. */
static void valid_rx_frame_decode();
/** SABM frame tx path post processing. */
static void on_post_tx_frame_sabm();
/** DM frame tx path post processing. */
static void on_post_tx_frame_dm();
/** UIH frame tx path post processing. */
static void on_post_tx_frame_uih();
/** Resolve rx frame type.
*
* @return Frame type.
*/
static Mux::FrameRxType frame_rx_type_resolve();
/** Resolve tx frame type.
*
* @return Frame type.
*/
static Mux::FrameTxType frame_tx_type_resolve();
/** Begin the frame retransmit sequence. */
static void frame_retransmit_begin();
/** TX state entry functions. */
static void tx_retransmit_enqueu_entry_run();
static void tx_retransmit_done_entry_run();
static void tx_idle_entry_run();
static void tx_internal_resp_entry_run();
static void tx_noretransmit_entry_run();
typedef void (*tx_state_entry_func_t)();
/** TX state exit function. */
static void tx_idle_exit_run();
typedef void (*tx_state_exit_func_t)();
/** Change Tx state machine state.
*
* @param new_state State to transit.
* @param entry_func State entry function.
* @param exit_func State exit function.
*/
static void tx_state_change(TxState new_state, tx_state_entry_func_t entry_func, tx_state_exit_func_t exit_func);
/** RX state entry functions. */
static void rx_header_read_entry_run();
typedef void (*rx_state_entry_func_t)();
/** Null action function. */
static void null_action();
/** Change Rx state machine state.
*
* @param new_state State to transit.
* @param entry_func State entry function.
*/
static void rx_state_change(RxState new_state, rx_state_entry_func_t entry_func);
/** Begin DM frame transmit sequence. */
static void dm_response_send();
/** Append DLCI ID to storage.
*
* @param dlci_id ID of the DLCI to append.
*/
static void dlci_id_append(uint8_t dlci_id);
/** Get file handle based on DLCI ID.
*
* @param dlci_id ID of the DLCI used as the key
*
* @return Valid object reference or NULL if not found.
*/
static MuxDataService* file_handle_get(uint8_t dlci_id);
/** Evaluate is DLCI ID in use.
*
* @param dlci_id ID of the DLCI yo evaluate
*
* @return True if in use, false otherwise.
*/
static bool is_dlci_in_use(uint8_t dlci_id);
/** Evaluate is DLCI ID queue full.
*
* @return True if full, false otherwise.
*/
static bool is_dlci_q_full();
/** Begin pending self iniated multiplexer open sequence. */
static void pending_self_iniated_mux_open_start();
/** Begin pending self iniated DLCI establishment sequence. */
static void pending_self_iniated_dlci_open_start();
/** Begin pending peer iniated DLCI establishment sequence.
*
* @param dlci_id ID of the DLCI to establish.
*/
static void pending_peer_iniated_dlci_open_start(uint8_t dlci_id);
/** Enqueue user data for transmission.
*
* @note: This is API is only meant to be used for the multiplexer (user) data service tx. Supplied buffer can be
* reused/freed upon call return.
*
* @param dlci_id ID of the DLCI to use.
* @param buffer Begin of the user data.
* @param size The number of bytes to write.
* @return The number of bytes written, negative error on failure.
*/
static ssize_t user_data_tx(uint8_t dlci_id, const void* buffer, size_t size);
/** Read user data into a buffer.
*
* @note: This is API is only meant to be used for the multiplexer (user) data service rx.
*
* @param buffer The buffer to read in to.
* @param size The number of bytes to read.
* @return The number of bytes read, -EAGAIN if no data availabe for read.
*/
static ssize_t user_data_rx(void* buffer, size_t size);
/** Clear TX callback pending bit.
*
* @param bit Bit to clear.
*/
static void tx_callback_pending_bit_clear(uint8_t bit);
/** Set TX callback pending bit for supplied DLCI ID.
*
* @param dlci_id DLCI ID for bit to set.
*/
static void tx_callback_pending_bit_set(uint8_t dlci_id);
/** Advance the current TX callback index bit.
*
* @return The current TX callback index bit after advanced.
*/
static uint8_t tx_callback_index_advance();
/** Get the TX callback pending bitmask.
*
* @return TX callback pending bitmask.
*/
static uint8_t tx_callback_pending_mask_get();
/** Dispatch TX callback based on supplied bit.
*
* @param bit Bit indetifier of callback to dispatch.
*/
static void tx_callback_dispatch(uint8_t bit);
/** Run main processing loop for resolving pending TX callbacks and dispatching them if they exists.
*/
static void tx_callbacks_run();
/** Get data service object based on supplied bit id.
*
* @param bit Bit indetifier of data service object to get.
* @return Data service object reference.
*/
static MuxDataService& tx_callback_lookup(uint8_t bit);
/** Get minimum of 2 supplied paramaters.
*
* @param size_1 1st param for comparisation.
* @param size_2 2nd param for comparisation.
* @return Minimum of supplied paramaters.
*/
static size_t min(uint8_t size_1, size_t size_2);
/** Enqueue callback to event queue.
*/
static void event_queue_enqueue();
/** Verify is FCS valid in RX frame.
*
* @return True upon valid FCS, false otherwise.
*/
static bool is_rx_fcs_valid();
/* Deny object creation. */
Mux();
/* Deny copy constructor. */
Mux(const Mux& obj);
/* Deny assignment operator. */
Mux& operator=(const Mux& obj);
/* Definition for Tx context type. */
struct tx_context_t {
int timer_id; /* Timer id. */
union {
uint32_t align_4_byte; /* Force 4-byte alignment. */
uint8_t buffer[MBED_CONF_MUX_BUFFER_SIZE]; /* Rx buffer. */
};
uint8_t retransmit_counter; /* Frame retransmission counter. */
uint8_t bytes_remaining; /* Bytes remaining in the buffer to write. */
uint8_t offset; /* Offset in the buffer where to write from. */
uint8_t tx_callback_context; /* Context for the TX callback dispatching logic as follows:
- 4 LO bits contain the pending callback mask
- 4 HI bits contain the current bit used for masking */
TxState tx_state; /* Tx state machine current state. */
};
/* Definition for Rx context type. */
struct rx_context_t {
union {
uint32_t align_4_byte; /* Force 4-byte alignment. */
uint8_t buffer[MBED_CONF_MUX_BUFFER_SIZE]; /* Rx buffer. */
};
uint8_t offset; /* Offset in the buffer where to read to. */
uint8_t read_length; /* Amount to read in number of bytes. */
RxState rx_state; /* Rx state machine current state. */
};
/* Definition for state type. */
struct state_t {
uint16_t is_mux_open : 1; /* True when multiplexer is open. */
uint16_t is_mux_open_pending : 1; /* True when multiplexer open is pending. */
uint16_t is_mux_open_running : 1; /* True when multiplexer open is running. */
uint16_t is_dlci_open_pending : 1; /* True when DLCI open is pending. */
uint16_t is_dlci_open_running : 1; /* True when DLCI open is running. */
uint16_t is_system_thread_context : 1; /* True when current context is system thread context. */
uint16_t is_tx_callback_context : 1; /* True when current context is TX callback context. */
uint16_t is_user_tx_pending : 1; /* True when user TX is pending. */
uint16_t is_user_rx_ready : 1; /* True when user RX is ready/available. */
};
static FileHandle* _serial; /* Serial used. */
static events::EventQueue* _event_q; /* Event queue used. */
static rtos::Semaphore _semaphore; /* Semaphore used. */
static PlatformMutex _mutex; /* Mutex used. */
static MuxDataService _mux_objects[MBED_CONF_MUX_DLCI_COUNT]; /* Number of supported DLCIs. */
static tx_context_t _tx_context; /* Tx context. */
static rx_context_t _rx_context; /* Rx context. */
static state_t _state; /* General state context. */
static const uint8_t _crctable[MUX_CRC_TABLE_LEN]; /* CRC table used for frame FCS. */
static uint8_t _shared_memory; /* Shared memory used passing data between user and
system threads. */
};
} // namespace mbed
#endif

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) , 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 "mbed_mux.h"
namespace mbed
{
ssize_t MuxDataService::write(const void* buffer, size_t size)
{
return Mux::user_data_tx(_dlci, buffer, size);
}
ssize_t MuxDataService::read(void *buffer, size_t size)
{
return Mux::user_data_rx(buffer, size);
}
off_t MuxDataService::seek(off_t offset, int whence)
{
MBED_ASSERT(false);
return 0;
}
int MuxDataService::close()
{
MBED_ASSERT(false);
return 0;
}
void MuxDataService::sigio(Callback<void()> func)
{
_sigio_cb = func;
}
} // namespace mbed

View File

@ -0,0 +1,55 @@
/*
* 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 "QUECTEL_BC95_CellularNetwork.h"
#include "QUECTEL_BC95_CellularPower.h"
#include "QUECTEL_BC95.h"
#define CONNECT_DELIM "\r\n"
#define CONNECT_BUFFER_SIZE (1280 + 80 + 80) // AT response + sscanf format
#define CONNECT_TIMEOUT 8000
#define MAX_STARTUP_TRIALS 5
#define MAX_RESET_TRIALS 5
using namespace events;
using namespace mbed;
QUECTEL_BC95::QUECTEL_BC95(EventQueue &queue) : AT_CellularDevice(queue)
{
}
QUECTEL_BC95::~QUECTEL_BC95()
{
}
CellularNetwork *QUECTEL_BC95::open_network(FileHandle *fh)
{
if (!_network) {
_network = new QUECTEL_BC95_CellularNetwork(*get_at_handler(fh));
}
return _network;
}
CellularPower *QUECTEL_BC95::open_power(FileHandle *fh)
{
if (!_power) {
_power = new QUECTEL_BC95_CellularPower(*get_at_handler(fh));
}
return _power;
}

View File

@ -0,0 +1,40 @@
/*
* 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 QUECTEL_BC95_H_
#define QUECTEL_BC95_H_
#include "AT_CellularDevice.h"
namespace mbed {
class QUECTEL_BC95 : public AT_CellularDevice
{
public:
QUECTEL_BC95(events::EventQueue &queue);
virtual ~QUECTEL_BC95();
public: // CellularDevice
virtual CellularNetwork *open_network(FileHandle *fh);
virtual CellularPower *open_power(FileHandle *fh);
public: // NetworkInterface
void handle_urc(FileHandle *fh);
};
} // namespace mbed
#endif // QUECTEL_BC95_H_

View File

@ -0,0 +1,60 @@
/*
* 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 "QUECTEL_BC95_CellularNetwork.h"
#include "QUECTEL_BC95_CellularStack.h"
using namespace mbed;
QUECTEL_BC95_CellularNetwork::QUECTEL_BC95_CellularNetwork(ATHandler &atHandler) : AT_CellularNetwork(atHandler)
{
//TODO Set default to NB1 or leave it UNKNOWN
//_ops_act = operator_t::OPS_NB1;
}
QUECTEL_BC95_CellularNetwork::~QUECTEL_BC95_CellularNetwork()
{
}
NetworkStack *QUECTEL_BC95_CellularNetwork::get_stack()
{
if (!_stack) {
_stack = new QUECTEL_BC95_CellularStack(_at, _cid, _ip_stack_type);
}
return _stack;
}
bool QUECTEL_BC95_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
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)
{
if (opRat != operator_t::RAT_NB1) {
//TODO: Set as unknown or force to NB1?
_op_act = operator_t::RAT_UNKNOWN;
return NSAPI_ERROR_UNSUPPORTED;
}
return NSAPI_ERROR_OK;
}

View File

@ -0,0 +1,58 @@
/*
* 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 QUECTEL_BC95_CELLULAR_NETWORK_H_
#define QUECTEL_BC95_CELLULAR_NETWORK_H_
#include "AT_CellularNetwork.h"
namespace mbed {
class QUECTEL_BC95_CellularNetwork : public AT_CellularNetwork
{
public:
QUECTEL_BC95_CellularNetwork(ATHandler &atHandler);
virtual ~QUECTEL_BC95_CellularNetwork();
/** Provide access to the NetworkStack object
*
* @return The underlying NetworkStack object
*/
virtual NetworkStack *get_stack();
/**
* Sets radio access technology.
*
* @param opRat Radio access technology
*
* @return zero on success
*/
virtual nsapi_error_t set_access_technology_impl(operator_t::RadioAccessTechnology opRat);
protected:
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
/**
* Check if modem supports given registration type.
*
* @param reg_type enum RegistrationType
* @return true if given registration type is supported by modem
*/
virtual bool has_registration(RegistrationType reg_type);
};
} // namespace mbed
#endif // QUECTEL_BC95_CELLULAR_NETWORK_H_

View File

@ -0,0 +1,50 @@
/* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <QUECTEL_BC95_CellularPower.h>
#include "onboard_modem_api.h"
using namespace mbed;
QUECTEL_BC95_CellularPower::QUECTEL_BC95_CellularPower(ATHandler &atHandler) : AT_CellularPower(atHandler)
{
}
QUECTEL_BC95_CellularPower::~QUECTEL_BC95_CellularPower()
{
}
nsapi_error_t QUECTEL_BC95_CellularPower::set_at_mode()
{
_at.lock();
_at.flush();
_at.cmd_start("AT+CMEE="); // verbose responses
_at.write_int(1);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
return _at.unlock_return_error();
}
nsapi_error_t QUECTEL_BC95_CellularPower::reset()
{
_at.lock();
_at.cmd_start("AT+NRB"); // reset to full power levels
_at.cmd_stop();
_at.resp_start("REBOOTING", true);
return _at.unlock_return_error();
}

View File

@ -0,0 +1,44 @@
/* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TELIT_HE910_CELLULAR_POWER_H_
#define TELIT_HE910_CELLULAR_POWER_H_
#include "AT_CellularPower.h"
namespace mbed {
class QUECTEL_BC95_CellularPower : public AT_CellularPower
{
public:
QUECTEL_BC95_CellularPower(ATHandler &atHandler);
virtual ~QUECTEL_BC95_CellularPower();
public: //from CellularPower
/**
* Set AT command mode.
* @remark must be called after power on to prepare correct AT mode
* @return blocking until success or failure
*/
virtual nsapi_error_t set_at_mode();
/**
* Reset and wake-up cellular device.
* @return zero on success
*/
virtual nsapi_error_t reset();
};
} // namespace mbed
#endif // TELIT_HE910_CELLULAR_POWER_H_

View File

@ -0,0 +1,200 @@
/*
* 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 "QUECTEL_BC95_CellularStack.h"
#include "CellularUtil.h"
using namespace mbed;
using namespace mbed_cellular_util;
QUECTEL_BC95_CellularStack::QUECTEL_BC95_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type) : AT_CellularStack(atHandler, cid, stack_type)
{
_at.set_urc_handler("+NSONMI:", mbed::Callback<void()>(this, &QUECTEL_BC95_CellularStack::urc_nsonmi));
}
QUECTEL_BC95_CellularStack::~QUECTEL_BC95_CellularStack()
{
}
nsapi_error_t QUECTEL_BC95_CellularStack::socket_listen(nsapi_socket_t handle, int backlog)
{
return NSAPI_ERROR_UNSUPPORTED;
}
nsapi_error_t QUECTEL_BC95_CellularStack::socket_accept(void *server, void **socket, SocketAddress *addr)
{
return NSAPI_ERROR_UNSUPPORTED;
}
void QUECTEL_BC95_CellularStack::urc_nsonmi()
{
int sock_id =_at.read_int();
for (int i = 0; i < get_max_socket_count(); i++) {
CellularSocket *sock = _socket[i];
if (sock && sock->id == sock_id) {
if (sock->_cb) {
sock->_cb(sock->_data);
}
break;
}
}
}
int QUECTEL_BC95_CellularStack::get_max_socket_count()
{
return BC95_SOCKET_MAX;
}
int QUECTEL_BC95_CellularStack::get_max_packet_size()
{
return BC95_MAX_PACKET_SIZE;
}
bool QUECTEL_BC95_CellularStack::is_protocol_supported(nsapi_protocol_t protocol)
{
return (protocol == NSAPI_UDP);
}
nsapi_error_t QUECTEL_BC95_CellularStack::socket_close_impl(int sock_id)
{
_at.cmd_start("AT+NSOCL=");
_at.write_int(sock_id);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
return _at.get_last_error();
}
nsapi_error_t QUECTEL_BC95_CellularStack::create_socket_impl(CellularSocket *socket)
{
int sock_id;
bool socketOpenWorking = false;
if (socket->proto == NSAPI_UDP) {
_at.cmd_start("AT+NSOCR=DGRAM,17,");
_at.write_int(socket->localAddress.get_port());
_at.write_int(1);
_at.cmd_stop();
_at.resp_start();
sock_id = _at.read_int();
_at.resp_stop();
bool socketOpenWorking = (_at.get_last_error() == NSAPI_ERROR_OK);
if (!socketOpenWorking) {
_at.cmd_start("AT+NSOCL=0");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start("AT+NSOCR=DGRAM,17,");
_at.write_int(socket->localAddress.get_port());
_at.write_int(1);
_at.cmd_stop();
_at.resp_start();
sock_id = _at.read_int();
_at.resp_stop();
socketOpenWorking = (_at.get_last_error() == NSAPI_ERROR_OK);
}
}
if (!socketOpenWorking) {
return NSAPI_ERROR_NO_SOCKET;
}
// Check for duplicate socket id delivered by modem
for (int i = 0; i < BC95_SOCKET_MAX; i++) {
CellularSocket *sock = _socket[i];
if (sock && sock->created && sock->id == sock_id) {
return NSAPI_ERROR_NO_SOCKET;
}
}
socket->id = sock_id;
socket->created = true;
return NSAPI_ERROR_OK;
}
nsapi_size_or_error_t QUECTEL_BC95_CellularStack::socket_sendto_impl(CellularSocket *socket, const SocketAddress &address,
const void *data, nsapi_size_t size)
{
int sent_len = 0;
char hexstr[BC95_MAX_PACKET_SIZE*2 + 1] = {0};
char_str_to_hex_str((const char*)data, size, hexstr);
_at.cmd_start("AT+NSOST=");
_at.write_int(socket->id);
_at.write_string(address.get_ip_address(), false);
_at.write_int(address.get_port());
_at.write_int(size);
_at.write_string(hexstr, false);
_at.cmd_stop();
_at.resp_start();
socket->id = _at.read_int();
sent_len = _at.read_int();
_at.resp_stop();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
return sent_len;
}
return _at.get_last_error();
}
nsapi_size_or_error_t QUECTEL_BC95_CellularStack::socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address,
void *buffer, nsapi_size_t size)
{
nsapi_size_or_error_t recv_len=0;
int port;
char ip_address[NSAPI_IP_SIZE];
char hexstr[BC95_MAX_PACKET_SIZE*2 + 1] = {0};
_at.cmd_start("AT+NSORF=");
_at.write_int(socket->id);
_at.write_int(size);
_at.cmd_stop();
_at.resp_start();
// receiving socket id
_at.skip_param();
_at.read_string(ip_address, sizeof(ip_address));
port = _at.read_int();
recv_len = _at.read_int();
_at.read_string(hexstr, sizeof(hexstr));
// remaining length
_at.skip_param();
if (!recv_len || (_at.get_last_error() != NSAPI_ERROR_OK)) {
return NSAPI_ERROR_WOULD_BLOCK;
}
if (address) {
address->set_ip_address(ip_address);
address->set_port(port);
}
if (recv_len > 0) {
hex_str_to_char_str((const char*) hexstr, recv_len*2, (char*)buffer);
}
return recv_len;
}

View File

@ -0,0 +1,133 @@
/*
* 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 QUECTEL_BC95_CELLULARSTACK_H_
#define QUECTEL_BC95_CELLULARSTACK_H_
#include "AT_CellularStack.h"
#define BC95_SOCKET_MAX 7
#define BC95_MAX_PACKET_SIZE 512
namespace mbed {
class QUECTEL_BC95_CellularStack : public AT_CellularStack
{
public:
QUECTEL_BC95_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type);
virtual ~QUECTEL_BC95_CellularStack();
public: // NetworkStack
/** Listen for connections on a TCP socket
*
* Marks the socket as a passive socket that can be used to accept
* incoming connections.
*
* @param handle Socket handle
* @param backlog Number of pending connections that can be queued
* simultaneously
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_listen(nsapi_socket_t handle, int backlog);
/** Accepts a connection on a TCP socket
*
* The server socket must be bound and set to listen for connections.
* On a new connection, creates a network socket and stores it in the
* specified handle. The handle must be passed to following calls on
* the socket.
*
* A stack may have a finite number of sockets, in this case
* NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
*
* This call is non-blocking. If accept would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param server Socket handle to server to accept from
* @param handle Destination for a handle to the newly created socket
* @param address Destination for the remote address or NULL
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_accept(nsapi_socket_t server,
nsapi_socket_t *handle, SocketAddress *address=0);
protected:
/**
* Gets maximum number of sockets modem supports
*/
virtual int get_max_socket_count();
/**
* Gets maximum packet size
*/
virtual int get_max_packet_size();
/**
* Checks if modem supports given protocol
*
* @param protocol Protocol type
*/
virtual bool is_protocol_supported(nsapi_protocol_t protocol);
/**
* Implements modem specific AT command set for socket closing
*
* @param sock_id Socket id
*/
virtual nsapi_error_t socket_close_impl(int sock_id);
/**
* Implements modem specific AT command set for creating socket
*
* @param socket Cellular socket handle
*/
virtual nsapi_error_t create_socket_impl(CellularSocket *socket);
/**
* Implements modem specific AT command set for sending data
*
* @param socket Cellular socket handle
* @param address The SocketAddress of the remote host
* @param data Buffer of data to send to the host
* @param size Size of the buffer in bytes
* @return Number of sent bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_sendto_impl(CellularSocket *socket, const SocketAddress &address,
const void *data, nsapi_size_t size);
/**
* Implements modem specific AT command set for receiving data
*
* @param handle Socket handle
* @param address Destination for the source address or NULL
* @param buffer Destination buffer for data received from the host
* @param size Size of the buffer in bytes
* @return Number of received bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address,
void *buffer, nsapi_size_t size);
private:
// URC handlers
void urc_nsonmi();
};
} // namespace mbed
#endif /* QUECTEL_BC95_CELLULARSTACK_H_ */

View File

@ -0,0 +1,46 @@
/*
* 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 <QUECTEL/BG96/QUECTEL_BG96.h>
#include <QUECTEL/BG96/QUECTEL_BG96_CellularNetwork.h>
#include <QUECTEL/BG96/QUECTEL_BG96_CellularStack.h>
using namespace mbed;
using namespace events;
#define CONNECT_DELIM "\r\n"
#define CONNECT_BUFFER_SIZE (1280 + 80 + 80) // AT response + sscanf format
#define CONNECT_TIMEOUT 8000
#define MAX_STARTUP_TRIALS 5
#define MAX_RESET_TRIALS 5
QUECTEL_BG96::QUECTEL_BG96(EventQueue &queue) : AT_CellularDevice(queue)
{
}
QUECTEL_BG96::~QUECTEL_BG96()
{
}
CellularNetwork *QUECTEL_BG96::open_network(FileHandle *fh)
{
if (!_network) {
_network = new QUECTEL_BG96_CellularNetwork(*get_at_handler(fh));
}
return _network;
}

View File

@ -0,0 +1,47 @@
/*
* 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 QUECTEL_BG96_H_
#define QUECTEL_BG96_H_
#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
class QUECTEL_BG96 : public AT_CellularDevice
{
public:
QUECTEL_BG96(events::EventQueue &queue);
virtual ~QUECTEL_BG96();
public: // CellularDevice
virtual CellularNetwork *open_network(FileHandle *fh);
public: // NetworkInterface
void handle_urc(FileHandle *fh);
};
} // namespace mbed
#endif // QUECTEL_BG96_H_

View File

@ -0,0 +1,115 @@
/*
* 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 <QUECTEL/BG96/QUECTEL_BG96_CellularNetwork.h>
#include <QUECTEL/BG96/QUECTEL_BG96_CellularStack.h>
using namespace mbed;
QUECTEL_BG96_CellularNetwork::QUECTEL_BG96_CellularNetwork(ATHandler &atHandler) : AT_CellularNetwork(atHandler)
{
}
QUECTEL_BG96_CellularNetwork::~QUECTEL_BG96_CellularNetwork()
{
}
bool QUECTEL_BG96_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
if ((requested_stack == IPV4_STACK) ||
(requested_stack == IPV6_STACK) ||
(requested_stack == IPV4V6_STACK)) {
return true;
}
return false;
}
NetworkStack *QUECTEL_BG96_CellularNetwork::get_stack()
{
if (!_stack) {
_stack = new QUECTEL_BG96_CellularStack(_at, _cid, _ip_stack_type);
}
return _stack;
}
nsapi_error_t QUECTEL_BG96_CellularNetwork::set_access_technology_impl(operator_t::RadioAccessTechnology opsAct)
{
_at.lock();
switch (opsAct) {
case operator_t::RAT_CATM1:
_at.cmd_start("AT+QCFG=\"nwscanseq\",020301");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start("AT+QCFG=\"nwscanmode\",3,1");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start("AT+QCFG=\"iotopmode\",0,1");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
break;
case operator_t::RAT_NB1:
_at.cmd_start("AT+QCFG=\"nwscanseq\",030201");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start("AT+QCFG=\"nwscanmode\",3,1");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start("AT+QCFG=\"iotopmode\",1,1");
_at.cmd_stop();
_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:
_at.cmd_start("AT+QCFG=\"nwscanseq\",010203");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start("AT+QCFG=\"nwscanmode\",1,1");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
break;
default:
_at.cmd_start("AT+QCFG=\"nwscanseq\",020301");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start("AT+QCFG=\"nwscanmode\",0,1"); //auto mode
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start("AT+QCFG=\"iotopmode\",2,1"); //auto mode
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.unlock();
_op_act = operator_t::RAT_UNKNOWN;
return NSAPI_ERROR_UNSUPPORTED;
}
return _at.unlock_return_error();
}

View File

@ -0,0 +1,50 @@
/*
* 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 QUECTEL_BG96_CELLULAR_NETWORK_H_
#define QUECTEL_BG96_CELLULAR_NETWORK_H_
#include "AT_CellularNetwork.h"
namespace mbed {
class QUECTEL_BG96_CellularNetwork : public AT_CellularNetwork
{
public:
QUECTEL_BG96_CellularNetwork(ATHandler &atHandler);
virtual ~QUECTEL_BG96_CellularNetwork();
/** Provide access to the NetworkStack object
*
* @return The underlying NetworkStack object
*/
virtual NetworkStack *get_stack();
/**
* Sets radio access technology.
*
* @param opRat Access technology
*
* @return zero on success
*/
virtual nsapi_error_t set_access_technology_impl(operator_t::RadioAccessTechnology opRat);
protected:
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
};
} // namespace mbed
#endif // QUECTEL_BG96_CELLULAR_NETWORK_H_

View File

@ -0,0 +1,262 @@
/*
* 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 <QUECTEL/BG96/QUECTEL_BG96_CellularStack.h>
#include "CellularLog.h"
using namespace mbed;
QUECTEL_BG96_CellularStack::QUECTEL_BG96_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type) : AT_CellularStack(atHandler, cid, stack_type)
{
_at.set_urc_handler("+QIURC: ", mbed::Callback<void()>(this, &QUECTEL_BG96_CellularStack::urc_qiurc));
}
QUECTEL_BG96_CellularStack::~QUECTEL_BG96_CellularStack()
{
}
nsapi_error_t QUECTEL_BG96_CellularStack::socket_listen(nsapi_socket_t handle, int backlog)
{
return NSAPI_ERROR_UNSUPPORTED;
}
nsapi_error_t QUECTEL_BG96_CellularStack::socket_accept(void *server, void **socket, SocketAddress *addr)
{
return NSAPI_ERROR_UNSUPPORTED;
}
void QUECTEL_BG96_CellularStack::urc_qiurc()
{
int sock_id=0;
_at.lock();
(void) _at.skip_param();
sock_id = _at.read_int();
_at.unlock();
for (int i = 0; i < get_max_socket_count(); i++) {
CellularSocket *sock = _socket[i];
if (sock && sock->id == sock_id) {
if (sock->_cb) {
sock->_cb(sock->_data);
}
break;
}
}
}
int QUECTEL_BG96_CellularStack::get_max_socket_count()
{
return BG96_SOCKET_MAX;
}
int QUECTEL_BG96_CellularStack::get_max_packet_size()
{
return BG96_MAX_PACKET_SIZE;
}
bool QUECTEL_BG96_CellularStack::is_protocol_supported(nsapi_protocol_t protocol)
{
return (protocol == NSAPI_UDP);
}
nsapi_error_t QUECTEL_BG96_CellularStack::socket_close_impl(int sock_id)
{
_at.cmd_start("AT+QICLOSE=");
_at.write_int(sock_id);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
return _at.get_last_error();
}
void QUECTEL_BG96_CellularStack::handle_open_socket_response(int &modem_connect_id, int &err)
{
// OK
_at.resp_start();
_at.resp_stop();
// QIOPEN -> should be handled as URC?
_at.set_at_timeout(BG96_CREATE_SOCKET_TIMEOUT);
_at.resp_start("+QIOPEN:");
_at.restore_at_timeout();
modem_connect_id = _at.read_int();
err = _at.read_int();
}
nsapi_error_t QUECTEL_BG96_CellularStack::create_socket_impl(CellularSocket *socket)
{
int modem_connect_id;
int request_connect_id = socket->id;
int remote_port = 0;
int err = -1;
if (socket->proto == NSAPI_UDP && !socket->connected) {
_at.cmd_start("AT+QIOPEN=");
_at.write_int(_cid);
_at.write_int(request_connect_id);
_at.write_string("UDP SERVICE");
_at.write_string("127.0.0.1");
_at.write_int(remote_port);
_at.write_int(socket->localAddress.get_port());
_at.write_int(0);
_at.cmd_stop();
handle_open_socket_response(modem_connect_id, err);
if ((_at.get_last_error() == NSAPI_ERROR_OK) && err) {
_at.cmd_start("AT+QICLOSE=");
_at.write_int(modem_connect_id);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start("AT+QIOPEN=");
_at.write_int(_cid);
_at.write_int(request_connect_id);
_at.write_string("UDP SERVICE");
_at.write_string("127.0.0.1");
_at.write_int(remote_port);
_at.write_int(socket->localAddress.get_port());
_at.write_int(0);
_at.cmd_stop();
handle_open_socket_response(modem_connect_id, err);
}
} else if (socket->proto == NSAPI_UDP && socket->connected) {
_at.cmd_start("AT+QIOPEN=");
_at.write_int(_cid);
_at.write_int(request_connect_id);
_at.write_string("UDP");
_at.write_string(socket->remoteAddress.get_ip_address());
_at.write_int(socket->remoteAddress.get_port());
_at.cmd_stop();
handle_open_socket_response(modem_connect_id, err);
if ((_at.get_last_error() == NSAPI_ERROR_OK) && err) {
_at.cmd_start("AT+QICLOSE=");
_at.write_int(modem_connect_id);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start("AT+QIOPEN=");
_at.write_int(_cid);
_at.write_int(request_connect_id);
_at.write_string("UDP");
_at.write_string(socket->remoteAddress.get_ip_address());
_at.write_int(socket->remoteAddress.get_port());
_at.cmd_stop();
handle_open_socket_response(modem_connect_id, err);
}
}
// If opened successfully BUT not requested one, close it
if (!err && (modem_connect_id != request_connect_id)) {
_at.cmd_start("AT+QICLOSE=");
_at.write_int(modem_connect_id);
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
}
nsapi_error_t ret_val = _at.get_last_error();
socket->created = ((ret_val == NSAPI_ERROR_OK) && (modem_connect_id == request_connect_id));
return ret_val;
}
nsapi_size_or_error_t QUECTEL_BG96_CellularStack::socket_sendto_impl(CellularSocket *socket, const SocketAddress &address,
const void *data, nsapi_size_t size)
{
int sent_len = 0;
int sent_len_before = 0;
int sent_len_after = 0;
// Get the sent count before sending
_at.cmd_start("AT+QISEND=");
_at.write_int(socket->id);
_at.write_int(0);
_at.cmd_stop();
_at.resp_start("+QISEND:");
sent_len_before = _at.read_int();
_at.resp_stop();
// Send
_at.cmd_start("AT+QISEND=");
_at.write_int(socket->id);
_at.write_int(size);
_at.write_string(address.get_ip_address());
_at.write_int(address.get_port());
_at.cmd_stop();
_at.resp_start(">");
_at.write_bytes((uint8_t*)data, size);
_at.resp_start();
_at.set_stop_tag("\r\n");
_at.resp_stop();
// Get the sent count after sending
_at.cmd_start("AT+QISEND=");
_at.write_int(socket->id);
_at.write_int(0);
_at.cmd_stop();
_at.resp_start("+QISEND:");
sent_len_after = _at.read_int();
_at.resp_stop();
if (_at.get_last_error() == NSAPI_ERROR_OK) {
sent_len = sent_len_after - sent_len_before;
return sent_len;
}
return _at.get_last_error();
}
nsapi_size_or_error_t QUECTEL_BG96_CellularStack::socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address,
void *buffer, nsapi_size_t size)
{
nsapi_size_or_error_t recv_len=0;
int port;
char ip_address[NSAPI_IP_SIZE + 1];
_at.cmd_start("AT+QIRD=");
_at.write_int(socket->id);
_at.cmd_stop();
_at.resp_start("+QIRD:");
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);
_at.resp_stop();
if (!recv_len || (_at.get_last_error() != NSAPI_ERROR_OK)) {
return NSAPI_ERROR_WOULD_BLOCK;
}
if (address) {
address->set_ip_address(ip_address);
address->set_port(port);
}
return recv_len;
}

View File

@ -0,0 +1,136 @@
/*
* 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 QUECTEL_BG96_CELLULARSTACK_H_
#define QUECTEL_BG96_CELLULARSTACK_H_
#include "AT_CellularStack.h"
namespace mbed {
#define BG96_SOCKET_MAX 12
#define BG96_MAX_PACKET_SIZE 1460
#define BG96_CREATE_SOCKET_TIMEOUT 150000 //150 seconds
class QUECTEL_BG96_CellularStack : public AT_CellularStack
{
public:
QUECTEL_BG96_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type);
virtual ~QUECTEL_BG96_CellularStack();
public: // NetworkStack
/** Listen for connections on a TCP socket
*
* Marks the socket as a passive socket that can be used to accept
* incoming connections.
*
* @param handle Socket handle
* @param backlog Number of pending connections that can be queued
* simultaneously
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_listen(nsapi_socket_t handle, int backlog);
/** Accepts a connection on a TCP socket
*
* The server socket must be bound and set to listen for connections.
* On a new connection, creates a network socket and stores it in the
* specified handle. The handle must be passed to following calls on
* the socket.
*
* A stack may have a finite number of sockets, in this case
* NSAPI_ERROR_NO_SOCKET is returned if no socket is available.
*
* This call is non-blocking. If accept would block,
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
*
* @param server Socket handle to server to accept from
* @param handle Destination for a handle to the newly created socket
* @param address Destination for the remote address or NULL
* @return 0 on success, negative error code on failure
*/
virtual nsapi_error_t socket_accept(nsapi_socket_t server,
nsapi_socket_t *handle, SocketAddress *address=0);
protected:
/**
* Gets maximum number of sockets modem supports
*/
virtual int get_max_socket_count();
/**
* Gets maximum packet size
*/
virtual int get_max_packet_size();
/**
* Checks if modem supports given protocol
*
* @param protocol Protocol type
*/
virtual bool is_protocol_supported(nsapi_protocol_t protocol);
/**
* Implements modem specific AT command set for socket closing
*
* @param sock_id Socket id
*/
virtual nsapi_error_t socket_close_impl(int sock_id);
/**
* Implements modem specific AT command set for creating socket
*
* @param socket Cellular socket handle
*/
virtual nsapi_error_t create_socket_impl(CellularSocket *socket);
/**
* Implements modem specific AT command set for sending data
*
* @param socket Cellular socket handle
* @param address The SocketAddress of the remote host
* @param data Buffer of data to send to the host
* @param size Size of the buffer in bytes
* @return Number of sent bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_sendto_impl(CellularSocket *socket, const SocketAddress &address,
const void *data, nsapi_size_t size);
/**
* Implements modem specific AT command set for receiving data
*
* @param handle Socket handle
* @param address Destination for the source address or NULL
* @param buffer Destination buffer for data received from the host
* @param size Size of the buffer in bytes
* @return Number of received bytes on success, negative error
* code on failure
*/
virtual nsapi_size_or_error_t socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address,
void *buffer, nsapi_size_t size);
private:
// URC handlers
void urc_qiurc();
void handle_open_socket_response(int &modem_connect_id, int &err);
};
} // namespace mbed
#endif /* QUECTEL_BG96_CELLULARSTACK_H_ */

View File

@ -0,0 +1,76 @@
/*
* 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 "TELIT_HE910.h"
#include "TELIT_HE910_CellularPower.h"
#include "TELIT_HE910_CellularNetwork.h"
#include "TELIT_HE910_CellularMultiplexer.h"
using namespace mbed;
using namespace events;
TELIT_HE910::TELIT_HE910(EventQueue &queue) : AT_CellularDevice(queue)
{
}
TELIT_HE910::~TELIT_HE910()
{
}
CellularPower *TELIT_HE910::open_power(FileHandle *fh)
{
if (!_power) {
ATHandler *atHandler = get_at_handler(fh);
if (atHandler) {
_power = new TELIT_HE910_CellularPower(*atHandler);
if (!_power) {
release_at_handler(atHandler);
}
}
}
return _power;
}
CellularNetwork *TELIT_HE910::open_network(FileHandle *fh)
{
if (!_network) {
ATHandler *atHandler = get_at_handler(fh);
if (atHandler) {
_network = new TELIT_HE910_CellularNetwork(*atHandler);
if (!_network) {
release_at_handler(atHandler);
}
}
}
return _network;
}
CellularMultiplexer *TELIT_HE910::open_multiplexer(FileHandle *fh)
{
if (!_multiplexer) {
ATHandler *atHandler = get_at_handler(fh);
if (atHandler) {
_multiplexer = new AT_CellularMultiplexer(*atHandler);
if (!_multiplexer) {
release_at_handler(atHandler);
}
}
}
return _multiplexer;
}

View File

@ -0,0 +1,38 @@
/*
* 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_TARGETS_TELIT_HE910_TELIT_HE910_H_
#define CELLULAR_TARGETS_TELIT_HE910_TELIT_HE910_H_
#include "AT_CellularDevice.h"
namespace mbed {
class TELIT_HE910 : public AT_CellularDevice
{
public:
TELIT_HE910(events::EventQueue &queue);
virtual ~TELIT_HE910();
public: // from CellularDevice
virtual CellularPower *open_power(FileHandle *fh);
virtual CellularNetwork *open_network(FileHandle *fh);
virtual CellularMultiplexer *open_multiplexer(FileHandle *fh);
};
} // namespace mbed
#endif /* CELLULAR_TARGETS_TELIT_HE910_TELIT_HE910_H_ */

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2017, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "TELIT_HE910_CellularMultiplexer.h"
using namespace mbed;
TELIT_HE910_CellularMultiplexer::TELIT_HE910_CellularMultiplexer(ATHandler &atHandler)
: AT_CellularMultiplexer(atHandler)
{
}
TELIT_HE910_CellularMultiplexer::~TELIT_HE910_CellularMultiplexer()
{
}
nsapi_error_t TELIT_HE910_CellularMultiplexer::multiplexer_mode_start()
{
_at.lock();
_at.cmd_start("AT#SELINT=2");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start("ATE0V1&K3&D2");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start("AT+IPR=115200");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start("AT&W0&P0");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start("AT#CMUXMODE=5");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
_at.cmd_start("AT+CMUX=0");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
return _at.unlock_return_error();
}

View File

@ -0,0 +1,34 @@
/*
* 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 TELIT_HE910_CELLULARMULTIPLEXER_H_
#define TELIT_HE910_CELLULARMULTIPLEXER_H_
#include "AT_CellularMultiplexer.h"
namespace mbed {
class TELIT_HE910_CellularMultiplexer : public AT_CellularMultiplexer {
public:
TELIT_HE910_CellularMultiplexer(ATHandler &atHandler);
virtual ~TELIT_HE910_CellularMultiplexer();
// override from AT_CellularMultiplexer
virtual nsapi_error_t multiplexer_mode_start();
};
} // namespace mbed
#endif /* TELIT_HE910_CELLULARMULTIPLEXER_H_ */

View File

@ -0,0 +1,44 @@
/*
* 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 <TELIT_HE910_CellularNetwork.h>
using namespace mbed;
TELIT_HE910_CellularNetwork::TELIT_HE910_CellularNetwork(ATHandler &atHandler) : AT_CellularNetwork(atHandler)
{
}
TELIT_HE910_CellularNetwork::~TELIT_HE910_CellularNetwork()
{
}
bool TELIT_HE910_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
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)
{
_op_act = operator_t::RAT_UNKNOWN;
return NSAPI_ERROR_UNSUPPORTED;
}

View File

@ -0,0 +1,53 @@
/*
* 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 TELIT_HE910_CELLULAR_NETWORK_H_
#define TELIT_HE910_CELLULAR_NETWORK_H_
#include "AT_CellularNetwork.h"
namespace mbed {
class TELIT_HE910_CellularNetwork : public AT_CellularNetwork
{
public:
TELIT_HE910_CellularNetwork(ATHandler &atHandler);
virtual ~TELIT_HE910_CellularNetwork();
protected:
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
/**
* Check if modem supports given registration type.
*
* @param rat enum RegistrationType
* @return true if given registration type is supported by modem
*/
virtual bool has_registration(RegistrationType rat);
/**
* Sets access technology to be scanned.
*
* @param opRat Access technology
*
* @return zero on success
*/
virtual nsapi_error_t set_access_technology_impl(operator_t::RadioAccessTechnology opRat);
};
} // namespace mbed
#endif // TELIT_HE910_CELLULAR_NETWORK_H_

View File

@ -0,0 +1,69 @@
/*
* 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 "TELIT_HE910_CellularPower.h"
// for modem powering up&down
#include "onboard_modem_api.h"
using namespace mbed;
TELIT_HE910_CellularPower::TELIT_HE910_CellularPower(ATHandler &atHandler) : AT_CellularPower(atHandler)
{
}
TELIT_HE910_CellularPower::~TELIT_HE910_CellularPower()
{
}
nsapi_error_t TELIT_HE910_CellularPower::on()
{
#if MODEM_ON_BOARD
::onboard_modem_init();
::onboard_modem_power_up();
#endif
return NSAPI_ERROR_OK;
}
nsapi_error_t TELIT_HE910_CellularPower::off()
{
#if MODEM_ON_BOARD
::onboard_modem_power_down();
#endif
return NSAPI_ERROR_OK;
}
/**
* Set AT command mode.
* @remark must be called after power on to prepare correct AT mode
* @return blocking until success or failure
*/
nsapi_error_t TELIT_HE910_CellularPower::set_at_mode()
{
nsapi_error_t err = AT_CellularPower::set_at_mode();
if (err != NSAPI_ERROR_OK) {
return err;
}
_at.lock();
_at.cmd_start("AT&K0;&C1;&D0");
_at.cmd_stop();
_at.resp_start();
_at.resp_stop();
return _at.unlock_return_error();
}

View File

@ -0,0 +1,52 @@
/*
* 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 TELIT_HE910_CELLULAR_POWER_H_
#define TELIT_HE910_CELLULAR_POWER_H_
#include "AT_CellularPower.h"
namespace mbed {
class TELIT_HE910_CellularPower : public AT_CellularPower
{
public:
TELIT_HE910_CellularPower(ATHandler &atHandler);
virtual ~TELIT_HE910_CellularPower();
public: //from CellularPower
/**
* Set cellular device power on.
* @return zero on success
*/
virtual nsapi_error_t on();
/**
* Set cellular device power off.
* @return zero on success
*/
virtual nsapi_error_t off();
/**
* Set AT command mode.
* @remark must be called after power on to prepare correct AT mode
* @return blocking until success or failure
*/
virtual nsapi_error_t set_at_mode();
};
} // namespace mbed
#endif // TELIT_HE910_CELLULAR_POWER_H_

View File

@ -0,0 +1,47 @@
/*
* 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 "UBLOX_C027_CellularNetwork.h"
#include "UBLOX_C027_CellularPower.h"
#include "UBLOX_C027.h"
using namespace mbed;
using namespace events;
UBLOX_C027::UBLOX_C027(EventQueue &queue) : AT_CellularDevice(queue)
{
}
UBLOX_C027::~UBLOX_C027()
{
}
CellularNetwork *UBLOX_C027::open_network(FileHandle *fh)
{
if (!_network) {
_network = new UBLOX_C027_CellularNetwork(*get_at_handler(fh));
}
return _network;
}
CellularPower *UBLOX_C027::open_power(FileHandle *fh)
{
if (!_power) {
_power = new UBLOX_C027_CellularPower(*get_at_handler(fh));
}
return _power;
}

View File

@ -0,0 +1,40 @@
/*
* 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 UBLOX_C027_H_
#define UBLOX_C027_H_
#include "AT_CellularDevice.h"
namespace mbed {
class UBLOX_C027 : public AT_CellularDevice
{
public:
UBLOX_C027(events::EventQueue &queue);
virtual ~UBLOX_C027();
public: // CellularDevice
virtual CellularNetwork *open_network(FileHandle *fh);
virtual CellularPower *open_power(FileHandle *fh);
public: // NetworkInterface
};
} // namespace mbed
#endif // UBLOX_C027_H_

View File

@ -0,0 +1,44 @@
/*
* 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 "UBLOX_C027_CellularNetwork.h"
using namespace mbed;
UBLOX_C027_CellularNetwork::UBLOX_C027_CellularNetwork(ATHandler &atHandler) : AT_CellularNetwork(atHandler)
{
}
UBLOX_C027_CellularNetwork::~UBLOX_C027_CellularNetwork()
{
}
bool UBLOX_C027_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack)
{
return requested_stack == IPV4_STACK ? true : false;
}
bool UBLOX_C027_CellularNetwork::has_registration(RegistrationType reg_type)
{
return (reg_type == C_REG || reg_type == C_GREG);
}
nsapi_error_t UBLOX_C027_CellularNetwork::set_access_technology_impl(operator_t::RadioAccessTechnology opRat)
{
_op_act = operator_t::RAT_UNKNOWN;
return NSAPI_ERROR_UNSUPPORTED;
}

View File

@ -0,0 +1,52 @@
/*
* 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 UBLOX_C027_CELLULAR_NETWORK_H_
#define UBLOX_C027_CELLULAR_NETWORK_H_
#include "AT_CellularNetwork.h"
namespace mbed {
class UBLOX_C027_CellularNetwork : public AT_CellularNetwork
{
public:
UBLOX_C027_CellularNetwork(ATHandler &atHandler);
virtual ~UBLOX_C027_CellularNetwork();
protected:
virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack);
/**
* Check if modem supports given registration type.
*
* @param rat enum RegistrationType
* @return true if given registration type is supported by modem
*/
virtual bool has_registration(RegistrationType rat);
/**
* Sets access technology to be scanned.
*
* @param opRat Access technology
*
* @return zero on success
*/
virtual nsapi_error_t set_access_technology_impl(operator_t::RadioAccessTechnology opRat);
};
} // namespace mbed
#endif // UBLOX_C027_CELLULAR_NETWORK_H_

View File

@ -0,0 +1,49 @@
/*
* 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 "onboard_modem_api.h"
#include "UBLOX_C027_CellularPower.h"
using namespace mbed;
UBLOX_C027_CellularPower::UBLOX_C027_CellularPower(ATHandler &atHandler) : AT_CellularPower(atHandler)
{
}
UBLOX_C027_CellularPower::~UBLOX_C027_CellularPower()
{
}
nsapi_error_t UBLOX_C027_CellularPower::on()
{
#if MODEM_ON_BOARD
::onboard_modem_init();
::onboard_modem_power_up();
#endif
return NSAPI_ERROR_OK;
}
nsapi_error_t UBLOX_C027_CellularPower::off()
{
#if MODEM_ON_BOARD
::onboard_modem_power_down();
#endif
return NSAPI_ERROR_OK;
}

View File

@ -0,0 +1,45 @@
/*
* 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 UBLOX_C027_CELLULARPOWER_H_
#define UBLOX_C027_CELLULARPOWER_H_
#include "AT_CellularPower.h"
namespace mbed {
class UBLOX_C027_CellularPower : public AT_CellularPower
{
public:
UBLOX_C027_CellularPower(ATHandler &atHandler);
virtual ~UBLOX_C027_CellularPower();
public: //from CellularPower
/**
* Set cellular device power on.
* @return zero on success
*/
virtual nsapi_error_t on();
/**
* Set cellular device power off.
* @return zero on success
*/
virtual nsapi_error_t off();
};
} // namespace mbed
#endif // UBLOX_C027_CELLULARPOWER_H_