API reference

The library exports the following set of functions. A non-zero return value indicates that an error has occurred.

  int lnp_open(tower, device, flags);
  void lnp_close(tower);
  int lnp_set_range(tower, range);

  void lnp_raw_set_handler(tower, handler);
  void lnp_lego_set_handler(tower, handler);
  void lnp_integrity_set_handler(tower, handler);
  void lnp_addressing_set_handler(tower, address, handler);
  void lnp_addressing_set_multi(tower, mask, value, handler);

  void lnp_block(tower);
  void lnp_unblock(tower);

  int lnp_raw_send(tower, data, unsigned length);
  int lnp_lego_send(tower, data, length);
  int lnp_integrity_send(tower, data, length);
  int lnp_addressing_send(tower, data, length, dest, src);

  unsigned char lnp_addressing_host(mask, address);
  unsigned char lnp_addressing_port(mask, address);
  unsigned char lnp_addressing_addr(mask, host, port);

  void lnp_hexdump(prefix, data, length);

Initializing the tower

The function lnp_open opens the device the tower is connected to, and configures it as needed. Two threads for the keepalive mechanism and data reception are started on success. The tower record stores all settings of the device and serves as some kind of handle that must be passed to all other functions.

  int lnp_open(struct lnptower *tower, char *device, unsigned flags);

The device parameter must contain a valid device name, the installation instruction contains a few typical examples for different platforms. If device is a NULL pointer, lnphost will try to evaluate the RCXTTY environment variable or move to a platform dependent default setting (LNP_DEFAULTDEVICE). flags is a bitmask based on the following entries.

  • LNP_FAST increases the speed from 2400 to 4800 baud (currently only with the serial tower)
  • LNP_NOPARITY disables the parity bit (compatibility mode for old legOS versions
  • LNP_NOKEEPALIVE disables the keepalive mechanism on the serial tower

The lnp_close function terminates the two threads and closes the connection to the tower device.

  void lnp_close(struct lnptower *tower);

Transmission range of the USB tower can be set to three different values (LNP_LOWRANGE, LNP_MIDRANGE und LNP_HIGHRANGE).

  int lnp_set_range(struct lnptower *tower, int range);

This function is not implemented at the moment because the Linux kernel module does not support this function.

Receiving data

lnphost supports 4 different types of packet handlers for raw data, the lego protocol, brickOS integrity layer and brickOS addressing layer. A handler is called if a matching valid packet has been received. This can also occur if the packet is send by the same tower, because these echoed packets cannot be detected and removed reliably. A decoded copy of the packet's payload is passed to the handler.

  typedef void (*lnp_raw_handler_t) (unsigned char *data, unsigned length,
                   int isvalid);
  typedef void (*lnp_lego_handler_t) (unsigned char *data, unsigned length);
  typedef void (*lnp_integrity_handler_t)(unsigned char *data,
                   unsigned char length);
  typedef void (*lnp_addressing_handler_t) (unsigned char *data,
                   unsigned char length, unsigned char source, unsigned char dest);

The handler may call all system functions, but it must be kept in mind that the handler is executed concurrently to the main program. The reception mechanism is blocked until the handler terminates, so the operating system's input buffer might overrun if execution takes too long (usually more than a second). A simple set of routines can be used to install handlers for the different types of packages. It is always possible to pass LNP_NOHANDLER instead of an existing function to remove the previous handler.

  void lnp_raw_set_handler(struct lnptower *tower, lnp_raw_handler_t handler);
  void lnp_lego_set_handler(struct lnptower *tower, lnp_raw_handler_t handler);
  void lnp_integrity_set_handler(struct lnptower *tower,
                            lnp_integrity_handler_t handler);
  void lnp_addressing_set_handler(struct lnptower *tower, unsigned char address,
                                   lnp_addressing_handler_t handler);

The raw data handler receives all bytes from the input stream without any filtering or processing. It can be called for single bytes or whole blocks, including valid packets for one of the protocols. In the latter case the parameter isvalid will be set to a non-zero value

BrickOS and lnpd are using 8 bit wide addresses for sources and destinations in the addressing layer. lnphost allows the user to use the whole address instead of using a fixed host number as brickOS and lnpd do. A few conversion functions can translate between these addressing schemes, they are discussed near the bottom of this page.

  lnp_addressing_set_multi(struct lnptower *tower, unsigned char mask,
                 unsigned char value, lnp_addressing_handler_t handler);

lnp_addressing_set_multi can be used to establish a single handler for a whole range of ports. The specified handler will be set for all addresses which match the condition (address&mask)==value.

It is possible to disable the callback mechanism for any period of time.

  void lnp_block(struct lnptower *tower);
  void lnp_unblock(struct lnptower *tower);

The receiver continues to work independent of this setting and will still try to assemble packets from incoming bytes. It simply does not call any handler it a packet is complete. Blocking callbacks does not erase any data in the input buffers.

Sending data

The following functions encapsulate the data passed to them into a packet of the particular format and send it to the tower. The only exception is lnp_send_raw which sends the passed data without any modification.

  int lnp_raw_send(struct lnptower *tower, unsigned char *data, unsigned length);
  int lnp_lego_send(struct lnptower *tower, unsigned char *data,
                             unsigned char length);
  int lnp_integrity_send(struct lnptower *tower, unsigned char *data,
                             unsigned char length);
  int lnp_addressing_send(struct lnptower *tower, unsigned char *data,
                             unsigned char length,
                             unsigned char dest, unsigned char src);

Address calculation

BrickOS uses an 8 bit wide address to mark sources and destinations for addressing layer packets. The address field can be split into a host address (upper bits) and a port number (lower bits). A netmask describes which bits belong to the host address, and the mask should be identical on all communication participants. BrickOS uses a default netmask of 0xf0 and host address 0 for the RCX and 8 for the tower. Every host can use up to 16 ports, only port 0 is reserved for program downloads. This means that for example to tower can use addresses 0x81 to 0x8f. The following two functions can extract host address and port number from a given 8 bit address.

  unsigned char lnp_addressing_host(unsigned char mask, unsigned char address);
  unsigned char lnp_addressing_port(unsigned char mask, unsigned char address);

The opposite conversion can be done by lnp_addressing_addr, which assembles a host address and a port number into an address.

  unsigned char lnp_addressing_addr(unsigned char mask,
                   unsigned char host, unsigned char port);

It is possible to use any value as a netmask with lnphost, but this should not be done to maintain compatibility with brickOS.

Additional functions

The function lnp_hexdump can be used to dump a block of data for debugging purposes. A prefix string can printed before the start of every line if desired. Otherwise prefix must be set to NULL.

  void lnp_hexdump(char *prefix, void *data, unsigned length);