6 years, 7 months ago.

Parse time from matrix keypad input and convert to Unix Timestamp

I am currently working on a system that requires the current time to function correctly. The system's only means of input is a 3x4 matrix keypad (0,1,2,3,4,5,6,7,8,9,*,#) and the only means of feedback is a 16x2 LCD. I am using the STM Nucleo F411RE development board.

What I already have: LCD setup and communication and input capture on matrix keypad (1 Char at a time).

What I require: A way to store inputs from the keypad in a buffer that will be parsed from a human readable date (YYYY/MM/DD hh-mm-ss) and then converted to a Unix timestamp that in turn will update the board's current time, if the time conversion was done correctly. (This is my envisioned solution, but other methods may work just as well)

Limitation: I will not be able to use serial COM from a pc to communicate with the board. The keypad is the ONLY input.

This might be trivial but I am not an expert in C++, thus any help will be greatly appreciated!

1 Answer

6 years, 7 months ago.

Obviously a number of ways to do this. First, here are some helpful snippets for different time operations.

    /* Set Time using Unix Timestamp */
    set_time(1387188323);

    /* Make required Variables */
    time_t seconds = time(NULL);
    struct tm *mygmtime = gmtime(&seconds);
    struct tm *datetime = gmtime(&seconds);
    char buffer[32];

    /* Set Time using Date Time tm Structure */
    datetime->tm_sec = 0;
    datetime->tm_min = 20;
    datetime->tm_hour = 21;
    datetime->tm_mday = 22;
    datetime->tm_mon = 2;
    datetime->tm_year = 116;
    datetime->tm_wday = 2;
    datetime->tm_yday = 81;
    datetime->tm_isdst = 0;

    set_time(mktime(datetime));

    /* Get Time Struct from RTC and Pretty Print */
    mygmtime = gmtime(&seconds);
    strftime(buffer,32,"%Y-%m-%d %H:%M:%S",mygmtime);
    printf("UTC: %s\n\r",buffer);

Now, if you truly wanted a user to enter a data as YYYY/MM/DD hh-mm-ss, you could use the strtok function to parse this into individual tokens. Then you can just deal with year, month, day, etc individually. The strtok function uses the original string buffer as storage and it replaces all delimiter characters it finds with end of string character. Then it returns pointers to the start of each token.

/** Parse buffer into Tokens  via strtok using delimitors
    Strtok replaces the delimitor in buffer string with \0 to end the string
    All these pointers still point to the same buffer memory but with diff start addresses
    @param  buffer  Array containing string to Parse.  Function updates values.
    @param  tokens  Array of type char pointer. Function updates values.
 */
static void parseTokens(char buffer[], char *tokens[]) {
    char *tok;       // temporary token pointer
    int   index = 0; // index to tokens

    // Any of these chars are treated as delimitors
    tok = strtok(buffer, " /-\n");

    while (tok != NULL) {
        // Store Pointers
        tokens[index++] = tok;
        tok = strtok(NULL, " /-\n");
    }
}

That being said, I would probably not implement it this way, as it would require the user to perfectly enter the whole data string and understand they have to use correct delimiters. It would probably be better to first prompt them with 4 digit year (they type in 4 digits and hit enter), then with 2 digit month, 2 digit day, etc, etc. Or display everything on one line but the user can only interact with the number fields, the delimiters are automatically skipped over. Could make the number they are currently on blink.

Accepted Answer

Excellent answer! Your answer cleared a few things up for me and I agree with your idea of only letting the user interact with the digits. Thank you for the detailed answer, I found it extremely helpful.

posted by Jeandré Mostert 12 Sep 2017