Make Your Own Hexabus Device

Bernd Lietzow edited this page May 23, 2013 · 16 revisions
Clone this wiki locally

This document can help you build your own Hexabus compatible device using one of the Hexabus prototype boards.

Keep in mind that the Hexabus software and the Hexabus protocol are work in progress. Things may change, even to the point where different versions become completely incompatible with each other. If you're working on a Hexabus device, please try to stay updated on what happens in the development branch of the repository. And of course, if you find problems or bugs or if you need a new feature, let us know!

This document refers to the development branch of the repository.

You need:

  • A Hexabus prototype board or a Hexabus Socket
  • A Hexabus USB-Stick (for over-the-air flashing) or a JTAGICE or somehow compatible device (for flashing via JTAG)
  • A copy of the source tree from the development branch
  • All the related software (avr-gcc, cmake, avrdude, ...)

Notes on how to compile and upload a firmware image to a Hexabus Plug or USB Stick can be found under Compiling-and-uploading-Firmware.

Make yourself at least somehow familiar with how Contiki works, and how the Hexabus specific things work. Get to know the hardware, and which features you need for your specific application.

Compile the firmware: Go to firmware/Hexabus-Socket and run make there. (Use the VM for this if necessary) Flash it onto the board (as described in Compiling-and-uploading-Firmware).

If you have a Hexabus Development Board, you might want to change your Hexabus device's IP address at this point. All the prototype boards default to fe80::50:c4ff:fe04:000a, which becomes a problem if you have multiple ones and forget to change the address. The IP address is generated from the MAC address so it is adjusted by changing the device MAC address.

If you want to connect / send packets from your PC to your Hexabus device, you either need a router setup as the one described in Getting Started, or you put the USB Stick into you PC's USB port and run radvd there. The radvd.conf shown in Getting Started should also work there, just adjust the prefix if you have to.

Compile hexaswitch, and try out the network functions the Hexabus Socket software offers (get the device descriptor, switch the relay, get the power meter reading, wait for a value broadcast, ...). You might want to hook up an FTDI to your board (see Hexabusplugserialinterface) to get an idea of what's going on. This also helps a lot during development, PRINTF is your friend.

Adding Functionality

In most cases, the functionality you want to add is best implemented as one or multiple Contiki processes. Whether you use a process or just add some functions is up to you.

The connection to the Hexabus world is made through the Endpoint Registry. Once you have implemented everything to your liking, adding an endpoint to control your new code from the network requires only a few simple steps:

  • Add your endpoint ID to shared/endpoints.h -- use the NAME defined there instead of the literal EID everywhere else.
  • Include shared/endpoints.h and endpoint_registry.h
  • Add a read function to your code. This will be called whenever your endpoint is read, e.g. by queries. The prototype for such a function is static enum hxb_error_code read(struct hxb_value* val). Simply assign the current value of your endpoint to the appropriate member of val for primitive types (e.g. val->v_float for floating point values) or copy it into the appropriate member for strings and binary packets. Return HXB_ERR_SUCCESS on success, or another hxb_error_code on error.
  • If required, add a write function. These functions have the prototype static enum hxb_error_code write(const hxb_envelope* env) and will we called whenever the endpoint is written to. env->value will contain the value written to the endpoint for primitive types, or a pointer to the value for strings and binary packets. Writes from other devices in the network will set ev->src_ip to the ip of the device that sent the write packet, and ev->src_port to the corresponding port. Write from the state machine will be executed with src_ip == ::1 and src_port == 0.
  • Give your endpoint a name. Declare the name as static const char ep_name[] PROGMEM = "<your name>";
  • Describe the endpoint. This is done by declaring an endpoint descriptor:
    ENDPOINT_DESCRIPTOR ep_your_name = {
      .datatype = <your hxb_datatype>,
      .eid = <your EID>,
      .name = ep_name,
      .read = read, // name of your read function
      .write = write // name of your write function, or 0 if the endpoint is read-only
    The endpoint registry will check data types for you, take care of EID matching, packet handling and other mundane tasks.
  • Call ENDPOINT_REGISTER(ep_your_name) somewhere. At this point, your endpoint will be known to the system.

If your endpoint is some kind of sensor then its reading might be of interest to other Hexabus devices on the network, you can broadcast its value if you want to. If you want to broadcast it periodically, you can set this up in hexabus_config.h -- just add it to the VALUE_BROADCAST_AUTO_EIDS (and don't forget to update VALUE_BROADCAST_NUMBER_OF_AUTO_EIDS). If the endpoint's value should be broadcast whenever some event occurs, you can do this by calling broadcast_value from the value_broadcast module.