Cellular: Fix BG96 power on and connect

pull/11372/head
Ari Parkkila 2019-08-29 04:24:07 -07:00
parent 5a6bf446d2
commit cb20277701
9 changed files with 100 additions and 90 deletions

View File

@ -43,6 +43,7 @@ set(unittest-test-sources
stubs/SerialBase_stub.cpp
stubs/CellularStateMachine_stub.cpp
stubs/CellularContext_stub.cpp
stubs/ThisThread_stub.cpp
stubs/ConditionVariable_stub.cpp
stubs/Mutex_stub.cpp
)

View File

@ -926,7 +926,7 @@ void ATHandler::set_3gpp_error(int err, DeviceErrorType error_type)
for (size_t i = 0; i < sizeof(map_3gpp_errors) / sizeof(map_3gpp_errors[0]); i++) {
if (map_3gpp_errors[i][0] == err) {
_last_3gpp_error = map_3gpp_errors[i][1];
tr_debug("AT3GPP error code %d", get_3gpp_error());
tr_error("AT3GPP error code %d", get_3gpp_error());
break;
}
}
@ -943,7 +943,7 @@ void ATHandler::at_error(bool error_code_expected, DeviceErrorType error_type)
set_3gpp_error(err, error_type);
_last_at_err.errCode = err;
_last_at_err.errType = error_type;
tr_error("AT error code %ld", err);
tr_warn("AT error code %ld", err);
} else {
tr_warn("ATHandler ERROR reading failed");
}

View File

@ -608,6 +608,7 @@ nsapi_error_t AT_CellularContext::open_data_channel()
connected, or timeout after 30 seconds*/
nsapi_error_t err = nsapi_ppp_connect(_at.get_file_handle(), callback(this, &AT_CellularContext::ppp_status_cb), _uname, _pwd, (nsapi_ip_stack_t)_pdp_type);
if (err) {
tr_error("nsapi_ppp_connect failed");
ppp_disconnected();
}
@ -993,6 +994,7 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr)
tr_info("cellular_callback: PPP mode and NSAPI_STATUS_DISCONNECTED");
_cb_data.error = NSAPI_ERROR_NO_CONNECTION;
_is_connected = false;
ppp_disconnected();
}
}
#else

View File

@ -15,6 +15,7 @@
* limitations under the License.
*/
#include "rtos/ThisThread.h"
#include "CellularUtil.h"
#include "AT_CellularDevice.h"
#include "AT_CellularInformation.h"
@ -202,6 +203,7 @@ nsapi_error_t AT_CellularDevice::get_sim_state(SimState &state)
_at->flush();
nsapi_error_t error = _at->at_cmd_str("+CPIN", "?", simstr, sizeof(simstr));
ssize_t len = strlen(simstr);
device_err_t err = _at->get_last_device_error();
_at->unlock();
if (len != -1) {
@ -213,7 +215,6 @@ nsapi_error_t AT_CellularDevice::get_sim_state(SimState &state)
state = SimStatePukNeeded;
} else {
simstr[len] = '\0';
tr_error("Unknown SIM state %s", simstr);
state = SimStateUnknown;
}
} else {
@ -229,7 +230,11 @@ nsapi_error_t AT_CellularDevice::get_sim_state(SimState &state)
tr_error("SIM PUK required");
break;
case SimStateUnknown:
tr_warn("SIM state unknown");
if (err.errType == DeviceErrorTypeErrorCME && err.errCode == 14) {
tr_info("SIM busy");
} else {
tr_warn("SIM state unknown");
}
break;
default:
tr_info("SIM is ready");
@ -443,12 +448,18 @@ nsapi_error_t AT_CellularDevice::init()
setup_at_handler();
_at->lock();
_at->flush();
_at->at_cmd_discard("E0", "");
_at->at_cmd_discard("+CMEE", "=1");
_at->at_cmd_discard("+CFUN", "=1");
for (int retry = 1; retry <= 3; retry++) {
_at->clear_error();
_at->flush();
_at->at_cmd_discard("E0", "");
_at->at_cmd_discard("+CMEE", "=1");
_at->at_cmd_discard("+CFUN", "=1");
if (_at->get_last_error() == NSAPI_ERROR_OK) {
break;
}
tr_debug("Wait 100ms to init modem");
rtos::ThisThread::sleep_for(100); // let modem have time to get ready
}
return _at->unlock_return_error();
}

View File

@ -211,8 +211,9 @@ nsapi_error_t AT_CellularNetwork::set_registration(const char *plmn)
if (!plmn) {
tr_debug("Automatic network registration");
NWRegisteringMode mode;
get_network_registering_mode(mode);
if (get_network_registering_mode(mode) != NSAPI_ERROR_OK) {
return NSAPI_ERROR_DEVICE_ERROR;
}
if (mode != NWModeAutomatic) {
return _at.at_cmd_discard("+COPS", "=0");
}

View File

@ -234,6 +234,9 @@ nsapi_error_t CellularDevice::shutdown()
}
CellularContext *curr = get_context_list();
while (curr) {
if (curr->is_connected()) {
curr->disconnect();
}
curr->cellular_callback(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED);
curr = (CellularContext *)curr->_next;
}

View File

@ -367,6 +367,7 @@ void CellularStateMachine::state_device_ready()
}
} else {
_status = 0;
_is_retry = true;
enter_to_state(STATE_INIT);
}
}

View File

@ -97,92 +97,35 @@ void QUECTEL_BG96::set_ready_cb(Callback<void()> callback)
_at->set_urc_handler(DEVICE_READY_URC, callback);
}
nsapi_error_t QUECTEL_BG96::hard_power_on()
{
if (_pwr.is_connected()) {
tr_info("Modem power on");
ThisThread::sleep_for(250);
_pwr = !_active_high;
ThisThread::sleep_for(250); // BG96_Hardware_Design_V1.1 says 100 ms, but 250 ms seems to be more robust
_pwr = _active_high;
ThisThread::sleep_for(500);
}
return NSAPI_ERROR_OK;
}
nsapi_error_t QUECTEL_BG96::soft_power_on()
{
if (!_rst.is_connected()) {
return NSAPI_ERROR_OK;
}
tr_info("Reset modem");
_rst = !_active_high;
ThisThread::sleep_for(100);
_rst = _active_high;
ThisThread::sleep_for(150 + 460); // RESET_N timeout from BG96_Hardware_Design_V1.1
_rst = !_active_high;
ThisThread::sleep_for(500);
// wait for RDY
_at->lock();
_at->set_at_timeout(10 * 1000);
_at->resp_start();
_at->set_stop_tag("RDY");
bool rdy = _at->consume_to_stop_tag();
_at->set_stop_tag(OK);
_at->restore_at_timeout();
if (!rdy) {
// check if modem was silently powered on
_at->clear_error();
_at->set_at_timeout(100);
_at->at_cmd_discard("", ""); //Send AT
_at->restore_at_timeout();
}
return _at->unlock_return_error();
}
nsapi_error_t QUECTEL_BG96::hard_power_off()
{
if (_pwr.is_connected()) {
tr_info("Modem power off");
_pwr = _active_high;
ThisThread::sleep_for(650); // from BG96_Hardware_Design_V1.1
_pwr = !_active_high;
tr_info("QUECTEL_BG96::soft_power_on");
// check if modem was powered on already
if (wake_up()) {
return NSAPI_ERROR_OK;
}
if (!wake_up(true)) {
tr_error("Modem not responding");
soft_power_off();
return NSAPI_ERROR_DEVICE_ERROR;
}
}
return NSAPI_ERROR_OK;
}
nsapi_error_t QUECTEL_BG96::init()
nsapi_error_t QUECTEL_BG96::soft_power_off()
{
setup_at_handler();
int retry = 0;
_at->lock();
_at->flush();
_at->at_cmd_discard("E0", ""); // echo off
_at->at_cmd_discard("+CMEE", "=1"); // verbose responses
_at->cmd_start("AT+QPOWD");
_at->cmd_stop_read_resp();
if (_at->get_last_error() != NSAPI_ERROR_OK) {
return _at->unlock_return_error();
}
do {
_at->clear_error();
_at->at_cmd_discard("+CFUN", "=1"); // set full functionality
if (_at->get_last_error() == NSAPI_ERROR_OK) {
break;
tr_warn("Force modem off");
if (_pwr.is_connected()) {
press_button(_pwr, 650); // BG96_Hardware_Design_V1.1: Power off signal at least 650 ms
}
// wait some time that modem gets ready for CFUN command, and try again
retry++;
ThisThread::sleep_for(64); // experimental value
} while (retry < 3);
}
return _at->unlock_return_error();
}
@ -215,3 +158,52 @@ void QUECTEL_BG96::urc_pdpdeact()
}
send_disconnect_to_context(cid);
}
void QUECTEL_BG96::press_button(DigitalOut &button, uint32_t timeout)
{
if (!button.is_connected()) {
return;
}
button = _active_high;
ThisThread::sleep_for(timeout);
button = !_active_high;
}
bool QUECTEL_BG96::wake_up(bool reset)
{
// check if modem is already ready
_at->lock();
_at->flush();
_at->set_at_timeout(30);
_at->cmd_start("AT");
_at->cmd_stop_read_resp();
nsapi_error_t err = _at->get_last_error();
_at->restore_at_timeout();
_at->unlock();
// modem is not responding, power it on
if (err != NSAPI_ERROR_OK) {
if (!reset) {
// BG96_Hardware_Design_V1.1 requires VBAT to be stable over 30 ms, that's handled above
tr_info("Power on modem");
press_button(_pwr, 250); // BG96_Hardware_Design_V1.1 requires time 100 ms, but 250 ms seems to be more robust
} else {
tr_warn("Reset modem");
press_button(_rst, 150); // BG96_Hardware_Design_V1.1 requires RESET_N timeout at least 150 ms
}
_at->lock();
// According to BG96_Hardware_Design_V1.1 USB is active after 4.2s, but it seems to take over 5s
_at->set_at_timeout(6000);
_at->resp_start();
_at->set_stop_tag("RDY");
bool rdy = _at->consume_to_stop_tag();
_at->set_stop_tag(OK);
_at->restore_at_timeout();
_at->unlock();
if (!rdy) {
return false;
}
}
// sync to check that AT is really responsive and to clear garbage
return _at->sync(500);
}

View File

@ -41,17 +41,16 @@ protected: // AT_CellularDevice
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, bool cp_req = false, bool nonip_req = false);
virtual AT_CellularInformation *open_information_impl(ATHandler &at);
virtual void set_ready_cb(Callback<void()> callback);
virtual nsapi_error_t hard_power_on();
virtual nsapi_error_t hard_power_off();
virtual nsapi_error_t soft_power_on();
virtual nsapi_error_t init();
virtual nsapi_error_t soft_power_off();
virtual void set_at_urcs_impl();
public:
void handle_urc(FileHandle *fh);
private:
nsapi_error_t press_power_button(uint32_t timeout);
void press_button(DigitalOut &button, uint32_t timeout);
bool wake_up(bool reset = false);
bool _active_high;
DigitalOut _pwr;
DigitalOut _rst;