Read today a
post on Geektimes , and I want to share the experience. I do not want to discuss the pros and cons of the Arduino, but the conditions of the project in which I applied the following are to be done under it. Essence - you need to provide the user with a terminal to control the device. Appropriately, not a small part of the work is working with strings. To apply or not the proposed solution - let everyone decide for himself.
I decided to refuse the String class: linker
error . It appeared to me only when I tried to use the String class.
What was required? Information output and processing of the lines entered by the user. For example:
Ethernet controller - ok
STATIC mode
> time
2015-11-16 22:35:27
Actually, it is necessary to compare the drains. No, you first need to break the text into fragments with a separator (for example, a space), but then still compare the lines. Since the teams were "one, two - and obchlsya", then the text breakdown into fragments removed. Because of the above error, the String class could not be used, how else could it be? Arduino uses the
AVR-libc library, it is reasonable to refer to it first.
What do we have?
- stdlib.h - functions of mutual conversion of numbers and strings (in both directions).
- string.h - functions for working with strings. Our main interest.
- stdio.h is standard input / output functions.
This is not limited to functional. Mentioned that is associated with the task.
')
So, I recommend number 1 for familiarization - it will suddenly come in handy separately somewhere. By itself, it is used only for the operation of
string.h .
No. 2 - we use the
memset functions to fill or clear the buffer,
memcmp - for comparison.
I do not use
strcmp , since I need to explicitly limit the length of the fragment being compared. №3 - for format reading and output:
sprintf ,
sprint_P ,
sscanf ,
sscanf_P . Functions with the
_P suffix
are different in that the format string is taken from the memory of the PROGMEM programs, also known as the
F () macro in the Arduino libraries.
By the wayBy the way, if you fully implement the I / O functions of a separate character getc and putc , you will get standard input, output, error streams and for working with files, if you have any. You can often get by with overriding putchar () and getchar () macros that work with standard input and output.
My string comparison looks like this:
if ( memcmp(str ,"statlist" ,8)==0 ) {
Perhaps, it is worth making a reservation that the beginnings of lines are compared. To search for fragments, you can use
memmem .
strings for Cthe strings for C are str , they are char * - this is a reference to the beginning of the char sequence, the last of which is 0x00 . So, they need to be placed somewhere. For example, in an array. Or use malloc , calloc , free . That does not allow to make mistakes implies shifting responsibility on the programmer for their placement and control of length .
That is, the search team may look like this:
if ( memcmp(str ,"statclear", 9)==0 ) { memset(journal, 0, sizeof(jrn_rec_t)*JRN_REC_NUM ); Serial.println( F("ok") ); }else if ( memcmp(str ,"statlist" ,8)==0 ) { funcStatlist(); }else if ( memcmp(str ,"cfgshow", 7)==0 ) { funcCfgShow(); }else if ( memcmp(str ,"timeset", 7)==0 ) { funcTimeSet( str);
Unobvious momentCommands, they are the same lines, with a greater length should go first in the given fragment. Think about why?
I “assemble” strings as follows: I read bytes from the port until the allowed length of the string is exceeded or until one of the newline characters \ r or \ n is encountered.
reading lineIt would be better to refine ... As long as it is. Called all the time in the main ring. If there is no work - as fast as possible to exit, return
false . If you typed a new line -
true .
bool readln( HardwareSerial &uart, char *outbuf)
Format I / O is also very useful. For example, parsing a string with a given date and time looks like this:
sscanf_P(str, (const char *)F("%*s %d-%d-%d %d:%d:%d"), &y, &m, &d, &hh, &mm, &ss)
Obtaining a string for IP output:
sprintf_P(buff, (const char *)F("Your IP: %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]);
More information about the format string can be read, for example,
here scanf and
here (printf).
That's all. I hope this material will help someone to get rid of the Arduino, or just better and write their programs in less time. But a more typical situation is to circumvent the limitations of
wiring .
Thanks to the author of the original article, at least for forcing me to collect this material.