diff --git a/Makefile b/Makefile index ce48b6d127..8492fe0f2c 100644 --- a/Makefile +++ b/Makefile @@ -57,6 +57,7 @@ MTK_PROTOCOL_H=$(STATICINCLUDE)/mtk_protocol.h XSENS_PROTOCOL_H=$(STATICINCLUDE)/xsens_protocol.h DL_PROTOCOL_H=$(STATICINCLUDE)/dl_protocol.h DL_PROTOCOL2_H=$(STATICINCLUDE)/dl_protocol2.h +ABI_MESSAGES_H=$(STATICINCLUDE)/abi_messages.h MESSAGES_XML = $(CONF)/messages.xml UBX_XML = $(CONF)/ubx.xml MTK_XML = $(CONF)/mtk.xml @@ -109,7 +110,7 @@ misc: multimon: cd $(MULTIMON); $(MAKE) -static_h: $(MESSAGES_H) $(MESSAGES2_H) $(UBX_PROTOCOL_H) $(MTK_PROTOCOL_H) $(XSENS_PROTOCOL_H) $(DL_PROTOCOL_H) $(DL_PROTOCOL2_H) +static_h: $(MESSAGES_H) $(MESSAGES2_H) $(UBX_PROTOCOL_H) $(MTK_PROTOCOL_H) $(XSENS_PROTOCOL_H) $(DL_PROTOCOL_H) $(DL_PROTOCOL2_H) $(ABI_MESSAGES_H) usb_lib: @[ -d sw/airborne/arch/lpc21/lpcusb ] && (cd sw/airborne/arch/lpc21/lpcusb; $(MAKE)) || echo "Not building usb_lib: sw/airborne/arch/lpc21/lpcusb directory missing" @@ -156,6 +157,11 @@ $(DL_PROTOCOL2_H) : $(MESSAGES_XML) tools $(Q)PAPARAZZI_SRC=$(PAPARAZZI_SRC) PAPARAZZI_HOME=$(PAPARAZZI_HOME) $(TOOLS)/gen_messages2.out $< datalink > /tmp/dl2.h $(Q)mv /tmp/dl2.h $@ +$(ABI_MESSAGES_H) : $(MESSAGES_XML) tools + @echo BUILD $@ + $(Q)PAPARAZZI_SRC=$(PAPARAZZI_SRC) $(TOOLS)/gen_abi.out $< airborne > /tmp/abi.h + $(Q)mv /tmp/abi.h $@ + include Makefile.ac sim : sim_static diff --git a/conf/firmwares/setup.makefile b/conf/firmwares/setup.makefile index ac28d42f49..cb68bd9572 100644 --- a/conf/firmwares/setup.makefile +++ b/conf/firmwares/setup.makefile @@ -123,3 +123,8 @@ setup_actuators.ARCHDIR = $(ARCH) setup_actuators.CFLAGS += -I$(ARCH) setup_actuators.srcs += $(SRC_ARCH)/led_hw.c endif + +# a test program for ABI +test_abi.CFLAGS += -DUSE_LED -DPERIPHERALS_AUTO_INIT +test_abi.srcs += mcu_periph/sys_time.c $(SRC_ARCH)/mcu_periph/sys_time_hw.c $(SRC_ARCH)/armVIC.c mcu.c $(SRC_ARCH)/mcu_arch.c +test_abi.srcs += test/test_abi.c diff --git a/conf/messages.xml b/conf/messages.xml index a02ef10a2c..df5e5c7e74 100644 --- a/conf/messages.xml +++ b/conf/messages.xml @@ -2426,24 +2426,31 @@ + + + + + + + - - + + - - + + - - + + - - + + @@ -2455,8 +2462,8 @@ - - + + diff --git a/sw/airborne/subsystems/abi.h b/sw/airborne/subsystems/abi.h new file mode 100644 index 0000000000..1e950e4e9f --- /dev/null +++ b/sw/airborne/subsystems/abi.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2011 ENAC - Gautier Hattenberger + * + * This file is part of paparazzi. + * + * paparazzi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * paparazzi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef ABI_H +#define ABI_H + +/* TODO Explain how to use ABI */ + +#include "abi_messages.h" + +#endif /* ABI_H */ diff --git a/sw/airborne/subsystems/abi_common.h b/sw/airborne/subsystems/abi_common.h new file mode 100644 index 0000000000..a1774e31b8 --- /dev/null +++ b/sw/airborne/subsystems/abi_common.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 ENAC - Gautier Hattenberger + * + * This file is part of paparazzi. + * + * paparazzi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * paparazzi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* Common tools for ABI middelware */ + +#ifndef ABI_COMMON_H +#define ABI_COMMON_H + +/* Include pprz math library */ +#include "math/pprz_algebra_int.h" +#include "math/pprz_algebra_float.h" +/* Include here headers with structure definition you may want to use with ABI + * Ex: '#include "subsystems/gps.h"' in order to use the GpsState structure + */ + + +/* Some magic to avoid to compile C code, only headers */ +#ifdef ABI_C +#define EXTERN +#else +#define EXTERN extern +#endif + +/* Generic callback definition */ +typedef void (*abi_callback)(void); + +/* Event structure to store callbacks in a linked list */ +struct abi_struct { + abi_callback cb; + struct abi_struct * next; +}; +typedef struct abi_struct abi_event; + +/* Macros for linked list */ +#define ABI_FOREACH(head,el) for(el=head; el; el=el->next) +#define ABI_PREPEND(head,add) { (add)->next = head; head = add; } + +#endif /* ABI_COMMON_H */ + diff --git a/sw/airborne/test/test_abi.c b/sw/airborne/test/test_abi.c new file mode 100644 index 0000000000..800ba3d7f0 --- /dev/null +++ b/sw/airborne/test/test_abi.c @@ -0,0 +1,92 @@ +/* + * $Id$ + * + * Copyright (C) 2011 Gautier Hattenberger + * + * This file is part of paparazzi. + * + * paparazzi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * paparazzi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#define ABI_C + +#include "mcu.h" +#include "sys_time.h" + +struct abi_boo { + int a; + int b; +}; + +#include "subsystems/abi.h" + +// ABI event and callback for TEST_ABI message +abi_event ev; + +static void test_cb (const int8_t value, const struct abi_boo boo, const struct Int32Vect3 * vect) { + switch (value) { + case 0 : + LED_TOGGLE(1); break; + case 1 : + LED_TOGGLE(2); break; + case 2 : + LED_TOGGLE(3); break; + }; +} + + +static inline void main_init( void ); +static inline void main_periodic_task( void ); +static inline void main_event_task( void ); + + +int main(void) { + main_init(); + + while(1) { + if (sys_time_periodic()) + main_periodic_task(); + main_event_task(); + } + + return 0; +} + + +static inline void main_init( void ) { + mcu_init(); + sys_time_init(); + + mcu_int_enable(); + + // Bind to ABI message + AbiBindMsgTEST_ABI(&ev, test_cb); +} + + + +static inline void main_periodic_task( void ) { + static int8_t val = 0; + struct abi_boo b = { 1, 2 }; + struct Int32Vect3 v = { 3, 4, 5 }; + RunOnceEvery(60,{ AbiSendMsgTEST_ABI(val,b,&v); val=(val+1)%3; }); +} + + + +static inline void main_event_task( void ) { + +} diff --git a/sw/tools/Makefile b/sw/tools/Makefile index 83603a21a7..7c2161b65d 100644 --- a/sw/tools/Makefile +++ b/sw/tools/Makefile @@ -30,7 +30,7 @@ OCAMLNETCMA=$(shell ocamlfind query -r -a-format -predicates byte netstring) OCAMLLEX=ocamllex OCAMLYACC=ocamlyacc -all: gen_common.cmo gen_aircraft.out gen_airframe.out gen_messages2.out gen_messages.out gen_ubx.out gen_mtk.out gen_flight_plan.out gen_radio.out gen_periodic.out gen_settings.out gen_xsens.out gen_modules.out find_free_msg_id.out gen_srtm.out mergelogs +all: gen_common.cmo gen_aircraft.out gen_airframe.out gen_messages2.out gen_messages.out gen_ubx.out gen_mtk.out gen_flight_plan.out gen_radio.out gen_periodic.out gen_settings.out gen_xsens.out gen_modules.out gen_abi.out find_free_msg_id.out gen_srtm.out mergelogs FP_CMO = fp_proc.cmo gen_flight_plan.cmo ABS_FP = $(FP_CMO:%=$$PAPARAZZI_SRC/sw/tools/%) diff --git a/sw/tools/gen_abi.ml b/sw/tools/gen_abi.ml new file mode 100644 index 0000000000..a833bba3c0 --- /dev/null +++ b/sw/tools/gen_abi.ml @@ -0,0 +1,198 @@ +(* + * $Id$ + * + * XML preprocessing of messages.xml for aiborne middleware ABI + * + * Copyright (C) 2011 ENAC, Gautier Hattenberger + * + * This file is part of paparazzi. + * + * paparazzi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * paparazzi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + *) + +open Printf + +type _type = string +type _name = string + +type field = _name * _type + +type fields = field list + +type message = { + name : string; + id : int; + fields : fields + } + +module Syntax = struct + (** Translates a "message" XML element into a value of the 'message' type *) + let struct_of_xml = fun xml -> + let name = ExtXml.attrib xml "name" + and id = ExtXml.int_attrib xml "id" + and fields = + List.map + (fun field -> + let _name = ExtXml.attrib field "name" + and _type = ExtXml.attrib field "type" in + (_name, _type)) + (Xml.children xml) in + { id = id; name = name; fields = fields } + + let check_single_ids = fun msgs -> + let tab = Array.create 256 false (* TODO remove limitation to 256 msg not needed here *) + and last_id = ref 0 in + List.iter (fun msg -> + if tab.(msg.id) then + failwith (sprintf "Duplicated message id: %d" msg.id); + if msg.id < !last_id then + fprintf stderr "Warning: unsorted id: %d\n%!" msg.id; + last_id := msg.id; + tab.(msg.id) <- true) + msgs + + (** Translates one class of a XML message file into a list of messages *) + let read = fun filename class_ -> + let xml = Xml.parse_file filename in + try + let xml_class = ExtXml.child ~select:(fun x -> Xml.attrib x "name" = class_) xml "class" in + let msgs = List.map struct_of_xml (Xml.children xml_class) in + check_single_ids msgs; + msgs + with + Not_found -> failwith (sprintf "No class '%s' found" class_) +end (* module Suntax *) + + +(** Pretty printer *) +module Gen_onboard = struct + (* Print message IDs and return the highest value *) + let print_message_id = fun h messages -> + let highest_id = ref 0 in + Printf.fprintf h "\n/* Messages IDs */\n"; + List.iter (fun msg -> + if msg.id > !highest_id then highest_id := msg.id; + Printf.fprintf h "#define ABI_%s_ID %d\n" (String.capitalize msg.name) msg.id + ) messages; + !highest_id + + (* Print structure array *) + let print_struct = fun h size -> + Printf.fprintf h "\n/* Array and linked list structure */\n"; + Printf.fprintf h "#define ABI_MESSAGE_NB %d\n\n" (size+1); + Printf.fprintf h "EXTERN abi_event* abi_queues[ABI_MESSAGE_NB];\n" + + (* Print arguments' function from fields *) + let print_args = fun h fields -> + let rec args = fun h l -> + match l with + [] -> Printf.fprintf h ")" + | [(n,t)] -> Printf.fprintf h "const %s %s)" t n + | (n,t)::l' -> Printf.fprintf h "const %s %s, " t n; args h l' + in + Printf.fprintf h "("; + args h fields + + (* Print callbacks prototypes for all messages *) + let print_callbacks = fun h messages -> + Printf.fprintf h "\n/* Callbacks */\n"; + List.iter (fun msg -> + Printf.fprintf h "typedef void (*abi_callback%s)" (String.capitalize msg.name); + print_args h msg.fields; + Printf.fprintf h ";\n"; + ) messages + + (* Print a bind function *) + let print_msg_bind = fun h msg -> + let name = String.capitalize msg.name in + Printf.fprintf h "\nstatic inline void AbiBindMsg%s(abi_event * ev, abi_callback%s cb) {\n" name name; + Printf.fprintf h " ev->cb = (abi_callback)cb;\n"; + Printf.fprintf h " ABI_PREPEND(abi_queues[ABI_%s_ID],ev);\n" name; + Printf.fprintf h "}\n" + + (* Print a send function *) + let print_msg_send = fun h msg -> + (* print arguments *) + let rec args = fun h l -> + match l with + [] -> Printf.fprintf h ");\n" + | [(n,_)] -> Printf.fprintf h "%s);\n" n + | (n,_)::l' -> Printf.fprintf h "%s, " n; args h l' + in + let name = String.capitalize msg.name in + Printf.fprintf h "\nstatic inline void AbiSendMsg%s" name; + print_args h msg.fields; + Printf.fprintf h " {\n"; + Printf.fprintf h " abi_event* e;\n"; + Printf.fprintf h " ABI_FOREACH(abi_queues[ABI_%s_ID],e) {\n" name; + Printf.fprintf h " abi_callback%s cb = (abi_callback%s)(e->cb);\n" name name; + Printf.fprintf h " cb("; + args h msg.fields; + Printf.fprintf h " };\n"; + Printf.fprintf h "};\n" + + (* Print bind and send functions for all messages *) + let print_bind_send = fun h messages -> + Printf.fprintf h "\n/* Bind and Send functions */\n"; + List.iter (fun msg -> + print_msg_bind h msg; + print_msg_send h msg + ) messages + +end (* module Gen_onboard *) + + +(********************* Main **************************************************) +let () = + if Array.length Sys.argv <> 3 then begin + failwith (sprintf "Usage: %s <.xml file> " Sys.argv.(0)) + end; + + let filename = Sys.argv.(1) + and class_name = Sys.argv.(2) in + + try + let h = stdout in + + (** Read and store messages *) + let messages = Syntax.read filename class_name in + + (** Print file header *) + Printf.fprintf h "/* Automatically generated from %s */\n" filename; + Printf.fprintf h "/* Please DO NOT EDIT */\n\n"; + Printf.fprintf h "/* Onboard middleware library ABI\n"; + Printf.fprintf h " * send and receive messages of class %s\n" class_name; + Printf.fprintf h " */\n\n"; + Printf.fprintf h "#ifndef ABI_MESSAGES_H\n"; + Printf.fprintf h "#define ABI_MESSAGES_H\n\n"; + Printf.fprintf h "#include \"subsystems/abi_common.h\"\n"; + + (** Print Messages IDs *) + let highest_id = Gen_onboard.print_message_id h messages in + + (** Print general structure definition *) + Gen_onboard.print_struct h highest_id; + + (** Print Messages callbacks definition *) + Gen_onboard.print_callbacks h messages; + + (** Print Bind and Send functions for all messages *) + Gen_onboard.print_bind_send h messages; + + Printf.fprintf h "\n#endif // ABI_MESSAGES_H\n" + with + Xml.Error (msg, pos) -> failwith (sprintf "%s:%d : %s\n" filename (Xml.line pos) (Xml.error_msg msg))