Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [paho-dev] Contributing and coding standards?

Hello Ian,

Well my board is running a single core MIPS 24KEc at 580Mz with 256MiB
of RAM -- an embedded system by any definition, although it's still a
fairly "beefy" processor with a 64k instruction cache and a 32k data
cache.  But, we've been throwing a lot at it and it's become apparent
that we need to squeeze what we can as I started getting the CPU
utilization up quite a bit.

For my purposes, I may create a shared library that links in the paho
embedded stuff statically, but only exposes my higher level interface
(wrapping paho) that my programs will use.  I don't know for certain yet
honestly, but I want to try to keep the footprint small and efficient to
see how much throughput I can get.

It's probably better to consider the platform "POSIX" instead of "Linux"
since there's really nothing specific to the Linux kernel or the GNU
userland that I have seen thus far.  The addition of threading/async
support could change that, of course.  I don't know the Apple platforms
very well, but I know that it they are POSIX compliant systems.  I also
find it helpful when I can build my embedded software for my workstation
for as much development and testing as possible prior to testing and
debugging on my boards.  To that end, a POSIX build could even be done
on Windows with MinGW or Cygwin.

I like the idea of abstracting the required "platform services" (for
lack of a better term?) and I've been trying to come up with a cleaner
way to do it, but I have not so far.  I've had a *lot* of ideas to
suggest, but upon examination most of them suck. :)

None the less, defining the lower-level interfaces would be good, even
if only in comments.  Example:

class Socket
{
public:
    virtual int connect(const char* hostname, int port, unsigned int timeout = 1000) = 0;
    virtual int read(unsigned char* buffer, int len, unsigned int timeout) = 0;
    virtual int write(const unsigned char* buffer, int len, unsigned int timeout) = 0;
    virtual int disconnect() = 0;
};

class Timer
{
public:
    virtual bool expired() = 0;
    virtual void countdown_ms(unsigned long ms) = 0;
    virtual void countdown(unsigned int seconds) = 0;
    virtual unsigned long left_ms() = 0;
};


In practice, passing them as template parameters is better so we aren't
making virtual function calls, but I think that having them derive from
the above would ensure a common interface and just mean that the objects
will be larger by the size of a pointer and the addition of a small
function pointer table for each class?   I'm not really sure yet, I
haven't tried it out.

I'm playing with the build a bit and I've split the C++ client sources
into three files:

mqtt/embed/client.hpp      -- contains just the class declaratinos
mqtt/embed/client_impl.hpp -- contains the function implementations
client.cpp                 -- just includes the above

So the (perhaps kooky) idea here is that we can build a shared library,
static library or a program can just include mqtt/embed/client_impl.hpp
from one of it's .cpp files.  What I'm working on now is a mechanism to
have these two files include the correct per-arch/OS, maybe by having
socket.hpp, socket_impl.hpp, timer.hpp and timer_impl.hpp for each platform?

Alternatively, instead of some abstract Socket and Timer base class,
there could be a single declaration using #ifdefs for each arch and then
each arch defines the member functions -- this is possibly my worst idea :)

class Socket
{
public:
#ifdef POSIX
    Socket();
#elif defined(ARDUINO)
    Socket(Client& client);
#elif defined(MBED)
    Socket(EthernetInterface *anet);
#endif

    int connect(const char* hostname, int port, unsigned int timeout = 1000);
    int read(unsigned char* buffer, int len, unsigned int timeout);
    int write(const unsigned char* buffer, int len, unsigned int timeout);
    int disconnect();

private:
#ifdef POSIX
    int sock;
#elif defined(ARDUINO)
    Client* client;
#elif defined(MBED)
    bool open;
    TCPSocket mysock;
    EthernetInterface *net;
    Timer timer;
#endif
};


I'm still experimenting and I just got a new load of work, so it might
go slower than I had hoped.

Thanks,
Daniel


Back to the top