Difference between revisions of "Abi"

From PaparazziUAV
Jump to navigation Jump to search
 
Line 16: Line 16:
   <message name="DATA" id="0">
   <message name="DATA" id="0">
   <field name="a" type="float"/>
   <field name="a" type="float"/>
   <field name="b" type="struct bla"/>
   <field name="b" type="struct bla *"/>
   </message>
   </message>
   ...
   ...
Line 23: Line 23:
== Code generation ==
== Code generation ==


The generated code will be in var/include/abi_messages.h. Bind and Send functions are generated, as well as callback type definition. A linked list is used to store the binded callbacks for each message. The head of the list is in an array to allow a fast access.
The generated code will be in var/include/abi_messages.h and include some structure definition from sw/airborne/subsystems/abi_common.h. Bind and Send functions are generated, as well as callback type definition. A linked list is used to store the binded callbacks for each message. The head of the list is in an array to allow a fast access.


  // Message IDs
  // Code in abi_common.h
  #define DATA_ID 0
  // Here, include header custom structures you may want to use in ABI messages
// Default is to include pprz algebra libraries
   
   
// Callbacks
  typedef void (*abi_callback)(void); // Generic callback definition
  typedef void (*abi_callback)(void); // Generic callback definition
typedef void (*abi_callbackDATA)(const float * a, const struct bla * b); // Specific callback for DATA message (arguments are const to prevent modifying them)
// Array and linked list
#define ABI_MESSAGE_NB <highest id of the messages in airborne class + 1>
   
   
  struct _abi_event_struct {
  struct _abi_event_struct {
Line 39: Line 35:
   struct _abi_event_struct * next;
   struct _abi_event_struct * next;
  };
  };
  typedef struct _abi_event_struct * abi_event;
  typedef struct _abi_event_struct abi_event;
   
   
  #ifdef ABI_C
  #ifdef ABI_C
Line 46: Line 42:
  #define EXTERN extern
  #define EXTERN extern
  #endif
  #endif
EXTERN abi_event abi_queues[ABI_MESSAGE_NB]; // Magic trick to avoid generating .c file
   
   
  #define ABI_FOREACH(head,el) for(el=head; el; el=el->next)
  #define ABI_FOREACH(head,el) for(el=head; el; el=el->next)
  #define ABI_PREPEND(head,new) { (add)->next = head; head = add; }
  #define ABI_PREPEND(head,new) { (add)->next = head; head = add; }
// Code generated in var/include/abi_messages.h
#include "subsystems/abi_common.h
// Message IDs
#define DATA_ID 0
// Callbacks
typedef void (*abi_callbackDATA)(const float a, const struct bla * b); // Specific callback for DATA message (arguments are const to prevent modifying them)
// Array and linked list
#define ABI_MESSAGE_NB <highest id of the messages in airborne class + 1>
EXTERN abi_event abi_queues[ABI_MESSAGE_NB]; // Magic trick to avoid generating .c file
   
   
  // Bind and Send for each messages
  // Bind and Send for each messages
  static inline void AbiBindMsgDATA(abi_event ev, abi_callbackDATA cb) {
  static inline void AbiBindMsgDATA(abi_event * ev, abi_callbackDATA cb) {
   ev->cb = (abi_callback)cb; // Store callback
   ev->cb = (abi_callback)cb; // Store callback
   ABI_PREPEND(abi_queues[DATA_ID],ev); // add to the head of the list (because I'm lazy)
   ABI_PREPEND(abi_queues[DATA_ID],ev); // add to the head of the list (because I'm lazy)
  }
  }
   
   
  static inline void AbiSendMsgDATA(float * a, struct bla * b) {
  static inline void AbiSendMsgDATA(float a, struct bla * b) {
   // Call all callback functions
   // Call all callback functions
   abi_event e;
   abi_event* e;
   ABI_FOREACH(abi_queues[DATA_ID],e) {
   ABI_FOREACH(abi_queues[DATA_ID],e) {
   abi_callbackDATA cb = (abi_callbackDATA)(e->cb); // C black magic
   abi_callbackDATA cb = (abi_callbackDATA)(e->cb); // C black magic
Line 82: Line 91:
  abi_event ev;
  abi_event ev;
   
   
  void data_cb(const float * a, const struct bla * b) {
  void data_cb(const float a, const struct bla * b) {
   // do something here
   // do something here
  }
  }
Line 88: Line 97:
In the initialization function (or later) call the binding functions for the message you want to receive.
In the initialization function (or later) call the binding functions for the message you want to receive.


  AbiBindMsgDATA(ev, data_cb);
  AbiBindMsgDATA(&ev, data_cb);


== Airborne code for publisher ==
== Airborne code for publisher ==
Line 100: Line 109:
  float var = 2.;
  float var = 2.;
  struct bla s;
  struct bla s;
  AbiSendMsgDATA(&var,&s);
  AbiSendMsgDATA(var,&s);




That's it !
That's it !
A dev branch of ABI with a test program is in the github repository git://github.com/gautierhattenberger/paparazzi.git, branch abi

Revision as of 11:13, 18 July 2011

This page presents some idea for an embedded middleware named ABI based on publish/subscribe like Ivy.

General idea

  • Give an easy way to allow software components to exchange data with minimum delay nor execution overhead.
  • The components don't need to know each other, they only need the message format.
  • Each subscriber set a callback function that will be called when new data are sent.

Implementation

Message definition

The messages are describe in conf/messages.xml like any other messages in paparazzi. Name are unique, IDs starts from 0. "type" field should be a real C type. Field name might be useless.

<class name="airborne">
 <message name="DATA" id="0">
  <field name="a" type="float"/>
  <field name="b" type="struct bla *"/>
 </message>
 ...
</class>

Code generation

The generated code will be in var/include/abi_messages.h and include some structure definition from sw/airborne/subsystems/abi_common.h. Bind and Send functions are generated, as well as callback type definition. A linked list is used to store the binded callbacks for each message. The head of the list is in an array to allow a fast access.

// Code in abi_common.h
// Here, include header custom structures you may want to use in ABI messages
// Default is to include pprz algebra libraries

typedef void (*abi_callback)(void); // Generic callback definition

struct _abi_event_struct {
 abi_callback cb;
 struct _abi_event_struct * next;
};
typedef struct _abi_event_struct abi_event;

#ifdef ABI_C
#define EXTERN
#else
#define EXTERN extern
#endif

#define ABI_FOREACH(head,el) for(el=head; el; el=el->next)
#define ABI_PREPEND(head,new) { (add)->next = head; head = add; }


// Code generated in var/include/abi_messages.h
#include "subsystems/abi_common.h
// Message IDs
#define DATA_ID 0

// Callbacks
typedef void (*abi_callbackDATA)(const float a, const struct bla * b); // Specific callback for DATA message (arguments are const to prevent modifying them)

// Array and linked list
#define ABI_MESSAGE_NB <highest id of the messages in airborne class + 1>

EXTERN abi_event abi_queues[ABI_MESSAGE_NB]; // Magic trick to avoid generating .c file

// Bind and Send for each messages
static inline void AbiBindMsgDATA(abi_event * ev, abi_callbackDATA cb) {
 ev->cb = (abi_callback)cb; // Store callback
 ABI_PREPEND(abi_queues[DATA_ID],ev); // add to the head of the list (because I'm lazy)
}

static inline void AbiSendMsgDATA(float a, struct bla * b) {
 // Call all callback functions
 abi_event* e;
 ABI_FOREACH(abi_queues[DATA_ID],e) {
  abi_callbackDATA cb = (abi_callbackDATA)(e->cb); // C black magic
  cb(a,b);
 }
}

Airborne code for main AP

This part of the code should be written and called only once in a .c file (like main.c, but it can be somewhere else)

#define ABI_C 1

#include "abi_messages.h"

Airborne code for subscriber

Include header and declare an abi_event as a global variable. Write the callback function with the proper prototype.

#include "abi_messages.h"

abi_event ev;

void data_cb(const float a, const struct bla * b) {
 // do something here
}

In the initialization function (or later) call the binding functions for the message you want to receive.

AbiBindMsgDATA(&ev, data_cb);

Airborne code for publisher

Include header of course.

#include "abi_messages.h"

In any function, call the send function.

float var = 2.;
struct bla s;
AbiSendMsgDATA(var,&s);


That's it !

A dev branch of ABI with a test program is in the github repository git://github.com/gautierhattenberger/paparazzi.git, branch abi