Scanf in serial monitor (ESP-IDF)

Hello,

I'm aware that my problem is not arduino-esp related but i wanted to give it a go anyway to see if this place is a viable option for my esp-idf related problems as the espressif forum rarely gets any views.

tested with the esp32 c6 devkit, with watchdog disabled.
A simplistic routine where i read from the terminal for keyboard input using scanf in a while loop, sometimes when log messages are printed to the terminal while inside the loop waiting for user input, the esp simply stops responding without any error or warning.

I was wondering why this is, i suspect my approach is actually very bad or missing some key elements, either that or the serial terminal in the esp-ide is to blame.
I have not yet tested this with a program such as PuTTY.

Another thing to note is that there is another function in this program that is being called that is also using user input over serial terminal in the same manner as described in scan_usercmd().
Normally these should not be able to conflict with each other as they are both being processed independently in a while loop without using freertos.

I suspect that when the program prints to the monitor while waiting for user input, the system used the printed char or string and there freezes somehow.

#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <unistd.h>
#include <inttypes.h>
#include "esp_err.h"
#include "wifi_app.h"
#include "sntptime.h"
#include "nvs_flash.h"
#include "esp_log.h"
#include "esp_timer.h"

bool started = false;
static const char tag[] = "-[MAIN.c]-";

void scan_usercmd(void)
{
	int cmd = 0;
	esp_err_t err;
	printf(" Options: \n1: start wifi connection\n2: manually start sntp sync \n3: Stop sntp service\n4: Get system time\n5: Scan en list all available AP\nEnter command: ");
	
	while( cmd == 0 || cmd > 5)	scanf("%i", &cmd); // Wait for valid input
		
	printf("%i\n",cmd);
	switch(cmd)
	{
		case 1: {
			err = InitWifi();
			if( err == ESP_OK)	{
				ESP_LOGI(tag, "Succesfully started the wifi connection.");
			} else ESP_LOGE(tag, "Failed to start the wifi connection (%i)", err);
				break;
		}
		/*case 10: {
			DeinitWifi();
			break;
		}*/
		case 2: {
			err = timeSyncStart();
			if( err == ESP_OK) {
				ESP_LOGI(tag, "Succesfully started sntp.");
			} else ESP_LOGE(tag, "Failed to start sntp (%i)", err);
				break;
		}
		case 3: {
			timeSyncStop();
			break;
		}
		case 4: {
			struct tm timeinfo;
    		        time_t now;
    		        char Strtime[100];
			printf("\nGetting system time..");
			time(&now);
			localtime_r(&now, &timeinfo);
			strftime(Strtime, sizeof(Strtime), "%c", &timeinfo);
			printf("System time: '%s'\n", Strtime);
			break;
		}
		case 5: {
			ScanPrintWifiStations();
			break;
		}
	}
	
}

void app_main(void)
{
	esp_err_t err = nvs_flash_init();
	if(err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
	{
		ESP_ERROR_CHECK(nvs_flash_erase());
		err = nvs_flash_init();
	}
	if(err != ESP_OK)
	{
		ESP_LOGD(tag, "Error (%s) while initializing memory, can not proceed", esp_err_to_name(err));
	}
	err = esp_timer_early_init();
	if(err != ESP_OK) ESP_LOGE(tag, "Could not early initiate timer.h library (%i).", err);
	
	while(1) {
		scan_usercmd();
		/*if(!started) {
			if( InitWifiConnection() == ESP_OK)	started = true;
		}*/
		
	}
	ESP_LOGE(tag,"app_main escaped infinite loop..");
}

not sure if you're trying to use scanf() to read input to the Arduino thru some external keyboard or just the serial monitor.

i've found that it's typically best to read a complete line of input and then process it although i can see how using scanf() to read from a consitently formatted file might work

look this over
bear in mind that input from the IDEs serial monitor is not sent until the enter key is pressed, so Serial.available() typically means a complete line will be available.

this is likely not to be true with some other serial emulator such as putty, in which case waiting for a complete line might be blocking


char s [90];

void
loop (void)
{
    if (Serial.available ()) {
        char buf [90];
        int  n = Serial.readBytesUntil ('\n', buf, sizeof(buf)-1);
        buf [n] = '\0';         // add terminating nul

        char cmd [20];
        int  val;
        sscanf (buf, "%s %d", cmd, &val);

        sprintf (s, " %6d %s\n", val, cmd);
        Serial.println (s);
    }
}

void
setup (void)
{
    Serial.begin (9600);
}

I'm trying to use scanf() to read keyboard input from the serial monitor of the espressif IDE.
The problem here is that i can't use the arduino esp framework so i can't use the serial commands from arduino so I did a quick scoop through the serial library from arduino but that is practicly impossible (for me) to decode to see how they did it there.

The serial monitor in esp-IDE allows to type directly into the monitor, i have found that is not very practical, but they also have a command prompt availlable that allows you to input entire strings at once.

The way i have implemented this is by blocking, this is soley for testing and simulation purposes, i had to disable watchdog timer as it was inflicting with this functionality.

I'm using while loop to check for input and "should" normally stay in that blocking loop untill the user has entered one of the recognized number (/letter/sentence).
But the system seems to freeze unable to check for input, i'm fairly sure its due to the program printing to the serial monitor while checking for user input, but can't figure out how to get around that.

here's another approach that i use which is non-blocking, processing one char at a time, capturing multi-digit values, processing single char commands

// pcRead - debugging using serial monitor

const char version [] = "PcRead 240209a";

int debug = 0;

// -----------------------------------------------------------------------------
// process single character commands from the PC
#define MAX_CHAR  10
char s [MAX_CHAR] = {};

int  analogPin = 0;

void
pcRead (void)
{

    static int  val = 0;

    if (Serial.available()) {
        int c = Serial.read ();

        switch (c)  {
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            val = c - '0' + (10 * val);
            break;

        case 'A':
            analogPin = val;
            Serial.print   ("analogPin = ");
            Serial.println (val);
            val = 0;
            break;

        case 'D':
            debug ^= 1;
            break;

        case 'I':
            pinMode (val, INPUT);
            Serial.print   ("pinMode ");
            Serial.print   (val);
            Serial.println (" INPUT");
            val = 0;
            break;

        case 'O':
            pinMode (val, OUTPUT);
            Serial.print   ("pinMode ");
            Serial.print   (val);
            Serial.println (" OUTPUT");
            val = 0;
            break;

        case 'P':
            pinMode (val, INPUT_PULLUP);
            Serial.print   ("pinMode ");
            Serial.print   (val);
            Serial.println (" INPUT_PULLUP");
            val = 0;
            break;


        case 'a':
            Serial.print   ("analogRead: ");
            Serial.println (analogRead (val));
            val = 0;
            break;

        case 'c':
            digitalWrite (val, LOW);
            Serial.print   ("digitalWrite: LOW  ");
            Serial.println (val);
            val = 0;
            break;

        case 'p':
#if !defined(ARDUINO_ARCH_ESP32)
            analogWrite (analogPin, val);
            Serial.print   ("analogWrite: pin ");
            Serial.print   (analogPin);
            Serial.print   (", ");
            Serial.println (val);
            val = 0;
#endif
            break;

        case 'r':
            Serial.print   ("digitalRead: pin ");
            Serial.print   (val);
            Serial.print   (", ");
            Serial.println (digitalRead (val));
            val = 0;
            break;

        case 's':
            digitalWrite (val, HIGH);
            Serial.print   ("digitalWrite: HIGH ");
            Serial.println (val);
            val = 0;
            break;

        case 't':
            Serial.print   ("pinToggle ");
            Serial.println (val);
            digitalWrite (val, ! digitalRead (val));
            val = 0;
            break;

        case 'v':
            Serial.print ("\nversion: ");
            Serial.println (version);
            break;

        case '\n':          // ignore
            break;

        case '?':
            Serial.println ("\npcRead:\n");
            Serial.println ("    [0-9] append to #");
            Serial.println ("  # A - set analog pin #");
            Serial.println ("  # D - set debug to #");
            Serial.println ("  # I - set pin # to INPUT");
            Serial.println ("  # O - set pin # to OUTPUT");
            Serial.println ("  # P - set pin # to INPUT_PULLUP");
            Serial.println ("  # a - analogRead (pin #)");
            Serial.println ("  # c - digitalWrite (pin #, LOW)");
            Serial.println ("  # p - analogWrite (analogPin, #)");
            Serial.println ("  # r - digitalRead (pin #)");
            Serial.println ("  # s  - digitalWrite (pin #, HIGH)");
            Serial.println ("    t  - toggle pin output");
            Serial.println ("    v  - print version");
            Serial.println ("    ?  - list of commands");
            break;

        default:
            Serial.print ("unknown char ");
            Serial.println (c,HEX);
            break;
        }
    }
}

// -----------------------------------------------------------------------------
void
loop (void)
{
    pcRead ();
}

// -----------------------------------------------------------------------------
void
setup (void)
{
    Serial.begin(9600);

    Serial.println (version);
#if defined(ARDUINO_ARCH_ESP32)
    Serial.println ("esp32");
#endif
}

Could you provide some clarity on how I can include the serial library from arduino-esp framework into ESP-IDE (esp IDF).

Can I even use arduino libraries inside esp-ide (esp-IDF) , and if that is possible can i choose wich ones to include.
Because i can image with both esp idf and complete arduino-esp IDF the final program size would be about twice as big/resourcefull.

been looking into adding arduino-esp as a component inside esp-ide, a total nightmare if git is unable to be used..
But it appears that i need to change my c files to cpp, is there a workaround for this so i can still use arduino serial library in esp-idf in esp-ide?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.