Skip to content

[amnb] Adapt for using Resumbles in fiber mode #1216

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions examples/nucleo_g071rb/amnb/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,12 @@ main()

while (true)
{
node1.update();
node2.update();
node3.update();
node1.update_transmit();
node1.update_receive();
node2.update_transmit();
node2.update_receive();
node3.update_transmit();
node3.update_receive();
thread.update();
}

Expand Down
166 changes: 166 additions & 0 deletions examples/nucleo_g071rb/amnb_fiber/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
* Copyright (c) 2019, Niklas Hauser
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include <modm/board.hpp>
#include <modm/communication/amnb.hpp>
#include <modm/processing.hpp>

using namespace Board;
using namespace std::chrono_literals;
using namespace modm::amnb;
using Usart1 = BufferedUart<UsartHal1, UartRxBuffer<32>>;
using Usart3 = BufferedUart<UsartHal3, UartRxBuffer<16>>;
using Usart4 = BufferedUart<UsartHal4>;
// ----------------------------------------------------------------------------

Listener listeners[] =
{
{1, [](uint8_t sender, const uint32_t& data)
{
MODM_LOG_INFO << "Node2 and Node3 received Broadcast 1 from '" << sender;
MODM_LOG_INFO << "': " << data << modm::endl;
}
},
{2, [](uint8_t sender)
{
MODM_LOG_INFO << "Node2 and Node3 received Broadcast 2 from '" << sender << "'" << modm::endl;
}
},
};
Action actions[] =
{
{1, []() -> Response
{
static uint8_t counter{0};
MODM_LOG_INFO << "Node1 or Node3 received Action 1" << modm::endl;
return counter++;
}
},
{2, [](const uint32_t& data) -> Response
{
static uint8_t counter{0};
MODM_LOG_INFO << "Node1 or Node3 received Action 2 with argument: " << data << modm::endl;
return ErrorResponse(counter++);
}
},
};

// Two nodes on the same device on different UARTs of course!
DeviceWrapper<Usart1> device1;
DeviceWrapper<Usart3> device2;
DeviceWrapper<Usart4> device3;
Node node1(device1, 1, actions);
Node node2(device2, 2, listeners);
Node node3(device3, 3, actions, listeners);

modm::Fiber fiberNode1t([]{ node1.update_transmit(); });
modm::Fiber fiberNode1r([]{ node1.update_receive(); });
modm::Fiber fiberNode2t([]{ node2.update_transmit(); });
modm::Fiber fiberNode2r([]{ node2.update_receive(); });
modm::Fiber fiberNode3t([]{ node3.update_transmit(); });
modm::Fiber fiberNode3r([]{ node3.update_receive(); });

// You need to connect D1 with D15 and with A0
using PinNode1 = GpioC4; // D1
using PinNode2 = GpioB8; // D15
using PinNode3 = GpioA0; // A0

class Thread : public modm::pt::Protothread
{
modm::ShortPeriodicTimer tmr{1s};
uint32_t counter{0};
Result<uint8_t> res1;
Result<uint8_t, uint8_t> res2;

public:
bool inline
update()
{
PT_BEGIN();

while(true)
{
PT_WAIT_UNTIL(tmr.execute());

node1.broadcast(1, counter++);
node3.broadcast(2);

res1 = PT_CALL(node2.request<uint8_t>(1, 1));
MODM_LOG_INFO << "Node1 responded with: " << res1.error();
if (res1) { MODM_LOG_INFO << " " << *res1 << modm::endl; }

res2 = PT_CALL(node1.request<uint8_t, uint8_t>(3, 2, counter));
MODM_LOG_INFO << "Node3 responded with: " << res2.error();
if (res2.hasUserError()) {
MODM_LOG_INFO << " " << *res2.userError() << modm::endl;
}

if (counter % 10 == 0)
{
MODM_LOG_INFO << "Node1t stack=" << fiberNode1t.stack_usage() << "\nNode1r stack=" << fiberNode1r.stack_usage() << modm::endl;
MODM_LOG_INFO << "Node2t stack=" << fiberNode2t.stack_usage() << "\nNode2r stack=" << fiberNode2r.stack_usage() << modm::endl;
MODM_LOG_INFO << "Node3t stack=" << fiberNode3t.stack_usage() << "\nNode3r stack=" << fiberNode3r.stack_usage() << modm::endl;
MODM_LOG_INFO << "Thread stack=" << this->stack_usage() << modm::endl;
}
}

PT_END();
}
}
thread;



// ----------------------------------------------------------------------------
int
main()
{
Board::initialize();
LedD13::setOutput();

Usart1::connect<PinNode1::Tx>();
Usart1::initialize<SystemClock, 115200>(Usart1::Parity::Even, Usart1::WordLength::Bit9);
// Use Single-Wire Half-Duplex Mode
PinNode1::configure(Gpio::OutputType::OpenDrain);
PinNode1::configure(Gpio::InputType::PullUp);
USART1->CR1 &= ~USART_CR1_UE;
USART1->CR3 = USART_CR3_HDSEL;
USART1->CR1 |= USART_CR1_UE;

Usart3::connect<PinNode2::Tx>();
Usart3::initialize<SystemClock, 115200>(Usart1::Parity::Even, Usart1::WordLength::Bit9);
// Use Single-Wire Half-Duplex Mode
PinNode2::configure(Gpio::OutputType::OpenDrain);
PinNode2::configure(Gpio::InputType::PullUp);
USART3->CR1 &= ~USART_CR1_UE;
USART3->CR3 = USART_CR3_HDSEL;
USART3->CR1 |= USART_CR1_UE;

Usart4::connect<PinNode3::Tx>();
Usart4::initialize<SystemClock, 115200>(Usart1::Parity::Even, Usart1::WordLength::Bit9);
// Use Single-Wire Half-Duplex Mode
PinNode3::configure(Gpio::OutputType::OpenDrain);
PinNode3::configure(Gpio::InputType::PullUp);
USART4->CR1 &= ~USART_CR1_UE;
USART4->CR3 = USART_CR3_HDSEL;
USART4->CR1 |= USART_CR1_UE;

fiberNode1t.watermark_stack();
fiberNode1r.watermark_stack();
fiberNode2t.watermark_stack();
fiberNode2r.watermark_stack();
fiberNode3t.watermark_stack();
fiberNode3r.watermark_stack();
thread.watermark_stack();

modm::fiber::Scheduler::run();

return 0;
}
18 changes: 18 additions & 0 deletions examples/nucleo_g071rb/amnb_fiber/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<library>
<extends>modm:nucleo-g071rb</extends>
<options>
<option name="modm:build:build.path">../../../build/nucleo_g071rb/amnb_fiber</option>
<option name="modm:communication:amnb:with_heap">no</option>
<option name="modm:processing:protothread:use_fiber">yes</option>
</options>
<modules>
<module>modm:platform:gpio</module>
<module>modm:communication:amnb</module>
<module>modm:platform:uart:1</module>
<module>modm:platform:uart:3</module>
<module>modm:platform:uart:4</module>
<module>modm:build:scons</module>
<module>modm:processing:protothread</module>
<module>modm:processing:fiber</module>
</modules>
</library>
9 changes: 7 additions & 2 deletions src/modm/communication/amnb/module.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,16 @@ else if (response.hasUserError())
else Error error = response.error();


/// node.update() must be called as often as possible!
/// node.update_{transmit, receive}() must be called as often as possible!
while(true)
{
node.update();
node.update_transmit();
node.update_receive();
}

// Alternatively you require one fiber per update function
modm::Fiber<> fiberNodeTransmit([]{ node.update_transmit(); });
modm::Fiber<> fiberNodeReceive([]{ node.update_receive(); });
```


Expand Down
57 changes: 25 additions & 32 deletions src/modm/communication/amnb/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,16 +125,8 @@ class Node : public modm::Resumable<6>
}

public:
void
update()
{
transmit();
receive();
}

protected:
modm::ResumableResult<void>
transmit()
update_transmit()
{
RF_BEGIN(2);
while(1)
Expand All @@ -150,6 +142,30 @@ class Node : public modm::Resumable<6>
RF_END();
}

modm::ResumableResult<void>
update_receive()
{
RF_BEGIN(5);
while(1)
{
rx_msg.deallocate(); // deallocates previous message
if (RF_CALL(interface.receiveHeader(&rx_msg)) == InterfaceStatus::Ok)
{
// Check lists if we are interested in this message
is_rx_msg_for_us = handleRxMessage(false);
// Receive the message data, only allocate if it's for us
if (RF_CALL(interface.receiveData(&rx_msg, is_rx_msg_for_us)) == InterfaceStatus::Ok)
{
// Only handle message *with* data if it's for us
if (is_rx_msg_for_us) handleRxMessage(true);
}
}
RF_YIELD();
}
RF_END();
}

protected:
modm::ResumableResult<void>
send(Message &msg)
{
Expand Down Expand Up @@ -200,29 +216,6 @@ class Node : public modm::Resumable<6>
RF_END();
}

modm::ResumableResult<void>
receive()
{
RF_BEGIN(5);
while(1)
{
rx_msg.deallocate(); // deallocates previous message
if (RF_CALL(interface.receiveHeader(&rx_msg)) == InterfaceStatus::Ok)
{
// Check lists if we are interested in this message
is_rx_msg_for_us = handleRxMessage(false);
// Receive the message data, only allocate if it's for us
if (RF_CALL(interface.receiveData(&rx_msg, is_rx_msg_for_us)) == InterfaceStatus::Ok)
{
// Only handle message *with* data if it's for us
if (is_rx_msg_for_us) handleRxMessage(true);
}
}
RF_YIELD();
}
RF_END();
}

protected:
bool
handleRxMessage(bool complete)
Expand Down
14 changes: 14 additions & 0 deletions src/modm/processing/fiber/mutex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@
#include <atomic>
#include <mutex>

/// @cond
namespace modm
{
template< uint8_t Functions > class Resumable;
template< uint8_t Levels > class NestedResumable;
}
/// @endcond

namespace modm::fiber
{

Expand All @@ -32,6 +40,9 @@ namespace modm::fiber
/// @see https://en.cppreference.com/w/cpp/thread/mutex
class mutex
{
template< uint8_t Functions > friend class ::modm::Resumable;
template< uint8_t Levels > friend class ::modm::NestedResumable;

mutex(const mutex&) = delete;
mutex& operator=(const mutex&) = delete;

Expand Down Expand Up @@ -87,6 +98,9 @@ class timed_mutex : public mutex
/// @see https://en.cppreference.com/w/cpp/thread/recursive_mutex
class recursive_mutex
{
template< uint8_t Functions > friend class ::modm::Resumable;
template< uint8_t Levels > friend class ::modm::NestedResumable;

recursive_mutex(const recursive_mutex&) = delete;
recursive_mutex& operator=(const recursive_mutex&) = delete;
using count_t = uint16_t;
Expand Down
Loading
Loading