Home | History | Annotate | Download | only in docs
      1 libmraa Internals                       {#internals}
      2 =================
      3 
      4 For building see @ref building. This will describe the general internal build
      5 of libmraa and will be useful to developers who'd like to understand more of
      6 how libmraa works or who'd like to add additional platforms. The internals will
      7 deal with the C API as that is the low level API which libmraa is built around.
      8 Note that C++ is simply a header only wrapper of the C API.
      9 
     10 libmraa has the philosophy that the board mapping is what we typically use in
     11 the API with the execption of i2c/spi bus numbering as they are typically not
     12 labelled on boards and so we use the kernel numbering scheme. Whilst this can
     13 confuse some, it's typically not an issue as platforms rarely expose more than
     14 one of these for user use and so when this is the case, libmraa will always use
     15 the bus in the pinmapper. For example edison uses i2c #6 but since there is
     16 only one, libmraa will try to be helpful and everything is treated as 6 when
     17 doing a mraa_i2c_init(). The _raw functions will override the pinmapper and can
     18 be accessed without a valid board configuration. This can be helpful either in
     19 development of platform configurations for mraa or when modifying kernels
     20 etc... Internally the mechanism is used heavily.
     21 
     22 In libmraa, all code is split into 7 modules, src/{i2c, spi, gpio, uart, pwm,
     23 aio and common}. These should be fairly self explanatory in goals/purpose but a
     24 few work in different ways. Public APIs are stored in api/ and internal headers
     25 are in include/
     26 
     27 ### Logging ###
     28 
     29 Logging is now done purely in syslog(). Note that on platforms running systemd
     30 journald will intercept syslog(3) calls and log to the journal instead. You can
     31 set the log mask by using mraa_set_log_level(). Doing a DEBUG build of libmraa
     32 will also cause the DEBUG macro to be defined which will cause the syslog mask
     33 to be unset.
     34 
     35 ### Contexts ###
     36 
     37 libmraa uses contexts to store all information, this context cannot be accessed
     38 by the user and so it's layout can and may be changed without warning to users.
     39 If an init() function fails it will return NULL and further calls with this
     40 context will lead to undefined behaviour.
     41 
     42 ### Pinmapper ###
     43 
     44 The mraa_board_t is defined in mraa/common.h. It's a mostly static structure
     45 initialised during mraa_init(). The pinmap file in
     46 src/{arch}/{manufacturer}_{boardname}_{revision}.c then fills this array. It's
     47 also where platform hooks can be defined, functions that will be run at various
     48 'hook' points in the code.
     49 
     50 The mraa_pininfo_t structure needs to be set for the board pincount (set in a
     51 macro in the platform configuration header. Every pin will have a
     52 mraa_pincapabilities_t which will define what it can do. The doxygen
     53 documentation explains how this works but it's essentially a bitfield which
     54 needs to be set for every capability the pin can have. Gpios can have multiple
     55 muxes which will be set at the gpio init before it can be toggled.
     56 
     57 ### i2c ###
     58 
     59 I2c from userspace in GNU/Linux is handled by character devices handled by the
     60 kernel driver i2c-dev. For more details the i2c/dev-interface documentation
     61 file in the kernel is the place to go.
     62 
     63 In libmraa, we re-use part of a library - libi2c from RoadNarrows -
     64 i2c/smbus.c. This library simply makes it easier for us to handle the error
     65 conditions that can arrise when writing on i2c buses. Essentially the API is
     66 fairly simple consisting of writes & reads.
     67 
     68 Careful - on alot of platforms i2cdetect will often crash. To findi your i2c
     69 addresses please look at your sensor's datasheet! If using i2cdetect most
     70 platforms do not support SMBus quick write so use the '-r' flag.
     71 
     72 ### spi ###
     73 
     74 Mraa deals exclusively with spidev, so when we say bus we really mean bus +
     75 chip select from spidev. Spi(0) could lead to spidev5.1 and Spi(1) to
     76 spidev5.2. Typically on a micro using a random gpio as a chip select works
     77 well, and on some platforms if one is careful with threads this can work well
     78 with mraa. However when a kernel module shares the same bus as spidev (but on a
     79 different CS) this behaviour is *very* dangerous. Platforms such as Galileo
     80 Gen2 & Edison + Arduino breakout board work this way. Mraa will not help you in
     81 using a non hardware chip select, do so at your own peril!
     82 
     83 ### gpio ###
     84 
     85 GPIO is probably the most complicated and odd module in libmraa. It is based on
     86 the gpiolib kernel driver framework which uses sysfs. There is a lot of good
     87 documentation in gpio/sysfs.txt in the kernel docs.
     88 
     89 The main issue is that gpios on hobbyist boards typically come with a number of
     90 muxers or level shifters and are often mapped in crazy ways. libmraa's goal is
     91 to make the label on your board match the API :) We hope that pleases you.
     92 
     93 Because boards are very different we use alot of platform hooks (@ref hooks) to
     94 make the initialisation work on all platforms. The hope is that simple
     95 platforms with no level shifters or expanders will work with just the pinmap
     96 definition.
     97 
     98 GPIOs are typically interfaced via sysfs because that's easier for us but we
     99 can also work with fast gpio. This is typically preffered to do mmap gpio
    100 access. This is however trickier and typically relies on lots of platform
    101 hooks. By default we support hitting /dev/mem or another device at specific
    102 addresses to toggle gpios which is how mmap access works on some boards.
    103 
    104 Note that in Linux gpios are numbered from ARCH_NR_GPIOS down. This means that
    105 if ARCH_NR_GPIOS is changed, the gpio numbering will change. In 3.18+ the
    106 default changed from 256 to 512, sadly the value cannot be viewed from
    107 userspace so we rely on the kernel version to extrapolate the likely value.
    108 
    109 ### uart ###
    110 
    111 libmraa does not support UART/serial as there are many good libraries that do
    112 this already. In the future we may wrap or use one. However the class exists to
    113 set the pinmapper correctly for uart to work on some platforms.
    114 
    115 ### pwm ###
    116 
    117 Internally everything with PWM in mraa is in microseconds because that's what
    118 the linux kernel uses and is probably all the granularity we'll ever
    119 need/achieve with the kind of hardware we're targetting. Board configuration
    120 pwm max/min values are always set in microseconds.
    121 
    122 ### aio ###
    123 
    124 AIO pins are numbered after GPIO pins. This means that on Arduino style boards
    125 pin 14 is A0. Typically mraa will only support an ADC if a platform ships with
    126 one and has a good kernel module for it. Extra i2c/spi ADCs can be supported
    127 via something like UPM but are unlikely to receive support in mraa at the moment.
    128 
    129 Note that giving mraa_aio_init(0) will literally query the pinmapper for
    130 board->gpio_count + 0 so you must place your aio pins after gpio_count. This is
    131 the default behaviour but can of course be overriden by advance function
    132 pointers. Whilst maybe not the sanest of defaults, most of the hobbyist boards
    133 we deal with follow a naming pattern similar to Arduino or have no ADC so for
    134 now we have considered this sensible.
    135 
    136 ### Initialisation ###
    137 
    138 mraa_init() needs to be called in order to initialise the platform files or
    139 'pinmap'. Because calling this is tedious libmraa uses a C constructor to run
    140 mraa_init on library load. This means that it is not possible to stop this
    141 running and all function calls like mraa_set_log_level() will not work during
    142 mraa_init(). This feature is supported by most sane compilers and libcs but you
    143 can turn off CTORS in uclibc, though I've yet to find a configuration with
    144 someone doing that. mraa_init() can be called multiple times if you feel like
    145 being 'safe'.
    146 
    147 In the SWIG modules mraa_init() is called during the %init stage of the module
    148 loading. This is simply to avoid mraa_init() running 'too' early, though I've
    149 never seen an issue in running it in a CTOR.
    150 
    151 ### SWIG ###
    152 
    153 At the time when libmraa was created (still the case?) the only - working -
    154 API/wrapper generation tool that supported nodejs was SWIG. For more general
    155 information on SWIG please see the SWIG documentation.
    156 
    157 The src/{javascript, python} & src/mraa.i folders contain all the files for the
    158 SWIG generation. The C++ headers in api/mraa/ are given as input sources to
    159 SWIG. SWIG modules do not link to libmraa (although maybe that would be a good
    160 idea...)
    161 
    162 Typemaps are used heavily to map uint8_t* pointers to bytearrays and
    163 node_buffers. These are native python & node.js types that represent uint8_t
    164 data the best and are very well supported in both languages. Argument
    165 conversions and memory allocations are performed so the performance of using
    166 these functions compared to the C/C++ equivalent will likely be a little lower,
    167 however it is much more natural than using carrays.i typemap library.
    168 
    169 ### NPM ###
    170 
    171 mraa is published on NPM, there is a target to prebuild a mraa src tarball that
    172 can be built with node-gyp. The way this works is to use the mraa_LIB_SRCS
    173 array to generate a binding.gyp file from the skeleton binding.gyp.cmake in
    174 src/javascript. Because we don't expect most NPM users to have SWIG we
    175 precompile the src/mraajsJAVASCRIPT_wrap.cxx. The src/version.c is already
    176 known since this is a static tarball so we write that too. These files are
    177 placed not in a build/ directory but in the main mraa directory. You can then
    178 tar the directory up and send it to NPM. This is done automatically on every
    179 commit by our automated build system.
    180 
    181