diff --git a/Makefile b/Makefile index cb9eec3f45..1d98d73191 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,7 @@ UBX_PROTOCOL_H=$(STATICINCLUDE)/ubx_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 XSENS_XML = $(CONF)/xsens_MTi-G.xml @@ -108,7 +109,7 @@ misc: multimon: cd $(MULTIMON); $(MAKE) -static_h: $(MESSAGES_H) $(MESSAGES2_H) $(UBX_PROTOCOL_H) $(XSENS_PROTOCOL_H) $(DL_PROTOCOL_H) $(DL_PROTOCOL2_H) +static_h: $(MESSAGES_H) $(MESSAGES2_H) $(UBX_PROTOCOL_H) $(XSENS_PROTOCOL_H) $(DL_PROTOCOL_H) $(DL_PROTOCOL2_H) $(ABI_MESSAGES_H) usb_lib: @[ -d sw/airborne/arch/lpc21/lpcusb ] && ((test -x "$(ARMGCC)" && (cd sw/airborne/arch/lpc21/lpcusb; $(MAKE))) || echo "Not building usb_lib: ARMGCC=$(ARMGCC) not found") || echo "Not building usb_lib: sw/airborne/arch/lpc21/lpcusb directory missing" @@ -147,6 +148,11 @@ $(DL_PROTOCOL2_H) : $(MESSAGES_XML) tools $(Q)PAPARAZZI_SRC=$(PAPARAZZI_SRC) $(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/airframes/ENAC/fixed-wing/funjet3.xml b/conf/airframes/ENAC/fixed-wing/funjet3.xml index f82437175f..764d6e69d7 100644 --- a/conf/airframes/ENAC/fixed-wing/funjet3.xml +++ b/conf/airframes/ENAC/fixed-wing/funjet3.xml @@ -12,7 +12,9 @@ - + + + - + @@ -37,10 +39,8 @@ - - - - + + @@ -56,6 +56,7 @@ + diff --git a/conf/autopilot/setup.makefile b/conf/autopilot/setup.makefile index bd1757dbb9..f633384d9a 100644 --- a/conf/autopilot/setup.makefile +++ b/conf/autopilot/setup.makefile @@ -79,3 +79,8 @@ setup_actuators.CFLAGS += -DDOWNLINK -DDOWNLINK_TRANSPORT=PprzTransport -DDATALI setup_actuators.CFLAGS += -DDOWNLINK_FBW_DEVICE=Uart1 -DDOWNLINK_AP_DEVICE=Uart1 setup_actuators.CFLAGS += $(SETUP_INC) -Ifirmwares/fixedwing setup_actuators.srcs += sys_time.c $(SRC_ARCH)/sys_time_hw.c $(SRC_ARCH)/armVIC.c pprz_transport.c downlink.c $(SRC_FIRMWARE)/setup_actuators.c $(SRC_ARCH)/mcu_periph/uart_arch.c firmwares/fixedwing/main.c mcu.c $(SRC_ARCH)/mcu_arch.c + +# a test program for ABI +test_abi.CFLAGS += -DUSE_LED -DPERIPHERALS_AUTO_INIT +test_abi.srcs += sys_time.c $(SRC_ARCH)/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 f5977aeff4..b0d7770b19 100644 --- a/conf/messages.xml +++ b/conf/messages.xml @@ -2308,24 +2308,29 @@ + + + + + - - + + - - + + - - + + - - + + @@ -2337,8 +2342,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/test/test_abi.c b/sw/airborne/test/test_abi.c new file mode 100644 index 0000000000..74762af7d9 --- /dev/null +++ b/sw/airborne/test/test_abi.c @@ -0,0 +1,87 @@ +/* + * $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" + +#include "subsystems/abi.h" + + +// ABI event and callback for TEST_ABI message +abi_event ev; +void test_cb (const int * value); + +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; +} + + +void test_cb (const int * value) { + 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 ) { + 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 int val = 0; + RunOnceEvery(60,{ AbiSendMsgTEST_ABI(&val); val=(val+1)%3; }); +} + + + +static inline void main_event_task( void ) { + +} diff --git a/sw/tools/Makefile b/sw/tools/Makefile index e0f0b33ccf..3189eca6b7 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_flight_plan.out gen_radio.out gen_periodic.out gen_settings.out gen_tuning.out gen_xsens.out gen_modules.out find_free_msg_id.out +all: gen_common.cmo gen_aircraft.out gen_airframe.out gen_messages2.out gen_messages.out gen_ubx.out gen_flight_plan.out gen_radio.out gen_periodic.out gen_settings.out gen_tuning.out gen_xsens.out gen_modules.out gen_abi.out find_free_msg_id.out 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..e920d0e55e --- /dev/null +++ b/sw/tools/gen_abi.ml @@ -0,0 +1,210 @@ +(* + * $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 general structure and utilities *) + 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 "typedef void (*abi_callback)(void);\n"; + Printf.fprintf h "struct abi_struct {\n"; + Printf.fprintf h " abi_callback cb;\n"; + Printf.fprintf h " struct abi_struct * next;\n"; + Printf.fprintf h "};\n"; + Printf.fprintf h "typedef struct abi_struct abi_event;\n\n"; + Printf.fprintf h "#ifdef ABI_C\n"; + Printf.fprintf h "#define EXTERN\n"; + Printf.fprintf h "#else\n"; + Printf.fprintf h "#define EXTERN extern\n"; + Printf.fprintf h "#endif\n"; + Printf.fprintf h "EXTERN abi_event * abi_queues[ABI_MESSAGE_NB];\n\n"; + Printf.fprintf h "#define ABI_FOREACH(head,el) for(el=head; el; el=el->next)\n"; + Printf.fprintf h "#define ABI_PREPEND(head,add) { (add)->next = head; head = add; }\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"; + + (** 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))