/* * SPDX-License-Identifier: MIT * * C++ example: the example tree driving a simulated board through orchard.hpp, * with the leaves as member functions of a class. * * orchard_cpp_demo [tree.json] load the tree from a file * orchard_cpp_demo --code use the same tree, built by the compiler * * Instead of reading the keyboard, it plays a fixed timeline of button presses * on a simulated clock, so a run takes no time and always prints the same * thing. Each line is a button event or a change of the LEDs. */ #include #include #include #include #include #include #include #include namespace { constexpr uint32_t tick_ms = 10; /* Simulated time. The clock passed to the tree is a plain function, so it reads a global */ orchard_time_t sim_now_ms = 0; orchard_time_t sim_clock() { return sim_now_ms; } class Board { public: /* * The leaves. arg comes from the tree file, not from the compiler, so * at() checks it: a bad index throws, and orchard::member_leaf turns * that into FAILURE. */ orchard_status button(int32_t arg, uint32_t *) { return buttons_.at(index(arg)) ? ORCHARD_SUCCESS : ORCHARD_FAILURE; } orchard_status led_on(int32_t arg, uint32_t *) { return set_led(arg, true); } orchard_status led_off(int32_t arg, uint32_t *) { return set_led(arg, false); } orchard_status led_toggle(int32_t arg, uint32_t *) { return set_led(arg, !leds_.at(index(arg))); } void press(std::size_t id, bool pressed) { buttons_.at(id) = pressed; } /* Print the LEDs if they changed since the last call */ void show_leds(orchard_time_t now) { if (leds_ == shown_) { return; } shown_ = leds_; std::printf("%6lu ms leds ", static_cast(now)); for (bool on : leds_) { std::putchar(on ? '*' : '.'); } std::putchar('\n'); } private: static std::size_t index(int32_t arg) { if (arg < 0) { throw std::out_of_range("negative index"); } return static_cast(arg); } orchard_status set_led(int32_t arg, bool on) { leds_.at(index(arg)) = on; return ORCHARD_SUCCESS; } std::array buttons_{}; std::array leds_{}; std::array shown_{{true, true, true, true, true}}; /* force a first print */ }; /* The Board is the tree's user pointer; member_leaf calls the method on it */ constexpr orchard_leaf_def leaves[] = { {"button", orchard::member_leaf}, {"led_on", orchard::member_leaf}, {"led_off", orchard::member_leaf}, {"led_toggle", orchard::member_leaf}, }; /* * The tree of tree.json, for --code. The compiler checks it and lays it out: * a misspelled leaf name or a negative wait is a build error, and loading it * cannot fail. */ using namespace orchard; constexpr auto example_tree = compile( leaves, reactive_fallback( /* Hold button 0: LED 1 blinks fast */ reactive_sequence(condition("button", 0), sequence(action("led_on", 1), wait(100), action("led_off", 1), wait(100))), /* Hold button 1 (but not button 2): LEDs 2 and 3 on */ reactive_sequence(condition("button", 1), invert(condition("button", 2)), action("led_on", 2), action("led_on", 3)), /* Idle: clear the outputs, heartbeat on LED 0 */ sequence(action("led_off", 1), action("led_off", 2), action("led_off", 3), action("led_on", 0), wait(500), action("led_off", 0), wait(500)))); struct Event { uint32_t at_ms; std::size_t button; bool pressed; }; /* Each branch of the tree in turn: blink, LEDs 2 and 3, blocked by button 2, idle */ const Event timeline[] = { {1200, 0, true}, {1700, 0, false}, {2200, 1, true}, {2600, 2, true}, {2900, 1, false}, {2900, 2, false}, }; constexpr uint32_t end_ms = 3500; Board board; Tree<64> tree(leaves, &board, sim_clock); char file_buf[4096]; } // namespace int main(int argc, char **argv) { const char *path = (argc > 1) ? argv[1] : "examples/posix/tree.json"; orchard::set_exception_handler( [](const char *what) { std::fprintf(stderr, "leaf failed: %s\n", what); }); if (std::strcmp(path, "--code") == 0) { tree.load(example_tree); path = "the tree built by the compiler"; } else { orchard_json_error err; int rc = tree.load_json_file(path, file_buf, &err); if (rc != 0) { std::fprintf(stderr, "%s:%u:%u: %s (%d)\n", path, err.line, err.col, err.msg, rc); return EXIT_FAILURE; } } std::printf("loaded %s: %zu/%zu nodes\n", path, tree.node_count(), tree.capacity()); const Event *next = timeline; const Event *const last = timeline + sizeof(timeline) / sizeof(timeline[0]); for (sim_now_ms = 0; sim_now_ms <= end_ms; sim_now_ms += tick_ms) { for (; next != last && next->at_ms <= sim_now_ms; ++next) { board.press(next->button, next->pressed); std::printf("%6lu ms button %zu %s\n", static_cast(sim_now_ms), next->button, next->pressed ? "pressed" : "released"); } tree.tick(); board.show_leds(sim_now_ms); } std::printf("\ntree after the last tick:\n"); orchard_print(tree.get(), [](void *, const char *line) { std::puts(line); }, nullptr); return EXIT_SUCCESS; }