diff --git a/UNITTESTS/features/cellular/framework/AT/at_cellularcontext/unittest.cmake b/UNITTESTS/features/cellular/framework/AT/at_cellularcontext/unittest.cmake index 5d36efe270..7470c4ecf0 100644 --- a/UNITTESTS/features/cellular/framework/AT/at_cellularcontext/unittest.cmake +++ b/UNITTESTS/features/cellular/framework/AT/at_cellularcontext/unittest.cmake @@ -38,4 +38,6 @@ set(unittest-test-sources stubs/randLIB_stub.cpp stubs/Semaphore_stub.cpp stubs/us_ticker_stub.cpp + stubs/UARTSerial_stub.cpp + stubs/SerialBase_stub.cpp ) diff --git a/UNITTESTS/stubs/AT_CellularContext_stub.cpp b/UNITTESTS/stubs/AT_CellularContext_stub.cpp index c1f70ad3fb..38b8dda130 100644 --- a/UNITTESTS/stubs/AT_CellularContext_stub.cpp +++ b/UNITTESTS/stubs/AT_CellularContext_stub.cpp @@ -42,6 +42,14 @@ AT_CellularContext::~AT_CellularContext() { } +void AT_CellularContext::set_file_handle(UARTSerial *serial, PinName dcd_pin, bool active_high) +{ +} + +void AT_CellularContext::enable_hup(bool enable) +{ +} + void AT_CellularContext::set_file_handle(FileHandle *fh) { } diff --git a/UNITTESTS/stubs/AT_CellularDevice_stub.cpp b/UNITTESTS/stubs/AT_CellularDevice_stub.cpp index 6f17565e84..a203de3703 100644 --- a/UNITTESTS/stubs/AT_CellularDevice_stub.cpp +++ b/UNITTESTS/stubs/AT_CellularDevice_stub.cpp @@ -64,7 +64,12 @@ nsapi_error_t AT_CellularDevice::release_at_handler(ATHandler *at_handler) } } -CellularContext *create_context(FileHandle *fh = NULL, const char *apn = MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN) +CellularContext *AT_CellularDevice::create_context(UARTSerial *serial, const char *const apn, PinName dcd_pin, + bool active_high) +{ +} + +CellularContext *create_context(FileHandle *fh, const char *apn) { } diff --git a/UNITTESTS/target_h/myCellularDevice.h b/UNITTESTS/target_h/myCellularDevice.h index 301f2a1466..f0b2e09a01 100644 --- a/UNITTESTS/target_h/myCellularDevice.h +++ b/UNITTESTS/target_h/myCellularDevice.h @@ -52,6 +52,12 @@ public: return NSAPI_ERROR_OK; } + virtual CellularContext *create_context(UARTSerial *serial, const char *const apn, PinName dcd_pin, + bool active_high) + { + return NULL; + } + virtual CellularContext *create_context(FileHandle *fh = NULL, const char *apn = NULL) { EventQueue que; diff --git a/features/cellular/framework/API/CellularContext.h b/features/cellular/framework/API/CellularContext.h index 44bd4ec581..14afdfd145 100644 --- a/features/cellular/framework/API/CellularContext.h +++ b/features/cellular/framework/API/CellularContext.h @@ -107,7 +107,6 @@ protected: // friend of CellularDevice, so it's the only way to close or delete this class. friend class CellularDevice; virtual ~CellularContext() {} - public: // from NetworkInterface virtual nsapi_error_t set_blocking(bool blocking) = 0; virtual NetworkStack *get_stack() = 0; @@ -227,6 +226,15 @@ public: // from NetworkInterface */ virtual void set_file_handle(FileHandle *fh) = 0; + /** Set the UART serial used to communicate with the modem. Can be used to change default file handle. + * File handle set with this method will use data carrier detect to be able to detect disconnection much faster in PPP mode. + * + * @param serial UARTSerial used in communication to modem. If null then the default file handle is used. + * @param dcd_pin Pin used to set data carrier detect on/off for the given UART + * @param active_high a boolean set to true if DCD polarity is active low + */ + virtual void set_file_handle(UARTSerial *serial, PinName dcd_pin = NC, bool active_high = false) = 0; + protected: // Device specific implementations might need these so protected enum ContextOperation { OP_INVALID = -1, @@ -245,6 +253,15 @@ protected: // Device specific implementations might need these so protected */ virtual void cellular_callback(nsapi_event_t ev, intptr_t ptr) = 0; + /** Enable or disable hang-up detection + * + * When in PPP data pump mode, it is helpful if the FileHandle will signal hang-up via + * POLLHUP, e.g., if the DCD line is deasserted on a UART. During command mode, this + * signaling is not desired. enable_hup() controls whether this function should be + * active. + */ + virtual void enable_hup(bool enable) = 0; + // member variables needed in target override methods NetworkStack *_stack; // must be pointer because of PPP nsapi_ip_stack_t _ip_stack_type; @@ -259,6 +276,8 @@ protected: // Device specific implementations might need these so protected const char *_apn; const char *_uname; const char *_pwd; + PinName _dcd_pin; + bool _active_high; }; /** diff --git a/features/cellular/framework/API/CellularDevice.h b/features/cellular/framework/API/CellularDevice.h index 35c46eb27e..9d7d5730c8 100644 --- a/features/cellular/framework/API/CellularDevice.h +++ b/features/cellular/framework/API/CellularDevice.h @@ -22,6 +22,7 @@ #include "CellularStateMachine.h" #include "Callback.h" #include "ATHandler.h" +#include "UARTSerial.h" namespace mbed { @@ -102,6 +103,21 @@ public: */ virtual CellularContext *create_context(FileHandle *fh = NULL, const char *apn = NULL) = 0; + /** Creates a new CellularContext interface. This API should be used if serial is UART and PPP mode used. + * CellularContext created will use data carrier detect to be able to detect disconnection much faster in PPP mode. + * UARTSerial usually is the same which was given for the CellularDevice. + * + * @param serial UARTSerial used in communication to modem. If null then the default file handle is used. + * @param apn access point to use with context, can be null. + * @param dcd_pin Pin used to set data carrier detect on/off for the given UART + * @param active_high a boolean set to true if DCD polarity is active low + * + * @return new instance of class CellularContext or NULL in case of failure + * + */ + virtual CellularContext *create_context(UARTSerial *serial, const char *apn, PinName dcd_pin = NC, + bool active_high = false) = 0; + /** Deletes the given CellularContext instance * * @param context CellularContext to delete @@ -113,6 +129,12 @@ public: */ void stop(); + /** Get the current FileHandle item used when communicating with the modem. + * + * @return reference to FileHandle + */ + FileHandle &get_file_handle() const; + /** Get event queue that can be chained to main event queue. * @return event queue */ diff --git a/features/cellular/framework/AT/ATHandler.cpp b/features/cellular/framework/AT/ATHandler.cpp index 4371f4ddaa..5144f37757 100644 --- a/features/cellular/framework/AT/ATHandler.cpp +++ b/features/cellular/framework/AT/ATHandler.cpp @@ -154,6 +154,10 @@ void ATHandler::set_file_handle(FileHandle *fh) void ATHandler::set_is_filehandle_usable(bool usable) { _is_fh_usable = usable; + if (usable) { + // set file handle sigio and blocking mode back + set_file_handle(_fileHandle); + } } void ATHandler::set_urc_handler(const char *prefix, Callback callback) diff --git a/features/cellular/framework/AT/AT_CellularContext.cpp b/features/cellular/framework/AT/AT_CellularContext.cpp index b2ab6ca8ca..46302d38e5 100644 --- a/features/cellular/framework/AT/AT_CellularContext.cpp +++ b/features/cellular/framework/AT/AT_CellularContext.cpp @@ -59,11 +59,13 @@ AT_CellularContext::AT_CellularContext(ATHandler &at, CellularDevice *device, co _cid = -1; _new_context_set = false; _next = NULL; + _dcd_pin = NC; + _active_high = false; } AT_CellularContext::~AT_CellularContext() { - tr_info("Delete CellularContext %s (%p)", _apn ? _apn : "", this); + tr_info("Delete CellularContext with apn: [%s] (%p)", _apn ? _apn : "", this); (void)disconnect(); @@ -79,6 +81,23 @@ void AT_CellularContext::set_file_handle(FileHandle *fh) _at.set_file_handle(_fh); } +void AT_CellularContext::set_file_handle(UARTSerial *serial, PinName dcd_pin, bool active_high) +{ + tr_info("CellularContext serial %p", serial); + _dcd_pin = dcd_pin; + _active_high = active_high; + _fh = serial; + _at.set_file_handle(static_cast(serial)); + enable_hup(false); +} + +void AT_CellularContext::enable_hup(bool enable) +{ + if (_dcd_pin != NC) { + static_cast(_fh)->set_data_carrier_detect(enable ? _dcd_pin : NC, _active_high); + } +} + nsapi_error_t AT_CellularContext::connect() { tr_info("CellularContext connect"); @@ -595,11 +614,16 @@ nsapi_error_t AT_CellularContext::open_data_channel() } _at.set_is_filehandle_usable(false); - + enable_hup(true); /* Initialize PPP * If blocking: mbed_ppp_init() is a blocking call, it will block until connected, or timeout after 30 seconds*/ - return nsapi_ppp_connect(_at.get_file_handle(), callback(this, &AT_CellularContext::ppp_status_cb), _uname, _pwd, _ip_stack_type); + nsapi_error_t err = nsapi_ppp_connect(_at.get_file_handle(), callback(this, &AT_CellularContext::ppp_status_cb), _uname, _pwd, _ip_stack_type); + if (err) { + ppp_disconnected(); + } + + return err; } void AT_CellularContext::ppp_status_cb(nsapi_event_t ev, intptr_t ptr) @@ -607,6 +631,8 @@ void AT_CellularContext::ppp_status_cb(nsapi_event_t ev, intptr_t ptr) tr_debug("ppp_status_cb: event %d, ptr %d", ev, ptr); if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE && ptr == NSAPI_STATUS_GLOBAL_UP) { _is_connected = true; + } else if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE && ptr == NSAPI_STATUS_DISCONNECTED) { + ppp_disconnected(); } else { _is_connected = false; } @@ -617,6 +643,20 @@ void AT_CellularContext::ppp_status_cb(nsapi_event_t ev, intptr_t ptr) _device->cellular_callback(ev, ptr); } +void AT_CellularContext::ppp_disconnected() +{ + enable_hup(false); + + // after ppp disconnect if we wan't to use same at handler we need to set filehandle again to athandler so it + // will set the correct sigio and nonblocking + _at.lock(); + _at.set_is_filehandle_usable(true); + if (!_at.sync(AT_SYNC_TIMEOUT)) { // consume extra characters after ppp disconnect, also it may take a while until modem listens AT commands + tr_error("AT sync failed after PPP Disconnect"); + } + _at.unlock(); +} + #endif //#if NSAPI_PPP_AVAILABLE nsapi_error_t AT_CellularContext::disconnect() @@ -631,15 +671,7 @@ nsapi_error_t AT_CellularContext::disconnect() tr_error("CellularContext disconnect failed!"); // continue even in failure due to ppp disconnect in any case releases filehandle } - // after ppp disconnect if we wan't to use same at handler we need to set filehandle again to athandler so it - // will set the correct sigio and nonblocking - _at.lock(); - _at.set_file_handle(_at.get_file_handle()); - _at.set_is_filehandle_usable(true); - if (!_at.sync(AT_SYNC_TIMEOUT)) { // consume extra characters after ppp disconnect, also it may take a while until modem listens AT commands - tr_error("AT sync failed after PPP Disconnect"); - } - _at.unlock(); + ppp_disconnected(); #endif // NSAPI_PPP_AVAILABLE _at.lock(); diff --git a/features/cellular/framework/AT/AT_CellularContext.h b/features/cellular/framework/AT/AT_CellularContext.h index dc59f69c65..4a671cabe2 100644 --- a/features/cellular/framework/AT/AT_CellularContext.h +++ b/features/cellular/framework/AT/AT_CellularContext.h @@ -57,6 +57,8 @@ public: virtual nsapi_error_t register_to_network(); virtual nsapi_error_t attach_to_network(); virtual void set_file_handle(FileHandle *fh); + virtual void set_file_handle(UARTSerial *serial, PinName dcd_pin = NC, bool active_high = false); + virtual void enable_hup(bool enable); protected: virtual void cellular_callback(nsapi_event_t ev, intptr_t ptr); @@ -93,6 +95,7 @@ private: #if NSAPI_PPP_AVAILABLE nsapi_error_t open_data_channel(); void ppp_status_cb(nsapi_event_t ev, intptr_t ptr); + void ppp_disconnected(); #endif // #if NSAPI_PPP_AVAILABLE nsapi_error_t do_activate_context(); bool set_new_context(int cid); diff --git a/features/cellular/framework/AT/AT_CellularDevice.cpp b/features/cellular/framework/AT/AT_CellularDevice.cpp index b60673ae17..30b8fbcc2c 100644 --- a/features/cellular/framework/AT/AT_CellularDevice.cpp +++ b/features/cellular/framework/AT/AT_CellularDevice.cpp @@ -167,6 +167,17 @@ CellularContext *AT_CellularDevice::get_context_list() const return _context_list; } +CellularContext *AT_CellularDevice::create_context(UARTSerial *serial, const char *const apn, PinName dcd_pin, + bool active_high) +{ + // Call FileHandle base version - explict upcast to avoid recursing into ourselves + CellularContext *ctx = create_context(static_cast(serial), apn); + if (serial) { + ctx->set_file_handle(serial, dcd_pin, active_high); + } + return ctx; +} + CellularContext *AT_CellularDevice::create_context(FileHandle *fh, const char *apn) { AT_CellularContext *ctx = create_context_impl(*get_at_handler(fh), apn); diff --git a/features/cellular/framework/AT/AT_CellularDevice.h b/features/cellular/framework/AT/AT_CellularDevice.h index 1412676461..c2343b47c2 100644 --- a/features/cellular/framework/AT/AT_CellularDevice.h +++ b/features/cellular/framework/AT/AT_CellularDevice.h @@ -46,6 +46,8 @@ public: virtual CellularContext *create_context(FileHandle *fh = NULL, const char *apn = NULL); + virtual CellularContext *create_context(UARTSerial *serial, const char *const apn, PinName dcd_pin = NC, bool active_high = false); + virtual void delete_context(CellularContext *context); virtual CellularNetwork *open_network(FileHandle *fh = NULL); diff --git a/features/cellular/framework/device/CellularContext.cpp b/features/cellular/framework/device/CellularContext.cpp index 64dfc7f13a..a134e28a17 100644 --- a/features/cellular/framework/device/CellularContext.cpp +++ b/features/cellular/framework/device/CellularContext.cpp @@ -26,6 +26,9 @@ MBED_WEAK CellularContext *CellularContext::get_default_instance() return NULL; } static CellularContext *context = dev->create_context(); +#if defined(MDMDCD) && defined(MDM_PIN_POLARITY) + context->set_file_handle(static_cast(&dev->get_file_handle()), MDMDCD, MDM_PIN_POLARITY); +#endif // #if defined(MDMDCD) && defined(MDM_PIN_POLARITY) return context; } #else diff --git a/features/cellular/framework/device/CellularDevice.cpp b/features/cellular/framework/device/CellularDevice.cpp index 305556d273..a886f5eb3d 100644 --- a/features/cellular/framework/device/CellularDevice.cpp +++ b/features/cellular/framework/device/CellularDevice.cpp @@ -21,7 +21,6 @@ #include "CellularLog.h" #include "CellularTargets.h" #include "EventQueue.h" -#include "UARTSerial.h" #ifdef CELLULAR_DEVICE #include CELLULAR_STRINGIFY(CELLULAR_DEVICE.h) @@ -52,6 +51,7 @@ MBED_WEAK CellularDevice *CellularDevice::get_default_instance() CellularDevice::CellularDevice(FileHandle *fh) : _network_ref_count(0), _sms_ref_count(0), _power_ref_count(0), _info_ref_count(0), _fh(fh), _queue(5 * EVENTS_EVENT_SIZE), _state_machine(0), _nw(0), _status_cb(0) { + MBED_ASSERT(fh); set_sim_pin(NULL); set_plmn(NULL); } @@ -66,6 +66,11 @@ void CellularDevice::stop() _state_machine->stop(); } +FileHandle &CellularDevice::get_file_handle() const +{ + return *_fh; +} + events::EventQueue *CellularDevice::get_queue() { return &_queue;