├── .cproject
├── .gitignore
├── .project
├── CMakeLists.txt
├── README.md
├── include
├── avr
│ ├── hardware
│ │ ├── arch.hpp
│ │ ├── configurator.hpp
│ │ ├── driver.hpp
│ │ ├── initialize.hpp
│ │ ├── pin.hpp
│ │ ├── standard
│ │ │ ├── arch.hpp
│ │ │ └── ports.hpp
│ │ ├── tags.hpp
│ │ └── test
│ │ │ ├── arch.hpp
│ │ │ └── ports.hpp
│ ├── pins.hpp
│ └── stepper.hpp
└── mpl
│ ├── collection.hpp
│ ├── integral_constant.hpp
│ └── util.hpp
├── platform_test
├── CMakeLists.txt
├── standard.cpp
└── stepper.cpp
└── test
├── CMakeLists.txt
├── arch.cpp
├── configurator.cpp
├── driver.cpp
├── initialize.cpp
├── mpl.cpp
├── pins.cpp
└── stepper.cpp
/.cproject:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /platform/
2 | /unit/
3 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | arduino_modern
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder
10 | clean,full,incremental,
11 |
12 |
13 |
14 |
15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
16 | full,incremental,
17 |
18 |
19 |
20 |
21 |
22 | org.eclipse.cdt.core.cnature
23 | org.eclipse.cdt.core.ccnature
24 | org.eclipse.cdt.managedbuilder.core.managedBuildNature
25 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
26 |
27 |
28 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.5)
2 |
3 | set(MODE "platform" CACHE STRING "")
4 | set(ARDUINO_CXX_FLAGS "-std=c++14 -mcall-prologues -ffunction-sections -fdata-sections -fno-exceptions")
5 |
6 | if (${MODE} STREQUAL "platform")
7 | set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/../arduino-cmake/cmake/ArduinoToolchain.cmake)
8 | endif (${MODE} STREQUAL "platform")
9 |
10 | Project(avr-core)
11 |
12 | if (${MODE} STREQUAL "unit")
13 | enable_testing()
14 | include(CTest)
15 | add_subdirectory(test)
16 | elseif(${MODE} STREQUAL "platform")
17 | add_subdirectory(platform_test)
18 | endif (${MODE} STREQUAL "unit")
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Modern C++ Arduino Library
2 |
3 | This project has not yet gained alpha status. Use at own risk.
4 |
5 | The goal of this project is to create a C++ arduino library that:
6 |
7 | * Enforces hardware semantics through type safety. Can't read an input pin for example.
8 | * Easy to use for everyone.
9 | * Fast - will use C++ metaprogramming through templates and constexpr to make things as fast as possible while not sacrificing interface simplicity.
10 | * Tight - Will use C++ metaprogramming to avoid unnecessary information being embedded into the executable.
11 |
12 | # using
13 |
14 | ## Adding a new platform:
15 |
16 | First you must describe your port type. This is going to have the size of the registers
17 | as well as providing access to them.
18 |
19 | Then you create your platform via calls to describe_platform and pass it a platform builder.
20 |
21 | Example:
22 |
23 | `constexpr auto test = describe_platform(arch_{}.register_pin(pin1, P0, 1));`
24 |
25 | The arguments to `register_pin` are the pin id you want to add, the port it uses, and the pin's bitmask. Calls to register_pin can be chained.
26 |
27 | In the future the interface will be:
28 |
29 | `constexpr auto test_platform = describe_platform(platform(test_io).register_pin(pin1, P0, 1));`
30 |
31 | ## Configuring your pins:
32 |
33 | `auto driver = initialize(test_platform.set_mode(pin1, output));`
34 |
35 | The arguments to `set_mode` are the pin id you want to set, and the mode you want to set it to.
36 |
37 | ## Using your pins:
38 |
39 | `driver.high(pin1);`
40 |
41 | This turns on pin1.
42 |
43 | `driver.low(pin1);`
44 |
45 | This turns off pin1.
46 |
47 | `bool on = driver.read(pin1);`
48 |
49 | Reads the value of the digital pin.
50 |
51 | You can only use high/low on pins configured for output, and read on pins configured for input.
52 |
53 | PWM and analog input pins are not yet supported.
54 |
55 | # Roadmap:
56 |
57 | In no particular order...
58 |
59 | * Devices - you'll be able create new devices or use those available in the library to operate periferals. They'll remove the pins from both availability and initialization and govern them themselves. You won't be able to mess with them outside the device.
60 | * Independence from arduino lib - only use the avr c runtime -- no Arduino.h anywhere.
61 | * Port merging - you'll be able to `driver.high(pin1,pin2,pin3);` and it will send one command per port. Metaprogramming will create the correct mask at compile time and it'll be used to set the pins to high in one call.
62 | * Further safety measures - registering an already registered pin should fail. registering a new pin with a port/mask combo already registered for another pin should fail. registering a pin with a mask past the port's capabilities should fail.
63 | * Timers
64 | * PWM - tone/analogWrite
65 | * More devices - things in mind: temp, light, motors, wire
66 | * MySensors compatibility layer: ability to implement MySensors nodes using this lib.
67 | * Lock-in - make it as tough as possible to break through the safety provided.
68 | * Event looping with signal interface. Utilities to go with.
69 | * All examples from Arduino Starter Kit book translated.
--------------------------------------------------------------------------------
/include/avr/hardware/arch.hpp:
--------------------------------------------------------------------------------
1 | #ifndef AVR_HARDWARE_ARCH_HPP
2 | #define AVR_HARDWARE_ARCH_HPP
3 |
4 | #include "../../mpl/collection.hpp"
5 | #include "pin.hpp"
6 |
7 | namespace avr { namespace hardware {
8 |
9 | // TODO: Would be nice to ensure a pin can't be registered with port/mask config already used.
10 | // Also if the port is full.
11 |
12 | template < typename RawOps >
13 | struct basic_ops : RawOps
14 | {
15 | template < typename Pin >
16 | static void set_mode(Pin pin, pin_config::input_tag)
17 | {
18 | auto old = basic_ops::status_register();
19 | basic_ops::disable_interrupts();
20 |
21 | *(pin.port().mode_register()) &= ~pin.mask();
22 | *(pin.port().output_register()) &= ~pin.mask();
23 |
24 | basic_ops::status_register() = old;
25 | }
26 |
27 | template < typename Pin >
28 | static void set_mode(Pin pin, pin_config::output_tag)
29 | {
30 | auto old = basic_ops::status_register();
31 | basic_ops::disable_interrupts();
32 |
33 | *(pin.port().mode_register()) |= pin.mask();
34 |
35 | basic_ops::status_register() = old;
36 | }
37 |
38 | template < typename Pin >
39 | static void high(Pin pin)
40 | {
41 | auto old = basic_ops::status_register();
42 | basic_ops::disable_interrupts();
43 |
44 | *(pin.port().output_register()) |= pin.mask();
45 |
46 | basic_ops::status_register() = old;
47 | }
48 |
49 | template < typename Pin >
50 | static void toggle(Pin pin)
51 | {
52 | auto old = basic_ops::status_register();
53 | basic_ops::disable_interrupts();
54 |
55 | *(pin.port().output_register()) ^= pin.mask();
56 |
57 | basic_ops::status_register() = old;
58 | }
59 |
60 | template < typename Pin >
61 | static void low(Pin pin)
62 | {
63 | auto old = basic_ops::status_register();
64 | basic_ops::disable_interrupts();
65 |
66 | *(pin.port().output_register()) &= ~pin.mask();
67 |
68 | basic_ops::status_register() = old;
69 | }
70 |
71 | template < typename Pin >
72 | static bool read(Pin pin)
73 | {
74 | return *pin.port().input_register() & pin.mask();
75 | }
76 |
77 | };
78 |
79 |
80 | template < typename RawOps, typename PinConfiguration = mpl::lookup_collection >
81 | struct arch__
82 | {
83 | using ops = RawOps;
84 |
85 | template < typename Pin, typename Port, typename Mask >
86 | static constexpr auto register_pin(Pin p, Port port, Mask mask)
87 | {
88 | return create(p, PinConfiguration::insert(p, pin(port,mask)));
89 | }
90 |
91 | template < typename Pin >
92 | static constexpr bool has_pin(Pin pin)
93 | {
94 | return PinConfiguration::has(pin);
95 | }
96 |
97 | static constexpr PinConfiguration pins() { return PinConfiguration{}; }
98 |
99 | static constexpr RawOps io() { return RawOps{}; }
100 |
101 | constexpr arch__() {}
102 |
103 | template < typename Pin, typename NewPins >
104 | static constexpr auto create(Pin, NewPins)
105 | {
106 | return arch__{};
107 | }
108 | };
109 |
110 | template < typename RawOps >
111 | using arch_ = arch__>;
112 |
113 |
114 | }}
115 |
116 |
117 | #endif
118 |
--------------------------------------------------------------------------------
/include/avr/hardware/configurator.hpp:
--------------------------------------------------------------------------------
1 | #ifndef AVR_HARDWARE_CONFIGURATOR_HPP
2 | #define AVR_HARDWARE_CONFIGURATOR_HPP
3 |
4 | #include "../../mpl/collection.hpp"
5 |
6 | namespace avr { namespace hardware {
7 |
8 | namespace detail_ {
9 |
10 | template < typename IO
11 | , typename AvailablePins
12 | , typename ConfiguredPins = mpl::lookup_collection
13 | >
14 | struct configurator
15 | {
16 | template < typename Pin >
17 | static constexpr bool available(Pin pin)
18 | {
19 | return AvailablePins::has(pin);
20 | }
21 |
22 | template < typename Pin, typename Mode >
23 | static constexpr auto set_mode(Pin pin, Mode mode)
24 | {
25 | return create( AvailablePins::remove(pin)
26 | , ConfiguredPins::insert(pin, make_config(pin,mode)));
27 | }
28 |
29 | template < typename Pin >
30 | static constexpr auto mode(Pin pin)
31 | {
32 | return ConfiguredPins::get(pin).mode; // invalid use of void? Pin isn't configured.
33 | }
34 |
35 | static constexpr IO io() { return IO{}; }
36 |
37 | constexpr ConfiguredPins configured() { return ConfiguredPins{}; }
38 |
39 | constexpr configurator() {}
40 |
41 | private:
42 |
43 | template < typename PinDesc, typename Mode >
44 | struct pin_config
45 | {
46 | constexpr pin_config() {}
47 |
48 | static constexpr auto pin_desc = PinDesc{};
49 | static constexpr auto mode = Mode{};
50 | };
51 |
52 | template < typename Pin, typename Mode >
53 | static constexpr auto make_config(Pin pin, Mode mode)
54 | {
55 | using desc = decltype(AvailablePins::get(pin));
56 | return pin_config{};
57 | }
58 |
59 | template < typename AP, typename CP >
60 | static constexpr auto create(AP ap, CP cp)
61 | {
62 | return configurator{};
63 | }
64 | };
65 |
66 | }
67 |
68 | template < typename PlatformBuilder >
69 | constexpr auto describe_platform(PlatformBuilder builder)
70 | {
71 | return detail_::configurator{};
72 | }
73 |
74 |
75 | }}
76 |
77 |
78 |
79 | #endif
80 |
--------------------------------------------------------------------------------
/include/avr/hardware/driver.hpp:
--------------------------------------------------------------------------------
1 | #ifndef AVR_HARDWARE_DRIVER_HPP
2 | #define AVR_HARDWARE_DRIVER_HPP
3 |
4 | #include "tags.hpp"
5 | #include "pin.hpp"
6 | #include "../../mpl/util.hpp"
7 |
8 | namespace avr { namespace hardware {
9 |
10 | namespace detail_ {
11 |
12 |
13 |
14 | template < typename IO
15 | , typename InputPins = mpl::lookup_collection
16 | , typename OutputPins = mpl::lookup_collection >
17 | struct driver
18 | {
19 | constexpr driver() {}
20 |
21 | template < typename ... Pin >
22 | void high(Pin ... pins) const
23 | {
24 | constexpr auto pin_collection = collate_pins(OutputPins{}, pins...);
25 | mpl::for_each( pin_collection.begin()
26 | , pin_collection.end()
27 | , [](auto pin_port) { IO::high(hardware::pin(pin_port.key(), pin_port.value())); });
28 | }
29 |
30 | template < typename ... Pin >
31 | void low(Pin ... pins) const
32 | {
33 | constexpr auto pin_collection = collate_pins(OutputPins{}, pins...);
34 | mpl::for_each( pin_collection.begin()
35 | , pin_collection.end()
36 | , [](auto pin_port) { IO::low(hardware::pin(pin_port.key(), pin_port.value())); });
37 | }
38 |
39 | template < typename ... Pin >
40 | void toggle(Pin ... pins) const
41 | {
42 | constexpr auto pin_collection = collate_pins(OutputPins{}, pins...);
43 | mpl::for_each( pin_collection.begin()
44 | , pin_collection.end()
45 | , [](auto pin_port) { IO::toggle(hardware::pin(pin_port.key(), pin_port.value())); });
46 | }
47 |
48 | template < typename Pin >
49 | bool read(Pin pin) const
50 | {
51 | return IO::read(InputPins::get(pin));
52 | }
53 |
54 | template < typename Pin, typename Desc >
55 | constexpr auto add_pin(Pin pin, Desc desc, pin_config::input_tag) const
56 | {
57 | using new_input = decltype(InputPins::insert(pin, desc));
58 |
59 | return driver{};
60 | }
61 |
62 | template < typename Pin, typename Desc >
63 | constexpr auto add_pin(Pin pin, Desc desc, pin_config::output_tag) const
64 | {
65 | using new_output = decltype(OutputPins::insert(pin,desc));
66 |
67 | return driver{};
68 | }
69 |
70 | };
71 |
72 | // TODO: accumulate
73 | template < typename Driver, typename End >
74 | constexpr auto const create_driver(Driver driver, End,End)
75 | {
76 | return driver;
77 | }
78 |
79 | template < typename Driver, typename Beg, typename End >
80 | constexpr auto const create_driver(Driver driver, Beg beg, End end)
81 | {
82 | return create_driver(driver.add_pin( beg.key()
83 | , beg.deref().value().pin_desc
84 | , beg.deref().value().mode), beg.next(), end);
85 | }
86 |
87 | template < typename IO >
88 | constexpr auto const new_driver(IO)
89 | {
90 | return driver{};
91 | }
92 |
93 | }
94 |
95 | template < typename HardwareConfig >
96 | auto const create_driver(HardwareConfig cfg)
97 | {
98 | return detail_::create_driver( detail_::new_driver(cfg.io())
99 | , cfg.configured().begin()
100 | , cfg.configured().end() );
101 | }
102 |
103 |
104 | #if 0
105 | template < typename PinDesc >
106 | struct input_pin
107 | {
108 | template < typename IO >
109 | static bool read(IO)
110 | {
111 | return IO::read(PinDesc{});
112 | }
113 |
114 | using pin_t = PinDesc;
115 | using type = input_pin;
116 | };
117 |
118 | template < typename PinDesc >
119 | struct output_pin
120 | {
121 | template < typename IO >
122 | static void high(IO)
123 | {
124 | IO::high(PinDesc{});
125 | }
126 |
127 | template < typename IO >
128 | static void low(IO)
129 | {
130 | IO::low(PinDesc{});
131 | }
132 |
133 | using pin_t = PinDesc;
134 | using type = output_pin;
135 | };
136 |
137 | template < typename PinDesc, typename Mode > struct pin_type;
138 |
139 | template < typename PinDesc >
140 | struct pin_type
141 | {
142 | using type = input_pin;
143 | };
144 | template < typename PinDesc >
145 | struct pin_type
146 | {
147 | using type = output_pin;
148 | };
149 |
150 | template < typename Pin, typename ... Drivers >
151 | struct get_driver;
152 |
153 | template < bool b, typename True, typename False > struct if_ { using type = False; };
154 | template < typename True, typename False >
155 | struct if_ { using type = True; };
156 |
157 | template < typename T > struct ident { using type = T; };
158 |
159 | template < typename Pin, typename Driver, typename ... Remaining >
160 | struct get_driver
161 | : if_, get_driver>::type
162 | {
163 | };
164 |
165 | template < typename ... PinDrivers >
166 | struct pin_drivers
167 | {
168 | template < typename IO, typename Pin >
169 | static void high(IO io,Pin)
170 | {
171 | using driver = typename get_driver::type;
172 | driver::high(io);
173 | }
174 |
175 | template < typename IO, typename Pin >
176 | static void low(IO io, Pin)
177 | {
178 | using driver = typename get_driver::type;
179 | driver::low(io);
180 | }
181 |
182 | template < typename IO, typename Pin >
183 | static bool read(IO io, Pin)
184 | {
185 | using driver = typename get_driver::type;
186 | return driver::read(io);
187 | }
188 | };
189 |
190 | template < typename ... Pins >
191 | using create_drivers = pin_drivers::type ...>;
192 |
193 | template < typename IO, typename Pins >
194 | struct driver_
195 | {
196 | static constexpr auto io = IO{};
197 |
198 | template < typename Pin >
199 | static void high(Pin pin) { Pins::high(io, pin); }
200 |
201 | template < typename Pin >
202 | static void low(Pin pin) { Pins::low(io,pin); }
203 |
204 | template < typename Pin >
205 | static bool read(Pin pin) { return Pins::read(io,pin); }
206 | };
207 |
208 | #endif
209 |
210 | }}
211 |
212 |
213 | #endif
214 |
--------------------------------------------------------------------------------
/include/avr/hardware/initialize.hpp:
--------------------------------------------------------------------------------
1 | #ifndef AVR_HARDWARE_INITIALIZE_HPP
2 | #define AVR_HARDWARE_INITIALIZE_HPP
3 |
4 | //#include "configurator.hpp"
5 | //#include "driver.hpp"
6 |
7 | #include "../../mpl/util.hpp"
8 | #include "driver.hpp"
9 |
10 | // TODO: Can probably eliminate this by sticking the initialization into the pin itself
11 | // as a static initialization. Thus you'd go: auto const pin = hardware_config.pin(pin1)
12 | // When that pin is instantiated the member will be initialized before main and the
13 | // routine to do so will call set_mode.
14 |
15 | namespace avr { namespace hardware {
16 |
17 |
18 | template < typename HardwareConfig >
19 | auto initialize(HardwareConfig hardware_config)
20 | {
21 | mpl::for_each( hardware_config.configured()
22 | , [=] (auto pin)
23 | {
24 | hardware_config.io().set_mode(pin.value().pin_desc, pin.value().mode);
25 | });
26 |
27 | return create_driver(hardware_config);
28 | }
29 |
30 | }}
31 |
32 | #endif
33 |
--------------------------------------------------------------------------------
/include/avr/hardware/pin.hpp:
--------------------------------------------------------------------------------
1 | #ifndef AVR_HARDWARE_PIN_HPP
2 | #define AVR_HARDWARE_PIN_HPP
3 |
4 | #include "../../mpl/collection.hpp"
5 |
6 | namespace avr { namespace hardware {
7 |
8 | namespace detail_ {
9 |
10 | template < typename Port, typename Mask >
11 | struct pin
12 | {
13 | using register_type = typename Port::register_type;
14 | constexpr pin() {}
15 |
16 | static constexpr Port port() { return Port{}; }
17 | static constexpr register_type mask() { return Mask::value(); }
18 | };
19 |
20 | }
21 |
22 | template < typename Port, typename Mask >
23 | constexpr detail_::pin pin(Port, Mask)
24 | {
25 | return detail_::pin{};
26 | }
27 |
28 |
29 | namespace detail_ {
30 |
31 | struct pin_collator
32 | {
33 | constexpr pin_collator() {}
34 |
35 | template < typename Result, typename Port, typename Mask >
36 | constexpr auto operator()(Result result, pin pin) const
37 | {
38 | constexpr auto pin_collection = result.at(pin.port(), mpl::integral_constant{});
39 | return result.insert(pin.port(), pin_collection | Mask{});
40 | }
41 | };
42 |
43 | template < typename PinCollection >
44 | struct lookup_pin
45 | {
46 | constexpr lookup_pin(){}
47 |
48 | template < typename Result, typename Pin >
49 | constexpr auto operator()(Result result, Pin pin) const
50 | {
51 | return result.append(PinCollection::get(pin));
52 | }
53 | };
54 |
55 | }
56 |
57 | template < typename PinCollection, typename ... Pin >
58 | constexpr auto collate_pins(PinCollection pin_collection, Pin ... pin)
59 | {
60 | constexpr auto pin_pack = mpl::collect_pack(pin...);
61 | constexpr auto transformed_pack = mpl::accumulate(pin_pack, mpl::collection{}, detail_::lookup_pin{});
62 |
63 | return mpl::accumulate(transformed_pack, mpl::lookup_collection{}, detail_::pin_collator{});
64 | }
65 |
66 |
67 |
68 | }}
69 |
70 | #endif
71 |
--------------------------------------------------------------------------------
/include/avr/hardware/standard/arch.hpp:
--------------------------------------------------------------------------------
1 | #ifndef AVR_HARDWARE_STANDARD_ARCH_HPP
2 | #define AVR_HARDWARE_STANDARD_ARCH_HPP
3 |
4 | // TODO: remove this requirement. The defs needed are likely in the avr libc.
5 | //#include
6 | //#include
7 | #include
8 |
9 | #include "../configurator.hpp"
10 | #include "../tags.hpp"
11 | #include "../arch.hpp"
12 | #include "../../../mpl/integral_constant.hpp"
13 |
14 | #include "ports.hpp"
15 |
16 | namespace avr { namespace hardware { namespace standard {
17 |
18 |
19 | struct arduino
20 | {
21 | //static decltype(SREG) current_status_register() { return SREG; }
22 | // Not sure why, but the following adds considerable size when used. The above doesn't.
23 | //static void restore_status_register(decltype(SREG) volatile& old) { SREG = old; }
24 |
25 |
26 | static decltype(SREG) volatile & status_register() { return SREG; }
27 |
28 | static void disable_interrupts() { cli(); }
29 | static void enable_interrupts() { sei(); }
30 | };
31 |
32 | using standard_arch = arch_;
33 |
34 |
35 | #define BV(X) mpl::integral_constant{}
36 |
37 | // PWM and AI pins not yet available.
38 |
39 | constexpr auto standard_hw =
40 | describe_platform(standard_arch{}
41 | .register_pin(pin1, ports::PD, BV(1))
42 | .register_pin(pin2, ports::PD, BV(2))
43 | //.register_pin(pin3, ports::PD, BV(3))
44 | .register_pin(pin4, ports::PD, BV(4))
45 | //.register_pin(pin5, ports::PD, BV(5))
46 | //.register_pin(pin6, ports::PD, BV(6))
47 | .register_pin(pin7, ports::PD, BV(7))
48 | .register_pin(pin8, ports::PB, BV(0))
49 | //.register_pin(pin9, ports::PB, BV(1))
50 | //.register_pin(pin10, ports::PB, BV(2))
51 | //.register_pin(pin11, ports::PB, BV(3))
52 | .register_pin(pin12, ports::PB, BV(4))
53 | .register_pin(pin13, ports::PB, BV(5))
54 | );
55 |
56 | /*
57 | * constexpr auto standard = arch.register_pin(pin13, PB, i<_BV(5)>{});
58 | * constexpr auto pgm_hardware_initializer = standard.set_mode(pin13, output);
59 | *
60 | * auto const pgm_hardware = pgm_hardware_initializer.init();
61 | *
62 | * auto const pin = pgm_hardware.pin(pin13);
63 | * pin.high();
64 | */
65 |
66 | }}} // avr::hardware::standard
67 |
68 |
69 | #endif
70 |
--------------------------------------------------------------------------------
/include/avr/hardware/standard/ports.hpp:
--------------------------------------------------------------------------------
1 | #ifndef AVR_HARDWARE_STANDARD_PORTS_HPP
2 | #define AVR_HARDWARE_STANDARD_PORTS_HPP
3 |
4 | namespace avr { namespace hardware { namespace standard { namespace ports {
5 |
6 | #define PORT(X) \
7 | struct P ## X ## _ \
8 | { \
9 | static uint8_t volatile* mode_register() { return &DDR ## X ; } \
10 | static uint8_t volatile* input_register() { return &PIN ## X ; } \
11 | static uint8_t volatile* output_register() { return &PORT ## X ; } \
12 | constexpr P ## X ## _ (){} \
13 | using register_type = uint8_t; \
14 | }; constexpr P ## X ## _ P ## X
15 |
16 | PORT(B);
17 | PORT(C);
18 | PORT(D);
19 |
20 |
21 |
22 | }}}}
23 |
24 | #endif
25 |
--------------------------------------------------------------------------------
/include/avr/hardware/tags.hpp:
--------------------------------------------------------------------------------
1 | #ifndef AVR_HARDWARE_TAGS_HPP
2 | #define AVR_HARDWARE_TAGS_HPP
3 |
4 | namespace avr { namespace hardware { namespace pin_config {
5 |
6 | constexpr struct digital_tag {} digital;
7 | constexpr struct analog_tag {} analog;
8 |
9 | constexpr struct input_tag { constexpr input_tag(){} } input;
10 | constexpr struct input_pull_tag { constexpr input_pull_tag(){} } input_pull;
11 | constexpr struct output_tag { constexpr output_tag(){} } output;
12 |
13 | // timers to come.
14 |
15 | #if 0
16 | template < int I >
17 | struct pin_tag { enum { id = I }; };
18 |
19 | template < typename PinTag, typename TypeTag >
20 | struct pin_descriptor
21 | {
22 | using pin_tag = PinTag;
23 | using type_tag = TypeTag;
24 |
25 | enum { id = PinTag::value };
26 |
27 | pin_tag pin;
28 | type_tag type;
29 |
30 | // uint8_t mask;
31 | // volatile uint8_t* mode_register();
32 | // volatile uint8_t* input_register();
33 | // volatile uint8_t* output_register();
34 | };
35 |
36 | template < typename PinTag, typename TypeTag, typename ModeTag >
37 | constexpr pin_descriptor create_pin(PinTag,TypeTag,ModeTag)
38 | {
39 | return pin_descriptor{};
40 | }
41 |
42 |
43 | template
44 | struct pin_collection : Next
45 | {
46 | };
47 |
48 | struct pins_end
49 | {
50 | template
51 | using pin_descriptor = pin_descriptor,TypeTag,ModeTag>;
52 |
53 | template
54 | using pin_collection = pin_collection,pins_end>;
55 |
56 | template
57 | constexpr pin_collection add_pin(TypeTag, ModeTag)
58 | {
59 | return pin_collection{};
60 | }
61 | };
62 |
63 | constexpr pins_end configure_pins() { return pins_end{}; }
64 | #endif
65 |
66 | }}}
67 |
68 | #endif
69 |
--------------------------------------------------------------------------------
/include/avr/hardware/test/arch.hpp:
--------------------------------------------------------------------------------
1 | #ifndef AVR_HARDWARE_TEST_HPP
2 | #define AVR_HARDWARE_TEST_HPP
3 |
4 | #include "../configurator.hpp" // TODO: Shouldn't be depending on this in this file.
5 | #include "../../pins.hpp"
6 | #include "ports.hpp"
7 | #include "../tags.hpp"
8 | #include "../arch.hpp"
9 | #include "../../../mpl/integral_constant.hpp"
10 |
11 | namespace avr { namespace hardware { namespace test {
12 |
13 | struct test_arch_
14 | {
15 | static bool& status_register() { static bool reg = false; return reg; }
16 |
17 | static void disable_interrupts() {}
18 | static void enable_interrupts() {}
19 | };
20 |
21 |
22 | constexpr auto test_arch =
23 | describe_platform(arch_{}
24 | .register_pin(pin1, P0, 1_c)
25 | .register_pin(pin2, P0, 2_c)
26 | .register_pin(pin3, P1, 1_c)
27 | );
28 |
29 | }}}
30 |
31 |
32 |
33 | #endif
34 |
--------------------------------------------------------------------------------
/include/avr/hardware/test/ports.hpp:
--------------------------------------------------------------------------------
1 | #ifndef AVR_HARDWARE_TEST_PORTS_HPP
2 | #define AVR_HARDWARE_TEST_PORTS_HPP
3 |
4 | namespace avr { namespace hardware { namespace test {
5 |
6 | template
7 | struct port
8 | {
9 | static uint8_t* mode_register() { return &mode; }
10 | static uint8_t* input_register() { return &input; }
11 | static uint8_t* output_register() { return &output; }
12 |
13 | static void reset();
14 |
15 | static uint8_t mode;
16 | static uint8_t input;
17 | static uint8_t output;
18 |
19 | using register_type = uint8_t;
20 |
21 | constexpr port() {}
22 | };
23 |
24 | using P0_ = port<0>;
25 | using P1_ = port<1>;
26 | using P2_ = port<2>;
27 |
28 | constexpr port<0> P0;
29 | constexpr port<1> P1;
30 | constexpr port<2> P2;
31 |
32 | #define DEFINE_TEST_PORT_REGISTERS() \
33 | template \
34 | uint8_t port::mode = 0; \
35 | \
36 | template \
37 | uint8_t port::input = 0; \
38 | \
39 | template \
40 | uint8_t port::output = 0
41 |
42 | #ifndef OMIT_PORT_REGISTERS
43 | DEFINE_TEST_PORT_REGISTERS();
44 | #endif
45 |
46 | }}}
47 |
48 | #endif
49 |
--------------------------------------------------------------------------------
/include/avr/pins.hpp:
--------------------------------------------------------------------------------
1 | #ifndef AVR_PINS_HPP
2 | #define AVR_PINS_HPP
3 |
4 | //#include
5 | //#include
6 |
7 | using uint8_t = char unsigned;
8 |
9 | namespace avr {
10 |
11 | template < uint8_t PinId >
12 | struct pin_tag { static constexpr uint8_t id = PinId; constexpr pin_tag() {}};
13 |
14 | #define PIN(X) \
15 | using pin ## X ## _tag = pin_tag; \
16 | constexpr auto pin ## X = pin ## X ## _tag{};
17 |
18 | PIN(1);
19 | PIN(2);
20 | PIN(3);
21 | PIN(4);
22 | PIN(5);
23 | PIN(6);
24 | PIN(7);
25 | PIN(8);
26 | PIN(9);
27 | PIN(10);
28 | PIN(11);
29 | PIN(12);
30 | PIN(13);
31 |
32 | }
33 |
34 | #endif
35 |
--------------------------------------------------------------------------------
/include/avr/stepper.hpp:
--------------------------------------------------------------------------------
1 | #ifndef AVR_STEPPER_HPP
2 | #define AVR_STEPPER_HPP
3 |
4 | namespace avr {
5 |
6 | template < typename T >
7 | T&& declval();
8 |
9 | struct steps
10 | {
11 | constexpr steps(int i) : count{i} {}
12 |
13 | int count;
14 | };
15 |
16 | struct phases
17 | {
18 | constexpr phases(int i) : count{i} {}
19 |
20 | int count;
21 | };
22 |
23 | struct stepper_motor
24 | {
25 | constexpr stepper_motor(avr::steps s, avr::phases p) : steps_{s}, phases_{p} {}
26 |
27 | constexpr auto steps() -> decltype(declval().count) { return steps_.count; }
28 | constexpr auto phases() -> decltype(declval().count) { return phases_.count; }
29 |
30 | private:
31 | avr::steps steps_;
32 | avr::phases phases_;
33 | };
34 |
35 | constexpr stepper_motor stepper(steps s, phases p) { return stepper_motor{s,p}; }
36 |
37 | }
38 |
39 | #endif
40 |
--------------------------------------------------------------------------------
/include/mpl/collection.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MPL_COLLECTION_HPP
2 | #define MPL_COLLECTION_HPP
3 |
4 | #include "integral_constant.hpp"
5 | #include "util.hpp"
6 |
7 | namespace mpl {
8 |
9 | namespace detail_ {
10 |
11 | struct lc_term;
12 |
13 | template < typename Collection >
14 | struct lc_iter;
15 |
16 |
17 | template < typename Key, typename Value, typename Next = lc_term >
18 | struct lc_node : Next
19 | {
20 | constexpr lc_node(){}
21 |
22 | template < typename Key_ >
23 | static constexpr auto remove(Key_ key)
24 | {
25 | using next_ = decltype(Next::remove(key));
26 | return lc_node{};
27 | }
28 |
29 | static constexpr Next remove(Key)
30 | {
31 | return Next{};
32 | }
33 |
34 | template < typename Key_, typename Value_ >
35 | static constexpr auto insert(Key_ key, Value_ value)
36 | {
37 | using next = decltype(Next::insert(key,value));
38 | return lc_node{};
39 | }
40 |
41 | template < typename Value_ >
42 | static constexpr auto insert(Key, Value_)
43 | {
44 | return lc_node{};
45 | }
46 |
47 | template < typename Key_>
48 | static constexpr auto get(Key_ key)
49 | {
50 | return Next::get(key);
51 | }
52 |
53 | static constexpr Value get(Key) { return Value{}; }
54 |
55 | template < typename Key_, typename Def >
56 | static constexpr auto at(Key_ key, Def def) { return Next::at(key,def); }
57 |
58 | template < typename Def >
59 | static constexpr auto at(Key, Def) { return Value{}; }
60 |
61 | template < typename Key_ >
62 | static constexpr bool has(Key_ key)
63 | {
64 | return Next::has(key);
65 | }
66 |
67 | static constexpr bool has(Key) { return true; }
68 |
69 | static constexpr lc_iter begin()
70 | {
71 | return lc_iter{};
72 | }
73 |
74 | static constexpr lc_iter end(); // { return lc_iter{}; }
75 |
76 | };
77 |
78 | struct lc_term
79 | {
80 | constexpr lc_term(){}
81 |
82 | template < typename Key >
83 | static constexpr bool has(Key) { return false; }
84 |
85 | template < typename Key, typename Value >
86 | static constexpr auto insert(Key,Value)
87 | {
88 | return lc_node{};
89 | }
90 |
91 | template < typename Key, typename Def >
92 | static constexpr Def at(Key, Def def) { return def; }
93 | };
94 | template < >
95 | struct lc_iter
96 | {
97 | constexpr lc_iter() {}
98 | static constexpr bool at_end() { return true; }
99 | };
100 |
101 |
102 | template < typename Key, typename Value, typename Next >
103 | struct lc_iter>
104 | {
105 | constexpr lc_iter()
106 | {}
107 |
108 | static constexpr bool at_end() { return false; }
109 |
110 | struct value_type
111 | {
112 | constexpr value_type(){}
113 |
114 | static constexpr Key key() { return Key{}; }
115 | static constexpr Value value() { return Value{}; }
116 | };
117 |
118 | static constexpr auto deref()
119 | {
120 | return value_type{};
121 | }
122 |
123 | static constexpr Key key() { return Key{}; }
124 |
125 | static constexpr lc_iter next() { return lc_iter{}; }
126 | };
127 |
128 | template < typename Key, typename Value, typename Next >
129 | constexpr lc_iter lc_node::end() { return lc_iter{}; }
130 |
131 | }
132 |
133 | struct lookup_collection : detail_::lc_term
134 | {
135 | constexpr lookup_collection(){}
136 | };
137 |
138 |
139 | namespace detail_ {
140 |
141 | struct c_term;
142 |
143 | template < typename Value, typename Next = c_term >
144 | struct c_node
145 | {
146 | template < typename Value_ >
147 | static constexpr auto append(Value_ val)
148 | {
149 | using next = decltype(Next::append(val));
150 | return c_node{};
151 | }
152 |
153 | template < typename Idx >
154 | static constexpr auto get(Idx idx)
155 | {
156 | return Next::get(idx - 1_c);
157 | }
158 |
159 | static constexpr Value get(mpl::integral_constant)
160 | {
161 | return Value{};
162 | }
163 |
164 | static constexpr auto begin();
165 | static constexpr auto end();
166 | };
167 |
168 | struct c_term
169 | {
170 | template < typename Value_ >
171 | static constexpr auto append(Value_)
172 | {
173 | return c_node{};
174 | }
175 | };
176 |
177 | template < typename Collection >
178 | struct c_iter
179 | {
180 | constexpr c_iter(){}
181 | };
182 |
183 | template < typename Value, typename Next >
184 | struct c_iter>
185 | {
186 | constexpr c_iter(){}
187 |
188 | static constexpr Value deref() { return Value{}; }
189 | static constexpr c_iter next() { return c_iter(); }
190 | };
191 |
192 | template < typename Value, typename Next >
193 | constexpr auto c_node::begin() { return c_iter>{}; }
194 |
195 | template < typename Value, typename Next >
196 | constexpr auto c_node::end() { return c_iter{}; }
197 |
198 | template < typename T >
199 | constexpr auto collect_pack(T t)
200 | {
201 | return c_term::append(t);
202 | }
203 |
204 | template < typename T, typename ... Pack>
205 | constexpr auto collect_pack(T t, Pack ... pack)
206 | {
207 | return collect_pack(pack...).append(t);
208 | }
209 |
210 | }
211 |
212 | struct collection : detail_::c_term
213 | {
214 | constexpr collection(){}
215 | };
216 |
217 | template < typename ... Pack >
218 | constexpr auto collect_pack(Pack...pack)
219 | {
220 | return detail_::collect_pack(pack...);
221 | }
222 |
223 |
224 | }
225 |
226 |
227 | #endif
228 |
--------------------------------------------------------------------------------
/include/mpl/integral_constant.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MPL_INTEGRAL_CONSTANT_HPP
2 | #define MPL_INTEGRAL_CONSTANT_HPP
3 |
4 | namespace mpl {
5 |
6 | template < typename T, T Value >
7 | struct integral_constant
8 | {
9 | constexpr static T value() { return Value; }
10 | };
11 |
12 | template < uint8_t Value >
13 | using uint8_t_ = integral_constant;
14 |
15 | template < typename T, T Value0, T Value1 >
16 | constexpr auto operator - (integral_constant,integral_constant)
17 | {
18 | return integral_constant{};
19 | }
20 |
21 | template < typename T, T Value0, T Value1 >
22 | constexpr auto operator | (integral_constant,integral_constant)
23 | {
24 | return integral_constant{};
25 | }
26 |
27 | namespace detail_ {
28 |
29 | template < typename T, char ... Seq >
30 | struct create_constant;
31 |
32 | template < typename T, char Head, char ... Tail >
33 | struct create_constant
34 | {
35 | static constexpr T value()
36 | {
37 | constexpr T val = create_constant::value() + (Head - '0') * place();
38 | return val;
39 | }
40 |
41 | static constexpr T place()
42 | {
43 | T n = 1;
44 | for (int i = 0; i < sizeof...(Tail); ++i)
45 | n *= 10;
46 | return n;
47 | }
48 | };
49 |
50 | template < typename T >
51 | struct create_constant
52 | {
53 | static constexpr T value() { return T{}; }
54 | };
55 |
56 |
57 | }
58 |
59 | }
60 |
61 | template < typename what > struct w;
62 |
63 | template < char ... Seq >
64 | constexpr auto operator""_c()
65 | {
66 | return mpl::integral_constant::value()>{};
67 | }
68 |
69 | #endif
70 |
--------------------------------------------------------------------------------
/include/mpl/util.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MPL_UTIL_HPP
2 | #define MPL_UTIL_HPP
3 |
4 | namespace mpl {
5 |
6 | template < typename T >
7 | T&& declval();
8 |
9 | template < typename T0, typename T1 >
10 | constexpr bool same_type(T0,T1) { return false; }
11 |
12 | template < typename T >
13 | constexpr bool same_type(T,T) { return true; }
14 |
15 | template < typename End, typename Fun >
16 | void for_each(End,End,Fun){}
17 |
18 | template < typename Beg, typename End, typename Fun >
19 | void for_each(Beg beg, End end, Fun fun)
20 | {
21 | fun(beg.deref());
22 | for_each(beg.next(), end, fun);
23 | }
24 |
25 | template < typename Collection, typename Fun >
26 | void for_each(Collection c, Fun f)
27 | {
28 | for_each(c.begin(), c.end(), f);
29 | }
30 |
31 | template < typename End, typename Result, typename Op >
32 | constexpr Result accumulate(End,End,Result, Op)
33 | {
34 | return Result{};
35 | }
36 |
37 | template < typename Beg, typename End, typename Result, typename Op >
38 | constexpr auto accumulate(Beg beg, End end, Result result, Op op)
39 | {
40 | return accumulate(beg.next(), end, op(result, beg.deref()), op);
41 | }
42 |
43 | template < typename Collection, typename Result, typename Op >
44 | constexpr auto accumulate(Collection collection, Result result, Op op)
45 | {
46 | return accumulate(collection.begin(), collection.end(), result, op);
47 | }
48 |
49 | }
50 |
51 | #endif
52 |
--------------------------------------------------------------------------------
/platform_test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | generate_avr_firmware(standard
3 | SRCS standard.cpp
4 | PORT /dev/ttyACM0
5 | SERIAL picocom @SERIAL_PORT@ -b 9600 -l
6 | BOARD uno)
7 |
8 |
9 | generate_arduino_firmware(stepper
10 | SRCS stepper.cpp
11 | PORT /dev/ttyACM0
12 | SERIAL picocom @SERIAL_PORT@ -b 9600 -l
13 | BOARD uno)
14 |
--------------------------------------------------------------------------------
/platform_test/standard.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "../include/avr/pins.hpp"
3 | #include "../include/avr/hardware/standard/arch.hpp"
4 | #include "../include/avr/hardware/standard/ports.hpp"
5 | #include "../include/avr/hardware/initialize.hpp"
6 |
7 | #include
8 |
9 | using namespace avr::hardware::standard;
10 | using namespace avr::hardware;
11 |
12 | using namespace avr;
13 |
14 | // 1260 16 12 1288 before using the driver.
15 | auto const driver = initialize(standard_hw.set_mode(pin13, pin_config::output));
16 | //.set_mode(pin1, pin_config::output)
17 | //.set_mode(pin2, pin_config::output));
18 |
19 | // 666 0 9 675 == same as not doing anything but delay. The constexpr stuff is functioning.
20 | //constexpr auto blah = standard_hw.set_mode(pin13, pin_config::output);
21 |
22 | void setup()
23 | {
24 | }
25 |
26 | void loop() {
27 | driver.high(pin13);
28 | _delay_ms(1000);
29 | driver.low(pin13);
30 | _delay_ms(500);
31 | }
32 |
33 | int main()
34 | {
35 | while (1) { loop(); }
36 | }
37 |
38 |
39 | /*
40 | *
41 | * original:
42 | text data bss dec hex filename
43 | 1064 0 9 1073 431 /home/satan/github/arduino/modern-core/platform/platform_test/standard.elf
44 | 0 0 0 0 0 /home/satan/github/arduino/modern-core/platform/platform_test/standard.eep
45 | *
46 | * set_mode:
47 | text data bss dec hex filename
48 | 934 0 9 943 3af /home/satan/github/arduino/modern-core/platform/platform_test/standard.elf
49 | 0 0 0 0 0 /home/satan/github/arduino/modern-core/platform/platform_test/standard.eep
50 | *
51 | * high/low:
52 | text data bss dec hex filename
53 | 690 0 9 699 2bb /home/satan/github/arduino/modern-core/platform/platform_test/standard.elf
54 | 0 0 0 0 0 /home/satan/github/arduino/modern-core/platform/platform_test/standard.eep
55 |
56 | * initialize:
57 | text data bss dec hex filename
58 | 728 0 9 737 2e1 /home/satan/github/arduino_modern/platform/platform_test/standard.elf
59 | 0 0 0 0 0 /home/satan/github/arduino_modern/platform/platform_test/standard.eep
60 | *
61 | * no more core:
62 | text data bss dec hex filename
63 | 238 0 0 238 ee /home/satan/github/arduino_modern/platform/platform_test/standard.elf
64 | 0 0 0 0 0 /home/satan/github/arduino_modern/platform/platform_test/standard.eep
65 |
66 | */
67 |
--------------------------------------------------------------------------------
/platform_test/stepper.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 |
5 | /*-----( Declare Constants, Pin Numbers )-----*/
6 | //---( Number of steps per revolution of INTERNAL motor in 4-step mode )---
7 | #define STEPS_PER_MOTOR_REVOLUTION 32
8 |
9 | //---( Steps per OUTPUT SHAFT of gear reduction )---
10 | #define STEPS_PER_OUTPUT_REVOLUTION 32 * 64 //2048
11 |
12 | /*-----( Declare objects )-----*/
13 | // create an instance of the stepper class, specifying
14 | // the number of steps of the motor and the pins it's
15 | // attached to
16 |
17 | //The pin connections need to be 4 pins connected
18 | // to Motor Driver In1, In2, In3, In4 and then the pins entered
19 | // here in the sequence 1-3-2-4 for proper sequencing
20 | Stepper small_stepper(STEPS_PER_MOTOR_REVOLUTION, 8, 10, 9, 11);
21 |
22 |
23 | /*-----( Declare Variables )-----*/
24 | int Steps2Take;
25 |
26 | void setup() /*----( SETUP: RUNS ONCE )----*/
27 | {
28 | // Nothing (Stepper Library sets pins as outputs)
29 | }/*--(end setup )---*/
30 |
31 | void loop() /*----( LOOP: RUNS CONSTANTLY )----*/
32 | {
33 | small_stepper.setSpeed(1); // SLOWLY Show the 4 step sequence
34 | Steps2Take = 4; // Rotate CW
35 | small_stepper.step(Steps2Take);
36 | delay(2000);
37 |
38 | Steps2Take = STEPS_PER_OUTPUT_REVOLUTION / 2; // Rotate CW 1/2 turn
39 | small_stepper.setSpeed(500);
40 | small_stepper.step(Steps2Take);
41 | delay(1000);
42 |
43 | Steps2Take = - STEPS_PER_OUTPUT_REVOLUTION / 2; // Rotate CCW 1/2 turn
44 | small_stepper.setSpeed(700); // 700 a good max speed??
45 | small_stepper.step(Steps2Take);
46 | delay(2000);
47 |
48 | }/* --(end main loop )-- */
49 |
50 | /* ( THE END ) */
51 |
52 |
53 | /*
54 | * original: https://arduino-info.wikispaces.com/SmallSteppers
55 | * text data bss dec hex filename
56 | 2470 0 37 2507 9cb /home/satan/github/arduino_modern/platform/platform_test/stepper.elf
57 | 0 0 0 0 0 /home/satan/github/arduino_modern/platform/platform_test/stepper.eep
58 | *
59 | */
60 |
--------------------------------------------------------------------------------
/test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | find_package(Boost)
3 | find_package(Boost COMPONENTS unit_test_framework timer system)
4 |
5 | add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})
6 | add_custom_target(tests)
7 |
8 | include_directories(${Boost_INCLUDE_DIR})
9 |
10 | set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -std=c++14)
11 |
12 | if (CI_BUILD)
13 | file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/test/reports)
14 | file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/test/valgrind_reports)
15 |
16 | add_custom_target(gcovr COMMAND gcovr --xml -e "/usr*" -e "${CMAKE_SOURCE_DIR}/test/*.cpp" -o test/coverage.xml WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
17 | add_dependencies(gcovr check)
18 | endif()
19 |
20 | function(add_boost_test name)
21 | #add_executable(${name} EXCLUDE_FROM_ALL ${ARGN})
22 | add_executable(${name} ${ARGN})
23 | target_link_libraries(${name} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
24 | ${Boost_TIMER_LIBRARY}
25 | ${Boost_SYSTEM_LIBRARY})
26 |
27 | if (CI_BUILD)
28 | add_test(${name} ./${name} --output_format=xml --log_level=all --report_level=no --log_sink=${CMAKE_BINARY_DIR}/test/reports/${name}.xml)
29 | else()
30 | add_test(${name} ./${name})
31 | endif()
32 |
33 | add_dependencies(check ${name})
34 | add_dependencies(tests ${name})
35 | endfunction()
36 |
37 | add_boost_test(mpl mpl.cpp)
38 |
39 | add_boost_test(arch arch.cpp)
40 | add_boost_test(configurator configurator.cpp)
41 | add_boost_test(initialize initialize.cpp)
42 | add_boost_test(driver driver.cpp)
43 | #add_boost_test(stepper stepper.cpp)
--------------------------------------------------------------------------------
/test/arch.cpp:
--------------------------------------------------------------------------------
1 | #define BOOST_TEST_DYN_LINK
2 | #define BOOST_TEST_MODULE arch
3 | #include
4 |
5 | #include "../include/avr/hardware/test/arch.hpp"
6 | #include "../include/mpl/integral_constant.hpp"
7 | #include "../include/avr/hardware/tags.hpp"
8 |
9 | #include "../include/avr/hardware/pin.hpp"
10 |
11 |
12 | BOOST_AUTO_TEST_CASE(pass) { }
13 |
14 | BOOST_AUTO_TEST_CASE(immediate_interface)
15 | {
16 | constexpr auto p1 = avr::hardware::pin(avr::hardware::test::P0, 1_c);
17 | constexpr auto p2 = avr::hardware::pin(avr::hardware::test::P0, 2_c);
18 |
19 | constexpr auto ops = avr::hardware::basic_ops{};
20 |
21 | ops.set_mode(p1, avr::hardware::pin_config::output);
22 | BOOST_CHECK_EQUAL(avr::hardware::test::P0.mode, 1);
23 |
24 | ops.set_mode(p2, avr::hardware::pin_config::output);
25 | BOOST_CHECK_EQUAL(avr::hardware::test::P0.mode, 3);
26 |
27 | ops.high(p1);
28 | BOOST_CHECK_EQUAL(avr::hardware::test::P0.output, 1);
29 |
30 | ops.set_mode(p1, avr::hardware::pin_config::input);
31 |
32 | BOOST_CHECK_EQUAL(avr::hardware::test::P0.mode, 2);
33 | BOOST_CHECK_EQUAL(avr::hardware::test::P0.output, 0);
34 |
35 | avr::hardware::test::P0.input = 5;
36 | BOOST_CHECK(ops.read(p1));
37 | }
38 |
39 | BOOST_AUTO_TEST_CASE(pin_registration)
40 | {
41 | // TODO: Something about the initial call should specify what kind of mask is expected.
42 | constexpr auto hardware =
43 | avr::hardware::arch_{}
44 | .register_pin(avr::pin1, avr::hardware::test::P0, 0)
45 | .register_pin(avr::pin2, avr::hardware::test::P0, 1)
46 | .register_pin(avr::pin3, avr::hardware::test::P1, 0)
47 | ;
48 |
49 | constexpr auto t0 = hardware.has_pin(avr::pin1);
50 | constexpr auto t1 = hardware.has_pin(avr::pin2);
51 | constexpr auto t2 = hardware.has_pin(avr::pin3);
52 | constexpr auto t3 = hardware.has_pin(avr::pin4);
53 |
54 | constexpr auto hardware2 = hardware.register_pin(avr::pin4, avr::hardware::test::P1, 1);
55 | constexpr auto t4 = hardware2.has_pin(avr::pin4);
56 |
57 | BOOST_CHECK(t0 && t1 && t2 && !t3 && t4);
58 | }
59 |
--------------------------------------------------------------------------------
/test/configurator.cpp:
--------------------------------------------------------------------------------
1 | #define BOOST_TEST_DYN_LINK
2 | #define BOOST_TEST_MODULE configurator
3 | #include
4 |
5 | #include "../include/avr/hardware/configurator.hpp"
6 | #include "../include/avr/hardware/test/arch.hpp"
7 | #include "../include/avr/pins.hpp"
8 | #include "../include/avr/hardware/tags.hpp"
9 |
10 | using namespace avr::hardware;
11 | using namespace avr::hardware::test;
12 | using namespace avr::hardware::pin_config;
13 |
14 | using namespace avr;
15 |
16 | constexpr auto test_platform =
17 | avr::hardware::arch_{}
18 | .register_pin(avr::pin1, avr::hardware::test::P0, 0)
19 | .register_pin(avr::pin2, avr::hardware::test::P0, 1)
20 | .register_pin(avr::pin3, avr::hardware::test::P1, 0)
21 | ;
22 |
23 |
24 | BOOST_AUTO_TEST_CASE(initial_state)
25 | {
26 | constexpr auto test_configurator = avr::hardware::describe_platform(test_platform);
27 |
28 | constexpr auto t0 = test_configurator.available(avr::pin1);
29 | constexpr auto t1 = test_configurator.available(avr::pin2);
30 | constexpr auto t2 = test_configurator.available(avr::pin3);
31 |
32 | BOOST_CHECK(t0 && t1 && t2);
33 | }
34 |
35 | #if 1
36 | BOOST_AUTO_TEST_CASE(configure_pins)
37 | {
38 | constexpr auto test_configurator = avr::hardware::describe_platform(test_platform);
39 |
40 | constexpr auto configured =
41 | test_configurator
42 | .set_mode(avr::pin1, avr::hardware::pin_config::input)
43 | .set_mode(avr::pin2, avr::hardware::pin_config::output)
44 | // uncomment next line to cause blowout.
45 | //.set_mode(avr::pin1, avr::hardware::pin_config::output) // TODO: devise a way for a better error message here.
46 | ;
47 |
48 | // pin availability:
49 | constexpr auto av0 = configured.available(avr::pin1);
50 | constexpr auto av1 = configured.available(avr::pin2);
51 | constexpr auto av2 = configured.available(avr::pin3);
52 |
53 | BOOST_CHECK(!av0 && !av1 && av2);
54 |
55 | // get modes:
56 | constexpr auto m0 = configured.mode(avr::pin1);
57 | constexpr auto m1 = configured.mode(avr::pin2);
58 |
59 | BOOST_CHECK(mpl::same_type(m0, avr::hardware::pin_config::input));
60 | BOOST_CHECK(mpl::same_type(m1, avr::hardware::pin_config::output));
61 |
62 | // uncomment to explode:
63 | //constexpr auto blow = configured.mode(avr::pin3);
64 | }
65 | #endif
66 |
67 | #if 0
68 | namespace {
69 |
70 | struct test_device
71 | {
72 | //template < typename Configurator >
73 | //static constexpr auto configure_pin(Configurator config)
74 | // -> decltype(config.set_mode(pin1, input).set_mode(pin2,output).set_mode(pin3,output))
75 | //{
76 | // return config.set_mode(pin1, input).set_mode(pin2,output).set_mode(pin3,output);
77 | //}
78 | constexpr test_device(){}
79 |
80 | template < typename Configurator >
81 | static constexpr auto configure(Configurator config)
82 | {
83 | return config.create_config(config.pins, config.devices.add(test_device{}))
84 | .set_mode(pin1,input).set_mode(pin2,output).set_mode(pin3,output);
85 | }
86 | };
87 |
88 |
89 | BOOST_AUTO_TEST_CASE(devices) // TODO: This should actually remove the pin entirely. Don't want it to give access later.
90 | {
91 | constexpr auto test_configurator = configurator, test_desc, test_desc>{};
92 |
93 | constexpr auto test0 = test_configurator.add_device(test_device{});
94 | //constexpr auto test0 = test_configurator;
95 |
96 | // assert that the device was added and pins set up to the appropriate mode.
97 | BOOST_CHECK(is_same(input, pin_mode(test0,pin1)));
98 | BOOST_CHECK(is_same(output, pin_mode(test0,pin2)));
99 | BOOST_CHECK(is_same(output, pin_mode(test0,pin3)));
100 |
101 | BOOST_CHECK(has_device(test0, test_device{}));
102 | }
103 | #endif
104 |
--------------------------------------------------------------------------------
/test/driver.cpp:
--------------------------------------------------------------------------------
1 | #define BOOST_TEST_DYN_LINK
2 | #define BOOST_TEST_MODULE driver
3 | #include
4 |
5 | #include "../include/avr/hardware/test/arch.hpp"
6 | #include "../include/avr/pins.hpp"
7 | #include "../include/avr/hardware/tags.hpp"
8 | #include "../include/avr/hardware/initialize.hpp"
9 |
10 | using namespace avr;
11 | using namespace avr::hardware;
12 | using namespace avr::hardware::test;
13 | using namespace avr::hardware::pin_config;
14 |
15 | BOOST_AUTO_TEST_CASE(pass) { }
16 |
17 |
18 | BOOST_AUTO_TEST_CASE(pin_io)
19 | {
20 | auto const driver = initialize(test_arch.set_mode(pin1,output)
21 | .set_mode(pin2,output)
22 | .set_mode(pin3,input));
23 |
24 | driver.high(pin1);
25 | BOOST_CHECK_EQUAL(0x01, P0.output);
26 | driver.high(pin2);
27 | BOOST_CHECK_EQUAL(0x03, P0.output);
28 | driver.low(pin1);
29 | BOOST_CHECK_EQUAL(0x02, P0.output);
30 |
31 | P1.input = 0x01;
32 | BOOST_CHECK(driver.read(pin3));
33 | }
34 |
35 | BOOST_AUTO_TEST_CASE(multi_pin)
36 | {
37 | auto const driver = initialize(test_arch.set_mode(pin1,output)
38 | .set_mode(pin2,output)
39 | .set_mode(pin3,output));
40 |
41 | P0.output = 0;
42 | P1.output = 0;
43 |
44 | driver.high(pin1, pin2, pin3);
45 | BOOST_CHECK_EQUAL(0x03, P0.output);
46 | BOOST_CHECK_EQUAL(0x01, P1.output);
47 |
48 | driver.low(pin1,pin3);
49 | BOOST_CHECK_EQUAL(0x02, P0.output);
50 | BOOST_CHECK_EQUAL(0x00, P1.output);
51 |
52 | driver.toggle(pin1,pin2);
53 | BOOST_CHECK_EQUAL(0x01, P0.output);
54 | }
55 |
--------------------------------------------------------------------------------
/test/initialize.cpp:
--------------------------------------------------------------------------------
1 | #define BOOST_TEST_DYN_LINK
2 | #define BOOST_TEST_MODULE configurator
3 | #include
4 |
5 |
6 | #include "../include/avr/hardware/configurator.hpp"
7 | #include "../include/avr/hardware/test/arch.hpp"
8 | #include "../include/avr/pins.hpp"
9 | #include "../include/avr/hardware/tags.hpp"
10 | #include "../include/avr/hardware/initialize.hpp"
11 |
12 | using namespace avr::hardware;
13 | using namespace avr::hardware::test;
14 | using namespace avr::hardware::pin_config;
15 |
16 | using namespace avr;
17 |
18 | BOOST_AUTO_TEST_CASE(initializes)
19 | {
20 | auto const driver = initialize(test_arch.set_mode(pin1,input)
21 | .set_mode(pin2,output)
22 | .set_mode(pin3,input));
23 |
24 | BOOST_CHECK_EQUAL(0x02, P0.mode);
25 | BOOST_CHECK_EQUAL(0x00, P1.mode);
26 | }
27 |
--------------------------------------------------------------------------------
/test/mpl.cpp:
--------------------------------------------------------------------------------
1 | #define BOOST_TEST_DYN_LINK
2 | #define BOOST_TEST_MODULE mpl
3 | #include
4 |
5 | #include "../include/mpl/util.hpp"
6 | #include "../include/mpl/collection.hpp"
7 | #include "../include/mpl/integral_constant.hpp"
8 |
9 | namespace {
10 |
11 | template < int I > struct key { constexpr key(){} };
12 |
13 | }
14 |
15 | BOOST_AUTO_TEST_CASE(same_type)
16 | {
17 | constexpr auto t0 = mpl::same_type(0,1);
18 | constexpr auto t1 = mpl::same_type(0,1.);
19 |
20 | BOOST_CHECK(t0);
21 | BOOST_CHECK(!t1);
22 | }
23 |
24 | BOOST_AUTO_TEST_CASE(integral)
25 | {
26 | BOOST_CHECK_EQUAL(5, (mpl::detail_::create_constant::value()));
27 |
28 | constexpr auto val = 5_c;
29 | BOOST_CHECK_EQUAL(5, val.value());
30 | }
31 |
32 |
33 | namespace {
34 |
35 | template < typename End >
36 | constexpr int count(End,End) { return 0; }
37 |
38 | template < typename Beg, typename End >
39 | constexpr int count(Beg iter, End end)
40 | {
41 | return 1 + count(iter.next(), end);
42 | }
43 |
44 | }
45 |
46 | BOOST_AUTO_TEST_CASE(lookup_collection)
47 | {
48 | constexpr auto test_collection = mpl::lookup_collection{};
49 | constexpr auto t0 = test_collection.insert(key<0>{}, 5_c).insert(key<1>{}, 666_c);
50 | constexpr auto t1 = t0.get(key<0>{});
51 | constexpr auto t2 = t0.get(key<1>{});
52 | constexpr auto t3 = count(t0.begin(), t0.end());
53 |
54 | constexpr auto t4 = t0.insert(key<0>{}, 9_c);
55 |
56 | static_assert(t0.has(key<0>{}),"");
57 | static_assert(t0.has(key<1>{}),"");
58 | static_assert(!t0.has(key<2>{}),"");
59 |
60 | //BOOST_CHECK_EQUAL(t3, 2);
61 |
62 | BOOST_CHECK_EQUAL(t4.get(key<0>{}).value(), 9);
63 |
64 | BOOST_CHECK_EQUAL(t1.value(), 5);
65 | BOOST_CHECK_EQUAL(t2.value(), 666);
66 |
67 |
68 | constexpr auto test_collection2 = t0.remove(key<0>{});
69 | BOOST_CHECK(!test_collection.has(key<0>{}));
70 |
71 | // uncomment to explode...
72 | //constexpr auto blow = test_collection2[key<0>{}];
73 | }
74 |
75 | BOOST_AUTO_TEST_CASE(collection)
76 | {
77 | constexpr auto test_collection = mpl::collection{};
78 | constexpr auto t0 = test_collection.append(1_c);
79 | constexpr auto t1 = t0.append(2_c);
80 |
81 | BOOST_CHECK_EQUAL(t1.get(0_c).value(), 1);
82 | BOOST_CHECK_EQUAL(t1.get(1_c).value(), 2);
83 |
84 | BOOST_CHECK_EQUAL(count(t1.begin(), t1.end()), 2);
85 | }
86 |
--------------------------------------------------------------------------------
/test/pins.cpp:
--------------------------------------------------------------------------------
1 | #define BOOST_TEST_DYN_LINK
2 | #define BOOST_TEST_MODULE pins
3 | #include
4 |
5 | BOOST_AUTO_TEST_CASE(empty) {}
6 |
--------------------------------------------------------------------------------
/test/stepper.cpp:
--------------------------------------------------------------------------------
1 | #define BOOST_TEST_DYN_LINK
2 | #define BOOST_TEST_MODULE pins
3 | #include
4 |
5 | #include "../include/avr/stepper.hpp"
6 | #include "../include/avr/hardware/test/arch.hpp"
7 | #include "../include/avr/pins.hpp"
8 | #include "../include/avr/hardware/initialize.hpp"
9 |
10 |
11 | namespace {
12 |
13 | // ensure that these things work in constexpr functions...
14 | //constexpr avr::steps steps(avr::stepper_motor motor) { return avr::steps{}; }
15 |
16 | template < int I >
17 | struct blah { enum { value = I };};
18 | }
19 |
20 |
21 | BOOST_AUTO_TEST_CASE(empty) { }
22 |
23 | BOOST_AUTO_TEST_CASE(initial_config) // What you'll provide for a particular motor
24 | {
25 | constexpr auto test_stepper = avr::stepper(avr::steps{2048}, avr::phases{4});
26 | constexpr auto test_steps = blah::value;
27 | constexpr auto test_phases = blah::value;
28 |
29 | BOOST_CHECK_EQUAL(test_steps, 2048);
30 | BOOST_CHECK_EQUAL(test_phases, 4);
31 | }
32 |
33 | BOOST_AUTO_TEST_CASE(motor_config)
34 | {
35 |
36 | }
37 |
38 | BOOST_AUTO_TEST_CASE(motor_init)
39 | {
40 | }
41 |
42 | BOOST_AUTO_TEST_CASE(motor_driver)
43 | {
44 | }
45 |
--------------------------------------------------------------------------------