void OBD2Task(void *pvParameters)
{
    pr_info("Start OBD2 task\r\n");
    size_t max_obd2_samplerate = msToTicks((TICK_RATE_HZ / MAX_OBD2_SAMPLE_RATE));
    LoggerConfig *config = getWorkingLoggerConfig();
    OBD2Config *oc = &config->OBD2Configs;
    while(1) {
        while(oc->enabled && oc->enabledPids > 0) {
            for (size_t i = 0; i < oc->enabledPids; i++) {
                PidConfig *pidCfg = &oc->pids[i];
                int value;
                unsigned char pid = pidCfg->pid;
                if (OBD2_request_PID(pid, &value, OBD2_PID_DEFAULT_TIMEOUT_MS)) {
                    OBD2_set_current_PID_value(i, value);
                    if (TRACE_LEVEL) {
                        pr_trace("read OBD2 PID ");
                        pr_trace_int(pid);
                        pr_trace("=")
                        pr_trace_int(value);
                        pr_trace("\r\n");
                    }
                } else {
                    pr_warning_int_msg("OBD2: PID read fail: ", pid);
                }
                delayTicks(max_obd2_samplerate);
            }
        }
        delayMs(OBD2_FEATURE_DISABLED_DELAY_MS);
    }
}
int serial_buffer_rx(struct serial_buffer *sb,
                     const size_t ms_delay)
{
        const size_t available = sb->length - sb->curr_len;
        char *ptr = sb->buffer + sb->curr_len;
        size_t msg_len = 0;

        while (!msg_len) {
                const int read = serial_get_line_wait(
                        sb->serial, ptr, available, msToTicks(ms_delay));

                if (!read) {
                        pr_trace("[serial_buffer] msg timeout\r\n");
                        return 0;
                }

                ctrl_char_strip(ptr);
                msg_len = strlen(ptr);
        }

        pr_trace("[serial_buffer] Msg (offset = ");
        pr_trace_int(sb->curr_len);
        pr_trace("): \"");
        pr_trace(ptr);
        pr_trace("\"\r\n");

        sb->curr_len += msg_len + 1;
        return msg_len + 1;
}