cppm

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

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/

Usage

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.

Memory Objects

shm - Shared Memory

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.

Example

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.

In [1]:
from cppm import cppmagic
In [2]:
%%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 shms.

In [3]:
%%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;
}
Episode 1 in which Sherlock is a good guy!
Episode 2 in which Sherlock is a bad guy!
Episode 3 in which Sherlock is dead!
Episode 4 in which Sherlock is now alive again!

Now, we just have to stop the server to make sure we're not leaving too many things open.

In [4]:
%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

In [5]:
!ipcs
IPC status from <running system> as of Wed May 24 10:44:34 EDT 2017
T     ID     KEY        MODE       OWNER    GROUP
Message Queues:

T     ID     KEY        MODE       OWNER    GROUP
Shared Memory:
m  65536 0x52020016 --rw-------     root    wheel
m 983041 0x0000162e --rw-rw-rw-   ahagen    staff

T     ID     KEY        MODE       OWNER    GROUP
Semaphores:

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:

In [6]:
!ipcrm -M 5678

ah_value - Stateful Variables

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).

Usage

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.

In [1]:
from cppm import cppmagic
In [2]:
%%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.

In [3]:
%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.

In [4]:
%%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, &notifier::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;
}
Motor is up to speed
The maximum when up to speed was 9, and the minimum was 5.

TCP Objects

UDP Objects