F() messes with program I'm working on command-handler library and I have a big problem with F() function.
Example sketch for library uses quite a lot of RAM, because it has to print a lot of text over UART. As before, I've used F() to lower RAM usage. It worked on first!

Lib works with help of strtok function. Command fomar is:


  cmd1,..,paramN;..;cmdN,..,paramN


Commands are separated with ; while command parameters(params) are separated with ,
Library works without any problems, it returns memory address(char*) of any command and every param.

When I try to compare parameter/command with strcmp it works only if all commands are in uppercase.
Let's take LED command for example:
It works only with Led, LED or any case where is letter d in uppercase. led won't work, and it will say that command le doesn't exist. Yes, le, it won't print led. But, after DURATION command, it somehow start working.

Memory for serial buffer is dynamicly allocaed in object constructor, in global scope.
Why? All those problems are because F(). Can someone explain why? Here's the code and screenshot of serial monitor.

void execCmd(const char *set)
{
char *cmdParam = CMDHandler.find(set, CMD_PARAM);

if (!strcmp(cmdParam, "LED"))
{
    // ONE WAY TO CHECK IF COMMAND HAS PARAM(S) - BEFORE GETTING PARAM(S) == BETTER WAY
    if (!CMDHandler.count(CMDHandler.getNext(CMD_PARAM), CMD_PARAM))
    {       
        Serial.print(F("-&gt;&gt; Command LED: Current LED status is "));
        Serial.println(digitalRead(LED_PIN));
        return;     
    }

    cmdParam = CMDHandler.find(nullptr, CMD_PARAM);
    LEDStatus = 0;
    uint8_t status = atoi(cmdParam);

    digitalWrite(LED_PIN, status);
    Serial.print(F("-&gt;&gt; Command led: LED Status is "));
    Serial.println(status, DEC);
}
else if (!strcmp(cmdParam, "LOOP"))
{
    cmdParam = CMDHandler.find(nullptr, CMD_PARAM);

    // SECOND WAY TO CHECK IF COMMAND HAS PARAM(S) - AFTER GETTING EVERY PARAM
    if (cmdParam == nullptr)
    {
        Serial.println(F("-&gt;&gt; Command LOOP: Expected one parameter!"));
        return;
    }   

    uint8_t status = atoi(cmdParam);
    if (status)
    {
        LEDStatus = 2;
        digitalWrite(LED_PIN, HIGH);
        Serial.println(F("-&gt;&gt; Command LOOP: LED Blink Loop is on!"));
        delay(blinkDuration);
    }
    else
    {
        LEDStatus = 0;
        digitalWrite(LED_PIN, LOW);
        Serial.println(F("-&gt;&gt; Command LOOP: LED Blink Loop is off!"));          
    }   
}
else if (!strcmp(cmdParam, "DURATION"))
{
    if (!CMDHandler.count(CMDHandler.getNext(CMD_PARAM), CMD_PARAM))
    {
        Serial.print(F("-&gt;&gt; Command DURATION: Current blink duration is "));
        Serial.print(blinkDuration, DEC);
        Serial.println("ms");
        return;     
    }

    cmdParam = CMDHandler.find(nullptr, CMD_PARAM);
    blinkDuration = atoi(cmdParam);

    Serial.print(F("-&gt;&gt; Command DURATION: New blink duration is "));    
    Serial.print(blinkDuration, DEC);
    Serial.println("ms!");  
}
else if (!strcmp(cmdParam, "HELP"))
{
    Serial.println(F("------ HELP ------\n-&gt; LED [0/1] - Turns off/on LED on pin 13\n-&gt; LOOP [0/1] - Stops/starts blink loop with LED on pin 13\n-&gt; DURATION [X] - Changes duration of LED loop blink. Recommended values is 50-500ms\n"));
}
else
{
    Serial.print(F("-&gt;&gt; Command "));
    Serial.print(cmdParam);
    Serial.println(F(" does not exist!"));
}


}

char *CMDHand::find(const char *input, uint8_t const type)
{
    char *found = nullptr;
    char separator = delimiter[type];

    if (input != nullptr) // FIRST CALL
    {
        constrain[type] = input + strlen(input) - 1;
        next[type] = input;
    }
    else if (next[type] &gt; constrain[type]) return (nullptr);

    found = strtok(next[type], &amp;separator); // FOR SOME REASON IT DOES NOT WORK IF I PUT &amp;delimiter[type] INSTEAD OF &amp;separator
    last[type] = next[type];
    next[type] += strlen(found) + 1;

    return (found);
}
To compare with F() macro encased strings you have to use special forms of the string functions that are suffixed with _P.  You also need to cast the string literals to the right type (PGM_P).

To do a case-insensitive comparison you should use strcasecmp instead of strcmp.

To put those together you end up with:

if (strcasecmp_P(cmdParam, (PGM_P)F("help")) == 0) {
    ...
}




There is a problem here:

found = strtok(next[type], &amp;separator)


strtok takes a C string as a list of separators (must be NULL terminated). You're passing it the address of a single character. There may or may not (probably not) be a NULL in the next byte in memory, but everything else up to the first NULL found in memory will be taken as delimiter characters.