Efficient text scanning on STM32

Hey guys,

i want to implement a firmware on a STM32L432KC for interfacing a NB-IoT chip by Quectel. The interface is text-based, e.g. send a query command like "AT+QISTATE?" and getting a respon like "0,TCPIP,"127.0.0.1","8001","1",1,0,"quectel.com",DIRECT,0".
With an eval board connected to PC i solved this interactions using regular expressions, but i think this is a little bit overdone on this µC...
I was thinking about importing the sscanf() method from C via FFI... What do you think? Is there are a more efficient way to inpterpret this kind of responses?

Thank you for you advises and kind regards,
Michael

If space is a concern, You could probably implement a simple parser for this without using any external crates. The grammar looks pretty simple, if you treat everything as a string: Every string is either quoted or unquoted. You can parse just by iterating over the characters with .chars(). (Or treat it as a Vec<u8>, and just handle one byte at a time). Once you've turned a line into a Vec<&str>, (or an appropriately sized tuple), create a well-typed Response struct, and just implement FromStr for each field and .parse() your fields into struct, and you end up with something like:

impl Response {
    fn from_line(line: &[&str]) -> Result<Response, _> {
        Ok(Response {
            seq_id: line[0].parse()?,
            protocol: line[1].parse()?,
            addr: line[2].parse()?,
            port: line[3].parse()?,
            version_str: line[4].parse()?,
            major_version: line[5].parse()?,
            minor_version: line[6].parse()?,
            source: line[7].parse()?,
            extra: line[8].parse()?,
            extra2: line[9].parse()?,
        }
    }
}

I'm, of course, making up names for the fields. I don't actually have any idea what the fields of the CSV mean.

If you're worried about keeping things small, you're probably best off handrolling just what you need for this particular format.

2 Likes

I would advise against using sscanf() even if space wasn't a concern – it's incredibly hard to use correctly.

1 Like

I don't think sscanf() can parse CSV with maybe-quoted values... except if the quotes are always there. Also, do you even have a C stdlib to import from? In any case, @H2CO3 is right: stay away from basically untyped C APIs.

I would look at one of the parsing crates that supports no-std. I think nom does? If it proves to be too heavy code-size wise you can still hand roll some logic.

1 Like

Ok, basically i got the idea building little parser methods. But then i need some kind of pattern to describe the bride variety of possible responses. This one above is only one of many... Here are more example responses:

+QIOPEN: 0,150

OK

+QIURC: "incoming",11,1,"172.31.242.222",54091

This is the reason why i remembered to sscanf() with its simple pattern "%s,%d..."-style in my old C/C++-times... and this is the reason why i found to regular expressions when i started using Rust and were confronted to this problem.

If space is a concern

Would it be possible to implement regex with no_std on a µC like the STM32L432KC? I thought regular expressions would be a little overkill for a µC...

I don't know about no_std regexp libraries. However you could build a scanner+parser using nom in no_std mode. See for example this esp8266at response parser which parses a similar syntax. It's efficient, but probably overkill for this case.

I'd too stay away from sscanf. FFI complicates the code, throws away rust's safety guarantees, and it doesn't add that much above implementing the scanning yourself with a loop.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.