Jump to content
yyrkoon

More C versus C++

Recommended Posts

BTW: sleep .2 is 200 ms sleep

 

I know . . . or two tenths of a second ;)

william@beaglebone:~/dev$ time ./read-temp

Device: 28-00000647ddf6
18.00C
18.06C
18.06C
18.06C
18.06C^C

real    0m5.394s
user    0m0.000s
sys     0m0.072s

So how does .000 usertime compare to .008 ? ;)

 

@@Rickta59

 

Come back lol . . .I spent nearly as much time in kernel that you spent in user space. Not exactly sure if that's a bad thing or not.

 

[EDIT] actually nearly 10 times as much. But, and I'm assuming this has to do with my program runs a looser loop, thus ran longer, and time() + opendir() etc are sys calls which do land in kernel mode.

 

Most of that is initial application setup that runs once, but I'm also opening and closing the file descriptor once every second. Which I'm not sure what you're doing there with echo . . . either way, it doesn't work on the beaglebone( Debian Jessie 8.6 ), and cat in place of echo doesn't work either. The script runs too fast to read from the sensor properly. So one thing to know about the DS18B20 is that it's data refresh rate can be anywhere between 100, and 750 milliseconds. Depending on how it's configured. I have not got aroudn ot figurering out how to configure the sensor through Linux, but I'm not sure I will either. Chances are pretty good ill only be reading the the sensor once every minute, maybe even more.

 

So here is part of what strace has to say about your script:

read(3, "20 01 4b 46 7f ff 10 10 fc : crc"..., 128) = 73
read(3, "", 128)                        = 0
close(3)  

What this tells me is that you probably need to use read_line() as it looks like it's only catching the first half of the output from the sensor. By the way, it also almost looks as the crc value is not correct either. But who knows what strace is doing there . . .

Share this post


Link to post
Share on other sites

I'm a little embarrassed to admit, but, I had no idea the Linux 'sleep' command could take a decimal point..... always thought it had to use integers.

 

Turns out it takes suffixes for 's' (seconds, the default), 'm' (minutes), 'h' for hours and 'd' for days too!

DESCRIPTION
       Pause  for  NUMBER  seconds.  SUFFIX may be 's' for seconds (the default), 'm' for minutes, 'h' for hours or 'd' for days.  Unlike most implementa?
       tions that require NUMBER be an integer, here NUMBER may be an arbitrary floating point number.  Given two or more arguments, pause for the  amount
       of time specified by the sum of their values.

Share this post


Link to post
Share on other sites

Ok so when I wrote the first script I didn't really know what the w1_slave returned, it was more an example of what you might do. I went and dug up what I think the w1_slave returns.  Here is the format I think it returns, but I really don't know you will have to adjust for it

 

Assumming it returns something like this:

$ cat /tmp/bus/w1/devices/28-100000001/w1_slave
4b 01 4b 46 7f ff 05 10 e1 : crc=e1 YES
4b 01 4b 46 7f ff 05 10 e1 t=19065
You could use this script:

#!/bin/bash

# read the w1-temp values
# put each line1 and 2 into variables
# parse and see if it is ready
# if so read the raw value and round it to 2 decimals
read_sensor()
{
    SENSOR_FILE=$1
    local __celsius_raw=$2
    local __celsius_dec=$3
    local __rc=$4

    local indx=0;
    while IFS='' read -r temp; do
        case $indx in
        0) line1=$temp;;
        1) line2=$temp;;
        esac
        indx=$((indx+1))
    done < $SENSOR_FILE

    ready=${line1/YES/,ready}

    if [ "${ready#*,}" == "ready" ] 
    then
        local celsius_raw=${line2#*t=}
        local celsius_dec=$(echo "scale=2; ((${celsius_raw}+5)/1000.0)" | bc)
        eval $__rc="1"
        eval $__celsius_raw="'$celsius_raw'"
        eval $__celsius_dec="'$celsius_dec'"
    else
        eval $__rc="0"
    fi
}

# loop through all the sensors
SENSOR_FILES=$(echo /sys/bus/w1/devices/28-*/w1_slave)

while true; do
    for sensor_file in ${SENSOR_FILES}; do
    read_sensor $sensor_file c d rc
    if [ "$rc" == "1" ]; then
        echo "Raw=${c}"
        echo "Celsius=${d}"
    else
        >&2 echo -n "."
    fi
    done
  sleep 0.2
done;
This one uses only one external command "bc" to convert the raw value to a rounded one

 

$ time ./w1_poll.sh

real 0m5.560s

user 0m0.012s

sys 0m0.008s

 

 

-rick

 

Also here: https://gist.github.com/RickKimball/926a6e638d6fea994384af4d8487078f

Share this post


Link to post
Share on other sites

 

I'm a little embarrassed to admit, but, I had no idea the Linux 'sleep' command could take a decimal point..... always thought it had to use integers.

 

Turns out it takes suffixes for 's' (seconds, the default), 'm' (minutes), 'h' for hours and 'd' for days too!

DESCRIPTION
       Pause  for  NUMBER  seconds.  SUFFIX may be 's' for seconds (the default), 'm' for minutes, 'h' for hours or 'd' for days.  Unlike most implementa?
       tions that require NUMBER be an integer, here NUMBER may be an arbitrary floating point number.  Given two or more arguments, pause for the  amount
       of time specified by the sum of their values.

 

Yeah, been that way for a while now, with .1 being the lowest possible value. I still use usleep though for some reason I do not even know why. Familiarity I guess.

Share this post


Link to post
Share on other sites

Ok so when I wrote the first script I didn't really know what the w1_slave returned, it was more an example of what you might do. I went and dug up what I think the w1_slave returns.  Here is the format I think it returns, but I really don't know you will have to adjust for it

 

Assumming it returns something like this:

$ cat /tmp/bus/w1/devices/28-100000001/w1_slave
4b 01 4b 46 7f ff 05 10 e1 : crc=e1 YES
4b 01 4b 46 7f ff 05 10 e1 t=19065
You could use this script:

#!/bin/bash

# read the w1-temp values
# put each line1 and 2 into variables
# parse and see if it is ready
# if so read the raw value and round it to 2 decimals
read_sensor()
{
    SENSOR_FILE=$1
    local __celsius_raw=$2
    local __celsius_dec=$3
    local __rc=$4

    local indx=0;
    while IFS='' read -r temp; do
        case $indx in
        0) line1=$temp;;
        1) line2=$temp;;
        esac
        indx=$((indx+1))
    done < $SENSOR_FILE

    ready=${line1/YES/,ready}

    if [ "${ready#*,}" == "ready" ] 
    then
        local celsius_raw=${line2#*t=}
        local celsius_dec=$(echo "scale=2; ((${celsius_raw}+5)/1000.0)" | bc)
        eval $__rc="1"
        eval $__celsius_raw="'$celsius_raw'"
        eval $__celsius_dec="'$celsius_dec'"
    else
        eval $__rc="0"
    fi
}

# loop through all the sensors
SENSOR_FILES=$(echo /sys/bus/w1/devices/28-*/w1_slave)

while true; do
    for sensor_file in ${SENSOR_FILES}; do
    read_sensor $sensor_file c d rc
    if [ "$rc" == "1" ]; then
        echo "Raw=${c}"
        echo "Celsius=${d}"
    else
        >&2 echo -n "."
    fi
    done
  sleep 0.2
done;
This one uses only one external command "bc" to convert the raw value to a rounded one

 

$ time ./w1_poll.sh

real 0m5.560s

user 0m0.012s

sys 0m0.008s

 

 

-rick

 

Also here: https://gist.github.com/RickKimball/926a6e638d6fea994384af4d8487078f

 

Thanks Rick I appreciate the effort. You realize there are about 5million bash scripts for 1-wire and the rPI ? Some really nice ones too.

Share this post


Link to post
Share on other sites

Thanks Rick I appreciate the effort. You realize there are about 5million bash scripts for 1-wire and the rPI ? Some really nice ones too.

 

 I didn't actually look no. If there are, why are you writing another solution?

Share this post


Link to post
Share on other sites

I

 

 I didn't actually look no. If there are, why are you writing another solution?

 I already told you why last night. That, and what you've seen is not all I'll be doing.

Share this post


Link to post
Share on other sites

# best solution

$ while true; do for sensor_file in /tmp/bus/w1/devices/28-*/w1_slave; do echo "scale=2; $(cat ${sensor_file} | grep  -E -o ".{0,0}t=.{0,5}" | cut -c 3- )/1000.0" | bc; done; sleep .5; done

Yeah there are a bunch of one liners out there.

 

But as I'm not only going to be reading the file, and displaying the temp to screen. That was just me experimenting, and then "obsessing" to convert a C program to C++.

 

So first off the final application I'll be writing will be for a client, billing them 3-4 hours for the software. Then probably an additional 1-2 hours for a setup script to make sure everything needed is in place. Then if not, install all the needed goodies. While I'm not quite sure what the client wants *YET* my idea is to log the data out via MQTT. Then it becomes a question of how often do we log. Here, I'm thinking we probably want a command line option variable between say 1-60 seconds. 1 second to create a temperature profile of the board, if needed. Then 60 seconds normal checking / logging. Maybe even an additional parameter to only log when the temperature is within a certain range. e.g. board is close to or is overheating, so start logging. With perhaps yet another parameter to tell the board to shutdown when overheating. There is even a web front end, as well as an iPhone/Android app in the works.

 

At this point, writing a shell script probably is not ideal. Not to mention it'll get very messy quickly. Perhaps even slow.

 

So for a one off board type project, DiY style. *MAYBE* a shell script. But there are multiple boards, nation wide, logging data out to a server <somewhere else> in the US. Think 10's of boards at this point (30-40) deployed, with around 50-60 total made so far. Just for one type of board, there are actually 3-4 variations for different situations, with only the first variation being deployed in the wild _right_now_. The original idea though( not mine, the clients ) is actually really cool, and innovative.

Share this post


Link to post
Share on other sites

So coming back to this problem again, just now. I decided for my current purpose to use a shell script. Mostly because a shell script should be readable by most, that are familiar with UNIX like systems, and I'm not the only one maintaining this system.

 

@@Rickta59

bc is a problem, because it does not come default with the current debian image we're working with. Sure I could install bc using APT, but why waste the effort and space ? I did create a simple solution though based off a couple of stackoverflow posts I searched for . . .

root@beaglebone:~# temp=$(cat /sys/bus/w1/devices/28-*/w1_slave |awk ' /t=/ {print $10}')
root@beaglebone:~# echo ${temp:2}
16812

This is of course fixed type, but I do not necessarily need a floating point type do I ? I don't think so . . . But going back to our discussion from before. Running cat on a 1-wire device, there is a very noticeable 2-3 second pause at the beginning. This pause, as I recall does not happen when I ran the C++ code mentioned previously. With that said, for the purpose I'm using this for. It doesn't matter.

 

EDIT:

 

If floating point did matter though . . .

root@beaglebone:~# temp=$(cat /sys/bus/w1/devices/28-*/w1_slave |awk ' /t=/ {print $10}')
root@beaglebone:~# awk "BEGIN {print ${temp:2}/1000}"
16.937

Share this post


Link to post
Share on other sites

Here's some more C++ magic which seems applicable to embedded programming.

I think he optimized for speed instead of space (using tons of mov instead of a loop to initialize sprite bitmaps). But a lot of impressive optimization by the compiler.

On the downside, I didn't understand half the constructs he was using. I guess I need to relearn C++ :huh:

via embedded.fm podcast

Share this post


Link to post
Share on other sites
On 3/12/2017 at 3:23 PM, chicken said:

Here's some more C++ magic which seems applicable to embedded programming.

I think he optimized for speed instead of space (using tons of mov instead of a loop to initialize sprite bitmaps). But a lot of impressive optimization by the compiler.

On the downside, I didn't understand half the constructs he was using. I guess I need to relearn C++ :huh:

via embedded.fm podcast

Didn't know you posted, heh been super busy with the day job building a monitoring system for the company, in addition to building an update system( for our own software )from scratch . . . pretty interesting stuff, and I learned A  LOT about systemd services + timers, but without actually getting into the architecture of it all. It's a nightmare trying to visualize all this in your head.

Chicken, I've come to realize that that for myself, C is the only real way to go with embedded design. I personally find C++ good for when you need to use a lot of strings, and perhaps other various constructs, it can be ok to work with. But when you need all out performance, C will usually be the best option. Unless you're super proficient with C++, and you write all of, or at least all of the important code from scratch. Same goes for C though really. An example would be my two process application where I needed to share a file between the two halves, and I wrote my own binary file lock. Because the C std API calls were all way too slow.

 

EDIT:

Oh, and you can bet I will eventually get around to watching the video.

Share this post


Link to post
Share on other sites
15 minutes ago, chicken said:

I don't try to convince anybody. I'm way too busy myself to unlearn bare metal C.

But I thought the video will be relevant for people that venture down the rabbit hole.

Sure, I get it. Like you, I guess I am just more used to using C most of the time, but I still like many aspects of C++, as well as other languages.

It's kind of funny, I was watching a youtube video the other day before bed, and I forget the speakers name( He's pretty well known, I should remember his name, but I dont - I'm not a "fanboy" that way ), where he was explaining why C++ was what he considered the better choice for embedded software development. Then he showed a chart from the last 10-15 years. Which showed C graphing upwards, while C++ was trending downwards . . . Ah right, Dan Saks, but his contention is that C++ is better than C, and I completely disagree with that. I think every language has it's place, and for different people, that will skew one direction or another.

But there is a reason why you will never, at least within the near future, see any C++ code in the Linux kernel.

 

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×