123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- // SPDX-License-Identifier: MIT
- // SPDX-FileCopyrightText: 2022 Ivan Baidakou
- #include "common.h"
- #include "rotor-light.hpp"
- #include <avr/interrupt.h>
- #include <avr/io.h>
- #include <avr/sleep.h>
- #include <avr/wdt.h>
- #include <string.h>
- #include <util/delay.h>
- #define LED PB5
- namespace rl = rotor_light;
- namespace message {
- struct ChangeInterval : rl::Message {
- static constexpr auto type_id = __LINE__;
- ChangeInterval(rl::ActorId to, const rl::Duration &delta_)
- : Message{to}, delta{delta_} {}
- rl::MessageTypeId get_type_id() const override { return type_id; }
- rl::Duration delta;
- };
- struct Notify : rl::Message {
- static constexpr auto type_id = __LINE__;
- Notify(rl::ActorId to, const char *data_) : Message(to), data{data_} {}
- rl::MessageTypeId get_type_id() const override { return type_id; }
- const char *data;
- };
- } // namespace message
- struct Blinker : rl::Actor<2> {
- using Parent = Actor<2>;
- void initialize() override {
- next_event = 0;
- subscribe(&Blinker::on_change_interval);
- Parent::initialize();
- }
- void advance_start() override {
- Parent::advance_start();
- next_event = add_event(
- delay, [](void *data) { static_cast<Blinker *>(data)->blink(); }, this);
- }
- void blink() {
- if (next_event) {
- supervisor->get_planner()->remove_event(next_event, this);
- }
- PORTB ^= (1 << LED);
- send<message::Notify>(0, notifier_id, "blink\r\n");
- next_event = add_event(
- delay, [](void *data) { static_cast<Blinker *>(data)->blink(); }, this);
- }
- void on_change_interval(message::ChangeInterval &msg) {
- if (delay > msg.delta) {
- send<message::Notify>(0, notifier_id, "dec\r\n");
- } else {
- send<message::Notify>(0, notifier_id, "inc\r\n");
- }
- delay = msg.delta;
- blink();
- }
- rl::ActorId notifier_id;
- rl::Duration delay;
- rl::TimePoint next_event;
- };
- struct Notifier : rl::Actor<2> {
- using Parent = Actor<2>;
- void initialize() override {
- ptr = end = nullptr;
- subscribe(&Notifier::on_notify);
- Parent::initialize();
- }
- void advance_start() override {
- Parent::advance_start();
- send<message::Notify>(0, id, "Ready\n");
- }
- void on_notify(message::Notify &message) {
- if (!ptr) { // prevent overloading
- cli();
- ptr = message.data;
- end = message.data + strlen(message.data);
- send_next();
- sei();
- }
- }
- void send_next() {
- if (end) {
- if (ptr == end) {
- ptr = nullptr;
- end = nullptr;
- } else {
- // enable empty data buffer interrupt
- UCSR0B |= (1 << UDRIE0);
- while (!(UCSR0A & (1 << UDRE0)))
- ;
- // if (!(UCSR0A & (1<<UDRE0))) {
- UDR0 = *ptr++;
- //}
- }
- }
- }
- volatile const char *ptr;
- const char *end;
- };
- static void app_hw_init();
- using Supervisor =
- rl::Supervisor<rl::SupervisorBase::min_handlers_amount, Blinker, Notifier>;
- using Storage =
- rl::traits::MessageStorage<rl::message::ChangeState,
- rl::message::ChangeStateAck,
- message::ChangeInterval, message::Notify>;
- using Queue = rl::Queue<Storage, 5>; /* upto 5 messages in 1 queue */
- using Planner = rl::Planner<2>; /* upto 2 time events */
- Queue queue;
- Planner planner;
- rl::Context context{&queue, &planner, &get_now};
- Supervisor sup;
- int main(int, char **) {
- app_hw_init();
- /* setup */
- sup.bind(context);
- auto blinker = sup.get_child<0>();
- blinker->delay = rl::Duration{1000000};
- blinker->notifier_id = sup.get_child<1>()->get_id();
- /* let it polls timer */
- sup.start(true);
- /* main cycle */
- sup.process();
- return 0;
- }
- static void app_hw_init() {
- // Initialize the application including WDT, PORTB.5 and TIMER0
- // We will now disable the watchdog.
- // Service the watchdog just to be sure to avoid pending timeout.
- wdt_reset();
- // Clear WDRF in MCUSR.
- MCUSR &= ~(1U << WDRF);
- // Write logical one to WDCE and WDE.
- // Keep the old prescaler setting to prevent unintentional time-out.
- WDTCSR |= (1U << WDCE) | (1U << WDE);
- // Turn off the WDT.
- WDTCSR = 0x00;
- // We will now initialize PORTB.5 to be used as an LED driver port.
- // Set PORTB.5 value to low.
- PORTB &= ~(1U << PORTB5);
- /* initializing PB5 which is connected to port 13 of uno as output*/
- DDRB |= (1 << LED);
- enable_timer();
- // USART
- #define BAUD 9600
- #include <util/setbaud.h>
- UBRR0H = UBRRH_VALUE;
- UBRR0L = UBRRL_VALUE;
- UCSR0B = (1 << RXEN0) // enable rx
- | (1 << TXEN0) // enable tx
- | (1 << RXCIE0) // enable rx interrupt
- ;
- /* Set frame format: 8data, 2stop bit */
- UCSR0C = (1 << USBS0) | (3 << UCSZ00);
- // Enable all interrupts.
- sei();
- }
- ISR(USART_RX_vect) {
- if (UCSR0A & (1 << RXC0)) {
- auto c = static_cast<char>(UDR0);
- auto blinker = sup.get_child<0>();
- const auto &value = blinker->delay;
- if (c == '+') {
- auto new_value = value + value / 10;
- blinker->send<message::ChangeInterval>(0, blinker->get_id(), new_value);
- } else if (c == '-') {
- auto new_value = value - value / 10;
- blinker->send<message::ChangeInterval>(0, blinker->get_id(), new_value);
- }
- }
- }
- ISR(USART_UDRE_vect) {
- // disable empty data buffer interrupt
- UCSR0B &= ~(1 << UDRIE0);
- auto notifier = sup.get_child<1>();
- notifier->send_next();
- }
|