Watchdog Triggered Cheap Yellow Display
I am currently having an issue when trying to connect to SAE1850 devices but Ido not encounter the error with OBDII devices. I am trying to use LVGL on a cheap yellow display to make a simple multigauge.
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <XPT2046_Touchscreen.h>
#include <BluetoothSerial.h>
#include <ELMduino.h>
#include <atomic>
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 320
#define XPT2046_IRQ 36
#define XPT2046_MOSI 32
#define XPT2046_MISO 39
#define XPT2046_CLK 25
#define XPT2046_CS 33
#define LCD_BACK_LIGHT_PIN 21
#define LEDC_CHANNEL_0 0
#define LEDC_TIMER_12_BIT 12
#define LEDC_BASE_FREQ 5000
SPIClass touchscreenSPI(VSPI);
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);
TFT_eSPI tft = TFT_eSPI();
uint32_t draw_buf[SCREEN_WIDTH * SCREEN_HEIGHT / 10];
BluetoothSerial SerialBT;
ELM327 obd;
std::atomic<uint32_t> rpm{0};
std::atomic<uint32_t> coolant_temp{0};
std::atomic<uint32_t> voltage{0};
std::atomic<uint32_t> tpsval{0};
uint32_t last_displayed_rpm = -1;
uint32_t last_displayed_temp = -1;
uint32_t last_displayed_voltage = -1;
uint32_t last_displayed_tpsval = -1;
SemaphoreHandle_t lvgl_mutex;
TaskHandle_t lvgl_task_handle;
TaskHandle_t obd_task_handle;
TaskHandle_t bt_icon_task_handle;
static lv_obj_t *status_label;
static lv_obj_t *rpm_label;
static lv_obj_t *rpm_val;
static lv_obj_t *coolant_temp_label;
static lv_obj_t *coolant_temp_val;
static lv_obj_t *voltage_label;
static lv_obj_t *voltage_unit_label;
static lv_obj_t *voltage_val;
static lv_obj_t *TPS_label;
static lv_obj_t *TPS_unit_label;
static lv_obj_t *TPS_val;
static lv_obj_t *bt_icon_label;
static lv_obj_t *toggle_btn;
static lv_obj_t *settings_btn;
static lv_obj_t *settings_scr;
static lv_obj_t *main_scr;
static lv_obj_t *brightness_slider;
bool use_celsius = false;
uint8_t current_brightness = 128;
void lvgl_task(void *parameters);
void obd_task(void *parameters);
void bt_icon_task(void *parameters);
void show_main_screen();
void show_settings_screen();
void ledcAnalogWrite(uint8_t channel, uint32_t value, uint32_t valueMax = 255) {
// calculate duty, 4095 from 2 ^ 12 - 1
uint32_t duty = (4095 * min(value, valueMax)) / valueMax;
// write duty to LEDC
ledcWrite(channel, duty);
Serial.printf("duty value: %d\n", duty);
Serial.printf("brightness value: %d\n", current_brightness);
}
void brightness_slider_event_handler(lv_event_t *e) {
lv_obj_t *slider = (lv_obj_t *)lv_event_get_target(e); // Explicit cast added here
int value = lv_slider_get_value(slider);
current_brightness = value; // Update the global brightness value
Serial.printf("Brightness Slider Value: %d\n", value); // Log to Serial Monitor
ledcAnalogWrite(LEDC_CHANNEL_0, value);
// ⚡️ Later: Add brightness control logic here
}
void toggle_temp_unit_event_handler(lv_event_t *e) {
use_celsius = !use_celsius;
lv_obj_t *btn = (lv_obj_t *)lv_event_get_current_target(e);
lv_label_set_text(lv_obj_get_child(btn, 0), use_celsius ? "Units: Metric" : "Units: Standard");
update_coolant_temp_val(coolant_temp.load());
Serial.printf("Temperature unit changed to: %s\n", use_celsius ? "metric" : "standard");
}
void back_btn_event_handler(lv_event_t *e) {
show_main_screen();
}
void settings_btn_event_handler(lv_event_t *e) {
show_settings_screen();
}
void lv_create_settings_gui() {
settings_scr = lv_obj_create(NULL);
lv_obj_t *label = lv_label_create(settings_scr);
lv_label_set_text(label, "Settings");
lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 10);
lv_obj_t *temp_unit_btn = lv_btn_create(settings_scr);
lv_obj_add_flag(temp_unit_btn, LV_OBJ_FLAG_CHECKABLE);
lv_obj_set_height(temp_unit_btn, LV_SIZE_CONTENT);
lv_obj_align(temp_unit_btn, LV_ALIGN_CENTER, 0, 30);
lv_obj_add_event_cb(temp_unit_btn, toggle_temp_unit_event_handler, LV_EVENT_CLICKED, NULL);
lv_obj_t *btn_label = lv_label_create(temp_unit_btn);
lv_label_set_text(btn_label, "Units: Standard");
lv_obj_t *brightness_label = lv_label_create(settings_scr);
lv_label_set_text(brightness_label, "Brightness");
lv_obj_align(brightness_label, LV_ALIGN_CENTER, 0, -60);
brightness_slider = lv_slider_create(settings_scr);
lv_slider_set_range(brightness_slider, 0, 255);
lv_slider_set_value(brightness_slider, current_brightness, LV_ANIM_OFF);
lv_obj_set_size(brightness_slider, 180, 10);
lv_obj_align(brightness_slider, LV_ALIGN_CENTER, 0, -40);
lv_obj_add_event_cb(brightness_slider, brightness_slider_event_handler, LV_EVENT_VALUE_CHANGED, NULL);
lv_obj_t *back_btn = lv_btn_create(settings_scr);
lv_obj_set_height(back_btn, LV_SIZE_CONTENT);
lv_obj_align(back_btn, LV_ALIGN_TOP_RIGHT, -10, 10);
lv_obj_add_event_cb(back_btn, back_btn_event_handler, LV_EVENT_CLICKED, NULL);
lv_obj_t *back_label = lv_label_create(back_btn);
lv_label_set_text(back_label, "Back");
}
void lv_create_main_gui() {
static lv_style_t style_large_text;
lv_style_init(&style_large_text);
lv_style_set_text_font(&style_large_text, &lv_font_montserrat_48); // Change to desired font
static lv_style_t style_medium_text;
lv_style_init(&style_medium_text);
lv_style_set_text_font(&style_medium_text, &lv_font_montserrat_32); // Change to desired font
static lv_style_t style_mm_text;
lv_style_init(&style_mm_text);
lv_style_set_text_font(&style_mm_text, &lv_font_montserrat_22); // Change to desired font
static lv_style_t style_small_text;
lv_style_init(&style_small_text);
lv_style_set_text_font(&style_small_text, &lv_font_montserrat_18); // Change to desired font
main_scr = lv_scr_act();
status_label = lv_label_create(main_scr);
lv_label_set_text(status_label, "Status: Initializing...");
lv_obj_add_style(status_label, &style_small_text, 0);
lv_obj_align(status_label, LV_ALIGN_TOP_MID, 0, 10);
rpm_val = lv_label_create(main_scr);
lv_label_set_text(rpm_val, "----");
lv_obj_add_style(rpm_val, &style_large_text, 0);
lv_obj_align(rpm_val, LV_ALIGN_CENTER, 80, -20);
rpm_label = lv_label_create(main_scr);
lv_label_set_text(rpm_label, "RPM:");
lv_obj_add_style(rpm_label, &style_medium_text, 0);
lv_obj_align_to(rpm_label, rpm_val, LV_ALIGN_CENTER, 0, -30);
voltage_val = lv_label_create(main_scr);
lv_label_set_text(voltage_val, "--.-");
lv_obj_add_style(voltage_val, &style_large_text, 0);
lv_obj_align(voltage_val, LV_ALIGN_CENTER, 80, 70);
voltage_label = lv_label_create(main_scr);
lv_label_set_text(voltage_label, "Volts:");
lv_obj_add_style(voltage_label, &style_medium_text, 0);
lv_obj_align_to(voltage_label, voltage_val, LV_ALIGN_CENTER, 0, -40);
voltage_unit_label = lv_label_create(main_scr);
lv_label_set_text(voltage_unit_label, "V");
lv_obj_add_style(voltage_unit_label, &style_large_text, 0);
lv_obj_align_to(voltage_unit_label, voltage_val, LV_ALIGN_CENTER, 40, 0);
TPS_val = lv_label_create(main_scr);
lv_label_set_text(TPS_val, "---");
lv_obj_add_style(TPS_val, &style_large_text, 0);
lv_obj_align(TPS_val, LV_ALIGN_CENTER, -80, -20);
TPS_label = lv_label_create(main_scr);
lv_label_set_text(TPS_label, "Throttle Position:");
lv_obj_add_style(TPS_label, &style_small_text, 0);
lv_obj_align_to(TPS_label, TPS_val, LV_ALIGN_CENTER, 0, -30);
TPS_unit_label = lv_label_create(main_scr);
lv_label_set_text(TPS_unit_label, "%");
lv_obj_add_style(TPS_unit_label, &style_large_text, 0);
lv_obj_align_to(TPS_unit_label, TPS_val, LV_ALIGN_CENTER, 60, 0);
coolant_temp_val = lv_label_create(main_scr);
update_coolant_temp_val(coolant_temp.load());
lv_obj_add_style(coolant_temp_val, &style_large_text, 0);
lv_obj_align(coolant_temp_val, LV_ALIGN_CENTER, -80, 70);
coolant_temp_label = lv_label_create(main_scr);
lv_label_set_text(coolant_temp_label, "Coolant Temp:");
lv_obj_add_style(coolant_temp_label, &style_small_text, 0);
lv_obj_align_to(coolant_temp_label, coolant_temp_val, LV_ALIGN_CENTER, 0, -40);
bt_icon_label = lv_label_create(main_scr);
lv_label_set_text(bt_icon_label, "");
lv_obj_add_style(bt_icon_label, &style_small_text, 0);
lv_obj_align(bt_icon_label, LV_ALIGN_TOP_LEFT, 10, 10);
settings_btn = lv_btn_create(main_scr);
lv_obj_set_height(settings_btn, LV_SIZE_CONTENT);
lv_obj_align(settings_btn, LV_ALIGN_TOP_RIGHT, -5, 5);
lv_obj_add_event_cb(settings_btn, settings_btn_event_handler, LV_EVENT_CLICKED, NULL);
lv_obj_t *settings_label = lv_label_create(settings_btn);
lv_label_set_text(settings_label, LV_SYMBOL_SETTINGS);
}
void show_main_screen() {
lv_scr_load(main_scr);
}
void show_settings_screen() {
lv_scr_load(settings_scr);
}
void setup() {
Serial.begin(115200);
lv_init();
lvgl_mutex = xSemaphoreCreateMutex();
touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
touchscreen.begin(touchscreenSPI);
touchscreen.setRotation(2);
tft.init();
tft.begin();
// Initialize LEDC for backlight control
ledcSetup(LEDC_CHANNEL_0, LEDC_BASE_FREQ, LEDC_TIMER_12_BIT);
ledcAttachPin(LCD_BACK_LIGHT_PIN, LEDC_CHANNEL_0);
ledcAnalogWrite(LEDC_CHANNEL_0, current_brightness); // Set initial brightness
delay(1000);
Serial.println("Setting initial brightness to 25...");
ledcAnalogWrite(LEDC_CHANNEL_0, 25); // Set to mid-high brightness
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
lv_display_t *disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));
lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270);
lv_indev_t *indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(indev, touchscreen_read);
lv_create_main_gui();
lv_create_settings_gui();
xTaskCreatePinnedToCore(lvgl_task, "LVGL Task", 12000, NULL, 3, &lvgl_task_handle, 1);
xTaskCreatePinnedToCore(obd_task, "OBD Task", 10000, NULL, 2, &obd_task_handle, 0);
xTaskCreatePinnedToCore(bt_icon_task, "BT Icon Task", 2048, NULL, 1, &bt_icon_task_handle, 1);
}
void loop() {
vTaskDelete(NULL);
}
void touchscreen_read(lv_indev_t *indev, lv_indev_data_t *data) {
if (touchscreen.tirqTouched() && touchscreen.touched()) {
TS_Point p = touchscreen.getPoint();
data->point.x = map(p.x, 200, 3700, 1, SCREEN_WIDTH);
data->point.y = map(p.y, 240, 3800, 1, SCREEN_HEIGHT);
data->state = LV_INDEV_STATE_PRESSED;
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
}
void lv_safe_call(std::function<void()> func) {
if (xSemaphoreTake(lvgl_mutex, pdMS_TO_TICKS(50))) {
func();
xSemaphoreGive(lvgl_mutex);
}
}
void update_status_label(const char *text) {
lv_safe_call([&]() { lv_label_set_text(status_label, text); });
}
void update_rpm_val(uint32_t current_rpm) {
if (current_rpm > 0 && current_rpm != last_displayed_rpm) {
lv_safe_call([&]() {
char buf[16];
snprintf(buf, sizeof(buf), "%d", current_rpm);
lv_label_set_text(rpm_val, buf);
});
last_displayed_rpm = current_rpm;
}
}
void update_coolant_temp_val(uint32_t temp) {
lv_safe_call([&]() {
char buf[16]; // Adjust buffer size since we removed extra text
if (temp == 0 && last_displayed_temp == -1) {
snprintf(buf, sizeof(buf), "--%s", use_celsius ? "°C" : "°F");
} else {
uint32_t display_temp = use_celsius ? temp : static_cast<uint32_t>((temp * 9.0 / 5.0) + 32);
snprintf(buf, sizeof(buf), "%d%s", display_temp, use_celsius ? "°C" : "°F");
}
lv_label_set_text(coolant_temp_val, buf);
last_displayed_temp = temp;
});
}
void update_voltage_val(uint32_t voltage) {
if (voltage != last_displayed_voltage) {
lv_safe_call([&]() {
char buf[32]; // Increase buffer size to accommodate decimal points
snprintf(buf, sizeof(buf), "%.1f", static_cast<float>(voltage)); // Use float directly
lv_label_set_text(voltage_val, buf);
});
last_displayed_voltage = voltage;
}
}
void update_TPS_val(uint32_t tpsval) {
if (tpsval != last_displayed_tpsval) {
lv_safe_call([&]() {
char buf[32]; // Increase buffer size to accommodate decimal points
snprintf(buf, sizeof(buf), "%d", tpsval);
lv_label_set_text(TPS_val, buf);
});
last_displayed_tpsval = tpsval;
}
}
void connect_to_obd() {
update_status_label("Connecting to OBD...");
SerialBT.begin("ESP32_OBD", true);
//SerialBT.setTimeout(50);
if (!SerialBT.connect("OBDII")) {
update_status_label("Retrying OBD connection...");
//vTaskDelay(pdMS_TO_TICKS(1000));
}
SerialBT.println("AT Z"); // Reset
vTaskDelay(pdMS_TO_TICKS(1000));
if (!obd.begin(SerialBT, true, 2000)) {
update_status_label("Reinitializing ELM327...");
// vTaskDelay(pdMS_TO_TICKS(200));
}
update_status_label("Connected to ELM327");
}
void lvgl_task(void *parameters) {
while (true) {
if (xSemaphoreTake(lvgl_mutex, portMAX_DELAY)) {
lv_task_handler();
lv_tick_inc(5);
xSemaphoreGive(lvgl_mutex);
}
vTaskDelay(pdMS_TO_TICKS(2));
}
}
typedef enum {
ENG_RPM,
COOLANT_TEMP,
VOLTAGE,
TPS
} obd_pid_states;
void obd_task(void *parameters) {
connect_to_obd(); // Initial connection
obd_pid_states obd_state = ENG_RPM;
while (true) {
if (!SerialBT.hasClient()) {
// If Bluetooth is disconnected, attempt to reconnect
update_status_label("OBD Disconnected! Reconnecting...");
while (!SerialBT.hasClient()) { // Keep trying until connected
Serial.println("Attempting to reconnect...");
SerialBT.end(); // Reset Bluetooth
vTaskDelay(pdMS_TO_TICKS(500)); // Short delay
SerialBT.begin("ESP32_OBD", true);
if (SerialBT.connect("OBDII")) {
connect_to_obd(); // Reinitialize OBD connection
update_status_label("Reconnected to OBD");
}
vTaskDelay(pdMS_TO_TICKS(2000)); // Wait before retrying
}
}
// Continue polling OBD if connected
switch (obd_state) {
case ENG_RPM: {
float tempRPM = obd.rpm();
if (obd.nb_rx_state == ELM_SUCCESS) {
rpm = static_cast<uint32_t>(tempRPM);
update_rpm_val(rpm.load());
obd_state = COOLANT_TEMP;
} else if (obd.nb_rx_state != ELM_GETTING_MSG) {
obd.printError();
obd_state = COOLANT_TEMP;
}
break;
}
case COOLANT_TEMP: {
float tempC = obd.engineCoolantTemp();
if (obd.nb_rx_state == ELM_SUCCESS) {
coolant_temp = static_cast<uint32_t>(tempC);
update_coolant_temp_val(coolant_temp.load());
obd_state = VOLTAGE;
} else if (obd.nb_rx_state != ELM_GETTING_MSG) {
obd.printError();
obd_state = VOLTAGE;
}
break;
}
case VOLTAGE: {
float voltageC = obd.ctrlModVoltage();
if (obd.nb_rx_state == ELM_SUCCESS) {
voltage = static_cast<uint32_t>(voltageC);
update_voltage_val(voltage.load());
obd_state = TPS;
} else if (obd.nb_rx_state != ELM_GETTING_MSG) {
obd.printError();
obd_state = TPS;
}
break;
}
case TPS: {
float throttle = obd.throttle();
if (obd.nb_rx_state == ELM_SUCCESS) {
tpsval = static_cast<uint32_t>(throttle);
update_TPS_val(tpsval.load());
obd_state = ENG_RPM;
} else if (obd.nb_rx_state != ELM_GETTING_MSG) {
obd.printError();
obd_state = ENG_RPM;
}
break;
}
}
vTaskDelay(pdMS_TO_TICKS(12)); // Small delay between readings
}
}
void bt_icon_task(void *parameters) {
bool visible = true;
while (true) {
lv_safe_call([&]() {
lv_label_set_text(bt_icon_label, SerialBT.hasClient() ? LV_SYMBOL_BLUETOOTH : (visible ? LV_SYMBOL_BLUETOOTH : ""));
// Update TPS label when Bluetooth is disconnected
if (!SerialBT.hasClient()) {
lv_label_set_text(rpm_val, "----");
lv_label_set_text(coolant_temp_val, "---");
lv_label_set_text(voltage_val, "--");
lv_label_set_text(TPS_val, "---");
update_status_label("Retrying connection...");
}
});
visible = !visible;
vTaskDelay(pdMS_TO_TICKS(SerialBT.hasClient() ? 500 : 250));
}
}
Serial monitor:
Delimiter found.
All chars received: OK
Clearing input serial buffer
Sending the following command/query: 0100
Received char: S
Received char: E
Received char: A
Received char: R
Received char: C
Received char: H
Received char: I
Received char: N
Received char: G
Received char: .
Received char: .
Received char: .
Received char: \r
E (47170) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (47170) task_wdt: - IDLE (CPU 0)
E (47170) task_wdt: Tasks currently running:
E (47170) task_wdt: CPU 0: OBD Task
E (47170) task_wdt: CPU 1: IDLE
E (47170) task_wdt: Aborting.
When I use the Bluetooth_multiple_pids example my serial monitor returns:
All chars received: OK
Clearing input serial buffer
Sending the following command/query: 0100
Received char: S
Received char: E
Received char: A
Received char: R
Received char: C
Received char: H
Received char: I
Received char: N
Received char: G
Received char: .
Received char: .
Received char: .
Received char: \r
Received char: U
Received char: N
Received char: A
Received char: B
Received char: L
Received char: E
Received char: _
Received char: T
Received char: O
Received char: _
Received char: C
Received char: O
Received char: N
Received char: N
Received char: E
Received char: C
Received char: T
Received char: \r
Received char: \r
Received char: >
Delimiter found.
All chars received: SEARCHING...UNABLETOCONNECT
ELM responded with error "UNABLE TO CONNECT"
Setting protocol via AT TP A%c did not work - trying via AT SP %c
Clearing input serial buffer
Sending the following command/query: AT SP 0
Received char: O
Received char: K
Received char: \r
Received char: \r
Received char: >
Delimiter found.
All chars received: OK
Since you know the protocol you want to connect with, try specifying that in obd.begin(). That will avoid the delay incurred with searching for the correct protocol.
Since you know the protocol you want to connect with, try specifying that in obd.begin(). That will avoid the delay incurred with searching for the correct protocol.
Well my car uses OBDII and my truck uses SAEJ1850, it would be great to make the device universal in also if I wanted to give them to friends.
In both cases, the failures are occurring at the initialization step, where ELM327 is doing the auto search for the correct protocol. The second failure isn't a timeout per se, it's a notice that the ELM327 device simply can't find a compatible ECU/protocol. It's possible the first example would return the same, if it weren't killed by the watchdog first. Are you certain that your ELM device works with the vehicles you're working with? Does it work with other apps or one of the simple sketches like examples/ESP32_Bluetooth_Serial?
In both cases, the failures are occurring at the initialization step, where ELM327 is doing the auto search for the correct protocol. The second failure isn't a timeout per se, it's a notice that the ELM327 device simply can't find a compatible ECU/protocol. It's possible the first example would return the same, if it weren't killed by the watchdog first. Are you certain that your ELM device works with the vehicles you're working with? Does it work with other apps or one of the simple sketches like examples/ESP32_Bluetooth_Serial?
So ESP_Bluetooth_multiple_pids connects to both OBDII and SAEj1850 without problems. I will include the serial output from that now with my SAEj1850 since that is what is causing problems for me.
Clearing input serial buffer
Sending the following command/query: AT D
Received char: A
Received char: T
Received char: _
Received char: D
Received char: \r
Received char: \r
Received char: O
Received char: K
Received char: \r
Received char: \r
Received char: >
Delimiter found.
All chars received: ATDOK
Clearing input serial buffer
Sending the following command/query: AT Z
Received char: A
Received char: T
Received char: _
Received char: Z
Received char: \r
Received char: \r
Received char: \r
Received char: E
Received char: L
Received char: M
Received char: 3
Received char: 2
Received char: 7
Received char: _
Received char: v
Received char: 1
Received char: .
Received char: 5
Received char: \r
Received char: \r
Received char: >
Delimiter found.
All chars received: ATZELM327v1.5
Clearing input serial buffer
Sending the following command/query: AT E0
Received char: A
Received char: T
Received char: _
Received char: E
Received char: 0
Received char: \r
Received char: O
Received char: K
Received char: \r
Received char: \r
Received char: >
Delimiter found.
All chars received: ATE0OK
Clearing input serial buffer
Sending the following command/query: AT S0
Received char: O
Received char: K
Received char: \r
Received char: \r
Received char: >
Delimiter found.
All chars received: OK
Clearing input serial buffer
Sending the following command/query: AT AL
Received char: O
Received char: K
Received char: \r
Received char: \r
Received char: >
Delimiter found.
All chars received: OK
Clearing input serial buffer
Sending the following command/query: AT ST 00
Received char: O
Received char: K
Received char: \r
Received char: \r
Received char: >
Delimiter found.
All chars received: OK
Clearing input serial buffer
Sending the following command/query: AT SP A0
Received char: O
Received char: K
Received char: \r
Received char: \r
Received char: >
Delimiter found.
All chars received: OK
Clearing input serial buffer
Sending the following command/query: 0100
Received char: S
Received char: E
Received char: A
Received char: R
Received char: C
Received char: H
Received char: I
Received char: N
Received char: G
Received char: .
Received char: .
Received char: .
Received char: \r
Received char: U
Received char: N
Received char: A
Received char: B
Received char: L
Received char: E
Received char: _
Received char: T
Received char: O
Received char: _
Received char: C
Received char: O
Received char: N
Received char: N
Received char: E
Received char: C
Received char: T
Received char: \r
Received char: \r
Received char: >
Delimiter found.
All chars received: SEARCHING...UNABLETOCONNECT
ELM responded with error "UNABLE TO CONNECT"
Setting protocol via AT TP A%c did not work - trying via AT SP %c
Clearing input serial buffer
Sending the following command/query: AT SP 0
Received char: O
Received char: K
Received char: \r
Received char: \r
Received char: >
Delimiter found.
All chars received: OK
Connected to ELM327
Service: 1
PID: 12
Normal length query detected
Query string: 010C1
Clearing input serial buffer
Connected to ELM327
Service: 1
PID: 12
Normal length query detected
Query string: 010C1
Clearing input serial buffer
Sending the following command/query: 010C1
Received char: S
Received char: E
Received char: A
Received char: R
Received char: C
Received char: H
Received char: I
Received char: N
Received char: G
Received char: .
Received char: .
Received char: .
Received char: \r
Timeout detected with overflow of 0ms
Received: SEARCHING...
ERROR: ELM_TIMEOUT
Service: 1
PID: 13
Normal length query detected
Query string: 010D1
Clearing input serial buffer
Sending the following command/query: 010D1
Received char: S
Received char: T
Received char: O
Received char: P
Received char: P
Received char: E
Received char: D
Received char: \r
Received char: \r
Received char: >
Delimiter found.
All chars received: STOPPED
ELM responded with error "STOPPED"
Received: STOPPED
ERROR: ELM_STOPPED
Service: 1
PID: 12
Normal length query detected
Query string: 010C1
Clearing input serial buffer
Sending the following command/query: 010C1
Received char: S
Received char: E
Received char: A
Received char: R
Received char: C
Received char: H
Received char: I
Received char: N
Received char: G
Received char: .
Received char: .
Received char: .
Received char: \r
Received char: 4
Received char: 1
Received char: 0
Received char: C
Received char: 0
Received char: 0
Received char: 0
Received char: 0
Received char: \r
Received char: \r
Received char: >
Delimiter found.
All chars received: SEARCHING...410C0000
Expected response header: 410C
Single response detected
Processing hex nibble: 0
Processing hex nibble: 0
Processing hex nibble: 0
Processing hex nibble: 0
64-bit response:
responseByte_0: 0
responseByte_1: 0
responseByte_2: 0
responseByte_3: 0
responseByte_4: 0
responseByte_5: 0
responseByte_6: 0
responseByte_7: 0
rpm: 0.00
Service: 1
PID: 13
Normal length query detected
Query string: 010D1
Clearing input serial buffer
Sending the following command/query: 010D1
Received char: 4
Received char: 1
Received char: 0
Received char: D
Received char: 0
Received char: 0
Received char: \r
Received char: \r
Received char: >
Delimiter found.
All chars received: 410D00
Expected response header: 410D
Single response detected
Processing hex nibble: 0
Processing hex nibble: 0
64-bit response:
responseByte_0: 0
responseByte_1: 0
responseByte_2: 0
responseByte_3: 0
responseByte_4: 0
responseByte_5: 0
responseByte_6: 0
responseByte_7: 0
mph: 0.00
So after a couple failed attempts to connect, it does finally sync up and return some results. The rpm and mph values are 0 presumably because the engine is off and vehicle is not moving. The way the protocol search works in an auto search is that after receiving the SP0 command, the ELM327 does not actually initiate the search immediately; instead, it initiates the search on the next query sent. The library tries to manage this for you and even extends the default timeout during this search. In this case, you get an "Unable to connect" message follow by a valid connection a few queries later. I honestly don't know what's happening there. Do you have more than one device you can test with?
So after a couple failed attempts to connect, it does finally sync up and return some results. The rpm and mph values are 0 presumably because the engine is off and vehicle is not moving. The way the protocol search works in an auto search is that after receiving the SP0 command, the ELM327 does not actually initiate the search immediately; instead, it initiates the search on the next query sent. The library tries to manage this for you and even extends the default timeout during this search. In this case, you get an "Unable to connect" message follow by a valid connection a few queries later. I honestly don't know what's happening there. Do you have more than one device you can test with?
The only other ELM device I have is WIFI. Are you able to tell me how to extend the watchdog timer for that function so it has time to fail, then default to the other protocols ? If I am comprehending the CPP in the library correctly it seems that when the connection protocol is not specified it will call an AT Z to reset an AT E0 to disable echo, then a AT SP0, after that it sends 0100 to check for supported PIDS, if that returns a timeout it will move onto the next protocol and then send the 0100 again. That is provided I am comprehending the CPP file and how it operates in a basic sketch without protocol specification.
https://github.com/PowerBroker2/ELMduino/blob/286023d3fd0b0fd525ea7669fa64dc0465645854/src/ELMduino.cpp#L122-L125
You can change the timeout for the protocol search here. I don't think that's the issue with the "unable to connect" issue, but it might help.