cellular: AT Handler API

pull/8749/head
Teemu Kultala 2018-11-29 14:38:38 +02:00
parent 3b138fba02
commit dbdbae3632
11 changed files with 291 additions and 71 deletions

View File

@ -61,6 +61,16 @@ TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_get_at_handler)
EXPECT_TRUE(dev.open_power(&fh1));
ATHandler_stub::fh_value = NULL;
AT_CellularDevice *dev2 = new AT_CellularDevice(&fh1);
EXPECT_TRUE(dev2->open_information(&fh1));
ATHandler *at = dev2->get_at_handler();
EXPECT_TRUE(at->get_ref_count() == 4);
delete dev2;
EXPECT_TRUE(at->get_ref_count() == 3);
AT_CellularDevice dev3(&fh1);
EXPECT_TRUE(dev3.release_at_handler(at) == NSAPI_ERROR_OK);
EXPECT_TRUE(ATHandler_stub::ref_count == 2);
}
TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_open_network)
@ -211,7 +221,7 @@ TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_close_information)
AT_CellularBase_stub::handler_value = AT_CellularBase_stub::handler_at_constructor_value;
dev.close_information();
EXPECT_TRUE(ATHandler_stub::ref_count == 1);
EXPECT_TRUE(ATHandler_stub::ref_count == kATHandler_destructor_ref_ount);
ATHandler_stub::fh_value = NULL;
}
@ -276,13 +286,21 @@ TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_create_delete_context)
FileHandle_stub fh1;
AT_CellularDevice *dev = new AT_CellularDevice(&fh1);
ATHandler *at = dev->get_at_handler();
EXPECT_TRUE(at->get_ref_count() == 1);
EXPECT_TRUE(dev->release_at_handler(at) == NSAPI_ERROR_OK);
CellularContext *ctx = dev->create_context(NULL);
delete dev;
dev = new AT_CellularDevice(&fh1);
at = dev->get_at_handler();
EXPECT_TRUE(at->get_ref_count() == 1);
ctx = dev->create_context(NULL);
CellularContext *ctx1 = dev->create_context(&fh1);
EXPECT_TRUE(at->get_ref_count() == 3);
CellularContext *ctx2 = dev->create_context(&fh1);
EXPECT_TRUE(at->get_ref_count() == 4);
EXPECT_TRUE(ctx);
EXPECT_TRUE(ctx1);
@ -293,13 +311,21 @@ TEST_F(TestAT_CellularDevice, test_AT_CellularDevice_create_delete_context)
EXPECT_TRUE(xx);
dev->delete_context(ctx);
EXPECT_TRUE(at->get_ref_count() == 3);
dev->delete_context(ctx1);
EXPECT_TRUE(at->get_ref_count() == 2);
dev->delete_context(NULL);
EXPECT_TRUE(at->get_ref_count() == 2);
dev->delete_context(ctx2);
EXPECT_TRUE(at->get_ref_count() == 1);
ctx = dev->create_context(NULL);
EXPECT_TRUE(at->get_ref_count() == 2);
ctx1 = dev->create_context(&fh1);
EXPECT_TRUE(at->get_ref_count() == 3);
ctx2 = dev->create_context(&fh1);
EXPECT_TRUE(at->get_ref_count() == 4);
EXPECT_TRUE(dev->release_at_handler(at) == NSAPI_ERROR_OK);
EXPECT_TRUE(ctx);
EXPECT_TRUE(ctx1);
EXPECT_TRUE(ctx1 != ctx);

View File

@ -86,6 +86,25 @@ TEST_F(TestATHandler, test_ATHandler_set_file_handle)
at.set_file_handle(&fh2);
}
TEST_F(TestATHandler, test_ATHandler_get_release)
{
EventQueue que;
FileHandle_stub fh1;
ATHandler *at1 = ATHandler::get(&fh1, que, 0, ",", 0, 0);
EXPECT_TRUE(at1->get_ref_count() == 1);
EXPECT_TRUE(ATHandler::get(NULL, que, 0, ",", 0, 0) == NULL);
ATHandler *at2 = ATHandler::get(&fh1, que, 0, ",", 0, 0);
EXPECT_TRUE(at1->get_ref_count() == 2);
EXPECT_TRUE(at2->get_ref_count() == 2);
EXPECT_TRUE(ATHandler::release(at1) == NSAPI_ERROR_OK);
EXPECT_TRUE(at2->get_ref_count() == 1);
EXPECT_TRUE(ATHandler::release(at2) == NSAPI_ERROR_OK);
EXPECT_TRUE(ATHandler::release(NULL) == NSAPI_ERROR_PARAMETER);
}
TEST_F(TestATHandler, test_ATHandler_lock)
{
EventQueue que;

View File

@ -60,7 +60,8 @@ char *ATHandler_stub::urc_string_table[kATHandler_urc_table_max_size];
ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, int timeout, const char *output_delimiter, uint16_t send_delay) :
_nextATHandler(0),
_fileHandle(fh),
_queue(queue)
_queue(queue),
_ref_count(1)
{
ATHandler_stub::ref_count = 1;
@ -72,6 +73,8 @@ ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, int timeout, const char
ATHandler_stub::urc_string_table[i++] = NULL;
}
}
ATHandler *ATHandler::_atHandlers = NULL;
PlatformMutex ATHandler::_getReleaseMutex;
void ATHandler::set_debug(bool debug_on)
{
@ -95,28 +98,93 @@ ATHandler::~ATHandler()
void ATHandler::inc_ref_count()
{
ATHandler_stub::ref_count++;
_ref_count++;
ATHandler_stub::ref_count = _ref_count;
}
void ATHandler::dec_ref_count()
{
ATHandler_stub::ref_count--;
_ref_count--;
ATHandler_stub::ref_count = _ref_count;
}
int ATHandler::get_ref_count()
{
return ATHandler_stub::ref_count;
return _ref_count;
}
FileHandle *ATHandler::get_file_handle()
{
return ATHandler_stub::fh_value;
ATHandler_stub::fh_value = (FileHandle_stub *)_fileHandle;
return _fileHandle;
}
void ATHandler::set_file_handle(FileHandle *fh)
{
}
// each parser is associated with one filehandle (that is UART)
ATHandler *ATHandler::get(FileHandle *fileHandle, events::EventQueue &queue, uint32_t timeout,
const char *delimiter, uint16_t send_delay, bool debug_on)
{
if (!fileHandle) {
return NULL;
}
_getReleaseMutex.lock();
ATHandler *atHandler = _atHandlers;
while (atHandler) {
if (atHandler->get_file_handle() == fileHandle) {
atHandler->inc_ref_count();
_getReleaseMutex.unlock();
return atHandler;
}
atHandler = atHandler->_nextATHandler;
}
atHandler = new ATHandler(fileHandle, queue, timeout, delimiter, send_delay);
if (debug_on) {
atHandler->set_debug(debug_on);
}
atHandler->_nextATHandler = _atHandlers;
_atHandlers = atHandler;
_getReleaseMutex.unlock();
return atHandler;
}
nsapi_error_t ATHandler::release(ATHandler *at_handler)
{
if (!at_handler || at_handler->get_ref_count() == 0) {
return NSAPI_ERROR_PARAMETER;
}
_getReleaseMutex.lock();
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;
at_handler = NULL;
break;
} else {
prev = atHandler;
atHandler = atHandler->_nextATHandler;
}
}
}
_getReleaseMutex.unlock();
return NSAPI_ERROR_OK;
}
nsapi_error_t ATHandler::set_urc_handler(const char *urc, mbed::Callback<void()> cb)
{
if (ATHandler_stub::urc_amount < kATHandler_urc_table_max_size) {

View File

@ -34,7 +34,8 @@ AT_CellularBase::AT_CellularBase(ATHandler &at) : _at(at)
ATHandler &AT_CellularBase::get_at_handler()
{
return *AT_CellularBase_stub::handler_value;
AT_CellularBase_stub::handler_value = &_at;
return _at;
}
device_err_t AT_CellularBase::get_device_error() const

View File

@ -27,22 +27,25 @@ AT_CellularDevice::AT_CellularDevice(FileHandle *fh) : CellularDevice(fh), _netw
_sim(0), _power(0), _information(0), _context_list(0), _default_timeout(DEFAULT_AT_TIMEOUT),
_modem_debug_on(false)
{
_atHandlers = new ATHandler(fh, _queue, 0, ",");
}
AT_CellularDevice::~AT_CellularDevice()
{
delete _atHandlers;
}
ATHandler *AT_CellularDevice::get_at_handler(FileHandle *fileHandle)
{
return _atHandlers;
return ATHandler::get(fileHandle, _queue, _default_timeout, "\r", get_send_delay(), _modem_debug_on);
}
void AT_CellularDevice::release_at_handler(ATHandler *at_handler)
ATHandler *AT_CellularDevice::get_at_handler()
{
return get_at_handler(NULL);
}
nsapi_error_t AT_CellularDevice::release_at_handler(ATHandler *at_handler)
{
return ATHandler::release(at_handler);
}
CellularContext *create_context(FileHandle *fh = NULL, const char *apn = MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN)
@ -57,7 +60,7 @@ void delete_context(CellularContext *context)
CellularNetwork *AT_CellularDevice::open_network(FileHandle *fh)
{
return new AT_CellularNetwork(*_atHandlers);
return new AT_CellularNetwork(*ATHandler::get(fh, _queue, _default_timeout, "\r", get_send_delay(), _modem_debug_on));
}
CellularSMS *AT_CellularDevice::open_sms(FileHandle *fh)

View File

@ -119,6 +119,14 @@ public:
{
CellularDevice::cellular_callback(ev, ptr);
}
virtual ATHandler *get_at_handler()
{
return NULL;
}
virtual nsapi_error_t release_at_handler(ATHandler *at_handler)
{
return NSAPI_ERROR_OK;
}
AT_CellularNetwork *_network;
AT_CellularContext *_context_list;
};

View File

@ -21,6 +21,7 @@
#include "CellularTargets.h"
#include "CellularStateMachine.h"
#include "Callback.h"
#include "ATHandler.h"
namespace mbed {
@ -249,6 +250,20 @@ public:
*/
virtual CellularContext *get_context_list() const;
/** Get the current ATHandler instance in use for debug purposes etc.
* Once use has been finished call to release_at_handler() has to be made
*
* @return Pointer to the ATHandler in use
*/
virtual ATHandler *get_at_handler() = 0;
/** Release the ATHandler taken into use with get_at_handler()
*
* @param at_handler
* @return NSAPI_ERROR_OK on success, NSAPI_ERROR_PARAMETER on failure
*/
virtual nsapi_error_t release_at_handler(ATHandler *at_handler) = 0;
protected:
friend class AT_CellularNetwork;
friend class AT_CellularContext;

View File

@ -110,6 +110,8 @@ ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, int timeout, const char
set_file_handle(fh);
}
ATHandler *ATHandler::_atHandlers = NULL;
PlatformMutex ATHandler::_getReleaseMutex;
void ATHandler::set_debug(bool debug_on)
{
@ -160,6 +162,69 @@ void ATHandler::set_is_filehandle_usable(bool usable)
_is_fh_usable = usable;
}
// each parser is associated with one filehandle (that is UART)
ATHandler *ATHandler::get(FileHandle *fileHandle, events::EventQueue &queue, uint32_t timeout,
const char *delimiter, uint16_t send_delay, bool debug_on)
{
if (!fileHandle) {
return NULL;
}
_getReleaseMutex.lock();
ATHandler *atHandler = _atHandlers;
while (atHandler) {
if (atHandler->get_file_handle() == fileHandle) {
atHandler->inc_ref_count();
_getReleaseMutex.unlock();
return atHandler;
}
atHandler = atHandler->_nextATHandler;
}
atHandler = new ATHandler(fileHandle, queue, timeout, delimiter, send_delay);
if (debug_on) {
atHandler->set_debug(debug_on);
}
atHandler->_nextATHandler = _atHandlers;
_atHandlers = atHandler;
_getReleaseMutex.unlock();
return atHandler;
}
nsapi_error_t ATHandler::release(ATHandler *at_handler)
{
if (!at_handler || at_handler->get_ref_count() == 0) {
return NSAPI_ERROR_PARAMETER;
}
_getReleaseMutex.lock();
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;
at_handler = NULL;
break;
} else {
prev = atHandler;
atHandler = atHandler->_nextATHandler;
}
}
}
_getReleaseMutex.unlock();
return NSAPI_ERROR_OK;
}
nsapi_error_t ATHandler::set_urc_handler(const char *prefix, mbed::Callback<void()> callback)
{
if (find_urc_handler(prefix)) {

View File

@ -83,6 +83,27 @@ public:
*/
FileHandle *get_file_handle();
/** Get a new ATHandler instance, and update the linked list
*
* @param fileHandle filehandle 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 delimiter delimiter used when parsing at responses, "\r" should be used as output_delimiter
* @param send_delay the minimum delay in ms between the end of last response and the beginning of a new command
* @param debug_on Set true to enable debug traces
* @return NULL, if fileHandle is not set, or a pointer to an existing ATHandler, if the fileHandle is
* already in use. Otherwise a pointer to a new ATHandler instance is returned
*/
static ATHandler *get(FileHandle *fileHandle, events::EventQueue &queue, uint32_t timeout,
const char *delimiter, uint16_t send_delay, bool debug_on);
/** Release an ATHandler instance, and update the linked list
*
* @param at_handler Pointer to the ATHandler
* @return NSAPI_ERROR_OK on success, NSAPI_ERROR_PARAMETER on failure
*/
static nsapi_error_t release(ATHandler *at_handler);
/** Locks the mutex for file handle if AT_HANDLER_MUTEX is defined.
*/
void lock();
@ -222,6 +243,9 @@ private:
int32_t _ref_count;
bool _is_fh_usable;
static ATHandler *_atHandlers;
static PlatformMutex _getReleaseMutex;
//*************************************
public:

View File

@ -33,7 +33,7 @@ using namespace mbed;
#define DEFAULT_AT_TIMEOUT 1000 // at default timeout in milliseconds
AT_CellularDevice::AT_CellularDevice(FileHandle *fh) : CellularDevice(fh), _atHandlers(0), _network(0), _sms(0),
AT_CellularDevice::AT_CellularDevice(FileHandle *fh) : CellularDevice(fh), _network(0), _sms(0),
_sim(0), _power(0), _information(0), _context_list(0), _default_timeout(DEFAULT_AT_TIMEOUT),
_modem_debug_on(false)
{
@ -60,15 +60,10 @@ AT_CellularDevice::~AT_CellularDevice()
AT_CellularContext *next;
while (curr) {
next = (AT_CellularContext *)curr->_next;
ATHandler *at = &curr->get_at_handler();
delete curr;
curr = next;
}
ATHandler *atHandler = _atHandlers;
while (atHandler) {
ATHandler *old = atHandler;
atHandler = atHandler->_nextATHandler;
delete old;
release_at_handler(at);
}
}
@ -78,50 +73,19 @@ ATHandler *AT_CellularDevice::get_at_handler(FileHandle *fileHandle)
if (!fileHandle) {
fileHandle = _fh;
}
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, "\r", get_send_delay());
if (_modem_debug_on) {
atHandler->set_debug(_modem_debug_on);
}
atHandler->_nextATHandler = _atHandlers;
_atHandlers = atHandler;
return atHandler;
return ATHandler::get(fileHandle, _queue, _default_timeout,
"\r", get_send_delay(), _modem_debug_on);
}
void AT_CellularDevice::release_at_handler(ATHandler *at_handler)
ATHandler *AT_CellularDevice::get_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;
break;
} else {
prev = atHandler;
atHandler = atHandler->_nextATHandler;
}
}
}
return get_at_handler(NULL);
}
nsapi_error_t AT_CellularDevice::release_at_handler(ATHandler *at_handler)
{
return ATHandler::release(at_handler);
}
CellularContext *AT_CellularDevice::get_context_list() const
@ -173,7 +137,13 @@ void AT_CellularDevice::delete_context(CellularContext *context)
prev = curr;
curr = (AT_CellularContext *)curr->_next;
}
curr = (AT_CellularContext *)context;
ATHandler *at = NULL;
if (curr) {
at = &curr->get_at_handler();
}
delete (AT_CellularContext *)context;
release_at_handler(at);
}
CellularNetwork *AT_CellularDevice::open_network(FileHandle *fh)
@ -340,10 +310,20 @@ 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;
if (_network) {
_network->get_at_handler().set_at_timeout(_default_timeout, true);
}
if (_sms) {
_sms->get_at_handler().set_at_timeout(_default_timeout, true);
}
if (_power) {
_power->get_at_handler().set_at_timeout(_default_timeout, true);
}
if (_sim) {
_sim->get_at_handler().set_at_timeout(_default_timeout, true);
}
if (_information) {
_information->get_at_handler().set_at_timeout(_default_timeout, true);
}
}
@ -356,10 +336,20 @@ void AT_CellularDevice::modem_debug_on(bool on)
{
_modem_debug_on = on;
ATHandler *atHandler = _atHandlers;
while (atHandler) {
atHandler->set_debug(_modem_debug_on);
atHandler = atHandler->_nextATHandler;
if (_network) {
_network->get_at_handler().set_debug(_modem_debug_on);
}
if (_sms) {
_sms->get_at_handler().set_debug(_modem_debug_on);
}
if (_power) {
_power->get_at_handler().set_debug(_modem_debug_on);
}
if (_sim) {
_sim->get_at_handler().set_debug(_modem_debug_on);
}
if (_information) {
_information->get_at_handler().set_debug(_modem_debug_on);
}
}

View File

@ -72,15 +72,16 @@ public:
virtual nsapi_error_t init_module();
ATHandler *_atHandlers;
virtual ATHandler *get_at_handler(FileHandle *fh);
ATHandler *get_at_handler(FileHandle *fh);
virtual ATHandler *get_at_handler();
/** Releases the given at_handler. If last reference to at_hander then it's deleted.
*
* @param at_handler
* @return NSAPI_ERROR_OK on success, NSAPI_ERROR_PARAMETER on failure
*/
void release_at_handler(ATHandler *at_handler);
virtual nsapi_error_t release_at_handler(ATHandler *at_handler);
/** Creates new instance of AT_CellularContext or if overridden, modem specific implementation.
*