static int read_IMEI(Serial *serial)
{
    int res = sendCommand(serial, "AT+GSN\r", "");
    if (res != NO_CELL_RESPONSE && strlen(g_cellBuffer) == 15) {
        strncpy(g_IMEI_number, g_cellBuffer, IMEI_NUMBER_LENGTH);
        pr_debug_str_msg("Cell: IMEI: ", g_IMEI_number);
    }
    return res;
}
static enum writing_status open_existing_log_file(struct logging_status *ls)
{
        pr_debug_str_msg("Logging: Opening log file ", ls->name);

        int rc = f_open(g_logfile, ls->name, FA_WRITE);

        if (FR_OK != rc)
                return WRITING_INACTIVE;

        // Seek to the end so we append instead of overwriting
        rc = f_lseek(g_logfile, f_size(g_logfile));

        return rc == FR_OK ? WRITING_ACTIVE : WRITING_INACTIVE;
}
static int read_subscriber_number(Serial *serial)
{
    int res = sendCommand(serial, "AT+CNUM\r", "+CNUM:");
    if (res != NO_CELL_RESPONSE) {
        char *num_start = strstr(g_cellBuffer, ",\"");
        if (num_start) {
            num_start += 2;
            char *num_end = strstr(num_start, "\"");
            if (num_end) {
                *num_end = '\0';
                strncpy(g_subscriber_number, num_start, MAX_SUBSCRIBER_NUMBER_LENGTH);
                pr_debug_str_msg("Cell: phone number: ", num_start);
            }
        }
    }
    return res;
}
void connectivityTask(void *params)
{

    char * buffer = (char *)portMalloc(BUFFER_SIZE);
    size_t rxCount = 0;

    ConnParams *connParams = (ConnParams*)params;
    LoggerMessage msg;

    Serial *serial = get_serial(connParams->serial);

    xQueueHandle sampleQueue = connParams->sampleQueue;
    uint32_t connection_timeout = connParams->connection_timeout;

    DeviceConfig deviceConfig;
    deviceConfig.serial = serial;
    deviceConfig.buffer = buffer;
    deviceConfig.length = BUFFER_SIZE;

    const LoggerConfig *logger_config = getWorkingLoggerConfig();

    bool logging_enabled = false;

    while (1) {
        bool should_stream = logging_enabled ||
                             logger_config->ConnectivityConfigs.telemetryConfig.backgroundStreaming ||
                             connParams->always_streaming;

        while (should_stream && connParams->init_connection(&deviceConfig) != DEVICE_INIT_SUCCESS) {
            pr_info("conn: not connected. retrying\r\n");
            vTaskDelay(INIT_DELAY);
        }

        serial->flush();
        rxCount = 0;
        size_t badMsgCount = 0;
        size_t tick = 0;
        size_t last_message_time = getUptimeAsInt();
        bool should_reconnect = false;

        while (1) {
            if ( should_reconnect )
                break; /*break out and trigger the re-connection if needed */

            should_stream =
                    logging_enabled ||
                    connParams->always_streaming ||
                    logger_config->ConnectivityConfigs.telemetryConfig.backgroundStreaming;

            const char res = receive_logger_message(sampleQueue, &msg,
                                                    IDLE_TIMEOUT);

            /*///////////////////////////////////////////////////////////
            // Process a pending message from logger task, if exists
            ////////////////////////////////////////////////////////////*/
            if (pdFALSE != res) {
                switch(msg.type) {
                case LoggerMessageType_Start: {
                    api_sendLogStart(serial);
                    put_crlf(serial);
                    tick = 0;
                    logging_enabled = true;
                    /* If we're not already streaming trigger a re-connect */
                    if (!should_stream)
                        should_reconnect = true;
                    break;
                }
                case LoggerMessageType_Stop: {
                    api_sendLogEnd(serial);
                    put_crlf(serial);
                    if (! (logger_config->ConnectivityConfigs.telemetryConfig.backgroundStreaming ||
                           connParams->always_streaming))
                        should_reconnect = true;
                    logging_enabled = false;
                    break;
                }
                case LoggerMessageType_Sample: {
                        if (!should_stream)
                                break;

                        const int send_meta = tick == 0 ||
                                (connParams->periodicMeta &&
                                 (tick % METADATA_SAMPLE_INTERVAL == 0));
                        api_send_sample_record(serial, msg.sample, tick, send_meta);

                        if (connParams->isPrimary)
                                toggle_connectivity_indicator();

                        put_crlf(serial);
                        tick++;
                        break;
                }
                default:
                    break;
                }
            }

            /*//////////////////////////////////////////////////////////
            // Process incoming message, if available
            ////////////////////////////////////////////////////////////
            //read in available characters, process message as necessary*/
            int msgReceived = processRxBuffer(serial, buffer, &rxCount);
            /*check the latest contents of the buffer for something that might indicate an error condition*/
            if (connParams->check_connection_status(&deviceConfig) != DEVICE_STATUS_NO_ERROR) {
                pr_info("conn: disconnected\r\n");
                break;
            }
            /*now process a complete message if available*/
            if (msgReceived) {
                last_message_time = getUptimeAsInt();
                pr_debug(connParams->connectionName);
                pr_debug_str_msg(": rx: ", buffer);
                int msgRes = process_api(serial, buffer, BUFFER_SIZE);

                int msgError = (msgRes == API_ERROR_MALFORMED);
                if (msgError) {
                    pr_debug("(failed)\r\n");
                }
                if (msgError) {
                    badMsgCount++;
                } else {
                    badMsgCount = 0;
                }
                if (badMsgCount >= BAD_MESSAGE_THRESHOLD) {
                    pr_warning_int_msg("re-connecting- empty/bad msgs :", badMsgCount );
                    break;
                }
                rxCount = 0;
            }

            /*disconnect if a timeout is configured and
            // we haven't heard from the other side for a while */
            const size_t timeout = getUptimeAsInt() - last_message_time;
            if (connection_timeout && timeout > connection_timeout ) {
                pr_info_str_msg(connParams->connectionName, ": timeout");
                should_reconnect = true;
            }
        }
        clear_connectivity_indicator();
        connParams->disconnect(&deviceConfig);
    }
}
void putsCell(Serial *serial, const char *data)
{
    LED_toggle(0);
    serial->put_s(data);
    pr_debug_str_msg("cellWrite: ", data);
}