summaryrefslogtreecommitdiff
path: root/ucoo
diff options
context:
space:
mode:
Diffstat (limited to 'ucoo')
-rw-r--r--ucoo/arch/Module1
-rw-r--r--ucoo/arch/arch.hh47
-rw-r--r--ucoo/arch/arch.host.cc83
-rw-r--r--ucoo/arch/arch.stm32.cc57
-rw-r--r--ucoo/arch/arch_common.arm.hh59
-rw-r--r--ucoo/arch/arch_common.hh43
-rw-r--r--ucoo/arch/arch_common.host.hh47
-rw-r--r--ucoo/arch/host/Module2
-rw-r--r--ucoo/arch/host/host.hh81
-rw-r--r--ucoo/arch/host/host.host.cc181
-rw-r--r--ucoo/arch/host/host_stream.hh54
-rw-r--r--ucoo/arch/host/host_stream.host.cc146
-rw-r--r--ucoo/arch/host/mex/Config2
-rw-r--r--ucoo/arch/host/mex/Module2
-rw-r--r--ucoo/arch/host/mex/mex.hh56
-rw-r--r--ucoo/arch/host/mex/mex_msg.hh148
-rw-r--r--ucoo/arch/host/mex/mex_msg.host.cc290
-rw-r--r--ucoo/arch/host/mex/mex_node.hh104
-rw-r--r--ucoo/arch/host/mex/mex_node.host.cc174
-rw-r--r--ucoo/arch/host/mex/mex_socket.hh59
-rw-r--r--ucoo/arch/host/mex/mex_socket.host.cc95
-rw-r--r--ucoo/arch/host/mex/socket.h39
-rw-r--r--ucoo/arch/host/mex/socket.host.c88
-rw-r--r--ucoo/arch/host/mex/test/Makefile9
-rw-r--r--ucoo/arch/host/mex/test/hub.py6
-rw-r--r--ucoo/arch/host/mex/test/test_mex.cc245
-rw-r--r--ucoo/arch/host/test/Makefile9
-rw-r--r--ucoo/arch/host/test/test_host.cc49
-rw-r--r--ucoo/arch/stm32f4/stm32f4.ld6
-rw-r--r--ucoo/arch/syscalls.cc36
-rw-r--r--ucoo/arch/syscalls.newlib.cc179
-rw-r--r--ucoo/arch/syscalls.newlib.hh35
-rw-r--r--ucoo/base/proto/Config2
-rw-r--r--ucoo/base/proto/Module1
-rw-r--r--ucoo/base/proto/proto.cc257
-rw-r--r--ucoo/base/proto/proto.hh99
-rw-r--r--ucoo/base/proto/test/Makefile9
-rw-r--r--ucoo/base/proto/test/test_proto.cc67
-rw-r--r--ucoo/base/stdio/Module1
-rw-r--r--ucoo/base/stdio/stdio.cc68
-rw-r--r--ucoo/base/stdio/stdio.hh39
-rw-r--r--ucoo/base/test/Config5
-rw-r--r--ucoo/base/test/Module1
-rw-r--r--ucoo/base/test/test.cc118
-rw-r--r--ucoo/base/test/test.hh99
-rw-r--r--ucoo/base/test/test.host.cc42
-rw-r--r--ucoo/base/test/test.stm32.cc48
-rw-r--r--ucoo/base/test/test/Makefile9
-rw-r--r--ucoo/base/test/test/test_test.cc48
-rw-r--r--ucoo/common.hh91
-rw-r--r--ucoo/dev/avrisp/Config6
-rw-r--r--ucoo/dev/avrisp/Module1
-rw-r--r--ucoo/dev/avrisp/avrisp.cc452
-rw-r--r--ucoo/dev/avrisp/avrisp.hh247
-rw-r--r--ucoo/dev/avrisp/avrisp_frame.cc173
-rw-r--r--ucoo/dev/avrisp/avrisp_frame.hh95
-rw-r--r--ucoo/dev/avrisp/avrisp_proto.cc269
-rw-r--r--ucoo/dev/avrisp/avrisp_proto.hh50
-rw-r--r--ucoo/dev/avrisp/test/Makefile9
-rw-r--r--ucoo/dev/avrisp/test/test_avrisp.cc89
-rw-r--r--ucoo/dev/usdist/Module1
-rw-r--r--ucoo/dev/usdist/usdist.cc103
-rw-r--r--ucoo/dev/usdist/usdist.hh80
-rw-r--r--ucoo/dev/xmodem/Module1
-rw-r--r--ucoo/dev/xmodem/xmodem.cc164
-rw-r--r--ucoo/dev/xmodem/xmodem.hh46
-rw-r--r--ucoo/hal/adc/Module1
-rw-r--r--ucoo/hal/adc/adc.hh35
-rw-r--r--ucoo/hal/adc/adc.host.cc92
-rw-r--r--ucoo/hal/adc/adc.host.hh52
-rw-r--r--ucoo/hal/adc/adc_hard.stm32f4.cc69
-rw-r--r--ucoo/hal/adc/adc_hard.stm32f4.hh73
-rw-r--r--ucoo/hal/adc/test/Makefile9
-rw-r--r--ucoo/hal/adc/test/test_adc.cc51
-rw-r--r--ucoo/hal/gpio/Module1
-rw-r--r--ucoo/hal/gpio/gpio.hh35
-rw-r--r--ucoo/hal/gpio/gpio.host.cc181
-rw-r--r--ucoo/hal/gpio/gpio.host.hh69
-rw-r--r--ucoo/hal/gpio/gpio.stm32f4.cc105
-rw-r--r--ucoo/hal/gpio/gpio.stm32f4.hh85
-rw-r--r--ucoo/hal/gpio/test/Makefile9
-rw-r--r--ucoo/hal/gpio/test/test_gpio.cc71
-rw-r--r--ucoo/hal/i2c/Config5
-rw-r--r--ucoo/hal/i2c/Module1
-rw-r--r--ucoo/hal/i2c/i2c.hh36
-rw-r--r--ucoo/hal/i2c/i2c.host.cc213
-rw-r--r--ucoo/hal/i2c/i2c.host.hh66
-rw-r--r--ucoo/hal/i2c/i2c_hard.stm32.cc396
-rw-r--r--ucoo/hal/i2c/i2c_hard.stm32.hh91
-rw-r--r--ucoo/hal/i2c/i2c_slave_data_buffer.cc80
-rw-r--r--ucoo/hal/i2c/i2c_slave_data_buffer.hh71
-rw-r--r--ucoo/hal/i2c/test/Makefile9
-rw-r--r--ucoo/hal/i2c/test/hub.py6
-rw-r--r--ucoo/hal/i2c/test/test_i2c.cc226
-rw-r--r--ucoo/hal/spi/Module1
-rw-r--r--ucoo/hal/spi/spi_soft.cc125
-rw-r--r--ucoo/hal/spi/spi_soft.hh64
-rw-r--r--ucoo/hal/spi/test/Makefile9
-rw-r--r--ucoo/hal/spi/test/test_spi.cc112
-rw-r--r--ucoo/hal/uart/Config6
-rw-r--r--ucoo/hal/uart/Module1
-rw-r--r--ucoo/hal/uart/test/Config4
-rw-r--r--ucoo/hal/uart/test/Makefile12
-rw-r--r--ucoo/hal/uart/test/test_uart.cc70
-rw-r--r--ucoo/hal/uart/test/test_uart_disc.cc128
-rw-r--r--ucoo/hal/uart/uart.hh36
-rw-r--r--ucoo/hal/uart/uart.stm32.cc221
-rw-r--r--ucoo/hal/uart/uart.stm32.hh78
-rw-r--r--ucoo/hal/usb/Config12
-rw-r--r--ucoo/hal/usb/Module1
-rw-r--r--ucoo/hal/usb/test/Config2
-rw-r--r--ucoo/hal/usb/test/Makefile9
-rw-r--r--ucoo/hal/usb/test/test_usb.cc73
-rw-r--r--ucoo/hal/usb/usb.hh33
-rw-r--r--ucoo/hal/usb/usb.stm32.cc160
-rw-r--r--ucoo/hal/usb/usb.stm32.hh98
-rw-r--r--ucoo/hal/usb/usb_desc.stm32.c193
-rw-r--r--ucoo/hal/usb/usb_desc.stm32.h33
-rw-r--r--ucoo/intf/Module1
-rw-r--r--ucoo/intf/adc.hh45
-rw-r--r--ucoo/intf/i2c.hh124
-rw-r--r--ucoo/intf/io.hh54
-rw-r--r--ucoo/intf/spi_master.cc48
-rw-r--r--ucoo/intf/spi_master.hh70
-rw-r--r--ucoo/intf/stream.cc63
-rw-r--r--ucoo/intf/stream.hh65
-rw-r--r--ucoo/utils/Module1
-rw-r--r--ucoo/utils/bytes.hh52
-rw-r--r--ucoo/utils/crc.cc102
-rw-r--r--ucoo/utils/crc.hh70
-rw-r--r--ucoo/utils/delay.arm.cc76
-rw-r--r--ucoo/utils/delay.arm.hh52
-rw-r--r--ucoo/utils/delay.hh76
-rw-r--r--ucoo/utils/dtrace.py40
-rw-r--r--ucoo/utils/fifo.hh76
-rw-r--r--ucoo/utils/fifo.tcc108
-rw-r--r--ucoo/utils/test/Makefile12
-rw-r--r--ucoo/utils/test/test_crc.cc49
-rw-r--r--ucoo/utils/test/test_delay.cc64
-rw-r--r--ucoo/utils/test/test_fifo.cc78
-rw-r--r--ucoo/utils/trace.hh133
141 files changed, 10300 insertions, 0 deletions
diff --git a/ucoo/arch/Module b/ucoo/arch/Module
new file mode 100644
index 0000000..6c23a20
--- /dev/null
+++ b/ucoo/arch/Module
@@ -0,0 +1 @@
+arch_SOURCES := arch.host.cc arch.stm32.cc syscalls.newlib.cc syscalls.cc
diff --git a/ucoo/arch/arch.hh b/ucoo/arch/arch.hh
new file mode 100644
index 0000000..e0889bd
--- /dev/null
+++ b/ucoo/arch/arch.hh
@@ -0,0 +1,47 @@
+#ifndef ucoo_arch_arch_hh
+#define ucoo_arch_arch_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+/// Initialise arch, take program arguments.
+void
+arch_init (int argc, const char **argv);
+
+/// Reset.
+void
+arch_reset ();
+
+#ifdef TARGET_host
+
+/// Retrieve program arguments.
+void
+arch_get_args (int &argc, const char **&argv);
+
+#endif
+
+} // namespace ucoo
+
+#endif // ucoo_arch_arch_hh
diff --git a/ucoo/arch/arch.host.cc b/ucoo/arch/arch.host.cc
new file mode 100644
index 0000000..1ddd6a9
--- /dev/null
+++ b/ucoo/arch/arch.host.cc
@@ -0,0 +1,83 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/arch/arch.hh"
+#include "ucoo/common.hh"
+
+#include <cstdlib>
+#include <cstdio>
+#include <time.h>
+#include <errno.h>
+
+namespace ucoo {
+
+static int arch_stored_argc;
+static const char **arch_stored_argv;
+
+void
+arch_init (int argc, const char **argv)
+{
+ arch_stored_argc = argc;
+ arch_stored_argv = argv;
+}
+
+void
+arch_reset ()
+{
+ // Not supported.
+ halt ();
+}
+
+void
+arch_get_args (int &argc, const char **&argv)
+{
+ argc = arch_stored_argc;
+ argv = arch_stored_argv;
+}
+
+void
+halt ()
+{
+ fprintf (stderr, "halt\n");
+ abort ();
+}
+
+void
+halt_perror ()
+{
+ perror ("halt");
+ abort ();
+}
+
+void
+yield ()
+{
+ // Do a small delay.
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 100 * 1000 * 1000;
+ while (nanosleep (&ts, &ts) == -1 && errno == EINTR)
+ ;
+}
+
+} // namespace ucoo
diff --git a/ucoo/arch/arch.stm32.cc b/ucoo/arch/arch.stm32.cc
new file mode 100644
index 0000000..649091d
--- /dev/null
+++ b/ucoo/arch/arch.stm32.cc
@@ -0,0 +1,57 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/arch/arch.hh"
+#include "ucoo/common.hh"
+
+#include <libopencm3/stm32/f4/rcc.h>
+#include <libopencm3/cm3/scb.h>
+
+namespace ucoo {
+
+void
+arch_init (int argc, const char **argv)
+{
+ rcc_clock_setup_hse_3v3 (&hse_8mhz_3v3[CLOCK_3V3_120MHZ]);
+}
+
+void
+arch_reset ()
+{
+ SCB_AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_SYSRESETREQ;
+}
+
+void
+halt ()
+{
+ while (1)
+ ;
+}
+
+void
+halt_perror ()
+{
+ halt ();
+}
+
+} // namespace ucoo
diff --git a/ucoo/arch/arch_common.arm.hh b/ucoo/arch/arch_common.arm.hh
new file mode 100644
index 0000000..7b4abfd
--- /dev/null
+++ b/ucoo/arch/arch_common.arm.hh
@@ -0,0 +1,59 @@
+#ifndef ucoo_arch_arch_common_arm_hh
+#define ucoo_arch_arch_common_arm_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+/// Type used to save irq state.
+typedef unsigned int irq_flags_t;
+
+static inline irq_flags_t
+irq_lock (void)
+{
+ irq_flags_t flags;
+ __asm__ __volatile__ ("mrs %0, PRIMASK\n\t"
+ "cpsid i"
+ : "=r" (flags) :
+ : "memory", "cc");
+ return flags;
+}
+
+inline void
+irq_restore (irq_flags_t flags)
+{
+ __asm__ __volatile__ ("msr PRIMASK, %0"
+ : : "r" (flags)
+ : "memory", "cc");
+}
+
+inline void
+yield ()
+{
+ // Nothing, the CPU is ours!
+}
+
+} // namespace ucoo
+
+#endif // ucoo_arch_arch_common_arm_hh
diff --git a/ucoo/arch/arch_common.hh b/ucoo/arch/arch_common.hh
new file mode 100644
index 0000000..ac70e62
--- /dev/null
+++ b/ucoo/arch/arch_common.hh
@@ -0,0 +1,43 @@
+#ifndef ucoo_arch_arch_common_hh
+#define ucoo_arch_arch_common_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+#if defined (TARGET_arm)
+# include "arch_common.arm.hh"
+#elif defined (TARGET_host)
+# include "arch_common.host.hh"
+#else
+# error "not implemented for this target"
+#endif
+
+namespace ucoo {
+
+/// Give some time to other tasks when running in a tight loop.
+void
+yield ();
+
+} // namespace ucoo
+
+#endif // ucoo_arch_arch_common_hh
diff --git a/ucoo/arch/arch_common.host.hh b/ucoo/arch/arch_common.host.hh
new file mode 100644
index 0000000..0ee2553
--- /dev/null
+++ b/ucoo/arch/arch_common.host.hh
@@ -0,0 +1,47 @@
+#ifndef ucoo_arch_arch_common_host_hh
+#define ucoo_arch_arch_common_host_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+/// Type used to save irq state.
+typedef unsigned int irq_flags_t;
+
+static inline irq_flags_t
+irq_lock (void)
+{
+ // Nothing on host, there is no interrupts.
+ return 0;
+}
+
+inline void
+irq_restore (irq_flags_t)
+{
+ // Nothing on host, there is no interrupts.
+}
+
+} // namespace ucoo
+
+#endif // ucoo_arch_arch_common_host_hh
diff --git a/ucoo/arch/host/Module b/ucoo/arch/host/Module
new file mode 100644
index 0000000..2c7fead
--- /dev/null
+++ b/ucoo/arch/host/Module
@@ -0,0 +1,2 @@
+arch_host_SOURCES := host.host.cc host_stream.host.cc
+host_LIBS += -lutil
diff --git a/ucoo/arch/host/host.hh b/ucoo/arch/host/host.hh
new file mode 100644
index 0000000..f1307fa
--- /dev/null
+++ b/ucoo/arch/host/host.hh
@@ -0,0 +1,81 @@
+#ifndef ucoo_arch_host_host_hh
+#define ucoo_arch_host_host_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/arch/host/mex/mex_node.hh"
+
+#include <string>
+#include <list>
+#include <memory>
+
+namespace ucoo {
+
+/// Host support class.
+class Host
+{
+ public:
+ /// Constructor, with default instance name.
+ Host (const std::string &default_instance_name);
+ /// Get instance name, strip a number of tail components if requested.
+ std::string get_instance (int strip = 0) const;
+ /// Get Mex node. Connect if not done yet.
+ mex::Node &get_node ();
+ /// Declare a command line option without value.
+ void add_option (char opt, const char *help);
+ /// Declare a command line option with value.
+ void add_option (char opt, const char *metavar, const char *help,
+ const std::string &default_value);
+ /// Test if option was set.
+ bool is_option_set (char opt) const;
+ /// Get value for option.
+ const std::string &get_option (char opt) const;
+ /// To be done once, parse options.
+ void parse_options ();
+ private:
+ /// Display usage message and exit.
+ void usage (int ret);
+ private:
+ /// Instance name, from default or from command line.
+ std::string instance_name_;
+ /// Mex node, or 0 if not connected yet.
+ std::auto_ptr<mex::Node> node_;
+ /// Store options definitions and values.
+ struct Option
+ {
+ const char *metavar;
+ const char *help;
+ bool set;
+ std::string value;
+ };
+ typedef std::map<char, Option> Options;
+ Options options_;
+ /// Program name, used for messages.
+ const char *program_name_;
+ /// Option parsing is done.
+ bool option_parsed_;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_arch_host_host_hh
diff --git a/ucoo/arch/host/host.host.cc b/ucoo/arch/host/host.host.cc
new file mode 100644
index 0000000..9ccc0d1
--- /dev/null
+++ b/ucoo/arch/host/host.host.cc
@@ -0,0 +1,181 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "host.hh"
+
+#include "ucoo/arch/arch.hh"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <algorithm>
+#include <unistd.h>
+
+namespace ucoo {
+
+Host::Host (const std::string &default_instance_name)
+ : program_name_ ("program"), option_parsed_ (false)
+{
+ add_option ('i', "NAME", "instance name", default_instance_name);
+ add_option ('h', "display this help message");
+}
+
+std::string
+Host::get_instance (int strip) const
+{
+ assert (strip >= 0);
+ std::string instance = get_option ('i');
+ if (strip)
+ {
+ std::string::size_type end = std::string::npos;
+ do
+ {
+ end = instance.rfind (':', end - 1);
+ if (end == std::string::npos)
+ end = 0;
+ } while (end != 0 && --strip);
+ instance.erase (end);
+ }
+ return instance;
+}
+
+mex::Node &
+Host::get_node ()
+{
+ if (!node_.get ())
+ node_.reset (new mex::Node);
+ return *node_;
+}
+
+void
+Host::add_option (char opt, const char *help)
+{
+ Option o;
+ o.metavar = 0;
+ o.help = help;
+ o.set = false;
+ if (!options_.insert (Options::value_type (opt, o)).second)
+ assert_unreachable ();
+}
+
+void
+Host::add_option (char opt, const char *metavar, const char *help,
+ const std::string &default_value)
+{
+ Option o;
+ o.metavar = metavar;
+ o.help = help;
+ o.set = false;
+ o.value = default_value;
+ if (!options_.insert (Options::value_type (opt, o)).second)
+ assert_unreachable ();
+}
+
+bool
+Host::is_option_set (char opt) const
+{
+ assert (option_parsed_);
+ Options::const_iterator i = options_.find (opt);
+ assert (i != options_.end ());
+ return i->second.set;
+}
+
+const std::string &
+Host::get_option (char opt) const
+{
+ assert (option_parsed_);
+ Options::const_iterator i = options_.find (opt);
+ assert (i != options_.end ());
+ return i->second.value;
+}
+
+void
+Host::parse_options ()
+{
+ // Get program arguments.
+ int argc;
+ const char **argv;
+ arch_get_args (argc, argv);
+ // Save program name.
+ const char *slash = std::strrchr (argv[0], '/');
+ program_name_ = slash ? slash + 1 : argv[0];
+ // Parse.
+ std::string getoptdesc;
+ for (Options::const_iterator i = options_.begin ();
+ i != options_.end (); ++i)
+ {
+ getoptdesc.push_back (i->first);
+ if (i->second.metavar)
+ getoptdesc.push_back (':');
+ }
+ int c;
+ const char *getoptdescs = getoptdesc.c_str ();
+ char **getopt_argv = const_cast<char **> (argv);
+ while ((c = getopt (argc, getopt_argv, getoptdescs)) != -1)
+ {
+ if (c == '?')
+ usage (1);
+ else
+ {
+ Options::iterator i = options_.find (c);
+ assert (i != options_.end ());
+ i->second.set = true;
+ if (i->second.metavar)
+ i->second.value = optarg;
+ }
+ }
+ if (optind != argc)
+ {
+ fprintf (stderr, "%s: too many arguments\n", argv[0]);
+ usage (1);
+ }
+ option_parsed_ = true;
+ if (is_option_set ('h'))
+ usage (0);
+}
+
+void
+Host::usage (int ret)
+{
+ FILE *out = ret == 0 ? stdout : stderr;
+ fprintf (out, "Usage: %s [options...]\n\nOptions:\n", program_name_);
+ size_t max_meta = 0;
+ for (Options::const_iterator i = options_.begin ();
+ i != options_.end (); ++i)
+ {
+ if (i->second.metavar)
+ max_meta = std::max (max_meta,
+ std::strlen (i->second.metavar) + 1);
+ }
+ for (Options::const_iterator i = options_.begin ();
+ i != options_.end (); ++i)
+ {
+ const Option &o = i->second;
+ fprintf (out, " -%c %-*s %s\n", i->first,
+ static_cast<int> (max_meta),
+ o.metavar ? o.metavar : "", o.help);
+ }
+ exit (ret);
+}
+
+} // namespace ucoo
diff --git a/ucoo/arch/host/host_stream.hh b/ucoo/arch/host/host_stream.hh
new file mode 100644
index 0000000..4aebdbf
--- /dev/null
+++ b/ucoo/arch/host/host_stream.hh
@@ -0,0 +1,54 @@
+#ifndef ucoo_arch_host_stream_hh
+#define ucoo_arch_host_stream_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/stream.hh"
+
+namespace ucoo {
+
+class HostStream : public Stream
+{
+ public:
+ /// Default constructor, use stdin/stdout.
+ HostStream ();
+ /// PTY constructor, will make a link to PTY at the given name.
+ HostStream (const char *name);
+ /// Close if needed.
+ ~HostStream ();
+ /// See Stream::block.
+ void block (bool block = true);
+ /// See Stream::read.
+ int read (char *buf, int count);
+ /// See Stream::write.
+ int write (const char *buf, int count);
+ /// See Stream::poll.
+ int poll ();
+ private:
+ /// Input and output file descriptors.
+ int fdi_, fdo_;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_arch_host_stream_hh
diff --git a/ucoo/arch/host/host_stream.host.cc b/ucoo/arch/host/host_stream.host.cc
new file mode 100644
index 0000000..d971862
--- /dev/null
+++ b/ucoo/arch/host/host_stream.host.cc
@@ -0,0 +1,146 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "host_stream.hh"
+
+#include "ucoo/common.hh"
+
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <pty.h>
+#include <fcntl.h>
+#include <errno.h>
+
+namespace ucoo {
+
+/// Setup non canonical mode.
+static void
+setup_raw (int fd)
+{
+ struct termios tc;
+ tcgetattr (fd, &tc);
+ tc.c_iflag &= ~(IGNPAR | PARMRK | ISTRIP | IGNBRK | BRKINT | IGNCR |
+ ICRNL | INLCR | IXON | IXOFF | IXANY | IMAXBEL);
+ tc.c_iflag |= INPCK;
+ tc.c_oflag &= ~(OPOST);
+ tc.c_cflag &= ~(HUPCL | CSTOPB | PARENB | PARODD | CSIZE);
+ tc.c_cflag |= CS8 | CLOCAL | CREAD;
+ tc.c_lflag &= ~(ICANON | ECHO | ISIG | IEXTEN | NOFLSH | TOSTOP);
+ tc.c_cc[VTIME] = 0;
+ tc.c_cc[VMIN] = 1;
+ tcflush (fd, TCIFLUSH);
+ tcsetattr (fd, TCSANOW, &tc);
+}
+
+HostStream::HostStream ()
+ : fdi_ (0), fdo_ (1)
+{
+}
+
+HostStream::HostStream (const char *name)
+ : fdi_ (-1), fdo_ (-1)
+{
+ int fd, slave_fd, r;
+ // Open and unlock pt.
+ if (openpty (&fd, &slave_fd, 0, 0, 0) == -1
+ || grantpt (fd) == -1
+ || unlockpt (fd) == -1)
+ halt_perror ();
+ // Make a link to the slave pts.
+ unlink (name);
+ const char *slave_name = ptsname (fd);
+ assert (slave_name);
+ r = symlink (slave_name, name);
+ assert_perror (r != -1);
+ // Make slave raw.
+ setup_raw (slave_fd);
+ // Use as both in and out.
+ fdi_ = fdo_ = fd;
+ // slave_fd is left open.
+}
+
+HostStream::~HostStream ()
+{
+ if (fdi_ != -1 && fdi_ != 0)
+ close (fdi_);
+ if (fdo_ != -1 && fdo_ != 1 && fdo_ != fdi_)
+ close (fdo_);
+}
+
+void
+HostStream::block (bool block)
+{
+ Stream::block (block);
+ // Do not care to use non blocking on output for host. However, if
+ // fdi_ == fdo_, this will change input and output.
+ int r = fcntl (fdi_, F_SETFL, block ? 0 : O_NONBLOCK);
+ assert_perror (r != -1);
+}
+
+int
+HostStream::read (char *buf, int count)
+{
+ int r = ::read (fdi_, buf, count);
+ if (r == 0)
+ return -2;
+ if (r == -1 && errno == EAGAIN)
+ return 0;
+ assert_perror (r != -1);
+ return r;
+}
+
+int
+HostStream::write (const char *buf, int count)
+{
+ int writen = 0;
+ while (writen < count)
+ {
+ int r = ::write (fdo_, buf + writen, count - writen);
+ if (r == -1 && errno == EAGAIN)
+ break;
+ assert_perror (r != -1);
+ writen += r;
+ }
+ return writen;
+}
+
+int
+HostStream::poll ()
+{
+ fd_set fds;
+ struct timeval tv;
+ int r;
+ // Use select to poll.
+ FD_ZERO (&fds);
+ FD_SET (fdi_, &fds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ r = select (FD_SETSIZE, &fds, 0, 0, &tv);
+ // Check result.
+ assert_perror (r != -1);
+ return r;
+}
+
+} // namespace ucoo
diff --git a/ucoo/arch/host/mex/Config b/ucoo/arch/host/mex/Config
new file mode 100644
index 0000000..de679f0
--- /dev/null
+++ b/ucoo/arch/host/mex/Config
@@ -0,0 +1,2 @@
+[arch/host/mex]
+default_address = "localhost", "2442"
diff --git a/ucoo/arch/host/mex/Module b/ucoo/arch/host/mex/Module
new file mode 100644
index 0000000..941482b
--- /dev/null
+++ b/ucoo/arch/host/mex/Module
@@ -0,0 +1,2 @@
+arch_host_mex_SOURCES := mex_msg.host.cc mex_node.host.cc mex_socket.host.cc \
+ socket.host.c
diff --git a/ucoo/arch/host/mex/mex.hh b/ucoo/arch/host/mex/mex.hh
new file mode 100644
index 0000000..9e6ca09
--- /dev/null
+++ b/ucoo/arch/host/mex/mex.hh
@@ -0,0 +1,56 @@
+#ifndef ucoo_arch_host_mex_mex_hh
+#define ucoo_arch_host_mex_mex_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+namespace mex {
+
+/// Message type identifiers.
+enum mtype_t
+{
+ /// IDLE message, sent by nodes to the hub to signal it had handled all
+ /// messages. It can have an optional parameter: the date at which the
+ /// node will not be idle anymore.
+ MTYPE_IDLE = 0,
+ /// DATE message, sent by the hub to the nodes to update the current date
+ /// value, sent by a node to request the current date (useful at startup).
+ MTYPE_DATE = 1,
+ /// REQ (request) message, sent from a node to other nodes to request a
+ /// response message.
+ MTYPE_REQ = 2,
+ /// RSP (response) message, response to a REQ message, only sent to the
+ /// requesting node.
+ MTYPE_RSP = 3,
+ /// RES (reserve) message, sent to the hub to request a message type, sent
+ /// to a node with the allocated message type.
+ MTYPE_RES = 4,
+ /// First unreserved message identifier, to be used by user messages.
+ MTYPE_USER_MIN = 0x20,
+};
+
+} // namespace mex
+} // namespace ucoo
+
+#endif // ucoo_arch_host_mex_mex_hh
diff --git a/ucoo/arch/host/mex/mex_msg.hh b/ucoo/arch/host/mex/mex_msg.hh
new file mode 100644
index 0000000..6aca09d
--- /dev/null
+++ b/ucoo/arch/host/mex/mex_msg.hh
@@ -0,0 +1,148 @@
+#ifndef ucoo_arch_host_mex_mex_msg_hh
+#define ucoo_arch_host_mex_mex_msg_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/common.hh"
+
+#include "ucoo/arch/host/mex/mex.hh"
+
+#include <vector>
+
+namespace ucoo {
+namespace mex {
+
+class MsgPusher;
+class MsgPoper;
+class MsgReader;
+class MsgWriter;
+
+/// Mex message.
+///
+/// Format used for payload push and pop:
+/// - b: 8 bits.
+/// - h: 16 bits.
+/// - l: 32 bits.
+/// Uppercase is used for unsigned.
+class Msg
+{
+ public:
+ /// New message with the given MTYPE.
+ explicit Msg (mtype_t mtype);
+ /// Read a new message.
+ explicit Msg (MsgReader &reader);
+ /// Write a message.
+ void write (MsgWriter &writer);
+ /// Add data to the message payload. FMT string describes the provided
+ /// data. Return a pusher which will do the actual push, using the
+ /// operator<<.
+ MsgPusher push (const char *fmt);
+ /// Add data to the message payload from a buffer.
+ void push (const char *buffer, int size);
+ /// Extract data from the message payload. FMT string describes the
+ /// requested data. Return a poper which will do the actual pop, using
+ /// the operator>>.
+ MsgPoper pop (const char *fmt);
+ /// Pop buffer of given size. Data is kept valid as long as this object
+ /// is alive.
+ const char *pop (int size);
+ /// Encapsulate a message in another one, adding header data. Return a
+ /// pusher which will do the actual header data push, using the
+ /// operator<<.
+ MsgPusher encapsulate (mtype_t mtype, const char *fmt);
+ /// Decapsulate a message from payload. The current payload becomes the
+ /// full message.
+ void decapsulate ();
+ /// Get remaining length.
+ int len () const;
+ /// Get message type.
+ mtype_t mtype () const { return mtype_; }
+ private:
+ /// Message payload, not including message type.
+ std::vector<char> payload_;
+ /// Unused space at head of payload.
+ int head_skip_;
+ /// Message type.
+ mtype_t mtype_;
+};
+
+/// Helper used to push data to message.
+class MsgPusher
+{
+ public:
+ /// Push an integer.
+ MsgPusher &operator<< (int32_t v);
+ /// Push an unsigned integer, used when an int is not enough.
+ MsgPusher &operator<< (uint32_t v);
+ private:
+ MsgPusher (std::vector<char>::iterator out, const char *fmt);
+ void push (int64_t v);
+ private:
+ friend class Msg;
+ std::vector<char>::iterator out_;
+ const char *fmt_;
+};
+
+/// Helper used to pop data from message.
+class MsgPoper
+{
+ public:
+ /// Pop for each supported types.
+ MsgPoper &operator>> (int32_t &v);
+ MsgPoper &operator>> (uint32_t &v);
+ MsgPoper &operator>> (int16_t &v);
+ MsgPoper &operator>> (uint16_t &v);
+ MsgPoper &operator>> (int8_t &v);
+ MsgPoper &operator>> (uint8_t &v);
+ private:
+ MsgPoper (std::vector<char>::const_iterator in, const char *fmt);
+ uint32_t pop_bytes (int bytes);
+ int64_t pop (int bits, bool sign);
+ private:
+ friend class Msg;
+ std::vector<char>::const_iterator in_;
+ const char *fmt_;
+};
+
+/// Abstract Msg reader.
+class MsgReader
+{
+ public:
+ /// Get message size.
+ virtual int size () = 0;
+ /// Read message bytes to provided buffer.
+ virtual void read (char *buf) = 0;
+};
+
+/// Abstract Msg writer.
+class MsgWriter
+{
+ public:
+ /// Write COUNT bytes from provided buffer.
+ virtual void write (const char *buf, int count) = 0;
+};
+
+} // namespace mex
+} // namespace ucoo
+
+#endif // ucoo_arch_host_mex_mex_msg_hh
diff --git a/ucoo/arch/host/mex/mex_msg.host.cc b/ucoo/arch/host/mex/mex_msg.host.cc
new file mode 100644
index 0000000..5876e22
--- /dev/null
+++ b/ucoo/arch/host/mex/mex_msg.host.cc
@@ -0,0 +1,290 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#define __STDC_LIMIT_MACROS 1
+#include "mex_msg.hh"
+
+namespace ucoo {
+namespace mex {
+
+const int default_head_skip = 3;
+
+/// Compute needed size to store given format.
+static int
+calcsize (const char *fmt)
+{
+ int size = 0;
+ for (; *fmt; fmt++)
+ {
+ switch (*fmt)
+ {
+ case 'l':
+ case 'L':
+ size += 4;
+ break;
+ case 'h':
+ case 'H':
+ size += 2;
+ break;
+ case 'b':
+ case 'B':
+ size += 1;
+ break;
+ }
+ }
+ return size;
+}
+
+Msg::Msg (mtype_t mtype)
+ : head_skip_ (default_head_skip),
+ mtype_ (mtype)
+{
+ payload_.resize (head_skip_);
+}
+
+Msg::Msg (MsgReader &reader)
+ : head_skip_ (default_head_skip),
+ mtype_ (MTYPE_IDLE)
+{
+ int size = reader.size ();
+ payload_.resize (head_skip_ - 1 + size);
+ reader.read (&payload_.front () + head_skip_ - 1);
+ mtype_ = static_cast<mtype_t> (payload_[head_skip_ - 1]);
+}
+
+void
+Msg::write (MsgWriter &writer)
+{
+ assert (head_skip_ >= 1);
+ payload_[head_skip_ - 1] = static_cast<int> (mtype_);
+ writer.write (&payload_.front () + head_skip_ - 1,
+ payload_.size () - head_skip_ + 1);
+}
+
+MsgPusher
+Msg::push (const char *fmt)
+{
+ int push_index = payload_.size ();
+ payload_.resize (push_index + calcsize (fmt));
+ return MsgPusher (payload_.begin () + push_index, fmt);
+}
+
+void
+Msg::push (const char *buffer, int size)
+{
+ payload_.insert (payload_.end (), buffer, buffer + size);
+}
+
+MsgPoper
+Msg::pop (const char *fmt)
+{
+ int pop_size = calcsize (fmt);
+ assert (pop_size <= (int) payload_.size () - head_skip_);
+ int pop_index = head_skip_;
+ head_skip_ += pop_size;
+ return MsgPoper (payload_.begin () + pop_index, fmt);
+}
+
+const char *
+Msg::pop (int size)
+{
+ assert (size <= (int) payload_.size () - head_skip_);
+ const char *r = &payload_.front () + head_skip_;
+ head_skip_ += size;
+ return r;
+}
+
+MsgPusher
+Msg::encapsulate (mtype_t mtype, const char *fmt)
+{
+ int head_size = calcsize (fmt) + 1;
+ assert (head_size <= head_skip_);
+ payload_[head_skip_ - 1] = static_cast<int> (mtype_);
+ mtype_ = mtype;
+ head_skip_ -= head_size;
+ return MsgPusher (payload_.begin () + head_skip_, fmt);
+}
+
+void
+Msg::decapsulate ()
+{
+ assert (1 <= payload_.size () - head_skip_);
+ mtype_ = static_cast<mtype_t> (payload_[head_skip_]);
+ head_skip_++;
+}
+
+int
+Msg::len () const
+{
+ return payload_.size () - head_skip_;
+}
+
+MsgPusher &
+MsgPusher::operator<< (int32_t v)
+{
+ push (v);
+ return *this;
+}
+
+MsgPusher &
+MsgPusher::operator<< (uint32_t v)
+{
+ push (v);
+ return *this;
+}
+
+MsgPusher::MsgPusher (std::vector<char>::iterator out, const char *fmt)
+ : out_ (out),
+ fmt_ (fmt)
+{
+}
+
+void
+MsgPusher::push (int64_t v)
+{
+ switch (*fmt_)
+ {
+ case 'l':
+ assert (v >= INT32_MIN && v <= INT32_MAX);
+ break;
+ case 'L':
+ assert (v >= 0 && v <= UINT32_MAX);
+ break;
+ case 'h':
+ assert (v >= INT16_MIN && v <= INT16_MAX);
+ break;
+ case 'H':
+ assert (v >= 0 && v <= UINT16_MAX);
+ break;
+ case 'b':
+ assert (v >= INT8_MIN && v <= INT8_MAX);
+ break;
+ case 'B':
+ assert (v >= 0 && v <= UINT8_MAX);
+ break;
+ default:
+ assert (0);
+ }
+ switch (*fmt_)
+ {
+ case 'l':
+ case 'L':
+ *out_++ = v >> 24;
+ *out_++ = v >> 16;
+ case 'h':
+ case 'H':
+ *out_++ = v >> 8;
+ case 'b':
+ case 'B':
+ *out_++ = v >> 0;
+ }
+ fmt_++;
+}
+
+MsgPoper &
+MsgPoper::operator>> (int32_t &v)
+{
+ v = pop (31, true);
+ return *this;
+}
+
+MsgPoper &
+MsgPoper::operator>> (uint32_t &v)
+{
+ v = pop (32, false);
+ return *this;
+}
+
+MsgPoper &
+MsgPoper::operator>> (int16_t &v)
+{
+ v = pop (15, true);
+ return *this;
+}
+
+MsgPoper &
+MsgPoper::operator>> (uint16_t &v)
+{
+ v = pop (16, false);
+ return *this;
+}
+
+MsgPoper &
+MsgPoper::operator>> (int8_t &v)
+{
+ v = pop (7, true);
+ return *this;
+}
+
+MsgPoper &
+MsgPoper::operator>> (uint8_t &v)
+{
+ v = pop (8, false);
+ return *this;
+}
+
+MsgPoper::MsgPoper (std::vector<char>::const_iterator in, const char *fmt)
+ : in_ (in),
+ fmt_ (fmt)
+{
+}
+
+uint32_t
+MsgPoper::pop_bytes (int bytes)
+{
+ uint32_t r = 0;
+ while (bytes--)
+ r = r << 8 | static_cast<unsigned char> (*in_++);
+ return r;
+}
+
+int64_t
+MsgPoper::pop (int bits, bool sign)
+{
+ switch (*fmt_++)
+ {
+ case 'l':
+ assert (bits >= 31 && sign);
+ return static_cast<int32_t> (pop_bytes (4));
+ case 'L':
+ assert (bits >= 32);
+ return static_cast<uint32_t> (pop_bytes (4));
+ case 'h':
+ assert (bits >= 15 && sign);
+ return static_cast<int16_t> (pop_bytes (2));
+ case 'H':
+ assert (bits >= 16);
+ return static_cast<uint16_t> (pop_bytes (2));
+ case 'b':
+ assert (bits >= 7 && sign);
+ return static_cast<int8_t> (pop_bytes (1));
+ case 'B':
+ assert (bits >= 8);
+ return static_cast<uint8_t> (pop_bytes (1));
+ default:
+ assert_unreachable ();
+ }
+}
+
+} // namespace mex
+} // namespace ucoo
diff --git a/ucoo/arch/host/mex/mex_node.hh b/ucoo/arch/host/mex/mex_node.hh
new file mode 100644
index 0000000..103deea
--- /dev/null
+++ b/ucoo/arch/host/mex/mex_node.hh
@@ -0,0 +1,104 @@
+#ifndef ucoo_arch_host_mex_mex_node_hh
+#define ucoo_arch_host_mex_mex_node_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/common.hh"
+#include "mex_msg.hh"
+#include "mex_socket.hh"
+
+#include <memory>
+#include <map>
+#include <string>
+#include <tr1/functional>
+
+namespace ucoo {
+namespace mex {
+
+/// Mex node, singleton.
+class Node
+{
+ public:
+ /// Message handler type.
+ typedef std::tr1::function<void (Node &, Msg &)> Handler;
+ public:
+ /// Connect to mex hub.
+ Node ();
+ /// Wait forever.
+ void wait ();
+ /// Wait until date is reached.
+ void wait (uint32_t date);
+ /// Return current date.
+ uint32_t date () const { return date_; }
+ /// Send a message.
+ void send (Msg &msg);
+ /// Send a request and return response.
+ std::auto_ptr<Msg> request (Msg &msg);
+ /// Send a response while handling a request.
+ void response (Msg &msg);
+ /// Reserve a message type.
+ mtype_t reserve (const std::string &name);
+ /// Register a handler for a message type.
+ void handler_register (mtype_t mtype, Handler handler);
+ /// Register a handler for a message type, member function version.
+ template<class T>
+ void handler_register (mtype_t mtype, T &obj,
+ void (T::*handler) (Node &, Msg &))
+ {
+ using namespace std::tr1::placeholders;
+ handler_register (mtype, std::tr1::bind (handler, &obj, _1, _2));
+ }
+ /// Register a handler for a message type, member function version,
+ /// without Node parameter.
+ template<class T>
+ void handler_register (mtype_t mtype, T &obj,
+ void (T::*handler) (Msg &))
+ {
+ using namespace std::tr1::placeholders;
+ handler_register (mtype, std::tr1::bind (handler, &obj, _2));
+ }
+ private:
+ /// Receive one message.
+ std::auto_ptr<Msg> recv ();
+ /// Dispatch message to the right handler.
+ void dispatch (Msg &msg);
+ /// Handle an incomming DATE message.
+ void handle_date (Msg &msg);
+ /// Handle an incomming REQ message.
+ void handle_req (Msg &msg);
+ private:
+ /// Connection to hub.
+ Socket socket_;
+ /// Current date.
+ uint32_t date_;
+ /// When handling a request, this is the request identifier, else -1.
+ int req_;
+ /// Registered handlers.
+ typedef std::map<mtype_t, Handler> Handlers;
+ Handlers handlers_;
+};
+
+} // namespace mex
+} // namespace ucoo
+
+#endif // ucoo_arch_host_mex_mex_node_hh
diff --git a/ucoo/arch/host/mex/mex_node.host.cc b/ucoo/arch/host/mex/mex_node.host.cc
new file mode 100644
index 0000000..f6f7c98
--- /dev/null
+++ b/ucoo/arch/host/mex/mex_node.host.cc
@@ -0,0 +1,174 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "mex_node.hh"
+
+#include <cstring>
+
+namespace ucoo {
+namespace mex {
+
+Node::Node ()
+ : date_ (0),
+ req_ (-1)
+{
+ // Connect.
+ socket_.connect ();
+ // Setup default handlers.
+ handler_register (MTYPE_DATE, *this, &Node::handle_date);
+ handler_register (MTYPE_REQ, *this, &Node::handle_req);
+ // Synchronise with the hub.
+ bool sync = false;
+ while (!sync)
+ {
+ std::auto_ptr<Msg> msg = recv ();
+ if (msg->mtype () == MTYPE_DATE)
+ sync = true;
+ dispatch (*msg);
+ }
+}
+
+void
+Node::wait ()
+{
+ while (1)
+ {
+ // Signal IDLE state.
+ Msg idle (MTYPE_IDLE);
+ send (idle);
+ // Receive and dispatch messages.
+ std::auto_ptr<Msg> msg = recv ();
+ dispatch (*msg);
+ }
+}
+
+void
+Node::wait (uint32_t date)
+{
+ while (date_ != date)
+ {
+ // Signal IDLE state.
+ Msg idle (MTYPE_IDLE);
+ idle.push ("L") << date;
+ send (idle);
+ // Receive and dispatch messages.
+ std::auto_ptr<Msg> msg = recv ();
+ dispatch (*msg);
+ }
+}
+
+void
+Node::send (Msg &msg)
+{
+ msg.write (socket_);
+}
+
+std::auto_ptr<Msg>
+Node::request (Msg &msg)
+{
+ // Send request.
+ msg.encapsulate (MTYPE_REQ, "B") << 0;
+ send (msg);
+ // Wait for response.
+ std::auto_ptr<Msg> rsp;
+ rsp = recv ();
+ while (rsp->mtype () != MTYPE_RSP)
+ {
+ dispatch (*rsp);
+ rsp = recv ();
+ }
+ // Eat unused request identifier.
+ rsp->pop ("B");
+ rsp->decapsulate ();
+ return rsp;
+}
+
+void
+Node::response (Msg &msg)
+{
+ assert (req_ != -1);
+ msg.encapsulate (MTYPE_RSP, "B") << req_;
+ send (msg);
+ req_ = -1;
+}
+
+mtype_t
+Node::reserve (const std::string &name)
+{
+ // Send request.
+ Msg msg (MTYPE_RES);
+ msg.push (name.data (), name.size ());
+ send (msg);
+ // Wait for response.
+ std::auto_ptr<Msg> rsp;
+ rsp = recv ();
+ while (rsp->mtype () != MTYPE_RES)
+ {
+ dispatch (*rsp);
+ rsp = recv ();
+ }
+ // Return allocated message type.
+ int mtype;
+ rsp->pop ("B") >> mtype;
+ return static_cast<mtype_t> (mtype);
+}
+
+void
+Node::handler_register (mtype_t mtype, Handler handler)
+{
+ std::pair<Handlers::iterator, bool> r =
+ handlers_.insert (Handlers::value_type (mtype, handler));
+ assert (r.second);
+}
+
+std::auto_ptr<Msg>
+Node::recv ()
+{
+ return std::auto_ptr<Msg> (new Msg (socket_));
+}
+
+void
+Node::dispatch (Msg &msg)
+{
+ Handlers::const_iterator it = handlers_.find (msg.mtype ());
+ if (it != handlers_.end ())
+ it->second (*this, msg);
+}
+
+void
+Node::handle_date (Msg &msg)
+{
+ msg.pop ("L") >> date_;
+}
+
+void
+Node::handle_req (Msg &msg)
+{
+ msg.pop ("B") >> req_;
+ msg.decapsulate ();
+ dispatch (msg);
+ req_ = -1;
+}
+
+} // namespace mex
+} // namespace ucoo
diff --git a/ucoo/arch/host/mex/mex_socket.hh b/ucoo/arch/host/mex/mex_socket.hh
new file mode 100644
index 0000000..915e1b9
--- /dev/null
+++ b/ucoo/arch/host/mex/mex_socket.hh
@@ -0,0 +1,59 @@
+#ifndef ucoo_arch_host_mex_mex_socket_hh
+#define ucoo_arch_host_mex_mex_socket_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "mex_msg.hh"
+
+namespace ucoo {
+namespace mex {
+
+/// Mex socket, able to read and write messages.
+class Socket : public MsgReader, public MsgWriter
+{
+ public:
+ /// Default constructor.
+ Socket () : fd_ (-1), read_size_ (-1) { }
+ /// Destructor, close the connection.
+ ~Socket ();
+ /// Connect to Mex hub.
+ void connect ();
+ /// See MsgReader::size.
+ int size ();
+ /// See MsgReader::read.
+ void read (char *buf);
+ /// See MsgWriter::write.
+ void write (const char *buf, int count);
+ private:
+ /// File descriptor to open socket, or -1 if not open.
+ int fd_;
+ /// Size of the next message to be read, or -1 if not known yet.
+ int read_size_;
+ /// This socket sequence number.
+ int seq_;
+};
+
+} // namespace mex
+} // namespace ucoo
+
+#endif // ucoo_arch_host_mex_mex_socket_hh
diff --git a/ucoo/arch/host/mex/mex_socket.host.cc b/ucoo/arch/host/mex/mex_socket.host.cc
new file mode 100644
index 0000000..41a6e01
--- /dev/null
+++ b/ucoo/arch/host/mex/mex_socket.host.cc
@@ -0,0 +1,95 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "mex_socket.hh"
+
+#include "ucoo/common.hh"
+
+#include "config/arch/host/mex.hh"
+#include "socket.h"
+
+#include <unistd.h>
+#include <cstdlib>
+
+namespace ucoo {
+namespace mex {
+
+Socket::~Socket ()
+{
+ if (fd_ != -1)
+ close (fd_);
+}
+
+void
+Socket::connect ()
+{
+ fd_ = socket_client UCOO_CONFIG_ARCH_HOST_MEX_DEFAULT_ADDRESS;
+}
+
+int
+Socket::size ()
+{
+ uint8_t header[3];
+ int r = ::read (fd_, header, sizeof (header));
+ assert_perror (r != -1);
+ if (r == 0)
+ exit (0);
+ else
+ {
+ assert (r == sizeof (header));
+ read_size_ = (header[0] << 8) | header[1];
+ seq_ = header[2];
+ return read_size_;
+ }
+}
+
+void
+Socket::read (char *buf)
+{
+ assert (fd_ != -1);
+ assert (read_size_ > 0);
+ int r = ::read (fd_, buf, read_size_);
+ assert_perror (r != -1);
+ assert (r == read_size_);
+ read_size_ = -1;
+}
+
+void
+Socket::write (const char *buf, int count)
+{
+ assert (fd_ != -1);
+ assert (read_size_ == -1);
+ uint8_t header[3];
+ header[0] = count >> 8;
+ header[1] = count;
+ header[2] = seq_;
+ int r = ::write (fd_, header, sizeof (header));
+ assert_perror (r != -1);
+ assert (r == sizeof (header));
+ r = ::write (fd_, buf, count);
+ assert_perror (r != -1);
+ assert (r == count);
+}
+
+} // namespace mex
+} // namespace ucoo
diff --git a/ucoo/arch/host/mex/socket.h b/ucoo/arch/host/mex/socket.h
new file mode 100644
index 0000000..f8fc348
--- /dev/null
+++ b/ucoo/arch/host/mex/socket.h
@@ -0,0 +1,39 @@
+#ifndef ucoo_arch_host_mex_socket_h
+#define ucoo_arch_host_mex_socket_h
+/* ucoolib - Microcontroller object oriented library. {{{
+ *
+ * Copyright (C) 2012 Nicolas Schodet
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * }}} */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Create and connect a client socket. */
+int
+socket_client (const char *addr, const char *port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ucoo_arch_host_mex_socket_h */
diff --git a/ucoo/arch/host/mex/socket.host.c b/ucoo/arch/host/mex/socket.host.c
new file mode 100644
index 0000000..d202192
--- /dev/null
+++ b/ucoo/arch/host/mex/socket.host.c
@@ -0,0 +1,88 @@
+/* imported from mysock library and modified for ucoolib.
+ * mysock library - client functions. {{{
+ *
+ * Copyright (C) 2001 Nicolas Schodet
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * }}} */
+#include "socket.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+int
+socket_client (const char *addr, const char *port)
+{
+ int s;
+ struct sockaddr_in saddr;
+ struct servent *port_info;
+ struct hostent *host_info;
+ unsigned short int iport;
+ unsigned int iaddr;
+ iport = htons (atoi (port));
+ if (!iport)
+ {
+ port_info = getservbyname (port, "tcp");
+ if (!port_info)
+ {
+ fprintf (stderr, "Service %s unknown\n", port);
+ exit (EXIT_FAILURE);
+ }
+ iport = port_info->s_port;
+ }
+ iaddr = inet_addr (addr);
+ if (iaddr == INADDR_NONE)
+ {
+ host_info = gethostbyname (addr);
+ if (!host_info)
+ {
+ fprintf (stderr, "Host %s unknown\n", addr);
+ exit (EXIT_FAILURE);
+ }
+ iaddr = * (int *) host_info->h_addr;
+ }
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = iaddr;
+ saddr.sin_port = iport;
+ s = socket (AF_INET, SOCK_STREAM, 0);
+ if (s < 0)
+ {
+ perror ("socket");
+ exit (EXIT_FAILURE);
+ }
+ int on = 1;
+ if (setsockopt (s, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof (on))
+ < 0)
+ {
+ perror ("setsockopt (NODELAY)");
+ exit (EXIT_FAILURE);
+ }
+ if (connect (s, (struct sockaddr *) &saddr, sizeof (saddr)) < 0)
+ {
+ perror ("connect");
+ exit (EXIT_FAILURE);
+ }
+ return s;
+}
diff --git a/ucoo/arch/host/mex/test/Makefile b/ucoo/arch/host/mex/test/Makefile
new file mode 100644
index 0000000..d54907c
--- /dev/null
+++ b/ucoo/arch/host/mex/test/Makefile
@@ -0,0 +1,9 @@
+BASE = ../../../../..
+
+TARGETS = host
+host_PROGS = test_mex
+test_mex_SOURCES = test_mex.cc
+
+MODULES =
+
+include $(BASE)/build/top.mk
diff --git a/ucoo/arch/host/mex/test/hub.py b/ucoo/arch/host/mex/test/hub.py
new file mode 100644
index 0000000..31dcec1
--- /dev/null
+++ b/ucoo/arch/host/mex/test/hub.py
@@ -0,0 +1,6 @@
+# Hub for test.
+from mex.hub import Hub
+def log (x):
+ print x
+h = Hub (min_clients = 2, log = log)
+h.wait ()
diff --git a/ucoo/arch/host/mex/test/test_mex.cc b/ucoo/arch/host/mex/test/test_mex.cc
new file mode 100644
index 0000000..d7834a9
--- /dev/null
+++ b/ucoo/arch/host/mex/test/test_mex.cc
@@ -0,0 +1,245 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/arch/host/mex/mex_msg.hh"
+#include "ucoo/arch/host/mex/mex_node.hh"
+#include "ucoo/arch/arch.hh"
+#include "ucoo/common.hh"
+
+#include <cstdio>
+#include <cstring>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+using namespace ucoo::mex;
+
+/// Global error number, should be zero at end of test.
+static int error;
+
+/// Helper function, print a buffer.
+static void
+printbuf (const char *head, const char *buf, int count)
+{
+ printf ("%s:", head);
+ for (int i = 0; i < count; i++)
+ printf (" %02x", (unsigned char) buf[i]);
+ printf ("\n");
+}
+
+/// Helper function, check for equality.
+static void
+check (int64_t a, int64_t b, const char *name = NULL)
+{
+ printf ("%s: %Lx\n", name ? name : "pop", a);
+ if (a != b)
+ {
+ printf (" expected: %Lx\n", b);
+ error++;
+ }
+}
+
+/// Test writer, will check what is written and display it.
+class TestWriter : public MsgWriter
+{
+ const char *exbuf_;
+ int excount_;
+ public:
+ template<int count>
+ TestWriter (const char (&buf)[count])
+ : exbuf_ (buf), excount_ (count) { }
+ void write (const char *buf, int count)
+ {
+ printbuf ("write", buf, count);
+ if (count != excount_ || memcmp (buf, exbuf_, count) != 0)
+ {
+ printbuf (" expected", exbuf_, excount_);
+ error++;
+ }
+ }
+};
+
+/// Test reader, will return a predefined message and display it.
+class TestReader : public MsgReader
+{
+ const char *buf_;
+ int count_;
+ public:
+ template<int count>
+ TestReader (const char (&buf)[count])
+ : buf_ (buf), count_ (count) { }
+ int size () { return count_; }
+ void read (char *buf)
+ {
+ printbuf ("read", buf_, count_);
+ memcpy (buf, buf_, count_);
+ }
+};
+
+/// Test message class.
+void
+test_msg ()
+{
+ {
+ Msg m (MTYPE_DATE);
+ const char w1b[] = { 0x01 };
+ TestWriter w1 (w1b);
+ m.write (w1);
+ m.push ("BHl") << 1 << 2 << 3;
+ m.push ("\x04\x05", 2);
+ const char w2b[] = { 0x01, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03,
+ 0x04, 0x05 };
+ TestWriter w2 (w2b);
+ m.write (w2);
+ }
+ {
+ uint32_t ua, ub, uc;
+ int32_t a, b, c;
+ const char rb[] = { 0x01, 0xff, 0xfe, 0xfd, 0xfc, 1, 2, 3, 4 };
+ TestReader r (rb);
+ Msg m (r);
+ check (m.mtype (), 1, "mtype");
+ check (m.len (), 8, "len");
+ m.pop ("BBH") >> ua >> ub >> uc;
+ check (ua, 0xff); check (ub, 0xfe); check (uc, 0xfdfc);
+ m.pop ("BBH") >> ua >> ub >> uc;
+ check (ua, 1); check (ub, 2); check (uc, 0x304);
+ m = Msg (r);
+ m.pop ("bbh") >> a >> b >> c;
+ check (a, -1); check (b, -2); check (c, -0x204);
+ m.pop ("bbh") >> a >> b >> c;
+ check (a, 1); check (b, 2); check (c, 0x304);
+ m = Msg (r);
+ m.pop ("LL") >> ua >> ub;
+ check (ua, 0xfffefdfc); check (ub, 0x01020304);
+ m = Msg (r);
+ m.pop ("ll") >> a >> b;
+ check (a, -0x010204); check (b, 0x01020304);
+ m = Msg (r);
+ const char *s;
+ s = m.pop (8);
+ printbuf ("pop", s, 8);
+ if (memcmp (s, &rb[1], 8) != 0)
+ {
+ printbuf (" expected", &rb[1], 8);
+ error++;
+ }
+ }
+ {
+ Msg m (static_cast<mtype_t> (0x20));
+ m.push ("bb") << 1 << 2;
+ m.encapsulate (static_cast<mtype_t> (0x21), "b") << 5;
+ check (m.mtype (), 0x21, "mtype");
+ check (m.len (), 4, "len");
+ const char w1b[] = { 0x21, 0x05, 0x20, 0x01, 0x02 };
+ TestWriter w1 (w1b);
+ m.write (w1);
+ m.pop ("b");
+ m.decapsulate ();
+ check (m.mtype (), 0x20, "mtype");
+ check (m.len (), 2, "len");
+ }
+}
+
+void
+test_node_1 ()
+{
+ Node node;
+ mtype_t hello_mtype, world_mtype;
+ hello_mtype = node.reserve ("hello");
+ world_mtype = node.reserve ("world");
+ node.wait (42);
+ Msg hello (hello_mtype);
+ hello.push ("l") << 42;
+ node.send (hello);
+ Msg world (world_mtype);
+ world.push ("bh") << 12 << 5678;
+ std::auto_ptr<Msg> resp (node.request (world));
+ int sum;
+ resp->pop ("l") >> sum;
+ ucoo::assert (sum == 12 + 5678);
+ node.wait (42 * 2);
+}
+
+void
+test_node_2_handle_hello (Node &, Msg &msg)
+{
+ int pass;
+ msg.pop ("l") >> pass;
+ ucoo::assert (pass == 42);
+ printf ("hello\n");
+}
+
+void
+test_node_2_handle_world (Node &node, Msg &msg)
+{
+ int a, b;
+ msg.pop ("bh") >> a >> b;
+ printf ("world\n");
+ Msg resp (msg.mtype ());
+ resp.push ("l") << a + b;
+ node.response (resp);
+}
+
+void
+test_node_2 ()
+{
+ Node node;
+ mtype_t hello_mtype, world_mtype;
+ hello_mtype = node.reserve ("hello");
+ world_mtype = node.reserve ("world");
+ node.handler_register (hello_mtype, test_node_2_handle_hello);
+ node.handler_register (world_mtype, test_node_2_handle_world);
+ node.wait ();
+}
+
+/// Test node operation, need a Mex hub to work.
+void
+test_node ()
+{
+ int pid;
+ pid = fork ();
+ ucoo::assert_perror (pid != -1);
+ if (pid)
+ {
+ test_node_1 ();
+ int status;
+ waitpid (pid, &status, 0);
+ }
+ else
+ {
+ test_node_2 ();
+ ucoo::assert_unreachable ();
+ }
+}
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ test_msg ();
+ test_node ();
+ printf ("%s\n", error ? "FAIL" : "PASS");
+ return error ? 1 : 0;
+}
diff --git a/ucoo/arch/host/test/Makefile b/ucoo/arch/host/test/Makefile
new file mode 100644
index 0000000..9a329a3
--- /dev/null
+++ b/ucoo/arch/host/test/Makefile
@@ -0,0 +1,9 @@
+BASE = ../../../..
+
+TARGETS = host
+host_PROGS = test_host
+test_host_SOURCES = test_host.cc
+
+MODULES =
+
+include $(BASE)/build/top.mk
diff --git a/ucoo/arch/host/test/test_host.cc b/ucoo/arch/host/test/test_host.cc
new file mode 100644
index 0000000..645836a
--- /dev/null
+++ b/ucoo/arch/host/test/test_host.cc
@@ -0,0 +1,49 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/arch/host/host.hh"
+#include "ucoo/arch/arch.hh"
+
+#include <cstdio>
+#include <cstdlib>
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ ucoo::Host host ("test_host");
+ host.add_option ('c', "connect to mex hub");
+ host.add_option ('p', "FOO", "print FOO", "Hello world!");
+ host.add_option ('s', "STRIP", "print striped instance", "");
+ host.parse_options ();
+ puts (host.get_option ('p').c_str ());
+ if (host.is_option_set ('s'))
+ {
+ const std::string &strips = host.get_option ('s');
+ int strip = atoi (strips.c_str ()); // Quick'n dirty convertion.
+ puts (host.get_instance (strip).c_str ());
+ }
+ if (host.is_option_set ('c'))
+ host.get_node ();
+ return 0;
+}
diff --git a/ucoo/arch/stm32f4/stm32f4.ld b/ucoo/arch/stm32f4/stm32f4.ld
new file mode 100644
index 0000000..ceef7af
--- /dev/null
+++ b/ucoo/arch/stm32f4/stm32f4.ld
@@ -0,0 +1,6 @@
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
+}
+INCLUDE libopencm3_stm32f4.ld
diff --git a/ucoo/arch/syscalls.cc b/ucoo/arch/syscalls.cc
new file mode 100644
index 0000000..b35ac5a
--- /dev/null
+++ b/ucoo/arch/syscalls.cc
@@ -0,0 +1,36 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace __gnu_cxx {
+
+/// Replaces the default verbose terminate handler.
+/// Avoids the inclusion of code to inpect C++ objects.
+void
+__verbose_terminate_handler ()
+{
+ while (1)
+ ;
+}
+
+} //namespace __gnu_cxx
diff --git a/ucoo/arch/syscalls.newlib.cc b/ucoo/arch/syscalls.newlib.cc
new file mode 100644
index 0000000..abdd75f
--- /dev/null
+++ b/ucoo/arch/syscalls.newlib.cc
@@ -0,0 +1,179 @@
+/* ucoolib - Microcontroller object oriented library. {{{
+ *
+ * Copyright (C) 2012 Nicolas Schodet
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * }}} */
+#include "ucoo/common.hh"
+#include "syscalls.newlib.hh"
+
+#include <reent.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+ucoo::Stream *ucoo::syscalls_streams[3];
+
+/** This is needed by C++ ABI, this simple definition will do. See:
+ * http://lists.debian.org/debian-gcc/2003/07/msg00057.html */
+void *__dso_handle = (void*) &__dso_handle;
+
+/** This function is called when a pure virtual function is called. This is
+ * needed by linker because when a abstract class constructor or destructor is
+ * called, object is not complete. Replace the one provided by the toolchain
+ * to avoid including the world. */
+extern "C" void
+__cxa_pure_virtual (void)
+{
+ ucoo::halt ();
+}
+
+/** Increase program data space. */
+extern "C" void *
+_sbrk_r (struct _reent *ptr, int incr)
+{
+ extern char end; /* Defined in linker script. */
+ static char *heap_end;
+ char *prev_heap_end;
+ if (heap_end == 0)
+ heap_end = &end;
+ prev_heap_end = heap_end;
+ heap_end += incr;
+ return (void *) prev_heap_end;
+}
+
+/** Exit program, endless loop to stop program, to be improved. */
+extern "C" void
+_exit (int n)
+{
+ ucoo::halt ();
+}
+
+/** Close a file, unimplemented. */
+extern "C" int
+_close_r (struct _reent *ptr, int fd)
+{
+ return -1;
+}
+
+/** Status of open file, consider all files as character devices. */
+extern "C" int
+_fstat_r (struct _reent *ptr, int fd, struct stat *st)
+{
+ st->st_mode = S_IFCHR;
+ return 0;
+}
+
+/** Get PID, minimal implementation. */
+extern "C" int
+_getpid_r (struct _reent *ptr)
+{
+ return 1;
+}
+
+/** Whether file is a terminal, consider this is always true. */
+extern "C" int
+_isatty_r (struct _reent *ptr, int fd)
+{
+ return 1;
+}
+
+/** Send a signal, no process, no signal. */
+extern "C" int
+_kill_r (struct _reent *ptr, int pid, int sig)
+{
+ ptr->_errno = EINVAL;
+ return -1;
+}
+
+/** Set position in a file, no-op. */
+extern "C" off_t
+_lseek_r (struct _reent *ptr, int fd, off_t pos, int whence)
+{
+ return 0;
+}
+
+/** Open a file, unimplemented. */
+extern "C" int
+_open_r (struct _reent *ptr, const char *file, int flags, int mode)
+{
+ return -1;
+}
+
+/** Read from file. */
+extern "C" int
+_read_r (struct _reent *ptr, int fd, void *buf, size_t cnt)
+{
+ if (fd == 0)
+ {
+ if (ucoo::syscalls_streams[0])
+ {
+ ucoo::Stream &s = *ucoo::syscalls_streams[0];
+ int r = s.read (reinterpret_cast<char *> (buf), cnt);
+ switch (r)
+ {
+ case -2:
+ return 0;
+ case -1:
+ ptr->_errno = EIO;
+ return -1;
+ case 0:
+ ptr->_errno = EAGAIN;
+ return -1;
+ default:
+ return r;
+ }
+ }
+ else
+ return 0;
+ }
+ else
+ {
+ ptr->_errno = EBADF;
+ return -1;
+ }
+}
+
+/** Write to file. */
+extern "C" int
+_write_r (struct _reent *ptr, int fd, const void *buf, size_t cnt)
+{
+ if ((fd == 1 || fd == 2) && ucoo::syscalls_streams[fd])
+ {
+ ucoo::Stream &s = *ucoo::syscalls_streams[fd];
+ int r = s.write (reinterpret_cast<const char *> (buf), cnt);
+ switch (r)
+ {
+ case -1:
+ ptr->_errno = EIO;
+ return -1;
+ case 0:
+ ptr->_errno = EAGAIN;
+ return -1;
+ default:
+ return r;
+ }
+ }
+ else
+ {
+ ptr->_errno = EBADF;
+ return -1;
+ }
+}
+
diff --git a/ucoo/arch/syscalls.newlib.hh b/ucoo/arch/syscalls.newlib.hh
new file mode 100644
index 0000000..af4ff98
--- /dev/null
+++ b/ucoo/arch/syscalls.newlib.hh
@@ -0,0 +1,35 @@
+#ifndef ucoo_arch_syscalls_newlib_hh
+#define ucoo_arch_syscalls_newlib_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/stream.hh"
+
+namespace ucoo {
+
+// Streams used as stdin, stdout and stderr.
+extern Stream *syscalls_streams[3];
+
+} // namespace ucoo
+
+#endif // ucoo_arch_syscalls_newlib_hh
diff --git a/ucoo/base/proto/Config b/ucoo/base/proto/Config
new file mode 100644
index 0000000..4edaa6b
--- /dev/null
+++ b/ucoo/base/proto/Config
@@ -0,0 +1,2 @@
+[base/proto]
+args_max_size = 16
diff --git a/ucoo/base/proto/Module b/ucoo/base/proto/Module
new file mode 100644
index 0000000..68f866f
--- /dev/null
+++ b/ucoo/base/proto/Module
@@ -0,0 +1 @@
+base_proto_SOURCES = proto.cc
diff --git a/ucoo/base/proto/proto.cc b/ucoo/base/proto/proto.cc
new file mode 100644
index 0000000..838a79b
--- /dev/null
+++ b/ucoo/base/proto/proto.cc
@@ -0,0 +1,257 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "proto.hh"
+
+#include <cctype>
+
+namespace ucoo {
+
+Proto::Proto (Handler &handler, Stream &stream)
+ : handler_ (handler), stream_ (stream), step_ (IDLE)
+{
+}
+
+void
+Proto::accept ()
+{
+ int c;
+ while ((c = stream_.getc ()) != -1)
+ {
+ if (c == '!')
+ step_ = BANG;
+ else
+ {
+ switch (step_)
+ {
+ case IDLE:
+ // Nothing received yet.
+ break;
+ case BANG:
+ // Bang received yet.
+ if (std::isalpha (c))
+ {
+ cmd_ = c;
+ size_ = 0;
+ step_ = COMMAND;
+ }
+ else
+ {
+ handler_.proto_handle (*this, '?', 0, 0);
+ step_ = IDLE;
+ }
+ break;
+ case COMMAND:
+ // Command received yet.
+ if (c == '\r' || c == '\n')
+ {
+ handler_.proto_handle (*this, cmd_, args_, size_);
+ step_ = IDLE;
+ }
+ else if (c == '\'')
+ step_ = ARG_CHAR;
+ else if (c == '"')
+ step_ = ARG_STRING;
+ else
+ {
+ step_ = ARG_DIGIT;
+ accept_digit (c);
+ }
+ break;
+ case ARG_DIGIT:
+ step_ = COMMAND;
+ accept_digit (c);
+ break;
+ case ARG_CHAR:
+ step_ = COMMAND;
+ accept_char (c);
+ break;
+ case ARG_STRING:
+ if (c == '\r' || c == '\n')
+ {
+ handler_.proto_handle (*this, cmd_, args_, size_);
+ step_ = IDLE;
+ }
+ else
+ {
+ accept_char (c);
+ }
+ break;
+ }
+ }
+ }
+}
+
+void
+Proto::send (char cmd)
+{
+ char buf[3];
+ char *p = buf;
+ *p++ = '!';
+ *p++ = cmd;
+ *p++ = '\n';
+ stream_.write (buf, p - buf);
+}
+
+void
+Proto::send (char cmd, const char *fmt, int a0)
+{
+ send (cmd, fmt, a0, 0, 0, 0);
+}
+
+void
+Proto::send (char cmd, const char *fmt, int a0, int a1)
+{
+ send (cmd, fmt, a0, a1, 0, 0);
+}
+
+void
+Proto::send (char cmd, const char *fmt, int a0, int a1, int a2)
+{
+ send (cmd, fmt, a0, a1, a2, 0);
+}
+
+static inline void
+send_byte (char *buf, uint8_t b)
+{
+ static const char hexchars[] = "0123456789abcdef";
+ buf[0] = hexchars[b >> 4];
+ buf[1] = hexchars[b & 0xf];
+}
+
+static char *
+send_arg (char *buf, char fmt, int v)
+{
+ switch (fmt)
+ {
+ case 'L':
+ case 'l':
+ send_byte (buf, (v >> 24) & 0xff);
+ buf += 2;
+ send_byte (buf, (v >> 16) & 0xff);
+ buf += 2;
+ case 'H':
+ case 'h':
+ send_byte (buf, (v >> 8) & 0xff);
+ buf += 2;
+ case 'B':
+ case 'b':
+ send_byte (buf, v & 0xff);
+ buf += 2;
+ break;
+ default:
+ assert_unreachable ();
+ }
+ return buf;
+}
+
+void
+Proto::send (char cmd, const char *fmt, int a0, int a1, int a2, int a3)
+{
+ char buf[3 + 4 * 4 * 2]; // Large enough for the largest frame.
+ char *p = buf;
+ *p++ = '!';
+ *p++ = cmd;
+ if (*fmt)
+ {
+ p = send_arg (p, *fmt++, a0);
+ if (*fmt)
+ {
+ p = send_arg (p, *fmt++, a1);
+ if (*fmt)
+ {
+ p = send_arg (p, *fmt++, a2);
+ if (*fmt)
+ {
+ p = send_arg (p, *fmt++, a3);
+ }
+ }
+ }
+ }
+ *p++ = '\n';
+ stream_.write (buf, p - buf);
+}
+
+void
+Proto::send_buf (char cmd, const uint8_t *args, int size)
+{
+ int i;
+ char buf[3 + 2 * size];
+ char *p = buf;
+ *p++ = '!';
+ *p++ = cmd;
+ for (i = 0; i < size; i++)
+ {
+ send_byte (p, args[i]);
+ p += 2;
+ }
+ *p++ = '\n';
+ stream_.write (buf, p - buf);
+}
+
+void
+Proto::accept_digit (int c)
+{
+ // Test for argument list overflow.
+ if (size_ >= UCOO_CONFIG_BASE_PROTO_ARGS_MAX_SIZE)
+ {
+ handler_.proto_handle (*this, '?', 0, 0);
+ step_ = IDLE;
+ return;
+ }
+ // Convert from hexa.
+ if ('0' <= c && c <= '9')
+ c -= '0';
+ else if ('a' <= c && c <= 'f')
+ c -= 'a' - 10;
+ else if ('A' <= c && c <= 'F')
+ c -= 'A' - 10;
+ else
+ {
+ handler_.proto_handle (*this, '?', 0, 0);
+ step_ = IDLE;
+ return;
+ }
+ // Add digit.
+ args_[size_] <<= 4;
+ args_[size_] |= c;
+ if (step_ == COMMAND)
+ size_++;
+}
+
+void
+Proto::accept_char (int c)
+{
+ // Test for argument list overflow or unwanted char.
+ if (size_ >= UCOO_CONFIG_BASE_PROTO_ARGS_MAX_SIZE || !std::isprint (c))
+ {
+ handler_.proto_handle (*this, '?', 0, 0);
+ step_ = IDLE;
+ return;
+ }
+ // Add char.
+ args_[size_] = c;
+ size_++;
+}
+
+} // namespace ucoo
diff --git a/ucoo/base/proto/proto.hh b/ucoo/base/proto/proto.hh
new file mode 100644
index 0000000..a4ee999
--- /dev/null
+++ b/ucoo/base/proto/proto.hh
@@ -0,0 +1,99 @@
+#ifndef ucoo_base_proto_proto_hh
+#define ucoo_base_proto_proto_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/common.hh"
+#include "ucoo/intf/stream.hh"
+
+#include "config/base/proto.hh"
+
+namespace ucoo {
+
+/// Support for old proto protocol.
+class Proto
+{
+ public:
+ /// Receivers should implement this interface.
+ class Handler
+ {
+ public:
+ /// Handle a received message.
+ virtual void proto_handle (Proto &proto, char cmd,
+ const uint8_t *args, int size) = 0;
+ };
+ public:
+ /// Constructor.
+ Proto (Handler &handler, Stream &stream);
+ /// Read from stream and handle any received message.
+ void accept ();
+ /// Send a message with no argument.
+ void send (char cmd);
+ /// Send a message with one argument.
+ void send (char cmd, const char *fmt, int a0);
+ /// Send a message with two arguments.
+ void send (char cmd, const char *fmt, int a0, int a1);
+ /// Send a message with three arguments.
+ void send (char cmd, const char *fmt, int a0, int a1, int a2);
+ /// Send a message with four arguments.
+ void send (char cmd, const char *fmt, int a0, int a1, int a2, int a3);
+ /// Send a message, with a byte buffer.
+ void send_buf (char cmd, const uint8_t *args, int size);
+ private:
+ /// Accept a digit to be used for args.
+ void accept_digit (int c);
+ /// Accept a quoted char to be used for args.
+ void accept_char (int c);
+ private:
+ /// Handler interface.
+ Handler &handler_;
+ /// Connected stream.
+ Stream &stream_;
+ /// Decoding step.
+ enum Step
+ {
+ /// Nothing received yet.
+ IDLE,
+ /// Exclamation mark received.
+ BANG,
+ /// Expecting argument or end of frame.
+ COMMAND,
+ /// Expecting second hex digit of an argument.
+ ARG_DIGIT,
+ /// Quote received, expect any char.
+ ARG_CHAR,
+ /// Double quote received, read a string.
+ ARG_STRING,
+ };
+ Step step_;
+ /// Received message current size.
+ int size_;
+ /// Message arguments being received.
+ uint8_t args_[UCOO_CONFIG_BASE_PROTO_ARGS_MAX_SIZE];
+ /// Command being received.
+ char cmd_;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_base_proto_proto_hh
diff --git a/ucoo/base/proto/test/Makefile b/ucoo/base/proto/test/Makefile
new file mode 100644
index 0000000..f02be13
--- /dev/null
+++ b/ucoo/base/proto/test/Makefile
@@ -0,0 +1,9 @@
+BASE = ../../../..
+
+TARGETS = host stm32f4
+PROGS = test_proto
+test_proto_SOURCES = test_proto.cc
+
+MODULES = base/proto base/test hal/usb
+
+include $(BASE)/build/top.mk
diff --git a/ucoo/base/proto/test/test_proto.cc b/ucoo/base/proto/test/test_proto.cc
new file mode 100644
index 0000000..9a11233
--- /dev/null
+++ b/ucoo/base/proto/test/test_proto.cc
@@ -0,0 +1,67 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/base/proto/proto.hh"
+
+#include "ucoo/arch/arch.hh"
+#include "ucoo/base/test/test.hh"
+
+class TestProto : public ucoo::Proto::Handler
+{
+ public:
+ void proto_handle (ucoo::Proto &proto, char cmd,
+ const uint8_t *args, int size)
+ {
+#define c(cmd, size) ((cmd) << 8 | (size))
+ switch (c (cmd, size))
+ {
+ // Receive various format.
+ case c ('a', 1):
+ case c ('a', 4):
+ case c ('b', 8):
+ // Send various formats.
+ proto.send ('h', "hh", -1, 1);
+ proto.send ('e', "B", 0xf0);
+ proto.send ('l', "HBB", 0x1234, 0x56, 0x78);
+ proto.send ('o', "L", 0x87654321u);
+ break;
+ default:
+ // Error, unknown command.
+ proto.send ('?');
+ return;
+ }
+ proto.send_buf (cmd, args, size);
+ }
+};
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ ucoo::Stream &s = ucoo::test_stream ();
+ TestProto test_proto;
+ ucoo::Proto proto (test_proto, s);
+ while (1)
+ proto.accept ();
+}
+
diff --git a/ucoo/base/stdio/Module b/ucoo/base/stdio/Module
new file mode 100644
index 0000000..f9cffeb
--- /dev/null
+++ b/ucoo/base/stdio/Module
@@ -0,0 +1 @@
+base_stdio_SOURCES := stdio.cc
diff --git a/ucoo/base/stdio/stdio.cc b/ucoo/base/stdio/stdio.cc
new file mode 100644
index 0000000..91bbe00
--- /dev/null
+++ b/ucoo/base/stdio/stdio.cc
@@ -0,0 +1,68 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "stdio.hh"
+
+#include <unistd.h>
+
+namespace ucoo {
+
+/// Callback to read a stream.
+ssize_t
+stream_io_read (void *cookie, char *buf, size_t n)
+{
+ Stream *stream = static_cast<Stream *> (cookie);
+ int r = stream->read (buf, n);
+ if (r == -2)
+ return 0;
+ else
+ return r;
+}
+
+/// Callback to write a stream.
+ssize_t
+stream_io_write (void *cookie, const char *buf, size_t n)
+{
+ Stream *stream = static_cast<Stream *> (cookie);
+ int r = stream->write (buf, n);
+ return r;
+}
+
+/// Table of callback for fopencookie.
+static const cookie_io_functions_t stream_io_functions =
+{
+ stream_io_read,
+ stream_io_write,
+ NULL,
+ NULL,
+};
+
+FILE *
+fstreamopen (Stream &stream, const char *mode)
+{
+ // fopencookie is a glibc extension also implemented in newlib, nice!
+ return fopencookie (static_cast<void *> (&stream), mode,
+ stream_io_functions);
+}
+
+} // namespace ucoo
diff --git a/ucoo/base/stdio/stdio.hh b/ucoo/base/stdio/stdio.hh
new file mode 100644
index 0000000..b56736a
--- /dev/null
+++ b/ucoo/base/stdio/stdio.hh
@@ -0,0 +1,39 @@
+#ifndef ucoo_base_stdio_stdio_hh
+#define ucoo_base_stdio_stdio_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/stream.hh"
+
+#include <cstdio>
+
+namespace ucoo {
+
+/// Open a stdio stream connecter to STREAM. The MODE parameter uses the same
+/// syntax as stdio fopen.
+FILE *
+fstreamopen (Stream &stream, const char *mode);
+
+} // namespace ucoo
+
+#endif // ucoo_base_stdio_stdio_hh
diff --git a/ucoo/base/test/Config b/ucoo/base/test/Config
new file mode 100644
index 0000000..133808b
--- /dev/null
+++ b/ucoo/base/test/Config
@@ -0,0 +1,5 @@
+[base/test]
+wait = false
+
+[base/test:stm32]
+wait = true
diff --git a/ucoo/base/test/Module b/ucoo/base/test/Module
new file mode 100644
index 0000000..9a3c77b
--- /dev/null
+++ b/ucoo/base/test/Module
@@ -0,0 +1 @@
+base_test_SOURCES := test.cc test.host.cc test.stm32.cc
diff --git a/ucoo/base/test/test.cc b/ucoo/base/test/test.cc
new file mode 100644
index 0000000..4f2e8f0
--- /dev/null
+++ b/ucoo/base/test/test.cc
@@ -0,0 +1,118 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "test.hh"
+
+#include "ucoo/common.hh"
+#include "ucoo/base/stdio/stdio.hh"
+#include "ucoo/utils/delay.hh"
+
+#include "config/base/test.hh"
+
+#include <cstdarg>
+
+namespace ucoo {
+
+TestSuite::TestSuite (const char *test_suite)
+ : test_suite_ (test_suite), test_group_ ("none"),
+ test_nb_ (0), fail_nb_ (0), in_test_ (false)
+{
+ test_stream_setup ();
+ if (UCOO_CONFIG_BASE_TEST_WAIT)
+ {
+ Stream &s = test_stream ();
+ int n;
+ char b;
+ s.block (false);
+ do
+ {
+ printf ("waiting to start...\n");
+ delay (1);
+ n = s.read (&b, 1);
+ } while (n <= 0);
+ s.block ();
+ }
+}
+
+bool
+TestSuite::report ()
+{
+ assert (!in_test_);
+ printf ("test results: %d tests, %d fails\n", test_nb_, fail_nb_);
+ return fail_nb_ == 0;
+}
+
+void
+TestSuite::group (const char *test_group)
+{
+ test_group_ = test_group;
+}
+
+Test::Test (TestSuite &suite, const char *test)
+ : suite_ (suite), test_ (test), failed_ (false)
+{
+ assert (!suite_.in_test_);
+ suite_.in_test_ = true;
+ suite_.test_nb_++;
+}
+
+Test::~Test (void)
+{
+ if (!failed_)
+ printf ("%s:%s:%s:P: pass\n", suite_.test_suite_, suite_.test_group_,
+ test_);
+ suite_.in_test_ = false;
+}
+
+void
+Test::fail ()
+{
+ fail ("fail");
+}
+
+void
+Test::fail (const char *fail_fmt, ...)
+{
+ va_list ap;
+ assert (!failed_);
+ printf ("%s:%s:%s:F: ", suite_.test_suite_, suite_.test_group_, test_);
+ va_start (ap, fail_fmt);
+ vprintf (fail_fmt, ap);
+ va_end (ap);
+ putchar ('\n');
+ suite_.fail_nb_++;
+ failed_ = true;
+}
+
+void
+Test::info (const char *info_fmt, ...)
+{
+ va_list ap;
+ printf ("%s:%s:%s:I: ", suite_.test_suite_, suite_.test_group_, test_);
+ va_start (ap, info_fmt);
+ vprintf (info_fmt, ap);
+ va_end (ap);
+ putchar ('\n');
+}
+
+} // namespace ucoo
diff --git a/ucoo/base/test/test.hh b/ucoo/base/test/test.hh
new file mode 100644
index 0000000..fd8ac32
--- /dev/null
+++ b/ucoo/base/test/test.hh
@@ -0,0 +1,99 @@
+#ifndef ucoo_base_test_test_hh
+#define ucoo_base_test_test_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/stream.hh"
+
+/// Test helpers to fail and break to end of current block.
+#define test_fail_break_unless(test, cond) \
+ ({ if (!(cond)) { \
+ test.fail (#cond); \
+ break; \
+ } })
+
+namespace ucoo {
+
+/// Get a reference to test stream. This stream is the preferred way to
+/// interact with a tester.
+Stream &
+test_stream (void);
+
+/// Setup stdin and stdout to use the reference test stream. On host, this
+/// function does nothing.
+void
+test_stream_setup (void);
+
+/// Test suite context.
+class TestSuite
+{
+ public:
+ /// Create a new test suite.
+ TestSuite (const char *test_suite);
+ /// Report the overall test results, return true if all tests passed.
+ bool report ();
+ /// Enter a new test group.
+ void group (const char *test_group);
+ private:
+ friend class Test;
+ /// Test suite name.
+ const char *test_suite_;
+ /// Test group name.
+ const char *test_group_;
+ /// Number of attempted tests.
+ int test_nb_;
+ /// Number of test failures.
+ int fail_nb_;
+ /// Running a test.
+ bool in_test_;
+};
+
+/// Test context.
+class Test
+{
+ public:
+ /// Start a new test, may be followed by fail, test stops at object
+ /// destruction.
+ Test (TestSuite &suite, const char *test);
+ /// Stop a test.
+ ~Test (void);
+ /// End the current test with a fail status.
+ void fail ();
+ /// End the current test with a fail status and message.
+ void __attribute__ ((format (printf, 2, 3)))
+ fail (const char *fail_fmt, ...);
+ /// Give info about the current test.
+ void __attribute__ ((format (printf, 2, 3)))
+ info (const char *info_fmt, ...);
+ private:
+ /// Attached test suite.
+ TestSuite &suite_;
+ /// Test name.
+ const char *test_;
+ /// Failed yet.
+ bool failed_;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_base_test_test_hh
diff --git a/ucoo/base/test/test.host.cc b/ucoo/base/test/test.host.cc
new file mode 100644
index 0000000..d43d235
--- /dev/null
+++ b/ucoo/base/test/test.host.cc
@@ -0,0 +1,42 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "test.hh"
+
+#include "ucoo/arch/host/host_stream.hh"
+
+namespace ucoo {
+
+Stream &
+test_stream (void)
+{
+ static HostStream s;
+ return s;
+}
+
+void
+test_stream_setup (void)
+{
+}
+
+} // namespace ucoo
diff --git a/ucoo/base/test/test.stm32.cc b/ucoo/base/test/test.stm32.cc
new file mode 100644
index 0000000..3961a70
--- /dev/null
+++ b/ucoo/base/test/test.stm32.cc
@@ -0,0 +1,48 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "test.hh"
+
+#include "ucoo/hal/usb/usb.hh"
+#include "ucoo/arch/syscalls.newlib.hh"
+
+namespace ucoo {
+
+Stream &
+test_stream (void)
+{
+ static UsbStreamControl usc ("APBTeam", "test");
+ static UsbStream us (usc, 0);
+ return us;
+}
+
+void
+test_stream_setup (void)
+{
+ Stream *s = &test_stream ();
+ syscalls_streams[0] = s;
+ syscalls_streams[1] = s;
+ syscalls_streams[2] = s;
+}
+
+} // namespace ucoo
diff --git a/ucoo/base/test/test/Makefile b/ucoo/base/test/test/Makefile
new file mode 100644
index 0000000..610c71a
--- /dev/null
+++ b/ucoo/base/test/test/Makefile
@@ -0,0 +1,9 @@
+BASE = ../../../..
+
+TARGETS = host stm32f4
+PROGS = test_test
+test_test_SOURCES = test_test.cc
+
+MODULES = utils base/test hal/usb
+
+include $(BASE)/build/top.mk
diff --git a/ucoo/base/test/test/test_test.cc b/ucoo/base/test/test/test_test.cc
new file mode 100644
index 0000000..dcc6b76
--- /dev/null
+++ b/ucoo/base/test/test/test_test.cc
@@ -0,0 +1,48 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/base/test/test.hh"
+#include "ucoo/arch/arch.hh"
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ ucoo::TestSuite test_suite ("test_test");
+ // Really, what a dumb test!
+ test_suite.group ("group one");
+ {
+ ucoo::Test test (test_suite, "the first test");
+ test.fail ("Oh no! test %d!", 123);
+ }
+ {
+ ucoo::Test test (test_suite, "try again");
+ test.info ("working harder...");
+ }
+ test_suite.group ("group two");
+ {
+ ucoo::Test test (test_suite, "simple test");
+ }
+ return test_suite.report () ? 0 : 1;
+}
+
diff --git a/ucoo/common.hh b/ucoo/common.hh
new file mode 100644
index 0000000..282041f
--- /dev/null
+++ b/ucoo/common.hh
@@ -0,0 +1,91 @@
+#ifndef ucoo_common_hh
+#define ucoo_common_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include <stdint.h>
+
+#include "ucoo/arch/arch_common.hh"
+
+namespace ucoo {
+
+/// Integer which is read and written atomically.
+typedef int int_atomic_t;
+
+/// Compiler barrier. Prevents the compiler from moving the memory accesses
+/// from one side of it to the other side.
+extern inline void
+barrier ()
+{
+ __asm__ __volatile__("": : : "memory");
+}
+
+/// Ensure a single access is done, avoid compiler optimisations.
+template<typename T>
+extern inline volatile T &
+access_once (T &x)
+{
+ return *static_cast<volatile T *> (&x);
+}
+
+/// Stop, abruptly.
+void
+halt () __attribute__ ((noreturn));
+
+/// Stop, try to output error description corresponding to errno.
+void
+halt_perror () __attribute__ ((noreturn));
+
+/// To be used to swear that the given condition is true. If this is not the
+/// case... well... you swore!
+extern inline void
+assert (bool condition)
+{
+ if (!__builtin_expect (condition, 1))
+ halt ();
+}
+
+/// To be used to swear that this code can never be reached.
+void
+assert_unreachable () __attribute__ ((noreturn));
+extern inline void
+assert_unreachable ()
+{
+ halt ();
+}
+
+/// To be used to swear that the given condition is true, but print errno
+/// description anyway in case you lied.
+extern inline void
+assert_perror (bool condition)
+{
+ if (!__builtin_expect (condition, 1))
+ halt_perror ();
+}
+
+} // namespace ucoo
+
+/// Get array length at compile time, must be a macro until c++11.
+#define lengthof(array) (sizeof (array) / sizeof((array)[0]))
+
+#endif // ucoo_common_h
diff --git a/ucoo/dev/avrisp/Config b/ucoo/dev/avrisp/Config
new file mode 100644
index 0000000..cf3eb48
--- /dev/null
+++ b/ucoo/dev/avrisp/Config
@@ -0,0 +1,6 @@
+[dev/avrisp]
+frame_buffer_size = 281
+proto_signature = "APBisp_2"
+proto_build_number = 0x0100
+proto_hw_version = 0x02
+proto_sw_version = 0x0204
diff --git a/ucoo/dev/avrisp/Module b/ucoo/dev/avrisp/Module
new file mode 100644
index 0000000..d66f06f
--- /dev/null
+++ b/ucoo/dev/avrisp/Module
@@ -0,0 +1 @@
+dev_avrisp_SOURCES := avrisp.cc avrisp_proto.cc avrisp_frame.cc
diff --git a/ucoo/dev/avrisp/avrisp.cc b/ucoo/dev/avrisp/avrisp.cc
new file mode 100644
index 0000000..80c92a8
--- /dev/null
+++ b/ucoo/dev/avrisp/avrisp.cc
@@ -0,0 +1,452 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "avrisp.hh"
+
+#include "ucoo/utils/delay.hh"
+
+namespace ucoo {
+
+/// Command used to load extended address.
+static const uint8_t avrisp_cmd_load_extended_address = 0x4d;
+/// Bit to address high byte.
+static const uint8_t avrisp_cmd_high_byte = 1 << 3;
+/// Extra EEPROM programming delay.
+static const int avrisp_eeprom_delay_ms = 2;
+/// Miscellaneous read delay.
+static const int avrisp_misc_read_delay_ms = 5;
+
+AvrIsp::AvrIsp (AvrIspIntf &intf)
+ : intf_ (intf)
+{
+}
+
+AvrIspResult
+AvrIsp::enter_progmode (uint8_t sck_duration_us, uint8_t timeout_ms,
+ uint8_t stab_delay_ms, uint8_t cmd_exe_delay_ms,
+ uint8_t synch_loops, uint8_t byte_delay_ms,
+ uint8_t poll_value, uint8_t poll_index,
+ const uint8_t cmd[4])
+{
+ int i;
+ uint8_t tmp1, tmp2;
+ // Reset context.
+ ext_addr_ = 0;
+ last_ext_addr_ = 0xff;
+ larger_than_64k_ = 0;
+ bytes_left_ = 0;
+ // Enable SPI.
+ intf_.enable (sck_duration_us);
+ delay_ms (stab_delay_ms);
+ // Limit the number of loops.
+ if (synch_loops > 48)
+ synch_loops = 48;
+ // Minimum byte delay.
+ if (byte_delay_ms < 1)
+ byte_delay_ms = 1;
+ // Synchronisation loops.
+ for (i = 0; i < synch_loops; i++)
+ {
+ delay_ms (cmd_exe_delay_ms);
+ intf_.send_and_recv (cmd[0]);
+ delay_ms (byte_delay_ms);
+ intf_.send_and_recv (cmd[1]);
+ delay_ms (byte_delay_ms);
+ tmp1 = intf_.send_and_recv (cmd[2]);
+ delay_ms (byte_delay_ms);
+ tmp2 = intf_.send_and_recv (cmd[3]);
+ // Test success.
+ if (poll_index == 0
+ || (poll_index == 3 && tmp1 == poll_value)
+ || (poll_index != 3 && tmp2 == poll_value))
+ return AVRISP_OK;
+ // Else, new try.
+ intf_.sck_pulse ();
+ delay_ms (20);
+ }
+ return AVRISP_FAILED;
+}
+
+void
+AvrIsp::leave_progmode (uint8_t pre_delay_ms, uint8_t post_delay_ms)
+{
+ delay_ms (pre_delay_ms);
+ intf_.disable ();
+ delay_ms (post_delay_ms);
+}
+
+void
+AvrIsp::load_address (uint32_t addr)
+{
+ addr_ = addr & 0xffff;
+ ext_addr_ = (addr >> 16) & 0xff;
+ last_ext_addr_ = 0xff;
+ larger_than_64k_ = (addr & 0x80000000) ? 1 : 0;
+}
+
+AvrIspResult
+AvrIsp::chip_erase (uint8_t erase_delay_ms, uint8_t poll_method,
+ const uint8_t cmd[4])
+{
+ int tries;
+ intf_.send_and_recv (cmd[0]);
+ intf_.send_and_recv (cmd[1]);
+ intf_.send_and_recv (cmd[2]);
+ intf_.send_and_recv (cmd[3]);
+ if (poll_method == 0)
+ {
+ // Use delay.
+ delay_ms (erase_delay_ms);
+ }
+ else
+ {
+ // Use RDY/BSY command.
+ tries = 150;
+ while ((spi_tx_32 (0xf0000000) & 1) && tries)
+ tries--;
+ if (tries == 0)
+ return AVRISP_TIMEOUT;
+ }
+ return AVRISP_OK;
+}
+
+AvrIspResult
+AvrIsp::program_begin (uint16_t num_bytes, uint8_t mode, uint8_t delay_ms,
+ uint8_t cmd_write_mem, uint8_t cmd_write_page,
+ uint8_t cmd_read_mem, const uint8_t poll[2],
+ uint8_t flash)
+{
+ // Set delay bounds.
+ if (delay_ms < 4)
+ delay_ms = 4;
+ if (delay_ms > 32)
+ delay_ms = 32;
+ // Check data size.
+ if (flash && (num_bytes & 1))
+ return AVRISP_FAILED;
+ // Store parameters.
+ start_addr_ = addr_;
+ bytes_left_ = num_bytes;
+ mode_ = mode;
+ delay_ms_ = delay_ms;
+ cmd_write_mem_ = cmd_write_mem;
+ cmd_write_page_ = cmd_write_page;
+ cmd_read_mem_ = cmd_read_mem;
+ poll_[0] = poll[0];
+ poll_[1] = poll[1];
+ pollable_ = 0;
+ flash_ = flash;
+ return AVRISP_OK;
+}
+
+AvrIspResult
+AvrIsp::program_flash_begin (uint16_t num_bytes, uint8_t mode,
+ uint8_t delay_ms, uint8_t cmd_write_mem,
+ uint8_t cmd_write_page, uint8_t cmd_read_mem,
+ const uint8_t poll[2])
+{
+ return program_begin (num_bytes, mode, delay_ms, cmd_write_mem,
+ cmd_write_page, cmd_read_mem, poll, 1);
+}
+
+AvrIspResult
+AvrIsp::program_eeprom_begin (uint16_t num_bytes, uint8_t mode,
+ uint8_t delay_ms, uint8_t cmd_write_mem,
+ uint8_t cmd_write_page, uint8_t cmd_read_mem,
+ const uint8_t poll[2])
+{
+ return program_begin (num_bytes, mode, delay_ms, cmd_write_mem,
+ cmd_write_page, cmd_read_mem, poll, 0);
+}
+
+AvrIspResult
+AvrIsp::program_continue (const uint8_t *data, uint16_t size)
+{
+ uint16_t i;
+ uint8_t read;
+ int tries;
+ // Check size.
+ if (size > bytes_left_ || (flash_ && (size & 1)))
+ return AVRISP_FAILED;
+ bytes_left_ -= size;
+ // Loop on each input bytes.
+ for (i = 0; i < size; i++)
+ {
+ // Check for Load Extended Address.
+ if (larger_than_64k_ && last_ext_addr_ != ext_addr_)
+ {
+ intf_.send_and_recv (avrisp_cmd_load_extended_address);
+ intf_.send_and_recv (0x00);
+ intf_.send_and_recv (ext_addr_);
+ intf_.send_and_recv (0x00);
+ last_ext_addr_ = ext_addr_;
+ }
+ // Write memory/load page, using bit 3 as byte selector.
+ if (flash_ && (i & 1))
+ intf_.send_and_recv (cmd_write_mem_ | avrisp_cmd_high_byte);
+ else
+ intf_.send_and_recv (cmd_write_mem_);
+ spi_tx_16 (addr_);
+ intf_.send_and_recv (data[i]);
+ // EEPROM needs more delay.
+ if (!flash_)
+ delay_ms (avrisp_eeprom_delay_ms);
+ // Poll.
+ if (!(mode_ & AVRISP_MODE_PAGE))
+ {
+ // Poll right now.
+ tries = 150;
+ read = poll_[0];
+ if ((mode_ & AVRISP_MODE_WORD_VALUE) && data[i] != read)
+ {
+ // Poll by reading byte.
+ while (read != data[i] && tries)
+ {
+ if (flash_ && (i & 1))
+ intf_.send_and_recv (cmd_read_mem_
+ | avrisp_cmd_high_byte);
+ else
+ intf_.send_and_recv (cmd_read_mem_);
+ spi_tx_16 (addr_);
+ read = intf_.send_and_recv (0x00);
+ tries--;
+ }
+ }
+ else if (mode_ & AVRISP_MODE_WORD_RDY_BSY)
+ {
+ // RDY/BSY polling.
+ while ((spi_tx_32 (0xf0000000) & 1) && tries)
+ tries--;
+ }
+ else
+ // Simple delay.
+ delay_ms (delay_ms_);
+ if (tries == 0)
+ return AVRISP_TIMEOUT;
+ }
+ else
+ {
+ // Check for poll method.
+ if (!pollable_ && data[i] != poll_[0])
+ {
+ pollable_ = 0x02 | (i & 1);
+ poll_addr_ = addr_;
+ }
+ }
+ // Increment address.
+ if (!flash_ || (i & 1))
+ {
+ addr_++;
+ if (addr_ == 0)
+ ext_addr_++;
+ }
+ }
+ return AVRISP_OK;
+}
+
+AvrIspResult
+AvrIsp::program_end ()
+{
+ uint8_t read;
+ int tries;
+ // Check size.
+ if (bytes_left_ != 0)
+ return AVRISP_FAILED;
+ // Write page if requested.
+ if ((mode_ & (AVRISP_MODE_PAGE | AVRISP_MODE_PAGE_WRITE))
+ == (AVRISP_MODE_PAGE | AVRISP_MODE_PAGE_WRITE))
+ {
+ // Write page.
+ intf_.send_and_recv (cmd_write_page_);
+ spi_tx_16 (start_addr_);
+ intf_.send_and_recv (0x00);
+ // EEPROM needs more delay.
+ if (!flash_)
+ delay_ms (avrisp_eeprom_delay_ms);
+ // Poll.
+ tries = 150;
+ read = poll_[0];
+ if ((mode_ & AVRISP_MODE_PAGE_VALUE) && pollable_)
+ {
+ // Poll by reading byte.
+ while (read == poll_[0] && tries)
+ {
+ if (flash_ && (pollable_ & 1))
+ intf_.send_and_recv (cmd_read_mem_ | avrisp_cmd_high_byte);
+ else
+ intf_.send_and_recv (cmd_read_mem_);
+ spi_tx_16 (poll_addr_);
+ read = intf_.send_and_recv (0x00);
+ tries--;
+ }
+ }
+ else if (mode_ & AVRISP_MODE_PAGE_RDY_BSY)
+ {
+ // RDY/BSY polling.
+ while ((spi_tx_32 (0xf0000000) & 1) && tries)
+ tries--;
+ }
+ else
+ // Simple delay.
+ delay_ms (delay_ms_);
+ if (tries == 0)
+ return AVRISP_TIMEOUT;
+ }
+ return AVRISP_OK;
+}
+
+AvrIspResult
+AvrIsp::read_begin (uint16_t num_bytes, uint8_t cmd_read_mem, uint8_t flash)
+{
+ // Check data size.
+ if (flash && (num_bytes & 1))
+ return AVRISP_FAILED;
+ // Store parameters.
+ bytes_left_ = num_bytes;
+ cmd_read_mem_ = cmd_read_mem;
+ flash_ = flash;
+ return AVRISP_OK;
+}
+
+AvrIspResult
+AvrIsp::read_flash_begin (uint16_t num_bytes, uint8_t cmd_read_mem)
+{
+ return read_begin (num_bytes, cmd_read_mem, 1);
+}
+
+AvrIspResult
+AvrIsp::read_eeprom_begin (uint16_t num_bytes, uint8_t cmd_read_mem)
+{
+ return read_begin (num_bytes, cmd_read_mem, 0);
+}
+
+AvrIspResult
+AvrIsp::read_continue (uint8_t *data, uint16_t size)
+{
+ uint16_t i;
+ // Check size.
+ if (size > bytes_left_ || (flash_ && (size & 1)))
+ return AVRISP_FAILED;
+ bytes_left_ -= size;
+ // Loop on each bytes.
+ for (i = 0; i < size; i++)
+ {
+ // Check for Load Extended Address.
+ if (larger_than_64k_ && last_ext_addr_ != ext_addr_)
+ {
+ intf_.send_and_recv (avrisp_cmd_load_extended_address);
+ intf_.send_and_recv (0x00);
+ intf_.send_and_recv (ext_addr_);
+ intf_.send_and_recv (0x00);
+ last_ext_addr_ = ext_addr_;
+ }
+ // Read memory, using bit 3 as byte selector.
+ if (flash_ && (i & 1))
+ intf_.send_and_recv (cmd_read_mem_ | avrisp_cmd_high_byte);
+ else
+ intf_.send_and_recv (cmd_read_mem_);
+ spi_tx_16 (addr_);
+ data[i] = intf_.send_and_recv (0x00);
+ // Increment address.
+ if (!flash_ || (i & 1))
+ {
+ addr_++;
+ if (addr_ == 0)
+ ext_addr_++;
+ }
+ }
+ return AVRISP_OK;
+}
+
+AvrIspResult
+AvrIsp::read_end ()
+{
+ // Check size.
+ if (bytes_left_ != 0)
+ return AVRISP_FAILED;
+ return AVRISP_OK;
+}
+
+void
+AvrIsp::program_misc (const uint8_t cmd[4])
+{
+ uint8_t i;
+ for (i = 0; i < 4; i++)
+ intf_.send_and_recv (cmd[i]);
+}
+
+uint8_t
+AvrIsp::read_misc (uint8_t ret_addr, const uint8_t cmd[4])
+{
+ uint8_t i, read = 0, tmp;
+ for (i = 0; i < 4; i++)
+ {
+ tmp = intf_.send_and_recv (cmd[i]);
+ if (i == ret_addr)
+ read = tmp;
+ delay_ms (avrisp_misc_read_delay_ms);
+ }
+ return read;
+}
+
+void
+AvrIsp::multi (uint8_t num_tx, uint8_t num_rx, uint8_t rx_start,
+ const uint8_t *dout, uint8_t *din)
+{
+ uint8_t in, out;
+ while (num_tx || num_rx)
+ {
+ out = 0;
+ if (num_tx)
+ {
+ out = *dout++;
+ num_tx--;
+ }
+ in = intf_.send_and_recv (out);
+ if (rx_start)
+ rx_start--;
+ else if (num_rx)
+ {
+ *din++ = in;
+ num_rx--;
+ }
+ }
+}
+
+void
+AvrIsp::spi_tx_16 (uint16_t data)
+{
+ intf_.send_and_recv ((data >> 8) & 0xff);
+ intf_.send_and_recv ((data >> 0) & 0xff);
+}
+
+uint8_t
+AvrIsp::spi_tx_32 (uint32_t data)
+{
+ intf_.send_and_recv ((data >> 24) & 0xff);
+ intf_.send_and_recv ((data >> 16) & 0xff);
+ intf_.send_and_recv ((data >> 8) & 0xff);
+ return intf_.send_and_recv ((data >> 0) & 0xff);
+}
+
+} // namespace ucoo
diff --git a/ucoo/dev/avrisp/avrisp.hh b/ucoo/dev/avrisp/avrisp.hh
new file mode 100644
index 0000000..2c686b0
--- /dev/null
+++ b/ucoo/dev/avrisp/avrisp.hh
@@ -0,0 +1,247 @@
+#ifndef ucoo_dev_avrisp_avrisp_hh
+#define ucoo_dev_avrisp_avrisp_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/common.hh"
+
+namespace ucoo {
+
+/// Results returned by ISP functions.
+enum AvrIspResult
+{
+ /// Operation success.
+ AVRISP_OK,
+ /// Operation failed.
+ AVRISP_FAILED,
+ /// Operation failed on a timeout.
+ AVRISP_TIMEOUT,
+};
+
+/// ISP Programming mode.
+enum AvrIspMode
+{
+ /// Use page programming.
+ AVRISP_MODE_PAGE = 1,
+ /// Use simple delay for word programming.
+ AVRISP_MODE_WORD_DELAY = 2,
+ /// Use value polling if possible for word programming, fall back to delay
+ /// if not possible.
+ AVRISP_MODE_WORD_VALUE = 4,
+ /// Use RDY/BSY polling for word programming.
+ AVRISP_MODE_WORD_RDY_BSY = 8,
+ /// Use simple delay for page programming.
+ AVRISP_MODE_PAGE_DELAY = 16,
+ /// Use value polling if possible for page programming, fall back to delay
+ /// if not possible.
+ AVRISP_MODE_PAGE_VALUE = 32,
+ /// Use RDY/BSY polling for page programming.
+ AVRISP_MODE_PAGE_RDY_BSY = 64,
+ /// Write page at end of transfer. Used for big pages which must be
+ /// transfered in several packets.
+ AVRISP_MODE_PAGE_WRITE = 128,
+};
+
+/// Interface to hardware connection.
+class AvrIspIntf
+{
+ public:
+ /// Send and receive one byte through SPI interface.
+ virtual uint8_t send_and_recv (uint8_t tx) = 0;
+ /// Enable programming:
+ /// - set RESET and SCK to low,
+ /// - power on, or if not possible, do a positive RESET pulse,
+ /// - enable SPI, mode 0.
+ virtual void enable (uint8_t sck_duration_us) = 0;
+ /// Disable programming:
+ /// - disable SPI,
+ /// - release RESET,
+ /// - power off if desired.
+ virtual void disable () = 0;
+ /// Do a pulse on SCK. This is used to try to resynchronise.
+ virtual void sck_pulse () = 0;
+};
+
+/// AVR serial programming.
+class AvrIsp
+{
+ public:
+ /// Constructor.
+ AvrIsp (AvrIspIntf &intf);
+ /// Enable SPI port and enter programing mode.
+ /// - sck_duration_us: SCK period.
+ /// - timeout_ms: command time-out, unused.
+ /// - stab_delay_ms: stabilisation delay once device is reseted and SPI
+ /// initialised.
+ /// - cmd_exe_delay_ms: delay for the command execution.
+ /// - synch_loops: number of synchronisation loops (there is no start of
+ /// frame in SPI).
+ /// - byte_delay_ms: delay between each byte.
+ /// - poll_value: value to read to consider the sequence is correct.
+ /// - poll_index: transfer index at which the poll_value must be read.
+ /// - cmd: command bytes to be transfered.
+ /// - returns: AVRISP_OK or AVRISP_FAILED if no synchronisation.
+ AvrIspResult enter_progmode (uint8_t sck_duration_us,
+ uint8_t timeout_ms, uint8_t stab_delay_ms,
+ uint8_t cmd_exe_delay_ms,
+ uint8_t synch_loops, uint8_t byte_delay_ms,
+ uint8_t poll_value, uint8_t poll_index,
+ const uint8_t cmd[4]);
+ /// Leave programming mode and disable SPI port.
+ /// - pre_delay_ms: delay before disabling.
+ /// - post_delay_ms: delay after disabling.
+ void leave_progmode (uint8_t pre_delay_ms, uint8_t post_delay_ms);
+ /// Load programing address.
+ /// - addr: address to load, bit 31 means the device has more than 64k
+ /// words and extended addressing should be used.
+ void load_address (uint32_t addr);
+ /// Chip full erase.
+ /// - erase_delay_ms: delay to ensure the erase is finished.
+ /// - poll_method: use delay (0) or RDY/BSY polling (1).
+ /// - cmd: chip erase command.
+ /// - returns: AVRISP_OK or AVRISP_TIMEOUT if using polling and it
+ /// timed-out.
+ AvrIspResult chip_erase (uint8_t erase_delay_ms, uint8_t poll_method,
+ const uint8_t cmd[4]);
+ /// Start a program command.
+ /// - num_bytes: total number of bytes to program.
+ /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters.
+ /// See class for other parameters meaning.
+ AvrIspResult program_begin (uint16_t num_bytes, uint8_t mode,
+ uint8_t delay_ms, uint8_t cmd_write_mem,
+ uint8_t cmd_write_page, uint8_t cmd_read_mem,
+ const uint8_t poll[2], uint8_t flash);
+ /// Start a flash memory program command.
+ /// - num_bytes: total number of bytes to program.
+ /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters.
+ /// See class for other parameters meaning.
+ AvrIspResult program_flash_begin (uint16_t num_bytes, uint8_t mode,
+ uint8_t delay_ms, uint8_t cmd_write_mem,
+ uint8_t cmd_write_page,
+ uint8_t cmd_read_mem,
+ const uint8_t poll[2]);
+ /// Start a EEPROM memory program command.
+ /// - num_bytes: total number of bytes to program.
+ /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters.
+ /// See class for other parameters meaning.
+ AvrIspResult program_eeprom_begin (uint16_t num_bytes,
+ uint8_t mode,
+ uint8_t delay_ms,
+ uint8_t cmd_write_mem,
+ uint8_t cmd_write_page,
+ uint8_t cmd_read_mem,
+ const uint8_t poll[2]);
+ /// Provide data for memory programming. Data should be given by even
+ /// sized packs or loading of word addressed data will fail.
+ /// - returns: AVRISP_OK, AVRISP_FAILED for bad parameters or
+ /// AVRISP_TIMEOUT if using polling and it timed-out.
+ AvrIspResult program_continue (const uint8_t *data, uint16_t size);
+ /// End program command.
+ /// - returns: AVRISP_OK, AVRISP_FAILED if too early or AVRISP_TIMEOUT if
+ /// using polling and it timed-out.
+ AvrIspResult program_end ();
+ /// Start a read command.
+ /// - num_bytes: total number of bytes to program.
+ /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters.
+ /// See class for other parameters meaning.
+ AvrIspResult read_begin (uint16_t num_bytes, uint8_t cmd_read_mem,
+ uint8_t flash);
+ /// Start a flash memory read command.
+ /// - num_bytes: total number of bytes to program.
+ /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters.
+ /// See class for other parameters meaning.
+ AvrIspResult read_flash_begin (uint16_t num_bytes, uint8_t cmd_read_mem);
+ /// Start a EEPROM memory read command.
+ /// - num_bytes: total number of bytes to program.
+ /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters.
+ /// See class for other parameters meaning.
+ AvrIspResult read_eeprom_begin (uint16_t num_bytes, uint8_t cmd_read_mem);
+ /// Get data from read memory. Data should be read by even sized packs or
+ /// loading of word addressed data will fail.
+ /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters.
+ AvrIspResult read_continue (uint8_t *data, uint16_t size);
+ /// End read command.
+ /// - returns: AVRISP_OK or AVRISP_FAILED if too early.
+ AvrIspResult read_end ();
+ /// Program miscellaneous memory (fuse, lock).
+ /// - cmd: program command.
+ void program_misc (const uint8_t cmd[4]);
+ /// Read miscellaneous memory (fuse, lock, signature, osccal).
+ /// - ret_addr: transfer index at which the return value must be read.
+ /// - cmd: read command.
+ uint8_t read_misc (uint8_t ret_addr, const uint8_t cmd[4]);
+ /// Generic SPI access.
+ /// - num_tx: number of bytes to transmit.
+ /// - num_rx: number of bytes to receive.
+ /// - rx_start: start reception after this number of transmitted bytes.
+ /// - dout: buffer to read sent bytes.
+ /// - din: buffer to write received bytes.
+ /// Limitation: no support for doing this in several chunks as memory
+ /// programing and reading.
+ void multi (uint8_t num_tx, uint8_t num_rx, uint8_t rx_start,
+ const uint8_t *dout, uint8_t *din);
+ private:
+ /// Transmit a 16 bit data.
+ void spi_tx_16 (uint16_t data);
+ /// Transmit a 32 bit data and return last byte received. This is used for
+ /// RDY/BSY polling.
+ uint8_t spi_tx_32 (uint32_t data);
+ private:
+ /// Hardware interface.
+ AvrIspIntf &intf_;
+ /// Current address.
+ uint16_t addr_;
+ /// Current extended address.
+ uint8_t ext_addr_;
+ /// Extended address loaded in device.
+ uint8_t last_ext_addr_;
+ /// Whether the device needs extended addressing.
+ uint8_t larger_than_64k_;
+ /// Programming start address (used for page program command).
+ uint16_t start_addr_;
+ /// Number of bytes left to process.
+ uint16_t bytes_left_;
+ /// Programming mode.
+ uint8_t mode_;
+ /// Programming delay if no other poll method.
+ uint8_t delay_ms_;
+ /// Write Program Memory or Load Page.
+ uint8_t cmd_write_mem_;
+ /// Write Page.
+ uint8_t cmd_write_page_;
+ /// Read Program Memory.
+ uint8_t cmd_read_mem_;
+ /// Value read until memory is programmed for value polling.
+ uint8_t poll_[2];
+ /// Whether the page can be polled (if almost one byte is not poll[0]).
+ /// This is non zero if true, with LSB = 1 for high byte.
+ uint8_t pollable_;
+ /// Address to use for polling.
+ uint16_t poll_addr_;
+ /// Whether this is a flash memory.
+ uint8_t flash_;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_dev_avrisp_avrisp_hh
diff --git a/ucoo/dev/avrisp/avrisp_frame.cc b/ucoo/dev/avrisp/avrisp_frame.cc
new file mode 100644
index 0000000..4cc8c98
--- /dev/null
+++ b/ucoo/dev/avrisp/avrisp_frame.cc
@@ -0,0 +1,173 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "avrisp_frame.hh"
+
+namespace ucoo {
+
+static const uint8_t avrisp_frame_proto_start = 27;
+static const uint8_t avrisp_frame_proto_token = 14;
+static const uint8_t avrisp_frame_proto_answer_cksum_error = 0xb0;
+static const uint8_t avrisp_frame_proto_status_cksum_error = 0xc1;
+
+AvrIspFrame::AvrIspFrame (AvrIspProto &proto)
+ : proto_ (proto), state_ (AVRISP_FRAME_STATE_START), buffer_send_index_ (-1)
+{
+}
+
+void
+AvrIspFrame::read_and_write (Stream &stream)
+{
+ // Design is inherited from byte based C interface.
+ while (1)
+ {
+ if (buffer_send_index_ == -1)
+ {
+ // Read.
+ int c = stream.getc ();
+ if (c == -1)
+ return;
+ else
+ accept_char (c);
+ }
+ else
+ {
+ // Write.
+ int r = stream.write (reinterpret_cast<char *> (buffer_)
+ + buffer_send_index_,
+ buffer_len_ - buffer_send_index_);
+ if (r <= 0)
+ return;
+ else
+ buffer_send_index_ += r;
+ if (buffer_send_index_ == buffer_len_)
+ buffer_send_index_ = -1;
+ }
+ }
+}
+
+inline AvrIspFrameState
+operator++ (AvrIspFrameState& state, int)
+{
+ const int i = static_cast<int> (state);
+ state = static_cast<AvrIspFrameState> (i + 1);
+ return state;
+}
+
+void
+AvrIspFrame::accept_char (uint8_t c)
+{
+ switch (state_)
+ {
+ case AVRISP_FRAME_STATE_START:
+ if (c == avrisp_frame_proto_start)
+ {
+ cksum_ = avrisp_frame_proto_start;
+ state_++;
+ }
+ break;
+ case AVRISP_FRAME_STATE_WAIT_SEQ:
+ cksum_ ^= c;
+ seq_ = c;
+ state_++;
+ break;
+ case AVRISP_FRAME_STATE_WAIT_LEN_MSB:
+ cksum_ ^= c;
+ len_ = c << 8;
+ state_++;
+ break;
+ case AVRISP_FRAME_STATE_WAIT_LEN_LSB:
+ cksum_ ^= c;
+ len_ |= c;
+ buffer_len_ = 0;
+ if (len_ == 0
+ || len_ > (UCOO_CONFIG_DEV_AVRISP_FRAME_BUFFER_SIZE - proto_head_
+ - proto_tail_))
+ state_ = AVRISP_FRAME_STATE_START;
+ else
+ state_++;
+ break;
+ case AVRISP_FRAME_STATE_WAIT_TOKEN:
+ if (c == avrisp_frame_proto_token)
+ {
+ cksum_ ^= c;
+ state_++;
+ }
+ else
+ state_ = AVRISP_FRAME_STATE_START;
+ break;
+ case AVRISP_FRAME_STATE_DATA:
+ cksum_ ^= c;
+ buffer_[proto_head_ + buffer_len_++] = c;
+ if (buffer_len_ == len_)
+ state_++;
+ break;
+ case AVRISP_FRAME_STATE_WAIT_CKSUM:
+ cksum_ ^= c;
+ state_ = AVRISP_FRAME_STATE_START;
+ process ();
+ break;
+ }
+}
+
+void
+AvrIspFrame::send_frame (int len)
+{
+ int i = 0;
+ uint8_t cksum;
+ buffer_[i++] = avrisp_frame_proto_start;
+ cksum = avrisp_frame_proto_start;
+ buffer_[i++] = seq_;
+ cksum ^= seq_;
+ buffer_[i++] = len >> 8;
+ cksum ^= len >> 8;
+ buffer_[i++] = len & 0xff;
+ cksum ^= len & 0xff;
+ buffer_[i++] = avrisp_frame_proto_token;
+ cksum ^= avrisp_frame_proto_token;
+ for (; i < proto_head_ + len; i++)
+ cksum ^= buffer_[i];
+ buffer_[i] = cksum;
+ buffer_len_ = proto_head_ + len + proto_tail_;
+ buffer_send_index_ = 0;
+}
+
+void
+AvrIspFrame::process ()
+{
+ if (cksum_ != 0)
+ {
+ /* Bad checksum. */
+ buffer_[proto_head_] = avrisp_frame_proto_answer_cksum_error;
+ buffer_[proto_head_ + 1] = avrisp_frame_proto_status_cksum_error;
+ send_frame (2);
+ }
+ else
+ {
+ int r = proto_.accept (buffer_ + proto_head_, buffer_len_);
+ if (r)
+ send_frame (r);
+ }
+}
+
+} // namespace ucoo
diff --git a/ucoo/dev/avrisp/avrisp_frame.hh b/ucoo/dev/avrisp/avrisp_frame.hh
new file mode 100644
index 0000000..5631122
--- /dev/null
+++ b/ucoo/dev/avrisp/avrisp_frame.hh
@@ -0,0 +1,95 @@
+#ifndef ucoo_dev_avrisp_avrisp_frame_hh
+#define ucoo_dev_avrisp_avrisp_frame_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "avrisp_proto.hh"
+
+#include "ucoo/intf/stream.hh"
+
+#include "config/dev/avrisp.hh"
+
+namespace ucoo {
+
+/// State of frame decoding.
+enum AvrIspFrameState
+{
+ /// Start state, nothing decoded.
+ AVRISP_FRAME_STATE_START,
+ /// After message started, waiting sequence number.
+ AVRISP_FRAME_STATE_WAIT_SEQ,
+ /// Waiting first length byte.
+ AVRISP_FRAME_STATE_WAIT_LEN_MSB,
+ /// Waiting second length byte.
+ AVRISP_FRAME_STATE_WAIT_LEN_LSB,
+ /// Waiting token.
+ AVRISP_FRAME_STATE_WAIT_TOKEN,
+ /// Reading data.
+ AVRISP_FRAME_STATE_DATA,
+ /// Waiting checksum.
+ AVRISP_FRAME_STATE_WAIT_CKSUM,
+};
+
+/// Transfer data between a Stream and AvrIspProto which works frame by frame.
+class AvrIspFrame
+{
+ public:
+ /// Constructor.
+ AvrIspFrame (AvrIspProto &proto);
+ /// Read & write from stream. If operation on stream blocks, this will
+ /// block too.
+ void read_and_write (Stream &stream);
+ private:
+ /// Handle received char.
+ void accept_char (uint8_t c);
+ /// Send frame in buffer (actually just setup, work is done in
+ /// read_and_write()).
+ void send_frame (int len);
+ /// Process found received frame.
+ void process ();
+ private:
+ /// Frame based ISP protocol handler.
+ AvrIspProto &proto_;
+ /// Current state.
+ AvrIspFrameState state_;
+ /// Message sequence number.
+ uint8_t seq_;
+ /// Message length.
+ int len_;
+ /// Checksum current value.
+ uint8_t cksum_;
+ /// Buffer to store frame until validated.
+ uint8_t buffer_[UCOO_CONFIG_DEV_AVRISP_FRAME_BUFFER_SIZE];
+ /// Used buffer length.
+ int buffer_len_;
+ /// Index to first byte to send from buffer, or -1 if not sending.
+ int buffer_send_index_;
+ /// Size of the frame header.
+ static const uint8_t proto_head_ = 5;
+ /// Size of the frame tail.
+ static const uint8_t proto_tail_ = 1;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_dev_avrisp_avrisp_frame_hh
diff --git a/ucoo/dev/avrisp/avrisp_proto.cc b/ucoo/dev/avrisp/avrisp_proto.cc
new file mode 100644
index 0000000..bdf0457
--- /dev/null
+++ b/ucoo/dev/avrisp/avrisp_proto.cc
@@ -0,0 +1,269 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "avrisp_proto.hh"
+
+#include "ucoo/utils/bytes.hh"
+
+#include "config/dev/avrisp.hh"
+
+#include <cstring>
+#include <algorithm>
+
+namespace ucoo {
+
+/// Protocol commands.
+enum AvrIspProtoCmd
+{
+ AVRISP_PROTO_CMD_SIGN_ON = 0x01,
+ AVRISP_PROTO_CMD_SET_PARAMETER = 0x02,
+ AVRISP_PROTO_CMD_GET_PARAMETER = 0x03,
+ AVRISP_PROTO_CMD_SET_DEVICE_PARAMETERS = 0x04,
+ AVRISP_PROTO_CMD_OSCCAL = 0x05,
+ AVRISP_PROTO_CMD_LOAD_ADDRESS = 0x06,
+ AVRISP_PROTO_CMD_FIRMWARE_UPGRADE = 0x07,
+ AVRISP_PROTO_CMD_ENTER_PROGMODE_ISP = 0x10,
+ AVRISP_PROTO_CMD_LEAVE_PROGMODE_ISP = 0x11,
+ AVRISP_PROTO_CMD_CHIP_ERASE_ISP = 0x12,
+ AVRISP_PROTO_CMD_PROGRAM_FLASH_ISP = 0x13,
+ AVRISP_PROTO_CMD_READ_FLASH_ISP = 0x14,
+ AVRISP_PROTO_CMD_PROGRAM_EEPROM_ISP = 0x15,
+ AVRISP_PROTO_CMD_READ_EEPROM_ISP = 0x16,
+ AVRISP_PROTO_CMD_PROGRAM_FUSE_ISP = 0x17,
+ AVRISP_PROTO_CMD_READ_FUSE_ISP = 0x18,
+ AVRISP_PROTO_CMD_PROGRAM_LOCK_ISP = 0x19,
+ AVRISP_PROTO_CMD_READ_LOCK_ISP = 0x1a,
+ AVRISP_PROTO_CMD_READ_SIGNATURE_ISP = 0x1b,
+ AVRISP_PROTO_CMD_READ_OSCCAL_ISP = 0x1c,
+ AVRISP_PROTO_CMD_SPI_MULTI = 0x1d,
+};
+
+/// Protocol command status.
+enum AvrIspProtoStatus
+{
+ AVRISP_PROTO_STATUS_CMD_OK = 0x00,
+
+ AVRISP_PROTO_STATUS_CMD_TOUT = 0x80,
+ AVRISP_PROTO_STATUS_RDY_BSY_TOUT = 0x81,
+ AVRISP_PROTO_STATUS_SET_PARAM_MISSING = 0x82,
+
+ AVRISP_PROTO_STATUS_CMD_FAILED = 0xc0,
+ AVRISP_PROTO_STATUS_CKSUM_ERROR = 0xc1,
+ AVRISP_PROTO_STATUS_CMD_UNKNOWN = 0xc9,
+};
+
+/// Protocol parameters.
+enum AvrIspProtoParam
+{
+ AVRISP_PROTO_PARAM_BUILD_NUMBER_LOW = 0x80,
+ AVRISP_PROTO_PARAM_BUILD_NUMBER_HIGH = 0x81,
+ AVRISP_PROTO_PARAM_HW_VER = 0x90,
+ AVRISP_PROTO_PARAM_SW_MAJOR = 0x91,
+ AVRISP_PROTO_PARAM_SW_MINOR = 0x92,
+ AVRISP_PROTO_PARAM_VTARGET = 0x94,
+ AVRISP_PROTO_PARAM_VADJUST = 0x95,
+ AVRISP_PROTO_PARAM_OSC_PSCALE = 0x96,
+ AVRISP_PROTO_PARAM_OSC_CMATCH = 0x97,
+ AVRISP_PROTO_PARAM_SCK_DURATION = 0x98,
+ AVRISP_PROTO_PARAM_TOPCARD_DETECT = 0x9a,
+ AVRISP_PROTO_PARAM_STATUS = 0x9c,
+ AVRISP_PROTO_PARAM_DATA = 0x9d,
+ AVRISP_PROTO_PARAM_RESET_POLARITY = 0x9e,
+ AVRISP_PROTO_PARAM_CONTROLLER_INIT = 0x9f,
+};
+
+static inline AvrIspProtoStatus
+avrisp_proto_isp_status (AvrIspResult isp_status)
+{
+ if (isp_status == AVRISP_OK)
+ return AVRISP_PROTO_STATUS_CMD_OK;
+ else if (isp_status == AVRISP_TIMEOUT)
+ return AVRISP_PROTO_STATUS_CMD_TOUT;
+ else
+ return AVRISP_PROTO_STATUS_CMD_FAILED;
+}
+
+AvrIspProto::AvrIspProto (AvrIsp &isp)
+ : isp_ (isp), sck_duration_us_ (1)
+{
+}
+
+int
+AvrIspProto::accept (uint8_t *data, int len)
+{
+ uint8_t r;
+ AvrIspProtoStatus status;
+ AvrIspResult isp_status;
+ uint16_t size;
+ /* Decode command. */
+ switch (data[0])
+ {
+ case AVRISP_PROTO_CMD_SIGN_ON:
+ if (len != 1) break;
+ data[1] = AVRISP_PROTO_STATUS_CMD_OK;
+ data[2] = sizeof (UCOO_CONFIG_DEV_AVRISP_PROTO_SIGNATURE);
+ memcpy (&data[3], UCOO_CONFIG_DEV_AVRISP_PROTO_SIGNATURE,
+ sizeof (UCOO_CONFIG_DEV_AVRISP_PROTO_SIGNATURE));
+ return 3 + sizeof (UCOO_CONFIG_DEV_AVRISP_PROTO_SIGNATURE);
+ case AVRISP_PROTO_CMD_SET_PARAMETER:
+ if (len != 3) break;
+ status = AVRISP_PROTO_STATUS_CMD_OK;
+ switch (data[1])
+ {
+ case AVRISP_PROTO_PARAM_SCK_DURATION:
+ sck_duration_us_ = std::max (data[2], static_cast<uint8_t> (1));
+ break;
+ case AVRISP_PROTO_PARAM_RESET_POLARITY:
+ if (data[2] != 1)
+ status = AVRISP_PROTO_STATUS_CMD_FAILED;
+ break;
+ default:
+ status = AVRISP_PROTO_STATUS_CMD_FAILED;
+ break;
+ }
+ data[1] = status;
+ return 2;
+ case AVRISP_PROTO_CMD_GET_PARAMETER:
+ if (len != 2) break;
+ status = AVRISP_PROTO_STATUS_CMD_OK;
+ switch (data[1])
+ {
+ case AVRISP_PROTO_PARAM_SCK_DURATION:
+ data[2] = sck_duration_us_;
+ break;
+ case AVRISP_PROTO_PARAM_RESET_POLARITY:
+ data[2] = 1;
+ break;
+ case AVRISP_PROTO_PARAM_BUILD_NUMBER_LOW:
+ data[2] = bytes_unpack (UCOO_CONFIG_DEV_AVRISP_PROTO_BUILD_NUMBER, 0);
+ break;
+ case AVRISP_PROTO_PARAM_BUILD_NUMBER_HIGH:
+ data[2] = bytes_unpack (UCOO_CONFIG_DEV_AVRISP_PROTO_BUILD_NUMBER, 1);
+ break;
+ case AVRISP_PROTO_PARAM_HW_VER:
+ data[2] = UCOO_CONFIG_DEV_AVRISP_PROTO_HW_VERSION;
+ break;
+ case AVRISP_PROTO_PARAM_SW_MAJOR:
+ data[2] = bytes_unpack (UCOO_CONFIG_DEV_AVRISP_PROTO_SW_VERSION, 1);
+ break;
+ case AVRISP_PROTO_PARAM_SW_MINOR:
+ data[2] = bytes_unpack (UCOO_CONFIG_DEV_AVRISP_PROTO_SW_VERSION, 0);
+ break;
+ default:
+ status = AVRISP_PROTO_STATUS_CMD_FAILED;
+ break;
+ }
+ data[1] = status;
+ return status == AVRISP_PROTO_STATUS_CMD_OK ? 3 : 2;
+ case AVRISP_PROTO_CMD_LOAD_ADDRESS:
+ if (len != 5) break;
+ isp_.load_address (bytes_pack (data[1], data[2], data[3], data[4]));
+ data[1] = AVRISP_PROTO_STATUS_CMD_OK;
+ return 2;
+ case AVRISP_PROTO_CMD_ENTER_PROGMODE_ISP:
+ if (len != 12) break;
+ isp_status = isp_.enter_progmode (sck_duration_us_, data[1], data[2],
+ data[3], data[4], data[5], data[6],
+ data[7], &data[8]);
+ data[1] = avrisp_proto_isp_status (isp_status);
+ return 2;
+ case AVRISP_PROTO_CMD_LEAVE_PROGMODE_ISP:
+ if (len != 3) break;
+ isp_.leave_progmode (data[1], data[2]);
+ data[1] = AVRISP_PROTO_STATUS_CMD_OK;
+ return 2;
+ case AVRISP_PROTO_CMD_CHIP_ERASE_ISP:
+ if (len != 7) break;
+ isp_status = isp_.chip_erase (data[1], data[2], &data[3]);
+ data[1] = avrisp_proto_isp_status (isp_status);
+ return 2;
+ case AVRISP_PROTO_CMD_PROGRAM_FLASH_ISP:
+ case AVRISP_PROTO_CMD_PROGRAM_EEPROM_ISP:
+ if (len < 10) break;
+ size = bytes_pack (data[1], data[2]);
+ if (len != 10 + size) break;
+ isp_status = isp_.program_begin (size, data[3], data[4], data[5], data[6],
+ data[7], &data[8], data[0]
+ == AVRISP_PROTO_CMD_PROGRAM_FLASH_ISP);
+ if (isp_status == AVRISP_OK)
+ isp_status = isp_.program_continue (&data[10], size);
+ if (isp_status == AVRISP_OK)
+ isp_status = isp_.program_end ();
+ data[1] = avrisp_proto_isp_status (isp_status);
+ return 2;
+ case AVRISP_PROTO_CMD_READ_FLASH_ISP:
+ case AVRISP_PROTO_CMD_READ_EEPROM_ISP:
+ if (len != 4) break;
+ size = bytes_pack (data[1], data[2]);
+ isp_status = isp_.read_begin (size, data[3], data[0]
+ == AVRISP_PROTO_CMD_READ_FLASH_ISP);
+ if (isp_status == AVRISP_OK)
+ isp_status = isp_.read_continue (&data[2], size);
+ if (isp_status == AVRISP_OK)
+ isp_status = isp_.read_end ();
+ if (isp_status == AVRISP_OK)
+ {
+ data[1] = AVRISP_PROTO_STATUS_CMD_OK;
+ data[2 + size] = AVRISP_PROTO_STATUS_CMD_OK;
+ return 2 + size + 1;
+ }
+ else
+ {
+ data[1] = AVRISP_PROTO_STATUS_CMD_FAILED;
+ return 2;
+ }
+ case AVRISP_PROTO_CMD_PROGRAM_FUSE_ISP:
+ case AVRISP_PROTO_CMD_PROGRAM_LOCK_ISP:
+ if (len != 5) break;
+ isp_.program_misc (&data[1]);
+ data[1] = AVRISP_PROTO_STATUS_CMD_OK;
+ data[2] = AVRISP_PROTO_STATUS_CMD_OK;
+ return 3;
+ case AVRISP_PROTO_CMD_READ_FUSE_ISP:
+ case AVRISP_PROTO_CMD_READ_LOCK_ISP:
+ case AVRISP_PROTO_CMD_READ_SIGNATURE_ISP:
+ case AVRISP_PROTO_CMD_READ_OSCCAL_ISP:
+ if (len != 6) break;
+ r = isp_.read_misc (data[1], &data[2]);
+ data[1] = AVRISP_PROTO_STATUS_CMD_OK;
+ data[2] = r;
+ data[3] = AVRISP_PROTO_STATUS_CMD_OK;
+ return 4;
+ case AVRISP_PROTO_CMD_SPI_MULTI:
+ if (len < 4) break;
+ size = data[2];
+ if (len != 4 + size) break;
+ isp_.multi (data[1], data[2], data[3], &data[4], &data[2]);
+ data[1] = AVRISP_PROTO_STATUS_CMD_OK;
+ data[2 + size] = AVRISP_PROTO_STATUS_CMD_OK;
+ return 2 + size + 1;
+ default:
+ /* Unknown. */
+ data[1] = AVRISP_PROTO_STATUS_CMD_UNKNOWN;
+ return 2;
+ }
+ data[1] = AVRISP_PROTO_STATUS_CMD_FAILED;
+ return 2;
+}
+
+} // namespace ucoo
diff --git a/ucoo/dev/avrisp/avrisp_proto.hh b/ucoo/dev/avrisp/avrisp_proto.hh
new file mode 100644
index 0000000..8192d7c
--- /dev/null
+++ b/ucoo/dev/avrisp/avrisp_proto.hh
@@ -0,0 +1,50 @@
+#ifndef ucoo_dev_avrisp_avrisp_proto_hh
+#define ucoo_dev_avrisp_avrisp_proto_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "avrisp.hh"
+
+namespace ucoo {
+
+/// Interpret commands in the AVR068 and AVR069 format. Framing is needed for
+/// AVR068 and provided by AvrIspFrame.
+class AvrIspProto
+{
+ public:
+ /// Constructor.
+ AvrIspProto (AvrIsp &isp);
+ /// Accept a frame to interpret. Return the response length provided in
+ /// the same buffer. The buffer should be large enough to store the
+ /// largest frame used by AVR06[89] protocol.
+ int accept (uint8_t *data, int len);
+ private:
+ /// Ref to ISP class.
+ AvrIsp &isp_;
+ /// SCK period.
+ uint8_t sck_duration_us_;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_dev_avrisp_avrisp_proto_hh
diff --git a/ucoo/dev/avrisp/test/Makefile b/ucoo/dev/avrisp/test/Makefile
new file mode 100644
index 0000000..80a8334
--- /dev/null
+++ b/ucoo/dev/avrisp/test/Makefile
@@ -0,0 +1,9 @@
+BASE = ../../../..
+
+TARGETS = stm32f4
+PROGS = test_avrisp
+test_avrisp_SOURCES = test_avrisp.cc
+
+MODULES = dev/avrisp hal/spi hal/gpio base/test hal/usb utils
+
+include $(BASE)/build/top.mk
diff --git a/ucoo/dev/avrisp/test/test_avrisp.cc b/ucoo/dev/avrisp/test/test_avrisp.cc
new file mode 100644
index 0000000..f38cf52
--- /dev/null
+++ b/ucoo/dev/avrisp/test/test_avrisp.cc
@@ -0,0 +1,89 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/dev/avrisp/avrisp_frame.hh"
+
+#include "ucoo/arch/arch.hh"
+#include "ucoo/base/test/test.hh"
+#include "ucoo/hal/gpio/gpio.hh"
+#include "ucoo/hal/spi/spi_soft.hh"
+#include "ucoo/utils/delay.hh"
+
+#include <libopencm3/stm32/f4/rcc.h>
+
+class TestAvrIspIntf : public ucoo::AvrIspIntf
+{
+ public:
+ TestAvrIspIntf (ucoo::Io &reset, ucoo::Io &sck, ucoo::Io &mosi,
+ ucoo::Io &miso)
+ : reset_ (reset), sck_ (sck), spi_ (sck, mosi, miso) { }
+ uint8_t send_and_recv (uint8_t tx)
+ {
+ return spi_.send_and_recv (tx);
+ }
+ void enable (uint8_t sck_duration_us)
+ {
+ reset_.output ();
+ reset_.reset ();
+ sck_.output ();
+ sck_.reset ();
+ ucoo::delay_us (1000);
+ reset_.set ();
+ ucoo::delay_us (100);
+ reset_.reset ();
+ int freq = 1000000 / sck_duration_us;
+ spi_.enable (freq, ucoo::SPI_MODE_0);
+ }
+ void disable ()
+ {
+ spi_.disable ();
+ reset_.input ();
+ }
+ void sck_pulse ()
+ {
+ sck_.toggle ();
+ ucoo::delay_us (100);
+ sck_.toggle ();
+ }
+ private:
+ ucoo::Io &reset_;
+ ucoo::Io &sck_;
+ ucoo::SpiSoftMaster spi_;
+};
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ ucoo::Stream &ts = ucoo::test_stream ();
+ rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPDEN
+ | RCC_AHB1ENR_IOPEEN);
+ ucoo::Gpio reset (GPIOD, 10), sck (GPIOE, 7), mosi (GPIOD, 8),
+ miso (GPIOD, 9);
+ TestAvrIspIntf intf (reset, sck, mosi, miso);
+ ucoo::AvrIsp isp (intf);
+ ucoo::AvrIspProto proto (isp);
+ ucoo::AvrIspFrame frame (proto);
+ while (1)
+ frame.read_and_write (ts);
+}
diff --git a/ucoo/dev/usdist/Module b/ucoo/dev/usdist/Module
new file mode 100644
index 0000000..bedbac4
--- /dev/null
+++ b/ucoo/dev/usdist/Module
@@ -0,0 +1 @@
+dev_usdist_SOURCES = usdist.cc
diff --git a/ucoo/dev/usdist/usdist.cc b/ucoo/dev/usdist/usdist.cc
new file mode 100644
index 0000000..8a254bf
--- /dev/null
+++ b/ucoo/dev/usdist/usdist.cc
@@ -0,0 +1,103 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "usdist.hh"
+
+namespace ucoo {
+
+
+UsDist::UsDist (UsDistControl &ctrl, Adc &adc, Io &io,
+ int distance_min, int distance_max, int distance_too_far,
+ int resolution)
+ : adc_ (adc), io_ (io), next_ (0),
+ distance_min_ (distance_min), distance_max_ (distance_max),
+ distance_too_far_ (distance_too_far), resolution_ (resolution),
+ distance_ (-1)
+{
+ next_ = ctrl.sensors_;
+ ctrl.sensors_ = this;
+ if (resolution_ == -1)
+ resolution_ = adc_.get_resolution ();
+}
+
+void
+UsDist::enable ()
+{
+ io_.set ();
+}
+
+void
+UsDist::disable ()
+{
+ io_.reset ();
+}
+
+int
+UsDist::read ()
+{
+ int v = adc_.read ();
+ // The sensor returns a value between 4 and 20 mA proportional to the
+ // distance between calibrated values. Ignore faulty sensors.
+ const int max = resolution_;
+ const int min = max / 5;
+ if (v <= min / 4)
+ distance_ = -1;
+ else if (v <= min)
+ distance_ = distance_min_;
+ else
+ distance_ = distance_min_
+ + ((v - min) * (distance_max_ - distance_min_) / (max - min));
+ if (distance_too_far_ != -1 && distance_ > distance_too_far_)
+ distance_ = -1;
+ return distance_;
+}
+
+UsDistControl::UsDistControl (int period)
+ : period_ (period), sensors_ (0), current_ (0), wait_ (0)
+{
+}
+
+bool
+UsDistControl::update ()
+{
+ bool new_measure = false;
+ if (wait_)
+ wait_--;
+ else
+ {
+ if (current_)
+ {
+ current_->disable ();
+ current_->read ();
+ new_measure = true;
+ current_ = current_->next_;
+ }
+ if (!current_)
+ current_ = sensors_;
+ current_->enable ();
+ wait_ = period_ - 1;
+ }
+ return new_measure;
+}
+
+} // namespace ucoo
diff --git a/ucoo/dev/usdist/usdist.hh b/ucoo/dev/usdist/usdist.hh
new file mode 100644
index 0000000..88233ba
--- /dev/null
+++ b/ucoo/dev/usdist/usdist.hh
@@ -0,0 +1,80 @@
+#ifndef ucoo_dev_usdist_usdist_hh
+#define ucoo_dev_usdist_usdist_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/adc.hh"
+#include "ucoo/intf/io.hh"
+
+namespace ucoo {
+
+class UsDistControl;
+
+/// Single US distance sensor.
+class UsDist
+{
+ public:
+ /// Constructor.
+ UsDist (UsDistControl &ctrl, Adc &adc, Io &io,
+ int distance_min, int distance_max, int distance_too_far = -1,
+ int resolution = -1);
+ /// Enable measure.
+ void enable ();
+ /// Disable measure.
+ void disable ();
+ /// Read current value.
+ int read ();
+ /// Return last measured distance.
+ int get () const { return distance_; }
+ private:
+ Adc &adc_;
+ Io &io_;
+ UsDist *next_;
+ int distance_min_, distance_max_, distance_too_far_, resolution_;
+ int distance_;
+ friend class UsDistControl;
+};
+
+/// Handle a set of US distance sensors.
+class UsDistControl
+{
+ public:
+ /// Constructor.
+ UsDistControl (int period);
+ /// Make measurements, return true if a new measure is available.
+ bool update ();
+ private:
+ /// Number of updates between measures.
+ int period_;
+ /// Pointer to linked list of sensors.
+ UsDist *sensors_;
+ /// Current measuring sensor.
+ UsDist *current_;
+ /// Number of updates before the next action.
+ int wait_;
+ friend class UsDist;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_dev_usdist_usdist_hh
diff --git a/ucoo/dev/xmodem/Module b/ucoo/dev/xmodem/Module
new file mode 100644
index 0000000..37bc5eb
--- /dev/null
+++ b/ucoo/dev/xmodem/Module
@@ -0,0 +1 @@
+dev_xmodem_SOURCES = xmodem.cc
diff --git a/ucoo/dev/xmodem/xmodem.cc b/ucoo/dev/xmodem/xmodem.cc
new file mode 100644
index 0000000..849d396
--- /dev/null
+++ b/ucoo/dev/xmodem/xmodem.cc
@@ -0,0 +1,164 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "xmodem.hh"
+#include "ucoo/utils/delay.hh"
+#include "ucoo/common.hh"
+
+namespace ucoo {
+
+static const char xmodem_ack = 0x06;
+static const char xmodem_c = 'C';
+static const char xmodem_nack = 0x15;
+static const char xmodem_eot = 0x04;
+static const char xmodem_soh = 0x01;
+static const char xmodem_stx = 0x02;
+static const char xmodem_can = 0x18;
+
+/// Get character with one second timeout.
+static int
+xmodem_getc (Stream &s)
+{
+ for (int timeout = 1000; timeout; timeout--)
+ {
+ int c = s.getc ();
+ if (c != -1)
+ return c;
+ delay_ms (1);
+ }
+ return -1;
+}
+
+/// Blocking putc.
+static void
+xmodem_putc (Stream &s, int c)
+{
+ s.block (true);
+ s.putc (c);
+ s.block (false);
+}
+
+/// Update CRC on received payload.
+static uint16_t
+xmodem_crc_update (uint16_t crc, uint8_t c)
+{
+ int i;
+ crc = crc ^ (c << 8);
+ for (i = 0; i < 8; i++)
+ {
+ if (crc & 0x8000)
+ crc = (crc << 1) ^ 0x1021;
+ else
+ crc = (crc << 1);
+ }
+ return crc;
+}
+
+int
+xmodem_receive (Stream &s, XmodemReceiver &receiver)
+{
+ int i, length, total = 0;
+ int c, c2;
+ uint16_t crc;
+ bool started = false;
+ bool ok = false;
+ uint8_t block_number = 1;
+ bool dup = false;
+ char buf[1024];
+ s.block (false);
+ while (1)
+ {
+ // Send ACK, NACK or 'C'.
+ if (ok)
+ xmodem_putc (s, xmodem_ack);
+ else
+ {
+ // Purge.
+ while (xmodem_getc (s) != -1)
+ ;
+ xmodem_putc (s, started ? xmodem_nack : xmodem_c);
+ }
+ ok = false;
+ // Receive SOH, STX, or EOT.
+ c = xmodem_getc (s);
+ if (c == xmodem_soh)
+ length = 128;
+ else if (c == xmodem_stx)
+ length = 1024;
+ else if (c == xmodem_eot)
+ break;
+ else
+ continue;
+ // Receive block number.
+ c = xmodem_getc (s);
+ if (c == -1)
+ continue;
+ c2 = xmodem_getc (s);
+ if (c2 == -1 || c2 != 255 - c)
+ continue;
+ else if (started && c == block_number - 1)
+ dup = true;
+ else if (c != block_number)
+ continue;
+ // Receive data.
+ crc = 0;
+ for (i = 0; i < length && c != -1; i++)
+ {
+ c = xmodem_getc (s);
+ crc = xmodem_crc_update (crc, c);
+ buf[i] = c;
+ }
+ if (c == -1)
+ continue;
+ // Receive CRC.
+ c = xmodem_getc (s);
+ if (c == -1)
+ continue;
+ crc = xmodem_crc_update (crc, c);
+ c = xmodem_getc (s);
+ if (c == -1)
+ continue;
+ crc = xmodem_crc_update (crc, c);
+ if (crc != 0)
+ continue;
+ // Success, handle data.
+ if (!dup)
+ {
+ started = true;
+ block_number++;
+ int r = receiver.write (buf, length);
+ if (r == -1)
+ {
+ total = -1;
+ break;
+ }
+ total += length;
+ }
+ ok = true;
+ dup = false;
+ }
+ xmodem_putc (s, total == -1 ? xmodem_can : xmodem_ack);
+ return total;
+}
+
+} // namespace ucoo
diff --git a/ucoo/dev/xmodem/xmodem.hh b/ucoo/dev/xmodem/xmodem.hh
new file mode 100644
index 0000000..ec75662
--- /dev/null
+++ b/ucoo/dev/xmodem/xmodem.hh
@@ -0,0 +1,46 @@
+#ifndef ucoo_dev_xmodem_xmodem_hh
+#define ucoo_dev_xmodem_xmodem_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/stream.hh"
+
+namespace ucoo {
+
+/// Handle data received from XMODEM.
+class XmodemReceiver
+{
+ public:
+ /// Write up to COUNT bytes of data from BUF to stream. Return the number
+ /// of written bytes or -1 on error.
+ virtual int write (const char *buf, int count) = 0;
+};
+
+/// Make a XMODEM reception from stream and write any received data to
+/// receiver.
+int
+xmodem_receive (Stream &s, XmodemReceiver &receiver);
+
+} // namespace ucoo
+
+#endif // ucoo_dev_xmodem_xmodem_hh
diff --git a/ucoo/hal/adc/Module b/ucoo/hal/adc/Module
new file mode 100644
index 0000000..f633ffd
--- /dev/null
+++ b/ucoo/hal/adc/Module
@@ -0,0 +1 @@
+hal_adc_SOURCES = adc.host.cc adc_hard.stm32f4.cc
diff --git a/ucoo/hal/adc/adc.hh b/ucoo/hal/adc/adc.hh
new file mode 100644
index 0000000..b7832c3
--- /dev/null
+++ b/ucoo/hal/adc/adc.hh
@@ -0,0 +1,35 @@
+#ifndef ucoo_hal_adc_adc_hh
+#define ucoo_hal_adc_adc_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+#if defined (TARGET_host)
+# include "adc.host.hh"
+#elif defined (TARGET_stm32f4)
+# include "adc_hard.stm32f4.hh"
+#else
+# error "not implemented for this target"
+#endif
+
+#endif // ucoo_hal_adc_adc_hh
diff --git a/ucoo/hal/adc/adc.host.cc b/ucoo/hal/adc/adc.host.cc
new file mode 100644
index 0000000..0dfc01d
--- /dev/null
+++ b/ucoo/hal/adc/adc.host.cc
@@ -0,0 +1,92 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "adc.host.hh"
+
+#include <string>
+
+namespace ucoo {
+
+/// Shared context between instances.
+class AdcHostShared
+{
+ public:
+ /// Constructor, connect to mex node.
+ AdcHostShared (Host &host);
+ /// Register a new instance.
+ void register_instance (Host &host, AdcHost &instance, const char *name);
+ private:
+ /// Handle value from Mex.
+ void handle_adc_channel (mex::Msg &msg);
+ private:
+ Host &host_;
+ typedef std::map<std::string, AdcHost *> Instances;
+ Instances instances_;
+};
+
+AdcHostShared::AdcHostShared (Host &host)
+ : host_ (host)
+{
+ std::string instance = host_.get_instance ();
+ mex::Node &node = host_.get_node ();
+ mex::mtype_t mtype = node.reserve (instance + ":adc_channel");
+ node.handler_register (mtype, *this, &AdcHostShared::handle_adc_channel);
+}
+
+void
+AdcHostShared::register_instance (Host &host, AdcHost &instance,
+ const char *name)
+{
+ assert (&host == &host_);
+ std::pair<Instances::iterator, bool> r =
+ instances_.insert (Instances::value_type (name, &instance));
+ assert (r.second);
+}
+
+void
+AdcHostShared::handle_adc_channel (mex::Msg &msg)
+{
+ int ivalue, namelen;
+ msg.pop ("l") >> ivalue;
+ namelen = msg.len ();
+ std::string name (msg.pop (namelen), namelen);
+ Instances::iterator i = instances_.find (name);
+ assert (i != instances_.end ());
+ double fvalue = ivalue / (double) (1u << 31);
+ i->second->value_ = fvalue * i->second->resolution_;
+}
+
+AdcHostShared *AdcHost::shared_;
+
+AdcHost::AdcHost (Host &host, const char *name, int resolution)
+ : resolution_ (resolution), value_ (0)
+{
+ if (!shared_)
+ {
+ static AdcHostShared shared (host);
+ shared_ = &shared;
+ }
+ shared_->register_instance (host, *this, name);
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/adc/adc.host.hh b/ucoo/hal/adc/adc.host.hh
new file mode 100644
index 0000000..02b7cc9
--- /dev/null
+++ b/ucoo/hal/adc/adc.host.hh
@@ -0,0 +1,52 @@
+#ifndef ucoo_hal_adc_adc_host_hh
+#define ucoo_hal_adc_adc_host_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/adc.hh"
+#include "ucoo/arch/host/host.hh"
+
+namespace ucoo {
+
+class AdcHostShared;
+
+/// Host ADC channel.
+class AdcHost : public Adc
+{
+ public:
+ /// Constructor.
+ AdcHost (Host &host, const char *name, int resolution);
+ /// See Adc::read.
+ int read () { return value_; }
+ /// See Adc::get_resolution.
+ int get_resolution () const { return resolution_; }
+ private:
+ int resolution_;
+ int value_;
+ static AdcHostShared *shared_;
+ friend class AdcHostShared;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_adc_adc_host_hh
diff --git a/ucoo/hal/adc/adc_hard.stm32f4.cc b/ucoo/hal/adc/adc_hard.stm32f4.cc
new file mode 100644
index 0000000..38661e3
--- /dev/null
+++ b/ucoo/hal/adc/adc_hard.stm32f4.cc
@@ -0,0 +1,69 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "adc_hard.stm32f4.hh"
+
+#include <libopencm3/stm32/f4/adc.h>
+#include <libopencm3/stm32/f4/rcc.h>
+
+namespace ucoo {
+
+AdcHard::AdcHard (int n)
+ : n_ (n)
+{
+ static const uint32_t bases[] = { ADC1, ADC2, ADC3 };
+ assert (n < (int) lengthof (bases));
+ base_ = bases[n];
+}
+
+AdcHard::~AdcHard ()
+{
+ disable ();
+}
+
+void
+AdcHard::enable ()
+{
+ rcc_peripheral_enable_clock (&RCC_APB2ENR, RCC_APB2ENR_ADC1EN << n_);
+ ADC_CR2 (base_) = ADC_CR2_ADON;
+}
+
+void
+AdcHard::disable ()
+{
+ ADC_CR2 (base_) = 0;
+ rcc_peripheral_disable_clock (&RCC_APB2ENR, RCC_APB2ENR_ADC1EN << n_);
+}
+
+int
+AdcHard::read (int channel)
+{
+ ADC_SQR3 (base_) = channel;
+ ADC_CR2 (base_) |= ADC_CR2_SWSTART;
+ while (!(ADC_SR (base_) & ADC_SR_EOC))
+ yield ();
+ ADC_SR (base_) = ~ADC_SR_EOC;
+ return ADC_DR (base_);
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/adc/adc_hard.stm32f4.hh b/ucoo/hal/adc/adc_hard.stm32f4.hh
new file mode 100644
index 0000000..7ab0d7f
--- /dev/null
+++ b/ucoo/hal/adc/adc_hard.stm32f4.hh
@@ -0,0 +1,73 @@
+#ifndef ucoo_hal_adc_adc_hard_stm32f4_hh
+#define ucoo_hal_adc_adc_hard_stm32f4_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/adc.hh"
+#include "ucoo/common.hh"
+
+namespace ucoo {
+
+/// ADC interface. This control a full ADC, use AdcHardChannel for a single
+/// channel.
+class AdcHard
+{
+ public:
+ static const int resolution = 1 << 12;
+ public:
+ /// Constructor for the Nth ADC.
+ AdcHard (int n);
+ /// Shutdown.
+ ~AdcHard ();
+ /// Enable, power on.
+ void enable ();
+ /// Disable.
+ void disable ();
+ /// Make a single measure.
+ int read (int channel);
+ private:
+ /// ADC index.
+ int n_;
+ /// ADC base address.
+ uint32_t base_;
+};
+
+/// Single ADC channel.
+class AdcHardChannel : public Adc
+{
+ public:
+ /// Constructor.
+ AdcHardChannel (AdcHard &adc, int channel)
+ : adc_ (adc), channel_ (channel) { }
+ /// See Adc::read.
+ int read () { return adc_.read (channel_); }
+ /// See Adc::get_resolution.
+ int get_resolution () const { return AdcHard::resolution; }
+ private:
+ AdcHard &adc_;
+ int channel_;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_adc_adc_hard_stm32f4_hh
diff --git a/ucoo/hal/adc/test/Makefile b/ucoo/hal/adc/test/Makefile
new file mode 100644
index 0000000..fc46e0d
--- /dev/null
+++ b/ucoo/hal/adc/test/Makefile
@@ -0,0 +1,9 @@
+BASE = ../../../..
+
+TARGETS = stm32f4
+stm32f4_PROGS = test_adc
+test_adc_SOURCES = test_adc.cc
+
+MODULES = hal/adc base/test hal/usb utils
+
+include $(BASE)/build/top.mk
diff --git a/ucoo/hal/adc/test/test_adc.cc b/ucoo/hal/adc/test/test_adc.cc
new file mode 100644
index 0000000..eaaf44e
--- /dev/null
+++ b/ucoo/hal/adc/test/test_adc.cc
@@ -0,0 +1,51 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/adc/adc.hh"
+
+#include "ucoo/arch/arch.hh"
+#include "ucoo/base/test/test.hh"
+#include "ucoo/utils/delay.hh"
+
+#include <libopencm3/stm32/f4/adc.h>
+#include "ucoo/hal/gpio/gpio.hh"
+
+#include <cstdio>
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ ucoo::test_stream_setup ();
+ // Have fun with temperature sensor.
+ ucoo::AdcHard adc (0);
+ adc.enable ();
+ ADC_CCR = ADC_CCR_TSVREFE;
+ ucoo::AdcHardChannel c (adc, 16);
+ while (1)
+ {
+ int r = c.read ();
+ std::printf ("ADC = %d\n", r);
+ ucoo::delay (0.5);
+ }
+}
diff --git a/ucoo/hal/gpio/Module b/ucoo/hal/gpio/Module
new file mode 100644
index 0000000..8f2ba40
--- /dev/null
+++ b/ucoo/hal/gpio/Module
@@ -0,0 +1 @@
+hal_gpio_SOURCES = gpio.host.cc gpio.stm32f4.cc
diff --git a/ucoo/hal/gpio/gpio.hh b/ucoo/hal/gpio/gpio.hh
new file mode 100644
index 0000000..86a6c91
--- /dev/null
+++ b/ucoo/hal/gpio/gpio.hh
@@ -0,0 +1,35 @@
+#ifndef ucoo_hal_gpio_gpio_hh
+#define ucoo_hal_gpio_gpio_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+#if defined (TARGET_host)
+# include "gpio.host.hh"
+#elif defined TARGET_stm32f4
+# include "gpio.stm32f4.hh"
+#else
+# error "not implemented for this target"
+#endif
+
+#endif // ucoo_hal_gpio_gpio_hh
diff --git a/ucoo/hal/gpio/gpio.host.cc b/ucoo/hal/gpio/gpio.host.cc
new file mode 100644
index 0000000..ca9065b
--- /dev/null
+++ b/ucoo/hal/gpio/gpio.host.cc
@@ -0,0 +1,181 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "gpio.host.hh"
+
+#include <cstring>
+
+namespace ucoo {
+
+/// Shared context between instances.
+class GpioShared
+{
+ public:
+ /// Constructor, connect to mex node.
+ GpioShared (Host &host);
+ /// Register a new GPIO.
+ void register_instance (Host &host, Gpio &instance);
+ /// Set output state.
+ void set (Gpio &instance, bool state);
+ /// Set direction.
+ void output (Gpio &instance, bool output);
+ private:
+ /// Send state change message.
+ void send (Gpio &instance);
+ /// Handle input value from Mex.
+ void handle_gpio_input (mex::Msg &msg);
+ private:
+ Host &host_;
+ mex::Node &node_;
+ mex::mtype_t gpio_output_mtype_, gpio_input_mtype_;
+ typedef std::map<std::string, Gpio *> Instances;
+ Instances instances_;
+};
+
+GpioShared::GpioShared (Host &host)
+ : host_ (host), node_ (host.get_node ())
+{
+ std::string instance = host_.get_instance ();
+ gpio_output_mtype_ = node_.reserve (instance + ":gpio_out");
+ gpio_input_mtype_ = node_.reserve (instance + ":gpio_in");
+ node_.handler_register (gpio_input_mtype_, *this,
+ &GpioShared::handle_gpio_input);
+}
+
+void
+GpioShared::register_instance (Host &host, Gpio &instance)
+{
+ assert (&host == &host_);
+ std::pair<Instances::iterator, bool> r =
+ instances_.insert (Instances::value_type (instance.name_, &instance));
+ assert (r.second);
+}
+
+void
+GpioShared::set (Gpio &instance, bool state)
+{
+ if (state != instance.output_)
+ {
+ instance.output_ = state;
+ send (instance);
+ }
+}
+
+void
+GpioShared::output (Gpio &instance, bool output)
+{
+ if (output != instance.direction_output_)
+ {
+ instance.direction_output_ = output;
+ send (instance);
+ }
+}
+
+void
+GpioShared::send (Gpio &instance)
+{
+ mex::Msg msg (gpio_output_mtype_);
+ msg.push ("BB") << instance.direction_output_ << instance.output_;
+ msg.push (instance.name_, std::strlen (instance.name_));
+ node_.send (msg);
+}
+
+void
+GpioShared::handle_gpio_input (mex::Msg &msg)
+{
+ int input, namelen;
+ msg.pop ("B") >> input;
+ namelen = msg.len ();
+ std::string name (msg.pop (namelen), namelen);
+ Instances::iterator i = instances_.find (name);
+ assert (i != instances_.end ());
+ i->second->input_ = input;
+}
+
+GpioShared *Gpio::shared_;
+
+Gpio::Gpio (Host &host, const char *name)
+ : name_ (name), input_ (false), output_ (false), direction_output_ (false)
+{
+ if (!shared_)
+ {
+ static GpioShared shared (host);
+ shared_ = &shared;
+ }
+ shared_->register_instance (host, *this);
+}
+
+Gpio::Gpio ()
+ : name_ (0), input_ (false), output_ (false), direction_output_ (false)
+{
+}
+
+void
+Gpio::set ()
+{
+ if (name_)
+ shared_->set (*this, true);
+}
+
+void
+Gpio::reset ()
+{
+ if (name_)
+ shared_->set (*this, false);
+}
+
+void
+Gpio::set (bool state)
+{
+ if (name_)
+ shared_->set (*this, state);
+}
+
+void
+Gpio::toggle ()
+{
+ if (name_)
+ shared_->set (*this, !output_);
+}
+
+bool
+Gpio::get () const
+{
+ return input_;
+}
+
+void
+Gpio::input ()
+{
+ if (name_)
+ shared_->output (*this, false);
+}
+
+void
+Gpio::output ()
+{
+ if (name_)
+ shared_->output (*this, true);
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/gpio/gpio.host.hh b/ucoo/hal/gpio/gpio.host.hh
new file mode 100644
index 0000000..fcd0cbf
--- /dev/null
+++ b/ucoo/hal/gpio/gpio.host.hh
@@ -0,0 +1,69 @@
+#ifndef ucoo_hal_gpio_gpio_host_hh
+#define ucoo_hal_gpio_gpio_host_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/io.hh"
+#include "ucoo/arch/host/host.hh"
+
+namespace ucoo {
+
+class GpioShared;
+
+/// General purpose input/output on host.
+class Gpio : public Io
+{
+ public:
+ /// Initialise GPIO.
+ Gpio (Host &host, const char *name);
+ /// Initialise GPIO, with no mex support.
+ Gpio ();
+ /// See Io::set.
+ void set ();
+ /// See Io::reset.
+ void reset ();
+ /// See Io::set.
+ void set (bool state);
+ /// See Io::toggle.
+ void toggle ();
+ /// See Io::get.
+ bool get () const;
+ /// See Io::input.
+ void input ();
+ /// See Io::output.
+ void output ();
+ private:
+ /// Name.
+ const char *name_;
+ /// Current input/output states.
+ bool input_, output_;
+ /// Current direction, true for output.
+ bool direction_output_;
+ /// Shared context.
+ static GpioShared *shared_;
+ friend class GpioShared;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_gpio_gpio_host_hh
diff --git a/ucoo/hal/gpio/gpio.stm32f4.cc b/ucoo/hal/gpio/gpio.stm32f4.cc
new file mode 100644
index 0000000..1b46fd5
--- /dev/null
+++ b/ucoo/hal/gpio/gpio.stm32f4.cc
@@ -0,0 +1,105 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "gpio.stm32f4.hh"
+
+namespace ucoo {
+
+void
+Gpio::set ()
+{
+ GPIO_BSRR (port_) = mask_;
+}
+
+void
+Gpio::reset ()
+{
+ GPIO_BSRR (port_) = mask_ << 16;
+}
+
+/// Helper to avoid virtual dance.
+static inline void
+Gpio_set (uint32_t port, uint16_t mask, bool state)
+{
+ if (state)
+ GPIO_BSRR (port) = mask;
+ else
+ GPIO_BSRR (port) = mask << 16;
+}
+
+void
+Gpio::set (bool state)
+{
+ Gpio_set (port_, mask_, state);
+}
+
+void
+Gpio::toggle ()
+{
+ // Avoid read/modify/write ODR, to achieve atomic operation.
+ Gpio_set (port_, mask_, !(GPIO_ODR (port_) & mask_));
+}
+
+bool
+Gpio::get () const
+{
+ return GPIO_IDR (port_) & mask_;
+}
+
+/// Set two bits in a register for the corresponding one-bit mask.
+static uint32_t
+dmask_set (uint32_t mask, uint32_t reg, uint32_t bits)
+{
+ uint32_t dmask = mask * mask;
+ reg &= ~(dmask | dmask << 1);
+ reg |= bits * dmask;
+ return reg;
+}
+
+void
+Gpio::input ()
+{
+ GPIO_MODER (port_) = dmask_set (mask_, GPIO_MODER (port_),
+ GPIO_MODE_INPUT);
+}
+
+void
+Gpio::output ()
+{
+ GPIO_MODER (port_) = dmask_set (mask_, GPIO_MODER (port_),
+ GPIO_MODE_OUTPUT);
+}
+
+void
+Gpio::pull (Pull dir)
+{
+ GPIO_PUPDR (port_) = dmask_set (mask_, GPIO_PUPDR (port_), dir);
+}
+
+void
+Gpio::speed (Speed s)
+{
+ GPIO_OSPEEDR (port_) = dmask_set (mask_, GPIO_OSPEEDR (port_), s);
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/gpio/gpio.stm32f4.hh b/ucoo/hal/gpio/gpio.stm32f4.hh
new file mode 100644
index 0000000..b2dfb16
--- /dev/null
+++ b/ucoo/hal/gpio/gpio.stm32f4.hh
@@ -0,0 +1,85 @@
+#ifndef ucoo_hal_gpio_gpio_stm32f4_hh
+#define ucoo_hal_gpio_gpio_stm32f4_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/io.hh"
+
+#include <libopencm3/stm32/f4/gpio.h>
+
+namespace ucoo {
+
+/// General purpose input/output on STM32F4.
+class Gpio : public Io
+{
+ public:
+ enum Pull
+ {
+ PULL_NONE = GPIO_PUPD_NONE,
+ PULL_UP = GPIO_PUPD_PULLUP,
+ PULL_DOWN = GPIO_PUPD_PULLDOWN,
+ };
+ enum Speed
+ {
+ SPEED_2MHZ = GPIO_OSPEED_2MHZ,
+ SPEED_25MHZ = GPIO_OSPEED_25MHZ,
+ SPEED_50MHZ = GPIO_OSPEED_50MHZ,
+ SPEED_100MHZ = GPIO_OSPEED_100MHZ,
+ };
+ public:
+ /// Constructor, take the PORT base address, and pin BIT number.
+ Gpio (uint32_t port, int bit);
+ /// See Io::set.
+ void set ();
+ /// See Io::reset.
+ void reset ();
+ /// See Io::set.
+ void set (bool state);
+ /// See Io::toggle.
+ void toggle ();
+ /// See Io::get.
+ bool get () const;
+ /// See Io::input.
+ void input ();
+ /// See Io::output.
+ void output ();
+ /// Set pull-up or pull-down.
+ void pull (Pull dir);
+ /// Set output speed.
+ void speed (Speed s);
+ private:
+ /// Port register base address.
+ const uint32_t port_;
+ /// IO bitmask.
+ const uint16_t mask_;
+};
+
+inline
+Gpio::Gpio (uint32_t port, int bit)
+ : port_ (port), mask_ (1u << bit)
+{
+}
+
+} // namespace ucoo
+
+#endif // ucoo_hal_gpio_gpio_stm32f4_hh
diff --git a/ucoo/hal/gpio/test/Makefile b/ucoo/hal/gpio/test/Makefile
new file mode 100644
index 0000000..e2f7692
--- /dev/null
+++ b/ucoo/hal/gpio/test/Makefile
@@ -0,0 +1,9 @@
+BASE = ../../../..
+
+TARGETS = stm32f4
+stm32f4_PROGS = test_gpio
+test_gpio_SOURCES = test_gpio.cc
+
+MODULES = hal/gpio utils
+
+include $(BASE)/build/top.mk
diff --git a/ucoo/hal/gpio/test/test_gpio.cc b/ucoo/hal/gpio/test/test_gpio.cc
new file mode 100644
index 0000000..a953505
--- /dev/null
+++ b/ucoo/hal/gpio/test/test_gpio.cc
@@ -0,0 +1,71 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/arch/arch.hh"
+#include "ucoo/hal/gpio/gpio.hh"
+#include "ucoo/utils/delay.hh"
+
+#include <libopencm3/stm32/f4/rcc.h>
+
+void
+test (ucoo::Io &loop_out, ucoo::Io &loop_in, ucoo::Io &led3, ucoo::Io &led4,
+ ucoo::Io &led5, ucoo::Io &led6)
+{
+ loop_in.input ();
+ loop_out.output ();
+ led3.output ();
+ led4.output ();
+ led5.output ();
+ led6.output ();
+ led3.set ();
+ led6.reset ();
+ bool state = false;
+ while (1)
+ {
+ led3.toggle ();
+ led4.set (state);
+ led5.set (loop_in.get ());
+ led6.toggle ();
+ state = !state;
+ loop_out.set (state);
+ ucoo::delay (1);
+ }
+}
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPBEN
+ | RCC_AHB1ENR_IOPDEN);
+ // For this test, shorten B6 & B7 to have loopback.
+ gpio_mode_setup (GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO7);
+ ucoo::Gpio loop_out (GPIOB, 6);
+ ucoo::Gpio loop_in (GPIOB, 7);
+ ucoo::Gpio led3 (GPIOD, 13);
+ ucoo::Gpio led4 (GPIOD, 12);
+ ucoo::Gpio led5 (GPIOD, 14);
+ ucoo::Gpio led6 (GPIOD, 15);
+ test (loop_out, loop_in, led3, led4, led5, led6);
+ return 0;
+}
diff --git a/ucoo/hal/i2c/Config b/ucoo/hal/i2c/Config
new file mode 100644
index 0000000..3871f5c
--- /dev/null
+++ b/ucoo/hal/i2c/Config
@@ -0,0 +1,5 @@
+[hal/i2c]
+# Size of slave buffer, used for both reception and transmission.
+slave_buffer_size = 64
+# Activate debug trace.
+trace = false
diff --git a/ucoo/hal/i2c/Module b/ucoo/hal/i2c/Module
new file mode 100644
index 0000000..ae93f22
--- /dev/null
+++ b/ucoo/hal/i2c/Module
@@ -0,0 +1 @@
+hal_i2c_SOURCES := i2c.host.cc i2c_slave_data_buffer.cc i2c_hard.stm32.cc
diff --git a/ucoo/hal/i2c/i2c.hh b/ucoo/hal/i2c/i2c.hh
new file mode 100644
index 0000000..2c06085
--- /dev/null
+++ b/ucoo/hal/i2c/i2c.hh
@@ -0,0 +1,36 @@
+#ifndef ucoo_hal_i2c_i2c_hh
+#define ucoo_hal_i2c_i2c_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+#if defined (TARGET_host)
+# include "i2c.host.hh"
+#elif defined (TARGET_stm32)
+# include "i2c_hard.stm32.hh"
+#else
+# error "not implemented for this target"
+#endif
+#include "i2c_slave_data_buffer.hh"
+
+#endif // ucoo_hal_i2c_i2c_hh
diff --git a/ucoo/hal/i2c/i2c.host.cc b/ucoo/hal/i2c/i2c.host.cc
new file mode 100644
index 0000000..4a2553b
--- /dev/null
+++ b/ucoo/hal/i2c/i2c.host.cc
@@ -0,0 +1,213 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "i2c.host.hh"
+
+#include "config/hal/i2c.hh"
+
+namespace ucoo {
+
+/// Shared context between instances.
+class I2cHostShared
+{
+ public:
+ /// Constructor, connect to mex node.
+ I2cHostShared (Host &host);
+ /// Register a new driver instance.
+ void register_instance (Host &host, I2cHost &instance);
+ /// Send message, return new master status.
+ int send (uint8_t addr, const char *buf, int count);
+ /// Receive message, return new master status.
+ int recv (uint8_t addr, char *buf, int count);
+ /// Handle read requests from master.
+ void handle_read (mex::Msg &msg);
+ /// Handle write requests from master.
+ void handle_write (mex::Msg &msg);
+ private:
+ Host &host_;
+ mex::Node &node_;
+ mex::mtype_t read_mtype_, write_mtype_;
+ typedef std::list<I2cHost *> Instances;
+ Instances instances_;
+};
+
+I2cHostShared::I2cHostShared (Host &host)
+ : host_ (host), node_ (host.get_node ())
+{
+ std::string instance = host_.get_instance (1);
+ read_mtype_ = node_.reserve (instance + ":read");
+ write_mtype_ = node_.reserve (instance + ":write");
+ node_.handler_register (read_mtype_, *this, &I2cHostShared::handle_read);
+ node_.handler_register (write_mtype_, *this, &I2cHostShared::handle_write);
+}
+
+void
+I2cHostShared::register_instance (Host &host, I2cHost &instance)
+{
+ assert (&host == &host_);
+ instances_.push_back (&instance);
+}
+
+int
+I2cHostShared::send (uint8_t addr, const char *buf, int count)
+{
+ // Test for this slave in the same program.
+ for (Instances::const_iterator i = instances_.begin ();
+ i != instances_.end (); ++i)
+ {
+ if (addr == (*i)->slave_addr_)
+ {
+ assert (count <= UCOO_CONFIG_HAL_I2C_SLAVE_BUFFER_SIZE);
+ (*i)->slave_data_handler_->to_recv (buf, count);
+ return count;
+ }
+ }
+ // Else, send message.
+ mex::Msg msg (write_mtype_);
+ msg.push ("B") << addr;
+ msg.push (buf, count);
+ node_.send (msg);
+ return count;
+}
+
+int
+I2cHostShared::recv (uint8_t addr, char *buf, int count)
+{
+ // Test for this slave in the same program.
+ for (Instances::const_iterator i = instances_.begin ();
+ i != instances_.end (); ++i)
+ {
+ if (addr == (*i)->slave_addr_)
+ {
+ assert (count <= UCOO_CONFIG_HAL_I2C_SLAVE_BUFFER_SIZE);
+ return (*i)->slave_data_handler_->to_send (buf, count);
+ }
+ }
+ // Else, send request and wait for response.
+ mex::Msg msg (read_mtype_);
+ msg.push ("BB") << addr << count;
+ std::auto_ptr<mex::Msg> rsp = node_.request (msg);
+ int rcount = rsp->len ();
+ assert (rcount <= count);
+ const char *rbuf = rsp->pop (rcount);
+ std::copy (rbuf, rbuf + rcount, buf);
+ return rcount;
+}
+
+void
+I2cHostShared::handle_read (mex::Msg &msg)
+{
+ uint8_t addr;
+ int size;
+ msg.pop ("BB") >> addr >> size;
+ for (Instances::const_iterator i = instances_.begin ();
+ i != instances_.end (); ++i)
+ {
+ if (addr == (*i)->slave_addr_)
+ {
+ assert (size <= UCOO_CONFIG_HAL_I2C_SLAVE_BUFFER_SIZE);
+ char buf[size];
+ int n = (*i)->slave_data_handler_->to_send (buf, size);
+ mex::Msg rsp (read_mtype_);
+ rsp.push (buf, n);
+ node_.response (rsp);
+ break;
+ }
+ }
+}
+
+void
+I2cHostShared::handle_write (mex::Msg &msg)
+{
+ uint8_t addr;
+ msg.pop ("B") >> addr;
+ for (Instances::const_iterator i = instances_.begin ();
+ i != instances_.end (); ++i)
+ {
+ if (addr == (*i)->slave_addr_)
+ {
+ int size = msg.len ();
+ assert (size <= UCOO_CONFIG_HAL_I2C_SLAVE_BUFFER_SIZE);
+ (*i)->slave_data_handler_->to_recv (msg.pop (size), size);
+ break;
+ }
+ }
+}
+
+I2cHostShared *I2cHost::shared_;
+
+I2cHost::I2cHost (Host &host, int n)
+ : n_ (n), slave_addr_ (0), slave_data_handler_ (0),
+ master_status_ (STATUS_ERROR)
+{
+ if (!shared_)
+ {
+ static I2cHostShared shared (host);
+ shared_ = &shared;
+ }
+ shared_->register_instance (host, *this);
+ // n is not used, there is no support for several buses in the MEX
+ // messages at the moment.
+}
+
+void
+I2cHost::send (uint8_t addr, const char *buf, int count)
+{
+ // Update status, there is no background task.
+ master_status_ = shared_->send (addr, buf, count);
+ // If needed, call callback.
+ if (finished_handler_)
+ finished_handler_->finished (master_status_);
+}
+
+void
+I2cHost::recv (uint8_t addr, char *buf, int count)
+{
+ // Update status, there is no background task.
+ master_status_ = shared_->recv (addr, buf, count);
+ // If needed, call callback.
+ if (finished_handler_)
+ finished_handler_->finished (master_status_);
+}
+
+int
+I2cHost::status ()
+{
+ return master_status_;
+}
+
+int
+I2cHost::wait ()
+{
+ // Transfers are immediate.
+ return status ();
+}
+
+void
+I2cHost::register_data (uint8_t addr, DataHandler &data_handler)
+{
+ slave_addr_ = addr;
+ slave_data_handler_ = &data_handler;
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/i2c/i2c.host.hh b/ucoo/hal/i2c/i2c.host.hh
new file mode 100644
index 0000000..c0bb7f9
--- /dev/null
+++ b/ucoo/hal/i2c/i2c.host.hh
@@ -0,0 +1,66 @@
+#ifndef ucoo_hal_i2c_i2c_host_hh
+#define ucoo_hal_i2c_i2c_host_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/i2c.hh"
+#include "ucoo/arch/host/host.hh"
+
+namespace ucoo {
+
+class I2cHostShared;
+
+/// I2C interface, host version.
+class I2cHost : public I2c
+{
+ public:
+ /// Initialise the Nth I2C.
+ I2cHost (Host &host, int n);
+ /// See I2cMaster::send.
+ void send (uint8_t addr, const char *buf, int count);
+ /// See I2cMaster::recv.
+ void recv (uint8_t addr, char *buf, int count);
+ /// See I2cMaster::status.
+ int status ();
+ /// See I2cMaster::wait.
+ int wait ();
+ /// See I2cSlave::register_data.
+ void register_data (uint8_t addr, DataHandler &data_handler);
+ private:
+ /// I2C number.
+ int n_;
+ /// Slave address.
+ uint8_t slave_addr_;
+ /// Handler called to source or sink data for slave exchanges.
+ DataHandler *slave_data_handler_;
+ /// Current master transfer status.
+ int master_status_;
+ /// Shared context.
+ static I2cHostShared *shared_;
+ friend class I2cHostShared;
+};
+
+} // namespace ucoo
+
+
+#endif // ucoo_hal_i2c_i2c_host_hh
diff --git a/ucoo/hal/i2c/i2c_hard.stm32.cc b/ucoo/hal/i2c/i2c_hard.stm32.cc
new file mode 100644
index 0000000..8122d15
--- /dev/null
+++ b/ucoo/hal/i2c/i2c_hard.stm32.cc
@@ -0,0 +1,396 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "i2c_hard.stm32.hh"
+
+#include <libopencm3/stm32/i2c.h>
+#include <libopencm3/stm32/f4/rcc.h>
+#include <libopencm3/cm3/nvic.h>
+
+#include "ucoo/utils/trace.hh"
+
+namespace ucoo {
+
+/// Local trace.
+static Trace<UCOO_CONFIG_HAL_I2C_TRACE> i2c_trace;
+
+static const int i2c_nb = 3;
+
+/// Information on I2C hardware structure.
+struct i2c_hardware_t
+{
+ /// I2C base address.
+ uint32_t base;
+ /// RCC enable bit.
+ uint32_t rcc_en;
+ /// Corresponding event IRQ (error IRQ is next one).
+ int ev_irq;
+};
+
+/// Information on I2C hardware array, this is zero indexed, I2C1 is at index
+/// 0.
+static const i2c_hardware_t i2c_hardware[i2c_nb] =
+{
+ { I2C1_BASE, RCC_APB1ENR_I2C1EN, NVIC_I2C1_EV_IRQ },
+ { I2C2_BASE, RCC_APB1ENR_I2C2EN, NVIC_I2C2_EV_IRQ },
+ { I2C3_BASE, RCC_APB1ENR_I2C3EN, NVIC_I2C3_EV_IRQ },
+};
+
+static I2cHard *i2c_instances[i2c_nb];
+
+} // namespace ucoo
+
+extern "C" {
+
+void i2c1_ev_isr () { ucoo::I2cHard::ev_isr (0); }
+
+void i2c1_er_isr () { ucoo::I2cHard::er_isr (0); }
+
+void i2c2_ev_isr () { ucoo::I2cHard::ev_isr (1); }
+
+void i2c2_er_isr () { ucoo::I2cHard::er_isr (1); }
+
+void i2c3_ev_isr () { ucoo::I2cHard::ev_isr (2); }
+
+void i2c3_er_isr () { ucoo::I2cHard::er_isr (2); }
+
+}
+
+namespace ucoo {
+
+I2cHard::I2cHard (int n)
+ : n_ (n), enabled_ (false), slave_addr_ (0), slave_data_handler_ (0),
+ master_ (false), master_status_ (STATUS_ERROR), master_buf_ (0)
+{
+ assert (n < i2c_nb);
+ assert (!i2c_instances[n]);
+ i2c_instances[n] = this;
+}
+
+I2cHard::~I2cHard ()
+{
+ disable ();
+ i2c_instances[n_] = 0;
+}
+
+void
+I2cHard::enable (int speed)
+{
+ enabled_ = true;
+ uint32_t base = i2c_hardware[n_].base;
+ // Turn on.
+ rcc_peripheral_enable_clock (&RCC_APB1ENR, i2c_hardware[n_].rcc_en);
+ // Reset.
+ I2C_CR1 (base) = I2C_CR1_SWRST;
+ // TODO: make sure the bus is free!!! How!
+ I2C_CR1 (base) = 0;
+ // Compute clock parameters.
+ int pclk = rcc_ppre1_frequency;
+ int pclk_mhz = pclk / 1000000;
+ uint16_t ccr, tris;
+ if (speed <= 100000)
+ {
+ ccr = pclk / speed / 2;
+ tris = pclk_mhz + 1;
+ }
+ else
+ {
+ assert (speed <= 400000);
+ ccr = I2C_CCR_FS | I2C_CCR_DUTY | (pclk / speed / 25);
+ tris = pclk_mhz * 3 / 10 + 1;
+ }
+ // Set all parameters.
+ I2C_CCR (base) = ccr;
+ I2C_TRISE (base) = tris;
+ I2C_OAR1 (base) = slave_addr_ | (1 << 14);
+ I2C_OAR2 (base) = 0;
+ I2C_CR2 (base) = I2C_CR2_ITEVTEN | I2C_CR2_ITERREN | pclk_mhz;
+ // Enable.
+ nvic_enable_irq (i2c_hardware[n_].ev_irq);
+ nvic_enable_irq (i2c_hardware[n_].ev_irq + 1);
+ I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_PE;
+
+}
+
+void
+I2cHard::disable ()
+{
+ if (enabled_)
+ {
+ enabled_ = false;
+ uint32_t base = i2c_hardware[n_].base;
+ // TODO: wait for end of transfer?
+ // Disable.
+ nvic_disable_irq (i2c_hardware[n_].ev_irq);
+ nvic_disable_irq (i2c_hardware[n_].ev_irq + 1);
+ I2C_CR1 (base) = 0;
+ // Turn off.
+ rcc_peripheral_disable_clock (&RCC_APB1ENR,
+ i2c_hardware[n_].rcc_en);
+ }
+}
+
+void
+I2cHard::transfer (uint8_t addr, char *buf, int count)
+{
+ assert (enabled_ && count);
+ // No need to lock, master is not busy.
+ assert (master_status_ != STATUS_BUSY);
+ uint32_t base = i2c_hardware[n_].base;
+ // Wait until STOP condition terminated, polling is the only way.
+ while (I2C_CR1 (base) & I2C_CR1_STOP)
+ barrier ();
+ // Now, program next transfer.
+ master_status_ = STATUS_BUSY;
+ master_slave_addr_ = addr;
+ master_buf_ = buf;
+ master_count_ = count;
+ // TODO: multimaster: about ACK, may have to lock IRQ for multimaster.
+ I2C_CR1 (base) |= I2C_CR1_START;
+}
+
+void
+I2cHard::send (uint8_t addr, const char *buf, int count)
+{
+ transfer (addr, const_cast<char *> (buf), count);
+}
+
+void
+I2cHard::recv (uint8_t addr, char *buf, int count)
+{
+ assert (count >= 2); // TODO: count = 1 not supported, there is no IT!
+ // LSB = 1 for receiver mode.
+ transfer (addr | 1, buf, count);
+}
+
+int
+I2cHard::status ()
+{
+ return master_status_;
+}
+
+int
+I2cHard::wait ()
+{
+ while (master_status_ == STATUS_BUSY)
+ barrier ();
+ return master_status_;
+}
+
+void
+I2cHard::register_data (uint8_t addr, DataHandler &data_handler)
+{
+ assert ((addr & 1) == 0);
+ slave_addr_ = addr;
+ slave_data_handler_ = &data_handler;
+ if (enabled_)
+ {
+ uint32_t base = i2c_hardware[n_].base;
+ // Just in case a transfer is triggered right now.
+ barrier ();
+ // According to datasheet, bit 14 should be 1!
+ I2C_OAR1 (base) = addr | (1 << 14);
+ }
+}
+
+void
+I2cHard::ev_isr (int n)
+{
+ uint32_t base = i2c_hardware[n].base;
+ assert (i2c_instances[n]);
+ I2cHard &i2c = *i2c_instances[n];
+ i2c_trace ("<%d> event isr", n);
+ while (1)
+ {
+ uint16_t sr1 = I2C_SR1 (base);
+ i2c_trace ("<%d> sr1=%04x", n, sr1);
+ // Can not read SR2 because doing so would clear the ADDR bit.
+ if (i2c.master_)
+ {
+ if (sr1 & I2C_SR1_ADDR)
+ {
+ uint16_t sr2;
+ // If only one or two bytes should be received, disable ACK
+ // before reading SR2, and STOP after... Crappy hardware!
+ if ((i2c.master_slave_addr_ & 1) && i2c.buf_count_ == 1)
+ {
+ I2C_CR1 (base) = I2C_CR1_PE;
+ sr2 = I2C_SR2 (base);
+ I2C_CR1 (base) = I2C_CR1_STOP | I2C_CR1_PE;
+ // TODO: what to wait now? Unsupported for now.
+ }
+ else if ((i2c.master_slave_addr_ & 1) && i2c.buf_count_ == 2)
+ {
+ I2C_CR1 (base) = I2C_CR1_POS | I2C_CR1_PE;
+ sr2 = I2C_SR2 (base);
+ // Wait for BTF.
+ }
+ else
+ {
+ sr2 = I2C_SR2 (base);
+ I2C_CR2 (base) |= I2C_CR2_ITBUFEN;
+ }
+ i2c_trace ("<%d> master sr2=%04x", n, sr2);
+ }
+ else if (sr1 & I2C_SR1_TxE
+ && i2c.buf_index_ < i2c.buf_count_)
+ {
+ i2c_trace ("<%d> master tx index=%d", n, i2c.buf_index_);
+ // Send next byte.
+ I2C_DR (base) = i2c.master_buf_[i2c.buf_index_++];
+ // Wait for BTF if last one.
+ if (i2c.buf_index_ == i2c.buf_count_)
+ I2C_CR2 (base) &= ~I2C_CR2_ITBUFEN;
+ }
+ else if (sr1 & I2C_SR1_RxNE
+ && i2c.buf_count_ - i2c.buf_index_ > 3)
+ {
+ i2c_trace ("<%d> master rx index=%d", n, i2c.buf_index_);
+ i2c.master_buf_[i2c.buf_index_++] = I2C_DR (base);
+ if (i2c.buf_count_ - i2c.buf_index_ == 3)
+ // Wait for BTF.
+ I2C_CR2 (base) &= ~I2C_CR2_ITBUFEN;
+ }
+ else if (sr1 & I2C_SR1_BTF)
+ {
+ i2c_trace ("<%d> master btf index=%d", n, i2c.buf_index_);
+ if (!(i2c.master_slave_addr_ & 1))
+ {
+ // End of transmission.
+ I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_STOP | I2C_CR1_PE;
+ i2c.master_ = false;
+ i2c.master_status_ = i2c.buf_index_;
+ if (i2c.finished_handler_)
+ i2c.finished_handler_->finished (i2c.master_status_);
+ }
+ else if (i2c.buf_count_ - i2c.buf_index_ == 3)
+ {
+ // Near end of reception.
+ I2C_CR1 (base) = I2C_CR1_PE;
+ i2c.master_buf_[i2c.buf_index_++] = I2C_DR (base);
+ // Wait for BTF.
+ }
+ else
+ {
+ // End of reception.
+ I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_STOP | I2C_CR1_PE;
+ if (i2c.buf_count_ - i2c.buf_index_ == 2)
+ i2c.master_buf_[i2c.buf_index_++] = I2C_DR (base);
+ i2c.master_buf_[i2c.buf_index_++] = I2C_DR (base);
+ i2c.master_ = false;
+ i2c.master_status_ = i2c.buf_index_;
+ if (i2c.finished_handler_)
+ i2c.finished_handler_->finished (i2c.master_status_);
+ }
+ }
+ else
+ break;
+ }
+ else
+ {
+ if (sr1 & I2C_SR1_ADDR)
+ {
+ uint16_t sr2 = I2C_SR2 (base);
+ i2c_trace ("<%d> slave sr2=%04x", n, sr2);
+ // Initiate new slave transfer.
+ if (sr2 & I2C_SR2_TRA)
+ {
+ i2c.buf_count_ = i2c.slave_data_handler_->to_send
+ (i2c.slave_buf_, sizeof (i2c.slave_buf_));
+ }
+ else
+ i2c.buf_count_ = sizeof (i2c.slave_buf_);
+ i2c.buf_index_ = 0;
+ I2C_CR2 (base) |= I2C_CR2_ITBUFEN;
+ }
+ else if (sr1 & I2C_SR1_TxE)
+ {
+ i2c_trace ("<%d> slave tx index=%d", n, i2c.buf_index_);
+ uint8_t b = 0xff;
+ if (i2c.buf_index_ < i2c.buf_count_)
+ b = i2c.slave_buf_[i2c.buf_index_++];
+ I2C_DR (base) = b;
+ }
+ else if (sr1 & I2C_SR1_RxNE)
+ {
+ i2c_trace ("<%d> slave rx index=%d", n, i2c.buf_index_);
+ uint8_t b = I2C_DR (base);
+ if (i2c.buf_index_ < i2c.buf_count_)
+ i2c.slave_buf_[i2c.buf_index_++] = b;
+ }
+ else if (sr1 & I2C_SR1_STOPF)
+ {
+ i2c_trace ("<%d> slave stop", n);
+ i2c.slave_data_handler_->to_recv (i2c.slave_buf_, i2c.buf_index_);
+ // TODO: multimaster: there is no way to write in this
+ // register if a START was requested to switch to master mode!
+ I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_PE;
+ I2C_CR2 (base) &= ~I2C_CR2_ITBUFEN;
+ }
+ else if (sr1 & I2C_SR1_SB)
+ {
+ i2c_trace ("<%d> master start", n);
+ // Starting master mode.
+ I2C_DR (base) = i2c.master_slave_addr_;
+ i2c.master_ = true;
+ i2c.buf_count_ = i2c.master_count_;
+ i2c.buf_index_ = 0;
+ }
+ else
+ break;
+ }
+
+ }
+}
+
+void
+I2cHard::er_isr (int n)
+{
+ uint32_t base = i2c_hardware[n].base;
+ assert (i2c_instances[n]);
+ I2cHard &i2c = *i2c_instances[n];
+ uint16_t sr1 = I2C_SR1 (base);
+ I2C_SR1 (base) = 0;
+ i2c_trace ("<%d> error isr sr1=%04x", n, sr1);
+ if (i2c.master_)
+ {
+ if (sr1 & I2C_SR1_ARLO)
+ {
+ // Try again.
+ I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_START | I2C_CR1_PE;
+ i2c.master_ = false;
+ }
+ else if (sr1 & I2C_SR1_AF)
+ {
+ I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_STOP | I2C_CR1_PE;
+ i2c.master_ = false;
+ i2c.master_status_ = i2c.buf_index_;
+ if (i2c.finished_handler_)
+ i2c.finished_handler_->finished (i2c.master_status_);
+ }
+ }
+ I2C_CR2 (base) &= ~I2C_CR2_ITBUFEN;
+ // TODO: handle misplaced STOP errata.
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/i2c/i2c_hard.stm32.hh b/ucoo/hal/i2c/i2c_hard.stm32.hh
new file mode 100644
index 0000000..94e4259
--- /dev/null
+++ b/ucoo/hal/i2c/i2c_hard.stm32.hh
@@ -0,0 +1,91 @@
+#ifndef ucoo_hal_i2c_i2c_hard_stm32_hh
+#define ucoo_hal_i2c_i2c_hard_stm32_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/i2c.hh"
+
+#include "config/hal/i2c.hh"
+
+namespace ucoo {
+
+/// I2C interface, using dedicated hardware.
+class I2cHard : public I2c
+{
+ public:
+ /// Constructor for the Nth I2C.
+ I2cHard (int n);
+ /// Shutdown.
+ ~I2cHard ();
+ /// Enable and setup
+ void enable (int speed = 100000);
+ /// Disable.
+ void disable ();
+ /// See I2cMaster::send.
+ void send (uint8_t addr, const char *buf, int count);
+ /// See I2cMaster::recv.
+ void recv (uint8_t addr, char *buf, int count);
+ /// See I2cMaster::status.
+ int status ();
+ /// See I2cMaster::wait.
+ int wait ();
+ /// See I2cSlave::register_data.
+ void register_data (uint8_t addr, DataHandler &data_handler);
+ /// Event ISR.
+ static void ev_isr (int n);
+ /// Error ISR.
+ static void er_isr (int n);
+ private:
+ /// Start a master transfer, send or recv, depending on addr LSB.
+ void transfer (uint8_t addr, char *buf, int count);
+ private:
+ /// I2C number.
+ int n_;
+ /// Is it enabled?
+ bool enabled_;
+ /// Slave address.
+ uint8_t slave_addr_;
+ /// Handler called to source or sink data for slave exchanges.
+ DataHandler *slave_data_handler_;
+ /// Slave buffer.
+ char slave_buf_[UCOO_CONFIG_HAL_I2C_SLAVE_BUFFER_SIZE];
+ /// Current buffer count (bytes to send), or buffer size (available room).
+ int buf_count_;
+ /// Current buffer index (position to read byte to send or write received
+ /// byte).
+ int buf_index_;
+ /// Master access granted.
+ bool master_;
+ /// Current master transfer status.
+ int master_status_;
+ /// Current master transfer buffer.
+ char *master_buf_;
+ /// Current master transfer size, copied to buf_count_ when active.
+ int master_count_;
+ /// Current master transfer slave address, LSB is set for receiver mode.
+ uint8_t master_slave_addr_;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_i2c_i2c_hard_stm32_hh
diff --git a/ucoo/hal/i2c/i2c_slave_data_buffer.cc b/ucoo/hal/i2c/i2c_slave_data_buffer.cc
new file mode 100644
index 0000000..1ba3a3a
--- /dev/null
+++ b/ucoo/hal/i2c/i2c_slave_data_buffer.cc
@@ -0,0 +1,80 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "i2c_slave_data_buffer.hh"
+
+#include <algorithm>
+
+namespace ucoo {
+
+I2cSlaveDataBuffer::I2cSlaveDataBuffer (char *send_buf, int send_size,
+ char *recv_buf, int recv_size)
+ : send_buf_ (send_buf), send_size_ (send_size), send_count_ (0),
+ recv_buf_ (recv_buf), recv_size_ (recv_size), recv_count_ (0)
+{
+}
+
+void
+I2cSlaveDataBuffer::update (const char *buf, int count)
+{
+ int r = std::min (count, send_size_);
+ irq_flags_t flags = irq_lock ();
+ std::copy (buf, buf + r, send_buf_);
+ send_count_ = r;
+ irq_restore (flags);
+}
+
+int
+I2cSlaveDataBuffer::poll (char *buf, int count)
+{
+ // Test to avoid superfluous irq lock. This is not a problem if
+ // condition become false before irq is locked.
+ if (recv_count_)
+ {
+ irq_flags_t flags = irq_lock ();
+ int r = std::min (count, recv_count_);
+ recv_count_ = 0;
+ std::copy (recv_buf_, recv_buf_ + r, buf);
+ irq_restore (flags);
+ return r;
+ }
+ else return 0;
+}
+
+int
+I2cSlaveDataBuffer::to_send (char *buf, int count)
+{
+ int r = std::min (count, send_count_);
+ std::copy (send_buf_, send_buf_ + r, buf);
+ return r;
+}
+
+void
+I2cSlaveDataBuffer::to_recv (const char *buf, int count)
+{
+ int r = std::min (count, recv_size_);
+ std::copy (buf, buf + r, recv_buf_);
+ recv_count_ = r;
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/i2c/i2c_slave_data_buffer.hh b/ucoo/hal/i2c/i2c_slave_data_buffer.hh
new file mode 100644
index 0000000..eae45ae
--- /dev/null
+++ b/ucoo/hal/i2c/i2c_slave_data_buffer.hh
@@ -0,0 +1,71 @@
+#ifndef ucoo_hal_i2c_i2c_slave_data_buffer_hh
+#define ucoo_hal_i2c_i2c_slave_data_buffer_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/i2c.hh"
+
+namespace ucoo {
+
+/// Data sink and source for I2C slave. Store any received data and data to
+/// send in buffers.
+class I2cSlaveDataBuffer : public I2cSlave::DataHandler
+{
+ public:
+ /// Constructor, take buffers.
+ I2cSlaveDataBuffer (char *send_buf, int send_size,
+ char *recv_buf, int recv_size);
+ /// Update slave internal buffer, will be sent to master on request.
+ void update (const char *buf, int count);
+ /// If data has been received, copy it to provided buffer and return its
+ /// size. Else, return 0.
+ int poll (char *buf, int count);
+ /// See I2cSlave::DataHandler::to_send.
+ int to_send (char *buf, int count);
+ /// See I2cSlave::DataHandler::to_recv.
+ void to_recv (const char *buf, int count);
+ private:
+ char *send_buf_;
+ int send_size_, send_count_;
+ char *recv_buf_;
+ int recv_size_, recv_count_;
+};
+
+/// Same as I2cSlaveDataBuffer, but include buffers.
+template<int send_size, int recv_size>
+class I2cSlaveDataBufferSize : public I2cSlaveDataBuffer
+{
+ public:
+ /// Default constructor.
+ I2cSlaveDataBufferSize ()
+ : I2cSlaveDataBuffer (send_array_, sizeof (send_array_),
+ recv_array_, sizeof (recv_array_))
+ { }
+ private:
+ char send_array_[send_size];
+ char recv_array_[recv_size];
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_i2c_i2c_slave_data_buffer_hh
diff --git a/ucoo/hal/i2c/test/Makefile b/ucoo/hal/i2c/test/Makefile
new file mode 100644
index 0000000..5046862
--- /dev/null
+++ b/ucoo/hal/i2c/test/Makefile
@@ -0,0 +1,9 @@
+BASE = ../../../..
+
+TARGETS = host stm32f4
+PROGS = test_i2c
+test_i2c_SOURCES = test_i2c.cc
+
+MODULES = hal/i2c utils base/test hal/usb
+
+include $(BASE)/build/top.mk
diff --git a/ucoo/hal/i2c/test/hub.py b/ucoo/hal/i2c/test/hub.py
new file mode 100644
index 0000000..c6c77f7
--- /dev/null
+++ b/ucoo/hal/i2c/test/hub.py
@@ -0,0 +1,6 @@
+# Hub for test.
+from mex.hub import Hub
+def log (x):
+ print x
+h = Hub (min_clients = 1, log = log)
+h.wait ()
diff --git a/ucoo/hal/i2c/test/test_i2c.cc b/ucoo/hal/i2c/test/test_i2c.cc
new file mode 100644
index 0000000..7fc7772
--- /dev/null
+++ b/ucoo/hal/i2c/test/test_i2c.cc
@@ -0,0 +1,226 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/i2c/i2c.hh"
+
+#include "ucoo/arch/arch.hh"
+#include "ucoo/base/test/test.hh"
+
+#ifdef TARGET_stm32
+# include <libopencm3/stm32/f4/rcc.h>
+# include "ucoo/hal/gpio/gpio.hh"
+#endif
+
+#ifdef TARGET_host
+# define TEST_NOT_THERE 0
+#else
+# define TEST_NOT_THERE 1
+#endif
+
+#include "ucoo/utils/delay.hh"
+
+#include <algorithm>
+#include <cstring>
+
+static const int buffer_size = 16;
+static const int margin = 5;
+static const uint8_t a1 = 0x2c, a2 = 0x2e, a3 = 0x42;
+
+void
+test_basic (ucoo::TestSuite &tsuite, ucoo::I2cMaster &m,
+ ucoo::I2cSlaveDataBuffer &d, uint8_t addr)
+{
+ tsuite.group ("basic");
+ {
+ ucoo::Test test (tsuite, "recv");
+ const char *hello = "Hello world!";
+ char buf[buffer_size + margin];
+ d.update (hello, std::strlen (hello) + 1);
+ char ref[buffer_size + margin];
+ int ref_size = std::strlen (hello) + 1;
+ std::copy (hello, hello + ref_size, ref);
+#ifdef TARGET_stm32
+ // Slave is not able to signal its buffer end. Extra bytes will be
+ // read as 0xff.
+ std::fill (ref + ref_size, ref + sizeof (ref), 0xff);
+ ref_size = sizeof (ref);
+#endif
+ for (int len = 2; len < (int) sizeof (buf); len++)
+ {
+ std::fill (buf, buf + sizeof (buf), 42);
+ m.recv (addr, buf, len);
+ int r = m.wait ();
+ int rexp = std::min (len, ref_size);
+ test_fail_break_unless (test, r == rexp);
+ test_fail_break_unless (test, std::equal (buf, buf + rexp, ref));
+ test_fail_break_unless (test, std::count (buf, buf + sizeof (buf), 42)
+ == (int) sizeof (buf) - rexp);
+ }
+ }
+ {
+ ucoo::Test test (tsuite, "send");
+ // Slave is supposed to signal when it received enough data, but this
+ // is not implemented.
+ char buf[buffer_size + margin];
+ for (int len = 1; len < (int) sizeof (buf); len++)
+ {
+ int r;
+ // Before transfer, no data.
+ r = d.poll (buf, sizeof (buf));
+ test_fail_break_unless (test, r == 0);
+ // Send data.
+ char c = '0' + len % 10;
+ std::fill (buf, buf + len, c);
+ m.send (addr, buf, len);
+ r = m.wait ();
+ test_fail_break_unless (test, r == len);
+ // Let some time for slave to finish reception.
+ ucoo::delay_ms (1);
+ // Check what is received.
+ r = d.poll (buf, sizeof (buf));
+ test_fail_break_unless (test, r == std::min (len, buffer_size));
+ test_fail_break_unless (test, std::count (buf, buf + r, c) == r);
+ }
+ }
+ do {
+ ucoo::Test test (tsuite, "callback");
+ // Callback object will start a reception, then a transmission of what
+ // was received.
+ class TestCallback : public ucoo::I2cMaster::FinishedHandler
+ {
+ ucoo::I2cMaster &m_;
+ uint8_t addr_;
+ int step_;
+ char buf_[buffer_size];
+ public:
+ bool failed;
+ public:
+ TestCallback (ucoo::I2cMaster &m, uint8_t addr)
+ : m_ (m), addr_ (addr), step_ (0), failed (false) { }
+ void finished (int status)
+ {
+ if (status != buffer_size)
+ failed = true;
+ else
+ {
+ switch (step_)
+ {
+ case 0:
+ step_++;
+ m_.recv (addr_, buf_, buffer_size);
+ break;
+ case 1:
+ step_++;
+ m_.send (addr_, buf_, buffer_size);
+ break;
+ case 2:
+ // Nothing, stop.
+ break;
+ }
+ }
+ }
+ };
+ TestCallback callback (m, addr);
+ m.register_finished (callback);
+ // Set slave data.
+ char buf[buffer_size];
+ std::fill (buf, buf + sizeof (buf), 42);
+ d.update (buf, sizeof (buf));
+ // Start transfers.
+ std::fill (buf, buf + sizeof (buf), 21);
+ m.send (addr, buf, sizeof (buf));
+ // Will only return after the last transfer.
+ m.wait ();
+ m.unregister_finished ();
+ test_fail_break_unless (test, !callback.failed);
+ // Let some time for slave to finish reception.
+ ucoo::delay_ms (1);
+ // Check what is received by slave (master should have read 42 from
+ // slave and send it back).
+ int r = d.poll (buf, sizeof (buf));
+ test_fail_break_unless (test, r == buffer_size);
+ test_fail_break_unless (test, std::count (buf, buf + r, 42) == r);
+ } while (0);
+}
+
+void
+test_not_there (ucoo::TestSuite &tsuite, ucoo::I2cMaster &m, uint8_t addr)
+{
+ tsuite.group ("not there");
+ do {
+ ucoo::Test test (tsuite, "recv");
+ char buf[buffer_size];
+ m.recv (addr, buf, buffer_size);
+ int r = m.wait ();
+ test_fail_break_unless (test, r == ucoo::I2cMaster::STATUS_ERROR);
+ } while (0);
+ do {
+ ucoo::Test test (tsuite, "send");
+ char buf[buffer_size];
+ std::fill (buf, buf + buffer_size, 42);
+ m.send (addr, buf, buffer_size);
+ int r = m.wait ();
+ test_fail_break_unless (test, r == ucoo::I2cMaster::STATUS_ERROR);
+ } while (0);
+}
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ ucoo::TestSuite tsuite ("i2c");
+#if defined (TARGET_host)
+ ucoo::Host host ("test_i2c");
+ host.parse_options ();
+ ucoo::I2cHost i2c1 (host, 0);
+ ucoo::I2cHost i2c2 (host, 1);
+#elif defined (TARGET_stm32)
+ // I2C1: B6: SCL, B9: SDA
+ // I2C3: A8: SCL, C9: SDA
+ rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN);
+ rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPBEN);
+ rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPCEN);
+ gpio_mode_setup (GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6 | GPIO9);
+ gpio_mode_setup (GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO8);
+ gpio_mode_setup (GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9);
+ gpio_set_output_options (GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO6 | GPIO9);
+ gpio_set_output_options (GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO8);
+ gpio_set_output_options (GPIOC, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO9);
+ gpio_set_af (GPIOB, GPIO_AF4, GPIO6 | GPIO9);
+ gpio_set_af (GPIOA, GPIO_AF4, GPIO8);
+ gpio_set_af (GPIOC, GPIO_AF4, GPIO9);
+ ucoo::I2cHard i2c1 (0);
+ ucoo::I2cHard i2c2 (2);
+ i2c1.enable ();
+ i2c2.enable ();
+#endif
+ ucoo::I2cSlaveDataBufferSize<16, 16> data1, data2;
+ i2c1.register_data (a1, data1);
+ i2c2.register_data (a2, data2);
+ // Run tests.
+ test_basic (tsuite, i2c1, data2, a2);
+ if (TEST_NOT_THERE)
+ test_not_there (tsuite, i2c1, a3);
+ test_basic (tsuite, i2c2, data1, a1);
+ return tsuite.report () ? 0 : 1;
+}
diff --git a/ucoo/hal/spi/Module b/ucoo/hal/spi/Module
new file mode 100644
index 0000000..a6df136
--- /dev/null
+++ b/ucoo/hal/spi/Module
@@ -0,0 +1 @@
+hal_spi_SOURCES := spi_soft.cc
diff --git a/ucoo/hal/spi/spi_soft.cc b/ucoo/hal/spi/spi_soft.cc
new file mode 100644
index 0000000..3bcc0d5
--- /dev/null
+++ b/ucoo/hal/spi/spi_soft.cc
@@ -0,0 +1,125 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "spi_soft.hh"
+
+#include "ucoo/utils/delay.hh"
+#include "ucoo/common.hh"
+
+namespace ucoo {
+
+SpiSoftMaster::SpiSoftMaster (Io &sck, Io &mosi, Io &miso)
+ : sck_ (sck), mosi_ (mosi), miso_ (miso), enabled_ (false)
+{
+}
+
+SpiSoftMaster::~SpiSoftMaster ()
+{
+ disable ();
+}
+
+void
+SpiSoftMaster::enable (int speed, SpiMode mode)
+{
+ enabled_ = true;
+ // Take pins ownership, set SCK according to CPOL.
+ sck_.set (mode >= SPI_MODE_2);
+ sck_.output ();
+ mosi_.reset ();
+ mosi_.output ();
+ miso_.input ();
+ // Set clock period and clock phase.
+ half_period_ns_ = 1000 * 1000 * 1000 / 2 / speed;
+ cpha_ = mode & 1;
+}
+
+void
+SpiSoftMaster::disable ()
+{
+ enabled_ = false;
+ // Release pins.
+ sck_.input ();
+ sck_.reset ();
+ mosi_.input ();
+}
+
+void
+SpiSoftMaster::send_and_recv (const char *tx_buf, char *rx_buf, int count)
+{
+ while (count--)
+ *rx_buf++ = send_and_recv (*tx_buf++);
+}
+
+char
+SpiSoftMaster::send_and_recv (char tx)
+{
+ assert (enabled_);
+ uint8_t i, rx = 0;
+ // Depending on clock phase, sample is done on first transition or second
+ // transition.
+ for (i = 0x80; i; i >>= 1)
+ {
+ // Setup stage.
+ if (cpha_)
+ sck_.toggle ();
+ mosi_.set (tx & i);
+ delay_ns (half_period_ns_);
+ // Sample stage.
+ sck_.toggle ();
+ if (miso_.get ())
+ rx |= i;
+ delay_ns (half_period_ns_);
+ // SCK toggle for next setup stage.
+ if (!cpha_)
+ sck_.toggle ();
+ }
+ return rx;
+}
+
+void
+SpiSoftMaster::send (const char *tx_buf, int count)
+{
+ while (count--)
+ send (*tx_buf++);
+}
+
+void
+SpiSoftMaster::send (char tx)
+{
+ send_and_recv (tx);
+}
+
+void
+SpiSoftMaster::recv (char *rx_buf, int count)
+{
+ while (count--)
+ *rx_buf++ = recv ();
+}
+
+char
+SpiSoftMaster::recv ()
+{
+ return send_and_recv (0);
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/spi/spi_soft.hh b/ucoo/hal/spi/spi_soft.hh
new file mode 100644
index 0000000..2dc1a64
--- /dev/null
+++ b/ucoo/hal/spi/spi_soft.hh
@@ -0,0 +1,64 @@
+#ifndef ucoo_hal_spi_spi_soft_hh
+#define ucoo_hal_spi_spi_soft_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/spi_master.hh"
+#include "ucoo/intf/io.hh"
+
+namespace ucoo {
+
+/// Software implementation of a SPI master.
+class SpiSoftMaster : public SpiMaster
+{
+ public:
+ /// Constructor, need all SPI pins.
+ SpiSoftMaster (Io &sck, Io &mosi, Io &miso);
+ /// Destructor, disable.
+ ~SpiSoftMaster ();
+ /// Enable and setup.
+ void enable (int speed_hz, SpiMode mode = SPI_MODE_0);
+ /// Disable.
+ void disable ();
+ /// See SpiMaster::send_and_recv.
+ void send_and_recv (const char *tx_buf, char *rx_buf, int count);
+ /// Send and receive one byte.
+ char send_and_recv (char tx);
+ /// See SpiMaster::send.
+ void send (const char *tx_buf, int count);
+ /// Send one byte.
+ void send (char tx);
+ /// See SpiMaster::recv.
+ void recv (char *rx_buf, int count);
+ /// Receive one byte.
+ char recv ();
+ private:
+ Io &sck_, &mosi_, &miso_;
+ int half_period_ns_;
+ bool cpha_;
+ bool enabled_;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_spi_spi_soft_hh
diff --git a/ucoo/hal/spi/test/Makefile b/ucoo/hal/spi/test/Makefile
new file mode 100644
index 0000000..76b8230
--- /dev/null
+++ b/ucoo/hal/spi/test/Makefile
@@ -0,0 +1,9 @@
+BASE = ../../../..
+
+TARGETS = stm32f4
+PROGS = test_spi
+test_spi_SOURCES = test_spi.cc
+
+MODULES = hal/spi hal/gpio utils base/test hal/usb
+
+include $(BASE)/build/top.mk
diff --git a/ucoo/hal/spi/test/test_spi.cc b/ucoo/hal/spi/test/test_spi.cc
new file mode 100644
index 0000000..fa26abc
--- /dev/null
+++ b/ucoo/hal/spi/test/test_spi.cc
@@ -0,0 +1,112 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/spi/spi_soft.hh"
+#include "ucoo/hal/gpio/gpio.hh"
+#include "ucoo/utils/delay.hh"
+
+#include "ucoo/arch/arch.hh"
+#include "ucoo/base/test/test.hh"
+
+#include <libopencm3/stm32/f4/rcc.h>
+
+#include <algorithm>
+#include <cstdio>
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ ucoo::Stream &ts = ucoo::test_stream ();
+ // Use connection to LIS302DL device on discovery board.
+ rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN
+ | RCC_AHB1ENR_IOPEEN);
+ ucoo::Gpio ss (GPIOE, 3);
+ ss.set ();
+ ss.output ();
+ ucoo::Gpio sck (GPIOA, 5), mosi (GPIOA, 7), miso (GPIOA, 6);
+ ucoo::SpiSoftMaster spi (sck, mosi, miso);
+ spi.enable (1000000, ucoo::SPI_MODE_3);
+ // Loop with simple IU.
+ char buf[64];
+ unsigned int r;
+ int8_t x, y, z;
+ while (1)
+ {
+ ucoo::delay_ms (200);
+ // Read X, Y, Z.
+ ss.reset ();
+ spi.send (0xe9);
+ x = spi.recv ();
+ spi.recv ();
+ y = spi.recv ();
+ spi.recv ();
+ z = spi.recv ();
+ ss.set ();
+ ucoo::delay_ns (100);
+ r = snprintf (buf, sizeof (buf), "x: %4d, y: %4d, z: %4d\r", x, y, z);
+ r = std::min (sizeof (buf) - 1, r);
+ ts.write (buf, r);
+ // Simple UI.
+ while (ts.poll ())
+ {
+ char c = ts.getc ();
+ switch (c)
+ {
+ case '?':
+ static const char help[] =
+ "\n? - help\n"
+ "w - who am I\n"
+ "o - turn on\n"
+ "f - turn off\n";
+ ts.write (help, sizeof (help));
+ break;
+ case 'w':
+ {
+ // Read Who am I register.
+ ss.reset ();
+ spi.send (0x8f);
+ char rsp = spi.recv ();
+ ss.set ();
+ ucoo::delay_ns (100);
+ // Report result.
+ r = snprintf (buf, sizeof (buf), "\nI am 0x%02x\n",
+ static_cast<unsigned char> (rsp));
+ r = std::min (sizeof (buf) - 1, r);
+ ts.write (buf, r);
+ }
+ break;
+ case 'o':
+ case 'f':
+ {
+ char cmd[] = { 0x20, (char) (c == 'o' ? 0x47 : 0x07) };
+ ss.reset ();
+ spi.send (cmd, sizeof (cmd));
+ ss.set ();
+ ucoo::delay_ns (100);
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/ucoo/hal/uart/Config b/ucoo/hal/uart/Config
new file mode 100644
index 0000000..0a67d63
--- /dev/null
+++ b/ucoo/hal/uart/Config
@@ -0,0 +1,6 @@
+[hal/uart]
+# Size of reception buffer.
+rx_buffer = 32
+# Size of transmission buffer.
+tx_buffer = 32
+
diff --git a/ucoo/hal/uart/Module b/ucoo/hal/uart/Module
new file mode 100644
index 0000000..a9d185e
--- /dev/null
+++ b/ucoo/hal/uart/Module
@@ -0,0 +1 @@
+hal_uart_SOURCES = uart.stm32.cc
diff --git a/ucoo/hal/uart/test/Config b/ucoo/hal/uart/test/Config
new file mode 100644
index 0000000..4fd7571
--- /dev/null
+++ b/ucoo/hal/uart/test/Config
@@ -0,0 +1,4 @@
+[hal/uart]
+rx_buffer = 32
+tx_buffer = 8
+
diff --git a/ucoo/hal/uart/test/Makefile b/ucoo/hal/uart/test/Makefile
new file mode 100644
index 0000000..6989dd2
--- /dev/null
+++ b/ucoo/hal/uart/test/Makefile
@@ -0,0 +1,12 @@
+BASE = ../../../..
+
+TARGETS = host stm32f4
+PROGS = test_uart
+stm32f4_PROGS = test_uart_disc
+test_uart_SOURCES = test_uart.cc
+test_uart_disc_SOURCES = test_uart_disc.cc
+
+MODULES = hal/uart
+test_uart_disc_MODULES = $(MODULES) base/test hal/usb
+
+include $(BASE)/build/top.mk
diff --git a/ucoo/hal/uart/test/test_uart.cc b/ucoo/hal/uart/test/test_uart.cc
new file mode 100644
index 0000000..c1b111c
--- /dev/null
+++ b/ucoo/hal/uart/test/test_uart.cc
@@ -0,0 +1,70 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/uart/uart.hh"
+
+#include "ucoo/arch/arch.hh"
+
+#if defined (TARGET_stm32)
+# include <libopencm3/stm32/f4/rcc.h>
+# include "ucoo/hal/gpio/gpio.hh"
+#endif
+
+#include "ucoo/common.hh"
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+#if defined (TARGET_host)
+ ucoo::Uart u0, u1 ("uart1");
+#elif defined (TARGET_stm32)
+ // D8, D9: UART3
+ // C12, D2: UART5
+ rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPCEN);
+ rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPDEN);
+ gpio_mode_setup (GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO12);
+ gpio_mode_setup (GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO2 | GPIO8 | GPIO9);
+ gpio_set_af (GPIOC, GPIO_AF8, GPIO12);
+ gpio_set_af (GPIOD, GPIO_AF8, GPIO2);
+ gpio_set_af (GPIOD, GPIO_AF7, GPIO8 | GPIO9);
+ ucoo::Uart u0 (2), u1 (4);
+ u0.enable (38400, ucoo::Uart::EVEN, 1);
+ u1.enable (38400, ucoo::Uart::EVEN, 1);
+#endif
+ ucoo::Uart *u[] = { &u0, &u1 };
+ char buf[64];
+ while (1)
+ {
+ for (int i = 0; i < (int) lengthof (u); i++)
+ {
+ if (u[i]->poll ())
+ {
+ int len = u[i]->read (buf, sizeof (buf));
+ u[i]->write (buf, len);
+ }
+ }
+ ucoo::yield ();
+ }
+}
+
diff --git a/ucoo/hal/uart/test/test_uart_disc.cc b/ucoo/hal/uart/test/test_uart_disc.cc
new file mode 100644
index 0000000..e2d307a
--- /dev/null
+++ b/ucoo/hal/uart/test/test_uart_disc.cc
@@ -0,0 +1,128 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/uart/uart.hh"
+
+#include "ucoo/arch/arch.hh"
+#include "ucoo/hal/gpio/gpio.hh"
+#include "ucoo/base/test/test.hh"
+
+#include <libopencm3/stm32/f4/rcc.h>
+
+static void
+check_act (ucoo::Stream &ts, ucoo::Stream &u, char n)
+{
+ char buf[3 + 16 + 1];
+ if (!u.poll ())
+ return;
+ int r = u.read (buf + 3, 16);
+ if (r <= 0)
+ {
+ buf[3] = '#';
+ r = 1;
+ }
+ buf[0] = '<';
+ buf[1] = n;
+ buf[2] = ':';
+ buf[3 + r] = '>';
+ ts.write (buf, 3 + r + 1);
+}
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ ucoo::Stream &ts = ucoo::test_stream ();
+ ucoo::Uart u1 (0);
+ ucoo::Uart u3 (2);
+ ucoo::Uart u4 (3);
+ u1.enable (38400, ucoo::Uart::EVEN, 1);
+ u3.enable (38400, ucoo::Uart::EVEN, 1);
+ u4.enable (38400, ucoo::Uart::EVEN, 1);
+ // For this test, shorten B6 & B7 to have a loopback on UART1, shorten C10
+ // & C11 to connect UART3 to UART4.
+ rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPBEN
+ | RCC_AHB1ENR_IOPCEN);
+ gpio_mode_setup (GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE,
+ GPIO6 | GPIO7);
+ gpio_set_af (GPIOB, GPIO_AF7, GPIO6 | GPIO7);
+ gpio_mode_setup (GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE,
+ GPIO10 | GPIO11);
+ gpio_set_af (GPIOC, GPIO_AF7, GPIO10);
+ gpio_set_af (GPIOC, GPIO_AF8, GPIO11);
+ // Loop to report any activity on ports and provide a simple UI.
+ char buf[64];
+ int buf_i = 0;
+ ucoo::Uart *u = &u1;
+ while (1)
+ {
+ check_act (ts, u1, '1');
+ check_act (ts, u3, '3');
+ check_act (ts, u4, '4');
+ while (ts.poll ())
+ {
+ char c = ts.getc ();
+ switch (c)
+ {
+ case '?':
+ static const char help[] =
+ "? - help\n"
+ "1, 3, 4 - set output uart\n"
+ ": - reset output buffer index\n"
+ "! - send output buffer\n"
+ "O, E, N - change parity to Odd, Even or None\n"
+ "any - fill output buffer\n";
+ ts.write (help, sizeof (help));
+ break;
+ case '1':
+ u = &u1;
+ break;
+ case '3':
+ u = &u3;
+ break;
+ case '4':
+ u = &u4;
+ break;
+ case ':':
+ buf_i = 0;
+ break;
+ case '!':
+ u->write (buf, buf_i);
+ break;
+ case 'O':
+ u->enable (38400, ucoo::Uart::ODD, 1);
+ break;
+ case 'E':
+ u->enable (38400, ucoo::Uart::EVEN, 1);
+ break;
+ case 'N':
+ u->enable (38400, ucoo::Uart::NONE, 1);
+ break;
+ default:
+ if (buf_i < static_cast<int> (sizeof (buf)))
+ buf[buf_i++] = c;
+ break;
+ }
+ }
+ }
+}
diff --git a/ucoo/hal/uart/uart.hh b/ucoo/hal/uart/uart.hh
new file mode 100644
index 0000000..f4efd5b
--- /dev/null
+++ b/ucoo/hal/uart/uart.hh
@@ -0,0 +1,36 @@
+#ifndef ucoo_hal_uart_uart_hh
+#define ucoo_hal_uart_uart_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+#if defined (TARGET_host)
+# include "ucoo/arch/host/host_stream.hh"
+namespace ucoo { typedef HostStream Uart; }
+#elif defined (TARGET_stm32)
+# include "uart.stm32.hh"
+#else
+# error "not implemented for this target"
+#endif
+
+#endif // ucoo_hal_uart_uart_hh
diff --git a/ucoo/hal/uart/uart.stm32.cc b/ucoo/hal/uart/uart.stm32.cc
new file mode 100644
index 0000000..14dc849
--- /dev/null
+++ b/ucoo/hal/uart/uart.stm32.cc
@@ -0,0 +1,221 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "uart.stm32.hh"
+
+#include <libopencm3/stm32/f4/usart.h>
+#include <libopencm3/stm32/f4/rcc.h>
+#include <libopencm3/cm3/nvic.h>
+
+#ifndef TARGET_stm32f4
+// Need RCC adaptations and USART6 different handling for F1.
+# error "it's a trap, only implemented for F4 for the moment"
+#endif
+
+namespace ucoo {
+
+static const int uart_nb = 6;
+
+/// Information on UART hardware structure.
+struct uart_hardware_t
+{
+ /// UART base address.
+ uint32_t base;
+ /// APB number.
+ int apb;
+ /// RCC enable bit.
+ uint32_t rcc_en;
+ /// Corresponding IRQ.
+ int irq;
+};
+
+/// Information on UART hardware array, this is zero indexed, USART1 is at
+/// index 0.
+static const uart_hardware_t uart_hardware[uart_nb] =
+{
+ { USART1, 2, RCC_APB2ENR_USART1EN, NVIC_USART1_IRQ },
+ { USART2, 1, RCC_APB1ENR_USART2EN, NVIC_USART2_IRQ },
+ { USART3, 1, RCC_APB1ENR_USART3EN, NVIC_USART3_IRQ },
+ { UART4, 1, RCC_APB1ENR_UART4EN, NVIC_UART4_IRQ },
+ { UART5, 1, RCC_APB1ENR_UART5EN, NVIC_UART5_IRQ },
+ { USART6, 2, RCC_APB2ENR_USART6EN, NVIC_USART6_IRQ },
+};
+
+static Uart *uart_instances[uart_nb];
+
+} // namespace ucoo
+
+extern "C" {
+
+void usart1_isr () { ucoo::Uart::isr (0); }
+
+void usart2_isr () { ucoo::Uart::isr (1); }
+
+void usart3_isr () { ucoo::Uart::isr (2); }
+
+void uart4_isr () { ucoo::Uart::isr (3); }
+
+void uart5_isr () { ucoo::Uart::isr (4); }
+
+void usart6_isr () { ucoo::Uart::isr (5); }
+
+}
+
+namespace ucoo {
+
+Uart::Uart (int n)
+ : n_ (n), error_char_ (default_error_char), enabled_ (false)
+{
+ assert (n < uart_nb);
+ assert (!uart_instances[n]);
+ uart_instances[n] = this;
+}
+
+Uart::~Uart ()
+{
+ disable ();
+ uart_instances[n_] = 0;
+}
+
+void
+Uart::enable (int speed, Parity parity, int stop_bits)
+{
+ enabled_ = true;
+ uint32_t base = uart_hardware[n_].base;
+ // Turn on.
+ rcc_peripheral_enable_clock
+ (uart_hardware[n_].apb == 1 ? &RCC_APB1ENR : &RCC_APB2ENR,
+ uart_hardware[n_].rcc_en);
+ // Set speed, rounded to nearest.
+ int apb_freq = uart_hardware[n_].apb == 1 ? rcc_ppre1_frequency
+ : rcc_ppre2_frequency;
+ USART_BRR (base) = (2 * apb_freq + speed) / (2 * speed);
+ // Set parameters and enable.
+ if (stop_bits == 1)
+ USART_CR2 (base) = USART_CR2_STOPBITS_1;
+ else if (stop_bits == 2)
+ USART_CR2 (base) = USART_CR2_STOPBITS_2;
+ else
+ assert_unreachable ();
+ USART_CR3 (base) = 0;
+ uint32_t cr1 = USART_CR1_UE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+ if (parity != NONE)
+ cr1 |= USART_CR1_M | USART_CR1_PCE;
+ if (parity == ODD)
+ cr1 |= USART_CR1_PS;
+ USART_CR1 (base) = cr1;
+ // Reset status.
+ (void) USART_SR (base);
+ (void) USART_DR (base);
+ // Enable interrupts.
+ nvic_enable_irq (uart_hardware[n_].irq);
+}
+
+void
+Uart::disable ()
+{
+ if (enabled_)
+ {
+ enabled_ = false;
+ uint32_t base = uart_hardware[n_].base;
+ // Stop UART.
+ nvic_disable_irq (uart_hardware[n_].irq);
+ USART_CR1 (base) = 0;
+ // Turn off.
+ rcc_peripheral_disable_clock
+ (uart_hardware[n_].apb == 1 ? &RCC_APB1ENR : &RCC_APB2ENR,
+ uart_hardware[n_].rcc_en);
+ }
+}
+
+void
+Uart::set_error_char (char c)
+{
+ error_char_ = c;
+}
+
+int
+Uart::read (char *buf, int count)
+{
+ assert (enabled_);
+ if (block_)
+ while (rx_fifo_.empty ())
+ barrier ();
+ return rx_fifo_.read (buf, count);
+}
+
+int
+Uart::write (const char *buf, int count)
+{
+ assert (enabled_);
+ int left = count;
+ while (left)
+ {
+ int r = tx_fifo_.write (buf, left);
+ if (r)
+ {
+ USART_CR1 (uart_hardware[n_].base) |= USART_CR1_TXEIE;
+ buf += r;
+ left -= r;
+ }
+ if (!block_)
+ break;
+ }
+ return count - left;
+}
+
+int
+Uart::poll ()
+{
+ return rx_fifo_.empty () ? 0 : 1;
+}
+
+void
+Uart::isr (int n)
+{
+ uint32_t base = uart_hardware[n].base;
+ uint32_t sr = USART_SR (base);
+ uint32_t dr = USART_DR (base);
+ assert (uart_instances[n]);
+ Uart &uart = *uart_instances[n];
+ if (sr & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE))
+ {
+ dr = uart.error_char_;
+ // Datasheet is not really clear about this when error bits are set.
+ sr |= USART_SR_RXNE;
+ }
+ if (sr & USART_SR_RXNE)
+ {
+ if (!uart.rx_fifo_.full ())
+ uart.rx_fifo_.push (dr);
+ }
+ if (sr & USART_SR_TXE)
+ {
+ if (!uart.tx_fifo_.empty ())
+ USART_DR (base) = static_cast<uint8_t> (uart.tx_fifo_.pop ());
+ if (uart.tx_fifo_.empty ())
+ USART_CR1 (base) &= ~USART_CR1_TXEIE;
+ }
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/uart/uart.stm32.hh b/ucoo/hal/uart/uart.stm32.hh
new file mode 100644
index 0000000..25d6f6e
--- /dev/null
+++ b/ucoo/hal/uart/uart.stm32.hh
@@ -0,0 +1,78 @@
+#ifndef ucoo_hal_uart_uart_stm32_hh
+#define ucoo_hal_uart_uart_stm32_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/stream.hh"
+#include "ucoo/utils/fifo.hh"
+
+#include "config/hal/uart.hh"
+
+namespace ucoo {
+
+/// Universal asynchronous receiver transmitter (UART).
+///
+/// When an error is detected on RX, error character is inserted in receive
+/// FIFO.
+class Uart : public Stream
+{
+ public:
+ /// Parity setting.
+ enum Parity { ODD, EVEN, NONE };
+ /// Default error character.
+ static const char default_error_char = '~';
+ public:
+ /// Constructor for the Nth UART.
+ Uart (int n);
+ /// Shutdown UART.
+ ~Uart ();
+ /// Enable and setup UART.
+ void enable (int speed, Parity parity = NONE, int stop_bits = 1);
+ /// Disable.
+ void disable ();
+ /// Change the error character.
+ void set_error_char (char c);
+ /// See Stream::read.
+ int read (char *buf, int count);
+ /// See Stream::write.
+ int write (const char *buf, int count);
+ /// See Stream::poll.
+ int poll ();
+ /// Handle interrupts.
+ static void isr (int n);
+ private:
+ /// UART number.
+ int n_;
+ /// RX FIFO, filled by interrupt handler.
+ Fifo<char, UCOO_CONFIG_HAL_UART_RX_BUFFER> rx_fifo_;
+ /// TX FIFO, emptied by interrupt handler.
+ Fifo<char, UCOO_CONFIG_HAL_UART_TX_BUFFER> tx_fifo_;
+ /// Error character, inserted in case of error.
+ char error_char_;
+ /// Is it enabled?
+ bool enabled_;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_uart_uart_stm32_hh
diff --git a/ucoo/hal/usb/Config b/ucoo/hal/usb/Config
new file mode 100644
index 0000000..9adaece
--- /dev/null
+++ b/ucoo/hal/usb/Config
@@ -0,0 +1,12 @@
+[hal/usb]
+# Theses are APBTeam IDs, given by Openmoko!
+vendor_id = 0x1d50
+product_id = 0x6052
+# Number of streams, interfaces, or pair of endpoints.
+stream_nb = 1
+# Set to 0 if powered from USB cable, 1 if device has its own power supply.
+self_powered = 0
+# Maximum power consumed from USB cable (mA).
+max_power = 100
+# End point size, you should use 64.
+ep_size = 64
diff --git a/ucoo/hal/usb/Module b/ucoo/hal/usb/Module
new file mode 100644
index 0000000..433c8b2
--- /dev/null
+++ b/ucoo/hal/usb/Module
@@ -0,0 +1 @@
+hal_usb_SOURCES = usb.stm32.cc usb_desc.stm32.c
diff --git a/ucoo/hal/usb/test/Config b/ucoo/hal/usb/test/Config
new file mode 100644
index 0000000..49b2f0b
--- /dev/null
+++ b/ucoo/hal/usb/test/Config
@@ -0,0 +1,2 @@
+[hal/usb]
+stream_nb = 1
diff --git a/ucoo/hal/usb/test/Makefile b/ucoo/hal/usb/test/Makefile
new file mode 100644
index 0000000..cec9ded
--- /dev/null
+++ b/ucoo/hal/usb/test/Makefile
@@ -0,0 +1,9 @@
+BASE = ../../../..
+
+TARGETS = stm32f4
+stm32f4_PROGS = test_usb
+test_usb_SOURCES = test_usb.cc
+
+MODULES = hal/usb
+
+include $(BASE)/build/top.mk
diff --git a/ucoo/hal/usb/test/test_usb.cc b/ucoo/hal/usb/test/test_usb.cc
new file mode 100644
index 0000000..a1fe362
--- /dev/null
+++ b/ucoo/hal/usb/test/test_usb.cc
@@ -0,0 +1,73 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/usb/usb.hh"
+#include "ucoo/arch/arch.hh"
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ ucoo::UsbStreamControl usc ("APBTeam", "USB test");
+ ucoo::UsbStream us[] = {
+ ucoo::UsbStream (usc, 0),
+#if UCOO_CONFIG_HAL_USB_STREAM_NB >= 2
+ ucoo::UsbStream (usc, 1),
+#endif
+#if UCOO_CONFIG_HAL_USB_STREAM_NB >= 3
+ ucoo::UsbStream (usc, 2),
+#endif
+ };
+ if (UCOO_CONFIG_HAL_USB_STREAM_NB > 1)
+ {
+ for (int i = 0; i < UCOO_CONFIG_HAL_USB_STREAM_NB; i++)
+ us[i].block (false);
+ }
+ char buf[6];
+ while (1)
+ {
+ for (int i = 0; i < UCOO_CONFIG_HAL_USB_STREAM_NB; i++)
+ {
+ int len = us[i].read (buf + 2, sizeof (buf) - 2);
+ if (len)
+ {
+ buf[0] = i + '0';
+ buf[1] = '>';
+ len += 2;
+ if (UCOO_CONFIG_HAL_USB_STREAM_NB == 1)
+ us[i].write (buf, len);
+ else
+ {
+ const char *p = buf;
+ while (len)
+ {
+ int r = us[i].write (p, len);
+ p += r;
+ len -= r;
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/ucoo/hal/usb/usb.hh b/ucoo/hal/usb/usb.hh
new file mode 100644
index 0000000..5324058
--- /dev/null
+++ b/ucoo/hal/usb/usb.hh
@@ -0,0 +1,33 @@
+#ifndef ucoo_hal_usb_usb_hh
+#define ucoo_hal_usb_usb_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+#ifdef TARGET_stm32
+# include "usb.stm32.hh"
+#else
+# error "not implemented for this target"
+#endif
+
+#endif // ucoo_hal_usb_usb_hh
diff --git a/ucoo/hal/usb/usb.stm32.cc b/ucoo/hal/usb/usb.stm32.cc
new file mode 100644
index 0000000..0410df5
--- /dev/null
+++ b/ucoo/hal/usb/usb.stm32.cc
@@ -0,0 +1,160 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "usb.stm32.hh"
+#include <algorithm>
+
+#include <libopencm3/stm32/f4/rcc.h>
+#include <libopencm3/stm32/f4/gpio.h>
+#include <libopencm3/cm3/nvic.h>
+
+#include "usb_desc.stm32.h"
+
+static usbd_device *usbdev;
+
+extern "C" {
+
+void
+otg_fs_isr ()
+{
+ usbd_poll (usbdev);
+}
+
+}
+
+namespace ucoo {
+
+UsbStreamControl *UsbStreamControl::instance_;
+
+const char *strings[] = {
+ NULL,
+ NULL
+};
+
+UsbStreamControl::RxBuffer::RxBuffer (void)
+ : size (0), offset (0)
+{
+}
+
+UsbStreamControl::UsbStreamControl (const char *vendor, const char *product)
+ : configured_ (false)
+{
+ assert (!instance_);
+ instance_ = this;
+ strings[0] = vendor;
+ strings[1] = product;
+ rcc_peripheral_enable_clock (&RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN);
+ rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN);
+ gpio_mode_setup (GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE,
+ GPIO9 | GPIO11 | GPIO12);
+ gpio_set_af (GPIOA, GPIO_AF10, GPIO9 | GPIO11 | GPIO12);
+ usbdev = usbd_init (&otgfs_usb_driver, &usb_desc_dev, &usb_desc_config,
+ strings, lengthof (strings));
+ usbd_register_set_config_callback (usbdev, set_config);
+ nvic_enable_irq (NVIC_OTG_FS_IRQ);
+}
+
+void
+UsbStreamControl::set_config (usbd_device *usbdev, uint16_t configured)
+{
+ instance_->configured_ = configured;
+ if (configured)
+ {
+ for (int i = 0; i < stream_nb_; i++)
+ {
+ usbd_ep_setup (usbdev, 0x01 + i, USB_ENDPOINT_ATTR_BULK, ep_size_,
+ rx_callback);
+ usbd_ep_setup (usbdev, 0x81 + i, USB_ENDPOINT_ATTR_BULK, ep_size_,
+ NULL);
+ }
+ }
+}
+
+void
+UsbStreamControl::rx_callback (usbd_device *usbdev, uint8_t ep)
+{
+ assert (ep > 0 && ep <= stream_nb_);
+ int num = ep - 1;
+ RxBuffer &rb = instance_->rx_buffer_[num];
+ assert (rb.size == 0 && rb.offset == 0);
+ usbd_ep_nak_set (usbdev, ep, 1);
+ rb.size = usbd_ep_read_packet (usbdev, ep, rb.buf, ep_size_);
+}
+
+UsbStream::UsbStream (UsbStreamControl &control, int num)
+ : control_ (control), num_ (num)
+{
+ assert (num < UsbStreamControl::stream_nb_);
+}
+
+int
+UsbStream::read (char *buf, int count)
+{
+ UsbStreamControl::RxBuffer &rb = control_.rx_buffer_[num_];
+ /* Wait for reception. */
+ if (!rb.size && !block_)
+ return 0;
+ while (!rb.size)
+ barrier ();
+ /* Copy to provided buffer. */
+ int len = std::min (count, rb.size - rb.offset);
+ buf = std::copy (rb.buf + rb.offset, rb.buf + rb.offset + len, buf);
+ rb.offset += len;
+ /* Reload buffer? */
+ if (rb.offset == rb.size)
+ {
+ rb.offset = rb.size = 0;
+ barrier ();
+ usbd_ep_nak_set (usbdev, num_ + 1, 0);
+ }
+ /* Done. */
+ return len;
+}
+
+int
+UsbStream::write (const char *buf, int count)
+{
+ int left = count;
+ while (left)
+ {
+ if (control_.configured_)
+ {
+ int len = std::min (left, UsbStreamControl::ep_size_);
+ len = usbd_ep_write_packet (usbdev, num_ + 0x81, buf, len);
+ buf += len;
+ left -= len;
+ }
+ if (!block_)
+ break;
+ }
+ return count - left;
+}
+
+int
+UsbStream::poll ()
+{
+ UsbStreamControl::RxBuffer &rb = control_.rx_buffer_[num_];
+ return rb.size - rb.offset;
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/usb/usb.stm32.hh b/ucoo/hal/usb/usb.stm32.hh
new file mode 100644
index 0000000..118e883
--- /dev/null
+++ b/ucoo/hal/usb/usb.stm32.hh
@@ -0,0 +1,98 @@
+#ifndef ucoo_hal_usb_usb_stm32_hh
+#define ucoo_hal_usb_usb_stm32_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/stream.hh"
+#include "ucoo/common.hh"
+
+#include "config/hal/usb.hh"
+
+#include <libopencm3/usb/usbd.h>
+
+namespace ucoo {
+
+class UsbStream;
+
+/// Top control class for an USB device. This is a limited implementation
+/// which fulfill most of our needs: one or more interfaces, each of them is
+/// handled as a character stream. This should be instantiated only once.
+class UsbStreamControl
+{
+ public:
+ /// Construct a new USB control object, with given VENDOR and PRODUCT
+ /// strings.
+ UsbStreamControl (const char *vendor, const char *product);
+ /// Return true if the device is configured. This means that the
+ /// connection is done with the host and data can be exchanged.
+ bool is_configured () const { return configured_; }
+ private:
+ /// Called by USB stack when device is configured. This is expected to
+ /// setup endpoints.
+ static void set_config (usbd_device *usbdev, uint16_t wValue);
+ /// Called by USB stack when a frame is received on a OUT endpoint.
+ static void rx_callback (usbd_device *usbdev, uint8_t ep);
+ private:
+ /// Size of endpoints.
+ static const int ep_size_ = UCOO_CONFIG_HAL_USB_EP_SIZE;
+ /// Number of streams (also interfaces or pair of endpoints).
+ static const int stream_nb_ = UCOO_CONFIG_HAL_USB_STREAM_NB;
+ /// Pointer to the one and only instance.
+ static UsbStreamControl *instance_;
+ /// Whether device is currently configured.
+ bool configured_;
+ /// Internal RX buffer type.
+ struct RxBuffer
+ {
+ char buf[ep_size_];
+ int size, offset;
+ RxBuffer (void);
+ };
+ /// Internal RX buffer, one per stream.
+ RxBuffer rx_buffer_[stream_nb_];
+ friend class UsbStream;
+};
+
+/// One USB stream, instantiated for each stream, interface, or pair of
+/// endpoints.
+class UsbStream : public Stream
+{
+ public:
+ /// Construct from control object and stream index.
+ UsbStream (UsbStreamControl &control, int num);
+ /// See Stream::read.
+ int read (char *buf, int count);
+ /// See Stream::write.
+ int write (const char *buf, int count);
+ /// See Stream::poll.
+ int poll ();
+ private:
+ /// Reference to control object.
+ UsbStreamControl &control_;
+ /// Stream index.
+ int num_;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_usb_usb_stm32_hh
diff --git a/ucoo/hal/usb/usb_desc.stm32.c b/ucoo/hal/usb/usb_desc.stm32.c
new file mode 100644
index 0000000..8d6fc87
--- /dev/null
+++ b/ucoo/hal/usb/usb_desc.stm32.c
@@ -0,0 +1,193 @@
+/* ucoolib - Microcontroller object oriented library. {{{
+ *
+ * Copyright (C) 2012 Nicolas Schodet
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * }}} */
+#include "usb_desc.stm32.h"
+
+#include "config/hal/usb.hh"
+
+const struct usb_device_descriptor usb_desc_dev = {
+ .bLength = USB_DT_DEVICE_SIZE,
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = 0x0200,
+ .bDeviceClass = 0xff,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+ .bMaxPacketSize0 = 64,
+ .idVendor = UCOO_CONFIG_HAL_USB_VENDOR_ID,
+ .idProduct = UCOO_CONFIG_HAL_USB_PRODUCT_ID,
+ .bcdDevice = 0x0000,
+ .iManufacturer = 1,
+ .iProduct = 2,
+ .iSerialNumber = 0,
+ .bNumConfigurations = 1,
+};
+
+static const struct usb_endpoint_descriptor usb_desc_endp_1[] = {
+ {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x01,
+ .bmAttributes = USB_ENDPOINT_ATTR_BULK,
+ .wMaxPacketSize = UCOO_CONFIG_HAL_USB_EP_SIZE,
+ .bInterval = 0,
+ },
+ {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x81,
+ .bmAttributes = USB_ENDPOINT_ATTR_BULK,
+ .wMaxPacketSize = UCOO_CONFIG_HAL_USB_EP_SIZE,
+ .bInterval = 0,
+ },
+};
+
+static const struct usb_interface_descriptor usb_desc_iface_1[] = {
+ {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = 0xff,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 0,
+ .iInterface = 0,
+
+ .endpoint = usb_desc_endp_1,
+ },
+};
+
+#if UCOO_CONFIG_HAL_USB_STREAM_NB >= 2
+
+static const struct usb_endpoint_descriptor usb_desc_endp_2[] = {
+ {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x02,
+ .bmAttributes = USB_ENDPOINT_ATTR_BULK,
+ .wMaxPacketSize = UCOO_CONFIG_HAL_USB_EP_SIZE,
+ .bInterval = 0,
+ },
+ {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x82,
+ .bmAttributes = USB_ENDPOINT_ATTR_BULK,
+ .wMaxPacketSize = UCOO_CONFIG_HAL_USB_EP_SIZE,
+ .bInterval = 0,
+ },
+};
+
+static const struct usb_interface_descriptor usb_desc_iface_2[] = {
+ {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = 0xff,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 0,
+ .iInterface = 0,
+
+ .endpoint = usb_desc_endp_2,
+ },
+};
+
+#endif /* UCOO_CONFIG_HAL_USB_STREAM_NB >= 2 */
+
+#if UCOO_CONFIG_HAL_USB_STREAM_NB >= 3
+
+static const struct usb_endpoint_descriptor usb_desc_endp_3[] = {
+ {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x03,
+ .bmAttributes = USB_ENDPOINT_ATTR_BULK,
+ .wMaxPacketSize = UCOO_CONFIG_HAL_USB_EP_SIZE,
+ .bInterval = 0,
+ },
+ {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x83,
+ .bmAttributes = USB_ENDPOINT_ATTR_BULK,
+ .wMaxPacketSize = UCOO_CONFIG_HAL_USB_EP_SIZE,
+ .bInterval = 0,
+ },
+};
+
+static const struct usb_interface_descriptor usb_desc_iface_3[] = {
+ {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 2,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = 0xff,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 0,
+ .iInterface = 0,
+
+ .endpoint = usb_desc_endp_3,
+ },
+};
+
+#endif /* UCOO_CONFIG_HAL_USB_STREAM_NB >= 3 */
+
+#if UCOO_CONFIG_HAL_USB_STREAM_NB > 3
+# error "too many streams requested"
+#endif
+
+static const struct usb_interface usb_desc_ifaces[] = {
+ {
+ .num_altsetting = 1,
+ .altsetting = usb_desc_iface_1,
+ },
+#if UCOO_CONFIG_HAL_USB_STREAM_NB >= 2
+ {
+ .num_altsetting = 1,
+ .altsetting = usb_desc_iface_2,
+ },
+#endif
+#if UCOO_CONFIG_HAL_USB_STREAM_NB >= 3
+ {
+ .num_altsetting = 1,
+ .altsetting = usb_desc_iface_3,
+ },
+#endif
+};
+
+const struct usb_config_descriptor usb_desc_config = {
+ .bLength = USB_DT_CONFIGURATION_SIZE,
+ .bDescriptorType = USB_DT_CONFIGURATION,
+ .wTotalLength = 0,
+ .bNumInterfaces = UCOO_CONFIG_HAL_USB_STREAM_NB,
+ .bConfigurationValue = 1,
+ .iConfiguration = 0,
+ .bmAttributes = 0x80 | (UCOO_CONFIG_HAL_USB_SELF_POWERED ? 0x40 : 0),
+ .bMaxPower = UCOO_CONFIG_HAL_USB_MAX_POWER / 2,
+
+ .interface = usb_desc_ifaces,
+};
+
diff --git a/ucoo/hal/usb/usb_desc.stm32.h b/ucoo/hal/usb/usb_desc.stm32.h
new file mode 100644
index 0000000..dca84b7
--- /dev/null
+++ b/ucoo/hal/usb/usb_desc.stm32.h
@@ -0,0 +1,33 @@
+#ifndef ucoo_hal_usb_usb_desc_stm32_h
+#define ucoo_hal_usb_usb_desc_stm32_h
+/* ucoolib - Microcontroller object oriented library. {{{
+ *
+ * Copyright (C) 2012 Nicolas Schodet
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * }}} */
+#include <libopencm3/usb/usbstd.h>
+
+/** USB device descriptor. */
+extern const struct usb_device_descriptor usb_desc_dev;
+/** USB configuration descriptor. */
+extern const struct usb_config_descriptor usb_desc_config;
+
+#endif /* ucoo_hal_usb_usb_desc_stm32_h */
diff --git a/ucoo/intf/Module b/ucoo/intf/Module
new file mode 100644
index 0000000..7477f00
--- /dev/null
+++ b/ucoo/intf/Module
@@ -0,0 +1 @@
+intf_SOURCES = stream.cc spi_master.cc
diff --git a/ucoo/intf/adc.hh b/ucoo/intf/adc.hh
new file mode 100644
index 0000000..83c0520
--- /dev/null
+++ b/ucoo/intf/adc.hh
@@ -0,0 +1,45 @@
+#ifndef ucoo_intf_adc_hh
+#define ucoo_intf_adc_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+/// Analog to digital converter. This is a really simple interface which
+/// should be enough for simple needs.
+class Adc
+{
+ public:
+ /// Make a conversion and return the value.
+ virtual int read () = 0;
+ /// Get resolution (number of possible different values).
+ virtual int get_resolution () const = 0;
+ protected:
+ /// Default constructor.
+ Adc () { }
+};
+
+} // namespace ucoo
+
+#endif // ucoo_intf_adc_hh
diff --git a/ucoo/intf/i2c.hh b/ucoo/intf/i2c.hh
new file mode 100644
index 0000000..7d3a624
--- /dev/null
+++ b/ucoo/intf/i2c.hh
@@ -0,0 +1,124 @@
+#ifndef ucoo_intf_i2c_hh
+#define ucoo_intf_i2c_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/common.hh"
+
+namespace ucoo {
+
+/// Master side of I2C interface.
+class I2cMaster
+{
+ public:
+ /// Master transfer status, any other value is the transfer size in case
+ /// of success.
+ enum Status
+ {
+ /// Transfer is still ongoing.
+ STATUS_BUSY = -1,
+ /// Transfer finished with error.
+ STATUS_ERROR = 0,
+ };
+ /// Callback used when master transfer is finised.
+ class FinishedHandler
+ {
+ public:
+ /// Called when transfer is finished, may be called in interrupt
+ /// context. I2C send and recv can be called from this handler.
+ virtual void finished (int status) = 0;
+ };
+ public:
+ /// Send data to selected slave. This is asynchronous, you will have to
+ /// poll status or use a callback to determine if transfer is finished.
+ /// Input buffer is not copied and should be kept valid until transfer is
+ /// finished.
+ ///
+ /// If asynchronous transfer is not supported, this will block.
+ virtual void send (uint8_t addr, const char *buf, int count) = 0;
+ /// Receive data from selected slave. This is asynchronous, you will have
+ /// to poll status or use a callback to determine if transfer is finished.
+ /// Buffer is directly written and should be kept valid until transfer is
+ /// finished.
+ ///
+ /// If asynchronous transfer is not supported, this will block.
+ virtual void recv (uint8_t addr, char *buf, int count) = 0;
+ /// Return last transfer status.
+ virtual int status () = 0;
+ /// Wait until transfer is finished and return status.
+ virtual int wait () = 0;
+ /// Register a handler called when transfer is finished.
+ void register_finished (FinishedHandler &finished_handler)
+ { finished_handler_ = &finished_handler; }
+ /// Remove registered handler.
+ void unregister_finished (void)
+ { finished_handler_ = 0; }
+ protected:
+ /// Default constructor.
+ I2cMaster () : finished_handler_ (0) { }
+ protected:
+ /// Handler called when transfer is finished.
+ FinishedHandler *finished_handler_;
+};
+
+/// Slave side of I2C interface.
+class I2cSlave
+{
+ public:
+ /// Data source and sink.
+ ///
+ /// When master requests data from a slave or send data to it, slave is
+ /// expected to reply as quickly as possible as the bus is stalled until a
+ /// response is done.
+ ///
+ /// This interface provides data to send to master and receives data from
+ /// master. It has to be fast and may be run under an interrupt context.
+ class DataHandler
+ {
+ public:
+ /// Request data to send to master, should write to provided buffer of
+ /// size COUNT and return the writen size.
+ virtual int to_send (char *buf, int count) = 0;
+ /// Provide data sent by master, should make a copy if needed as data will
+ /// be discarded.
+ virtual void to_recv (const char *buf, int count) = 0;
+ };
+ public:
+ /// Register data source and sink, along with 7 bit address (in MSB).
+ virtual void register_data (uint8_t addr, DataHandler &data_handler) = 0;
+ protected:
+ /// Default constructor.
+ I2cSlave () { }
+};
+
+/// Both side of I2C interface.
+class I2c : public I2cMaster, public I2cSlave
+{
+ protected:
+ /// Default constructor.
+ I2c () { }
+};
+
+} // namespace ucoo
+
+#endif // ucoo_intf_i2c_hh
diff --git a/ucoo/intf/io.hh b/ucoo/intf/io.hh
new file mode 100644
index 0000000..34246a1
--- /dev/null
+++ b/ucoo/intf/io.hh
@@ -0,0 +1,54 @@
+#ifndef ucoo_intf_io_hh
+#define ucoo_intf_io_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+/// One bit input/output interface.
+class Io
+{
+ public:
+ /// Set output to 1.
+ virtual void set () = 0;
+ /// Reset output to 0.
+ virtual void reset () = 0;
+ /// Set or reset output.
+ virtual void set (bool state) = 0;
+ /// Toggle output.
+ virtual void toggle () = 0;
+ /// Get input state (not the same as output latch!).
+ virtual bool get () const = 0;
+ /// Set as input.
+ virtual void input () = 0;
+ /// Set as output.
+ virtual void output () = 0;
+ protected:
+ /// Default constructor.
+ Io () { }
+};
+
+} // namespace ucoo
+
+#endif // ucoo_intf_io_hh
diff --git a/ucoo/intf/spi_master.cc b/ucoo/intf/spi_master.cc
new file mode 100644
index 0000000..38f749b
--- /dev/null
+++ b/ucoo/intf/spi_master.cc
@@ -0,0 +1,48 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "spi_master.hh"
+
+namespace ucoo {
+
+char
+SpiMaster::send_and_recv (char tx)
+{
+ char rx;
+ send_and_recv (&tx, &rx, 1);
+ return rx;
+}
+
+void
+SpiMaster::send (char tx)
+{
+ send_and_recv (tx);
+}
+
+char
+SpiMaster::recv ()
+{
+ return send_and_recv (0);
+}
+
+} // namespace ucoo
diff --git a/ucoo/intf/spi_master.hh b/ucoo/intf/spi_master.hh
new file mode 100644
index 0000000..5363aee
--- /dev/null
+++ b/ucoo/intf/spi_master.hh
@@ -0,0 +1,70 @@
+#ifndef ucoo_intf_spi_master_hh
+#define ucoo_intf_spi_master_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+/// SPI clock polarity and phase modes.
+enum SpiMode
+{
+ /// Mode 0, sample on rising edge, setup on falling edge.
+ SPI_MODE_0,
+ /// Mode 1, setup on rising edge, sample on falling edge.
+ SPI_MODE_1,
+ /// Mode 2, sample on falling edge, setup on rising edge.
+ SPI_MODE_2,
+ /// Mode 3, setup on falling edge, sample on rising edge.
+ SPI_MODE_3,
+};
+
+/// Interface to the master side of an SPI bus. Do not handle slave select,
+/// this should be done with a regular IO.
+class SpiMaster
+{
+ public:
+ /// Send and receive COUNT bytes of data. Send data from TX_BUF, store
+ /// received data in RX_BUF. TX_BUF and RX_BUF can be the same memory.
+ virtual void send_and_recv (const char *tx_buf, char *rx_buf, int count)
+ = 0;
+ /// Send and receive one byte, shortcut.
+ virtual char send_and_recv (char tx);
+ /// Send, and ignore received data. Same as send_and_recv, but received
+ /// data is discarded.
+ virtual void send (const char *tx_buf, int count) = 0;
+ /// Send one byte, shortcut.
+ virtual void send (char tx);
+ /// Send zeros, and receive data. Same as send_and_recv, but transmit
+ /// zeros.
+ virtual void recv (char *rx_buf, int count) = 0;
+ /// Receive one byte, shortcut.
+ virtual char recv ();
+ protected:
+ /// Default constructor.
+ SpiMaster () { }
+};
+
+} // namespace ucoo
+
+#endif // ucoo_intf_spi_master_hh
diff --git a/ucoo/intf/stream.cc b/ucoo/intf/stream.cc
new file mode 100644
index 0000000..31cea01
--- /dev/null
+++ b/ucoo/intf/stream.cc
@@ -0,0 +1,63 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "stream.hh"
+
+namespace ucoo {
+
+Stream::Stream ()
+ : block_ (true)
+{
+}
+
+void
+Stream::block (bool block/*true*/)
+{
+ block_ = block;
+}
+
+int
+Stream::getc ()
+{
+ int r;
+ char c;
+ r = read (&c, 1);
+ if (r == 1)
+ return static_cast<unsigned char> (c);
+ else
+ return -1;
+}
+
+int
+Stream::putc (int c)
+{
+ int r;
+ char b = c;
+ r = write (&b, 1);
+ if (r == 1)
+ return 0;
+ else
+ return -1;
+}
+
+} // namespace ucoo
diff --git a/ucoo/intf/stream.hh b/ucoo/intf/stream.hh
new file mode 100644
index 0000000..77eba92
--- /dev/null
+++ b/ucoo/intf/stream.hh
@@ -0,0 +1,65 @@
+#ifndef ucoo_intf_stream_hh
+#define ucoo_intf_stream_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+/// Interface to an object providing a stream oriented flow, like serial port,
+/// connected socket, or higher encapsulated protocol.
+class Stream
+{
+ public:
+ /// Set whether operations on this stream should block when no data is
+ /// available.
+ virtual void block (bool block = true);
+ /// Read up to COUNT bytes of data from stream and store them in BUF.
+ /// Return the number of read bytes, -1 on error or -2 on EOF.
+ ///
+ /// If blocking, will return as soon as there is some data available. If
+ /// not blocking, may return 0 if no data is available.
+ virtual int read (char *buf, int count) = 0;
+ /// Write up to COUNT bytes of data from BUF to stream. Return the number
+ /// of written bytes or -1 on error.
+ ///
+ /// If blocking, will try its best to write all data provided.
+ virtual int write (const char *buf, int count) = 0;
+ /// Shortcut to read one character. Return -1 on error, on EOF, or if no
+ /// character is available.
+ int getc ();
+ /// Shortcut to write one character. Return -1 on error.
+ int putc (int c);
+ /// Return the number of available bytes to be read.
+ virtual int poll () = 0;
+ protected:
+ /// Default constructor.
+ Stream ();
+ protected:
+ /// Current blocking operation flag.
+ bool block_;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_intf_stream_hh
diff --git a/ucoo/utils/Module b/ucoo/utils/Module
new file mode 100644
index 0000000..a37070f
--- /dev/null
+++ b/ucoo/utils/Module
@@ -0,0 +1 @@
+utils_SOURCES := delay.arm.cc crc.cc
diff --git a/ucoo/utils/bytes.hh b/ucoo/utils/bytes.hh
new file mode 100644
index 0000000..f922720
--- /dev/null
+++ b/ucoo/utils/bytes.hh
@@ -0,0 +1,52 @@
+#ifndef ucoo_utils_bytes_hh
+#define ucoo_utils_bytes_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+/// Pack two bytes to one 16 bit word.
+static inline uint16_t
+bytes_pack (uint8_t b1, uint8_t b0)
+{
+ return b1 << 8 | b0;
+}
+
+/// Pack four bytes to one 32 bit word.
+static inline uint32_t
+bytes_pack (uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0)
+{
+ return b3 << 24 | b2 << 16 | b1 << 8 | b0;
+}
+
+/// Unpack one byte from one 32 bit word.
+static inline uint8_t
+bytes_unpack (uint32_t w, int n)
+{
+ return (w >> (n * 8)) & 0xff;
+}
+
+} // namespace ucoo
+
+#endif // ucoo_utils_bytes_hh
diff --git a/ucoo/utils/crc.cc b/ucoo/utils/crc.cc
new file mode 100644
index 0000000..2627a1d
--- /dev/null
+++ b/ucoo/utils/crc.cc
@@ -0,0 +1,102 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "crc.hh"
+
+namespace ucoo {
+
+uint8_t
+crc8_compute (const uint8_t *data, int size)
+{
+ uint8_t crc = 0;
+ for (int i = 0; i < size; i++)
+ crc = crc8_update (crc, data[i]);
+ return crc;
+}
+
+static uint32_t const crc32tab[256] =
+{
+ // {{{
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+ // }}}
+};
+
+uint32_t
+crc32_update (uint32_t crc, uint8_t data)
+{
+ return crc32tab[(crc ^ data) & 0xff] ^ (crc >> 8);
+}
+
+uint32_t
+crc32_compute (const uint8_t *data, int size)
+{
+ uint32_t crc = 0xffffffff;
+ for (int i = 0; i < size; i++)
+ crc = crc32_update (crc, data[i]);
+ crc = crc ^ 0xffffffff;
+ return crc;
+}
+
+} // namespace ucoo
diff --git a/ucoo/utils/crc.hh b/ucoo/utils/crc.hh
new file mode 100644
index 0000000..b00989c
--- /dev/null
+++ b/ucoo/utils/crc.hh
@@ -0,0 +1,70 @@
+#ifndef ucoo_utils_crc_hh
+#define ucoo_utils_crc_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/common.hh"
+
+/// Please read "A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS",
+/// http://www.ross.net/crc/download/crc_v3.txt
+
+namespace ucoo {
+
+/// Dallas/Maxim iButton 8bit CRC.
+/// Polynomial: x^8 + x^5 + x^4 + 1
+/// Initial value: 0
+static inline uint8_t
+crc8_update (uint8_t crc, uint8_t data)
+{
+ uint8_t i;
+ crc = crc ^ data;
+ for (i = 0; i < 8; i++)
+ {
+ if (crc & 0x01)
+ crc = (crc >> 1) ^ 0x8C;
+ else
+ crc >>= 1;
+ }
+ return crc;
+}
+
+uint8_t
+crc8_compute (const uint8_t *data, int size);
+
+/// Name : "CRC-32"
+/// Width : 32
+/// Poly : 04C11DB7
+/// Init : FFFFFFFF
+/// RefIn : True
+/// RefOut : True
+/// XorOut : FFFFFFFF
+/// Check : CBF43926
+uint32_t
+crc32_update (uint32_t crc, uint8_t data);
+
+uint32_t
+crc32_compute (const uint8_t *data, int size);
+
+} // namespace ucoo
+
+#endif // ucoo_utils_crc_hh
diff --git a/ucoo/utils/delay.arm.cc b/ucoo/utils/delay.arm.cc
new file mode 100644
index 0000000..294f5ea
--- /dev/null
+++ b/ucoo/utils/delay.arm.cc
@@ -0,0 +1,76 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "delay.arm.hh"
+
+#include <algorithm>
+
+#include <libopencm3/cm3/systick.h>
+#include <libopencm3/stm32/f4/rcc.h>
+
+namespace ucoo {
+
+void
+delay_us (int us)
+{
+ // Horrible hack: there is no record of the current systick speed, make
+ // guesses based on APB2 clock. Also, suppose that frequency is a multiple
+ // of 1 MHz (to avoid 64 bit division).
+ int systick_mhz = rcc_ppre2_frequency / (4 * 1000000);
+ int cycles = systick_mhz * us;
+ STK_CTRL = 0;
+ // Loop several times if cycles is too big for the systick timer. Some
+ // nanoseconds are lost every second, I can live with that, it simplifies
+ // code.
+ while (cycles)
+ {
+ int loop_cycles = std::min (1 << 24, cycles);
+ STK_LOAD = loop_cycles - 1;
+ STK_VAL = 0;
+ STK_CTRL = STK_CTRL_ENABLE;
+ while (!(STK_CTRL & STK_CTRL_COUNTFLAG))
+ ;
+ STK_CTRL = 0;
+ cycles -= loop_cycles;
+ }
+}
+
+void
+delay_ns (int ns)
+{
+ // Horrible hack: there is no record of the current hclock speed, make
+ // guesses based on APB2 clock. Also, suppose that frequency is a multiple
+ // of 1 MHz (to avoid 64 bit division).
+ int hclock_mhz = rcc_ppre2_frequency / (1000000 / 2);
+ int cycles = (hclock_mhz * ns + 999) / 1000;
+ STK_CTRL = 0;
+ // Loop once, ns is supposed to be small.
+ STK_LOAD = cycles - 1;
+ STK_VAL = 0;
+ STK_CTRL = STK_CTRL_CLKSOURCE_AHB | STK_CTRL_ENABLE;
+ while (!(STK_CTRL & STK_CTRL_COUNTFLAG))
+ ;
+ STK_CTRL = 0;
+}
+
+} // namespace ucoo
diff --git a/ucoo/utils/delay.arm.hh b/ucoo/utils/delay.arm.hh
new file mode 100644
index 0000000..53d2c7e
--- /dev/null
+++ b/ucoo/utils/delay.arm.hh
@@ -0,0 +1,52 @@
+#ifndef ucoo_utils_delay_arm_hh
+#define ucoo_utils_delay_arm_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+/// Wait for an integral number of microseconds, used to implement delay.
+void
+delay_us (int us);
+
+/// Wait for a small integral number of nanoseconds, used to implement short
+/// delay.
+void
+delay_ns (int us);
+
+/// Wait for the specified delay in seconds.
+extern inline void
+delay (double s)
+{
+ if (s < 1e-6)
+ delay_ns (static_cast<int> (s * 1e9));
+ else
+ delay_us (static_cast<int> (s * 1e6));
+}
+extern inline void
+delay (double s) __attribute__ ((always_inline));
+
+} // namespace ucoo
+
+#endif // ucoo_utils_delay_arm_hh
diff --git a/ucoo/utils/delay.hh b/ucoo/utils/delay.hh
new file mode 100644
index 0000000..cc8cea3
--- /dev/null
+++ b/ucoo/utils/delay.hh
@@ -0,0 +1,76 @@
+#ifndef ucoo_utils_delay_hh
+#define ucoo_utils_delay_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+#if defined (TARGET_host)
+
+namespace ucoo {
+
+/// No delay on host.
+extern inline void
+delay (double s)
+{
+}
+
+} // namespace ucoo
+
+#elif defined (TARGET_arm)
+# include "delay.arm.hh"
+#else
+# error "not implemented for this target"
+#endif
+
+namespace ucoo {
+
+/// Shortcut for delay with nanosecond.
+extern inline void
+delay_ns (double ns)
+{
+ delay (ns * 1e-9);
+}
+extern inline void
+delay_ns (double ns) __attribute__ ((always_inline));
+
+/// Shortcut for delay with microsecond.
+extern inline void
+delay_us (double us)
+{
+ delay (us * 1e-6);
+}
+extern inline void
+delay_us (double us) __attribute__ ((always_inline));
+
+/// Shortcut for delay with millisecond.
+extern inline void
+delay_ms (double ms)
+{
+ delay (ms * 1e-3);
+}
+extern inline void
+delay_ms (double ms) __attribute__ ((always_inline));
+
+} // namespace ucoo
+
+#endif // ucoo_utils_delay_hh
diff --git a/ucoo/utils/dtrace.py b/ucoo/utils/dtrace.py
new file mode 100644
index 0000000..4180718
--- /dev/null
+++ b/ucoo/utils/dtrace.py
@@ -0,0 +1,40 @@
+"""GDB plugin to dump trace from a Trace object."""
+
+class DTrace(gdb.Command):
+ def __init__(self):
+ gdb.Command.__init__(self, "dtrace", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL, True)
+
+ def invoke(self, arg, from_tty):
+ args = gdb.string_to_argv(arg)
+ if len(args) != 1:
+ print 'Usage: dtrace <object>'
+ return
+
+ trace = gdb.parse_and_eval(args[0])
+ args_nb = trace['args_nb'];
+ entries_nb = trace['entries_nb'];
+ index = trace['index'];
+ entries = trace['entries'];
+
+ if entries[index]['str']:
+ r = range(index, entries_nb) + range(index)
+ else:
+ r = range(index)
+
+ for i in r:
+ entry = entries[i]
+ if not entry['str']:
+ break
+ s = entry['str'].string()
+ sargs = s.count('%') - 2 * s.count('%%')
+ args = tuple(entry['args'][i] for i in xrange(sargs))
+ try:
+ s = s % args
+ except:
+ pass
+ if s.startswith('<'):
+ n = int(s[1:].partition('>')[0])
+ s = ' ' * (n * 10) + s
+ print s
+
+DTrace()
diff --git a/ucoo/utils/fifo.hh b/ucoo/utils/fifo.hh
new file mode 100644
index 0000000..f80caf9
--- /dev/null
+++ b/ucoo/utils/fifo.hh
@@ -0,0 +1,76 @@
+#ifndef ucoo_utils_fifo_hh
+#define ucoo_utils_fifo_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/common.hh"
+
+namespace ucoo {
+
+/// First In First Out container. It is implemented as a circular buffer,
+/// providing thread safety if the reader and the writer are in separated
+/// threads.
+///
+/// This is a rather low level container used to implement ucoolib features.
+/// Be careful that there is only room for size - 1 elements in the FIFO.
+template<typename T, int size>
+class Fifo
+{
+ public:
+ /// Constructor, initialise an empty FIFO.
+ Fifo ();
+ /// Test whether the FIFO is empty.
+ bool empty () const { return head_ == tail_; }
+ /// Test whether the FIFO is full.
+ bool full () const { return head_ == next (tail_); }
+ /// Remove an element, do not do that if FIFO is empty!
+ T pop ();
+ /// Add an element, do not do that if FIFO is full!
+ void push (const T &e);
+ /// Pop up to COUNT elements and store them in BUF. Return the number of
+ /// read elements.
+ int read (T *buf, int count);
+ /// Push up to COUNT elements from BUF. Return the number of written
+ /// elements.
+ int write (const T *buf, int count);
+ private:
+ /// Return next index, use unsigned operation for optimisation.
+ int next (int index) const
+ {
+ return (static_cast<unsigned int> (index) + 1) % size;
+ }
+ private:
+ /// Index of the next element to pop, always incremented.
+ int_atomic_t head_;
+ /// Index of the next free space where to put a pushed element, also
+ /// always incremented.
+ int_atomic_t tail_;
+ /// Memory to store elements.
+ T buffer_[size];
+};
+
+} // namespace ucoo
+
+#include "fifo.tcc"
+
+#endif // ucoo_utils_fifo_hh
diff --git a/ucoo/utils/fifo.tcc b/ucoo/utils/fifo.tcc
new file mode 100644
index 0000000..be8f896
--- /dev/null
+++ b/ucoo/utils/fifo.tcc
@@ -0,0 +1,108 @@
+#ifndef ucoo_utils_fifo_tcc
+#define ucoo_utils_fifo_tcc
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include <algorithm>
+
+namespace ucoo {
+
+template<typename T, int size>
+inline
+Fifo<T, size>::Fifo ()
+ : head_ (0), tail_ (0)
+{
+}
+
+template<typename T, int size>
+inline T
+Fifo<T, size>::pop ()
+{
+ // Reader, can only update head.
+ int head = head_;
+ assert (head != tail_);
+ T v = buffer_[head];
+ head = next (head);
+ barrier ();
+ head_ = head;
+ return v;
+}
+
+template<typename T, int size>
+inline void
+Fifo<T, size>::push (const T &e)
+{
+ // Writer, can only update tail.
+ int tail = tail_;
+ buffer_[tail] = e;
+ tail = next (tail);
+ assert (head_ != tail);
+ barrier ();
+ tail_ = tail;
+}
+
+template<typename T, int size>
+inline int
+Fifo<T, size>::read (T *buf, int count)
+{
+ // Reader, can only update head.
+ int r = 0;
+ int head = head_;
+ int tail = access_once (tail_);
+ while (r < count && head != tail)
+ {
+ buf[r] = buffer_[head];
+ head = next (head);
+ r++;
+ }
+ // Ensure data is copied, then update head.
+ barrier ();
+ head_ = head;
+ return r;
+}
+
+template<typename T, int size>
+inline int
+Fifo<T, size>::write (const T *buf, int count)
+{
+ // Writer, can only update tail.
+ int r = 0;
+ int head = access_once (head_);
+ int tail = tail_;
+ int tailp1 = next (tail);
+ while (r < count && tailp1 != head)
+ {
+ buffer_[tail] = buf[r];
+ tail = tailp1;
+ r++;
+ tailp1 = next (tail);
+ }
+ // Ensure data is copied, then update tail.
+ barrier ();
+ tail_ = tail;
+ return r;
+}
+
+} // namespace ucoo
+
+#endif // ucoo_utils_fifo_tcc
diff --git a/ucoo/utils/test/Makefile b/ucoo/utils/test/Makefile
new file mode 100644
index 0000000..01fb2ce
--- /dev/null
+++ b/ucoo/utils/test/Makefile
@@ -0,0 +1,12 @@
+BASE = ../../..
+
+TARGETS = host stm32f4
+PROGS = test_fifo test_crc
+stm32f4_PROGS = test_delay
+test_fifo_SOURCES = test_fifo.cc
+test_delay_SOURCES = test_delay.cc
+test_crc_SOURCES = test_crc.cc
+
+MODULES = utils base/test hal/usb
+
+include $(BASE)/build/top.mk
diff --git a/ucoo/utils/test/test_crc.cc b/ucoo/utils/test/test_crc.cc
new file mode 100644
index 0000000..c20600d
--- /dev/null
+++ b/ucoo/utils/test/test_crc.cc
@@ -0,0 +1,49 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/utils/crc.hh"
+#include "ucoo/arch/arch.hh"
+#include "ucoo/base/test/test.hh"
+
+#include <cstring>
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ ucoo::TestSuite tsuite ("crc");
+ {
+ ucoo::Test test (tsuite, "crc8 test vector");
+ static const uint8_t test_vector[] = { 0x02, 0x1c, 0xb8, 0x01, 0, 0, 0, 0xa2 };
+ if (ucoo::crc8_compute (test_vector, lengthof (test_vector)) != 0)
+ test.fail ();
+ }
+ {
+ ucoo::Test test (tsuite, "crc32 test vector");
+ const char *check_str = "123456789";
+ if (ucoo::crc32_compute ((const uint8_t *) check_str,
+ std::strlen (check_str)) != 0xCBF43926)
+ test.fail ();
+ }
+ return tsuite.report () ? 0 : 1;
+}
diff --git a/ucoo/utils/test/test_delay.cc b/ucoo/utils/test/test_delay.cc
new file mode 100644
index 0000000..90a53e5
--- /dev/null
+++ b/ucoo/utils/test/test_delay.cc
@@ -0,0 +1,64 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/utils/delay.hh"
+#include "ucoo/arch/arch.hh"
+
+#include <libopencm3/stm32/f4/rcc.h>
+#include <libopencm3/stm32/f4/gpio.h>
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPDEN);
+ gpio_mode_setup (GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,
+ GPIO12 | GPIO13 | GPIO14 | GPIO15);
+ gpio_clear (GPIOD, GPIO12 | GPIO13 | GPIO14 | GPIO15);
+ int i, j;
+ while (1)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ gpio_toggle (GPIOD, GPIO12 << (i % 4));
+ ucoo::delay (1);
+ }
+ for (i = 0; i < 16; i++)
+ {
+ gpio_toggle (GPIOD, GPIO12 << (i % 4));
+ ucoo::delay_ms (250);
+ }
+ for (i = 0; i < 16000; i++)
+ {
+ gpio_toggle (GPIOD, GPIO12 << (i % 4));
+ ucoo::delay_us (250);
+ }
+ for (i = 0; i < 16; i++)
+ {
+ gpio_toggle (GPIOD, GPIO12 << (i % 4));
+ for (j = 0; j < 1000; j++)
+ ucoo::delay_us (250);
+ }
+ }
+ return 0;
+}
diff --git a/ucoo/utils/test/test_fifo.cc b/ucoo/utils/test/test_fifo.cc
new file mode 100644
index 0000000..dd9aa8e
--- /dev/null
+++ b/ucoo/utils/test/test_fifo.cc
@@ -0,0 +1,78 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/utils/fifo.hh"
+#include "ucoo/arch/arch.hh"
+#include "ucoo/base/test/test.hh"
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ ucoo::TestSuite tsuite ("fifo");
+ {
+ ucoo::Test test (tsuite, "push pop");
+ ucoo::Fifo<int, 16> fifo;
+ fifo.push (1);
+ fifo.push (2);
+ fifo.push (3);
+ if (fifo.pop () != 1 || fifo.pop () != 2 || fifo.pop () != 3)
+ test.fail ();
+ }
+ {
+ ucoo::Test test (tsuite, "full empty");
+ ucoo::Fifo<int, 4> fifo;
+ do
+ {
+ test_fail_break_unless (test, fifo.empty () && !fifo.full ());
+ fifo.push (1);
+ test_fail_break_unless (test, !fifo.empty () && !fifo.full ());
+ fifo.push (2);
+ test_fail_break_unless (test, !fifo.empty () && !fifo.full ());
+ fifo.push (3);
+ test_fail_break_unless (test, !fifo.empty () && fifo.full ());
+ } while (0);
+ }
+ {
+ ucoo::Test test (tsuite, "write read");
+ ucoo::Fifo<int, 8> fifo;
+ static const int b[] = { 1, 2, 3, 4, 5 };
+ int c[8];
+ int r;
+ do
+ {
+ r = fifo.write (b, 5);
+ test_fail_break_unless (test, r == 5);
+ r = fifo.read (c, 2);
+ test_fail_break_unless (test, r == 2 && c[0] == 1 && c[1] == 2);
+ r = fifo.write (b, 5);
+ test_fail_break_unless (test, r == 4);
+ r = fifo.read (c, 8);
+ test_fail_break_unless (test, r == 7);
+ test_fail_break_unless (test, c[0] == 3 && c[1] == 4 && c[2] == 5);
+ test_fail_break_unless (test, c[3] == 1 && c[4] == 2 && c[5] == 3
+ && c[6] == 4);
+ } while (0);
+ }
+ return tsuite.report () ? 0 : 1;
+}
diff --git a/ucoo/utils/trace.hh b/ucoo/utils/trace.hh
new file mode 100644
index 0000000..e2d33ac
--- /dev/null
+++ b/ucoo/utils/trace.hh
@@ -0,0 +1,133 @@
+#ifndef ucoo_utils_trace_hh
+#define ucoo_utils_trace_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+namespace ucoo {
+
+/// Trace buffer to be read with debugger, no initialisation, should be
+/// instantiated in BSS.
+class TraceBuffer
+{
+ /// Maximum number of arguments.
+ static const int args_nb = 4;
+ /// Maximum number of trace entries.
+ static const int entries_nb = 32;
+ public:
+ /// Trace without argument.
+ inline void operator() (const char *str);
+ /// Trace with N arguments...
+ inline void operator() (const char *str, int a0);
+ inline void operator() (const char *str, int a0, int a1);
+ inline void operator() (const char *str, int a0, int a1, int a2);
+ inline void operator() (const char *str, int a0, int a1, int a2, int a3);
+ private:
+ /// Trace entry, contains all given parameters.
+ struct Entry
+ {
+ const char *str;
+ int args[args_nb];
+ };
+ /// Trace entries array.
+ Entry entries[entries_nb];
+ /// Index of next entry to be written in entries array.
+ unsigned int index;
+};
+
+/// Dummy trace, trace nothing.
+class TraceDummy
+{
+ public:
+ inline void operator() (const char *str) { }
+ inline void operator() (const char *str, int a0) { }
+ inline void operator() (const char *str, int a0, int a1) { }
+ inline void operator() (const char *str, int a0, int a1, int a2) { }
+ inline void operator() (const char *str, int a0, int a1, int a2, int a3) { }
+};
+
+/// Conditional trace, whether it trace or not depends on the template
+/// argument.
+template<bool ENABLED>
+class Trace
+{
+};
+
+template<>
+class Trace<true> : public TraceBuffer
+{
+};
+
+template<>
+class Trace<false> : public TraceDummy
+{
+};
+
+inline void
+TraceBuffer::operator() (const char *str)
+{
+ entries[index].str = str;
+ index = (index + 1) % entries_nb;
+}
+
+inline void
+TraceBuffer::operator() (const char *str, int a0)
+{
+ entries[index].str = str;
+ entries[index].args[0] = a0;
+ index = (index + 1) % entries_nb;
+}
+
+inline void
+TraceBuffer::operator() (const char *str, int a0, int a1)
+{
+ entries[index].str = str;
+ entries[index].args[0] = a0;
+ entries[index].args[1] = a1;
+ index = (index + 1) % entries_nb;
+}
+
+inline void
+TraceBuffer::operator() (const char *str, int a0, int a1, int a2)
+{
+ entries[index].str = str;
+ entries[index].args[0] = a0;
+ entries[index].args[1] = a1;
+ entries[index].args[2] = a2;
+ index = (index + 1) % entries_nb;
+}
+
+inline void
+TraceBuffer::operator() (const char *str, int a0, int a1, int a2, int a3)
+{
+ entries[index].str = str;
+ entries[index].args[0] = a0;
+ entries[index].args[1] = a1;
+ entries[index].args[2] = a2;
+ entries[index].args[3] = a3;
+ index = (index + 1) % entries_nb;
+}
+
+} // namespace ucoo
+
+#endif // ucoo_utils_trace_hh