1 /** @file 2 * @brief HL7800 modem public API header file. 3 * 4 * Allows an application to control the HL7800 modem. 5 * 6 * Copyright (c) 2020 Laird Connectivity 7 * 8 * SPDX-License-Identifier: Apache-2.0 9 */ 10 11 #ifndef ZEPHYR_INCLUDE_DRIVERS_MODEM_HL7800_H_ 12 #define ZEPHYR_INCLUDE_DRIVERS_MODEM_HL7800_H_ 13 14 #ifdef __cplusplus 15 extern "C" { 16 #endif 17 18 #include <zephyr/types.h> 19 20 #include <time.h> 21 22 /* The size includes the NUL character, the strlen doesn't */ 23 #define MDM_HL7800_REVISION_MAX_SIZE 29 24 #define MDM_HL7800_REVISION_MAX_STRLEN (MDM_HL7800_REVISION_MAX_SIZE - 1) 25 26 #define MDM_HL7800_IMEI_SIZE 16 27 #define MDM_HL7800_IMEI_STRLEN (MDM_HL7800_IMEI_SIZE - 1) 28 29 #define MDM_HL7800_ICCID_MAX_SIZE 21 30 #define MDM_HL7800_ICCID_MAX_STRLEN (MDM_HL7800_ICCID_MAX_SIZE - 1) 31 32 #define MDM_HL7800_SERIAL_NUMBER_SIZE 15 33 #define MDM_HL7800_SERIAL_NUMBER_STRLEN (MDM_HL7800_SERIAL_NUMBER_SIZE - 1) 34 35 #define MDM_HL7800_APN_MAX_SIZE 64 36 #define MDM_HL7800_APN_USERNAME_MAX_SIZE 65 37 #define MDM_HL7800_APN_PASSWORD_MAX_SIZE 65 38 39 #define MDM_HL7800_APN_MAX_STRLEN (MDM_HL7800_APN_MAX_SIZE - 1) 40 #define MDM_HL7800_APN_USERNAME_MAX_STRLEN \ 41 (MDM_HL7800_APN_USERNAME_MAX_SIZE - 1) 42 #define MDM_HL7800_APN_PASSWORD_MAX_STRLEN \ 43 (MDM_HL7800_APN_PASSWORD_MAX_SIZE - 1) 44 45 #define MDM_HL7800_APN_CMD_MAX_SIZE \ 46 (32 + MDM_HL7800_APN_USERNAME_MAX_STRLEN + \ 47 MDM_HL7800_APN_PASSWORD_MAX_STRLEN) 48 49 #define MDM_HL7800_APN_CMD_MAX_STRLEN (MDM_HL7800_APN_CMD_MAX_SIZE - 1) 50 51 struct mdm_hl7800_apn { 52 char value[MDM_HL7800_APN_MAX_SIZE]; 53 char username[MDM_HL7800_APN_USERNAME_MAX_SIZE]; 54 char password[MDM_HL7800_APN_PASSWORD_MAX_SIZE]; 55 }; 56 57 #define MDM_HL7800_LTE_BAND_STR_SIZE 21 58 #define MDM_HL7800_LTE_BAND_STRLEN (MDM_HL7800_LTE_BAND_STR_SIZE - 1) 59 60 #define MDM_HL7800_OPERATOR_INDEX_SIZE 3 61 #define MDM_HL7800_OPERATOR_INDEX_STRLEN (MDM_HL7800_OPERATOR_INDEX_SIZE - 1) 62 63 #define MDM_HL7800_IMSI_MIN_STR_SIZE 15 64 #define MDM_HL7800_IMSI_MAX_STR_SIZE 16 65 #define MDM_HL7800_IMSI_MAX_STRLEN (MDM_HL7800_IMSI_MAX_STR_SIZE - 1) 66 67 #define MDM_HL7800_MODEM_FUNCTIONALITY_SIZE 2 68 #define MDM_HL7800_MODEM_FUNCTIONALITY_STRLEN \ 69 (MDM_HL7800_MODEM_FUNCTIONALITY_SIZE - 1) 70 71 #define MDM_HL7800_MAX_GPS_STR_SIZE 33 72 73 #define MDM_HL7800_MAX_POLTE_USER_ID_SIZE 16 74 #define MDM_HL7800_MAX_POLTE_PASSWORD_SIZE 16 75 #define MDM_HL7800_MAX_POLTE_LOCATION_STR_SIZE 33 76 77 /* Assign the server error code (location response) to a value 78 * that isn't used by locate response so that a single status 79 * callback can be used. 80 */ 81 #define MDM_HL7800_POLTE_SERVER_ERROR 10 82 83 #define MDM_HL7800_SET_POLTE_USER_AND_PASSWORD_FMT_STR "AT%%POLTECMD=\"SERVERAUTH\",\"%s\",\"%s\"" 84 85 struct mdm_hl7800_site_survey { 86 uint32_t earfcn; /* EUTRA Absolute Radio Frequency Channel Number */ 87 uint32_t cell_id; 88 int rsrp; 89 int rsrq; 90 }; 91 92 enum mdm_hl7800_radio_mode { MDM_RAT_CAT_M1 = 0, MDM_RAT_CAT_NB1 }; 93 94 enum mdm_hl7800_event { 95 HL7800_EVENT_RESERVED = 0, 96 HL7800_EVENT_NETWORK_STATE_CHANGE, 97 HL7800_EVENT_APN_UPDATE, 98 HL7800_EVENT_RSSI, 99 HL7800_EVENT_SINR, 100 HL7800_EVENT_STARTUP_STATE_CHANGE, 101 HL7800_EVENT_SLEEP_STATE_CHANGE, 102 HL7800_EVENT_RAT, 103 HL7800_EVENT_BANDS, 104 HL7800_EVENT_ACTIVE_BANDS, 105 HL7800_EVENT_FOTA_STATE, 106 HL7800_EVENT_FOTA_COUNT, 107 HL7800_EVENT_REVISION, 108 HL7800_EVENT_GPS, 109 HL7800_EVENT_GPS_POSITION_STATUS, 110 HL7800_EVENT_POLTE_REGISTRATION, 111 HL7800_EVENT_POLTE_LOCATE_STATUS, 112 HL7800_EVENT_POLTE, 113 HL7800_EVENT_SITE_SURVEY, 114 HL7800_EVENT_STATE, 115 }; 116 117 enum mdm_hl7800_state { 118 HL7800_STATE_NOT_READY = 0, 119 HL7800_STATE_INITIALIZED, 120 }; 121 122 enum mdm_hl7800_startup_state { 123 HL7800_STARTUP_STATE_READY = 0, 124 HL7800_STARTUP_STATE_WAITING_FOR_ACCESS_CODE, 125 HL7800_STARTUP_STATE_SIM_NOT_PRESENT, 126 HL7800_STARTUP_STATE_SIMLOCK, 127 HL7800_STARTUP_STATE_UNRECOVERABLE_ERROR, 128 HL7800_STARTUP_STATE_UNKNOWN, 129 HL7800_STARTUP_STATE_INACTIVE_SIM 130 }; 131 132 enum mdm_hl7800_network_state { 133 HL7800_NOT_REGISTERED = 0, 134 HL7800_HOME_NETWORK, 135 HL7800_SEARCHING, 136 HL7800_REGISTRATION_DENIED, 137 HL7800_OUT_OF_COVERAGE, 138 HL7800_ROAMING, 139 HL7800_EMERGENCY = 8, 140 /* Laird defined states */ 141 HL7800_UNABLE_TO_CONFIGURE = 0xf0 142 }; 143 144 enum mdm_hl7800_sleep { 145 HL7800_SLEEP_UNINITIALIZED = 0, 146 HL7800_SLEEP_HIBERNATE, 147 HL7800_SLEEP_AWAKE, 148 HL7800_SLEEP_LITE_HIBERNATE, 149 HL7800_SLEEP_SLEEP, 150 }; 151 152 enum mdm_hl7800_fota_state { 153 HL7800_FOTA_IDLE, 154 HL7800_FOTA_START, 155 HL7800_FOTA_WIP, 156 HL7800_FOTA_PAD, 157 HL7800_FOTA_SEND_EOT, 158 HL7800_FOTA_FILE_ERROR, 159 HL7800_FOTA_INSTALL, 160 HL7800_FOTA_REBOOT_AND_RECONFIGURE, 161 HL7800_FOTA_COMPLETE, 162 }; 163 164 enum mdm_hl7800_functionality { 165 HL7800_FUNCTIONALITY_MINIMUM = 0, 166 HL7800_FUNCTIONALITY_FULL = 1, 167 HL7800_FUNCTIONALITY_AIRPLANE = 4 168 }; 169 170 /* The modem reports state values as an enumeration and a string. 171 * GPS values are reported with a type of value and string. 172 */ 173 struct mdm_hl7800_compound_event { 174 uint8_t code; 175 char *string; 176 }; 177 178 enum mdm_hl7800_gnss_event { 179 HL7800_GNSS_EVENT_INVALID = -1, 180 HL7800_GNSS_EVENT_INIT, 181 HL7800_GNSS_EVENT_START, 182 HL7800_GNSS_EVENT_STOP, 183 HL7800_GNSS_EVENT_POSITION, 184 }; 185 186 enum mdm_hl7800_gnss_status { 187 HL7800_GNSS_STATUS_INVALID = -1, 188 HL7800_GNSS_STATUS_FAILURE, 189 HL7800_GNSS_STATUS_SUCCESS, 190 }; 191 192 enum mdm_hl7800_gnss_position_event { 193 HL7800_GNSS_POSITION_EVENT_INVALID = -1, 194 HL7800_GNSS_POSITION_EVENT_LOST_OR_NOT_AVAILABLE_YET, 195 HL7800_GNSS_POSITION_EVENT_PREDICTION_AVAILABLE, 196 HL7800_GNSS_POSITION_EVENT_2D_AVAILABLE, 197 HL7800_GNSS_POSITION_EVENT_3D_AVAILABLE, 198 HL7800_GNSS_POSITION_EVENT_FIXED_TO_INVALID, 199 }; 200 201 enum mdm_hl7800_gps_string_types { 202 HL7800_GPS_STR_LATITUDE, 203 HL7800_GPS_STR_LONGITUDE, 204 HL7800_GPS_STR_GPS_TIME, 205 HL7800_GPS_STR_FIX_TYPE, 206 HL7800_GPS_STR_HEPE, 207 HL7800_GPS_STR_ALTITUDE, 208 HL7800_GPS_STR_ALT_UNC, 209 HL7800_GPS_STR_DIRECTION, 210 HL7800_GPS_STR_HOR_SPEED, 211 HL7800_GPS_STR_VER_SPEED 212 }; 213 214 /* status: negative errno, 0 on success 215 * user and password aren't valid if status is non-zero. 216 */ 217 struct mdm_hl7800_polte_registration_event_data { 218 int status; 219 char *user; 220 char *password; 221 }; 222 223 /* status: negative errno, 0 on success, non-zero error code 224 * Data is not valid if status is non-zero. 225 */ 226 struct mdm_hl7800_polte_location_data { 227 uint32_t timestamp; 228 int status; 229 char latitude[MDM_HL7800_MAX_POLTE_LOCATION_STR_SIZE]; 230 char longitude[MDM_HL7800_MAX_POLTE_LOCATION_STR_SIZE]; 231 char confidence_in_meters[MDM_HL7800_MAX_POLTE_LOCATION_STR_SIZE]; 232 }; 233 234 /** 235 * event - The type of event 236 * event_data - Pointer to event specific data structure: 237 * HL7800_EVENT_NETWORK_STATE_CHANGE - mdm_hl7800_compound_event 238 * HL7800_EVENT_APN_UPDATE - struct mdm_hl7800_apn 239 * HL7800_EVENT_RSSI - int 240 * HL7800_EVENT_SINR - int 241 * HL7800_EVENT_STARTUP_STATE_CHANGE - mdm_hl7800_compound_event 242 * HL7800_EVENT_SLEEP_STATE_CHANGE - mdm_hl7800_compound_event 243 * HL7800_EVENT_RAT - int 244 * HL7800_EVENT_BANDS - string 245 * HL7800_EVENT_ACTIVE_BANDS - string 246 * HL7800_EVENT_FOTA_STATE - mdm_hl7800_compound_event 247 * HL7800_EVENT_FOTA_COUNT - uint32_t 248 * HL7800_EVENT_REVISION - string 249 * HL7800_EVENT_GPS - mdm_hl7800_compound_event 250 * HL7800_EVENT_GPS_POSITION_STATUS int 251 * HL7800_EVENT_POLTE_REGISTRATION mdm_hl7800_polte_registration_event_data 252 * HL7800_EVENT_POLTE mdm_hl7800_polte_location_data 253 * HL7800_EVENT_POLTE_LOCATE_STATUS int 254 * HL7800_EVENT_SITE_SURVEY mdm_hl7800_site_survey 255 * HL7800_EVENT_STATE mdm_hl7800_compound_event 256 */ 257 typedef void (*mdm_hl7800_event_callback_t)(enum mdm_hl7800_event event, 258 void *event_data); 259 260 struct mdm_hl7800_callback_agent { 261 sys_snode_t node; 262 mdm_hl7800_event_callback_t event_callback; 263 }; 264 265 /** 266 * @brief Power off the HL7800 267 * 268 * @return int32_t 0 for success 269 */ 270 int32_t mdm_hl7800_power_off(void); 271 272 /** 273 * @brief Reset the HL7800 (and allow it to reconfigure). 274 * 275 * @return int32_t >= 0 for success, < 0 for failure 276 */ 277 int32_t mdm_hl7800_reset(void); 278 279 /** 280 * @brief Control the wake signals to the HL7800. 281 * @note this API should only be used for debug purposes. 282 * 283 * @param awake True to keep the HL7800 awake, False to allow sleep 284 */ 285 void mdm_hl7800_wakeup(bool awake); 286 287 /** 288 * @brief Send an AT command to the HL7800. 289 * @note This API should only be used for debug purposes. 290 * It is possible to break the driver using this API. 291 * 292 * @param data AT command string 293 * @param resp_timeout Timeout in seconds to wait for the response 294 * @param resp Pointer to the response buffer. This can be NULL to ignore the response. 295 * @param resp_len Input: length of the response buffer, Output: length of the response. 296 * This can be NULL. 297 * @return int32_t 0 for success 298 */ 299 int32_t mdm_hl7800_send_at_cmd(const uint8_t *data, uint8_t resp_timeout, char *resp, 300 uint16_t *resp_len); 301 302 /** 303 * @brief Get the signal quality of the HL7800. 304 * If CONFIG_MODEM_HL7800_RSSI_RATE_SECONDS is non-zero, then 305 * this function returns the value from the last periodic read. 306 * If CONFIG_MODEM_HL7800_RSSI_RATE_SECONDS is 0, then this 307 * may cause the modem to be woken so that the values can be queried. 308 * 309 * @param rsrp Reference Signals Received Power (dBm) 310 * Range = -140 dBm to -44 dBm 311 * @param sinr Signal to Interference plus Noise Ratio (dB) 312 * Range = -128 dB to 40 dB 313 */ 314 void mdm_hl7800_get_signal_quality(int *rsrp, int *sinr); 315 316 /** 317 * @brief Get the SIM card ICCID 318 * 319 */ 320 char *mdm_hl7800_get_iccid(void); 321 322 /** 323 * @brief Get the HL7800 serial number 324 * 325 */ 326 char *mdm_hl7800_get_sn(void); 327 328 /** 329 * @brief Get the HL7800 IMEI 330 * 331 */ 332 char *mdm_hl7800_get_imei(void); 333 334 /** 335 * @brief Get the HL7800 firmware version 336 * 337 */ 338 char *mdm_hl7800_get_fw_version(void); 339 340 /** 341 * @brief Get the IMSI 342 * 343 */ 344 char *mdm_hl7800_get_imsi(void); 345 346 /** 347 * @brief Update the Access Point Name in the modem. 348 * 349 * @retval 0 on success, negative on failure. 350 */ 351 int32_t mdm_hl7800_update_apn(char *access_point_name); 352 353 /** 354 * @brief Update the Radio Access Technology (mode). 355 * 356 * @retval 0 on success, negative on failure. 357 */ 358 int32_t mdm_hl7800_update_rat(enum mdm_hl7800_radio_mode value); 359 360 /** 361 * @retval true if RAT value is valid 362 */ 363 bool mdm_hl7800_valid_rat(uint8_t value); 364 365 /** 366 * @brief Register a function that is called when a modem event occurs. 367 * Multiple users registering for callbacks is supported. 368 * 369 * @param agent event callback agent 370 * 371 * @retval 0 on success, negative on failure 372 */ 373 int mdm_hl7800_register_event_callback(struct mdm_hl7800_callback_agent *agent); 374 375 /** 376 * @brief Unregister a callback event function 377 * 378 * @param agent event callback agent 379 * 380 * @retval 0 on success, negative on failure 381 */ 382 int mdm_hl7800_unregister_event_callback(struct mdm_hl7800_callback_agent *agent); 383 384 /** 385 * @brief Force modem module to generate status events. 386 * 387 * @note This can be used to get the current state when a module initializes 388 * later than the modem. 389 */ 390 void mdm_hl7800_generate_status_events(void); 391 392 /** 393 * @brief Get the local time from the modem's real time clock. 394 * 395 * @param tm time structure 396 * @param offset The amount the local time is offset from GMT/UTC in seconds. 397 * @return int32_t 0 if successful 398 */ 399 int32_t mdm_hl7800_get_local_time(struct tm *tm, int32_t *offset); 400 401 #ifdef CONFIG_MODEM_HL7800_FW_UPDATE 402 /** 403 * @brief Update the HL7800 via XMODEM protocol. During the firmware update 404 * no other modem functions will be available. 405 * 406 * @param file_path Absolute path of the update file 407 * 408 * @param 0 if successful 409 */ 410 int32_t mdm_hl7800_update_fw(char *file_path); 411 #endif 412 413 /** 414 * @brief Read the operator index from the modem. 415 * 416 * @retval negative error code, 0 on success 417 */ 418 int32_t mdm_hl7800_get_operator_index(void); 419 420 /** 421 * @brief Get modem functionality 422 * 423 * @return int32_t negative errno on failure, else mdm_hl7800_functionality 424 */ 425 int32_t mdm_hl7800_get_functionality(void); 426 427 /** 428 * @brief Set airplane, normal, or reduced functionality mode. 429 * Airplane mode persists when reset. 430 * 431 * @note Boot functionality is also controlled by Kconfig 432 * MODEM_HL7800_BOOT_IN_AIRPLANE_MODE. 433 * 434 * @param mode 435 * @return int32_t negative errno, 0 on success 436 */ 437 int32_t mdm_hl7800_set_functionality(enum mdm_hl7800_functionality mode); 438 439 /** 440 * @brief When rate is non-zero: Put modem into Airplane mode. Enable GPS and 441 * generate HL7800_EVENT_GPS events. 442 * When zero: Disable GPS and put modem into normal mode. 443 * 444 * @note Airplane mode isn't cleared when the modem is reset. 445 * 446 * @param rate in seconds to query location 447 * @return int32_t negative errno, 0 on success 448 */ 449 int32_t mdm_hl7800_set_gps_rate(uint32_t rate); 450 451 /** 452 * @brief Register modem/SIM with polte.io 453 * 454 * @note It takes around 30 seconds for HL7800_EVENT_POLTE_REGISTRATION to 455 * be generated. If the applications saves the user and password 456 * information into non-volatile memory, then this command 457 * only needs to be run once. 458 * 459 * @return int32_t negative errno, 0 on success 460 */ 461 int32_t mdm_hl7800_polte_register(void); 462 463 /** 464 * @brief Enable PoLTE. 465 * 466 * @param user from polte.io or register command callback 467 * @param password from polte.io register command callback 468 * @return int32_t negative errno, 0 on success 469 */ 470 int32_t mdm_hl7800_polte_enable(char *user, char *password); 471 472 /** 473 * @brief Locate device using PoLTE. 474 * 475 * @note The first HL7800_EVENT_POLTE_LOCATE_STATUS event indicates 476 * the status of issuing the locate command. The second event 477 * requires 20-120 seconds to be generated and it contains the 478 * location information (or indicates server failure). 479 * 480 * @return int32_t negative errno, 0 on success 481 */ 482 int32_t mdm_hl7800_polte_locate(void); 483 484 /** 485 * @brief Perform a site survey. This command may return different values 486 * each time it is run (depending on what is in range). 487 * 488 * HL7800_EVENT_SITE_SURVEY is generated for each response received from modem. 489 * 490 * @retval negative error code, 0 on success 491 */ 492 int32_t mdm_hl7800_perform_site_survey(void); 493 494 /** 495 * @brief Set desired sleep level. Requires MODEM_HL7800_LOW_POWER_MODE 496 * 497 * @param level (sleep, lite hibernate, or hibernate) 498 * @return int negative errno, 0 on success 499 */ 500 int mdm_hl7800_set_desired_sleep_level(enum mdm_hl7800_sleep level); 501 502 /** 503 * @brief Allows mapping of WAKE_UP signal 504 * to a user accessible test point on the development board. 505 * 506 * @param func to be called when application requests modem wake/sleep. 507 * The state parameter of the callback is 1 when modem should stay awake, 508 * 0 when modem can sleep 509 */ 510 void mdm_hl7800_register_wake_test_point_callback(void (*func)(int state)); 511 512 /** 513 * @brief Allows mapping of P1.12_GPIO6 signal 514 * to a user accessible test point on the development board. 515 * 516 * @param func to be called when modem wakes/sleeps is sleep level is 517 * hibernate or lite hibernate. 518 * The state parameter of the callback follows gpio_pin_get definitions, 519 * but will default high if there is an error reading pin 520 */ 521 void mdm_hl7800_register_gpio6_callback(void (*func)(int state)); 522 523 /** 524 * @brief Allows mapping of UART1_CTS signal 525 * to a user accessible test point on the development board. 526 * 527 * @param func to be called when CTS state changes if sleep level is sleep. 528 * The state parameter of the callback follows gpio_pin_get definitions, 529 * but will default low if there is an error reading pin 530 */ 531 void mdm_hl7800_register_cts_callback(void (*func)(int state)); 532 533 /** 534 * @brief Set the bands available for the LTE connection. 535 * NOTE: This will cause the modem to reboot. This call returns before the reboot. 536 * 537 * @param bands Band bitmap in hexadecimal format without the 0x prefix. 538 * Leading 0's for the value can be omitted. 539 * 540 * @return int32_t negative errno, 0 on success 541 */ 542 int32_t mdm_hl7800_set_bands(const char *bands); 543 544 /** 545 * @brief Set the log level for the modem. 546 * 547 * @note It cannot be set higher than CONFIG_MODEM_LOG_LEVEL. 548 * If debug level is desired, then it must be compiled with that level. 549 * 550 * @param level 0 (None) - 4 (Debug) 551 * 552 * @retval new log level 553 */ 554 uint32_t mdm_hl7800_log_filter_set(uint32_t level); 555 556 #ifdef __cplusplus 557 } 558 #endif 559 560 #endif /* ZEPHYR_INCLUDE_DRIVERS_MODEM_HL7800_H_ */ 561