c++ objects for people with no time
I write a lot of firmware for the detectors I make. And I have to say,
c++
has some of the most convoluted classes imaginable. So,
everytime I have to use one of the complex c++
objects, or - even
worse - use the old non-semantic c
APIs for things, I try to write
it into a little bit more pythonic object. If you really want the full
power of these objects, don’t use this library. But if you want the
object to be exactly what it says it is, and no more, this library may
be one of the faster ways.
Installation is easy. Just clone, copy into /usr/inclue/c++
, and go.
If you’re on Windows, good luck. Maybe someone can tell me where Windows
developers might keep their header files.
Step-By-Step
git clone https://github.com/alexhagen/cppm
cp cppm/*.h /usr/includes/
There’s a bunch of different interfaces defined here, categorized roughly as memory objects, tcp objects, udp objects, and signals and timing. Specific documentation on all of those interfaces are included in the readmes folder.
I created this shared memory interface to pass variables amongst processes in linux for a detector firmware I was writing. It uses the shmget
and shmat
C interface under the hood, but that's all so non-semantic when you code it that you shouldn't have to worry about it.
My fiance is watching the tv show Sherlock Holmes behind me, so this example is themed on that show.
First, we have to create some server for the shared memory. This server has to be open for the client process to read it, so we'll just keep it open indefinitely. We also have to define a unique identifier for the shared memory server.
from cppm import cppmagic
%%runcppnb shm_server
#include "../ah_shm.h"
#include "../ah_signal.h"
#include <string>
int run = 1;
void cleanup(int signum){
run = 0;
}
int main(void){
// create the shm server
shm_server<std::string> *sherlock = new shm_server<std::string>(5678);
// latch a cleanup function onto the SIGTERM signal
ah_signal(SIGTERM, &cleanup);
while (run){
sherlock->set("is a good guy!");
sleep(1);
sherlock->set("is a bad guy!");
sleep(1);
sherlock->set("is dead!");
sleep(1);
sherlock->set("is now alive again!");
sleep(1);
}
delete sherlock;
return 0;
}
Now, to connect to the memory. We have to attach using the same key, which is a little bit of a paint, but if you use macros effectively, it'll just be like pointing at a file. This client will be way faster than using files though, for time intensive processes, use these shm
s.
%%runcpp shm_client
#include "../ah_shm.h"
#include <string>
int main(void){
shm_client<std::string> *holmes = new shm_client<std::string>(5678);
for(int i=1; i<5; i++){
const char* desc = holmes->get().c_str();
printf("Episode %d in which Sherlock %s\n", i, desc);
sleep(1);
}
delete holmes;
return 0;
}
Now, we just have to stop the server to make sure we're not leaving too many things open.
%killall
Just a note: I'm still working on the cleanup of this. To check that I've removed all of the attached shared memory, you can use the bash line
!ipcs
and to remove it, find the KEY
corresponding to it and use ipcrm
. Note that the KEY is usually the hexadecimal representation of the key
you used in c++
, so you can just use that:
!ipcrm -M 5678
The ah_value
class is a simple, encapsulated c++ class to help track values. It is written with the signal-slot paradigm so that events can be triggered as the values change. This is a way to decrease the overhead that must happen to trace some values (such as checking if something is over a certain value every loop).
Lets say we want to create a program that indicates whether a motor is up to speed, and thereafter, how much it has varied from that speed. First, we need some sort of notifier class. This class holds the value object, and also the notifier (duh) method, that will ring back and tell us when the alarm goes off.
from cppm import cppmagic
%%include notifier
#include "../common/sigslot.h"
#include "../ah_value.h"
#include <stdio.h>
class notifier : public sigslot::has_slots<>{
// we have to make this a sigslot so that it can accept slots
public:
// a value object for our notifier class
value<int> *vl;
// a constructor to pass in an external notifier class
notifier(value<int>*);
// we need a slot that will tell when it's up to speed
void up_to_speed(void);
};
notifier::notifier(value<int> *_vl){
vl = _vl;
}
void notifier::up_to_speed(void){
// let us know that we're up to speed
printf("Motor is up to speed\n");
// now reset the max min so we only get the maximum and minimum when up to
// speed
vl->resetmaxmin();
}
This is a great example for using a custom compiler with the cppmagics
class. Below we'll add the -Wall
option. I don't think this is necessary, but it'll work and it's informative.
%set_compiler g++ --std=c++11 -Wall
Finally, we need to write the main. We create our value and instantiate our notifier. We'll use the wonderful sigslot.h
from Sarah Thomson (which I believe has no license, but if it does, tell me and I'll comply), to connect the up_to_speed
method/slot to when the abovelevel
signal is tripped. Finally, we'll make up some data, and then look at the max and min of the data.
%%runcpp test_value
#include "../ah_value.h"
#include "notifier.h"
int main(void){
// we need to create a new value class of type int
value<int> *vl = new value<int>();
// we need to create a new notifier class and pass in our value
notifier *ntfr = new notifier(vl);
// we need to connect the signal for above level to the slot telling us
// we're up to speed
vl->abovelevel.connect(ntfr, ¬ifier::up_to_speed);
// now we have to set what level we're up to speed at
vl->setlevel(5);
// now we want to slowly increase the speed
vl->set(0);
vl->set(1);
vl->set(3);
vl->set(5);
vl->set(7);
vl->set(9);
vl->set(7);
vl->set(5);
// now that we're back below speed (remember we said *above* 5), we can end
// and look at details
printf("The maximum when up to speed was %d, and the minimum was %d.", \
vl->getmax(),vl->getmin());
return 0;
}