Only a subset of the public contributions is listed.

Current contribution

Kuiristo

A recipe manager for cooking robots — it speaks Thermomix — and a cookbook you can actually search. Recipes are indexed by preparation and total time, by ingredients you do or do not want in them, by course, by kind of preparation, by dietary profile, by season and by origin, with favourites bookmarked. Pick a few and it builds the shopping list. Pages are print-friendly and the whole book exports to a static offline copy.

Kakapo

A beep player small enough for a micro-controller with nothing but a buzzer on a PWM pin. It comes in two halves. The encoder, on the desktop, reads a CSV of frequency and duration or a line of beep commands and emits a C byte array — working out the tempo, or a fixed unit length, so the tune packs down as small as it can. The player, on the device, walks that array: a handful of opcodes for end-of-stream, tempo and note, and a melody costs a few dozen bytes of flash.

LOM

An LDAP object mapper for Ruby: a directory entry becomes a Ruby object and back again, with the mapping declared on the class — which branch to search, which filter, which attributes, and how each one is read and written. It is meant to be used with dry-struct, so the mapped object is a typed structure rather than a bag of strings.

Optique

A ports options and dependency configurator for FreeBSD, replacing what poudriere options -C does: that walks the dependency tree one port at a time and pops an interactive dialog for each. Optique scans the whole dependency closure in parallel — about a thousand ports in under a minute cold, and well under a second warm, from a persistent cache — presents a single interface over all of them, and writes every options file in one atomic pass at the end. It knows both the poudriere and the synth layouts.

Moses

A do-it-yourself water-leak breaker built around a Raspberry Pi. It watches household water usage and can shut the main supply through a solenoid valve, so a leak does not become water damage. Everything is driven over MQTT, so it joins an existing home-automation setup — Home Assistant, Node-RED — without locking the house into a proprietary cloud.

The three Moses programs
ProgramRole
moses_watermeter reads the water meter, over M-Bus or by counting GPIO pulses
moses_breaker opens and closes the solenoid valve through a relay
moses_sensors reads the optional BME280 — temperature, pressure, humidity

sinatra-wanted

Parameter processing for the Sinatra framework. One declarative call expresses the whole chain a request parameter usually goes through: required or optional with a default, type checking and coercion, retrieval of the object it names, and any further conversion through a block. It sits well with dry-types and Sequel — or an LDAP object mapper such as LOM — while depending on none of them.

Bitters

Provides access to Linux GPIO, SPI and I2C using the same kind of API that can be found for micro-controllers, which is what makes porting a vendor driver to Raspberry Pi user space straightforward. It goes through Linux ioctl for portability and performance (no devmem, no sysfs).

Toggle a reset pin and run an SPI transfer
example.c
#include "bitters.h"
#include "bitters/rpi.h"
#include "bitters/gpio.h"
#include "bitters/spi.h"

int main() {
  /* Device configuration (GPIO/SPI)*/
  struct bitters_gpio_cfg reset_cfg  = { .dir       = BITTERS_GPIO_DIR_OUT,
                                         .defval    = 1,
                                         .label     = "reset",              };

  struct bitters_spi_cfg spi0_cfg    = { .mode      = BITTERS_SPI_MODE_0,
                                         .transfer  = BITTERS_SPI_TRANSFER_MSB,
                                         .word      = BITTERS_SPI_WORDSIZE(8),
                                         .speed     =  3000000,             };

  /* Get device handler */
  bitters_gpio_pin_t reset = BITTERS_GPIO_PIN_INITIALIZER(BITTERS_RPI_GPIO_CHIP,
                                                          BITTERS_RPI_P1_15);
  bitters_spi_t spi0       = BITTERS_SPI_INITIALIZER(BITTERS_RPI_SPI0, 0);

  /* Initialise library and enable devices */
  bitters_init();
  bitters_gpio_pin_enable(&reset , &reset_cfg);
  bitters_spi_enable(&spi0, &spi0_cfg);

  /* Send a reset pulse */
  bitters_gpio_pin_write(&reset, 1);
  bitters_delay_us(100);
  bitters_gpio_pin_write(&reset, 0);

  /* Perform SPI transfer */
  uint8_t data[8];
  const struct bitters_spi_transfer xfr[] = {
    { .tx = "cmd", .len = 3            },
    { .rx = data,  .len = sizeof(data) }
  };
  
  bitters_spi_transfer(&spi0, xfr, 2);

  return 0;
}
A cut-glass bitters decanter
Bitters

DW1000 driver

A driver for the DW1000, a wireless transceiver based on ultra-wideband techniques, which allows cost-effective indoor and outdoor positioning. It was written so that a network protocol built on top of it has the same consistent behaviour — and the same bugs — on every platform: Zephyr, ChibiOS, MyNewt, Crazyflie, and Linux through the bitters library. Supporting another platform means implementing a small API for delays, GPIO toggling and SPI transfers.

Platforms the DW1000 driver supports
PlatformNotes
Zephyr requires version 2 or later
ChibiOS not tested recently
MyNewt not tested recently
Linux through the bitters library
Crazyflie based on FreeRTOS
Supply eight functions and two types to reach another platform
Porting API
/* Delay */
void _dw1000_delay_usec(uint16_t us);
void _dw1000_delay_msec(uint16_t ms);

/* GPIO toggling */
typedef ..to_define.. dw1000_ioline_t;
void _dw1000_ioline_set(dw1000_ioline_t line);
void _dw1000_ioline_clear(dw1000_ioline_t line);

/* SPI communication */
typedef ..to_define.. dw1000_spi_driver_t;
void _dw1000_spi_low_speed(dw1000_spi_driver_t *spi);
void _dw1000_spi_high_speed(dw1000_spi_driver_t *spi);
void _dw1000_spi_send(dw1000_spi_driver_t *spi,
              uint8_t *hdr, size_t hdrlen, uint8_t *data, size_t datalen);
void _dw1000_spi_recv(dw1000_spi_driver_t *spi,
              uint8_t *hdr, size_t hdrlen, uint8_t *data, size_t datalen);
The DW1000 ultra-wideband transceiver module
DW1000

Raspberry Pi UWB sniffer

Turns a Raspberry Pi into an ultra-wideband sniffer, leveraging the bitters library and the DW1000 driver to talk to the chip. Received UWB packets are forwarded to the Ethernet interface, so they can be processed and dissected with tcpdump or wireshark. They go out under their own ethertype, so a capture on the desktop is a single filter away: tcpdump ether proto 6666.

Capture UWB channel 5 and read the frames back over Ethernet
On the Raspberry Pi
# Sniffing UWB packets on the RPI and forwarding them to Ethernet network
#
# UWB chip is tuned for capturing on channel 5 with a 6.8Mb/s baudrate
# and preambule code 10.
#
uwb-sniffer -i eth1 -P 6666                                 \
    -c 5 -b 6800 -p 64                                      \
    --tx_pcode 10 --rx_pcode 10 --tx_plen 128 --rx_pac 8
On the desktop
# Analysing received packet on the desktop environment
# (it is better to use wireshark that tcpdump)
#
tcpdump ether proto 6666 and ether src aa:bb:cc:dd:ee:ff
A Raspberry Pi in a red case, jumper-wired to a UWB board
RPI + UWB

SPANK

A distance measurement protocol aimed at a swarm of drones, computing drone inter-distance over UWB and scheduling the measurements among the drones, so the swarm can maintain its structure. A demonstration using Crazyflie drones was done at EWSN 2020.

Platforms SPANK has been ported to
PlatformDirectoryNotes
Crazyflie 2port/cf2
MyNewt port/mynewt not tested recently
Zephyr port/zephyr
Unix port/unix simulation only
A Crazyflie quadcopter, a bare circuit board with four rotors
Crazyflies

Redskin

Distance measurement firmware based on the SPANK protocol, targeting the DWM1001 development board but easily portable to other hardware embedding a DW1000 chip. Various information can be accessed and configured from a UART console (through the USB port), and the firmware can also be interfaced with another subsystem over I2C.

How to interact with the Redskin firmware
BusInteractionConnected to
UARTShell a USB/UART converter, or the debugging interface
I2C Register based the I2C pins of an MCU or a Raspberry Pi

GTFS DB

Imports GTFS files into a database for further manipulation: agencies, routes, trips, stops and stop times, fares, calendars and their exceptions, transfers, frequencies and route shapes.

See the fourteen tables the import populates
Tables created and filled by a GTFS import
TableDescription
provider information about the imported file
stop_times times a vehicle arrives at and departs from stops, for each trip
stops stops where vehicles pick up or drop off riders
agency transit agencies with service represented in the dataset
calendar service dates as a weekly schedule with start and end dates
calendar_dates exceptions to the services defined in the calendar
fare_attributes fare information for a transit agency's routes
fare_rules rules applying fares to itineraries
feed_info dataset metadata
frequencies time between trips
routes groups of trips shown to riders as a single service
transfers rules for making connections at transfer points between routes
trips sequences of stops occurring during a specific time period
shapes rules mapping vehicle travel paths, also known as route alignments

This work was supported by the UrPolSens project funded by LABEX IMU (ANR-10-LABX-0088) of Université de Lyon, within the program Investissements d'Avenir (ANR-11-IDEX-0007) operated by the French National Research Agency (ANR).

Track simplifier

Simplifies a polyline using various methods (radial distance, Douglas Peucker, Reumann Witkam, …). The polyline is simply an array of points, and the caller supplies the two distance functions — point to point, and point to line — so the library does not care what a point looks like.

Hand it two distance lambdas and simplify a polyline
# The polyline
polyline   = [ {x: 1, y: 1}, {x: 5, y: 7}, ....., {x: 8, y: 1} ]

# The two methods to compute distance
# They also deal with the point structure (Array, Hash, ....)
dist_point = ->(a,b)    {   a,b =                [a[:x],a[:y]], [b[:x],b[:y]]
                            a,b =                Vector[*a],    Vector[*b]
                            (b - a).norm
                        }
dist_line  = ->(p, a,b) { p,a,b = [p[:x],p[:y]], [a[:x],a[:y]], [b[:x],b[:y]]
                          p,a,b = Vector[*p],    Vector[*a],    Vector[*b]
                          pa, ba = p-a, b-a
                          t      = pa.dot(ba)/ba.dot(ba)
                          (pa - t * ba).norm
                        }

# Perform simplification
ts = TrackSimplifier.new(point2point: dist_point, point2line: dist_line)
ts.radial_distance(polyline, radius)    # Radial distance
ts.reumann_witkam(polyline,  threshold) # Reumann Witkam

This work was supported by the Privamov project funded by LABEX IMU (ANR-10-LABX-0088) of Université de Lyon, within the program Investissements d'Avenir (ANR-11-IDEX-0007) operated by the French National Research Agency (ANR).

Everything else on GitLab

Code legacy

DNSdoctor

Archived · 2012

DNSdoctor is intended to help solving DNS misconfigurations or inconsistencies that are usually revealed by an increase in the latency of applications. The DNS is a critical resource for every network application, so it is quite important to ensure that a zone or domain name is correctly configured in the DNS.

It is a fork of ZoneCheck occurring at version 2.0.4 (but keeping the same developer). The tool was initiated and developed by engineers working at NIC France (INRIA's service) to check the correct configuration of a zone before delegating a domain name under .fr, and was in use until October 2003. The second version was started from scratch by myself (as an AFNIC employee) at the end of 2002, emphasis was put on modularity and extensibility; this version has now taken over the responsibility of checking the delegation of domain under .fr

DNSdoctor screenshot
DNSdoctor screenshot

MW-CVSweb

Archived · 2012

MW-CVSweb is an extension to MediaWiki which provides the special page Special:CVSweb. This page allows you to browse a CVS repository.

When developing an open source project, you generally welcome people's contributions; the idea here is to also encourage contributions to the website through the use of a Wiki, and this tool provides an integrated CVS browser to the Wiki platform. It is a port of the cvsweb application, to the MediaWiki platform.

MW-CVSweb screenshot
MW-CVSweb screenshot

ANEP Socket v0.5

Archived · 2000

An active network node is capable of dynamically loading and executing programs written in a variety of languages. These programs are carried in the payload of an active network frame. The program is executed by a receiving node in the environment specified by ANEP. Various options can be specified in the ANEP header, such as authentication, confidentiality, or integrity. (from the ANEP-draft)

An implementation of ANEP on top of IPv6 (and IPv4) has been made available, for the Linux kernel. This work was done as part of the AMARRAGE project, when working in the RESEDAS team at LORIA.

Various small tools

Archived
digest
An md5/md5sum like program able to perform file checking. (the standard FreeBSD md5 program is not able to perform file checking, and the Linux md5sum program is not able to generate file to the FreeBSD format).
ed2k
A program computing eDonkey link (ed2k://), or only the Hash/Id (à la md5).
xmlinfo
A program extracting information (xml encoding; DOCTYPE name, public and system ID) about an XML document.