diff --git a/examples/Tools/SerialSARAPassthrough/SerialSARAPassthrough.ino b/examples/Tools/SerialSARAPassthrough/SerialSARAPassthrough.ino index ec81337..9a2db06 100644 --- a/examples/Tools/SerialSARAPassthrough/SerialSARAPassthrough.ino +++ b/examples/Tools/SerialSARAPassthrough/SerialSARAPassthrough.ino @@ -10,12 +10,11 @@ Circuit: - MKR NB 1500 board - Antenna - - 1500 mAh or higher lipo battery connected - SIM card - Make sure the Serial Monitor's line ending is set to "Both NL and CR" + Make sure the Serial Monitor's line ending is set to "Both NL and CR" or "Carriage Return" - create 11 December 2017 + created 11 December 2017 Sandeep Mistry */ @@ -23,16 +22,16 @@ unsigned long baud = 115200; void setup() { - // enable the POW_ON pin - pinMode(SARA_PWR_ON, OUTPUT); - digitalWrite(SARA_PWR_ON, HIGH); - - // reset the ublox module + // NEVER EVER use RESET_N pinMode(SARA_RESETN, OUTPUT); - digitalWrite(SARA_RESETN, HIGH); - delay(100); digitalWrite(SARA_RESETN, LOW); + // Send Poweron pulse + pinMode(SARA_PWR_ON, OUTPUT); + digitalWrite(SARA_PWR_ON, HIGH); + delay(150); + digitalWrite(SARA_PWR_ON, LOW); + Serial.begin(baud); SerialSARA.begin(baud); } diff --git a/src/Modem.cpp b/src/Modem.cpp index b40ff5b..a0b38ee 100644 --- a/src/Modem.cpp +++ b/src/Modem.cpp @@ -24,11 +24,12 @@ ModemUrcHandler* ModemClass::_urcHandlers[MAX_URC_HANDLERS] = { NULL }; Print* ModemClass::_debugPrint = NULL; -ModemClass::ModemClass(Uart& uart, unsigned long baud, int resetPin, int powerOnPin) : +ModemClass::ModemClass(Uart& uart, unsigned long baud, int resetPin, int powerOnPin, int vIntPin) : _uart(&uart), _baud(baud), _resetPin(resetPin), _powerOnPin(powerOnPin), + _vIntPin(vIntPin), _lastResponseOrUrcMillis(0), _atCommandState(AT_COMMAND_IDLE), _ready(1), @@ -37,19 +38,42 @@ ModemClass::ModemClass(Uart& uart, unsigned long baud, int resetPin, int powerOn _buffer.reserve(64); } +void ModemClass::setVIntPin(int vIntPin) +{ + // Allow setting only if unset, used to track state + if (_vIntPin==SARA_VINT_OFF || _vIntPin==SARA_VINT_ON) { + _vIntPin=vIntPin; + } +} + +int ModemClass::isPowerOn() +{ + if (_vIntPin==SARA_VINT_OFF) { + return 0; + } else if (_vIntPin==SARA_VINT_ON) { + return 1; + } + return digitalRead(_vIntPin); +} + int ModemClass::begin(bool restart) { + // datasheet warns not to use _resetPin, this may lead to an unrecoverable state + digitalWrite(_resetPin, LOW); + + if (restart) { + shutdown(); + end(); + } + _uart->begin(_baud > 115200 ? 115200 : _baud); // power on module - pinMode(_powerOnPin, OUTPUT); - digitalWrite(_powerOnPin, HIGH); - - if (_resetPin > -1 && restart) { - pinMode(_resetPin, OUTPUT); - digitalWrite(_resetPin, HIGH); - delay(100); - digitalWrite(_resetPin, LOW); + if (!isPowerOn()) { + digitalWrite(_powerOnPin, HIGH); + delay(150); // Datasheet says power-on pulse should be >=150ms, <=3200ms + digitalWrite(_powerOnPin, LOW); + setVIntPin(SARA_VINT_ON); } else { if (!autosense()) { return 0; @@ -78,13 +102,29 @@ int ModemClass::begin(bool restart) return 1; } +int ModemClass::shutdown() +{ + // AT command shutdown + if (isPowerOn()) { + send("AT+CPWROFF"); + if (waitForResponse(40000) != 1) { + return 0; + } + setVIntPin(SARA_VINT_OFF); + } + return 1; +} + void ModemClass::end() { _uart->end(); - digitalWrite(_resetPin, HIGH); - - // power off module - digitalWrite(_powerOnPin, LOW); + // Hardware pin power off + if (isPowerOn()) { + digitalWrite(_powerOnPin, HIGH); + delay(1500); // Datasheet says power-off pulse should be >=1500ms + digitalWrite(_powerOnPin, LOW); + setVIntPin(SARA_VINT_OFF); + } } void ModemClass::debug() @@ -340,4 +380,4 @@ void ModemClass::setBaudRate(unsigned long baud) _baud = baud; } -ModemClass MODEM(SerialSARA, 115200, SARA_RESETN, SARA_PWR_ON); +ModemClass MODEM(SerialSARA, 115200, SARA_RESETN, SARA_PWR_ON, SARA_VINT); diff --git a/src/Modem.h b/src/Modem.h index 4cefd0f..32b63a1 100644 --- a/src/Modem.h +++ b/src/Modem.h @@ -25,6 +25,18 @@ #include +/* The NB 1500 does not connect the SARA V_INT pin so that it can be monitored. + The below constants and associated code enables connecting SARA_VINT to a digital input + using a level shifter (1.8V to 5V) or simply a MOS transistor, say a 2N7000. + The code does rudimentary tracking of the on/off state if this is not available. +*/ +#define SARA_VINT_OFF (-1) +#define SARA_VINT_ON (-2) + +#ifndef SARA_VINT +#define SARA_VINT SARA_VINT_OFF +#endif + class ModemUrcHandler { public: virtual void handleUrc(const String& urc) = 0; @@ -32,7 +44,7 @@ class ModemUrcHandler { class ModemClass { public: - ModemClass(Uart& uart, unsigned long baud, int resetPin, int powerOnPin); + ModemClass(Uart& uart, unsigned long baud, int resetPin, int powerOnPin, int vIntPin=SARA_VINT); int begin(bool restart = false); void end(); @@ -45,6 +57,9 @@ class ModemClass { int noop(); int reset(); + int shutdown(); + int isPowerOn(); + void setVIntPin(int vIntPin); size_t write(uint8_t c); size_t write(const uint8_t*, size_t); @@ -69,6 +84,7 @@ class ModemClass { unsigned long _baud; int _resetPin; int _powerOnPin; + int _vIntPin; unsigned long _lastResponseOrUrcMillis; enum { diff --git a/src/NB.cpp b/src/NB.cpp index ffc4d95..81c8038 100644 --- a/src/NB.cpp +++ b/src/NB.cpp @@ -124,17 +124,17 @@ int NB::isAccessAlive() bool NB::shutdown() { - if (_state == NB_READY) { - MODEM.send("AT+CPWROFF"); - MODEM.waitForResponse(40000); + // Attempt AT command shutdown + if (_state == NB_READY && MODEM.shutdown()) { + _state = NB_OFF; + return true; } - MODEM.end(); - _state = NB_OFF; - return true; + return false; } bool NB::secureShutdown() { + // Hardware power off MODEM.end(); _state = NB_OFF; return true; diff --git a/src/NBFileUtils.cpp b/src/NBFileUtils.cpp index 16bfa17..7238d84 100644 --- a/src/NBFileUtils.cpp +++ b/src/NBFileUtils.cpp @@ -12,8 +12,7 @@ bool NBFileUtils::begin(const bool restart) { int status; - if (restart) - MODEM.begin(); + MODEM.begin(restart); if (_debug) { MODEM.debug();