From aba8a21001ffd2a0084085fc29cf6db7e3c51ce1 Mon Sep 17 00:00:00 2001 From: Ryan Erickson Date: Thu, 19 Aug 2021 14:18:55 -0500 Subject: [PATCH] drivers: modem: hl7800: Add Position over LTE (PoLTE) Position over LTE (PoLTE) can be used to locate a device as an alternative to GNSS. Increase RX thread stack size for PoLTE processing. Signed-off-by: Ryan Erickson --- drivers/modem/Kconfig.hl7800 | 6 +- drivers/modem/hl7800.c | 297 +++++++++++++++++++++++++++++++++ include/drivers/modem/hl7800.h | 71 ++++++++ 3 files changed, 373 insertions(+), 1 deletion(-) diff --git a/drivers/modem/Kconfig.hl7800 b/drivers/modem/Kconfig.hl7800 index 2528a177bdd..6d3ddcf29e9 100644 --- a/drivers/modem/Kconfig.hl7800 +++ b/drivers/modem/Kconfig.hl7800 @@ -244,7 +244,8 @@ endif # MODEM_HL7800_LOW_POWER_MODE config MODEM_HL7800_RX_STACK_SIZE int "Size of the stack for the HL7800 modem driver RX thread" - default 1024 + default 1536 if MODEM_HL7800_POLTE + default 1280 help This stack is used by the HL7800 RX thread. @@ -299,4 +300,7 @@ config MODEM_HL7800_USE_GLONASS bool "Use GLONASS in addition to GPS" depends on MODEM_HL7800_GPS +config MODEM_HL7800_POLTE + bool "Enable PoLTE commands and handlers" + endif # MODEM_HL7800 diff --git a/drivers/modem/hl7800.c b/drivers/modem/hl7800.c index 2dfa08578d5..9f8d2704008 100644 --- a/drivers/modem/hl7800.c +++ b/drivers/modem/hl7800.c @@ -1162,6 +1162,64 @@ error: } #endif /* CONFIG_MODEM_HL7800_GPS */ +#ifdef CONFIG_MODEM_HL7800_POLTE +int32_t mdm_hl7800_polte_register(void) +{ + int ret = -1; + + hl7800_lock(); + wakeup_hl7800(); + /* register for events */ + SEND_AT_CMD_EXPECT_OK("AT%POLTEEV=\"REGISTER\",1"); + SEND_AT_CMD_EXPECT_OK("AT%POLTEEV=\"LOCATION\",1"); + /* register with polte.io */ + SEND_AT_CMD_EXPECT_OK("AT%POLTECMD=\"REGISTER\""); +error: + LOG_DBG("PoLTE register status: %d", ret); + allow_sleep(true); + hl7800_unlock(); + return ret; +} + +int32_t mdm_hl7800_polte_enable(char *user, char *password) +{ + int ret = -1; + char buf[sizeof(MDM_HL7800_SET_POLTE_USER_AND_PASSWORD_FMT_STR) + + MDM_HL7800_MAX_POLTE_USER_ID_SIZE + MDM_HL7800_MAX_POLTE_PASSWORD_SIZE] = { 0 }; + + hl7800_lock(); + wakeup_hl7800(); + + /* register for events */ + SEND_AT_CMD_EXPECT_OK("AT%POLTEEV=\"REGISTER\",1"); + SEND_AT_CMD_EXPECT_OK("AT%POLTEEV=\"LOCATION\",1"); + /* restore user and password (not saved in NV by modem) */ + snprintk(buf, sizeof(buf), MDM_HL7800_SET_POLTE_USER_AND_PASSWORD_FMT_STR, user, password); + ret = send_at_cmd(NULL, buf, MDM_CMD_SEND_TIMEOUT, MDM_DEFAULT_AT_CMD_RETRIES, false); + +error: + LOG_DBG("PoLTE register status: %d", ret); + allow_sleep(true); + hl7800_unlock(); + return ret; +} + +int32_t mdm_hl7800_polte_locate(void) +{ + int ret = -1; + + hl7800_lock(); + wakeup_hl7800(); + SEND_AT_CMD_EXPECT_OK("AT%POLTECMD=\"LOCATE\",2,1"); +error: + LOG_DBG("PoLTE locate status: %d", ret); + allow_sleep(true); + hl7800_unlock(); + return ret; +} + +#endif /* CONFIG_MODEM_HL7800_POLTE */ + void mdm_hl7800_generate_status_events(void) { hl7800_lock(); @@ -2547,6 +2605,240 @@ static bool on_cmd_ver_speed(struct net_buf **buf, uint16_t len) } #endif /* CONFIG_MODEM_HL7800_GPS */ +#ifdef CONFIG_MODEM_HL7800_POLTE +/* Handler: %POLTEEVU: "REGISTER",0, , */ +static bool on_cmd_polte_registration(struct net_buf **buf, uint16_t len) +{ + char rsp[MDM_MAX_RESP_SIZE] = { 0 }; + size_t rsp_len = sizeof(rsp) - 1; + char *rsp_end = rsp + rsp_len; + struct mdm_hl7800_polte_registration_event_data data; + struct net_buf *frag = NULL; + size_t out_len; + char *location; + bool parsed; + + memset(&data, 0, sizeof(data)); + + wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf), sizeof(rsp)); + + location = rsp; + parsed = false; + frag = NULL; + len = net_buf_findcrlf(*buf, &frag); + do { + if (!frag) { + LOG_ERR("Unable to find end"); + break; + } + + if (len > rsp_len) { + LOG_WRN("string too long (len:%d)", len); + len = rsp_len; + } + + out_len = net_buf_linearize(rsp, rsp_len, *buf, 0, len); + rsp[out_len] = 0; + + /* Command handler looks for string up to the user field */ + location = strstr(location, "\""); + if (location != NULL && location < rsp_end) { + location += 1; + if (location >= rsp_end) { + break; + } + data.user = location; + } else { + break; + } + + /* Find end of user field and null terminate string */ + location = strstr(location, "\""); + if (location != NULL && location < rsp_end) { + *location = 0; + location += 1; + if (location >= rsp_end) { + break; + } + } else { + break; + } + + location = strstr(location, ",\""); + if (location != NULL && location < rsp_end) { + location += 2; + if (location >= rsp_end) { + break; + } + data.password = location; + + } else { + break; + } + + location = strstr(location, "\""); + if (location != NULL && location < rsp_end) { + *location = 0; + } else { + break; + } + parsed = true; + } while (0); + + if (parsed && data.user && data.password) { + data.status = 0; + } else { + data.status = -1; + LOG_ERR("Unable to parse PoLTE registration"); + } + + event_handler(HL7800_EVENT_POLTE_REGISTRATION, &data); + + return true; +} + +/* Handler: %POLTECMD: "LOCATE", */ +static bool on_cmd_polte_locate_cmd_rsp(struct net_buf **buf, uint16_t len) +{ + char rsp[sizeof("99")] = { 0 }; + size_t rsp_len = sizeof(rsp) - 1; + size_t out_len; + struct net_buf *frag = NULL; + struct mdm_hl7800_polte_location_data data; + + memset(&data, 0, sizeof(data)); + + wait_for_modem_data_and_newline(buf, net_buf_frags_len(*buf), sizeof(rsp)); + + data.status = -1; + frag = NULL; + len = net_buf_findcrlf(*buf, &frag); + do { + if (!frag) { + LOG_ERR("Unable to find end"); + break; + } + + if (len > rsp_len) { + LOG_WRN("string too long (len:%d)", len); + len = rsp_len; + } + + out_len = net_buf_linearize(rsp, rsp_len, *buf, 0, len); + rsp[out_len] = 0; + + data.status = (uint32_t)strtoul(rsp, NULL, 10); + } while (0); + + event_handler(HL7800_EVENT_POLTE_LOCATE_STATUS, &data); + + return true; +} + +/* Handler: + * %POLTEEVU: "LOCATION",[,,,