From 24d73eb14bdc67cd20ee10ec2b5948206d60000a Mon Sep 17 00:00:00 2001 From: Jochen Wilhelmy Date: Sun, 18 Dec 2022 00:23:49 +0100 Subject: [PATCH 1/5] Implement BusNode driver and improve other drivers --- software/CMakeLists.txt | 6 + software/board/None/boardConfig.hpp | 6 + software/board/emuControl/boardConfig.hpp | 19 +- software/board/emuSwitch/boardConfig.hpp | 15 + software/board/nrf52Dongle/boardConfig.hpp | 30 +- software/board/switch/boardConfig.hpp | 60 ++- software/board/switch/link.ld | 2 +- software/control/src/BusInterface.cpp | 5 +- software/control/src/RoomControl.cpp | 2 +- software/control/src/SSD1309.cpp | 34 +- software/control/src/SSD1309.hpp | 11 +- software/control/src/SwapChain.hpp | 2 +- software/control/test/SSD1309Test.cpp | 4 +- software/protocol/src/crc.cpp | 31 +- software/protocol/src/crc.hpp | 9 + software/protocol/test/protocolTest.cpp | 43 +- software/switch/src/main.cpp | 9 +- software/system/src/BusMaster.hpp | 42 +- software/system/src/BusNode.hpp | 10 +- software/system/src/FlashStorage.cpp | 13 +- software/system/src/SpiMaster.hpp | 34 +- software/system/src/Timer.hpp | 6 +- software/system/src/emu/BusMasterImpl.cpp | 4 +- software/system/src/emu/BusNodeImpl.cpp | 12 +- software/system/src/emu/SpiSSD1309.cpp | 115 +++-- software/system/src/emu/SpiSSD1309.hpp | 25 +- software/system/src/nrf52/BusMasterImpl.cpp | 454 ++++++++++++------ software/system/src/nrf52/BusMasterImpl.hpp | 79 ++- software/system/src/nrf52/FlashImpl.cpp | 12 +- software/system/src/nrf52/FlashImpl.hpp | 3 + software/system/src/nrf52/Radio.cpp | 8 +- software/system/src/nrf52/SpiMasterImpl.cpp | 29 +- software/system/src/nrf52/SpiMasterImpl.hpp | 21 +- software/system/src/nrf52/nrf52.hpp | 5 +- software/system/src/stm32f0/BusNodeImpl.cpp | 313 +++++++++++- software/system/src/stm32f0/BusNodeImpl.hpp | 63 ++- software/system/src/stm32f0/FlashImpl.cpp | 16 +- software/system/src/stm32f0/FlashImpl.hpp | 4 +- software/system/src/stm32f0/SpiMasterImpl.cpp | 206 +++++--- software/system/src/stm32f0/SpiMasterImpl.hpp | 11 +- .../system/src/stm32f0/SpiMasterSingle16.cpp | 166 +++++++ .../system/src/stm32f0/SpiMasterSingle16.hpp | 37 ++ software/system/src/stm32f0/defs.hpp | 5 + software/system/src/stm32f0/gpio.hpp | 14 +- .../system/src/stm32f0/system/stm32f042x6.h | 362 +++++++------- software/system/test/BusMasterTest.cpp | 4 +- software/system/test/BusNodeTest.cpp | 34 ++ software/system/test/FlashTest.cpp | 24 +- software/system/test/InputTest.cpp | 2 +- software/system/test/SpiMasterTest.cpp | 28 +- software/system/test/StorageTest.cpp | 36 +- 51 files changed, 1853 insertions(+), 632 deletions(-) create mode 100644 software/system/src/stm32f0/SpiMasterSingle16.cpp create mode 100644 software/system/src/stm32f0/SpiMasterSingle16.hpp create mode 100644 software/system/test/BusNodeTest.cpp diff --git a/software/CMakeLists.txt b/software/CMakeLists.txt index 1647df5..c3c8b5f 100644 --- a/software/CMakeLists.txt +++ b/software/CMakeLists.txt @@ -310,6 +310,8 @@ if(EMU) set(SPI_MASTER system/src/SpiMaster.hpp system/src/SpiMaster.cpp + system/src/posix/SpiMasterImpl.hpp + system/src/posix/SpiMasterImpl.cpp system/src/emu/SpiBME680.hpp system/src/emu/SpiBME680.cpp system/src/emu/SpiMPQ6526.hpp @@ -385,6 +387,7 @@ if("stm32f0" IN_LIST PLATFORM) system/src/stm32f0/Loop.hpp system/src/stm32f0/Loop.cpp system/src/stm32f0/system/startup_stm32f042x6.s + #system/src/stm32f0/system/startup_stm32f051x8.s ) set(OUTPUT system/src/Output.hpp system/src/stm32f0/Output.cpp system/src/Debug.hpp) set(SPI_MASTER @@ -392,6 +395,8 @@ if("stm32f0" IN_LIST PLATFORM) system/src/SpiMaster.cpp system/src/stm32f0/SpiMasterImpl.hpp system/src/stm32f0/SpiMasterImpl.cpp + #system/src/stm32f0/SpiMasterSingle16.hpp + #system/src/stm32f0/SpiMasterSingle16.cpp ) set(STORAGE system/src/Storage.hpp @@ -664,6 +669,7 @@ endfunction() add_system_test_executable(Ble) add_system_test_executable(BusMaster) +add_system_test_executable(BusNode) add_system_test_executable(Calendar) add_system_test_executable(Flash) add_system_test_executable(Input) diff --git a/software/board/None/boardConfig.hpp b/software/board/None/boardConfig.hpp index db2d5bd..96b1aac 100644 --- a/software/board/None/boardConfig.hpp +++ b/software/board/None/boardConfig.hpp @@ -33,6 +33,12 @@ struct Drivers { FlashStorage storage{flash}; }; +struct DriversSpiMasterTest { + SpiMasterImpl transfer{"transfer"}; + SpiMasterImpl command{"command"}; + SpiMasterImpl data{"data"}; +}; + struct DriversFlashTest { FlashImpl flash{"flashTest.bin", 2, 4096, 4}; }; diff --git a/software/board/emuControl/boardConfig.hpp b/software/board/emuControl/boardConfig.hpp index a29fb62..705f9d6 100644 --- a/software/board/emuControl/boardConfig.hpp +++ b/software/board/emuControl/boardConfig.hpp @@ -1,10 +1,12 @@ #pragma once #include +#include #include #include #include #include +#include #include #include #include @@ -60,7 +62,8 @@ constexpr int DISPLAY_HEIGHT = 64; struct Drivers { SpiBME680 airSensor; - SpiSSD1309 display{DISPLAY_WIDTH, DISPLAY_HEIGHT}; + SpiSSD1309 displayCommand{DISPLAY_WIDTH, DISPLAY_HEIGHT}; + SpiSSD1309::Data displayData{displayCommand}; QuadratureDecoderImpl quadratureDecoder; BusMasterImpl busMaster; @@ -74,6 +77,20 @@ struct Drivers { FeRamStorage4 counters{feRam}; }; +struct DriversSpiMasterTest { + SpiMasterImpl transfer{"transfer"}; + SpiMasterImpl command{"command"}; + SpiMasterImpl data{"data"}; +}; + +struct DriversBusMasterTest { + BusMasterImpl busMaster; +}; + +struct DriversBusNodeTest { + BusNodeImpl busNode; +}; + struct DriversFlashTest { FlashImpl flash{"flashTest.bin", 2, 4096, 4}; }; diff --git a/software/board/emuSwitch/boardConfig.hpp b/software/board/emuSwitch/boardConfig.hpp index 1faa194..4300361 100644 --- a/software/board/emuSwitch/boardConfig.hpp +++ b/software/board/emuSwitch/boardConfig.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,20 @@ struct SwitchDrivers { StorageImpl counters{"switchCounters.bin", 0xff, 4}; }; +struct DriversSpiMasterTest { + SpiMasterImpl transfer{"transfer"}; + SpiMasterImpl command{"command"}; + SpiMasterImpl data{"data"}; +}; + +struct DriversBusMasterTest { + BusMasterImpl busMaster; +}; + +struct DriversBusNodeTest { + BusNodeImpl busNode; +}; + struct DriversFlashTest { FlashImpl flash{"flashTest.bin", 2, 1024, 4}; }; diff --git a/software/board/nrf52Dongle/boardConfig.hpp b/software/board/nrf52Dongle/boardConfig.hpp index 92d4692..112de2a 100644 --- a/software/board/nrf52Dongle/boardConfig.hpp +++ b/software/board/nrf52Dongle/boardConfig.hpp @@ -74,20 +74,36 @@ constexpr int USB_ENDPOINT_COUNT = 3; // ------- struct Drivers { - SpiMasterImpl spi{3, + SpiMasterImpl spiDevice{ gpio::P0(19), gpio::P0(20), gpio::P0(21), gpio::P0(21)}; // data/command for write-only display, can be same as MISO - SpiMasterImpl::Channel airSensor{spi, gpio::P0(2)}; - SpiMasterImpl::Channel display{spi, gpio::P0(3), true}; - SpiMasterImpl::Channel feRam{spi, gpio::P0(3)}; + SpiMasterImpl::Channel airSensor{spiDevice, gpio::P0(2)}; + SpiMasterImpl::Channel displayCommand{spiDevice, gpio::P0(3), SpiMasterImpl::Channel::Mode::COMMAND}; + SpiMasterImpl::Channel displayData{spiDevice, gpio::P0(3), SpiMasterImpl::Channel::Mode::DATA}; + SpiMasterImpl::Channel feRam{spiDevice, gpio::P0(3)}; QuadratureDecoderImpl quadratureDecoder{gpio::P0(4), gpio::P0(5)}; - BusMasterImpl busMaster{gpio::P0(2), gpio::P0(3)}; + //BusMasterImpl busMaster{gpio::P0(2), gpio::P0(3)}; - FlashImpl flash{0xe0000 - 0x20000, 4, 32768}; - FlashStorage storage{flash}; + //FlashImpl flash{0xe0000 - 0x20000, 4, 32768}; + //FlashStorage storage{flash}; +}; + +struct DriversSpiMasterTest { + SpiMasterImpl spi{ + gpio::P0(19), // SCK + gpio::P0(20), // MOSI + gpio::P0(21), // MISO + gpio::P0(21)}; // DC (data/command for write-only display, can be same as MISO) + SpiMasterImpl::Channel transfer{spi, gpio::P0(2)}; + SpiMasterImpl::Channel command{spi, gpio::P0(3), SpiMasterImpl::Channel::Mode::COMMAND}; + SpiMasterImpl::Channel data{spi, gpio::P0(3), SpiMasterImpl::Channel::Mode::DATA}; +}; + +struct DriversBusMasterTest { + BusMasterImpl busMaster{gpio::P0(2), gpio::P0(3)};; }; struct DriversFlashTest { diff --git a/software/board/switch/boardConfig.hpp b/software/board/switch/boardConfig.hpp index 203ede3..3963bd0 100644 --- a/software/board/switch/boardConfig.hpp +++ b/software/board/switch/boardConfig.hpp @@ -3,6 +3,7 @@ #include #include #include +//#include #include #include #include @@ -31,8 +32,10 @@ constexpr int TRIGGER_COUNT = INPUT_COUNT; // https://github.com/candle-usb/candleLight_fw/blob/master/include/config.h constexpr gpio::OutputConfig OUTPUTS[] = { {gpio::PB(2), gpio::Pull::DISABLED, gpio::Speed::LOW, gpio::Drive::PUSH_PULL, true, false, false}, // dummy - {gpio::PB(0), gpio::Pull::DISABLED, gpio::Speed::LOW, gpio::Drive::PUSH_PULL, true, false, false}, // green led - {gpio::PB(1), gpio::Pull::DISABLED, gpio::Speed::LOW, gpio::Drive::PUSH_PULL, true, false, false}, // blue led + //{gpio::PB(0), gpio::Pull::DISABLED, gpio::Speed::LOW, gpio::Drive::PUSH_PULL, true, false, false}, // green led + //{gpio::PB(1), gpio::Pull::DISABLED, gpio::Speed::LOW, gpio::Drive::PUSH_PULL, true, false, false}, // blue led + {gpio::PC(9), gpio::Pull::DISABLED, gpio::Speed::LOW, gpio::Drive::PUSH_PULL, true, false, false}, // green led + {gpio::PC(8), gpio::Pull::DISABLED, gpio::Speed::LOW, gpio::Drive::PUSH_PULL, true, false, false}, // blue led }; constexpr int OUTPUT_COUNT = array::count(OUTPUTS); @@ -45,37 +48,64 @@ constexpr int MPQ6526_MAPPING[] = {0, 1, 2, 3, 4, 5}; // ------- struct Drivers { - SpiMasterImpl spi{1, + /*SpiMasterImpl spi{1, gpio::PA(5), gpio::PA(7), gpio::PA(6)}; - SpiMasterImpl::Channel airSensor{spi, gpio::PA(3)}; - SpiMasterImpl::Channel display{spi, gpio::PA(4)}; + //SpiMasterImpl::Channel airSensor{spi, gpio::PA(3)}; + //SpiMasterImpl::Channel display{spi, gpio::PA(4)}; +*/ }; constexpr int FLASH_ADDRESS = 0x8000000; struct SwitchDrivers { SpiMasterImpl spi{1, - gpio::PA(5), - gpio::PA(7), - gpio::PA(6)}; + gpio::PA(5), // sck + gpio::PA(7), // mosi + gpio::PA(6)}; // miso SpiMasterImpl::Channel relayDriver{spi, gpio::PA(3)}; - - BusNodeImpl busNode; - - FlashImpl storageFlash{FLASH_ADDRESS + 20 * 1024, 2, 1024}; +/* + SpiMasterSingle16 relayDriver{ + gpio::PA(5), // sck + gpio::PA(7), // mosi + gpio::PA(6), // miso + gpio::PA(3)}; // cs +*/ + BusNodeImpl busNode{gpio::PA(10), gpio::PA(9)}; + + FlashImpl storageFlash{FLASH_ADDRESS + 24 * 1024, 2, 1024}; FlashStorage storage{storageFlash}; - FlashImpl countersFlash{FLASH_ADDRESS + 20 * 1024 + 2048, 10, 1024}; + FlashImpl countersFlash{FLASH_ADDRESS + 24 * 1024 + 2048, 10, 1024}; FlashStorage counters{countersFlash}; }; struct DriversFlashTest { - FlashImpl flash{FLASH_ADDRESS + 20 * 1024, 2, 1024}; + FlashImpl flash{FLASH_ADDRESS + 24 * 1024, 2, 1024}; }; struct DriversStorageTest { - FlashImpl flash{FLASH_ADDRESS + 20 * 1024, 2, 4096}; + FlashImpl flash{FLASH_ADDRESS + 24 * 1024, 2, 4096}; FlashStorage storage{flash}; }; + +struct DriversSpiMasterTest { + SpiMasterImpl spi{1, + gpio::PA(5), // sck + gpio::PA(7), // mosi + gpio::PA(6)}; // miso + SpiMasterImpl::Channel transfer{spi, gpio::PA(3)}; + SpiMasterImpl::Channel command{spi, gpio::PA(4)}; + SpiMasterImpl::Channel data{spi, gpio::PA(4)}; +/* + SpiMasterSingle16 transfer{ + gpio::PA(5), // sck + gpio::PA(7), // mosi + gpio::PA(6), // miso + gpio::PA(3)}; // cs*/ +}; + +struct DriversBusNodeTest { + BusNodeImpl busNode{gpio::PA(10), gpio::PA(9)}; +}; diff --git a/software/board/switch/link.ld b/software/board/switch/link.ld index 11aba25..1c95a81 100644 --- a/software/board/switch/link.ld +++ b/software/board/switch/link.ld @@ -62,7 +62,7 @@ _Min_Stack_Size = 0x400; /* required amount of stack */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 6K -FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 20K +FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 24K } /* Define output sections */ diff --git a/software/control/src/BusInterface.cpp b/software/control/src/BusInterface.cpp index 1a0f816..828f0a2 100644 --- a/software/control/src/BusInterface.cpp +++ b/software/control/src/BusInterface.cpp @@ -484,7 +484,7 @@ Coroutine BusInterface::receive() { Terminal::out << 'B' << dec(device->data.busDeviceId) << ": security counter error " << dec(securityCounter) << " <= " << dec(device->securityCounter) << '\n'; //break; } else { - //Terminal::out << 'B' << dec(device->data.busDeviceId) << ": security counter ok " << dec(securityCounter) << " > " << dec(device->securityCounter) << '\n'; + Terminal::out << 'B' << dec(device->data.busDeviceId) << ": security counter ok " << dec(securityCounter) << " > " << dec(device->securityCounter) << '\n'; } device->securityCounter = securityCounter; @@ -646,7 +646,7 @@ AwaitableCoroutine BusInterface::handleCommission(uint32_t busDeviceId, uint8_t MessageReader plugs(length, message); for (int i = 0; i < plugCount; ++i) { data->plugs[i] = plugs.e16L(); - Terminal::out << dec(endpointIndex) << " " << getTypeLabel(data->plugs[i]) << "\n"; + Terminal::out << "Ep " << dec(endpointIndex) << " Plug " << dec(i) << ' ' << getTypeLabel(data->plugs[i]) << "\n"; } // set id @@ -691,7 +691,6 @@ AwaitableCoroutine BusInterface::handleCommission(uint32_t busDeviceId, uint8_t auto oldEndpoint = oldDevice->endpoints; auto endpoint = device->endpoints; while (oldEndpoint != nullptr && endpoint != nullptr) { - //endpoint->subscribers.add(static_cast(static_cast &>(oldEndpoint->subscribers))); endpoint->subscribers.add(oldEndpoint->subscribers); // only works because old list removes itself from linked list oldEndpoint = oldEndpoint->next; endpoint = endpoint->next; diff --git a/software/control/src/RoomControl.cpp b/software/control/src/RoomControl.cpp index 6f34236..8e2724d 100644 --- a/software/control/src/RoomControl.cpp +++ b/software/control/src/RoomControl.cpp @@ -114,7 +114,7 @@ RoomControl::RoomControl(Drivers &drivers) , alarmInterface(ALARM_INTERFACE, drivers.storage) , functionInterface(FUNCTION_INTERFACE, drivers.storage) , interfaces{&localInterface, &busInterface, &radioInterface, &alarmInterface, &functionInterface} - , swapChain(drivers.display) + , swapChain({drivers.displayCommand, drivers.displayData}) { // load configuration int configurationSize = sizeof(Configuration); diff --git a/software/control/src/SSD1309.cpp b/software/control/src/SSD1309.cpp index b8554ed..5db66be 100644 --- a/software/control/src/SSD1309.cpp +++ b/software/control/src/SSD1309.cpp @@ -7,83 +7,83 @@ AwaitableCoroutine SSD1309::init() { // command unlock command[0] = 0xFD; command[1] = 0x12; - co_await this->spi.writeCommand(2, command); + co_await this->spi.command.write(2, command); // set display off command[0] = 0xAE; - co_await this->spi.writeCommand(1, command); + co_await this->spi.command.write(1, command); // set display clock divide ratio / oscillator frequency command[0] = 0xD5; command[1] = 0xA0; - co_await this->spi.writeCommand(2, command); + co_await this->spi.command.write(2, command); // set multiplex ratio command[0] = 0xA8; command[1] = 0x3F; - co_await this->spi.writeCommand(2, command); + co_await this->spi.command.write(2, command); // set display offset command[0] = 0xD3; command[1] = 0x00; - co_await this->spi.writeCommand(2, command); + co_await this->spi.command.write(2, command); // set display start line command[0] = 0x40; - co_await this->spi.writeCommand(1, command); + co_await this->spi.command.write(1, command); // set segment remap command[0] = 0xA1; - co_await this->spi.writeCommand(1, command); + co_await this->spi.command.write(1, command); // set com output scan direction command[0] = 0xC8; - co_await this->spi.writeCommand(1, command); + co_await this->spi.command.write(1, command); // set com pins hardware configuration command[0] = 0xDA; command[1] = 0x12; - co_await this->spi.writeCommand(2, command); + co_await this->spi.command.write(2, command); // set current control command[0] = 0x81; command[1] = 0xDF; - co_await this->spi.writeCommand(2, command); + co_await this->spi.command.write(2, command); // set pre-charge period command[0] = 0xD9; command[1] = 0x82; - co_await this->spi.writeCommand(2, command); + co_await this->spi.command.write(2, command); // set vcomh deselect level command[0] = 0xDB; command[1] = 0x34; - co_await this->spi.writeCommand(2, command); + co_await this->spi.command.write(2, command); // set entire display to normal command[0] = 0xA4; - co_await this->spi.writeCommand(1, command); + co_await this->spi.command.write(1, command); // set inverse display to normal command[0] = 0xA6; - co_await this->spi.writeCommand(1, command); + co_await this->spi.command.write(1, command); } AwaitableCoroutine SSD1309::enable() { //display::enableVcc(true); uint8_t command[1] = {0xAF}; - co_await this->spi.writeCommand(1, command); + co_await this->spi.command.write(1, command); this->enabled = true; } AwaitableCoroutine SSD1309::disable() { uint8_t command[1] = {0xAE}; - co_await this->spi.writeCommand(1, command); + co_await this->spi.command.write(1, command); this->enabled = false; //display::enableVcc(false); } AwaitableCoroutine SSD1309::setContrast(uint8_t contrast) { uint8_t command[2] = {0x81, contrast}; - co_await this->spi.writeCommand(2, command); + co_await this->spi.command.write(2, command); } diff --git a/software/control/src/SSD1309.hpp b/software/control/src/SSD1309.hpp index 938248b..7952585 100644 --- a/software/control/src/SSD1309.hpp +++ b/software/control/src/SSD1309.hpp @@ -12,7 +12,12 @@ */ class SSD1309 { public: - explicit SSD1309(SpiMaster &spi) : spi(spi) {} + struct Spi { + SpiMaster &command; + SpiMaster &data; + }; + + explicit SSD1309(Spi &spi) : spi(spi) {} /** * Initializate the display @@ -49,10 +54,10 @@ class SSD1309 { * @return use co_await on return value to await end of operation */ auto set(Bitmap const &bitmap) { - return this->spi.writeData(array::count(bitmap.data), bitmap.data); + return this->spi.data.write(array::count(bitmap.data), bitmap.data); } protected: - SpiMaster &spi; + Spi spi; bool enabled = false; }; diff --git a/software/control/src/SwapChain.hpp b/software/control/src/SwapChain.hpp index 4a53e9f..5f3c3e5 100644 --- a/software/control/src/SwapChain.hpp +++ b/software/control/src/SwapChain.hpp @@ -12,7 +12,7 @@ class SwapChain { /** * Constructor starts a coroutine that transfers the bitmaps to the display */ - SwapChain(SpiMaster &spi) : freeList{&bitmaps[0], &bitmaps[1]}, display(spi) { + SwapChain(SSD1309::Spi spi) : freeList{&bitmaps[0], &bitmaps[1]}, display(spi) { // start transfer coroutine transfer(); } diff --git a/software/control/test/SSD1309Test.cpp b/software/control/test/SSD1309Test.cpp index 714a5d7..4325034 100644 --- a/software/control/test/SSD1309Test.cpp +++ b/software/control/test/SSD1309Test.cpp @@ -6,7 +6,7 @@ #include -Coroutine draw(SpiMaster &spi) { +Coroutine draw(SSD1309::Spi spi) { SSD1309 display(spi); co_await display.init(); co_await display.enable(); @@ -34,7 +34,7 @@ int main(void) { Output::init(); Drivers drivers; - draw(drivers.display); + draw({drivers.displayCommand, drivers.displayData}); Loop::run(); } diff --git a/software/protocol/src/crc.cpp b/software/protocol/src/crc.cpp index b8e23e2..c24f5b7 100644 --- a/software/protocol/src/crc.cpp +++ b/software/protocol/src/crc.cpp @@ -1,5 +1,34 @@ #include "crc.hpp" + +static const uint8_t crc8Table[256] = { + 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, + 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, + 0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd, + 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd, + 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, + 0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a, + 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a, + 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, + 0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4, + 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4, + 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, + 0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34, + 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63, + 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, + 0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83, + 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3, +}; + +uint8_t crc8(int size, const void *data, uint16_t crc) { + auto *d = reinterpret_cast(data); + for (int i = 0; i < size; ++i) { + crc = crc8Table[crc ^ d[i]]; + } + return crc; +} + + // see https://www.mikrocontroller.net/attachment/91385/crc16.c // generated in protocolTest.cpp @@ -25,7 +54,7 @@ const uint16_t crc16Table[] { uint16_t crc16(int size, const void *data, uint16_t crc) { auto *d = reinterpret_cast(data); for (int i = 0; i < size; ++i) { - crc = crc16Table[(crc >> 8) ^ *d++] ^ (crc << 8); + crc = crc16Table[(crc >> 8) ^ d[i]] ^ (crc << 8); } return crc; } diff --git a/software/protocol/src/crc.hpp b/software/protocol/src/crc.hpp index 97d12ac..5bf31e5 100644 --- a/software/protocol/src/crc.hpp +++ b/software/protocol/src/crc.hpp @@ -3,6 +3,15 @@ #include +/** + * Calculate CRC-8, polynom 0x07, see https://crccalc.com/ + * @param size size of data + * @param data data + * @param crc chained CRC, can be used to calculate crc in multiple sections + * @return resulting CRC + */ +uint8_t crc8(int size, const void *data, uint16_t crc = 0); + /** * Calculate CRC-16/CCITT-FALSE, polynom 0x1021, see https://crccalc.com/ * @param size size of data diff --git a/software/protocol/test/protocolTest.cpp b/software/protocol/test/protocolTest.cpp index 95428c5..d9d192c 100644 --- a/software/protocol/test/protocolTest.cpp +++ b/software/protocol/test/protocolTest.cpp @@ -18,11 +18,19 @@ TEST(protocolTest, DataBuffer) { b.setData(0, b); } +TEST(protocolTest, crc8) { + // calc crc-8 + uint16_t crc = crc8(12, "Hello World!"); + + // expected result from CRC-8 on https://crccalc.com/ + EXPECT_EQ(crc, 0x1c); +} + TEST(protocolTest, crc16) { - // calc crc with CRC-16/CCITT-FALSE + // calc crc-16 uint16_t crc = crc16(12, "Hello World!"); - // expected result from https://crccalc.com/ + // expected result from CRC-16/CCITT-FALSE on https://crccalc.com/ EXPECT_EQ(crc, 0x882a); } @@ -201,15 +209,39 @@ void generateZa09Keys() { printKey("za09KeyLoadAesKey", aesKey); } + +// generate lookup table for crc8 +void generateCrc8Table(uint8_t polynomial) { + uint8_t crc_table[256]; + for (int b = 0; b <= 255; ++b) { + uint8_t v; + int i; + for (v = b, i = 8; --i >= 0;) { + if ((v & 0x80) != 0) + v = (v << 1) ^ polynomial; + else + v = v << 1; + } + crc_table[b] = v; + } + + for (int j = 0; j < 16; ++j) { + for (int i = 0; i < 16; ++i) { + std::cout << "0x" << std::hex << std::setfill('0') << std::setw(2) << int(crc_table[j * 16 + i]) << ", "; + } + std::cout << std::endl; + } +} + // generate lookup table for crc16 void generateCrc16Table(uint16_t polynomial) { - uint16_t crc_table[256]; + uint16_t crc_table[256]; for (int b = 0; b <= 255; ++b) { uint16_t v; int i; for (v = b << 8, i = 8; --i >= 0;) { - if ((v & 0x8000) != 0x0000) - v = ( v << 1 ) ^ polynomial; + if ((v & 0x8000) != 0) + v = (v << 1) ^ polynomial; else v = v << 1; } @@ -227,6 +259,7 @@ void generateCrc16Table(uint16_t polynomial) { int main(int argc, char **argv) { //generateBusKey(); //generateZa09Keys(); + //generateCrc8Table(0x07); //generateCrc16Table(0x1021); testing::InitGoogleTest(&argc, argv); diff --git a/software/switch/src/main.cpp b/software/switch/src/main.cpp index 62cb75c..99ace4f 100644 --- a/software/switch/src/main.cpp +++ b/software/switch/src/main.cpp @@ -527,15 +527,18 @@ class Switch { //Terminal::out << "ab " << dec(ax) << dec(ay) << dec(az) << " " << dec(bx) << dec(by) << dec(bz) << "\n"; // build 16 bit word for relay driver - uint16_t word = 0x8000 // enable + uint16_t w = 0x8000 // enable | (ax << (MPQ6526_MAPPING[0] * 2 + 1)) | (ay << (MPQ6526_MAPPING[1] * 2 + 1)) | (az << (MPQ6526_MAPPING[2] * 2 + 1)) | (bx << (MPQ6526_MAPPING[3] * 2 + 1)) | (by << (MPQ6526_MAPPING[4] * 2 + 1)) | (bz << (MPQ6526_MAPPING[5] * 2 + 1)); - //Terminal::out << "spi " << hex(word) << "\n"; - co_await this->drivers.relayDriver.transfer(1, &word, 0, nullptr); + //Terminal::out << "spi " << hex(w) << "\n"; + + // transfer + uint16_t r; + co_await this->drivers.relayDriver.transfer(2, &w, 2, &r); // wait some time until relay contacts react co_await Timer::sleep(RELAY_TIME); diff --git a/software/system/src/BusMaster.hpp b/software/system/src/BusMaster.hpp index a9ad37a..4655ff6 100644 --- a/software/system/src/BusMaster.hpp +++ b/software/system/src/BusMaster.hpp @@ -15,41 +15,49 @@ Protocol: The master always starts by sending a BREAK which are 13 zero bits and a stop bit followed by SYNC which is 0x55. Then a command or message follows which is sent by the master or a node. A message is acknowledged by the receiver. + If a node wants to send a command or a message, it sends a single bit (pulls the bus low for one bit time) to wake + up the master which then starts by sending a BREAK. BREAK SYNC | BREAK SYNC | | - Command: + BREAK: + 13 zero bits followed by one stop bit + + SYNC: + 0x55 + + : A device can be set to commissioning mode e.g. by pressing a button or button combination for a longer time or by power cycle, depending on security requirements. All devices in commissioning mode will send an enumerate command, simultaneous sending is resolved by bus arbitration. Commissioning command by master overrides all enumerate commands (by sending a leading zero) and causes the commissioned device to leave commissioning mode. - Enumerate: 0 - Commission: 0 0
+ Enumerate: 0 + Commission: 0 0
- Message: + : The message starts with the encoded device address for bus arbitration (always loses against commands as it never starts with zero) and contains either an attribute read request, attribute data or a plug message - attribute read: <255> - attribute data: <255> - plug message: - - Ack: - CRC-8 sent in response as acknowledgement + Attribute Read: <255> + Attribute Data: <255> + Plug Message: + (not implemented yet): + CRC-8 of Command or Message (not including sync) sent in response as acknowledgement - : + : Each byte encodes 3 bit of the device id as number of bits from 1 to 8, starting with lowest bits, 11 bytes in total -
: +
: One byte unique address that gets assigned to a device during commissioning - : - Two bytes, first is ((address & 7) + 1), second is (address / 8) encoded as number of bits from 0 to 8 + : + Two bytes, first is ((address & 7) + 1) and therefore never 0 to to be different from commands, + second is (address / 8) encoded as number of bits from 0 to 8 - : + : Four bytes security counter - + Message integrity code using the default key or a configured network key */ class BusMaster { @@ -61,7 +69,7 @@ class BusMaster { struct SendParameters { int length; - uint8_t const *data; + const uint8_t *data; }; diff --git a/software/system/src/BusNode.hpp b/software/system/src/BusNode.hpp index a3652cf..997f038 100644 --- a/software/system/src/BusNode.hpp +++ b/software/system/src/BusNode.hpp @@ -11,17 +11,17 @@ class BusNode { public: struct ReceiveParameters { - int *receiveLength; - uint8_t *receiveData; + int *length; + uint8_t *data; }; struct SendParameters { - int sendLength; - uint8_t const *sendData; + int length; + const uint8_t *data; }; - ~BusNode(); + virtual ~BusNode(); /** * Receive data from bus master diff --git a/software/system/src/FlashStorage.cpp b/software/system/src/FlashStorage.cpp index 9691ce1..d9c6509 100644 --- a/software/system/src/FlashStorage.cpp +++ b/software/system/src/FlashStorage.cpp @@ -1,4 +1,5 @@ #include "FlashStorage.hpp" +#include #include #include #include @@ -72,7 +73,7 @@ FlashStorage::FlashStorage(Flash &flash) switch (foundState) { case SectorState::EMPTY: // this happens if the flash is empty, make sure the sector is really empty - flash.eraseSectorBlocking(head); + //flash.eraseSectorBlocking(head); this->sectorIndex = head; this->sector = this->sectorIndex * this->info.sectorSize; @@ -103,7 +104,9 @@ FlashStorage::FlashStorage(Flash &flash) this->dataWriteOffset = this->info.sectorSize; // garbage collect tail sector + //Debug::setGreenLed(); gc(next); + //Debug::clearGreenLed(); break; } @@ -235,17 +238,17 @@ FlashStorage::SectorState FlashStorage::detectSectorState(int sectorIndex) { flash.readBlocking(sector, sizeof(entry), &entry); if (entry.isEmpty()) { - // section is empty or open: read first entry + // sector is empty or open: read first entry flash.readBlocking(sector + this->entrySize, sizeof(entry), &entry); if (entry.isEmpty()) { - // section is empty + // sector is empty return SectorState::EMPTY; } else { - // section is open + // sector is open return SectorState::OPEN; } } else { - // section is closed + // sector is closed return SectorState::CLOSED; } } diff --git a/software/system/src/SpiMaster.hpp b/software/system/src/SpiMaster.hpp index 798093c..76d5f43 100644 --- a/software/system/src/SpiMaster.hpp +++ b/software/system/src/SpiMaster.hpp @@ -13,7 +13,7 @@ class SpiMaster { // Internal helper: Stores the parameters in the awaitable during co_await struct Parameters { // pointer to configuration - void const *config; + void *config; // write data int writeCount; @@ -28,29 +28,33 @@ class SpiMaster { virtual ~SpiMaster(); /** - * Transfer data to/from SPI device - * @param writeCount number of 8/16/32 bit values to write - * @param writeData array of 8/16/32 bit values to write (ram-only dependent on driver) - * @param readCount number of 8/16/32 bit values to read - * @param readData array of 8/16/32 bit values to read (ram-only dependent on driver) + * Transfer data to/from SPI device. Zero length transfers are not supported, i.e. writeCount or readCount must be + * greater than zero. + * @param writeCount number of bytes to write + * @param writeData data to write (driver may require that the data is located in RAM) + * @param readCount number of bytes to read + * @param readData data to read * @return use co_await on return value to await completion */ [[nodiscard]] virtual Awaitable transfer(int writeCount, void const *writeData, int readCount, void *readData) = 0; /** - * Write a command to an SPI device, e.g. a display, indicating a command using a separate data/command line if supported - * @param index index of spi context - * @param writeCount length of data to write - * @param writeData data to write + * Write to an SPI device, convenience method. + * @param count number of bytes to write + * @param data data to write (driver may require that the data is located in RAM) * @return use co_await on return value to await completion */ - [[nodiscard]] inline Awaitable writeCommand(int count, void const *command) { - return transfer(count | 0x80000000, command, 0, nullptr); - } - - [[nodiscard]] inline Awaitable writeData(int count, void const *data) { + [[nodiscard]] inline Awaitable write(int count, void const *data) { return transfer(count, data, 0, nullptr); } + /** + * Transfer data to/from SPI device and block until finished. Zero length transfers are not supported, i.e. + * writeCount or readCount must be greater than zero. + * @param writeCount number of bytes to write + * @param writeData data to write (driver may require that the data is located in RAM) + * @param readCount number of bytes to read + * @param readData data to read + */ virtual void transferBlocking(int writeCount, void const *writeData, int readCount, void *readData) = 0; }; diff --git a/software/system/src/Timer.hpp b/software/system/src/Timer.hpp index 5df39ca..47c4e22 100644 --- a/software/system/src/Timer.hpp +++ b/software/system/src/Timer.hpp @@ -13,19 +13,19 @@ namespace Timer { void init(); /** - * Get current time in 1/1024 seconds + * Get current time in milliseconds * @return current time */ SystemTime now(); /** - * Suspend execution using co_await until a given time. Only up to TIMER_COUNT coroutines can wait simultaneously. + * Suspend execution using co_await until a given time. * @param time time point */ [[nodiscard]] Awaitable sleep(SystemTime time); /** - * Suspend execution using co_await for a given duration. Only up to TIMER_COUNT coroutines can wait simultaneously. + * Suspend execution using co_await for a given duration. * @param duration duration */ [[nodiscard]] inline Awaitable sleep(SystemDuration duration) {return sleep(now() + duration);} diff --git a/software/system/src/emu/BusMasterImpl.cpp b/software/system/src/emu/BusMasterImpl.cpp index ab100d7..914cee7 100644 --- a/software/system/src/emu/BusMasterImpl.cpp +++ b/software/system/src/emu/BusMasterImpl.cpp @@ -79,10 +79,12 @@ BusMasterImpl::BusMasterImpl() : file("busMaster.bin", File::Mode::READ_WRITE) { } Awaitable BusMasterImpl::receive(int &length, uint8_t *data) { + assert(length > 0); return {this->receiveWaitlist, &length, data}; } Awaitable BusMasterImpl::send(int length, uint8_t const *data) { + assert(length > 0); return {this->sendWaitlist, length, data}; } @@ -128,7 +130,7 @@ void BusMasterImpl::handle(Gui &gui) { setKey(device.persistentState.aesKey, r.data8<16>()); // reset security counter - device.persistentState.securityCounter = 0; + device.persistentState.securityCounter = 1; // set index device.persistentState.index = device.nextIndex; diff --git a/software/system/src/emu/BusNodeImpl.cpp b/software/system/src/emu/BusNodeImpl.cpp index a0e5eec..a21e2db 100644 --- a/software/system/src/emu/BusNodeImpl.cpp +++ b/software/system/src/emu/BusNodeImpl.cpp @@ -29,14 +29,14 @@ Awaitable BusNodeImpl::send(int length, uint8_t const * void BusNodeImpl::handle(Gui &gui) { // handle pending send operations this->sendWaitlist.resumeFirst([this](SendParameters &p) { - if (p.sendLength == 0) + if (p.length == 0) return true; uint8_t data[64]; - array::copy(p.sendLength, data, p.sendData); + array::copy(p.length, data, p.data); // read message - bus::MessageReader r(p.sendLength, data); + bus::MessageReader r(p.length, data); r.setHeader(); // get address @@ -216,9 +216,9 @@ void BusNodeImpl::sendToNode(bus::MessageWriter &w) { int length = w.getLength(); auto data = w.begin; this->receiveWaitlist.resumeFirst([length, data](ReceiveParameters &p) { - int len = min(length, *p.receiveLength); - array::copy(len, p.receiveData, data); - *p.receiveLength = len; + int len = min(length, *p.length); + array::copy(len, p.data, data); + *p.length = len; return true; }); } diff --git a/software/system/src/emu/SpiSSD1309.cpp b/software/system/src/emu/SpiSSD1309.cpp index e98fa33..f331968 100644 --- a/software/system/src/emu/SpiSSD1309.cpp +++ b/software/system/src/emu/SpiSSD1309.cpp @@ -7,8 +7,8 @@ SpiSSD1309::SpiSSD1309(int width, int height) : width(width), height(height) { int size = width * height / 8; - this->display = new uint8_t[size]; - array::fill(size, this->display, 0); + this->data = new uint8_t[size]; + array::fill(size, this->data, 0); this->displayBuffer = new uint8_t[width * height]; // add to list of handlers @@ -16,7 +16,7 @@ SpiSSD1309::SpiSSD1309(int width, int height) } SpiSSD1309::~SpiSSD1309() { - delete [] this->display; + delete [] this->data; delete [] this->displayBuffer; } @@ -25,61 +25,51 @@ Awaitable SpiSSD1309::transfer(int writeCount, void cons } void SpiSSD1309::transferBlocking(int writeCount, void const *writeData, int readCount, void *readData) { - bool command = writeCount < 0; - writeCount &= 0x7fffffff; auto w = reinterpret_cast(writeData); - auto r = reinterpret_cast(readData); - if (command) { - // execute commands - for (int i = 0; i < writeCount; ++i) { - switch (w[i]) { - // set contrast control - case 0x81: - this->displayContrast = w[++i]; - break; - - // entire display on - case 0xA4: - this->displayOn = false; - break; - case 0xA5: - this->displayOn = true; - break; - - // set normal/inverse display - case 0xA6: - this->displayInverse = false; - break; - case 0xA7: - this->displayInverse = true; - break; - - // set display on/off - case 0xAE: - this->displayEnabled = false; - break; - case 0xAF: - this->displayEnabled = true; - break; - } - } - } else { - // set data - for (int i = 0; i < writeCount; ++i) { - // copy byte (8 pixels in a column) - this->display[page * this->width + this->column] = w[i]; - - // increment column index - this->column = (this->column == this->width - 1) ? 0 : this->column + 1; - if (this->column == 0) - this->page = this->page == (this->height / 8 - 1) ? 0 : this->page + 1; + + // execute commands + for (int i = 0; i < writeCount; ++i) { + switch (w[i]) { + // set contrast control + case 0x81: + this->displayContrast = w[++i]; + break; + + // entire display on + case 0xA4: + this->displayOn = false; + break; + case 0xA5: + this->displayOn = true; + break; + + // set normal/inverse display + case 0xA6: + this->displayInverse = false; + break; + case 0xA7: + this->displayInverse = true; + break; + + // set display on/off + case 0xAE: + this->displayEnabled = false; + break; + case 0xAF: + this->displayEnabled = true; + break; } } } void SpiSSD1309::handle(Gui &gui) { this->waitlist.resumeFirst([this](Parameters &p) { - transferBlocking(p.writeCount, p.writeData, p.readCount, p.readData); + if (p.config == nullptr) { + transferBlocking(p.writeCount, p.writeData, p.readCount, p.readData); + } else { + auto &d = *reinterpret_cast(p.config); + d.transferBlocking(p.writeCount, p.writeData, p.readCount, p.readData); + } return true; }); @@ -99,8 +89,29 @@ void SpiSSD1309::getDisplay(uint8_t *buffer) { for (int j = 0; j < height; ++j) { uint8_t *b = &buffer[width * j]; for (int i = 0; i < width; ++i) { - bool bit = (this->display[i + width * (j >> 3)] & (1 << (j & 7))) != 0; + bool bit = (this->data[i + width * (j >> 3)] & (1 << (j & 7))) != 0; b[i] = bit ? foreground : background; } } } + + +Awaitable SpiSSD1309::Data::transfer(int writeCount, const void *writeData, int readCount, void *readData) { + return {this->display.waitlist, this, writeCount, writeData, readCount, readData}; +} + +void SpiSSD1309::Data::transferBlocking(int writeCount, const void *writeData, int readCount, void *readData) { + auto &d = this->display; + auto w = reinterpret_cast(writeData); + + // set data + for (int i = 0; i < writeCount; ++i) { + // copy byte (8 pixels in a column) + d.data[d.page * d.width + d.column] = w[i]; + + // increment column index + d.column = (d.column == d.width - 1) ? 0 : d.column + 1; + if (d.column == 0) + d.page = d.page == (d.height / 8 - 1) ? 0 : d.page + 1; + } +} diff --git a/software/system/src/emu/SpiSSD1309.hpp b/software/system/src/emu/SpiSSD1309.hpp index e426e10..fae6018 100644 --- a/software/system/src/emu/SpiSSD1309.hpp +++ b/software/system/src/emu/SpiSSD1309.hpp @@ -22,7 +22,7 @@ class SpiSSD1309 : public SpiMaster, public Loop::Handler2 { void handle(Gui &gui) override; - // get dipslay contents into an 8 bit grayscale image + // get display contents into an 8 bit grayscale image void getDisplay(uint8_t *buffer); @@ -39,8 +39,29 @@ class SpiSSD1309 : public SpiMaster, public Loop::Handler2 { bool displayOn = false; // all pixels on bool displayInverse = false; bool displayEnabled = false; - uint8_t *display; + uint8_t *data; uint8_t *displayBuffer; Waitlist waitlist; + + + /** + * Separate data channel + */ + class Data : public SpiMaster { + public: + /** + * Constructor + * @param device the SPI device to operate on + * @param csPin chip select pin of the slave + * @param writeOnly ture if we only write data and can use MISO as DC (data/command) signal (e.g. for a display) + */ + Data(SpiSSD1309 &display) : display(display) {} + + Awaitable transfer(int writeCount, const void *writeData, int readCount, void *readData) override; + void transferBlocking(int writeCount, const void *writeData, int readCount, void *readData) override; + + + SpiSSD1309 &display; + }; }; diff --git a/software/system/src/nrf52/BusMasterImpl.cpp b/software/system/src/nrf52/BusMasterImpl.cpp index c2e8a07..ea605d1 100644 --- a/software/system/src/nrf52/BusMasterImpl.cpp +++ b/software/system/src/nrf52/BusMasterImpl.cpp @@ -1,209 +1,377 @@ #include "BusMasterImpl.hpp" #include "gpio.hpp" #include +#include "Debug.hpp" // debug /* -#define initSignal() configureOutput(3) -#define setSignal(value) setOutput(3, value) -#define toggleSignal() toggleOutput(3) +#define initSignal() gpio::configureOutput(20) +#define setSignal(value) gpio::setOutput(20, value) +#define toggleSignal() gpio::toggleOutput(20) */ #define initSignal() #define setSignal(value) #define toggleSignal() + /* + How to calculate the value for the BAUDRATE register: desired baudrate * 2^32 / 16000000 (https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values) Dependencies: Config: Resources: NRF_UART0 - NRF_TIMER1 + NRF_TIMER1: Break and rx timeout + NRF_EGU1 + TRIGGERED[0]: Received a packet + TRIGGERED[1]: Send operation has finished + TRIGGERED[2]: Request to send by node */ +constexpr int TIMER_CLOCK = 1000000; // 1MHz +constexpr int BAUD_RATE = 19200; + namespace { -BusMasterImpl *busMaster[1]; +BusMasterImpl *busMaster; } -BusMasterImpl::BusMasterImpl(int rxPin, int txPin) : txPin(txPin) { - this->uart = NRF_UART0; - this->timer = NRF_TIMER1; - busMaster[0] = this; +BusMasterImpl::BusMasterImpl(int rxPin, int txPin) : rxPin(rxPin), txPin(txPin) { + const auto uart = NRF_UART0; + const auto timer = NRF_TIMER1; + const auto egu = NRF_EGU1; + + // set instance pointer + busMaster = this; + initSignal(); - // init uart + // configure rx pin (pull-up) and tx pin (idle state is high) + gpio::configureInput(rxPin);//, gpio::Pull::UP); gpio::setOutput(txPin, true); gpio::configureOutput(txPin); - configureInput(rxPin, gpio::Pull::UP); - //NRF_UART0->PSEL.TXD = BUS_TX_PIN; - NRF_UART0->PSEL.RXD = rxPin; - NRF_UART0->CONFIG = N(UART_CONFIG_STOP, One) | N(UART_CONFIG_PARITY, Excluded); - //NRF_UART0->INTENSET = N(UART_INTENSET_TXDRDY, Set) | N(UART_INTENSET_RXDRDY, Set); + + // init uart + uart->PSEL.RXD = rxPin; + uart->PSEL.TXD = txPin; + uart->CONFIG = N(UART_CONFIG_STOP, One) | N(UART_CONFIG_PARITY, Excluded); + uart->BAUDRATE = N(UARTE_BAUDRATE_BAUDRATE, Baud19200); + uart->INTENSET = N(UART_INTENSET_RXDRDY, Set);// | N(UART_INTENSET_TXDRDY, Set); + uart->ENABLE = N(UART_ENABLE_ENABLE, Enabled); enableInterrupt(UARTE0_UART0_IRQn); + // start receiving requests from nodes + uart->TASKS_STARTRX = TRIGGER; // -> EVENTS_RXRDY + // init timer - NRF_TIMER1->MODE = N(TIMER_MODE_MODE, Timer); - NRF_TIMER1->BITMODE = N(TIMER_BITMODE_BITMODE, 32Bit); - NRF_TIMER1->PRESCALER = 4; // 1MHz - NRF_TIMER1->CC[0] = 1250; - NRF_TIMER1->INTENSET = N(TIMER_INTENSET_COMPARE0, Set); + timer->MODE = N(TIMER_MODE_MODE, Timer); + timer->BITMODE = N(TIMER_BITMODE_BITMODE, 32Bit); + timer->PRESCALER = 4; // 1MHz + timer->INTENSET = N(TIMER_INTENSET_COMPARE0, Set); enableInterrupt(TIMER1_IRQn); + // init event generator + egu->INTENSET = + N(EGU_INTENSET_TRIGGERED0, Set) + | N(EGU_INTENSET_TRIGGERED1, Set) + | N(EGU_INTENSET_TRIGGERED2, Set); + // add to list of handlers -// Loop::handlers.add(*this); + Loop::handlers.add(*this); } Awaitable BusMasterImpl::receive(int &length, uint8_t *data) { + // start receiving immediately if no rx is pending and bus is idle + if (this->rxState == RxState::IDLE) { + ReceiveParameters p{&length, data}; + startReceive(p); + } + return {this->receiveWaitlist, &length, data}; } -Awaitable BusMasterImpl::send(int length, uint8_t const *data) { +Awaitable BusMasterImpl::send(int length, const uint8_t *data) { + if (length <= 0) + return {}; + + // start sending immediately if no tx is pending and bus is idle + if (this->txState == TxState::IDLE) { + //Debug::toggleRedLed(); + SendParameters p{length, data}; + startSend(p); + } + return {this->sendWaitlist, length, data}; } void BusMasterImpl::handle() { - if (rxReady) { - rxReady = false; - this->onTransferred(this->rxIndex); - setSignal(true); - } - if (requestReady) { - requestReady = false; - if (this->onRequest) - this->onRequest(this->requestData[0]);//, BusMaster::requestIndex); - this->requestIndex = 0; - } -} + const auto egu = NRF_EGU1; + + if (isInterruptPending(SWI1_EGU1_IRQn)) { + + // check if tx or rx operation has finished + if (egu->EVENTS_TRIGGERED[1]) { + // send operation complete + egu->EVENTS_TRIGGERED[1] = 0; + this->txState = TxState::IDLE; + + // check if a next send operation is pending + this->sendWaitlist.visitSecond([this](const SendParameters &p) { + startSend(p); + }); + + // resume first waiting coroutine + this->sendWaitlist.resumeFirst([](const SendParameters &p) { + return true; + }); + } else if (egu->EVENTS_TRIGGERED[0]) { + // receive operation complete + egu->EVENTS_TRIGGERED[0] = 0; + int rxLength = this->rxData - this->rxBegin; + this->rxState = RxState::IDLE; + + // check if a next receive operation is pending + this->receiveWaitlist.visitSecond([this](const ReceiveParameters &p) { + startReceive(p); + }); + + // resume first waiting coroutine + this->receiveWaitlist.resumeFirst([rxLength](const ReceiveParameters &p) { + *p.length = rxLength; + return true; + }); + } -void BusMasterImpl::uartIrqHandler() { - if (this->uart->EVENTS_TXDRDY) { - this->uart->EVENTS_TXDRDY = 0; - - // check if end of send buffer - int txIndex = this->txIndex; - if (txIndex < this->txLength) { - // send next byte - this->uart->TXD = this->txData[txIndex]; - this->txIndex = txIndex + 1; - } else { - // stop transmit - this->uart->TASKS_STOPTX = TRIGGER; + if (egu->EVENTS_TRIGGERED[2]) { + // a node requested to be read: Start break if we are in idle state (no new tx was started above) + egu->EVENTS_TRIGGERED[2] = 0; + if (this->state == State::IDLE) + startBreak(); } + + // clear pending interrupt flag at NVIC + clearInterrupt(SWI1_EGU1_IRQn); } - if (this->uart->EVENTS_RXDRDY) { - this->uart->EVENTS_RXDRDY = 0; - toggleSignal(); - //setSignal(true); +} + +void BusMasterImpl::startReceive(const ReceiveParameters &p) { + this->rxState = RxState::PENDING; + this->rxBegin = p.data; + this->rxEnd = p.data + *p.length; + + // don't start yet, wait for send or request signal from node +} + +void BusMasterImpl::startSend(const SendParameters &p) { + this->txState = TxState::PENDING; + this->txBegin = p.data; + this->txEnd = p.data + p.length; + startBreak(); +} + +void BusMasterImpl::startBreak() { + const auto uart = NRF_UART0; + const auto timer = NRF_TIMER1; + + // disconnect uart from tx and set high baud rate to force stop of rx/tx during break + uart->TASKS_STOPRX = TRIGGER; + uart->TASKS_STOPTX = TRIGGER; + uart->ENABLE = 0; + uart->INTENCLR = 0xffffffff; + uart->PSEL.TXD = gpio::DISCONNECTED; + uart->BAUDRATE = N(UARTE_BAUDRATE_BAUDRATE, Baud1M); + uart->ENABLE = N(UART_ENABLE_ENABLE, Enabled); + + // generate break: 13 bit times, 677us + gpio::setOutput(this->txPin, false); + timer->TASKS_CLEAR = TRIGGER; + timer->CC[0] = 677; + timer->TASKS_START = TRIGGER; + + // set state + this->state = State::BREAK; + + //Debug::toggleRedLed(); +} + + +// interrupt handlers + +void UARTE0_UART0_IRQHandler() { + busMaster->uartIrqHandler(); +} - if (this->state == SYNC) { +void BusMasterImpl::uartIrqHandler() { + const auto uart = NRF_UART0; + const auto timer = NRF_TIMER1; + const auto egu = NRF_EGU1; + + if (uart->EVENTS_RXDRDY) { + uart->EVENTS_RXDRDY = 0; + setSignal(false); + + // restart rx timeout + timer->TASKS_CLEAR = TRIGGER; + + auto b = uart->RXD; + switch (this->state) { + case State::IDLE: + // received a request signal from a node + egu->TASKS_TRIGGER[2] = TRIGGER; + break; + case State::SYNC: // check if sync byte was received correctly - uint8_t sync = this->uart->RXD; - if (sync != 0x55) { + //Debug::toggleRedLed(); + if (b != 0x55) { // error: sync byte not received correctly - // indicate that rx buffer is ready (zero length to indicate error) - this->rxReady = true; - - // stop timer - this->timer->TASKS_STOP = TRIGGER; + // repeat + startBreak(); - // now in request mode - this->state = REQUEST; + //todo indicate bus error after 3-5 retries } else { - // now receive data - this->state = RX; + // sync ok: now start to transfer data + if (this->rxState >= RxState::PENDING) { + this->rxState = RxState::ACTIVE; + this->rxData = this->rxBegin; + } + + // send first byte if tx is pending + if (this->txState >= TxState::PENDING) { + this->txState = TxState::ACTIVE; + auto data = this->txBegin; + this->txData = data + 1; + b = *data; + uart->TXD = b; + this->txByte = b; + } else { + // tx is idle: stop transmit + uart->TASKS_STOPTX = TRIGGER; + } + + // now in transfer state + this->state = State::TRANSFER; } - } else if (this->state == RX) { - // check if rx buffer full - int rxIndex = this->rxIndex; - this->rxData[rxIndex] = this->uart->RXD; - this->rxIndex = rxIndex + 1; - if (this->rxIndex == this->rxLength) { - // indicate that rx buffer is ready - this->rxReady = true; - - // stop timer - this->timer->TASKS_STOP = TRIGGER; - - // now in request mode - this->state = REQUEST; + break; + case State::TRANSFER: { + // received next byte + //Debug::toggleGreenLed(); + + // when tx is active, check if received byte is equal to the last sent byte + if (this->txState == TxState::ACTIVE) { + // check if byte was transferred ok and the current state of the bus is high + if (b == this->txByte && gpio::readInput(this->rxPin)) { + // byte was transferred ok + auto data = this->txData; + if (data < this->txEnd) { + // send next byte + this->txData = data + 1; + b = *data; + uart->TXD = b; + this->txByte = b; + } else { + // end: stop transmit and set tx state to success + uart->TASKS_STOPTX = TRIGGER; + this->txState = TxState::END; + } + } else { + // error: stop transmit as probably a node won the bus arbitration + uart->TASKS_STOPTX = TRIGGER; + this->txState = TxState::PENDING; + } + } else if (this->txState == TxState::END) { + // error: extra byte received after successful transmission + this->txState = TxState::PENDING; } - // restart rx timeout (unless stopped) - this->timer->TASKS_CLEAR = TRIGGER; - } else { - // check if request buffer full - int requestIndex = this->requestIndex; - if (requestIndex < array::count(this->requestData)) { - this->requestData[requestIndex] = this->uart->RXD; - this->requestIndex = requestIndex + 1; - if (requestIndex == array::count(this->requestData)) { - // indicate that requests are ready - this->requestReady = true; + // check if receive is pending + if (this->rxState == RxState::ACTIVE) { + auto data = this->rxData; + if (data < this->rxEnd) { + // add next byte to receive buffer + this->rxData = data + 1; + *data = b; } } + break; } - - //toggleSignal(); - } -} - -void BusMasterImpl::timerIrqHandler() { - if (this->timer->EVENTS_COMPARE[0]) { - this->timer->EVENTS_COMPARE[0] = 0; - - if (state == BREAK) { - gpio::setOutput(this->txPin, true); - - // reconfigure uart for transmission - this->uart->ENABLE = 0; - this->uart->EVENTS_RXDRDY = 0; - this->uart->EVENTS_TXDRDY = 0; - this->uart->BAUDRATE = N(UARTE_BAUDRATE_BAUDRATE, Baud19200); - this->uart->PSEL.TXD = this->txPin; - this->uart->INTENSET = N(UART_INTENSET_RXDRDY, Set) | N(UART_INTENSET_TXDRDY, Set); - this->uart->ENABLE = N(UART_ENABLE_ENABLE, Enabled); - - // start transfer with sync byte - this->uart->TASKS_STARTRX = TRIGGER; // -> EVENTS_RXRDY - this->uart->TASKS_STARTTX = TRIGGER; // -> EVENTS_TXRDY - this->uart->TXD = 0x55; - - // restart timer for rx timeout - this->timer->TASKS_CLEAR = TRIGGER; - this->timer->CC[0] = 1250; - - // expect receive of sync byte - this->state = SYNC; - setSignal(false); - } else { - //toggleSignal(); - - // stop timer - this->timer->TASKS_STOP = TRIGGER; - - // indicate that rx buffer is ready - this->rxReady = true; - - // now in request mode - this->state = REQUEST; - - // toggleSignal(); - setSignal(true); + default: + // ignore when in other state + break; } } -} -extern "C" { -void UARTE0_UART0_IRQHandler(void); -void TIMER1_IRQHandler(void); + // debug + /*if (uart->EVENTS_TXDRDY) { + uart->EVENTS_TXDRDY = 0; + setSignal(true); + }*/ } -void UARTE0_UART0_IRQHandler(void) { - busMaster[0]->uartIrqHandler(); +void TIMER1_IRQHandler() { + busMaster->timerIrqHandler(); } -void TIMER1_IRQHandler(void) { - busMaster[0]->timerIrqHandler(); +void BusMasterImpl::timerIrqHandler() { + const auto uart = NRF_UART0; + const auto timer = NRF_TIMER1; + const auto egu = NRF_EGU1; + + // clear interrupt flag + timer->EVENTS_COMPARE[0] = 0; + + if (state == State::BREAK) { + gpio::setOutput(this->txPin, true); + + // restart timer for pause (half bit) + timer->CC[0] = TIMER_CLOCK / (BAUD_RATE * 2); + timer->TASKS_CLEAR = TRIGGER; + this->state = State::PAUSE; + } else if (state == State::PAUSE) { + // end of break signal + //Debug::toggleBlueLed(); + gpio::setOutput(this->txPin, true); + + // reconfigure uart for transmission + uart->ENABLE = 0; + uart->EVENTS_RXDRDY = 0; + uart->EVENTS_TXDRDY = 0; + uart->PSEL.TXD = this->txPin; + uart->BAUDRATE = N(UARTE_BAUDRATE_BAUDRATE, Baud19200); + uart->INTENSET = N(UART_INTENSET_RXDRDY, Set);// | N(UART_INTENSET_TXDRDY, Set); + uart->ENABLE = N(UART_ENABLE_ENABLE, Enabled); + + // start transfer with sync byte + uart->TASKS_STARTRX = TRIGGER; // -> EVENTS_RXRDY + uart->TASKS_STARTTX = TRIGGER; // -> EVENTS_TXRDY + uart->TXD = 0x55; + + // restart timer for rx timeout (two characters = 20 bit) + timer->CC[0] = (20 * TIMER_CLOCK) / BAUD_RATE; + timer->TASKS_CLEAR = TRIGGER; + + // expect receiving the sync byte + this->state = State::SYNC; + } else { + // receive timeout + //Debug::toggleRedLed(); + + // stop timer + timer->TASKS_STOP = TRIGGER; + + // inform event loop if tx or rx operation has finished + if (this->txState == TxState::END) { + //Debug::toggleRedLed(); + this->txState = TxState::FINISHED; + egu->TASKS_TRIGGER[1] = TRIGGER; + } else if (this->rxState == RxState::ACTIVE) { + this->rxState = RxState::FINISHED; + egu->TASKS_TRIGGER[0] = TRIGGER; + } + + // return to idle state + this->state = State::IDLE; + + // now the next transfer will start either on send by the master or on request by a node + } } diff --git a/software/system/src/nrf52/BusMasterImpl.hpp b/software/system/src/nrf52/BusMasterImpl.hpp index 46b5539..04fb391 100644 --- a/software/system/src/nrf52/BusMasterImpl.hpp +++ b/software/system/src/nrf52/BusMasterImpl.hpp @@ -6,10 +6,19 @@ #include +extern "C" { +void UARTE0_UART0_IRQHandler(); +void TIMER1_IRQHandler(); +} + class BusMasterImpl : public BusMaster, public Loop::Handler2 { + friend void UARTE0_UART0_IRQHandler(); + friend void TIMER1_IRQHandler(); public: /** * Constructor + * @param rxPin receive pin from LIN driver + * @param txPin transmit pin to LIN driver */ BusMasterImpl(int rxPin, int txPin); @@ -18,42 +27,64 @@ class BusMasterImpl : public BusMaster, public Loop::Handler2 { void handle() override; +protected: + void startReceive(const ReceiveParameters &p); + void startSend(const SendParameters &p); + void startBreak(); + void uartIrqHandler(); void timerIrqHandler(); -protected: - + int rxPin; int txPin; - NRF_UART_Type *uart; - NRF_TIMER_Type *timer; - enum State { + // state + enum class State : uint8_t { + // idle, waiting for receive/send by application or a request from a node + IDLE, + + // sending break signal BREAK, + PAUSE, + + // sending sync byte SYNC, - RX, - REQUEST - }; - State volatile state; - // transmit buffer - uint8_t const *volatile txData; - int volatile txLength; - int volatile txIndex; + // receive until timeout or send until last character + TRANSFER, - // receive buffer - uint8_t *volatile rxData; - int volatile rxLength; - int volatile rxIndex; - bool rxReady; - std::function onTransferred; + // finished, waiting for handling in event loop + FINISHED, + }; + volatile State state = State::IDLE; - // request buffer - uint8_t requestData[1]; - int volatile requestIndex; - bool requestReady; - std::function onRequest; + // rx + enum class RxState : uint8_t { + IDLE, + FINISHED, + PENDING, + ACTIVE + }; + volatile RxState rxState = RxState::IDLE; + uint8_t *rxBegin; + uint8_t *rxEnd; + uint8_t *rxData; + // tx + enum class TxState : uint8_t { + IDLE, + FINISHED, + PENDING, + ACTIVE, + END + }; + volatile TxState txState = TxState::IDLE; + const uint8_t *txBegin; + const uint8_t *txEnd; + const uint8_t *txData; + uint8_t txByte; + // lists for coroutines waiting for receive or send to complete Waitlist receiveWaitlist; Waitlist sendWaitlist; }; diff --git a/software/system/src/nrf52/FlashImpl.cpp b/software/system/src/nrf52/FlashImpl.cpp index ecf7a0b..f6e7379 100644 --- a/software/system/src/nrf52/FlashImpl.cpp +++ b/software/system/src/nrf52/FlashImpl.cpp @@ -1,11 +1,21 @@ #include "FlashImpl.hpp" #include "nrf52.hpp" +#include +/* + https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fmemory.html&cp=4_0_0_3_1_1&anchor=flash + https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fnvmc.html&cp=4_0_0_3_2 + + Resources: + NRF_NVMC +*/ FlashImpl::FlashImpl(uint32_t baseAddress, int sectorCount, int sectorSize) - : baseAddress(baseAddress), sectorCount(sectorCount), sectorSize(sectorSize & ~(PAGE_SIZE - 1)) + : baseAddress(baseAddress), sectorCount(sectorCount), sectorSize(sectorSize) { + assert((baseAddress & (PAGE_SIZE - 1)) == 0); + assert((sectorSize & (PAGE_SIZE - 1)) == 0); } Flash::Info FlashImpl::getInfo() { diff --git a/software/system/src/nrf52/FlashImpl.hpp b/software/system/src/nrf52/FlashImpl.hpp index e5c2410..ab5f836 100644 --- a/software/system/src/nrf52/FlashImpl.hpp +++ b/software/system/src/nrf52/FlashImpl.hpp @@ -10,7 +10,10 @@ */ class FlashImpl : public Flash { public: + // size of a page that has to be erased at once static constexpr int PAGE_SIZE = 4096; + + // size of a block that has to be written at once static constexpr int BLOCK_SIZE = 4; /** diff --git a/software/system/src/nrf52/Radio.cpp b/software/system/src/nrf52/Radio.cpp index a90043a..2404097 100644 --- a/software/system/src/nrf52/Radio.cpp +++ b/software/system/src/nrf52/Radio.cpp @@ -30,9 +30,9 @@ NRF_PPI CH[27]: RADIO->EVENTS_END -> TIMER0->TASKS_CAPTURE[2] NRF_EGU0 - TRIGGER[0]: energy detection - TRIGGER[1]: receive queue - TRIGGER[2]: send queue + TRIGGERED[0]: energy detection + TRIGGERED[1]: received a packet + TRIGGERED[2]: send operation has finished Glossary: CCA: Clear Channel Assessment (-> ED and/or carrier detection) @@ -565,7 +565,7 @@ void handle() { } } - // check receive queue + // check if a packet was received if (NRF_EGU0->EVENTS_TRIGGERED[1]) { NRF_EGU0->EVENTS_TRIGGERED[1] = 0; do { diff --git a/software/system/src/nrf52/SpiMasterImpl.cpp b/software/system/src/nrf52/SpiMasterImpl.cpp index 4c31dd1..adeef90 100644 --- a/software/system/src/nrf52/SpiMasterImpl.cpp +++ b/software/system/src/nrf52/SpiMasterImpl.cpp @@ -17,14 +17,14 @@ // SpiMasterDevice -SpiMasterImpl::SpiMasterImpl(int index, int sckPin, int mosiPin, int misoPin, int dcPin) +SpiMasterImpl::SpiMasterImpl(int sckPin, int mosiPin, int misoPin, int dcPin) : misoPin(misoPin), sharedPin(misoPin == dcPin) { // configure SCK pin: output, low on idle gpio::configureOutput(sckPin); NRF_SPIM3->PSEL.SCK = sckPin; - // configure MOSI pin: output, high on ilde + // configure MOSI pin: output, high on idle gpio::setOutput(mosiPin, true); gpio::configureOutput(mosiPin); NRF_SPIM3->PSEL.MOSI = mosiPin; @@ -60,7 +60,7 @@ void SpiMasterImpl::handle() { NRF_SPIM3->EVENTS_END = 0; clearInterrupt(SPIM3_IRQn); - // disable SPI + // disable SPI (indicates idle state) NRF_SPIM3->ENABLE = 0; // check for more transfers @@ -83,8 +83,8 @@ void SpiMasterImpl::startTransfer(const SpiMaster::Parameters &p) { // check if MISO and DC (data/command) are on the same pin if (this->sharedPin) { - if (channel.writeOnly) { - // write only: use MISO pin for DC (command/data) signal + if (channel.mode != Channel::Mode::NONE) { + // DC (data/command signal) overrides MISO, i.e. write-only mode NRF_SPIM3->PSEL.MISO = gpio::DISCONNECTED; NRF_SPIM3->PSELDCX = this->misoPin; //configureOutput(this->dcPin); // done automatically by hardware @@ -96,7 +96,7 @@ void SpiMasterImpl::startTransfer(const SpiMaster::Parameters &p) { } // set command/data length - NRF_SPIM3->DCXCNT = p.writeCount >> 31; // 0 for data and 0xf for command + NRF_SPIM3->DCXCNT = channel.mode == Channel::Mode::COMMAND ? 0xf : 0; // 0 for data and 0xf for command // set write data NRF_SPIM3->TXD.MAXCNT = p.writeCount; @@ -108,14 +108,14 @@ void SpiMasterImpl::startTransfer(const SpiMaster::Parameters &p) { // enable and start NRF_SPIM3->ENABLE = N(SPIM_ENABLE_ENABLE, Enabled); - NRF_SPIM3->TASKS_START = TRIGGER; + NRF_SPIM3->TASKS_START = TRIGGER; // -> END } // SpiMasterImpl::Channel -SpiMasterImpl::Channel::Channel(SpiMasterImpl &master, int csPin, bool writeOnly) - : master(master), csPin(csPin), writeOnly(writeOnly) +SpiMasterImpl::Channel::Channel(SpiMasterImpl &master, int csPin, Mode mode) + : master(master), csPin(csPin), mode(mode) { // configure CS pin: output, high on idle gpio::setOutput(csPin, true); @@ -127,8 +127,8 @@ Awaitable SpiMasterImpl::Channel::transfer(int writeCount { // start transfer immediately if SPI is idle if (!NRF_SPIM3->ENABLE) { - Parameters parameters{this, writeCount, writeData, readCount, readData}; - this->master.startTransfer(parameters); + Parameters p{this, writeCount, writeData, readCount, readData}; + this->master.startTransfer(p); } return {master.waitlist, this, writeCount, writeData, readCount, readData}; @@ -144,6 +144,10 @@ void SpiMasterImpl::Channel::transferBlocking(int writeCount, const void *writeD __NOP(); } + // clear pending interrupt flag and disable SPI + NRF_SPIM3->EVENTS_END = 0; + NRF_SPIM3->ENABLE = 0; + Parameters parameters{this, writeCount, writeData, readCount, readData}; this->master.startTransfer(parameters); @@ -155,5 +159,8 @@ void SpiMasterImpl::Channel::transferBlocking(int writeCount, const void *writeD if (!running) { NRF_SPIM3->EVENTS_END = 0; clearInterrupt(SPIM3_IRQn); + + // disable SPI + NRF_SPIM3->ENABLE = 0; } } diff --git a/software/system/src/nrf52/SpiMasterImpl.hpp b/software/system/src/nrf52/SpiMasterImpl.hpp index 1820a68..697ad83 100644 --- a/software/system/src/nrf52/SpiMasterImpl.hpp +++ b/software/system/src/nrf52/SpiMasterImpl.hpp @@ -5,7 +5,7 @@ #include "gpio.hpp" /** - * Implementation of SPI hardware interface for nrf52 platform + * Implementation of SPI hardware interface for nrf52 with multiple virtual channels */ class SpiMasterImpl : public Loop::Handler2 { public: @@ -15,9 +15,9 @@ class SpiMasterImpl : public Loop::Handler2 { * @param sckPin clock pin * @param mosiPin master out slave in pin * @param misoPin master in slave out pin - * @param dcPin data/command pin e.g. for displays + * @param dcPin data/command pin e.g. for displays, can be same as MISO for read-only devices */ - SpiMasterImpl(int index, int sckPin, int mosiPin, int misoPin, int dcPin = gpio::DISCONNECTED); + SpiMasterImpl(int sckPin, int mosiPin, int misoPin, int dcPin = gpio::DISCONNECTED); void handle() override; @@ -26,6 +26,8 @@ class SpiMasterImpl : public Loop::Handler2 { int misoPin; bool sharedPin; + + // list for coroutines waiting for transfer to complete Waitlist waitlist; @@ -34,13 +36,20 @@ class SpiMasterImpl : public Loop::Handler2 { */ class Channel : public SpiMaster { public: + // mode of data/command signal + enum class Mode { + NONE, + COMMAND, // set DC low + DATA // set DC high + }; + /** * Constructor * @param device the SPI device to operate on * @param csPin chip select pin of the slave - * @param writeOnly ture if we only write data and can use MISO as DC (data/command) signal (e.g. for a display) + * @param mode mode of data/command pin */ - Channel(SpiMasterImpl &master, int csPin, bool writeOnly = false); + Channel(SpiMasterImpl &master, int csPin, Mode mode = Mode::NONE); Awaitable transfer(int writeCount, const void *writeData, int readCount, void *readData) override; void transferBlocking(int writeCount, const void *writeData, int readCount, void *readData) override; @@ -48,6 +57,6 @@ class SpiMasterImpl : public Loop::Handler2 { SpiMasterImpl &master; int csPin; - bool writeOnly; + Mode mode; }; }; diff --git a/software/system/src/nrf52/nrf52.hpp b/software/system/src/nrf52/nrf52.hpp index c5a05f9..a47dce8 100644 --- a/software/system/src/nrf52/nrf52.hpp +++ b/software/system/src/nrf52/nrf52.hpp @@ -6,6 +6,7 @@ #include "system/nrf52840_bitfields.h" #pragma GCC diagnostic pop + // construct bitfield from value #define V(field, value) ((value) << field##_Pos) @@ -26,9 +27,7 @@ constexpr int GENERATED = 1; - -// nvic -// see NVIC_Type in system/core_cm4.h +// NVIC (nested vectored interrupt controller) inline void enableInterrupt(int n) { NVIC->ISER[n >> 5] = 1 << (n & 31); } diff --git a/software/system/src/stm32f0/BusNodeImpl.cpp b/software/system/src/stm32f0/BusNodeImpl.cpp index be9fa8c..a9bbf37 100644 --- a/software/system/src/stm32f0/BusNodeImpl.cpp +++ b/software/system/src/stm32f0/BusNodeImpl.cpp @@ -1,19 +1,330 @@ #include "BusNodeImpl.hpp" +#include "defs.hpp" +#include "gpio.hpp" +#include "boardConfig.hpp" // CLOCK +#include "Debug.hpp" -BusNodeImpl::BusNodeImpl() { +/* + Reference manual: https://www.st.com/resource/en/reference_manual/dm00031936-stm32f0x1stm32f0x2stm32f0x8-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + Data sheet: https://www.st.com/resource/en/datasheet/stm32f042f6.pdf https://www.st.com/resource/en/datasheet/stm32f051r8.pdf + + Resources: + USART1: Bus (reference manual section 27) + TIM16: Timeout (reference manual section 20) + IRQ17: Transfer complete (https://community.arm.com/support-forums/f/architectures-and-processors-forum/4070/using-interrupts-not-implemented-as-software-interrupts) +*/ + +using namespace gpio; + +constexpr int COMPLETE_IRQ = 17; +constexpr int REQUEST_INTERVAL = 50 * 20; // 50ms +constexpr int REQUEST_BYTE = 0xff; + +namespace { + +// for alternate functions, see Table 14 and 15 in data sheet +inline PinFunction rxFunction(int pin) { + assert(pin == PA(10) || pin == PB(7)); + return {pin, pin == PA(10) ? 1 : 0}; +} + +inline PinFunction txFunction(int pin) { + assert(pin == PA(9) || pin == PB(6)); + return {pin, pin == PA(9) ? 1 : 0}; +} + +// instance pointer used in interrupt handlers +BusNodeImpl *busNode; + +} + +BusNodeImpl::BusNodeImpl(int rxPin, int txPin) : rxPin(rxPin) { + const auto uart = USART1; + const auto timer = TIM16; + + // set instance pointer + busNode = this; + + // configure UART pins + configureAlternateOutput(rxFunction(rxPin)); + configureAlternateOutput(txFunction(txPin)); + + // initialize UART + RCC->APB2ENR = RCC->APB2ENR | RCC_APB2ENR_USART1EN; // clock enable + uart->BRR = (CLOCK + 9600) / 19200; // baud rate + //uart->CR2 = USART_CR2_LINEN // LIN enable + // | USART_CR2_LBDIE; // LIN break interrupt enable + uart->CR1 = USART_CR1_UE // enable + | USART_CR1_RE // rx enable + | USART_CR1_TE // tx enable + | USART_CR1_RXNEIE; // rx interrupt enable + enableInterrupt(USART1_IRQn); + + // initialize timer + RCC->APB2ENR = RCC->APB2ENR | RCC_APB2ENR_TIM16EN; // clock enable + timer->PSC = (CLOCK + 9600) / 19200 + 1; // prescaler for bit time (f = CLOCK / (PSC + 1) -> PSC = CLOCK / f - 1) + timer->DIER = TIM_DIER_CC1IE; // interrupt enable for CC1 + timer->CCR1 = REQUEST_INTERVAL; // set timeout, but do not start timer yet + enableInterrupt(TIM16_IRQn); + // add to list of handlers Loop::handlers.add(*this); } Awaitable BusNodeImpl::receive(int &length, uint8_t *data) { + // start receiving immediately if no rx is pending and bus is idle + if (this->rxState == RxState::IDLE) { + ReceiveParameters p{&length, data}; + startReceive(p); + } + return {this->receiveWaitlist, &length, data}; } Awaitable BusNodeImpl::send(int length, uint8_t const *data) { + if (length <= 0) + return {}; + + // start sending immediately if no tx is pending and bus is idle + if (this->txState == TxState::IDLE) { + //Debug::toggleRedLed(); + SendParameters p{length, data}; + startSend(p); + } + return {this->sendWaitlist, length, data}; } void BusNodeImpl::handle() { + if (isInterruptPending(COMPLETE_IRQ)) { + // check if tx or rx operation has finished + if (this->txState == TxState::FINISHED) { + // send operation complete + this->txState = TxState::IDLE; + + // check if a next send operation is pending + this->sendWaitlist.visitSecond([this](const SendParameters &p) { + startSend(p); + }); + + // resume first waiting coroutine + this->sendWaitlist.resumeFirst([](const SendParameters &p) { + return true; + }); + } else if (this->rxState == RxState::FINISHED) { + // receive operation complete + int rxLength = this->rxData - this->rxBegin; + this->rxState = RxState::IDLE; + + // check if a next receive operation is pending + this->receiveWaitlist.visitSecond([this](const ReceiveParameters &p) { + startReceive(p); + }); + + // resume first waiting coroutine + this->receiveWaitlist.resumeFirst([rxLength](const ReceiveParameters &p) { + *p.length = rxLength; + return true; + }); + } + + // clear pending interrupt flag at NVIC + clearInterrupt(COMPLETE_IRQ); + } +} + +void BusNodeImpl::startReceive(const ReceiveParameters &p) { + this->rxState = RxState::PENDING; + this->rxBegin = p.data; + this->rxEnd = p.data + *p.length; + + // wait for master to start a transfer +} + +void BusNodeImpl::startSend(const SendParameters &p) { + this->txState = TxState::PENDING; + this->txBegin = p.data; + this->txEnd = p.data + p.length; + + // request a transfer when bus is idle + if (this->state == State::IDLE) + startRequest(); +} + +void BusNodeImpl::startRequest() { + const auto uart = USART1; + const auto timer = TIM16; + + // send a single start bit to inform the master that we want to send data + uart->TDR = REQUEST_BYTE; + + // repeat in case the master does not react + timer->CCR1 = REQUEST_INTERVAL; // set timeout + timer->CR1 = TIM_CR1_CEN; // start imer +} + + +// interrupt handlers + +void USART1_IRQHandler() { + busNode->usartIrqHandler(); +} + +void BusNodeImpl::usartIrqHandler() { + const auto uart = USART1; + const auto timer = TIM16; + + // stop and reset timer + timer->CR1 = 0; // stop timer + timer->EGR = TIM_EGR_UG; // reset timer + + // clear timer interrupt in case it triggered just before stop + timer->SR = ~TIM_SR_CC1IF; + clearInterrupt(TIM16_IRQn); + + // get interrupt status flags + auto isr = uart->ISR; + + if (isr & USART_ISR_LBDF) { + // break detected + uart->ICR = USART_ICR_LBDCF; + + // start receive timeout + timer->CCR1 = 20; // 2 characters = 20 bits + timer->CR1 = TIM_CR1_CEN; // start timer + + // now wait for sync + this->state = State::SYNC; + } + if (isr & USART_ISR_RXNE) { + // received a byte + uint8_t b = uart->RDR; + + switch (this->state) { + case State::IDLE: + // restart timer when tx is pending + if (this->txState >= TxState::PENDING) { + timer->CR1 = TIM_CR1_CEN; // restart timer + } + break; + case State::SYNC: + // check if sync byte was received correctly + if (b != 0x55) { + // go to error state and skip incoming bytes until a timeout occurs + this->state = State::ERROR; + } else { + // sync ok: now start to transfer data + if (this->rxState >= RxState::PENDING) { + this->rxState = RxState::ACTIVE; + this->rxData = this->rxBegin; + } + + // send first byte if tx is pending + if (this->txState >= TxState::PENDING) { + this->txState = TxState::ACTIVE; + auto data = this->txBegin; + this->txData = data + 1; + b = *data; + uart->TDR = b; + this->txByte = b; + } else { + // tx is idle: stop transmit + //uart->TASKS_STOPTX = TRIGGER; + } + + // now in transfer state + this->state = State::TRANSFER; + } + timer->CR1 = TIM_CR1_CEN; // restart timer + break; + case State::TRANSFER: + // received next byte + + // when tx is active, check if received byte is equal to the last sent byte + if (this->txState == TxState::ACTIVE) { + // check if byte was transferred ok and the current state of the bus is high + if (b == this->txByte && gpio::readInput(this->rxPin)) { + // byte was transferred ok + auto data = this->txData; + if (data < this->txEnd) { + // send next byte + this->txData = data + 1; + b = *data; + uart->TDR = b; + this->txByte = b; + } else { + // end: stop transmit and set tx state to success + //uart->TASKS_STOPTX = TRIGGER; + this->txState = TxState::END; + } + } else { + // error: stop transmit as probably another node won the bus arbitration + //uart->TASKS_STOPTX = TRIGGER; + this->txState = TxState::PENDING; + } + } else if (this->txState == TxState::END) { + // error: extra byte received after successful transmission + this->txState = TxState::PENDING; + } + + // check if receive is pending + if (this->rxState == RxState::ACTIVE) { + auto data = this->rxData; + if (data < this->rxEnd) { + // add next byte to receive buffer + this->rxData = data + 1; + *data = b; + } + } + + timer->CR1 = TIM_CR1_CEN; // restart timer + break; + case State::ERROR: + timer->CR1 = TIM_CR1_CEN; // restart timer + break; + } + } +} + +void TIM16_IRQHandler() { + busNode->timerIrqHandler(); +} + +void BusNodeImpl::timerIrqHandler() { + const auto timer = TIM16; + + // clear interrupt flag + timer->SR = ~TIM_SR_CC1IF; + + // stop and reset timer + timer->CR1 = 0; // stop timer + timer->EGR = TIM_EGR_UG; // reset timer + + switch (this->state) { + case State::TRANSFER: + // inform event loop if tx or rx operation has finished + if (this->txState == TxState::END) { + this->txState = TxState::FINISHED; + triggerInterrupt(COMPLETE_IRQ); + } else if (this->rxState == RxState::ACTIVE) { + this->rxState = RxState::FINISHED; + triggerInterrupt(COMPLETE_IRQ); + } + + // return to idle state + this->state = State::IDLE; + break; + default: + // timeout in IDLE, SYNC or ERROR state + Debug::toggleGreenLed(); + + // return to idle state + this->state = State::IDLE; + // request a transfer when tx is pending + if (this->txState >= TxState::PENDING) + startRequest(); + break; + } } diff --git a/software/system/src/stm32f0/BusNodeImpl.hpp b/software/system/src/stm32f0/BusNodeImpl.hpp index 2a19894..4ab8bc8 100644 --- a/software/system/src/stm32f0/BusNodeImpl.hpp +++ b/software/system/src/stm32f0/BusNodeImpl.hpp @@ -4,12 +4,21 @@ #include "Loop.hpp" +extern "C" { +void USART1_IRQHandler(); +void TIM16_IRQHandler(); +} + class BusNodeImpl : public BusNode, public Loop::Handler2 { + friend void USART1_IRQHandler(); + friend void TIM16_IRQHandler(); public: /** * Constructor + * @param rxPin receive pin from LIN driver + * @param txPin transmit pin to LIN driver */ - BusNodeImpl(); + BusNodeImpl(int rxPin, int txPin); [[nodiscard]] Awaitable receive(int &length, uint8_t *data) override; [[nodiscard]] Awaitable send(int length, uint8_t const *data) override; @@ -17,6 +26,58 @@ class BusNodeImpl : public BusNode, public Loop::Handler2 { void handle() override; protected: + void startReceive(const ReceiveParameters &p); + void startSend(const SendParameters &p); + void startRequest(); + + void usartIrqHandler(); + void timerIrqHandler(); + + int rxPin; + + // state + enum class State : uint8_t { + // idle, waiting for receive/send by master and sending a request from time to time if send is pending + IDLE, + + // receiving sync byte + SYNC, + + // receive until timeout or send until last character + TRANSFER, + + // error when receiving sync byte + ERROR + }; + volatile State state = State::IDLE; + + // rx + enum class RxState : uint8_t { + IDLE, + FINISHED, + PENDING, + ACTIVE + }; + volatile RxState rxState = RxState::IDLE; + uint8_t *rxBegin; + uint8_t *rxEnd; + uint8_t *rxData; + + // tx + enum class TxState : uint8_t { + IDLE, + FINISHED, + PENDING, + ACTIVE, + END + }; + volatile TxState txState = TxState::IDLE; + const uint8_t *txBegin; + const uint8_t *txEnd; + const uint8_t *txData; + uint8_t txByte; + + // lists for coroutines waiting for receive or send to complete Waitlist receiveWaitlist; Waitlist sendWaitlist; }; diff --git a/software/system/src/stm32f0/FlashImpl.cpp b/software/system/src/stm32f0/FlashImpl.cpp index ad85337..41f3efc 100644 --- a/software/system/src/stm32f0/FlashImpl.cpp +++ b/software/system/src/stm32f0/FlashImpl.cpp @@ -1,13 +1,20 @@ #include "FlashImpl.hpp" #include "defs.hpp" +#include -// https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fmemory.html&cp=4_0_0_3_1_1&anchor=flash -// https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fnvmc.html&cp=4_0_0_3_2 +/* + Reference manual: https://www.st.com/resource/en/reference_manual/dm00031936-stm32f0x1stm32f0x2stm32f0x8-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + + Resources: + FLASH: Flash controller (reference manual section 3) +*/ FlashImpl::FlashImpl(uint32_t baseAddress, int sectorCount, int sectorSize) - : baseAddress(baseAddress), sectorCount(sectorCount), sectorSize(sectorSize & ~(PAGE_SIZE - 1)) + : baseAddress(baseAddress), sectorCount(sectorCount), sectorSize(sectorSize) { + assert((baseAddress & (PAGE_SIZE - 1)) == 0); + assert((sectorSize & (PAGE_SIZE - 1)) == 0); } Flash::Info FlashImpl::getInfo() { @@ -23,6 +30,9 @@ void FlashImpl::eraseSectorBlocking(int sectorIndex) { // erase pages for (int i = 0; i < this->sectorSize; i += PAGE_SIZE) { + // set page erase mode + FLASH->CR = FLASH_CR_PER; + // set address of page to erase FLASH->AR = address + i; diff --git a/software/system/src/stm32f0/FlashImpl.hpp b/software/system/src/stm32f0/FlashImpl.hpp index 8ab59bf..a482e39 100644 --- a/software/system/src/stm32f0/FlashImpl.hpp +++ b/software/system/src/stm32f0/FlashImpl.hpp @@ -5,11 +5,13 @@ /** * Implementation of flash interface for stm32f0 - * See section 3 in reference manual: https://www.st.com/resource/en/reference_manual/dm00031936-stm32f0x1stm32f0x2stm32f0x8-advanced-armbased-32bit-mcus-stmicroelectronics.pdf */ class FlashImpl : public Flash { public: + // size of a page that has to be erased at once static constexpr int PAGE_SIZE = 1024; + + // size of a block that has to be written at once static constexpr int BLOCK_SIZE = 2; /** diff --git a/software/system/src/stm32f0/SpiMasterImpl.cpp b/software/system/src/stm32f0/SpiMasterImpl.cpp index 76c435f..dd9d056 100644 --- a/software/system/src/stm32f0/SpiMasterImpl.cpp +++ b/software/system/src/stm32f0/SpiMasterImpl.cpp @@ -1,17 +1,23 @@ #include "SpiMasterImpl.hpp" #include "defs.hpp" +#include "gpio.hpp" #include /* + Reference manual: https://www.st.com/resource/en/reference_manual/dm00031936-stm32f0x1stm32f0x2stm32f0x8-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + Data sheet: https://www.st.com/resource/en/datasheet/stm32f042f6.pdf + Dependencies: Config: SPI_CONTEXTS: Configuration of SPI channels (can share the same SPI peripheral) Resources: - SPI1 - TIM14 + SPI1: SPI master (reference manual section 28) + DMA1 (reference manual section 10) + Channel2: Read (reference manual table 29) + Channel3: Write GPIO CS-pins */ @@ -20,7 +26,7 @@ using namespace gpio; namespace { -// for alternate functions, see STM32F042x4 STM32F042x6 datasheet +// for alternate functions, see Table 14 and 15 in datasheet inline PinFunction sckFunction(int pin) { assert(pin == PA(5) || pin == PB(3)); return {pin, 0}; @@ -79,8 +85,9 @@ constexpr int SPI_CR1 = SPI_CR1_SPE | SPI_CR1_MSB_FIRST | SPI_CR1_DIV8; -constexpr int SPI_CR2 = SPI_CR2_DATA_SIZE(16) - | SPI_CR2_SSOE; +constexpr int SPI_CR2 = SPI_CR2_DATA_SIZE(8) + | SPI_CR2_FRXTH + | SPI_CR2_SSOE; // single master mode } @@ -93,67 +100,141 @@ SpiMasterImpl::SpiMasterImpl(int index, int sckPin, int mosiPin, int misoPin) { configureAlternateOutput(mosiFunction(mosiPin)); configureAlternateOutput(misoFunction(misoPin)); - // initialize TIM14 - RCC->APB1ENR = RCC->APB1ENR | RCC_APB1ENR_TIM14EN; - TIM14->DIER = TIM_DIER_CC1IE; // interrupt enable for CC1 + // initialize DMA + RCC->AHBENR = RCC->AHBENR | RCC_AHBENR_DMAEN; + DMA1_Channel2->CPAR = (uint32_t)&SPI1->DR; + DMA1_Channel3->CPAR = (uint32_t)&SPI1->DR; + RCC->AHBENR = RCC->AHBENR & ~RCC_AHBENR_DMAEN; // add to list of handlers Loop::handlers.add(*this); } void SpiMasterImpl::handle() { - if (TIM14->SR & TIM_SR_CC1IF) { - //if (SPI1->SR & SPI_SR_TXE) { - // set CS pin high - gpio::setOutput(this->csPin, true); - - // clear pending interrupt flags at peripheral and NVIC - TIM14->SR = ~TIM_SR_CC1IF; - clearInterrupt(TIM14_IRQn); - - // read - //int x = SPI1->DR; - - // disable timer and SPI - TIM14->CR1 = 0; - SPI1->CR1 = 0; - RCC->APB2ENR = RCC->APB2ENR & ~RCC_APB2ENR_SPI1EN; - - // check for more transfers - this->waitlist.visitSecond([this](const SpiMaster::Parameters &p) { - startTransfer(p); - }); - - // resume first waiting coroutine - this->waitlist.resumeFirst([](const SpiMaster::Parameters &p) { - return true; - }); + // check if read DMA has completed + if ((DMA1->ISR & DMA_ISR_TCIF2) != 0) { + // clear interrupt flags at DMA and NVIC + DMA1->IFCR = DMA_IFCR_CTCIF2; + clearInterrupt(DMA1_Ch2_3_DMA2_Ch1_2_IRQn); + + if (update()) { + // end of transfer + + // disable clocks + RCC->APB2ENR = RCC->APB2ENR & ~RCC_APB2ENR_SPI1EN; + RCC->AHBENR = RCC->AHBENR & ~RCC_AHBENR_DMAEN; + + // check for more transfers + this->waitlist.visitSecond([this](const SpiMaster::Parameters &p) { + startTransfer(p); + }); + + // resume first waiting coroutine + this->waitlist.resumeFirst([](const SpiMaster::Parameters &p) { + return true; + }); + } } } void SpiMasterImpl::startTransfer(const SpiMaster::Parameters &p) { auto &channel = *reinterpret_cast(p.config); - // initialize SPI + // enable clocks RCC->APB2ENR = RCC->APB2ENR | RCC_APB2ENR_SPI1EN; - SPI1->CR2 = SPI_CR2; - SPI1->CR1 = SPI_CR1; + RCC->AHBENR = RCC->AHBENR | RCC_AHBENR_DMAEN; - // set CS pin low and store it - gpio::setOutput(channel.csPin, false); + // set transfer state this->csPin = channel.csPin; + this->readCount = p.readCount; + this->readAddress = (uint32_t)p.readData; + this->writeCount = p.writeCount; + this->writeAddress = (uint32_t)p.writeData; + + // update transfer + update(); + + // now wait for DMA_ISR_TCIF2 flag +} + +bool SpiMasterImpl::update() { + if (this->readCount > 0) { + SPI1->CR1 = 0; + DMA1_Channel2->CCR = 0; + DMA1_Channel3->CCR = 0; + SPI1->CR2 = SPI_CR2 | SPI_CR2_RXDMAEN; // first enable receive DMA according to data sheet + if (this->writeCount > 0) { + // read and write + int count = min(this->readCount, this->writeCount); + DMA1_Channel2->CNDTR = count; + DMA1_Channel2->CMAR = this->readAddress; + DMA1_Channel2->CCR = DMA_CCR_EN // enable read channel + | DMA_CCR_TCIE // transfer complete interrupt enable + | DMA_CCR_MINC; // auto-increment memory + DMA1_Channel3->CNDTR = count; + DMA1_Channel3->CMAR = this->writeAddress; + DMA1_Channel3->CCR = DMA_CCR_EN // enable write channel + | DMA_CCR_DIR // read from memory + | DMA_CCR_MINC; // auto-increment memory + + this->readAddress += count; + this->writeAddress += count; + this->readCount -= count; + this->writeCount -= count; + } else { + // read only + DMA1_Channel2->CNDTR = this->readCount; + DMA1_Channel2->CMAR = this->readAddress; + DMA1_Channel2->CCR = DMA_CCR_EN // enable read channel + | DMA_CCR_TCIE // transfer complete interrupt enable + | DMA_CCR_MINC; // auto-increment memory + DMA1_Channel3->CNDTR = this->readCount; + DMA1_Channel3->CMAR = (uint32_t)&this->writeDummy; // write from dummy + DMA1_Channel3->CCR = DMA_CCR_EN // enable write channel + | DMA_CCR_DIR; // read from memory + + this->readCount = 0; + } + } else if (this->writeCount > 0) { + // write only + SPI1->CR1 = 0; + DMA1_Channel2->CCR = 0; + DMA1_Channel3->CCR = 0; + SPI1->CR2 = SPI_CR2 | SPI_CR2_RXDMAEN; // first enable receive DMA according to data sheet + + DMA1_Channel2->CNDTR = this->writeCount; + DMA1_Channel2->CMAR = (uint32_t)&this->readDummy; // read into dummy + DMA1_Channel2->CCR = DMA_CCR_EN // enable read channel + | DMA_CCR_TCIE; // transfer complete interrupt enable + DMA1_Channel3->CNDTR = this->writeCount; + DMA1_Channel3->CMAR = this->writeAddress; + DMA1_Channel3->CCR = DMA_CCR_EN // enable write channel + | DMA_CCR_DIR // read from memory + | DMA_CCR_MINC; // auto-increment memory + + this->writeCount = 0; + } else { + // end of transfer + + // set CS pin high + gpio::setOutput(this->csPin, true); + + // disable SPI and DMA + SPI1->CR1 = 0; + DMA1_Channel2->CCR = 0; + DMA1_Channel3->CCR = 0; - // prepare timer - TIM14->PSC = (2 << ((SPI_CR1 & SPI_CR1_BR_Msk) >> SPI_CR1_BR_Pos)) * 16 - 1; - TIM14->CCR1 = 1; - TIM14->EGR = TIM_EGR_UG; // clear + return true; + } - // write data - // todo: use DMA, now only the first word is transferred - SPI1->DR = *(uint16_t*)p.writeData; + // set CS pin low + gpio::setOutput(this->csPin, false); - // start timer - TIM14->CR1 = TIM_CR1_CEN; + // start SPI + SPI1->CR2 = SPI_CR2 | SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN; + SPI1->CR1 = SPI_CR1; + + return false; } @@ -171,7 +252,7 @@ Awaitable SpiMasterImpl::Channel::transfer(int writeCount void *readData) { // start transfer immediately if SPI is idle - if ((TIM14->CR1 & TIM_CR1_CEN) == 0) { + if (DMA1_Channel2->CCR == 0) { Parameters parameters{this, writeCount, writeData, readCount, readData}; this->master.startTransfer(parameters); } @@ -181,24 +262,35 @@ Awaitable SpiMasterImpl::Channel::transfer(int writeCount void SpiMasterImpl::Channel::transferBlocking(int writeCount, void const *writeData, int readCount, void *readData) { // check if a transfer is running - bool running = (TIM14->CR1 & TIM_CR1_CEN) != 0; + bool running = DMA1_Channel2->CCR != 0; // wait for end of running transfer if (running) { - while (!(TIM14->SR & TIM_SR_CC1IF)) - __NOP(); + do { + while ((DMA1->ISR & DMA_ISR_TCIF2) == 0) + __NOP(); + } while (!this->master.update()); } + // clear pending interrupt flag and disable SPI and DMA + DMA1->IFCR = DMA_IFCR_CTCIF2; + Parameters parameters{this, writeCount, writeData, readCount, readData}; this->master.startTransfer(parameters); // wait for end of transfer - while (!(TIM14->SR & TIM_SR_CC1IF)) - __NOP(); + do { + while ((DMA1->ISR & DMA_ISR_TCIF2) == 0) + __NOP(); + } while (!this->master.update()); - // clear pending interrupt flags at peripheral and NVIC unless a transfer was running which gets handled in handle() + // clear pending interrupt flags at DMA and NVIC unless a transfer was running which gets handled in handle() if (!running) { - TIM14->SR = ~TIM_SR_CC1IF; - clearInterrupt(TIM14_IRQn); + DMA1->IFCR = DMA_IFCR_CTCIF2; + clearInterrupt(DMA1_Ch2_3_DMA2_Ch1_2_IRQn); + + // disable clocks + RCC->APB2ENR = RCC->APB2ENR & ~RCC_APB2ENR_SPI1EN; + RCC->AHBENR = RCC->AHBENR & ~RCC_AHBENR_DMAEN; } } diff --git a/software/system/src/stm32f0/SpiMasterImpl.hpp b/software/system/src/stm32f0/SpiMasterImpl.hpp index 62c55f4..5c054ec 100644 --- a/software/system/src/stm32f0/SpiMasterImpl.hpp +++ b/software/system/src/stm32f0/SpiMasterImpl.hpp @@ -2,11 +2,10 @@ #include "../SpiMaster.hpp" #include "Loop.hpp" -#include "gpio.hpp" /** - * Implementation of SPI hardware interface for nrf52 platform with multiple virtual channels + * Implementation of SPI hardware interface for stm32f0 with multiple virtual channels */ class SpiMasterImpl : public Loop::Handler2 { public: @@ -45,6 +44,14 @@ class SpiMasterImpl : public Loop::Handler2 { protected: void startTransfer(SpiMaster::Parameters const &p); + bool update(); + + uint32_t readAddress; + int readCount; + uint32_t writeAddress; + int writeCount; + uint8_t readDummy; + uint8_t writeDummy = 0; int csPin; Waitlist waitlist; diff --git a/software/system/src/stm32f0/SpiMasterSingle16.cpp b/software/system/src/stm32f0/SpiMasterSingle16.cpp new file mode 100644 index 0000000..c7c1de7 --- /dev/null +++ b/software/system/src/stm32f0/SpiMasterSingle16.cpp @@ -0,0 +1,166 @@ +#include "SpiMasterSingle16.hpp" +#include "defs.hpp" +#include + + +/* + Reference manual: https://www.st.com/resource/en/reference_manual/dm00031936-stm32f0x1stm32f0x2stm32f0x8-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + Data sheet: https://www.st.com/resource/en/datasheet/stm32f042f6.pdf + + Dependencies: + + Config: + SPI_CONTEXTS: Configuration of SPI channels (can share the same SPI peripheral) + + Resources: + SPI1: SPI master (reference manual section 28) + GPIO + CS-pin +*/ + +using namespace gpio; + +namespace { + +// for alternate functions, see STM32F042x4 STM32F042x6 datasheet +inline PinFunction sckFunction(int pin) { + assert(pin == PA(5) || pin == PB(3)); + return {pin, 0}; +} + +inline PinFunction mosiFunction(int pin) { + assert(pin == PA(7) || pin == PB(5)); + return {pin, 0}; +} + +inline PinFunction misoFunction(int pin) { + assert(pin == PA(6) || pin == PB(4)); + return {pin, 0}; +} + + +// CR1 register +// ------------ + +// SPI mode +constexpr int SPI_CR1_OFF = 0; +constexpr int SPI_CR1_FULL_DUPLEX_MASTER = SPI_CR1_MSTR; + +// SPI clock phase and polarity +constexpr int SPI_CR1_CPHA_0 = 0; +constexpr int SPI_CR1_CPHA_1 = SPI_CR1_CPHA; +constexpr int SPI_CR1_CPOL_0 = 0; +constexpr int SPI_CR1_CPOL_1 = SPI_CR1_CPOL; + +// SPI bit order +constexpr int SPI_CR1_LSB_FIRST = SPI_CR1_LSBFIRST; +constexpr int SPI_CR1_MSB_FIRST = 0; + +// SPI prescaler +constexpr int SPI_CR1_DIV2 = 0; +constexpr int SPI_CR1_DIV4 = (SPI_CR1_BR_0); +constexpr int SPI_CR1_DIV8 = (SPI_CR1_BR_1); +constexpr int SPI_CR1_DIV16 = (SPI_CR1_BR_1 | SPI_CR1_BR_0); +constexpr int SPI_CR1_DIV32 = (SPI_CR1_BR_2); +constexpr int SPI_CR1_DIV64 = (SPI_CR1_BR_2 | SPI_CR1_BR_0); +constexpr int SPI_CR1_DIV128 = (SPI_CR1_BR_2 | SPI_CR1_BR_1); +constexpr int SPI_CR1_DIV256 = (SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0); + +// CR2 register +// ------------ + +// SPI data size (8, 16, 32) +constexpr int SPI_CR2_DATA_SIZE(int s) { return (s - 1) << SPI_CR2_DS_Pos; } + + +// configuration + +constexpr int SPI_CR1 = SPI_CR1_SPE + | SPI_CR1_FULL_DUPLEX_MASTER + | SPI_CR1_CPHA_1 | SPI_CR1_CPOL_0 // shift on rising edge, sample on falling edge + | SPI_CR1_MSB_FIRST + | SPI_CR1_DIV8; + +constexpr int SPI_CR2 = SPI_CR2_DATA_SIZE(16) + | SPI_CR2_RXNEIE // RXNE interrupt enable + | SPI_CR2_SSOE; // single master mode + +} + + +// SpiMasterSingle16 + +SpiMasterSingle16::SpiMasterSingle16(int sckPin, int mosiPin, int misoPin, int csPin) : csPin(csPin) { + // configure SPI pins (driven low when SPI is disabled) + configureAlternateOutput(sckFunction(sckPin)); + configureAlternateOutput(mosiFunction(mosiPin)); + configureAlternateOutput(misoFunction(misoPin)); + + // configure CS pin: output, high on idle + gpio::setOutput(csPin, true); + gpio::configureOutput(csPin); + + // initialize TIM14 + RCC->APB1ENR = RCC->APB1ENR | RCC_APB1ENR_TIM14EN; + + // add to list of handlers + Loop::handlers.add(*this); +} + +void SpiMasterSingle16::handle() { + if (SPI1->SR & SPI_SR_RXNE) { + // set CS pin high + gpio::setOutput(this->csPin, true); + + // read data and clear RXNE flag + uint16_t data = SPI1->DR; + + // clear pending interrupt flags at NVIC + clearInterrupt(SPI1_IRQn); + + // disable timer and SPI + SPI1->CR1 = 0; + RCC->APB2ENR = RCC->APB2ENR & ~RCC_APB2ENR_SPI1EN; + + // check for more transfers + this->waitlist.visitSecond([this](const SpiMaster::Parameters &p) { + startTransfer(p); + }); + + // resume first waiting coroutine + this->waitlist.resumeFirst([data](const SpiMaster::Parameters &p) { + *reinterpret_cast(p.readData) = data; + return true; + }); + } +} + +void SpiMasterSingle16::startTransfer(const SpiMaster::Parameters &p) { + // initialize SPI + RCC->APB2ENR = RCC->APB2ENR | RCC_APB2ENR_SPI1EN; + SPI1->CR2 = SPI_CR2; + SPI1->CR1 = SPI_CR1; + + // set CS pin low and store it + gpio::setOutput(this->csPin, false); + + // write data + SPI1->DR = *reinterpret_cast(p.writeData); + + // now wait for SPI_SR_RXNE flag +} + +Awaitable SpiMasterSingle16::transfer(int writeCount, void const *writeData, int readCount, + void *readData) +{ + // start transfer immediately if SPI is idle + if (SPI1->CR1 == 0) { + Parameters parameters{this, writeCount, writeData, readCount, readData}; + this->startTransfer(parameters); + } + + return {waitlist, this, writeCount, writeData, readCount, readData}; +} + +void SpiMasterSingle16::transferBlocking(int writeCount, void const *writeData, int readCount, void *readData) { +} diff --git a/software/system/src/stm32f0/SpiMasterSingle16.hpp b/software/system/src/stm32f0/SpiMasterSingle16.hpp new file mode 100644 index 0000000..e5d6946 --- /dev/null +++ b/software/system/src/stm32f0/SpiMasterSingle16.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include "../SpiMaster.hpp" +#include "Loop.hpp" +#include "gpio.hpp" + + +/** + * Implementation of SPI hardware interface for stm32f0 that transfers a single 16 bit word + */ +class SpiMasterSingle16 : public SpiMaster, public Loop::Handler2 { +public: + /** + * Constructor + * @param index index of device, 1-2 for SPI1 or SPI2 + * @param sckPin clock pin (SPI1: PA5 or PB3) + * @param mosiPin master out slave in pin (SPI1: PA7 or PB5) + * @param misoPin master in slave out pin (SPI1: PA6 or PB4) + */ + SpiMasterSingle16(int sckPin, int mosiPin, int misoPin, int csPin); + + void handle() override; + + // assumes writeCount and readCount to be 2 + Awaitable transfer(int writeCount, void const *writeData, int readCount, void *readData) override; + + // not implemented + void transferBlocking(int writeCount, void const *writeData, int readCount, void *readData) override; + +protected: + void startTransfer(SpiMaster::Parameters const &p); + + + int csPin; + + Waitlist waitlist; +}; diff --git a/software/system/src/stm32f0/defs.hpp b/software/system/src/stm32f0/defs.hpp index 8411d86..f5e6a27 100644 --- a/software/system/src/stm32f0/defs.hpp +++ b/software/system/src/stm32f0/defs.hpp @@ -1,6 +1,7 @@ #pragma once #include "system/stm32f042x6.h" +//#include "system/stm32f051x8.h" @@ -18,6 +19,10 @@ inline bool isInterruptPending(int n) { return (NVIC->ISPR[n >> 5] & (1 << (n & 31))) != 0; } +inline void triggerInterrupt(int n) { + NVIC->ISPR[n >> 5] = 1 << (n & 31); +} + inline void clearInterrupt(int n) { NVIC->ICPR[n >> 5] = 1 << (n & 31); } diff --git a/software/system/src/stm32f0/gpio.hpp b/software/system/src/stm32f0/gpio.hpp index 38b33ad..9a65a42 100644 --- a/software/system/src/stm32f0/gpio.hpp +++ b/software/system/src/stm32f0/gpio.hpp @@ -4,8 +4,10 @@ //#include -// data sheet: https://www.st.com/resource/en/datasheet/stm32f042f6.pdf -// refernece manual: https://www.st.com/resource/en/reference_manual/dm00031936-stm32f0x1stm32f0x2stm32f0x8-advanced-armbased-32bit-mcus-stmicroelectronics.pdf +/* + Data sheet: https://www.st.com/resource/en/datasheet/stm32f042f6.pdf + Refernece manual section 8: https://www.st.com/resource/en/reference_manual/dm00031936-stm32f0x1stm32f0x2stm32f0x8-advanced-armbased-32bit-mcus-stmicroelectronics.pdf +*/ namespace gpio { @@ -162,6 +164,9 @@ inline void configureAlternateInput(PinFunction pf, Pull pull = Pull::DISABLED) int pos2 = (pf.pin & 15) << 1; int pos4 = (pf.pin & 7) << 2; + // enable peripheral clock for the port + RCC->AHBENR = RCC->AHBENR | (1 << (RCC_AHBENR_GPIOAEN_Pos + (pf.pin >> 4))); + // set alternate function auto &AFR = port->AFR[(pf.pin >> 3) & 1]; AFR = (AFR & ~(15 << pos4)) | (pf.function << pos4); @@ -178,9 +183,12 @@ inline void configureAlternateOutput(PinFunction pf, Pull pull = Pull::DISABLED, { auto port = getPort(pf.pin); int pos = pf.pin & 15; - int pos2 = (pf.pin & 15) << 1; + int pos2 = pos << 1; int pos4 = (pf.pin & 7) << 2; + // enable peripheral clock for the port + RCC->AHBENR = RCC->AHBENR | (1 << (RCC_AHBENR_GPIOAEN_Pos + (pf.pin >> 4))); + // set alternate function auto &AFR = port->AFR[(pf.pin >> 3) & 1]; AFR = (AFR & ~(15 << pos4)) | (pf.function << pos4); diff --git a/software/system/src/stm32f0/system/stm32f042x6.h b/software/system/src/stm32f0/system/stm32f042x6.h index 937df54..94e14a1 100644 --- a/software/system/src/stm32f0/system/stm32f042x6.h +++ b/software/system/src/stm32f0/system/stm32f042x6.h @@ -40,7 +40,7 @@ extern "C" { #endif /* __cplusplus */ - /** @addtogroup Configuration_section_for_CMSIS +/** @addtogroup Configuration_section_for_CMSIS * @{ */ /** @@ -64,7 +64,7 @@ * in @ref Library_configuration_section */ - /*!< Interrupt Number Definition */ +/*!< Interrupt Number Definition */ typedef enum { /****** Cortex-M0 Processor Exceptions Numbers **************************************************************/ @@ -199,7 +199,7 @@ typedef struct uint32_t RESERVED4; /*!< Reserved, 0x218 */ __IO uint32_t FA1R; /*!< CAN filter activation register, Address offset: 0x21C */ uint32_t RESERVED5[8]; /*!< Reserved, 0x220-0x23F */ - CAN_FilterRegister_TypeDef sFilterRegister[28]; /*!< CAN Filter Register, Address offset: 0x240-0x31C */ + CAN_FilterRegister_TypeDef sFilterRegister[14]; /*!< CAN Filter Register, Address offset: 0x240-0x2AC */ }CAN_TypeDef; /** @@ -704,7 +704,16 @@ typedef struct * @{ */ - /** @addtogroup Peripheral_Registers_Bits_Definition +/** @addtogroup Hardware_Constant_Definition + * @{ + */ +#define LSI_STARTUP_TIME 85U /*!< LSI Maximum startup time in us */ + +/** + * @} + */ + +/** @addtogroup Peripheral_Registers_Bits_Definition * @{ */ @@ -1621,48 +1630,6 @@ typedef struct #define CAN_FM1R_FBM13_Pos (13U) #define CAN_FM1R_FBM13_Msk (0x1UL << CAN_FM1R_FBM13_Pos) /*!< 0x00002000 */ #define CAN_FM1R_FBM13 CAN_FM1R_FBM13_Msk /*! +#include +#include +#include +#include +#include + + +uint8_t send[] = {0x01, 0x00, 0x0f, 0x33, 0x55, 0xaa, 0xcc, 0xf0}; +uint8_t receive[10]; + + +Coroutine transferBus(BusNode &busNode) { + while (true) { + co_await busNode.send(array::count(send), send); + + //int receiveLength = array::count(receive); + + co_await Timer::sleep(1s); + + //Debug::toggleBlueLed(); + } +} + +int main() { + Loop::init(); + Timer::init(); + Output::init(); // for debug led's + DriversBusNodeTest drivers; + + transferBus(drivers.busNode); + + Loop::run(); +} diff --git a/software/system/test/FlashTest.cpp b/software/system/test/FlashTest.cpp index 99bb726..6b6b24b 100644 --- a/software/system/test/FlashTest.cpp +++ b/software/system/test/FlashTest.cpp @@ -8,10 +8,7 @@ uint8_t writeData[] = {0x12, 0x34, 0x56, 0x78}; uint8_t readData[4]; -int main() { - Loop::init(); - Timer::init(); - Output::init(); // for debug led's +void test() { DriversFlashTest drivers; drivers.flash.readBlocking(0, 4, readData); @@ -22,7 +19,14 @@ int main() { // erase drivers.flash.eraseSectorBlocking(0); - while (true) {} + // also switch on red and green leds in case erase did not work + drivers.flash.readBlocking(0, 4, readData); + if (array::equal(4, writeData, readData)) { + Debug::setRedLed(); + Debug::setGreenLed(); + } + + return; } // erase @@ -40,6 +44,14 @@ int main() { // read indicates that write or read failed Debug::setRedLed(); } +} + +int main() { + Loop::init(); + Timer::init(); + Output::init(); // for debug led's + + test(); - while (true) {} + Loop::run(); } diff --git a/software/system/test/InputTest.cpp b/software/system/test/InputTest.cpp index 795f90f..e7b2594 100644 --- a/software/system/test/InputTest.cpp +++ b/software/system/test/InputTest.cpp @@ -25,7 +25,7 @@ int main() { Loop::init(); Output::init(); // for debug signals on pins Input::init(); - Drivers drivers; + //Drivers drivers; handleInput(); diff --git a/software/system/test/SpiMasterTest.cpp b/software/system/test/SpiMasterTest.cpp index 04def35..6d9edd5 100644 --- a/software/system/test/SpiMasterTest.cpp +++ b/software/system/test/SpiMasterTest.cpp @@ -4,24 +4,30 @@ #include -uint16_t spi0Data[] = {0x0a51, 0x0ff0}; +uint8_t spiWriteData[] = {0x0a, 0x55}; +uint8_t spiReadData[10]; -Coroutine transferSpi0(SpiMaster &spi) { +Coroutine transferSpi(SpiMaster &spi) { while (true) { - co_await spi.transfer(2, spi0Data, 0, nullptr); + co_await spi.transfer(2, spiWriteData, 10, spiReadData); //co_await Timer::sleep(100ms); //Debug::toggleRedLed(); } } -uint16_t spi1Command[] = {0x00ff, 0x3355}; -uint16_t spi1Data[] = {0x3355, 0x00ff}; +uint8_t command[] = {0x00, 0xff}; +uint8_t data[] = {0x33, 0x55}; -Coroutine transferSpi1(SpiMaster &spi) { +struct Spi { + SpiMaster &command; + SpiMaster &data; +}; + +Coroutine writeCommandData(Spi spi) { while (true) { - co_await spi.writeCommand(2, spi1Command); - co_await spi.writeData(2, spi1Data); + co_await spi.command.write(2, command); + co_await spi.data.write(2, data); } } @@ -30,10 +36,10 @@ int main() { Loop::init(); Output::init(); // for debug led's Timer::init(); - Drivers drivers; + DriversSpiMasterTest drivers; - transferSpi0(drivers.airSensor); - transferSpi1(drivers.display); + transferSpi(drivers.transfer); + writeCommandData({drivers.command, drivers.data}); Loop::run(); } diff --git a/software/system/test/StorageTest.cpp b/software/system/test/StorageTest.cpp index 0165702..275a5fe 100644 --- a/software/system/test/StorageTest.cpp +++ b/software/system/test/StorageTest.cpp @@ -20,7 +20,7 @@ struct Kiss32Random { c = 7654321; } - uint32_t draw() { + int draw() { // Linear congruence generator x = 69069 * x + 12345; @@ -34,23 +34,24 @@ struct Kiss32Random { c = t >> 32; z = (uint32_t) t; - return x + y + z; + return (x + y + z) & 0x7fffffff; } }; void fail() { Debug::setRedLed(); - while (true) {} + Debug::setBlueLed(); } -int main() { - Loop::init(); - Timer::init(); - Output::init(); // for debug led's +void test() { + Debug::setBlueLed(); DriversStorageTest drivers; + Debug::clearBlueLed(); + // random generator for random data of random length Kiss32Random random; + // measure time auto start = Timer::now(); // table of currently stored elements @@ -60,7 +61,8 @@ int main() { // determine capacity auto info = drivers.flash.getInfo(); - unsigned int capacity = min(((info.sectorCount - 1) * (info.sectorSize - 8)) / (128 + 8), array::count(sizes)) - 1; + int capacity = min(((info.sectorCount - 1) * (info.sectorSize - 8)) / (128 + 8), array::count(sizes)) - 1; + Terminal::out << "capacity: " << dec(capacity) << '\n'; // clear storage drivers.storage.clearBlocking(); @@ -78,10 +80,10 @@ int main() { // check data if (readSize != size) - fail(); + return fail(); for (int j = 0; j < size; ++j) { if (buffer[j] != uint8_t(id + j)) - fail(); + return fail(); } } @@ -100,13 +102,23 @@ int main() { // store if (drivers.storage.writeBlocking(id, size, buffer) != Storage::Status::OK) - fail(); + return fail(); } auto end = Timer::now(); Terminal::out << dec(int((end - start) / 1s)) << "s\n"; + // ok Debug::setGreenLed(); - while (true) {} +} + +int main() { + Loop::init(); + Timer::init(); + Output::init(); // for debug led's + + test(); + + Loop::run(); } From 585c9fe8c4ec34da38c76b1890543ff220406816 Mon Sep 17 00:00:00 2001 From: Jochen Wilhelmy Date: Tue, 20 Dec 2022 14:22:26 +0100 Subject: [PATCH 2/5] Windows compatibility and new UsbDevice driver --- software/CMakeLists.txt | 53 +++- software/board/None/boardConfig.hpp | 1 + software/board/nrf52Dongle/boardConfig.hpp | 1 + software/conanfile.py | 10 +- software/control/test/BME680Test.cpp | 27 +- software/protocol/src/usb.hpp | 22 +- software/system/src/UsbDevice.cpp | 5 + software/system/src/UsbDevice.hpp | 65 ++++- software/system/src/emu/UsbDevice.cpp | 90 ------ .../{UsbDevice.cpp => UsbDeviceImpl.cpp} | 268 +++++------------- software/system/src/nrf52/UsbDeviceImpl.hpp | 129 +++++++++ software/system/src/posix/Calendar.cpp | 6 +- software/system/src/posix/File.hpp | 104 +++++-- software/system/src/posix/Handlers.cpp | 81 ++++++ .../src/posix/{Loop.hpp => Handlers.hpp} | 33 ++- software/system/src/posix/Loop.cpp | 79 +----- software/system/src/posix/Loop2.cpp | 24 -- software/system/src/posix/Network.cpp | 57 ++-- software/system/src/posix/Sound.cpp | 6 +- software/system/src/posix/SpiMasterImpl.cpp | 2 +- software/system/src/posix/SpiMasterImpl.hpp | 6 +- software/system/src/posix/StorageImpl.hpp | 12 +- software/system/src/posix/Terminal.cpp | 17 +- software/system/src/posix/Timer.cpp | 6 +- software/system/src/posix/UsbDeviceImpl.cpp | 89 ++++++ software/system/src/posix/UsbDeviceImpl.hpp | 40 +++ software/system/test/UsbDeviceTest.cpp | 21 +- software/system/test/UsbTestHost.cpp | 6 +- 28 files changed, 762 insertions(+), 498 deletions(-) create mode 100644 software/system/src/UsbDevice.cpp delete mode 100644 software/system/src/emu/UsbDevice.cpp rename software/system/src/nrf52/{UsbDevice.cpp => UsbDeviceImpl.cpp} (64%) create mode 100644 software/system/src/nrf52/UsbDeviceImpl.hpp create mode 100644 software/system/src/posix/Handlers.cpp rename software/system/src/posix/{Loop.hpp => Handlers.hpp} (57%) delete mode 100644 software/system/src/posix/Loop2.cpp create mode 100644 software/system/src/posix/UsbDeviceImpl.cpp create mode 100644 software/system/src/posix/UsbDeviceImpl.hpp diff --git a/software/CMakeLists.txt b/software/CMakeLists.txt index c3c8b5f..00ef1c0 100644 --- a/software/CMakeLists.txt +++ b/software/CMakeLists.txt @@ -13,6 +13,7 @@ set(CMAKE_CXX_STANDARD 20) # debug generated makefile #set(CMAKE_VERBOSE_MAKEFILE TRUE) +message("*** COMPILER ${CMAKE_CXX_COMPILER_ID}") message("*** TYPE ${CMAKE_BUILD_TYPE}") message("*** PLATFORM ${PLATFORM}") message("*** BOARD ${BOARD}") @@ -25,8 +26,13 @@ if("Linux" IN_LIST PLATFORM) set(LINUX 1) endif() +# windows +if("Windows" IN_LIST PLATFORM) + set(WINDOWS 1) +endif() + # posix compatible platforms -if(LINUX OR "Macos" IN_LIST PLATFORM OR "FreeBSD" IN_LIST PLATFORM) +if(LINUX OR WINDOWS OR "Macos" IN_LIST PLATFORM OR "FreeBSD" IN_LIST PLATFORM) set(POSIX 1) endif() @@ -82,13 +88,16 @@ if(POSIX) Ogg::ogg gtest::gtest ) + if(WINDOWS) + set(LIBRARIES ${LIBRARIES} wsock32 ws2_32 winmm) + endif() # enable address sanitizer - if(CMAKE_BUILD_TYPE STREQUAL Debug) - message("Enable Address Sanitizer") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") - endif() + #if(CMAKE_BUILD_TYPE STREQUAL Debug) + # message("Enable Address Sanitizer") + # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") + # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") + #endif() # set rpath so that shared libraries are searched in ../lib if(APPLE) @@ -149,6 +158,8 @@ endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") # clang set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcoroutines-ts -Wno-user-defined-literals") +elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + # visual studio else() # gcc set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcoroutines -fconcepts -Wno-literal-suffix") @@ -246,7 +257,12 @@ if(POSIX) system/src/posix/FlashImpl.hpp system/src/posix/FlashImpl.cpp ) - set(LOOP system/src/Loop.hpp system/src/posix/Loop.cpp system/src/posix/Loop2.cpp) + set(LOOP + system/src/Loop.hpp + system/src/posix/Handlers.cpp + system/src/posix/Handlers.hpp + system/src/posix/Loop.cpp + ) set(NETWORK system/src/Network.hpp system/src/posix/Network.cpp) set(OUTPUT system/src/Output.hpp system/src/posix/Output.cpp system/src/Debug.hpp) set(SOUND system/src/Sound.hpp system/src/posix/Sound.cpp) @@ -264,6 +280,12 @@ if(POSIX) ) set(TERMINAL system/src/Terminal.hpp system/src/posix/Terminal.cpp) set(TIMER system/src/SystemTime.hpp system/src/Timer.hpp system/src/posix/Timer.cpp) + set(USB_DEVICE + system/src/UsbDevice.hpp + system/src/UsbDevice.cpp + system/src/posix/UsbDeviceImpl.hpp + system/src/posix/UsbDeviceImpl.cpp + ) endif() if(LINUX) if(TARGET PkgConfig::BlueZ) @@ -286,8 +308,8 @@ if(EMU) set(INPUT system/src/Input.hpp system/src/emu/Input.hpp system/src/emu/Input.cpp) set(LOOP system/src/Loop.hpp - system/src/posix/Loop.hpp - system/src/posix/Loop.cpp + system/src/posix/Handlers.hpp + system/src/posix/Handlers.cpp system/src/emu/Loop.hpp system/src/emu/Loop.cpp system/src/emu/Gui.cpp @@ -321,7 +343,6 @@ if(EMU) system/src/emu/SpiSSD1309.hpp system/src/emu/SpiSSD1309.cpp ) - set(USB_DEVICE system/src/UsbDevice.hpp system/src/emu/UsbDevice.cpp) endif() if("nrf52" IN_LIST PLATFORM) set(BUS_MASTER @@ -365,7 +386,12 @@ if("nrf52" IN_LIST PLATFORM) ) set(TERMINAL system/src/Terminal.hpp system/src/nrf52/Terminal.cpp) set(TIMER system/src/SystemTime.hpp system/src/Timer.hpp system/src/nrf52/Timer.cpp) - set(USB_DEVICE system/src/UsbDevice.hpp system/src/nrf52/UsbDevice.cpp) + set(USB_DEVICE + system/src/UsbDevice.hpp + system/src/UsbDevice.cpp + system/src/nrf52/UsbDeviceImpl.hpp + system/src/nrf52/UsbDeviceImpl.cpp + ) endif() if("stm32f0" IN_LIST PLATFORM) set(BUS_NODE @@ -758,7 +784,7 @@ target_link_libraries(MqttSnBrokerTest ${LIBRARIES}) endif() # POSIX AND NOT EMU -if(${BOARD} STREQUAL "emuControl") +if(${BOARD} STREQUAL "None") # test for BME680 air sensor add_executable(BME680Test @@ -784,6 +810,9 @@ target_include_directories(BME680Test ) target_link_libraries(BME680Test ${LIBRARIES}) +endif() + +if(${BOARD} STREQUAL "emuControl") # test for SSD1309 display add_executable(SSD1309Test diff --git a/software/board/None/boardConfig.hpp b/software/board/None/boardConfig.hpp index 96b1aac..81ad0e0 100644 --- a/software/board/None/boardConfig.hpp +++ b/software/board/None/boardConfig.hpp @@ -1,6 +1,7 @@ #include #include #include +#include #include diff --git a/software/board/nrf52Dongle/boardConfig.hpp b/software/board/nrf52Dongle/boardConfig.hpp index 112de2a..a5fc183 100644 --- a/software/board/nrf52Dongle/boardConfig.hpp +++ b/software/board/nrf52Dongle/boardConfig.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/software/conanfile.py b/software/conanfile.py index 6228b4a..9aed4ce 100644 --- a/software/conanfile.py +++ b/software/conanfile.py @@ -82,7 +82,7 @@ def generate(self): toolchain.variables["CPU"] = self.options.cpu toolchain.variables["FPU"] = self.options.fpu - # https://github.com/conan-io/conan/blob/develop/conan/tools/cmake/toolchain.py + # https://github.com/conan-io/conan/blob/develop/conan/tools/cmake/toolchain/blocks.py if str(self.settings.os) not in p: toolchain.blocks["generic_system"].values["cmake_system_name"] = "Generic" toolchain.blocks["generic_system"].values["cmake_system_processor"] = self.settings.arch @@ -93,8 +93,12 @@ def generate(self): toolchain.variables["GENERATE_HEX"] = self.env.get("GENERATE_HEX", None) # bake CC and CXX from profile into toolchain - toolchain.blocks["generic_system"].values["compiler"] = self.env.get("CC", None) - toolchain.blocks["generic_system"].values["compiler_cpp"] = self.env.get("CXX", None) + cc = self.env.get("CC", None) + if cc != None: + toolchain.variables["CMAKE_C_COMPILER "] = cc + cxx = self.env.get("CXX", None) + if cxx != None: + toolchain.variables["CMAKE_CXX_COMPILER "] = cxx toolchain.generate() diff --git a/software/control/test/BME680Test.cpp b/software/control/test/BME680Test.cpp index 202491a..f75b740 100644 --- a/software/control/test/BME680Test.cpp +++ b/software/control/test/BME680Test.cpp @@ -31,7 +31,7 @@ struct UsbConfiguration { struct usb::ConfigDescriptor config; struct usb::InterfaceDescriptor interface; struct usb::EndpointDescriptor endpoints[1]; -} __attribute__((packed)); +}; static const UsbConfiguration configurationDescriptor = { .config = { @@ -67,14 +67,14 @@ static const UsbConfiguration configurationDescriptor = { uint8_t timerId; -StringBuffer<128> string __attribute__((aligned(4))); +StringBuffer<128> string;// __attribute__((aligned(4))); #define READ(reg) ((reg) | 0x80) #define WRITE(reg) ((reg) & 0x7f) constexpr int CHIP_ID = 0x61; -uint8_t buffer[129] __attribute__((aligned(4))); +uint8_t buffer[129];// __attribute__((aligned(4))); // get chip id and output result on debug led's Coroutine getId(SpiMaster &spi) { @@ -95,14 +95,14 @@ Coroutine getId(SpiMaster &spi) { } // read all registers and send to usb host -Coroutine getRegisters(SpiMaster &spi) { +Coroutine getRegisters(SpiMaster &spi, UsbDevice &usb) { while (true) { - // read upper page + // read upper page from sensor buffer[0] = READ(0); co_await spi.transfer(1, buffer, 129, buffer); // send to usb host - co_await UsbDevice::send(1, 128, buffer + 1); + co_await usb.send(1, 128, buffer + 1); Debug::toggleBlueLed(); // wait for 5s @@ -111,7 +111,7 @@ Coroutine getRegisters(SpiMaster &spi) { } // measure and send values to usb host -Coroutine measure(SpiMaster &spi) { +Coroutine measure(SpiMaster &spi, UsbDevice &usb) { BME680 sensor(spi); co_await sensor.init(); @@ -129,19 +129,18 @@ Coroutine measure(SpiMaster &spi) { + "Humidity: " + flt(sensor.getHumidity(), 1, 1) + "%\n" + "Gas: " + flt(sensor.getGasResistance(), 1, 1) + "Ω\n"; - co_await UsbDevice::send(1, string.count(), string.data()); + co_await usb.send(1, string.count(), string.data()); Debug::toggleRedLed(); co_await Timer::sleep(10s); } } - int main(void) { Loop::init(); Timer::init(); Output::init(); - UsbDevice::init( + UsbDeviceImpl usb( [](usb::DescriptorType descriptorType) { switch (descriptorType) { case usb::DescriptorType::DEVICE: @@ -152,9 +151,9 @@ int main(void) { return ConstData(); } }, - [](uint8_t bConfigurationValue) { + [](UsbDevice &usb, uint8_t bConfigurationValue) { // enable bulk endpoints in 1 (keep control endpoint 0 enabled in both directions) - UsbDevice::enableEndpoints(1 | (1 << 1), 1); + usb.enableEndpoints(1 | (1 << 1), 1); //getRegisters(); }, @@ -164,9 +163,9 @@ int main(void) { Drivers drivers; // test raw values - //getId(drivers.airSensor); + //getId(drivers.airSensor, usb); - measure(drivers.airSensor); + measure(drivers.airSensor, usb); Loop::run(); } diff --git a/software/protocol/src/usb.hpp b/software/protocol/src/usb.hpp index 51b53b0..f6a4407 100644 --- a/software/protocol/src/usb.hpp +++ b/software/protocol/src/usb.hpp @@ -3,6 +3,12 @@ #include #include +#ifdef _MSC_VER +#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop)) +#else +#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__)) +#endif + namespace usb { @@ -57,7 +63,7 @@ enum class Request : uint8_t { FLAGS_ENUM(Request) // device descriptor -struct DeviceDescriptor { +PACK(struct DeviceDescriptor { uint8_t bLength; DescriptorType bDescriptorType; uint16_t bcdUSB; @@ -72,10 +78,10 @@ struct DeviceDescriptor { uint8_t iProduct; uint8_t iSerialNumber; uint8_t bNumConfigurations; -} __attribute__((packed)); +}); // configuration descriptor -struct ConfigDescriptor { +PACK(struct ConfigDescriptor { uint8_t bLength; DescriptorType bDescriptorType; uint16_t wTotalLength; @@ -84,10 +90,10 @@ struct ConfigDescriptor { uint8_t iConfiguration; uint8_t bmAttributes; uint8_t bMaxPower; -} __attribute__((packed)); +}); // interface descriptor -struct InterfaceDescriptor { +PACK(struct InterfaceDescriptor { uint8_t bLength; DescriptorType bDescriptorType; uint8_t bInterfaceNumber; @@ -97,16 +103,16 @@ struct InterfaceDescriptor { uint8_t bInterfaceSubClass; uint8_t bInterfaceProtocol; uint8_t iInterface; -} __attribute__((packed)); +}); // endpoint descriptor -struct EndpointDescriptor { +PACK(struct EndpointDescriptor { uint8_t bLength; DescriptorType bDescriptorType; uint8_t bEndpointAddress; EndpointType bmAttributes; uint16_t wMaxPacketSize; uint8_t bInterval; -} __attribute__((packed)); +}); } // namespace usb diff --git a/software/system/src/UsbDevice.cpp b/software/system/src/UsbDevice.cpp new file mode 100644 index 0000000..722b71d --- /dev/null +++ b/software/system/src/UsbDevice.cpp @@ -0,0 +1,5 @@ +#include "UsbDevice.hpp" + + +UsbDevice::~UsbDevice() { +} diff --git a/software/system/src/UsbDevice.hpp b/software/system/src/UsbDevice.hpp index d9b3cf0..8d8a39e 100644 --- a/software/system/src/UsbDevice.hpp +++ b/software/system/src/UsbDevice.hpp @@ -7,6 +7,54 @@ #include +/** + * Interface to an USb device + */ +class UsbDevice { +public: + + // Internal helper: Stores the parameters and a reference to the result value in the awaitable during co_await + struct ReceiveParameters { + int &length; + void *data; + }; + + // Internal helper: Stores the parameters in the awaitable during co_await + struct SendParameters { + int length; + void const *data; + }; + + + virtual ~UsbDevice(); + + /** + * Enable endpoints. Can be done in onSetConfiguration. Endpoint 0 should stay enabled + * @param inFlags an enabled flag for each in endpoint + * @param outFlags an enabled flag for each out endpoint + */ + virtual void enableEndpoints(uint8_t inFlags, uint8_t outFlags) = 0; + + /** + * Suspend execution using co_await until data is received from an endpoint (OUT transfer) + * @param index endpoint index (1-7) + * @param length in: length of data buffer, out: length of data actually received + * @param data data to receive, must be in RAM + */ + [[nodiscard]] virtual Awaitable receive(int index, int &length, void *data) = 0; + + /** + * Suspend execution using co_await until data is sent over an endpoint (IN transfer) + * @param index endpoint index (1-7) + * @param length data length + * @param data data to send, must be in RAM + */ + [[nodiscard]] virtual Awaitable send(int index, int length, void const *data) = 0; + +}; + + +/* namespace UsbDevice { // Internal helper: Stores the parameters and a reference to the result value in the awaitable during co_await @@ -22,38 +70,39 @@ struct SendParameters { }; -/** +/ ** * Initialize USB * @param getDescriptor callback for obtaining descriptors * @param onSetConfiguration callback for setting the configuration (libusb_set_configuration() on host), always called from event loop * @param onRequest callback for vendor specific request - */ + * / void init( std::function const &getDescriptor, std::function const &onSetConfiguration, std::function const &onRequest); -/** +/ ** * Enable endpoints. Can be done in onSetConfiguration. Endpoint 0 should stay enabled * @param inFlags an enabled flag for each in endpoint * @param outFlags an enabled flag for each out endpoint - */ + * / void enableEndpoints(uint8_t inFlags, uint8_t outFlags); -/** +/ ** * Suspend execution using co_await until data is received from an endpoint (OUT transfer) * @param index endpoint index (1-7) * @param length in: length of data buffer, out: length of data actually received * @param data data to receive, must be in RAM - */ + * / [[nodiscard]] Awaitable receive(int index, int &length, void *data); -/** +/ ** * Suspend execution using co_await until data is sent over an endpoint (IN transfer) * @param index endpoint index (1-7) * @param length data length * @param data data to send, must be in RAM - */ + * / [[nodiscard]] Awaitable send(int index, int length, void const *data); } // namespace UsbDevice +*/ diff --git a/software/system/src/emu/UsbDevice.cpp b/software/system/src/emu/UsbDevice.cpp deleted file mode 100644 index 70d0219..0000000 --- a/software/system/src/emu/UsbDevice.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "../UsbDevice.hpp" -#include "Loop.hpp" -#include - - -namespace UsbDevice { - -bool text; - -// endpoints 1 - 7 -struct Endpoint { - Waitlist receiveWaitlist; - Waitlist sendWaitlist; -}; - -Endpoint endpoints[1]; - -std::function onSetConfiguration; - -// event loop handler chain -Loop::Handler nextHandler; -void handle(Gui &gui) { - // call onSetConfiguration once - if (UsbDevice::onSetConfiguration != nullptr) { - UsbDevice::onSetConfiguration(1); - UsbDevice::onSetConfiguration = nullptr; - } - - for (auto &endpoint : UsbDevice::endpoints) { - - endpoint.sendWaitlist.resumeFirst([](SendParameters p) { - if (UsbDevice::text) { - printf("%.*s", p.length, reinterpret_cast(p.data)); - } else { - // binary - printf("%d: ", p.length); - for (int i = 0; i < p.length; ++i) { - if ((i & 15) == 0) { - if (i != 0) - printf(",\n"); - } else { - printf(", "); - } - printf("0x%02x", reinterpret_cast(p.data)[i]); - } - printf("\n"); - } - return true; - }); - } - - // call next handler in chain - UsbDevice::nextHandler(gui); -} - -void init( - std::function const &getDescriptor, - std::function const &onSetConfiguration, - std::function const &onRequest) -{ - // get device descriptor - auto *deviceDescriptor = getDescriptor(usb::DescriptorType::DEVICE).cast(); - UsbDevice::text = deviceDescriptor->bDeviceProtocol == 1; - - // set configuration - UsbDevice::onSetConfiguration = onSetConfiguration; - //Loop::context.post([onSetConfiguration]() {onSetConfiguration(1);}); - - // add to event loop handler chain - UsbDevice::nextHandler = Loop::addHandler(handle); -} - -void enableEndpoints(uint8_t inFlags, uint8_t outFlags) { -} - -Awaitable receive(int index, int &length, void *data) { - assert(index == 1); - auto &endpoint = UsbDevice::endpoints[index - 1]; - - return {endpoint.receiveWaitlist, length, data}; -} - -Awaitable send(int index, int length, void const *data) { - assert(index == 1); - auto &endpoint = UsbDevice::endpoints[index - 1]; - - return {endpoint.sendWaitlist, length, data}; -} - -} // namespace Usb diff --git a/software/system/src/nrf52/UsbDevice.cpp b/software/system/src/nrf52/UsbDeviceImpl.cpp similarity index 64% rename from software/system/src/nrf52/UsbDevice.cpp rename to software/system/src/nrf52/UsbDeviceImpl.cpp index 84428ab..18f1af0 100644 --- a/software/system/src/nrf52/UsbDevice.cpp +++ b/software/system/src/nrf52/UsbDeviceImpl.cpp @@ -1,9 +1,9 @@ -#include "../UsbDevice.hpp" +#include "UsbDeviceImpl.hpp" #include "../Debug.hpp" #include "Loop.hpp" #include "nrf52.hpp" -#include -#include +//#include +//#include /* @@ -19,100 +19,81 @@ Bugs: Workaround for Errata 199 needs to be added when using more than one endpoint: https://infocenter.nordicsemi.com/topic/errata_nRF52840_Rev2/ERR/nRF52840/Rev2/latest/anomaly_840_199.html */ -namespace UsbDevice { - -std::function getDescriptor; -std::function onSetConfiguration; -std::function onRequest; - -// endpoint 0 -uint8_t ep0Buffer[64] __attribute__((aligned(4))); -uint8_t const *ep0Data; -int ep0SendLength = 0; - -void ep0Send(void const *data, int length) { - auto d = reinterpret_cast(data); - int l = min(length, 64); - array::copy(ep0Buffer, ep0Buffer + l, d); - NRF_USBD->EPIN[0].PTR = intptr_t(ep0Buffer); - NRF_USBD->EPIN[0].MAXCNT = l; - ep0Data = d; - ep0SendLength = length; - - NRF_USBD->TASKS_STARTEPIN[0] = TRIGGER; -} - -// endpoints 1 - 7 -struct Endpoint { - enum State : uint8_t { - IDLE, - BUFFER, +UsbDeviceImpl::UsbDeviceImpl( + std::function const &getDescriptor, + std::function const &onSetConfiguration, + std::function const &onRequest) + : getDescriptor(getDescriptor), onSetConfiguration(onSetConfiguration), onRequest(onRequest) +{ + NRF_USBD->INTENSET = N(USBD_INTENSET_USBEVENT, Set) + | N(USBD_INTENSET_EP0SETUP, Set) + | N(USBD_INTENSET_EP0DATADONE, Set) + | N(USBD_INTENSET_EPDATA, Set) + | 0xef << USBD_INTENSET_ENDEPOUT1_Pos // OUT endpoint 1-7 + | 0xef << USBD_INTENSET_ENDEPIN1_Pos // IN endpoint 1-7 + | N(USBD_INTENSET_USBRESET, Set); - // data is transferred via usb from host to internal buffer - USB, + NRF_USBD->ENABLE = N(USBD_ENABLE_ENABLE, Enabled); - // data is transferred via dma from internal buffer to memory - DMA, + // add to list of handlers + Loop::handlers.add(*this); +} - // wait for dma channel to be available (there is only one per endpoint) - WAIT - }; +void UsbDeviceImpl::enableEndpoints(uint8_t inFlags, uint8_t outFlags) { + NRF_USBD->EPINEN = inFlags; + NRF_USBD->EPOUTEN = outFlags; - // receive (OUT) - State receiveState = IDLE; - int maxReceiveLength; - int receiveLength = 0; - Waitlist receiveWaitlist; - void prepareReceive(int index, intptr_t data) { - // set pointer and wait for USB transfer into internal buffer - NRF_USBD->EPOUT[index].PTR = data; - this->receiveState = USB; - } - void startReceive(int index) { - // length of data in internal buffer - int bufferLength = NRF_USBD->SIZE.EPOUT[index]; - NRF_USBD->EPOUT[index].MAXCNT = min(this->receiveLength, bufferLength); - if (this->sendState == DMA) { - // DMA is currently in use: wait until DMA is free - this->receiveState = WAIT; - } else { - triggerReceive(index); + for (int index = 1; index < 8; ++index) { + if (inFlags & (1 << index)) { + NRF_USBD->DTOGGLE = index | N(USBD_DTOGGLE_IO, In) | N(USBD_DTOGGLE_VALUE, Data0); } - } - void triggerReceive(int index) { - // start DMA - NRF_USBD->TASKS_STARTEPOUT[index] = TRIGGER; - this->receiveState = DMA; - } + if (outFlags & (1 << index)) { + NRF_USBD->DTOGGLE = index | N(USBD_DTOGGLE_IO, Out) | N(USBD_DTOGGLE_VALUE, Data0); - // send (IN) - State sendState = IDLE; - int sendLength = 0; - Waitlist sendWaitlist; - void startSend(int index, intptr_t data) { - NRF_USBD->EPIN[index].PTR = data; - NRF_USBD->EPIN[index].MAXCNT = min(this->sendLength, 64); - if (this->receiveState == Endpoint::DMA) { - // DMA is currently in use: wait until DMA is free - this->sendState = Endpoint::WAIT; - } else { - triggerSend(index); + // write any value to start receiving OUT transfers into intermediate buffer + NRF_USBD->SIZE.EPOUT[index] = 0; } } - void triggerSend(int index) { - // start DMA - NRF_USBD->TASKS_STARTEPIN[index] = TRIGGER; - this->sendState = Endpoint::DMA; +} + +Awaitable UsbDeviceImpl::receive(int index, int &length, void *data) { + assert(index >= 1 && index <= ENDPOINT_COUNT); + auto& ep = this->endpoints[index - 1]; + + // check if usb receiver is idle or a buffer is ready + if (ep.receiveState <= Endpoint::BUFFER) { + // set receive data + ep.maxReceiveLength = length; + ep.receiveLength = length; + bool buffer = ep.receiveState == Endpoint::BUFFER; + ep.prepareReceive(index, intptr_t(data)); + + // we can immediately start receiving via DMA if data is already in the internal buffer + if (buffer) + ep.startReceive(index); // -> ENDEPOUT[index] } -}; -Endpoint endpoints[USB_ENDPOINT_COUNT - 1]; + return {ep.receiveWaitlist, length, data}; +} + +Awaitable UsbDeviceImpl::send(int index, int length, void const *data) { + assert(index >= 1 && index <= ENDPOINT_COUNT); + auto& ep = this->endpoints[index - 1]; + + // check if usb sender is idle + if (ep.sendState == Endpoint::IDLE) { + // set send data + ep.sendLength = length; + + // start first DMA transfer from memory to internal buffer + ep.startSend(index, intptr_t(data)); // -> ENDEPIN[index] + } + return {ep.sendWaitlist, length, data}; +} -// event loop handler chain -Loop::Handler nextHandler = nullptr; -void handle() { +void UsbDeviceImpl::handle() { if (isInterruptPending(USBD_IRQn)) { if (NRF_USBD->EVENTS_USBEVENT) { // clear pending interrupt flag at peripheral @@ -143,7 +124,7 @@ void handle() { } else if (bRequest == 0x09) { // set configuration uint8_t bConfigurationValue = NRF_USBD->WVALUEL; - UsbDevice::onSetConfiguration(bConfigurationValue); + this->onSetConfiguration(*this, bConfigurationValue); // enter status stage NRF_USBD->TASKS_EP0STATUS = TRIGGER; @@ -157,11 +138,11 @@ void handle() { if (bRequest == 0x06) { // get descriptor from user code by using the callback auto descriptorType = usb::DescriptorType(NRF_USBD->WVALUEH); - ConstData descriptor = UsbDevice::getDescriptor(descriptorType); + ConstData descriptor = this->getDescriptor(descriptorType); if (descriptor.size() > 0) { // send descriptor int wLength = (NRF_USBD->WLENGTHH << 8) | NRF_USBD->WLENGTHL; - int size = min(descriptor.size(), wLength); + int size = std::min(descriptor.size(), wLength); ep0Send(descriptor.data(), size); } else { // unsupported descriptor type: stall @@ -192,7 +173,7 @@ void handle() { int wIndex = (NRF_USBD->WINDEXH << 8) | NRF_USBD->WINDEXL; // let user code handle the request - bool result = UsbDevice::onRequest(bRequest, wValue, wIndex); + bool result = this->onRequest(bRequest, wValue, wIndex); if (result) { // enter status stage NRF_USBD->TASKS_EP0STATUS = TRIGGER; @@ -219,7 +200,7 @@ void handle() { // more to send ep0Data += sentCount; - int l = min(length, 64); + int l = std::min(length, 64); array::copy(ep0Buffer, ep0Buffer + l, ep0Data); NRF_USBD->EPIN[0].MAXCNT = l; NRF_USBD->TASKS_STARTEPIN[0] = TRIGGER; @@ -234,13 +215,13 @@ void handle() { uint32_t EPDATASTATUS = NRF_USBD->EPDATASTATUS; // handle end of DMA transfers - for (int index = 1; index < USB_ENDPOINT_COUNT; ++index) { + for (int index = 1; index <= ENDPOINT_COUNT; ++index) { // check if we sent via DMA to IN endpoint buffer if (NRF_USBD->EVENTS_ENDEPIN[index]) { // clear pending interrupt flag at peripheral NRF_USBD->EVENTS_ENDEPIN[index] = 0; - auto& ep = UsbDevice::endpoints[index - 1]; + auto& ep = this->endpoints[index - 1]; // check if receiver waits for DMA if (ep.receiveState == Endpoint::WAIT) @@ -256,7 +237,7 @@ void handle() { // clear pending interrupt flag at peripheral NRF_USBD->EVENTS_ENDEPOUT[index] = 0; - auto& ep = UsbDevice::endpoints[index - 1]; + auto& ep = this->endpoints[index - 1]; // check if sender waits for DMA if (ep.sendState == Endpoint::WAIT) @@ -296,14 +277,14 @@ void handle() { if (EPDATASTATUS != 0) { // clear flags NRF_USBD->EPDATASTATUS = EPDATASTATUS; - for (int index = 1; index < USB_ENDPOINT_COUNT; ++index) { + for (int index = 1; index <= ENDPOINT_COUNT; ++index) { int inFlag = 1 << index; int outFlag = inFlag << 16; // EPDATA IN if (EPDATASTATUS & inFlag) { // finished send to host (IN) - auto &ep = UsbDevice::endpoints[index - 1]; + auto &ep = this->endpoints[index - 1]; // check if more to send int sentCount = NRF_USBD->EPIN[index].AMOUNT; @@ -334,7 +315,7 @@ void handle() { // EPDATA OUT if (EPDATASTATUS & outFlag) { // finished receive from host (OUT) - auto& ep = UsbDevice::endpoints[index - 1]; + auto& ep = this->endpoints[index - 1]; if (ep.receiveState <= Endpoint::BUFFER) { // idle: mark that data is already waiting in the buffer @@ -357,101 +338,4 @@ void handle() { // clear pending interrupt flag at NVIC clearInterrupt(USBD_IRQn); } - - // call next handler in chain - UsbDevice::nextHandler(); } - -void init( - std::function const &getDescriptor, - std::function const &onSetConfiguration, - std::function const &onRequest) -{ - // check if already initialized - if (UsbDevice::nextHandler != nullptr) - return; - - // add to event loop handler chain - UsbDevice::nextHandler = Loop::addHandler(handle); - - UsbDevice::getDescriptor = getDescriptor; - UsbDevice::onSetConfiguration = onSetConfiguration; - UsbDevice::onRequest = onRequest; - - NRF_USBD->INTENSET = N(USBD_INTENSET_USBEVENT, Set) - | N(USBD_INTENSET_EP0SETUP, Set) - | N(USBD_INTENSET_EP0DATADONE, Set) - | N(USBD_INTENSET_EPDATA, Set) - | (1 < USB_ENDPOINT_COUNT ? N(USBD_INTENSET_ENDEPOUT1, Set) : 0) - | (2 < USB_ENDPOINT_COUNT ? N(USBD_INTENSET_ENDEPOUT2, Set) : 0) - | (3 < USB_ENDPOINT_COUNT ? N(USBD_INTENSET_ENDEPOUT3, Set) : 0) - | (4 < USB_ENDPOINT_COUNT ? N(USBD_INTENSET_ENDEPOUT4, Set) : 0) - | (5 < USB_ENDPOINT_COUNT ? N(USBD_INTENSET_ENDEPOUT5, Set) : 0) - | (6 < USB_ENDPOINT_COUNT ? N(USBD_INTENSET_ENDEPOUT6, Set) : 0) - | (7 < USB_ENDPOINT_COUNT ? N(USBD_INTENSET_ENDEPOUT7, Set) : 0) - | (1 < USB_ENDPOINT_COUNT ? N(USBD_INTENSET_ENDEPIN1, Set) : 0) - | (2 < USB_ENDPOINT_COUNT ? N(USBD_INTENSET_ENDEPIN2, Set) : 0) - | (3 < USB_ENDPOINT_COUNT ? N(USBD_INTENSET_ENDEPIN3, Set) : 0) - | (4 < USB_ENDPOINT_COUNT ? N(USBD_INTENSET_ENDEPIN4, Set) : 0) - | (5 < USB_ENDPOINT_COUNT ? N(USBD_INTENSET_ENDEPIN5, Set) : 0) - | (6 < USB_ENDPOINT_COUNT ? N(USBD_INTENSET_ENDEPIN6, Set) : 0) - | (7 < USB_ENDPOINT_COUNT ? N(USBD_INTENSET_ENDEPIN7, Set) : 0) - | N(USBD_INTENSET_USBRESET, Set); - - NRF_USBD->ENABLE = N(USBD_ENABLE_ENABLE, Enabled); -} - -void enableEndpoints(uint8_t inFlags, uint8_t outFlags) { - NRF_USBD->EPINEN = inFlags; - NRF_USBD->EPOUTEN = outFlags; - - for (int index = 1; index < 8; ++index) { - if (inFlags & (1 << index)) { - NRF_USBD->DTOGGLE = index | N(USBD_DTOGGLE_IO, In) | N(USBD_DTOGGLE_VALUE, Data0); - } - if (outFlags & (1 << index)) { - NRF_USBD->DTOGGLE = index | N(USBD_DTOGGLE_IO, Out) | N(USBD_DTOGGLE_VALUE, Data0); - - // write any value to start receiving OUT transfers into intermediate buffer - NRF_USBD->SIZE.EPOUT[index] = 0; - } - } -} - -Awaitable receive(int index, int &length, void *data) { - assert(index >= 1 && index < USB_ENDPOINT_COUNT); - auto& ep = UsbDevice::endpoints[index - 1]; - - // check if usb receiver is idle or a buffer is ready - if (ep.receiveState <= Endpoint::BUFFER) { - // set receive data - ep.maxReceiveLength = length; - ep.receiveLength = length; - bool buffer = ep.receiveState == Endpoint::BUFFER; - ep.prepareReceive(index, intptr_t(data)); - - // we can immediately start receiving via DMA if data is already in the internal buffer - if (buffer) - ep.startReceive(index); // -> ENDEPOUT[index] - } - - return {ep.receiveWaitlist, length, data}; -} - -Awaitable send(int index, int length, void const *data) { - assert(index >= 1 && index < USB_ENDPOINT_COUNT); - auto& ep = UsbDevice::endpoints[index - 1]; - - // check if usb sender is idle - if (ep.sendState == Endpoint::IDLE) { - // set send data - ep.sendLength = length; - - // start first DMA transfer from memory to internal buffer - ep.startSend(index, intptr_t(data)); // -> ENDEPIN[index] - } - - return {ep.sendWaitlist, length, data}; -} - -} // namespace UsbDevice diff --git a/software/system/src/nrf52/UsbDeviceImpl.hpp b/software/system/src/nrf52/UsbDeviceImpl.hpp new file mode 100644 index 0000000..97a0e86 --- /dev/null +++ b/software/system/src/nrf52/UsbDeviceImpl.hpp @@ -0,0 +1,129 @@ +#include "../UsbDevice.hpp" +#include "Loop.hpp" +#include "nrf52.hpp" + + +#include + + +/** + * Implementation of an SPI master that simply writes info about the transfer operations to Terminal::out + */ +class UsbDeviceImpl : public UsbDevice, public Loop::Handler2 { +public: + // number of endpoints without endpoint 0 + static constexpr int ENDPOINT_COUNT = 7; + + /** + * Constructor + * @param getDescriptor callback for obtaining descriptors + * @param onSetConfiguration callback for setting the configuration (libusb_set_configuration() on host), always called from event loop + * @param onRequest callback for vendor specific request + */ + UsbDeviceImpl( + std::function const &getDescriptor, + std::function const &onSetConfiguration, + std::function const &onRequest); + + void enableEndpoints(uint8_t inFlags, uint8_t outFlags) override; + [[nodiscard]] Awaitable receive(int index, int &length, void *data) override; + [[nodiscard]] Awaitable send(int index, int length, void const *data) override; + + void handle() override; + +protected: + + std::function getDescriptor; + std::function onSetConfiguration; + std::function onRequest; + + + // endpoint 0 + uint8_t ep0Buffer[64] __attribute__((aligned(4))); + uint8_t const *ep0Data; + int ep0SendLength = 0; + + void ep0Send(void const *data, int length) { + auto d = reinterpret_cast(data); + int l = std::min(length, 64); + array::copy(ep0Buffer, ep0Buffer + l, d); + NRF_USBD->EPIN[0].PTR = intptr_t(ep0Buffer); + NRF_USBD->EPIN[0].MAXCNT = l; + ep0Data = d; + ep0SendLength = length; + + NRF_USBD->TASKS_STARTEPIN[0] = TRIGGER; + } + + + // endpoints 1 - 7 + struct Endpoint { + enum State : uint8_t { + IDLE, + + BUFFER, + + // data is transferred via usb from host to internal buffer + USB, + + // data is transferred via dma from internal buffer to memory + DMA, + + // wait for dma channel to be available (there is only one per endpoint) + WAIT + }; + + // receive (OUT) + State receiveState = IDLE; + int maxReceiveLength; + int receiveLength = 0; + Waitlist receiveWaitlist; + + void prepareReceive(int index, intptr_t data) { + // set pointer and wait for USB transfer into internal buffer + NRF_USBD->EPOUT[index].PTR = data; + this->receiveState = USB; + } + + void startReceive(int index) { + // length of data in internal buffer + int bufferLength = NRF_USBD->SIZE.EPOUT[index]; + NRF_USBD->EPOUT[index].MAXCNT = std::min(this->receiveLength, bufferLength); + if (this->sendState == DMA) { + // DMA is currently in use: wait until DMA is free + this->receiveState = WAIT; + } else { + triggerReceive(index); + } + } + + void triggerReceive(int index) { + // start DMA + NRF_USBD->TASKS_STARTEPOUT[index] = TRIGGER; + this->receiveState = DMA; + } + + // send (IN) + State sendState = IDLE; + int sendLength = 0; + Waitlist sendWaitlist; + + void startSend(int index, intptr_t data) { + NRF_USBD->EPIN[index].PTR = data; + NRF_USBD->EPIN[index].MAXCNT = std::min(this->sendLength, 64); + if (this->receiveState == Endpoint::DMA) { + // DMA is currently in use: wait until DMA is free + this->sendState = Endpoint::WAIT; + } else { + triggerSend(index); + } + } + + void triggerSend(int index) { + // start DMA + NRF_USBD->TASKS_STARTEPIN[index] = TRIGGER; + this->sendState = Endpoint::DMA; + } + }; + Endpoint endpoints[ENDPOINT_COUNT]; +}; diff --git a/software/system/src/posix/Calendar.cpp b/software/system/src/posix/Calendar.cpp index 0ac17b2..0032397 100644 --- a/software/system/src/posix/Calendar.cpp +++ b/software/system/src/posix/Calendar.cpp @@ -1,11 +1,11 @@ #include "../Calendar.hpp" -#include "Loop.hpp" +#include "Handlers.hpp" #include namespace Calendar { -class Context : public Loop::Timeout { +class Context : public Loop::TimeHandler { public: void activate() override { // next activation in 1s @@ -30,7 +30,7 @@ void init() { Calendar::inited = true; Calendar::context.time = Loop::now() + 1s; - Loop::timeouts.add(Calendar::context); + Loop::timeHandlers.add(Calendar::context); } ClockTime now() { diff --git a/software/system/src/posix/File.hpp b/software/system/src/posix/File.hpp index e68f6a6..5e719c4 100644 --- a/software/system/src/posix/File.hpp +++ b/software/system/src/posix/File.hpp @@ -2,19 +2,39 @@ #include #include +#include +#ifdef _WIN32 +#define NOMINMAX +#include +#undef interface +#undef INTERFACE +#undef IN +#undef OUT +#else +#include #include #include -#include +#endif +namespace fs = std::filesystem; + class File { public: - enum class Mode { + enum class Mode : uint32_t { +#ifdef _WIN32 + READ = GENERIC_READ, + WRITE = GENERIC_WRITE, + READ_WRITE = READ | WRITE, + + TRUNCATE = 1 +#else READ = O_RDONLY, WRITE = O_WRONLY, READ_WRITE = O_RDWR, TRUNCATE = O_TRUNC +#endif }; /** @@ -22,27 +42,39 @@ class File { * @param name file name * @param mode combination of Mode elements */ - File(const std::string &name, Mode mode) { - this->fd = open(name.c_str(), O_CREAT | int(mode), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); - } + File(const fs::path &path, Mode mode); /** * Destructor */ ~File() { - close(this->fd); +#ifdef _WIN32 + CloseHandle(this->file); +#else + close(this->file); +#endif } - bool isOpen() {return this->fd != -1;} + bool isOpen() { +#ifdef _WIN32 + return this->file != nullptr; +#else + return this->file != -1; +#endif + } /** * Get size of file * @return file size */ int getSize() { +#ifdef _WIN32 + return GetFileSize(this->file, nullptr); +#else struct stat stat; - fstat(this->fd, &stat); + fstat(this->file, &stat); return stat.st_size; +#endif } /** @@ -51,32 +83,72 @@ class File { */ void resize(int size, uint8_t value = 0) { if (value != 0) { - int fileSize = getSize(); - fill(fileSize, size - fileSize, value); + int currentSize = getSize(); + if (currentSize <= size) { + fill(currentSize, size - currentSize, value); + return; + } } - ftruncate(this->fd, size); +#ifdef _WIN32 + SetFilePointer(this->file, size, nullptr, FILE_BEGIN); + SetEndOfFile(this->file); +#else + ftruncate(this->file, size); +#endif } int read(int offset, int length, void *data) { - return pread(this->fd, data, length, offset); +#ifdef _WIN32 + SetFilePointer(this->file, offset, nullptr, FILE_BEGIN); + DWORD numRead; + ReadFile(this->file, data, length, &numRead, nullptr); + return numRead; +#else + return pread(this->file, data, length, offset); +#endif } int write(int offset, int length, const void *data) { - return pwrite(this->fd, data, length, offset); +#ifdef _WIN32 + SetFilePointer(this->file, offset, nullptr, FILE_BEGIN); + DWORD numWritten; + WriteFile(this->file, data, length, &numWritten, nullptr); + return numWritten; +#else + return pwrite(this->file, data, length, offset); +#endif } void fill(int offset, int length, uint8_t value) { uint8_t buffer[16] = {value, value, value, value, value, value, value, value, value, value, value, value, value, value, value, value}; int count = length >> 4; for (int i = 0; i < count; ++i) - pwrite(this->fd, buffer, 16, offset + i * 16); + write(offset + i * 16, 16, buffer); int remaining = length & 15; if (remaining > 0) - pwrite(this->fd, buffer, remaining, offset + count * 16); + write(offset + count * 16, remaining, buffer); } protected: - int fd; +#ifdef _WIN32 + HANDLE file; +#else + int file; +#endif }; FLAGS_ENUM(File::Mode) + +inline File::File(const fs::path &path, Mode mode) { +#ifdef _WIN32 + this->file = CreateFileW(path.c_str(), + int(mode & Mode::READ_WRITE), + FILE_SHARE_READ, + nullptr, // security + (mode & Mode::TRUNCATE) != 0 ? CREATE_ALWAYS : OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + nullptr); +#else + this->file = open(name.c_str(), O_CREAT | int(mode), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); +#endif +} diff --git a/software/system/src/posix/Handlers.cpp b/software/system/src/posix/Handlers.cpp new file mode 100644 index 0000000..972404d --- /dev/null +++ b/software/system/src/posix/Handlers.cpp @@ -0,0 +1,81 @@ +#include "Handlers.hpp" +#ifdef _WIN32 +#define poll WSAPoll +#endif + + +namespace Loop { + +SocketHandler::~SocketHandler() { +} +SocketHandlerList socketHandlers; + +TimeHandler::~TimeHandler() { +} +TimeHandlerList timeHandlers; + +void runOnce(bool wait) { + // activate timeouts + SystemTime time; + bool activated; + do { + time = now(); + activated = false; + auto it = Loop::timeHandlers.begin(); + while (it != Loop::timeHandlers.end()) { + // increment iterator beforehand because a timer can remove() itself + auto current = it; + ++it; + + // check if timer needs to be activated + if (current->time <= time) { + current->activate(); + activated = true; + } + } + } while (activated); + + // get next timeout + auto next = time + SystemDuration::max(); + for (auto &handler : Loop::timeHandlers) { + if (handler.time < next) + next = handler.time; + } + + // fill poll infos + struct pollfd infos[16]; + int count = 0; + for (auto &handler : Loop::socketHandlers) { + infos[count++] = {handler.socket, handler.events, 0}; + } + assert(count <= array::count(infos)); + + // poll + auto timeout = (next - time).value; + //Terminal::out << "timeout " << dec(timeout) << '\n'; + int r = poll(infos, count, (timeout > 0 && wait) ? timeout : 0); + + // activate file descriptors + if (r > 0) { + int i = 0; + auto it = Loop::socketHandlers.begin(); + while (it != Loop::socketHandlers.end()) { + // increment iterator beforehand because a socket handler can remove() itself + auto current = it; + ++it; + + // check if file descriptor needs to be activated + auto events = infos[i].revents; + if (events != 0) + current->activate(events); + + // "garbage collect" file descriptors that are not interested in events anymore, also after close() was called + if (current->events == 0) + current->remove(); + + ++i; + } + } +} + +} // namespace Loop diff --git a/software/system/src/posix/Loop.hpp b/software/system/src/posix/Handlers.hpp similarity index 57% rename from software/system/src/posix/Loop.hpp rename to software/system/src/posix/Handlers.hpp index 8d183a1..a8ebac6 100644 --- a/software/system/src/posix/Loop.hpp +++ b/software/system/src/posix/Handlers.hpp @@ -4,41 +4,56 @@ #include "SystemTime.hpp" #include #include +#ifdef _WIN32 +#define NOMINMAX +#include +#undef interface +#undef INTERFACE +#undef IN +#undef OUT +#else +#include +using SOCKET = int; +#endif namespace Loop { // current time inline SystemTime now() { +#ifdef _WIN32 + return {timeGetTime()}; +#else timespec time; clock_gettime(CLOCK_MONOTONIC, &time); return {uint32_t(time.tv_sec * 1000 + time.tv_nsec / 1000000)}; +#endif } // list of file descriptors to observe readable/writable events (used in Network.cpp) -class FileDescriptor : public LinkedListNode { +class SocketHandler : public LinkedListNode { public: - virtual ~FileDescriptor(); + virtual ~SocketHandler(); virtual void activate(uint16_t events) = 0; - int fd = -1; + SOCKET socket = -1; short int events; }; -using FileDescriptorList = LinkedList; -extern FileDescriptorList fileDescriptors; +using SocketHandlerList = LinkedList; +extern SocketHandlerList socketHandlers; // timeouts for Timer and Calendar -class Timeout : public LinkedListNode { +class TimeHandler : public LinkedListNode { public: - virtual ~Timeout(); + virtual ~TimeHandler(); virtual void activate() = 0; SystemTime time; }; -using TimeoutList = LinkedList; -extern TimeoutList timeouts; +using TimeHandlerList = LinkedList; +extern TimeHandlerList timeHandlers; /** diff --git a/software/system/src/posix/Loop.cpp b/software/system/src/posix/Loop.cpp index 57ace80..3bffdf0 100644 --- a/software/system/src/posix/Loop.cpp +++ b/software/system/src/posix/Loop.cpp @@ -1,78 +1,21 @@ -#include "Loop.hpp" -#include +#include "Handlers.hpp" +#include "../Timer.hpp" +#include +#include namespace Loop { -FileDescriptor::~FileDescriptor() { -} -FileDescriptorList fileDescriptors; +bool inited = false; -Timeout::~Timeout() { +void init() { + Loop::inited = true; } -TimeoutList timeouts; - -void runOnce(bool wait) { - // activate timeouts - SystemTime time; - bool activated; - do { - time = now(); - activated = false; - auto it = Loop::timeouts.begin(); - while (it != Loop::timeouts.end()) { - // increment iterator beforehand because a timer can remove() itself - auto current = it; - ++it; - - // check if timer needs to be activated - if (current->time <= time) { - current->activate(); - activated = true; - } - } - } while (activated); - - // get next timeout - auto next = time + SystemDuration::max(); - for (auto &timeout : Loop::timeouts) { - if (timeout.time < next) - next = timeout.time; - } - - // fill poll infos - struct pollfd infos[16]; - int count = 0; - for (auto &fileDescriptor : Loop::fileDescriptors) { - infos[count++] = {fileDescriptor.fd, fileDescriptor.events, 0}; - } - assert(count <= array::count(infos)); - - // poll - auto timeout = (next - time).value; - //Terminal::out << "timeout " << dec(timeout) << '\n'; - int r = poll(infos, count, (timeout > 0 && wait) ? timeout : 0); - - // activate file descriptors - if (r > 0) { - int i = 0; - auto it = Loop::fileDescriptors.begin(); - while (it != Loop::fileDescriptors.end()) { - // increment iterator beforehand because a file descriptor can remove() itself - auto current = it; - ++it; - - // check if file descriptor needs to be activated - auto events = infos[i].revents; - if (events != 0) - current->activate(events); - - // "garbage collect" file descriptors that are not interested in events anymore, also after close() was called - if (current->events == 0) - current->remove(); - ++i; - } +void run() { + assert(Loop::inited); + while (true) { + runOnce(); } } diff --git a/software/system/src/posix/Loop2.cpp b/software/system/src/posix/Loop2.cpp deleted file mode 100644 index df024bf..0000000 --- a/software/system/src/posix/Loop2.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "Loop.hpp" -#include "../Timer.hpp" -#include -#include -#include -#include - - -namespace Loop { - -bool inited = false; - -void init() { - Loop::inited = true; -} - -void run() { - assert(Loop::inited); - while (true) { - runOnce(); - } -} - -} // namespace Loop diff --git a/software/system/src/posix/Network.cpp b/software/system/src/posix/Network.cpp index 8b10e49..5a920d4 100644 --- a/software/system/src/posix/Network.cpp +++ b/software/system/src/posix/Network.cpp @@ -1,14 +1,18 @@ #include "../Network.hpp" -#include "Loop.hpp" +#include "Handlers.hpp" #include #include -#include +#ifdef _WIN32 +#include +#else #include #include #include #include #include #include +inline void closesocket(int s) {close(s);} +#endif namespace Network { @@ -27,7 +31,7 @@ Address Address::fromString(String s) { } -class Context : public Loop::FileDescriptor { +class Context : public Loop::SocketHandler { public: void activate(uint16_t events) override { if (events & POLLIN) { @@ -35,7 +39,7 @@ class Context : public Loop::FileDescriptor { // receive struct sockaddr_in6 source = {}; socklen_t length = sizeof(source); - auto receivedCount = recvfrom(this->fd, p.data, *p.length, 0, (struct sockaddr*)&source, &length); + auto receivedCount = recvfrom(this->socket, (char*)p.data, *p.length, 0, (struct sockaddr*)&source, &length); if (receivedCount >= 0) { *p.length = receivedCount; @@ -59,7 +63,7 @@ class Context : public Loop::FileDescriptor { destination.sin6_port = htons(p.destination->port); // send - auto sentCount = sendto(this->fd, p.data, p.length, 0, (struct sockaddr*)&destination, sizeof(destination)); + auto sentCount = sendto(this->socket, (const char *)p.data, p.length, 0, (struct sockaddr*)&destination, sizeof(destination)); return sentCount >= 0; }); if (this->sendWaitlist.isEmpty()) @@ -84,26 +88,35 @@ bool open(int index, uint16_t port) { assert(uint(index) < NETWORK_CONTEXT_COUNT); auto &context = Network::contexts[index]; + // assert that socket is not open already + assert(context.socket == -1); + // create socket - assert(context.fd == -1); - int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); - fcntl(context.fd, F_SETFL, O_NONBLOCK); + int s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); +#ifdef _WIN32 + u_long blocking = 0; + ioctlsocket(s, FIONBIO, &blocking); +#else + fcntl(s, F_SETFL, O_NONBLOCK); +#endif // set reuse address and port int reuse = 1; - //setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); - setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)); + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse, sizeof(reuse)); + //setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)); + int broadcast = 1; + setsockopt(s, SOL_SOCKET, SO_BROADCAST, (const char *)&broadcast, sizeof(broadcast)); // bind to local port struct sockaddr_in6 address = {.sin6_family = AF_INET6, .sin6_port= htons(port)}; - if (bind(fd, (struct sockaddr*)&address, sizeof(address)) < 0) { + if (bind(s, (struct sockaddr*)&address, sizeof(address)) < 0) { int e = errno; - ::close(fd); + closesocket(s); return false; } // set file descriptor - context.fd = fd; + context.socket = s; context.events = 0; return true; } @@ -111,13 +124,13 @@ bool open(int index, uint16_t port) { bool join(int index, Address const &multicastGroup) { assert(uint(index) < NETWORK_CONTEXT_COUNT); auto &context = Network::contexts[index]; - assert(context.fd != -1); + assert(context.socket != -1); // join multicast group struct ipv6_mreq group; array::copy(16, group.ipv6mr_multiaddr.s6_addr, multicastGroup.u8); group.ipv6mr_interface = 0; - int r = setsockopt(context.fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &group, sizeof(group)); + int r = setsockopt(context.socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, (const char *)&group, sizeof(group)); if (r < 0) { int e = errno; return false; @@ -128,10 +141,10 @@ bool join(int index, Address const &multicastGroup) { void close(int index) { assert(uint(index) < NETWORK_CONTEXT_COUNT); auto &context = Network::contexts[index]; - assert(context.fd != -1); + assert(context.socket != -1); - ::close(context.fd); - context.fd = -1; + closesocket(context.socket); + context.socket = -1; context.events = 0; // resume waiting coroutines @@ -149,13 +162,13 @@ void close(int index) { Awaitable receive(int index, Endpoint& source, int &length, void *data) { assert(uint(index) < NETWORK_CONTEXT_COUNT); auto &context = Network::contexts[index]; - assert(context.fd != -1); + assert(context.socket != -1); context.events |= POLLIN; // add to event loop if necessary if (!context.isInList()) - Loop::fileDescriptors.add(context); + Loop::socketHandlers.add(context); // add to wait list return {context.receiveWaitlist, &source, &length, data}; @@ -164,13 +177,13 @@ Awaitable receive(int index, Endpoint& source, int &length, v Awaitable send(int index, Endpoint const &destination, int length, void const *data) { assert(uint(index) < NETWORK_CONTEXT_COUNT); auto &context = Network::contexts[index]; - assert(context.fd != -1); + assert(context.socket != -1); context.events |= POLLOUT; // add to event loop if necessary if (!context.isInList()) - Loop::fileDescriptors.add(context); + Loop::socketHandlers.add(context); // add to wait list return {context.sendWaitlist, &destination, length, data}; diff --git a/software/system/src/posix/Sound.cpp b/software/system/src/posix/Sound.cpp index d13da03..bc7d1ab 100644 --- a/software/system/src/posix/Sound.cpp +++ b/software/system/src/posix/Sound.cpp @@ -1,5 +1,5 @@ #include "../Sound.hpp" -#include "Loop.hpp" +#include "Handlers.hpp" #include "assert.hpp" #include "util.hpp" #define MA_NO_DECODING @@ -61,7 +61,7 @@ std::vector types; // timeout to check if audio devices need to be stopped -class Timeout : public Loop::Timeout { +class Timeout : public Loop::TimeHandler { public: void activate() override { // next activation in 1s @@ -210,7 +210,7 @@ void init() { Sound::inited = 2; Sound::timeout.time = Loop::now() + 1s; - Loop::timeouts.add(Sound::timeout); + Loop::timeHandlers.add(Sound::timeout); } Array getTypes() { diff --git a/software/system/src/posix/SpiMasterImpl.cpp b/software/system/src/posix/SpiMasterImpl.cpp index 0db4173..61d95e0 100644 --- a/software/system/src/posix/SpiMasterImpl.cpp +++ b/software/system/src/posix/SpiMasterImpl.cpp @@ -7,7 +7,7 @@ Awaitable SpiMasterImpl::transfer(int writeCount, void const *writeData, int readCount, void *readData) { if (!isInList()) { this->time = Loop::now() + 100ms; // emulate 100ms transfer time - Loop::timeouts.add(*this); + Loop::timeHandlers.add(*this); } return {this->waitlist, nullptr, writeCount, writeData, readCount, readData}; } diff --git a/software/system/src/posix/SpiMasterImpl.hpp b/software/system/src/posix/SpiMasterImpl.hpp index a07cd8d..db2f294 100644 --- a/software/system/src/posix/SpiMasterImpl.hpp +++ b/software/system/src/posix/SpiMasterImpl.hpp @@ -1,12 +1,12 @@ #include "../SpiMaster.hpp" -#include "Loop.hpp" +#include "Handlers.hpp" #include /** * Implementation of an SPI master that simply writes info about the transfer operations to Terminal::out */ -class SpiMasterImpl : public SpiMaster, public Loop::Timeout { +class SpiMasterImpl : public SpiMaster, public Loop::TimeHandler { public: /** * Constructor @@ -15,7 +15,7 @@ class SpiMasterImpl : public SpiMaster, public Loop::Timeout { explicit SpiMasterImpl(std::string name) : name(std::move(name)) { } - Awaitable transfer(int writeCount, void const *writeData, int readCount, void *readData) override; + [[nodiscard]] Awaitable transfer(int writeCount, void const *writeData, int readCount, void *readData) override; void transferBlocking(int writeCount, void const *writeData, int readCount, void *readData) override; void activate() override; diff --git a/software/system/src/posix/StorageImpl.hpp b/software/system/src/posix/StorageImpl.hpp index d13d8d0..4c533ad 100644 --- a/software/system/src/posix/StorageImpl.hpp +++ b/software/system/src/posix/StorageImpl.hpp @@ -18,13 +18,13 @@ class StorageImpl : public Storage { */ StorageImpl(std::string const &filename, int maxId, int maxDataSize); - [[nodiscard]] virtual Awaitable read(int id, int &size, void *data, Status &status) override; - [[nodiscard]] virtual Awaitable write(int id, int size, void const *data, Status &status) override; - [[nodiscard]] virtual Awaitable clear(Status &status) override; + [[nodiscard]] Awaitable read(int id, int &size, void *data, Status &status) override; + [[nodiscard]] Awaitable write(int id, int size, void const *data, Status &status) override; + [[nodiscard]] Awaitable clear(Status &status) override; - virtual Status readBlocking(int id, int &size, void *data) override; - virtual Status writeBlocking(int id, int size, void const *data) override; - virtual Status clearBlocking() override; + Status readBlocking(int id, int &size, void *data) override; + Status writeBlocking(int id, int size, void const *data) override; + Status clearBlocking() override; protected: void readData(); diff --git a/software/system/src/posix/Terminal.cpp b/software/system/src/posix/Terminal.cpp index f087990..0bb5442 100644 --- a/software/system/src/posix/Terminal.cpp +++ b/software/system/src/posix/Terminal.cpp @@ -1,11 +1,24 @@ #include "../Terminal.hpp" -#include +#include +#include +//#include namespace Terminal { void write(int index, String const &str) { - int size = ::write(index, str.data, str.count()); + std::string s(str.data, str.count()); + switch (index) { + case 1: + std::cout << s; + std::cout.flush(); + break; + case 2: + std::cerr << s; + std::cerr.flush(); + break; + } + //int size = ::write(index, str.data, str.count()); } Stream out{1}; diff --git a/software/system/src/posix/Timer.cpp b/software/system/src/posix/Timer.cpp index 2bf7f90..2518591 100644 --- a/software/system/src/posix/Timer.cpp +++ b/software/system/src/posix/Timer.cpp @@ -1,10 +1,10 @@ #include "../Timer.hpp" -#include "Loop.hpp" +#include "Handlers.hpp" namespace Timer { -class Context : public Loop::Timeout { +class Context : public Loop::TimeHandler { public: void activate() override { auto time = this->time; @@ -36,7 +36,7 @@ void init() { Timer::inited = true; Timer::context.time = now() + SystemDuration::max(); - Loop::timeouts.add(Timer::context); + Loop::timeHandlers.add(Timer::context); } SystemTime now() { diff --git a/software/system/src/posix/UsbDeviceImpl.cpp b/software/system/src/posix/UsbDeviceImpl.cpp new file mode 100644 index 0000000..1c1b54f --- /dev/null +++ b/software/system/src/posix/UsbDeviceImpl.cpp @@ -0,0 +1,89 @@ +#include "UsbDeviceImpl.hpp" +#include "../Terminal.hpp" +#include + + +UsbDeviceImpl::UsbDeviceImpl( + std::function const &getDescriptor, + std::function const &onSetConfiguration, + std::function const &onRequest) +{ + // get device descriptor + auto *deviceDescriptor = getDescriptor(usb::DescriptorType::DEVICE).cast(); + this->text = deviceDescriptor->bDeviceProtocol == 1; + + // set configuration + this->onSetConfiguration = onSetConfiguration; + //Loop::context.post([onSetConfiguration]() {onSetConfiguration(1);}); + + // call onSetConfiguration from event loop + this->time = Loop::now(); + Loop::timeHandlers.add(*this); +} + +void UsbDeviceImpl::enableEndpoints(uint8_t inFlags, uint8_t outFlags) { + Terminal::out << "enable in"; + for (int i = 0; i < 8; ++i) { + if (inFlags & (1 << i)) + Terminal::out << ' ' << dec(i); + } + Terminal::out << " out"; + for (int i = 0; i < 8; ++i) { + if (outFlags & (1 << i)) + Terminal::out << ' ' << dec(i); + } + Terminal::out << '\n'; +} + +Awaitable UsbDeviceImpl::receive(int index, int &length, void *data) { + assert(index == 1); + auto &endpoint = this->endpoints[index - 1]; + if (!isInList()) { + this->time = Loop::now() + 10ms; // emulate 10ms transfer time + Loop::timeHandlers.add(*this); + } + return {endpoint.receiveWaitlist, length, data}; +} + +Awaitable UsbDeviceImpl::send(int index, int length, void const *data) { + assert(index == 1); + auto &endpoint = this->endpoints[index - 1]; + if (!isInList()) { + this->time = Loop::now() + 10ms; // emulate 10ms transfer time + Loop::timeHandlers.add(*this); + } + return {endpoint.sendWaitlist, length, data}; +} + +void UsbDeviceImpl::activate() { + this->remove(); + + // call onSetConfiguration once + if (this->onSetConfiguration != nullptr) { + this->onSetConfiguration(*this, 1); + this->onSetConfiguration = nullptr; + } + + for (auto &endpoint : this->endpoints) { + + endpoint.sendWaitlist.resumeFirst([this](SendParameters p) { + if (this->text) { + Terminal::out << String(p.length, reinterpret_cast(p.data)); + } else { + // binary + Terminal::out << dec(p.length) << ": "; + for (int i = 0; i < p.length; ++i) { + if ((i & 15) == 0) { + if (i != 0) + Terminal::out << ",\n"; + } else { + Terminal::out << ", "; + } + Terminal::out << "0x" << hex(reinterpret_cast(p.data)[i]); + } + Terminal::out << '\n'; + } + return true; + }); + } +} diff --git a/software/system/src/posix/UsbDeviceImpl.hpp b/software/system/src/posix/UsbDeviceImpl.hpp new file mode 100644 index 0000000..3a220fe --- /dev/null +++ b/software/system/src/posix/UsbDeviceImpl.hpp @@ -0,0 +1,40 @@ +#include "../UsbDevice.hpp" +#include "Handlers.hpp" +#include + + +/** + * Implementation of an USB device that simply writes info about the transfer operations to Terminal::out + */ +class UsbDeviceImpl : public UsbDevice, public Loop::TimeHandler { +public: + /** + * Constructor + * @param getDescriptor callback for obtaining descriptors + * @param onSetConfiguration callback for setting the configuration (libusb_set_configuration() on host), always called from event loop + * @param onRequest callback for vendor specific request + */ + UsbDeviceImpl( + std::function const &getDescriptor, + std::function const &onSetConfiguration, + std::function const &onRequest); + + void enableEndpoints(uint8_t inFlags, uint8_t outFlags) override; + [[nodiscard]] Awaitable receive(int index, int &length, void *data) override; + [[nodiscard]] Awaitable send(int index, int length, void const *data) override; + + void activate() override; + +protected: + + bool text; + std::function onSetConfiguration; + + // endpoints 1 - 7 + struct Endpoint { + Waitlist receiveWaitlist; + Waitlist sendWaitlist; + }; + + Endpoint endpoints[1]; +}; diff --git a/software/system/test/UsbDeviceTest.cpp b/software/system/test/UsbDeviceTest.cpp index 186ec9c..e586231 100644 --- a/software/system/test/UsbDeviceTest.cpp +++ b/software/system/test/UsbDeviceTest.cpp @@ -6,6 +6,7 @@ #include //#include "nrf52/nrf52.hpp" //#include "nrf52/FlashImpl.hpp" +#include // Test for USB device. @@ -42,7 +43,7 @@ struct UsbConfiguration { struct usb::ConfigDescriptor config; struct usb::InterfaceDescriptor interface; struct usb::EndpointDescriptor endpoints[2]; -} __attribute__((packed)); +}; static const UsbConfiguration configurationDescriptor = { .config = { @@ -86,17 +87,17 @@ static const UsbConfiguration configurationDescriptor = { constexpr int bufferSize = 128; -uint8_t buffer[bufferSize] __attribute__((aligned(4))); +uint8_t buffer[bufferSize];// __attribute__((aligned(4))); //FlashImpl flash{0xe0000 - 0x20000, 2, 4096}; //uint8_t writeData[] = {0x12, 0x34, 0x56, 0x78, 0x9a}; // echo data from host -Coroutine echo() { +Coroutine echo(UsbDevice &usb) { while (true) { // receive data from host int length = bufferSize; - co_await UsbDevice::receive(1, length, buffer); + co_await usb.receive(1, length, buffer); // set green led to indicate processing Debug::setGreenLed(); @@ -111,7 +112,7 @@ Coroutine echo() { Debug::setColor(Debug::RED); // send data back to host - co_await UsbDevice::send(1, length, buffer); + co_await usb.send(1, length, buffer); /* // debug: send nrf52840 chip id @@ -152,7 +153,9 @@ Coroutine echo() { int main() { Loop::init(); Timer::init(); - UsbDevice::init( + + //UsbDevice::init( + UsbDeviceImpl usb( [](usb::DescriptorType descriptorType) { switch (descriptorType) { case usb::DescriptorType::DEVICE: @@ -163,10 +166,10 @@ int main() { return ConstData(); } }, - [](uint8_t bConfigurationValue) { + [](UsbDevice &usb, uint8_t bConfigurationValue) { // enable bulk endpoints 1 in and 1 out (keep control endpoint 0 enabled) Debug::setGreenLed(true); - UsbDevice::enableEndpoints(1 | (1 << 1), 1 | (1 << 1)); + usb.enableEndpoints(1 | (1 << 1), 1 | (1 << 1)); }, [](uint8_t bRequest, uint16_t wValue, uint16_t wIndex) { switch (Request(bRequest)) { @@ -190,7 +193,7 @@ int main() { Output::init(); // for debug led's // start to receive from usb host - echo(); + echo(usb); Loop::run(); } diff --git a/software/system/test/UsbTestHost.cpp b/software/system/test/UsbTestHost.cpp index 5f02f5f..4b1e431 100644 --- a/software/system/test/UsbTestHost.cpp +++ b/software/system/test/UsbTestHost.cpp @@ -1,6 +1,8 @@ #include #include #include +#undef IN +#undef OUT #include "StringOperators.hpp" @@ -169,9 +171,9 @@ int main() { } // print list of devices - //printDevices(devs); + printDevices(devices); for (int i = 0; devices[i]; ++i) { - //printDevice(devs[i]); + //printDevice(devices[i]); } // iterate over devices From 86250114d4d6c8e46f6068082114444176bcbefe Mon Sep 17 00:00:00 2001 From: Jochen Wilhelmy Date: Sat, 24 Dec 2022 21:01:41 +0100 Subject: [PATCH 3/5] Windows compatibility --- software/CMakeLists.txt | 9 +- software/control/src/BusInterface.cpp | 8 +- software/control/src/BusInterface.hpp | 2 +- software/control/src/LocalInterface.cpp | 2 +- software/control/src/RoomControl.hpp | 2 + software/control/test/BME680Test.cpp | 10 +- software/node/src/MqttSnBroker.cpp | 33 ++--- software/protocol/src/usb.hpp | 1 + software/protocol/src/zcl.hpp | 1 + software/system/src/Debug.hpp | 56 ++++---- software/system/src/Loop.hpp | 2 +- software/system/src/UsbDevice.hpp | 58 +------- software/system/src/emu/BusMasterImpl.cpp | 3 - software/system/src/emu/Gui.cpp | 3 +- software/system/src/emu/Loop.cpp | 4 +- software/system/src/emu/Radio.cpp | 2 +- software/system/src/nrf52/Loop.cpp | 2 +- software/system/src/nrf52/UsbDeviceImpl.cpp | 9 +- software/system/src/nrf52/UsbDeviceImpl.hpp | 6 +- software/system/src/posix/Calendar.cpp | 5 +- software/system/src/posix/Loop.cpp | 5 +- .../src/posix/{Handlers.hpp => Loop.hpp} | 30 +--- .../src/posix/{Handlers.cpp => Loop.inc.hpp} | 39 ++++- software/system/src/posix/Network.cpp | 18 ++- software/system/src/posix/Sound.cpp | 5 +- software/system/src/posix/SpiMasterImpl.cpp | 5 +- software/system/src/posix/SpiMasterImpl.hpp | 2 +- software/system/src/posix/Timer.cpp | 6 +- software/system/src/posix/UsbDeviceImpl.cpp | 7 +- software/system/src/posix/UsbDeviceImpl.hpp | 3 +- software/system/src/posix/libusb.hpp | 5 + software/system/test/CalendarTest.cpp | 6 +- software/system/test/FlashTest.cpp | 10 +- software/system/test/InputTest.cpp | 4 +- software/system/test/NetworkTest.cpp | 4 +- .../system/test/QuadratureDecoderTest.cpp | 12 +- software/system/test/RadioTest.cpp | 12 +- software/system/test/RandomTest.cpp | 15 +- software/system/test/SoundTest.cpp | 2 +- software/system/test/StorageTest.cpp | 10 +- software/system/test/TimerTest.cpp | 8 +- software/system/test/UsbDeviceTest.cpp | 21 +-- software/system/test/UsbTestHost.cpp | 136 +++++++++--------- software/tools/src/ieeeSniffer.cpp | 4 +- software/tools/src/radioDevice.cpp | 28 ++-- software/tools/src/terminal.cpp | 2 +- software/util/src/StringOperators.hpp | 3 +- software/util/test/utilTest.cpp | 4 + 48 files changed, 306 insertions(+), 318 deletions(-) rename software/system/src/posix/{Handlers.hpp => Loop.hpp} (62%) rename software/system/src/posix/{Handlers.cpp => Loop.inc.hpp} (77%) create mode 100644 software/system/src/posix/libusb.hpp diff --git a/software/CMakeLists.txt b/software/CMakeLists.txt index 00ef1c0..38bb4ed 100644 --- a/software/CMakeLists.txt +++ b/software/CMakeLists.txt @@ -160,6 +160,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcoroutines-ts -Wno-user-defined-literals") elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") # visual studio + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4455") else() # gcc set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcoroutines -fconcepts -Wno-literal-suffix") @@ -259,8 +260,8 @@ if(POSIX) ) set(LOOP system/src/Loop.hpp - system/src/posix/Handlers.cpp - system/src/posix/Handlers.hpp + system/src/posix/Loop.hpp + system/src/posix/Loop.inc.hpp system/src/posix/Loop.cpp ) set(NETWORK system/src/Network.hpp system/src/posix/Network.cpp) @@ -308,8 +309,8 @@ if(EMU) set(INPUT system/src/Input.hpp system/src/emu/Input.hpp system/src/emu/Input.cpp) set(LOOP system/src/Loop.hpp - system/src/posix/Handlers.hpp - system/src/posix/Handlers.cpp + system/src/posix/Loop.hpp + system/src/posix/Loop.inc.hpp system/src/emu/Loop.hpp system/src/emu/Loop.cpp system/src/emu/Gui.cpp diff --git a/software/control/src/BusInterface.cpp b/software/control/src/BusInterface.cpp index 828f0a2..f596061 100644 --- a/software/control/src/BusInterface.cpp +++ b/software/control/src/BusInterface.cpp @@ -727,13 +727,14 @@ AwaitableCoroutine BusInterface::handleCommission(uint32_t busDeviceId, uint8_t device.ptr = nullptr; } -AwaitableCoroutine BusInterface::readAttribute(int &length, uint8_t (&message)[MESSAGE_LENGTH], Device &device, +// uint8_t (&message)[MESSAGE_LENGTH] does not work on MSVC +AwaitableCoroutine BusInterface::readAttribute(int &length, uint8_t *message, Device &device, uint8_t endpointIndex, bus::Attribute attribute) { for (int retry = 0; ; ++retry) { // request attribute { - bus::MessageWriter w(message); + bus::MessageWriter w(MESSAGE_LENGTH, message); // set start of header w.setHeader(); @@ -777,8 +778,9 @@ AwaitableCoroutine BusInterface::readAttribute(int &length, uint8_t (&message)[M Timer::sleep(TIMEOUT)); // check if response was received - if (r == 1) + if (r == 1) { break; + } if (retry == MAX_RETRY) { length = -1; diff --git a/software/control/src/BusInterface.hpp b/software/control/src/BusInterface.hpp index af3a86f..47fa7b5 100644 --- a/software/control/src/BusInterface.hpp +++ b/software/control/src/BusInterface.hpp @@ -166,7 +166,7 @@ class BusInterface : public Interface { [[nodiscard]] AwaitableCoroutine handleCommission(uint32_t busDeviceId, uint8_t endpointCount); - [[nodiscard]] AwaitableCoroutine readAttribute(int &length, uint8_t (&message)[MESSAGE_LENGTH], Device &device, + [[nodiscard]] AwaitableCoroutine readAttribute(int &length, uint8_t *message, Device &device, uint8_t endpointIndex, bus::Attribute attribute); // publish messages to bus nodes diff --git a/software/control/src/LocalInterface.cpp b/software/control/src/LocalInterface.cpp index 5a2b647..cef78f2 100644 --- a/software/control/src/LocalInterface.cpp +++ b/software/control/src/LocalInterface.cpp @@ -241,7 +241,7 @@ Coroutine LocalInterface::readAirSensor(SpiMaster &spi) { #ifdef DEBUG co_await Timer::sleep(10s); #else - co_await timer::sleep(60s); + co_await Timer::sleep(60s); #endif } } diff --git a/software/control/src/RoomControl.hpp b/software/control/src/RoomControl.hpp index 70f6d42..36bcd0d 100644 --- a/software/control/src/RoomControl.hpp +++ b/software/control/src/RoomControl.hpp @@ -14,6 +14,8 @@ #include #include #include +#undef DELETE +#undef IGNORE /** diff --git a/software/control/test/BME680Test.cpp b/software/control/test/BME680Test.cpp index f75b740..44837e9 100644 --- a/software/control/test/BME680Test.cpp +++ b/software/control/test/BME680Test.cpp @@ -85,9 +85,9 @@ Coroutine getId(SpiMaster &spi) { // check chip id if (buffer[1] == CHIP_ID) - Debug::toggleGreenLed(); + debug::toggleGreen(); else - Debug::toggleRedLed(); + debug::toggleRed(); // wait for 1s co_await Timer::sleep(1s); @@ -103,7 +103,7 @@ Coroutine getRegisters(SpiMaster &spi, UsbDevice &usb) { // send to usb host co_await usb.send(1, 128, buffer + 1); - Debug::toggleBlueLed(); + debug::toggleBlue(); // wait for 5s co_await Timer::sleep(5s); @@ -119,7 +119,7 @@ Coroutine measure(SpiMaster &spi, UsbDevice &usb) { 2, 5, 2, // temperature and pressure oversampling and filter 1, // humidity oversampling 300, 100); // heater temperature (celsius) and duration (ms) - Debug::setBlueLed(true); + debug::setBlue(true); while (true) { co_await sensor.measure(); @@ -130,7 +130,7 @@ Coroutine measure(SpiMaster &spi, UsbDevice &usb) { + "Gas: " + flt(sensor.getGasResistance(), 1, 1) + "Ω\n"; co_await usb.send(1, string.count(), string.data()); - Debug::toggleRedLed(); + debug::toggleRed(); co_await Timer::sleep(10s); } diff --git a/software/node/src/MqttSnBroker.cpp b/software/node/src/MqttSnBroker.cpp index 0473722..a0aa8bb 100644 --- a/software/node/src/MqttSnBroker.cpp +++ b/software/node/src/MqttSnBroker.cpp @@ -785,7 +785,7 @@ Coroutine MqttSnBroker::receive() { auto keepAliveDuration = r.u16B(); auto clientId = r.string(); #ifdef DEBUG_PRINT - Terminal::out << (clientId + " connects to " + thisName + '\n'); + Terminal::out << clientId << " connects to " << thisName << '\n'; #endif if (connectionIndex == -1) { // try to find an unused connection @@ -835,7 +835,7 @@ Coroutine MqttSnBroker::receive() { auto msgId = r.u16B(); auto topicName = r.string(); #ifdef DEBUG_PRINT - Terminal::out << (this->connections[connectionIndex].name + " registers " + topicName + " at " + thisName + '\n'); + Terminal::out << this->connections[connectionIndex].name << " registers " << topicName << " at " << thisName << '\n'; #endif // register the topic auto returnCode = mqttsn::ReturnCode::ACCEPTED; @@ -875,7 +875,7 @@ Coroutine MqttSnBroker::receive() { auto msgId = r.u16B(); auto topicName = r.string(); #ifdef DEBUG_PRINT - Terminal::out << (this->connections[connectionIndex].name + " subscribes " + topicName + " at " + thisName + '\n'); + Terminal::out << this->connections[connectionIndex].name << " subscribes " << topicName << " at " << thisName << '\n'; #endif // register the topic int topicIndex = -1; @@ -918,7 +918,7 @@ Coroutine MqttSnBroker::receive() { auto msgId = r.u16B(); auto topicName = r.string(); #ifdef DEBUG_PRINT - Terminal::out << (this->connections[connectionIndex].name + " subscribes " + topicName + " from " + thisName + '\n'); + Terminal::out << this->connections[connectionIndex].name << " subscribes " << topicName << " from " << thisName << '\n'; #endif // register the topic if (connectionIndex == 0) { @@ -1008,12 +1008,12 @@ Coroutine MqttSnBroker::receive() { TopicInfo &topic = this->topics[topicIndex]; #ifdef DEBUG_PRINT - Terminal::out << (thisName + " receives " + dec(pubLength) + " bytes from "); + Terminal::out << thisName << " receives " << dec(pubLength) << " bytes from "; if (connectionIndex == 0) - Terminal::out << ("gateway"); + Terminal::out << "gateway"; else - Terminal::out << (connection.name); - Terminal::out << (" on topic '" + this->topics.get(topicIndex)->key + "' msgid " + dec(msgId) + '\n'); + Terminal::out << connection.name; + Terminal::out << " on topic '" << this->topics.get(topicIndex)->key << "' msgid " << dec(msgId) << '\n'; #endif // check if message is duplicate @@ -1104,12 +1104,12 @@ Coroutine MqttSnBroker::receive() { } #ifdef DEBUG_PRINT - Terminal::out << (thisName + " received " + typeString + " from "); + Terminal::out << thisName << " received " << typeString << " from "; if (connectionIndex == 0) - Terminal::out << ("gateway"); + Terminal::out << "gateway"; else - Terminal::out << (this->connections[connectionIndex].name); - Terminal::out << (" msgid " + dec(msgId) + '\n'); + Terminal::out << this->connections[connectionIndex].name; + Terminal::out << " msgid " << dec(msgId) << '\n'; #endif // check if we read past the end of the message @@ -1130,6 +1130,7 @@ Coroutine MqttSnBroker::receive() { }); } } + co_return; } Coroutine MqttSnBroker::forward() { @@ -1172,12 +1173,12 @@ Coroutine MqttSnBroker::forward() { uint16_t msgId = qos <= 0 ? 0 : getNextMsgId(); #ifdef DEBUG_PRINT - Terminal::out << (thisName + " forwards " + dec(length) + " bytes to "); + Terminal::out << thisName << " forwards " << dec(length) << " bytes to "; if (connectionIndex == 0) - Terminal::out << ("gateway"); + Terminal::out << "gateway"; else - Terminal::out << (connection.name); - Terminal::out << (" on topic '" + this->topics.get(topicIndex)->key + "' msgid " + dec(msgId) + '\n'); + Terminal::out << connection.name; + Terminal::out << " on topic '" << this->topics.get(topicIndex)->key << "' msgid " << dec(msgId) << '\n'; #endif // message flags diff --git a/software/protocol/src/usb.hpp b/software/protocol/src/usb.hpp index f6a4407..3b4ae10 100644 --- a/software/protocol/src/usb.hpp +++ b/software/protocol/src/usb.hpp @@ -58,6 +58,7 @@ enum class Request : uint8_t { STANDARD_DEVICE_IN = TYPE_STANDARD | RECIPIENT_DEVICE | IN, STANDARD_INTERFACE_OUT = TYPE_STANDARD | RECIPIENT_INTERFACE | OUT, STANDARD_INTERFACE_IN = TYPE_STANDARD | RECIPIENT_INTERFACE | IN, + VENDOR_DEVICE_OUT = TYPE_VENDOR | RECIPIENT_DEVICE | OUT, VENDOR_INTERFACE_OUT = TYPE_VENDOR | RECIPIENT_INTERFACE | OUT, }; FLAGS_ENUM(Request) diff --git a/software/protocol/src/zcl.hpp b/software/protocol/src/zcl.hpp index 8e3126d..c5779c7 100644 --- a/software/protocol/src/zcl.hpp +++ b/software/protocol/src/zcl.hpp @@ -2,6 +2,7 @@ #include #include +#undef READ_ATTRIBUTES /** diff --git a/software/system/src/Debug.hpp b/software/system/src/Debug.hpp index 11129d3..1924444 100644 --- a/software/system/src/Debug.hpp +++ b/software/system/src/Debug.hpp @@ -5,27 +5,27 @@ #include -namespace Debug { - -inline void setRedLed() {Output::set(OUTPUT_DEBUG_RED);} -inline void clearRedLed() {Output::clear(OUTPUT_DEBUG_RED);} -inline void setRedLed(bool value) {Output::set(OUTPUT_DEBUG_RED, value);} -inline void toggleRedLed() {Output::toggle(OUTPUT_DEBUG_RED);} - -inline void setGreenLed() {Output::set(OUTPUT_DEBUG_GREEN);} -inline void clearGreenLed() {Output::clear(OUTPUT_DEBUG_GREEN);} -inline void setGreenLed(bool value) {Output::set(OUTPUT_DEBUG_GREEN, value);} -inline void toggleGreenLed() {Output::toggle(OUTPUT_DEBUG_GREEN);} - -inline void setBlueLed() {Output::set(OUTPUT_DEBUG_BLUE);} -inline void clearBlueLed() {Output::clear(OUTPUT_DEBUG_BLUE);} -inline void setBlueLed(bool value) {Output::set(OUTPUT_DEBUG_BLUE, value);} -inline void toggleBlueLed() {Output::toggle(OUTPUT_DEBUG_BLUE);} - -inline void setLeds(int state) { - Debug::setRedLed(state & 1); - Debug::setGreenLed(state & 2); - Debug::setBlueLed(state & 4); +namespace debug { + +inline void setRed() {Output::set(OUTPUT_DEBUG_RED);} +inline void clearRed() {Output::clear(OUTPUT_DEBUG_RED);} +inline void setRed(bool value) {Output::set(OUTPUT_DEBUG_RED, value);} +inline void toggleRed() {Output::toggle(OUTPUT_DEBUG_RED);} + +inline void setGreen() {Output::set(OUTPUT_DEBUG_GREEN);} +inline void clearGreen() {Output::clear(OUTPUT_DEBUG_GREEN);} +inline void setGreen(bool value) {Output::set(OUTPUT_DEBUG_GREEN, value);} +inline void toggleGreen() {Output::toggle(OUTPUT_DEBUG_GREEN);} + +inline void setBlue() {Output::set(OUTPUT_DEBUG_BLUE);} +inline void clearBlue() {Output::clear(OUTPUT_DEBUG_BLUE);} +inline void setBlue(bool value) {Output::set(OUTPUT_DEBUG_BLUE, value);} +inline void toggleBlue() {Output::toggle(OUTPUT_DEBUG_BLUE);} + +inline void set(int state) { + setRed(state & 1); + setGreen(state & 2); + setBlue(state & 4); } enum Color { @@ -42,11 +42,11 @@ enum Color { WHITE = 7, }; -inline void setColor(Color color) { +inline void set(Color color) { int c = int(color); - Debug::setRedLed(c & 1); - Debug::setGreenLed(c & 2); - Debug::setBlueLed(c & 4); + setRed(c & 1); + setGreen(c & 2); + setBlue(c & 4); } class Counter { @@ -54,17 +54,17 @@ class Counter { Counter &operator ++() { ++this->c; - setLeds(this->c); + set(this->c); return *this; } Counter &operator --() { --this->c; - setLeds(this->c); + set(this->c); return *this; } int c = 0; }; -} // namespace Debug +} // namespace debug diff --git a/software/system/src/Loop.hpp b/software/system/src/Loop.hpp index 228023f..4e36711 100644 --- a/software/system/src/Loop.hpp +++ b/software/system/src/Loop.hpp @@ -14,6 +14,6 @@ void init(); void run(); // busy waiting, only for debug purposes, not very precise -void busyWait(int us); +void sleepBlocking(int us); } // namespace Loop diff --git a/software/system/src/UsbDevice.hpp b/software/system/src/UsbDevice.hpp index 8d8a39e..cb4f3fe 100644 --- a/software/system/src/UsbDevice.hpp +++ b/software/system/src/UsbDevice.hpp @@ -8,7 +8,9 @@ /** - * Interface to an USb device + * Interface to an USB device + * + * https://www.beyondlogic.org/usbnutshell/usb1.shtml */ class UsbDevice { public: @@ -52,57 +54,3 @@ class UsbDevice { [[nodiscard]] virtual Awaitable send(int index, int length, void const *data) = 0; }; - - -/* -namespace UsbDevice { - -// Internal helper: Stores the parameters and a reference to the result value in the awaitable during co_await -struct ReceiveParameters { - int &length; - void *data; -}; - -// Internal helper: Stores the parameters in the awaitable during co_await -struct SendParameters { - int length; - void const *data; -}; - - -/ ** - * Initialize USB - * @param getDescriptor callback for obtaining descriptors - * @param onSetConfiguration callback for setting the configuration (libusb_set_configuration() on host), always called from event loop - * @param onRequest callback for vendor specific request - * / -void init( - std::function const &getDescriptor, - std::function const &onSetConfiguration, - std::function const &onRequest); - -/ ** - * Enable endpoints. Can be done in onSetConfiguration. Endpoint 0 should stay enabled - * @param inFlags an enabled flag for each in endpoint - * @param outFlags an enabled flag for each out endpoint - * / -void enableEndpoints(uint8_t inFlags, uint8_t outFlags); - -/ ** - * Suspend execution using co_await until data is received from an endpoint (OUT transfer) - * @param index endpoint index (1-7) - * @param length in: length of data buffer, out: length of data actually received - * @param data data to receive, must be in RAM - * / -[[nodiscard]] Awaitable receive(int index, int &length, void *data); - -/ ** - * Suspend execution using co_await until data is sent over an endpoint (IN transfer) - * @param index endpoint index (1-7) - * @param length data length - * @param data data to send, must be in RAM - * / -[[nodiscard]] Awaitable send(int index, int length, void const *data); - -} // namespace UsbDevice -*/ diff --git a/software/system/src/emu/BusMasterImpl.cpp b/software/system/src/emu/BusMasterImpl.cpp index 914cee7..cfc6063 100644 --- a/software/system/src/emu/BusMasterImpl.cpp +++ b/software/system/src/emu/BusMasterImpl.cpp @@ -5,9 +5,6 @@ #include #include #include -#include -#include -#include namespace { diff --git a/software/system/src/emu/Gui.cpp b/software/system/src/emu/Gui.cpp index 9a83d43..5f500dc 100644 --- a/software/system/src/emu/Gui.cpp +++ b/software/system/src/emu/Gui.cpp @@ -1,3 +1,5 @@ +#define _USE_MATH_DEFINES +#include #include "Gui.hpp" #include #include @@ -5,7 +7,6 @@ #include #include #include -#include #include diff --git a/software/system/src/emu/Loop.cpp b/software/system/src/emu/Loop.cpp index 06c661a..35348db 100644 --- a/software/system/src/emu/Loop.cpp +++ b/software/system/src/emu/Loop.cpp @@ -1,5 +1,5 @@ #include "Loop.hpp" -#include "../posix/Loop.hpp" +#include "../posix/Loop.inc.hpp" #include #include @@ -113,7 +113,7 @@ void run() { // process events glfwPollEvents(); - Loop::runOnce(false); + Loop::handleEvents(false); // mouse gui.doMouse(window); diff --git a/software/system/src/emu/Radio.cpp b/software/system/src/emu/Radio.cpp index b951004..ad45def 100644 --- a/software/system/src/emu/Radio.cpp +++ b/software/system/src/emu/Radio.cpp @@ -467,7 +467,7 @@ void handle(Gui &gui) { int controlTransfer(libusb_device_handle *handle, Request request, uint16_t wValue, uint16_t wIndex) { return libusb_control_transfer(handle, - uint8_t(usb::Request::OUT | usb::Request::TYPE_VENDOR | usb::Request::RECIPIENT_INTERFACE), + uint8_t(usb::Request::VENDOR_DEVICE_OUT), uint8_t(request), wValue, wIndex, nullptr, 0, 1000); } diff --git a/software/system/src/nrf52/Loop.cpp b/software/system/src/nrf52/Loop.cpp index d9090fc..751aed4 100644 --- a/software/system/src/nrf52/Loop.cpp +++ b/software/system/src/nrf52/Loop.cpp @@ -76,7 +76,7 @@ void run() { } } -void busyWait(int us) { +void sleepBlocking(int us) { auto cycles = us * 8; for (int i = 0; i < cycles; ++i) { __NOP(); diff --git a/software/system/src/nrf52/UsbDeviceImpl.cpp b/software/system/src/nrf52/UsbDeviceImpl.cpp index 18f1af0..69e39f9 100644 --- a/software/system/src/nrf52/UsbDeviceImpl.cpp +++ b/software/system/src/nrf52/UsbDeviceImpl.cpp @@ -2,13 +2,9 @@ #include "../Debug.hpp" #include "Loop.hpp" #include "nrf52.hpp" -//#include -//#include /* - usb overview: https://www.beyondlogic.org/usbnutshell/usb5.shtml - Dependencies: Config: @@ -167,7 +163,7 @@ void UsbDeviceImpl::handle() { NRF_USBD->TASKS_EP0STALL = TRIGGER; } break; - case usb::Request::VENDOR_INTERFACE_OUT: + case usb::Request::VENDOR_DEVICE_OUT: { int wValue = (NRF_USBD->WVALUEH << 8) | NRF_USBD->WVALUEL; int wIndex = (NRF_USBD->WINDEXH << 8) | NRF_USBD->WINDEXL; @@ -201,7 +197,8 @@ void UsbDeviceImpl::handle() { ep0Data += sentCount; int l = std::min(length, 64); - array::copy(ep0Buffer, ep0Buffer + l, ep0Data); + //array::copy(ep0Buffer, ep0Buffer + l, ep0Data); + std::copy(ep0Data, ep0Data + l, ep0Buffer); NRF_USBD->EPIN[0].MAXCNT = l; NRF_USBD->TASKS_STARTEPIN[0] = TRIGGER; } else { diff --git a/software/system/src/nrf52/UsbDeviceImpl.hpp b/software/system/src/nrf52/UsbDeviceImpl.hpp index 97a0e86..0de659a 100644 --- a/software/system/src/nrf52/UsbDeviceImpl.hpp +++ b/software/system/src/nrf52/UsbDeviceImpl.hpp @@ -3,9 +3,6 @@ #include "nrf52.hpp" -#include - - /** * Implementation of an SPI master that simply writes info about the transfer operations to Terminal::out */ @@ -46,7 +43,8 @@ class UsbDeviceImpl : public UsbDevice, public Loop::Handler2 { void ep0Send(void const *data, int length) { auto d = reinterpret_cast(data); int l = std::min(length, 64); - array::copy(ep0Buffer, ep0Buffer + l, d); + //array::copy(ep0Buffer, ep0Buffer + l, d); + std::copy(d, d + l, ep0Buffer); NRF_USBD->EPIN[0].PTR = intptr_t(ep0Buffer); NRF_USBD->EPIN[0].MAXCNT = l; ep0Data = d; diff --git a/software/system/src/posix/Calendar.cpp b/software/system/src/posix/Calendar.cpp index 0032397..01f82b2 100644 --- a/software/system/src/posix/Calendar.cpp +++ b/software/system/src/posix/Calendar.cpp @@ -1,5 +1,6 @@ #include "../Calendar.hpp" -#include "Handlers.hpp" +#include "../Timer.hpp" +#include "Loop.hpp" #include @@ -29,7 +30,7 @@ void init() { return; Calendar::inited = true; - Calendar::context.time = Loop::now() + 1s; + Calendar::context.time = Timer::now() + 1s; Loop::timeHandlers.add(Calendar::context); } diff --git a/software/system/src/posix/Loop.cpp b/software/system/src/posix/Loop.cpp index 3bffdf0..c2f0ba8 100644 --- a/software/system/src/posix/Loop.cpp +++ b/software/system/src/posix/Loop.cpp @@ -1,5 +1,4 @@ -#include "Handlers.hpp" -#include "../Timer.hpp" +#include "Loop.inc.hpp" #include #include @@ -15,7 +14,7 @@ void init() { void run() { assert(Loop::inited); while (true) { - runOnce(); + handleEvents(); } } diff --git a/software/system/src/posix/Handlers.hpp b/software/system/src/posix/Loop.hpp similarity index 62% rename from software/system/src/posix/Handlers.hpp rename to software/system/src/posix/Loop.hpp index a8ebac6..4653ee2 100644 --- a/software/system/src/posix/Handlers.hpp +++ b/software/system/src/posix/Loop.hpp @@ -3,33 +3,15 @@ #include "../Loop.hpp" #include "SystemTime.hpp" #include -#include #ifdef _WIN32 -#define NOMINMAX -#include -#undef interface -#undef INTERFACE -#undef IN -#undef OUT +using Socket = uint64_t; #else -#include -using SOCKET = int; +using Socket = int; #endif namespace Loop { -// current time -inline SystemTime now() { -#ifdef _WIN32 - return {timeGetTime()}; -#else - timespec time; - clock_gettime(CLOCK_MONOTONIC, &time); - return {uint32_t(time.tv_sec * 1000 + time.tv_nsec / 1000000)}; -#endif -} - // list of file descriptors to observe readable/writable events (used in Network.cpp) class SocketHandler : public LinkedListNode { @@ -37,7 +19,7 @@ class SocketHandler : public LinkedListNode { virtual ~SocketHandler(); virtual void activate(uint16_t events) = 0; - SOCKET socket = -1; + Socket socket = -1; short int events; }; using SocketHandlerList = LinkedList; @@ -57,9 +39,9 @@ extern TimeHandlerList timeHandlers; /** - * Run the event loop only once - * @param wait wait for an event or timeout. Set to false when using a rendering loop, e.g. using GLFW + * Platform dependent function: Handle events + * @param wait wait for an event or timeout. Set to false when using a rendering loop, e.g. when using GLFW */ -void runOnce(bool wait = true); +void handleEvents(bool wait = true); } // namespace Loop diff --git a/software/system/src/posix/Handlers.cpp b/software/system/src/posix/Loop.inc.hpp similarity index 77% rename from software/system/src/posix/Handlers.cpp rename to software/system/src/posix/Loop.inc.hpp index 972404d..c129e93 100644 --- a/software/system/src/posix/Handlers.cpp +++ b/software/system/src/posix/Loop.inc.hpp @@ -1,25 +1,58 @@ -#include "Handlers.hpp" +#include "Loop.hpp" +#include "../Timer.hpp" #ifdef _WIN32 +#define NOMINMAX +#include +#undef interface +#undef INTERFACE +#undef IN +#undef OUT #define poll WSAPoll +#else +#include +#include #endif +namespace Timer { + +// current time +SystemTime now() { +#ifdef _WIN32 + return {timeGetTime()}; +#else + timespec time; + clock_gettime(CLOCK_MONOTONIC, &time); + return {uint32_t(time.tv_sec * 1000 + time.tv_nsec / 1000000)}; +#endif +} + +} + namespace Loop { +// SocketHandler + SocketHandler::~SocketHandler() { } SocketHandlerList socketHandlers; + +// TimeHandler + TimeHandler::~TimeHandler() { } TimeHandlerList timeHandlers; -void runOnce(bool wait) { + +// handleEvents + +static void handleEvents(bool wait) { // activate timeouts SystemTime time; bool activated; do { - time = now(); + time = Timer::now(); activated = false; auto it = Loop::timeHandlers.begin(); while (it != Loop::timeHandlers.end()) { diff --git a/software/system/src/posix/Network.cpp b/software/system/src/posix/Network.cpp index 5a920d4..861eae3 100644 --- a/software/system/src/posix/Network.cpp +++ b/software/system/src/posix/Network.cpp @@ -1,9 +1,11 @@ -#include "../Network.hpp" -#include "Handlers.hpp" -#include -#include #ifdef _WIN32 -#include +#define NOMINMAX +#include +#include +#undef interface +#undef INTERFACE +#undef IN +#undef OUT #else #include #include @@ -13,6 +15,10 @@ #include inline void closesocket(int s) {close(s);} #endif +#include "../Network.hpp" +#include "Loop.hpp" +#include +#include namespace Network { @@ -92,7 +98,7 @@ bool open(int index, uint16_t port) { assert(context.socket == -1); // create socket - int s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + auto s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); #ifdef _WIN32 u_long blocking = 0; ioctlsocket(s, FIONBIO, &blocking); diff --git a/software/system/src/posix/Sound.cpp b/software/system/src/posix/Sound.cpp index bc7d1ab..b73f6ed 100644 --- a/software/system/src/posix/Sound.cpp +++ b/software/system/src/posix/Sound.cpp @@ -1,5 +1,6 @@ #include "../Sound.hpp" -#include "Handlers.hpp" +#include "../Timer.hpp" +#include "Loop.hpp" #include "assert.hpp" #include "util.hpp" #define MA_NO_DECODING @@ -209,7 +210,7 @@ void init() { Sound::inited = 2; - Sound::timeout.time = Loop::now() + 1s; + Sound::timeout.time = Timer::now() + 1s; Loop::timeHandlers.add(Sound::timeout); } diff --git a/software/system/src/posix/SpiMasterImpl.cpp b/software/system/src/posix/SpiMasterImpl.cpp index 61d95e0..d23b6f6 100644 --- a/software/system/src/posix/SpiMasterImpl.cpp +++ b/software/system/src/posix/SpiMasterImpl.cpp @@ -1,12 +1,13 @@ #include "SpiMasterImpl.hpp" -#include +#include "../Timer.hpp" +#include "../Terminal.hpp" #include Awaitable SpiMasterImpl::transfer(int writeCount, void const *writeData, int readCount, void *readData) { if (!isInList()) { - this->time = Loop::now() + 100ms; // emulate 100ms transfer time + this->time = Timer::now() + 100ms; // emulate 100ms transfer time Loop::timeHandlers.add(*this); } return {this->waitlist, nullptr, writeCount, writeData, readCount, readData}; diff --git a/software/system/src/posix/SpiMasterImpl.hpp b/software/system/src/posix/SpiMasterImpl.hpp index db2f294..d8f4870 100644 --- a/software/system/src/posix/SpiMasterImpl.hpp +++ b/software/system/src/posix/SpiMasterImpl.hpp @@ -1,5 +1,5 @@ #include "../SpiMaster.hpp" -#include "Handlers.hpp" +#include "Loop.hpp" #include diff --git a/software/system/src/posix/Timer.cpp b/software/system/src/posix/Timer.cpp index 2518591..e323818 100644 --- a/software/system/src/posix/Timer.cpp +++ b/software/system/src/posix/Timer.cpp @@ -1,5 +1,5 @@ #include "../Timer.hpp" -#include "Handlers.hpp" +#include "Loop.hpp" namespace Timer { @@ -39,10 +39,6 @@ void init() { Loop::timeHandlers.add(Timer::context); } -SystemTime now() { - return Loop::now(); -} - Awaitable sleep(SystemTime time) { // check if Timer::init() was called assert(Timer::inited); diff --git a/software/system/src/posix/UsbDeviceImpl.cpp b/software/system/src/posix/UsbDeviceImpl.cpp index 1c1b54f..fcffc4e 100644 --- a/software/system/src/posix/UsbDeviceImpl.cpp +++ b/software/system/src/posix/UsbDeviceImpl.cpp @@ -1,4 +1,5 @@ #include "UsbDeviceImpl.hpp" +#include "../Timer.hpp" #include "../Terminal.hpp" #include @@ -17,7 +18,7 @@ UsbDeviceImpl::UsbDeviceImpl( //Loop::context.post([onSetConfiguration]() {onSetConfiguration(1);}); // call onSetConfiguration from event loop - this->time = Loop::now(); + this->time = Timer::now(); Loop::timeHandlers.add(*this); } @@ -39,7 +40,7 @@ Awaitable UsbDeviceImpl::receive(int index, int &l assert(index == 1); auto &endpoint = this->endpoints[index - 1]; if (!isInList()) { - this->time = Loop::now() + 10ms; // emulate 10ms transfer time + this->time = Timer::now() + 10ms; // emulate 10ms transfer time Loop::timeHandlers.add(*this); } return {endpoint.receiveWaitlist, length, data}; @@ -49,7 +50,7 @@ Awaitable UsbDeviceImpl::send(int index, int length, assert(index == 1); auto &endpoint = this->endpoints[index - 1]; if (!isInList()) { - this->time = Loop::now() + 10ms; // emulate 10ms transfer time + this->time = Timer::now() + 10ms; // emulate 10ms transfer time Loop::timeHandlers.add(*this); } return {endpoint.sendWaitlist, length, data}; diff --git a/software/system/src/posix/UsbDeviceImpl.hpp b/software/system/src/posix/UsbDeviceImpl.hpp index 3a220fe..cfc411c 100644 --- a/software/system/src/posix/UsbDeviceImpl.hpp +++ b/software/system/src/posix/UsbDeviceImpl.hpp @@ -1,6 +1,5 @@ #include "../UsbDevice.hpp" -#include "Handlers.hpp" -#include +#include "Loop.hpp" /** diff --git a/software/system/src/posix/libusb.hpp b/software/system/src/posix/libusb.hpp new file mode 100644 index 0000000..51b5826 --- /dev/null +++ b/software/system/src/posix/libusb.hpp @@ -0,0 +1,5 @@ +#define NOMINMAX +#include +#undef IN +#undef OUT +#undef READ_ATTRIBUTES diff --git a/software/system/test/CalendarTest.cpp b/software/system/test/CalendarTest.cpp index 323cb35..6eb87af 100644 --- a/software/system/test/CalendarTest.cpp +++ b/software/system/test/CalendarTest.cpp @@ -6,11 +6,11 @@ Coroutine handleSecondTick() { while (true) { co_await Calendar::secondTick(); - Debug::toggleBlueLed(); + debug::toggleBlue(); ClockTime time = Calendar::now(); - Debug::setRedLed((time.getMinutes() & 1) != 0); - Debug::setGreenLed((time.getHours() & 1) != 0); + debug::setRed((time.getMinutes() & 1) != 0); + debug::setGreen((time.getHours() & 1) != 0); } } diff --git a/software/system/test/FlashTest.cpp b/software/system/test/FlashTest.cpp index 6b6b24b..659ed65 100644 --- a/software/system/test/FlashTest.cpp +++ b/software/system/test/FlashTest.cpp @@ -14,7 +14,7 @@ void test() { drivers.flash.readBlocking(0, 4, readData); if (array::equal(4, writeData, readData)) { // blue indicates that the data is there from the last run - Debug::setBlueLed(); + debug::setBlue(); // erase drivers.flash.eraseSectorBlocking(0); @@ -22,8 +22,8 @@ void test() { // also switch on red and green leds in case erase did not work drivers.flash.readBlocking(0, 4, readData); if (array::equal(4, writeData, readData)) { - Debug::setRedLed(); - Debug::setGreenLed(); + debug::setRed(); + debug::setGreen(); } return; @@ -39,10 +39,10 @@ void test() { drivers.flash.readBlocking(0, 4, readData); if (array::equal(4, writeData, readData)) { // green indicates that write and read was successful - Debug::setGreenLed(); + debug::setGreen(); } else { // read indicates that write or read failed - Debug::setRedLed(); + debug::setRed(); } } diff --git a/software/system/test/InputTest.cpp b/software/system/test/InputTest.cpp index e7b2594..ec2164a 100644 --- a/software/system/test/InputTest.cpp +++ b/software/system/test/InputTest.cpp @@ -13,10 +13,10 @@ Coroutine handleInput() { co_await Input::trigger(1 << INPUT_POTI_BUTTON, 1 << INPUT_PCB_BUTTON, index, value); if (index == 0) { // rising edge on poti button detected - Debug::toggleRedLed(); + debug::toggleRed(); } else { // falling edge on pcb button detected - Debug::toggleGreenLed(); + debug::toggleGreen(); } } } diff --git a/software/system/test/NetworkTest.cpp b/software/system/test/NetworkTest.cpp index fb6ccf3..21155a0 100644 --- a/software/system/test/NetworkTest.cpp +++ b/software/system/test/NetworkTest.cpp @@ -20,7 +20,7 @@ Coroutine sender() { uint8_t data[] = {1, 2, 3, 4}; while (true) { co_await Network::send(0, destination, array::count(data), data); - Debug::toggleRedLed(); + debug::toggleRed(); co_await Timer::sleep(1s); } } @@ -31,7 +31,7 @@ Coroutine receiver() { while (true) { int count = 4; co_await Network::receive(0, source, count, data); - Debug::toggleGreenLed(); + debug::toggleGreen(); } } diff --git a/software/system/test/QuadratureDecoderTest.cpp b/software/system/test/QuadratureDecoderTest.cpp index b3b9cb9..241f0c1 100644 --- a/software/system/test/QuadratureDecoderTest.cpp +++ b/software/system/test/QuadratureDecoderTest.cpp @@ -25,9 +25,9 @@ Coroutine handleDecoder(QuadratureDecoder &decoder) { #ifdef DEBUG Terminal::out << "delta " << dec(delta) << '\n'; #endif - Debug::setRedLed(delta & 1); - Debug::setGreenLed(delta & 2); - Debug::setBlueLed(delta & 4); + debug::setRed(delta & 1); + debug::setGreen(delta & 2); + debug::setBlue(delta & 4); break; case 2: // button activated @@ -35,11 +35,11 @@ Coroutine handleDecoder(QuadratureDecoder &decoder) { Terminal::out << "activated " << dec(index) << '\n'; #endif if (index == 0) { - Debug::toggleRedLed(); + debug::toggleRed(); } else { - Debug::toggleGreenLed(); + debug::toggleGreen(); } - Debug::setBlueLed(false); + debug::setBlue(false); break; } } diff --git a/software/system/test/RadioTest.cpp b/software/system/test/RadioTest.cpp index 03753c5..a828016 100644 --- a/software/system/test/RadioTest.cpp +++ b/software/system/test/RadioTest.cpp @@ -56,8 +56,8 @@ Coroutine send() { packet1[3]++; bool success = result != 0; - Debug::setRedLed(!success); - Debug::setGreenLed(success); + debug::setRed(!success); + debug::setGreen(success); // change channel /*radio::stop(); @@ -81,15 +81,15 @@ Coroutine reply() { sendPacket[0] = array::count(sendPacket) - 1 - 1 + 2; while (true) { // wait for receive packet - Debug::setBlueLed(true); + debug::setBlue(true); co_await Radio::receive(0, receivePacket); - Debug::setBlueLed(false); + debug::setBlue(false); // reply - Debug::setRedLed(true); + debug::setRed(true); uint8_t result; co_await Radio::send(0, sendPacket, result); - Debug::setRedLed(false); + debug::setRed(false); } } diff --git a/software/system/test/RandomTest.cpp b/software/system/test/RandomTest.cpp index 9fdaa9f..390d659 100644 --- a/software/system/test/RandomTest.cpp +++ b/software/system/test/RandomTest.cpp @@ -4,6 +4,7 @@ #include #include #include +#include // device descriptor @@ -68,15 +69,15 @@ static const UsbConfiguration configurationDescriptor = { uint8_t sendData[16] __attribute__((aligned(4))); // send random numbers to host -Coroutine send() { +Coroutine send(UsbDevice &usb) { while (true) { // generate random numbers for (int i = 0; i < array::count(sendData); ++i) sendData[i] = Random::u8(); // send to host - co_await UsbDevice::send(1, array::count(sendData), sendData); - Debug::toggleBlueLed(); + co_await usb.send(1, array::count(sendData), sendData); + debug::toggleBlue(); co_await Timer::sleep(1s); } @@ -86,7 +87,7 @@ int main() { Loop::init(); Timer::init(); Random::init(); - UsbDevice::init( + UsbDeviceImpl usb( [](usb::DescriptorType descriptorType) { switch (descriptorType) { case usb::DescriptorType::DEVICE: @@ -97,12 +98,12 @@ int main() { return ConstData(); } }, - [](uint8_t bConfigurationValue) { + [](UsbDevice &usb, uint8_t bConfigurationValue) { // enable bulk endpoints in 1 (keep control endpoint 0 enabled) - UsbDevice::enableEndpoints(1 | (1 << 1), 1); + usb.enableEndpoints(1 | (1 << 1), 1); // start to send random numbers to host - send(); + send(usb); }, [](uint8_t bRequest, uint16_t wValue, uint16_t wIndex) { return false; diff --git a/software/system/test/SoundTest.cpp b/software/system/test/SoundTest.cpp index 739d7d9..d2c1f9a 100644 --- a/software/system/test/SoundTest.cpp +++ b/software/system/test/SoundTest.cpp @@ -14,7 +14,7 @@ Coroutine soundTest() { do { co_await Timer::sleep(1s); } while (Sound::isPlaying(index)); - Debug::toggleBlueLed(); + debug::toggleBlue(); index = (index + 1) % Sound::getTypes().count(); } diff --git a/software/system/test/StorageTest.cpp b/software/system/test/StorageTest.cpp index 275a5fe..a2642e7 100644 --- a/software/system/test/StorageTest.cpp +++ b/software/system/test/StorageTest.cpp @@ -39,14 +39,14 @@ struct Kiss32Random { }; void fail() { - Debug::setRedLed(); - Debug::setBlueLed(); + debug::setRed(); + debug::setBlue(); } void test() { - Debug::setBlueLed(); + debug::setBlue(); DriversStorageTest drivers; - Debug::clearBlueLed(); + debug::clearBlue(); // random generator for random data of random length Kiss32Random random; @@ -110,7 +110,7 @@ void test() { Terminal::out << dec(int((end - start) / 1s)) << "s\n"; // ok - Debug::setGreenLed(); + debug::setGreen(); } int main() { diff --git a/software/system/test/TimerTest.cpp b/software/system/test/TimerTest.cpp index 9d8ef8f..4124f10 100644 --- a/software/system/test/TimerTest.cpp +++ b/software/system/test/TimerTest.cpp @@ -5,17 +5,17 @@ Coroutine timer1() { while (true) { - Debug::setRedLed(true); + debug::setRed(true); co_await Timer::sleep(100ms); - Debug::setRedLed(false); + debug::setRed(false); co_await Timer::sleep(1900ms); } } Coroutine timer2() { while (true) { - Debug::toggleGreenLed(); + debug::toggleGreen(); auto timeout = Timer::now() + 3s; co_await Timer::sleep(timeout); @@ -27,7 +27,7 @@ Coroutine timer2() { Coroutine timer3() { while (true) { - Debug::toggleBlueLed(); + debug::toggleBlue(); // test if time overflow works on nrf52 auto time = Timer::now(); diff --git a/software/system/test/UsbDeviceTest.cpp b/software/system/test/UsbDeviceTest.cpp index e586231..fd949da 100644 --- a/software/system/test/UsbDeviceTest.cpp +++ b/software/system/test/UsbDeviceTest.cpp @@ -100,7 +100,7 @@ Coroutine echo(UsbDevice &usb) { co_await usb.receive(1, length, buffer); // set green led to indicate processing - Debug::setGreenLed(); + debug::setGreen(); // check received data bool error = false; @@ -109,7 +109,7 @@ Coroutine echo(UsbDevice &usb) { error = true; } if (error) - Debug::setColor(Debug::RED); + debug::set(debug::RED); // send data back to host co_await usb.send(1, length, buffer); @@ -145,8 +145,8 @@ Coroutine echo(UsbDevice &usb) { */ // clear green led and toggle blue led to indicate activity - Debug::clearGreenLed(); - Debug::toggleBlueLed(); + debug::clearGreen(); + debug::toggleBlue(); } } @@ -154,7 +154,6 @@ int main() { Loop::init(); Timer::init(); - //UsbDevice::init( UsbDeviceImpl usb( [](usb::DescriptorType descriptorType) { switch (descriptorType) { @@ -168,22 +167,26 @@ int main() { }, [](UsbDevice &usb, uint8_t bConfigurationValue) { // enable bulk endpoints 1 in and 1 out (keep control endpoint 0 enabled) - Debug::setGreenLed(true); + debug::setGreen(true); usb.enableEndpoints(1 | (1 << 1), 1 | (1 << 1)); }, [](uint8_t bRequest, uint16_t wValue, uint16_t wIndex) { switch (Request(bRequest)) { case Request::RED: - Debug::setRedLed(wValue != 0); + debug::setRed(wValue != 0); // debug: erase flash and write //flash.eraseSectorBlocking(0); //flash.writeBlocking(0, 4, writeData + 1); break; case Request::GREEN: - Debug::setGreenLed(wIndex != 0); + //Debug::setLeds(wValue); + //Debug::toggleGreenLed(); + debug::setGreen(wIndex != 0); break; case Request::BLUE: - Debug::setBlueLed(wValue == wIndex); + //Debug::setLeds(wIndex); + //Debug::toggleBlueLed(); + debug::setBlue(wValue == wIndex); break; default: return false; diff --git a/software/system/test/UsbTestHost.cpp b/software/system/test/UsbTestHost.cpp index 4b1e431..7bee60b 100644 --- a/software/system/test/UsbTestHost.cpp +++ b/software/system/test/UsbTestHost.cpp @@ -1,8 +1,6 @@ #include #include -#include -#undef IN -#undef OUT +#include #include "StringOperators.hpp" @@ -39,7 +37,7 @@ static void printDevices(libusb_device **devices) { } // https://github.com/libusb/libusb/blob/master/examples/testlibusb.c -/*static int printDevice(libusb_device *dev) { +static void printDevice(libusb_device *dev, int idVendor = 0, int idProduct = 0) { libusb_device_descriptor desc; libusb_device_handle *handle = NULL; unsigned char string[256]; @@ -48,90 +46,89 @@ static void printDevices(libusb_device **devices) { ret = libusb_get_device_descriptor(dev, &desc); if (ret < 0) { Terminal::err << "failed to get device descriptor\n"; - return -1; + return; } - printf("%04x:%04x\n", desc.idVendor, desc.idProduct); - printf("\tBus: %d\n", libusb_get_bus_number(dev)); - printf("\tDevice: %d\n", libusb_get_device_address(dev)); + if ((idVendor | idProduct) != 0 && (desc.idVendor != idVendor || desc.idProduct != idProduct)) + return; + + Terminal::out << hex(desc.idVendor) << ':' << hex(desc.idProduct) << '\n'; + Terminal::out << "\tBus: " << dec(libusb_get_bus_number(dev)) << '\n'; + Terminal::out << "\tDevice: " << dec(libusb_get_device_address(dev)) << '\n'; ret = libusb_open(dev, &handle); if (LIBUSB_SUCCESS == ret) { - printf("\tOpen\n"); + Terminal::out << "\tOpen\n"; // manufacturer if (desc.iManufacturer) { ret = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, string, sizeof(string)); if (ret > 0) - printf("\t\tManufacturer: %s\n", string); + Terminal::out << "\t\tManufacturer: " << str(string) << '\n'; } // product if (desc.iProduct) { ret = libusb_get_string_descriptor_ascii(handle, desc.iProduct, string, sizeof(string)); if (ret > 0) - printf("\t\tProduct: %s\n", string); + Terminal::out << "\t\tProduct: " << str(string) << '\n'; } libusb_close(handle); } else { - printf("\tOpen error: %d\n", ret); + Terminal::out << "\tOpen error: " << dec(ret) << '\n'; } - // configurations - for (int i = 0; i < desc.bNumConfigurations; i++) { - libusb_config_descriptor *config; - ret = libusb_get_config_descriptor(dev, i, &config); - if (LIBUSB_SUCCESS == ret) { - printf("\tConfiguration[%d]\n", i); - printf("\t\tTotalLength: %d\n", config->wTotalLength); - printf("\t\tNumInterfaces: %d\n", config->bNumInterfaces); - printf("\t\tConfigurationValue: %d\n", config->bConfigurationValue); - printf("\t\tConfiguration: %d\n", config->iConfiguration); - printf("\t\tAttributes: %02xh\n", config->bmAttributes); - printf("\t\tMaxPower: %d\n", config->MaxPower); - - } + // configurations + for (int i = 0; i < desc.bNumConfigurations; i++) { + libusb_config_descriptor *config; + ret = libusb_get_config_descriptor(dev, i, &config); + if (LIBUSB_SUCCESS == ret) { + Terminal::out << "\tConfiguration[" << dec(i) << "]\n"; + Terminal::out << "\t\tTotalLength: " << dec(config->wTotalLength) << '\n'; + Terminal::out << "\t\tNumInterfaces: " << dec(config->bNumInterfaces) << '\n'; + Terminal::out << "\t\tConfigurationValue: " << dec(config->bConfigurationValue) << '\n'; + Terminal::out << "\t\tConfiguration: " << dec(config->iConfiguration) << '\n'; + Terminal::out << "\t\tAttributes: " << hex(config->bmAttributes) << '\n'; + Terminal::out << "\t\tMaxPower: " << dec(config->MaxPower) << '\n'; + } + + // interfaces + for (int j = 0; j < config->bNumInterfaces; j++) { + libusb_interface const & interface = config->interface[j]; - // interfaces - for (int j = 0; j < config->bNumInterfaces; j++) { - libusb_interface const & interface = config->interface[j]; - - // alternate settings - for (int k = 0; k < interface.num_altsetting; k++) { - libusb_interface_descriptor const & descriptor = interface.altsetting[k]; - - printf("\t\tInterface[%d][%d]\n", j, k); - //printf("\t\t\tInterfaceNumber: %d\n", descriptor.bInterfaceNumber); - //printf("\t\t\tAlternateSetting: %d\n", descriptor.bAlternateSetting); - printf("\t\t\tNumEndpoints: %d\n", descriptor.bNumEndpoints); - printf("\t\t\tInterfaceClass: %d\n", descriptor.bInterfaceClass); - printf("\t\t\tInterfaceSubClass: %d\n", descriptor.bInterfaceSubClass); - printf("\t\t\tInterfaceProtocol: %d\n", descriptor.bInterfaceProtocol); - printf("\t\t\tInterface: %d\n", descriptor.iInterface); - - // endpoints - for (int l = 0; l < descriptor.bNumEndpoints; l++) { - libusb_endpoint_descriptor const & endpoint = descriptor.endpoint[l]; - - printf("\t\t\tEndpoint[%d]\n", l); - printf("\t\t\t\tEndpointAddress: %02xh\n", endpoint.bEndpointAddress); - printf("\t\t\t\tAttributes: %02xh\n", endpoint.bmAttributes); - printf("\t\t\t\tMaxPacketSize: %d\n", endpoint.wMaxPacketSize); - printf("\t\t\t\tInterval: %d\n", endpoint.bInterval); - printf("\t\t\t\tRefresh: %d\n", endpoint.bRefresh); - printf("\t\t\t\tSynchAddress: %d\n", endpoint.bSynchAddress); - } + // alternate settings + for (int k = 0; k < interface.num_altsetting; k++) { + libusb_interface_descriptor const & descriptor = interface.altsetting[k]; + + Terminal::out << "\t\tInterface[" << dec(j) << "][" << dec(k) << "]\n"; + //printf("\t\t\tInterfaceNumber: %d\n", descriptor.bInterfaceNumber); + //printf("\t\t\tAlternateSetting: %d\n", descriptor.bAlternateSetting); + Terminal::out << "\t\t\tNumEndpoints: " << dec(descriptor.bNumEndpoints) << '\n'; + Terminal::out << "\t\t\tInterfaceClass: " << dec(descriptor.bInterfaceClass) << '\n'; + Terminal::out << "\t\t\tInterfaceSubClass: " << dec(descriptor.bInterfaceSubClass) << '\n'; + Terminal::out << "\t\t\tInterfaceProtocol: " << dec(descriptor.bInterfaceProtocol) << '\n'; + Terminal::out << "\t\t\tInterface: " << dec(descriptor.iInterface) << '\n'; + + // endpoints + for (int l = 0; l < descriptor.bNumEndpoints; l++) { + libusb_endpoint_descriptor const & endpoint = descriptor.endpoint[l]; + + Terminal::out << "\t\t\tEndpoint[" << dec(l) << "]\n"; + Terminal::out << "\t\t\t\tEndpointAddress: " << hex(endpoint.bEndpointAddress) << '\n'; + Terminal::out << "\t\t\t\tAttributes: " << hex(endpoint.bmAttributes) << '\n'; + Terminal::out << "\t\t\t\tMaxPacketSize: " << dec(endpoint.wMaxPacketSize) << '\n'; + Terminal::out << "\t\t\t\tInterval: " << dec(endpoint.bInterval) << '\n'; + Terminal::out << "\t\t\t\tRefresh: " << dec(endpoint.bRefresh) << '\n'; + Terminal::out << "\t\t\t\tSynchAddress: " << dec(endpoint.bSynchAddress) << '\n'; } - } - - libusb_free_config_descriptor(config); + } - - - return 0; -}*/ + + libusb_free_config_descriptor(config); + } +} // vendor specific control request enum class Request : uint8_t { @@ -143,7 +140,7 @@ enum class Request : uint8_t { // sent vendor specific control request to usb device int controlOut(libusb_device_handle *handle, Request request, uint16_t wValue, uint16_t wIndex) { return libusb_control_transfer(handle, - uint8_t(usb::Request::OUT | usb::Request::TYPE_VENDOR | usb::Request::RECIPIENT_INTERFACE), + uint8_t(usb::Request::VENDOR_DEVICE_OUT), uint8_t(request), wValue, wIndex, @@ -173,7 +170,7 @@ int main() { // print list of devices printDevices(devices); for (int i = 0; devices[i]; ++i) { - //printDevice(devices[i]); + printDevice(devices[i], 0x1915, 0x1337); } // iterate over devices @@ -205,6 +202,15 @@ int main() { Terminal::err << "open error: " << dec(ret) << '\n'; continue; } + + if (libusb_kernel_driver_active(handle, 0) == 1) { + Terminal::out << "detach active kernel driver\n"; + ret = libusb_detach_kernel_driver(handle, 0); + if (ret != LIBUSB_SUCCESS) { + Terminal::out << "detach kernel driver error: " << dec(ret) << '\n'; + continue; + } + } // set configuration (reset alt_setting, reset toggles) ret = libusb_set_configuration(handle, 1); @@ -238,7 +244,7 @@ int main() { // flush out data from last run for (int i = 0; i < 4; ++i) - libusb_bulk_transfer(handle, 1 | usb::IN, buffer, 129, &transferred, 100); + ret = libusb_bulk_transfer(handle, 1 | usb::IN, buffer, 129, &transferred, 100); // echo loop: send data to device and check if we get back the same data int sendLength = 128; diff --git a/software/tools/src/ieeeSniffer.cpp b/software/tools/src/ieeeSniffer.cpp index 10f02ec..3596bfd 100644 --- a/software/tools/src/ieeeSniffer.cpp +++ b/software/tools/src/ieeeSniffer.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include // logs ieee 802.15.4 traffic to a .pcap file @@ -927,7 +927,7 @@ void handleZcl(PacketReader &r, uint8_t destinationEndpoint) { int controlTransfer(libusb_device_handle *handle, Radio::Request request, uint16_t wValue, uint16_t wIndex) { return libusb_control_transfer(handle, - uint8_t(usb::Request::OUT | usb::Request::TYPE_VENDOR | usb::Request::RECIPIENT_INTERFACE), + uint8_t(usb::Request::VENDOR_DEVICE_OUT), uint8_t(request), wValue, wIndex, nullptr, 0, 1000); } diff --git a/software/tools/src/radioDevice.cpp b/software/tools/src/radioDevice.cpp index 7155b01..6c170c3 100644 --- a/software/tools/src/radioDevice.cpp +++ b/software/tools/src/radioDevice.cpp @@ -143,12 +143,12 @@ static_assert(RADIO_CONTEXT_COUNT * 2 <= array::count(configurationDescriptor.en Barrier<> barriers[RADIO_CONTEXT_COUNT][256]; // receive from radio and send to usb host -Coroutine receive(int index) { +Coroutine receive(UsbDevice &usb, int index) { Radio::Packet packet; while (true) { // receive from radio co_await Radio::receive(index, packet); - Debug::setGreenLed(true); + debug::setGreen(true); // length without crc but with extra data int length = packet[0] - 2 + Radio::RECEIVE_EXTRA_LENGTH; @@ -156,27 +156,27 @@ Coroutine receive(int index) { // check if packet has minimum length (2 bytes frame control and extra data) if (length >= 2 + Radio::RECEIVE_EXTRA_LENGTH) { // send to usb host - co_await UsbDevice::send(1 + index, length, packet + 1); // IN + co_await usb.send(1 + index, length, packet + 1); // IN } - Debug::setGreenLed(false); + debug::setGreen(false); } } // receive from usb host and send to radio -Coroutine send(int index) { +Coroutine send(UsbDevice &usb, int index) { Radio::Packet packet; while (true) { // receive from usb host int length = RADIO_MAX_PAYLOAD_LENGTH + Radio::SEND_EXTRA_LENGTH; - co_await UsbDevice::receive(1 + index, length, packet + 1); // OUT + co_await usb.receive(1 + index, length, packet + 1); // OUT if (length == 1) { // cancel by mac counter uint8_t macCounter = packet[1]; barriers[index][macCounter].resumeAll(); } else if (length >= 2 + Radio::SEND_EXTRA_LENGTH) { - Debug::setRedLed(true); + debug::setRed(true); // set length to first byte (subtract extra data but add space for crc) packet[0] = length - Radio::SEND_EXTRA_LENGTH + 2; @@ -192,9 +192,9 @@ Coroutine send(int index) { // send mac counter and result back to usb host packet[0] = macCounter; packet[1] = result; - co_await UsbDevice::send(1 + index, 2, packet); // IN + co_await usb.send(1 + index, 2, packet); // IN } - Debug::setRedLed(false); + debug::setRed(false); } } } @@ -204,7 +204,7 @@ int main(void) { Loop::init(); Timer::init(); Radio::init(); - UsbDevice::init( + UsbDeviceImpl usb( [](usb::DescriptorType descriptorType) { switch (descriptorType) { case usb::DescriptorType::DEVICE: @@ -215,10 +215,10 @@ int main(void) { return ConstData(); } }, - [](uint8_t bConfigurationValue) { + [](UsbDevice &usb, uint8_t bConfigurationValue) { // enable bulk endpoints (keep control endpoint 0 enabled in both directions) int flags = ~(0xffffffff << (1 + RADIO_CONTEXT_COUNT)); - UsbDevice::enableEndpoints(flags, flags); + usb.enableEndpoints(flags, flags); }, [](uint8_t bRequest, uint16_t wValue, uint16_t wIndex) { switch (Radio::Request(bRequest)) { @@ -271,8 +271,8 @@ int main(void) { // start coroutines to send and receive for (int index = 0; index < RADIO_CONTEXT_COUNT; ++index) { for (int i = 0; i < 64; ++i) { - receive(index); - send(index); + receive(usb, index); + send(usb, index); } } diff --git a/software/tools/src/terminal.cpp b/software/tools/src/terminal.cpp index 5337449..b6a45c2 100644 --- a/software/tools/src/terminal.cpp +++ b/software/tools/src/terminal.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include diff --git a/software/util/src/StringOperators.hpp b/software/util/src/StringOperators.hpp index 83816f0..a9f6540 100644 --- a/software/util/src/StringOperators.hpp +++ b/software/util/src/StringOperators.hpp @@ -100,7 +100,8 @@ constexpr Flt flt(float value, int digitCount, int decimalCount) { // c-string -constexpr String str(char const *value) {return String(value);} +constexpr String str(const char *value) {return String(value);} +inline String str(const unsigned char *value) {return String(reinterpret_cast(value));} // underline node diff --git a/software/util/test/utilTest.cpp b/software/util/test/utilTest.cpp index 791bdf6..258e772 100644 --- a/software/util/test/utilTest.cpp +++ b/software/util/test/utilTest.cpp @@ -15,7 +15,11 @@ #include #include #include +#ifdef _WIN32 +#include // htonl +#else #include // htonl +#endif // test utility functions and classes From cd62443e046f056aba02dd08be23a08ad5c5bd21 Mon Sep 17 00:00:00 2001 From: Jochen Wilhelmy Date: Sat, 24 Dec 2022 21:40:59 +0100 Subject: [PATCH 4/5] Linux compatibility --- software/board/emuControl/boardConfig.hpp | 1 + software/board/emuSwitch/boardConfig.hpp | 1 + software/control/test/SSD1309Test.cpp | 2 +- software/system/src/linux/Ble.cpp | 44 ++++++++++----------- software/system/src/posix/File.hpp | 2 +- software/system/src/posix/Loop.hpp | 6 --- software/system/src/posix/Loop.inc.hpp | 8 ++-- software/system/src/posix/Network.cpp | 1 + software/system/src/stm32f0/BusNodeImpl.cpp | 2 +- software/system/test/BleTest.cpp | 2 +- 10 files changed, 34 insertions(+), 35 deletions(-) diff --git a/software/board/emuControl/boardConfig.hpp b/software/board/emuControl/boardConfig.hpp index 705f9d6..36afe94 100644 --- a/software/board/emuControl/boardConfig.hpp +++ b/software/board/emuControl/boardConfig.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/software/board/emuSwitch/boardConfig.hpp b/software/board/emuSwitch/boardConfig.hpp index 4300361..26d1cec 100644 --- a/software/board/emuSwitch/boardConfig.hpp +++ b/software/board/emuSwitch/boardConfig.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include diff --git a/software/control/test/SSD1309Test.cpp b/software/control/test/SSD1309Test.cpp index 4325034..611f5fc 100644 --- a/software/control/test/SSD1309Test.cpp +++ b/software/control/test/SSD1309Test.cpp @@ -23,7 +23,7 @@ Coroutine draw(SSD1309::Spi spi) { co_await display.set(bitmap); co_await Timer::sleep(200ms); - Debug::toggleRedLed(); + debug::toggleRed(); } } diff --git a/software/system/src/linux/Ble.cpp b/software/system/src/linux/Ble.cpp index 0def93a..1c7a446 100644 --- a/software/system/src/linux/Ble.cpp +++ b/software/system/src/linux/Ble.cpp @@ -18,7 +18,7 @@ constexpr int attCid = 4; char const *results[] = {"E8:85:47:17:BF:5A"}; // emulates a scanner -class Scanner : public Loop::Timeout { +class Scanner : public Loop::TimeHandler { public: void activate() override { auto time = this->time; @@ -50,7 +50,7 @@ class Scanner : public Loop::Timeout { Scanner scanner; -class Context : public Loop::FileDescriptor { +class Context : public Loop::SocketHandler { public: Waitlist receiveWaitlist; @@ -61,7 +61,7 @@ class Context : public Loop::FileDescriptor { if (events & POLLIN) { this->receiveWaitlist.resumeFirst([this](ReceiveParameters &p) { // receive - auto receivedCount = read(this->fd, p.data, *p.length); + auto receivedCount = read(this->socket, p.data, *p.length); if (receivedCount >= 0) { *p.length = receivedCount; return true; @@ -74,7 +74,7 @@ class Context : public Loop::FileDescriptor { if (events & POLLOUT) { this->sendWaitlist.resumeFirst([this](SendParameters &p) { // send - auto sentCount = write(this->fd, p.data, p.length); + auto sentCount = write(this->socket, p.data, p.length); return sentCount >= 0; }); if (this->sendWaitlist.isEmpty()) @@ -94,7 +94,7 @@ Awaitable scan(ScanResult &result) { // add to event loop if necessary if (!Ble::scanner.isInList()) { Ble::scanner.time = Timer::now(); - Loop::timeouts.add(Ble::scanner); + Loop::timeHandlers.add(Ble::scanner); } // add to wait list @@ -107,22 +107,22 @@ bool open(int index, Address const &address) { auto &context = Ble::contexts[index]; // create socket - assert(context.fd == -1); - int fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + assert(context.socket == -1); + auto s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); // bind sockaddr_l2 srcaddr = { .l2_family = AF_BLUETOOTH, .l2_cid = htobs(attCid)}; - if (bind(fd, (sockaddr *)&srcaddr, sizeof(srcaddr)) < 0) { - ::close(fd); + if (bind(s, (sockaddr *)&srcaddr, sizeof(srcaddr)) < 0) { + ::close(s); return false; } // set security level struct bt_security btsec = {.level = BT_SECURITY_LOW}; - if (setsockopt(fd, SOL_BLUETOOTH, BT_SECURITY, &btsec, sizeof(btsec)) != 0) { - ::close(fd); + if (setsockopt(s, SOL_BLUETOOTH, BT_SECURITY, &btsec, sizeof(btsec)) != 0) { + ::close(s); return false; } @@ -135,15 +135,15 @@ bool open(int index, Address const &address) { array::copy(dstaddr.l2_bdaddr.b, address.u8); // connect - if (connect(fd, (sockaddr *)&dstaddr, sizeof(dstaddr)) < 0) { - ::close(fd); + if (connect(s, (sockaddr *)&dstaddr, sizeof(dstaddr)) < 0) { + ::close(s); return false; } - fcntl(context.fd, F_SETFL, O_NONBLOCK); + fcntl(context.socket, F_SETFL, O_NONBLOCK); // set file descriptor - context.fd = fd; + context.socket = s; context.events = 0; return true; } @@ -151,10 +151,10 @@ bool open(int index, Address const &address) { void close(int index) { assert(uint(index) < BLUETOOTH_CONTEXT_COUNT); auto &context = Ble::contexts[index]; - assert(context.fd != -1); + assert(context.socket != -1); - ::close(context.fd); - context.fd = -1; + ::close(context.socket); + context.socket = -1; context.events = 0; // resume waiting coroutines @@ -172,13 +172,13 @@ void close(int index) { Awaitable receive(int index, int &length, uint8_t *data) { assert(uint(index) < BLUETOOTH_CONTEXT_COUNT); auto &context = Ble::contexts[index]; - assert(context.fd != -1); + assert(context.socket != -1); context.events |= POLLIN; // add to event loop if necessary if (!context.isInList()) - Loop::fileDescriptors.add(context); + Loop::socketHandlers.add(context); // add to wait list return {context.receiveWaitlist, &length, data}; @@ -187,13 +187,13 @@ Awaitable receive(int index, int &length, uint8_t *data) { Awaitable send(int index, int length, uint8_t const *data) { assert(uint(index) < BLUETOOTH_CONTEXT_COUNT); auto &context = Ble::contexts[index]; - assert(context.fd != -1); + assert(context.socket != -1); context.events |= POLLOUT; // add to event loop if necessary if (!context.isInList()) - Loop::fileDescriptors.add(context); + Loop::socketHandlers.add(context); // add to wait list return {context.sendWaitlist, length, data}; diff --git a/software/system/src/posix/File.hpp b/software/system/src/posix/File.hpp index 5e719c4..1278592 100644 --- a/software/system/src/posix/File.hpp +++ b/software/system/src/posix/File.hpp @@ -149,6 +149,6 @@ inline File::File(const fs::path &path, Mode mode) { FILE_ATTRIBUTE_NORMAL, nullptr); #else - this->file = open(name.c_str(), O_CREAT | int(mode), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); + this->file = open(path.c_str(), O_CREAT | int(mode), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); #endif } diff --git a/software/system/src/posix/Loop.hpp b/software/system/src/posix/Loop.hpp index 4653ee2..396fc49 100644 --- a/software/system/src/posix/Loop.hpp +++ b/software/system/src/posix/Loop.hpp @@ -38,10 +38,4 @@ using TimeHandlerList = LinkedList; extern TimeHandlerList timeHandlers; -/** - * Platform dependent function: Handle events - * @param wait wait for an event or timeout. Set to false when using a rendering loop, e.g. when using GLFW - */ -void handleEvents(bool wait = true); - } // namespace Loop diff --git a/software/system/src/posix/Loop.inc.hpp b/software/system/src/posix/Loop.inc.hpp index c129e93..9fed8f7 100644 --- a/software/system/src/posix/Loop.inc.hpp +++ b/software/system/src/posix/Loop.inc.hpp @@ -45,9 +45,11 @@ TimeHandler::~TimeHandler() { TimeHandlerList timeHandlers; -// handleEvents - -static void handleEvents(bool wait) { +/** + * Platform dependent function: Handle events + * @param wait wait for an event or timeout. Set to false when using a rendering loop, e.g. when using GLFW + */ +static void handleEvents(bool wait = true) { // activate timeouts SystemTime time; bool activated; diff --git a/software/system/src/posix/Network.cpp b/software/system/src/posix/Network.cpp index 861eae3..1f9da41 100644 --- a/software/system/src/posix/Network.cpp +++ b/software/system/src/posix/Network.cpp @@ -13,6 +13,7 @@ #include #include #include +#include inline void closesocket(int s) {close(s);} #endif #include "../Network.hpp" diff --git a/software/system/src/stm32f0/BusNodeImpl.cpp b/software/system/src/stm32f0/BusNodeImpl.cpp index a9bbf37..6341aff 100644 --- a/software/system/src/stm32f0/BusNodeImpl.cpp +++ b/software/system/src/stm32f0/BusNodeImpl.cpp @@ -317,7 +317,7 @@ void BusNodeImpl::timerIrqHandler() { break; default: // timeout in IDLE, SYNC or ERROR state - Debug::toggleGreenLed(); + debug::toggleGreen(); // return to idle state this->state = State::IDLE; diff --git a/software/system/test/BleTest.cpp b/software/system/test/BleTest.cpp index 4e609d5..5daa864 100644 --- a/software/system/test/BleTest.cpp +++ b/software/system/test/BleTest.cpp @@ -73,7 +73,7 @@ Coroutine scan() { << hex(result.address.u8[3]) << ':' << hex(result.address.u8[2]) << ':' << hex(result.address.u8[1]) << ':' << hex(result.address.u8[0]) << '\n'; - Debug::toggleBlueLed(); + debug::toggleBlue(); Ble::open(0, result.address); From 7ea59cce780b317614a98d0a424561454164738d Mon Sep 17 00:00:00 2001 From: Jochen Wilhelmy Date: Sun, 25 Dec 2022 15:27:37 +0100 Subject: [PATCH 5/5] Integrate Loop and Timer into loop --- software/CMakeLists.txt | 13 ++- software/board/switch/boardConfig.hpp | 4 +- software/control/src/AlarmInterface.cpp | 1 - software/control/src/BME680.cpp | 4 +- software/control/src/BusInterface.cpp | 4 +- software/control/src/FunctionInterface.cpp | 30 ++--- software/control/src/LocalInterface.cpp | 6 +- software/control/src/Menu.cpp | 1 - software/control/src/RadioInterface.cpp | 29 ++--- software/control/src/RadioInterface.hpp | 8 +- software/control/src/RoomControl.cpp | 22 ++-- software/control/src/main.cpp | 6 +- software/control/test/BME680Test.cpp | 14 +-- software/control/test/SSD1309Test.cpp | 10 +- software/node/src/MqttSnBroker.cpp | 18 +-- software/node/src/MqttSnClient.cpp | 28 ++--- software/node/src/MqttSnClient.hpp | 2 +- software/node/test/MqttSnBrokerTest.cpp | 6 +- software/node/test/MqttSnClientTest.cpp | 8 +- software/switch/src/main.cpp | 12 +- software/system/src/Loop.hpp | 25 +++- software/system/src/Timer.hpp | 33 ------ software/system/src/emu/BusMasterImpl.cpp | 2 +- software/system/src/emu/BusMasterImpl.hpp | 2 +- software/system/src/emu/BusNodeImpl.cpp | 2 +- software/system/src/emu/BusNodeImpl.hpp | 2 +- software/system/src/emu/Input.cpp | 4 +- software/system/src/emu/Loop.cpp | 46 +++----- software/system/src/emu/Loop.hpp | 5 +- software/system/src/emu/Output.cpp | 4 +- .../system/src/emu/QuadratureDecoderImpl.cpp | 2 +- .../system/src/emu/QuadratureDecoderImpl.hpp | 2 +- software/system/src/emu/Radio.cpp | 4 +- software/system/src/emu/SpiBME680.cpp | 2 +- software/system/src/emu/SpiBME680.hpp | 2 +- software/system/src/emu/SpiMPQ6526.cpp | 2 +- software/system/src/emu/SpiMPQ6526.hpp | 2 +- software/system/src/emu/SpiMR45Vxxx.cpp | 2 +- software/system/src/emu/SpiMR45Vxxx.hpp | 2 +- software/system/src/emu/SpiSSD1309.cpp | 2 +- software/system/src/emu/SpiSSD1309.hpp | 2 +- software/system/src/linux/Ble.cpp | 13 +-- software/system/src/nrf52/BusMasterImpl.cpp | 2 +- software/system/src/nrf52/BusMasterImpl.hpp | 2 +- software/system/src/nrf52/Calendar.cpp | 4 +- software/system/src/nrf52/Input.cpp | 7 +- software/system/src/nrf52/Loop.cpp | 99 +++++++++++++++- software/system/src/nrf52/Loop.hpp | 4 +- .../src/nrf52/QuadratureDecoderImpl.cpp | 2 +- .../src/nrf52/QuadratureDecoderImpl.hpp | 2 +- software/system/src/nrf52/Radio.cpp | 4 +- software/system/src/nrf52/SpiMasterImpl.cpp | 2 +- software/system/src/nrf52/SpiMasterImpl.hpp | 2 +- software/system/src/nrf52/Timer.cpp | 110 ------------------ software/system/src/nrf52/UsbDeviceImpl.cpp | 2 +- software/system/src/nrf52/UsbDeviceImpl.hpp | 2 +- software/system/src/posix/Calendar.cpp | 7 +- software/system/src/posix/Loop.cpp | 10 +- software/system/src/posix/Loop.hpp | 7 +- software/system/src/posix/Loop.inc.hpp | 91 +++++++++++---- software/system/src/posix/Network.cpp | 6 +- software/system/src/posix/Sound.cpp | 7 +- software/system/src/posix/SpiMasterImpl.cpp | 5 +- software/system/src/posix/SpiMasterImpl.hpp | 2 +- software/system/src/posix/Timer.cpp | 53 --------- software/system/src/posix/UsbDeviceImpl.cpp | 13 +-- software/system/src/posix/UsbDeviceImpl.hpp | 2 +- software/system/src/stm32f0/BusNodeImpl.cpp | 2 +- software/system/src/stm32f0/BusNodeImpl.hpp | 2 +- software/system/src/stm32f0/Input.cpp | 11 +- software/system/src/stm32f0/Loop.cpp | 87 +++++++++++++- software/system/src/stm32f0/Loop.hpp | 4 +- software/system/src/stm32f0/SpiMasterImpl.cpp | 2 +- software/system/src/stm32f0/SpiMasterImpl.hpp | 2 +- software/system/src/stm32f0/Timer.cpp | 96 --------------- software/system/test/BleTest.cpp | 6 +- software/system/test/BusMasterTest.cpp | 8 +- software/system/test/BusNodeTest.cpp | 8 +- software/system/test/CalendarTest.cpp | 4 +- software/system/test/FlashTest.cpp | 6 +- software/system/test/InputTest.cpp | 4 +- .../test/{TimerTest.cpp => LoopTest.cpp} | 20 ++-- software/system/test/NetworkTest.cpp | 8 +- .../system/test/QuadratureDecoderTest.cpp | 4 +- software/system/test/RadioTest.cpp | 12 +- software/system/test/RandomTest.cpp | 10 +- software/system/test/SoundTest.cpp | 8 +- software/system/test/SpiMasterTest.cpp | 6 +- software/system/test/StorageTest.cpp | 10 +- software/system/test/UsbDeviceTest.cpp | 6 +- software/tools/src/mdnsSniffer.cpp | 4 +- software/tools/src/radioDevice.cpp | 6 +- 92 files changed, 524 insertions(+), 647 deletions(-) delete mode 100644 software/system/src/Timer.hpp delete mode 100644 software/system/src/nrf52/Timer.cpp delete mode 100644 software/system/src/posix/Timer.cpp delete mode 100644 software/system/src/stm32f0/Timer.cpp rename software/system/test/{TimerTest.cpp => LoopTest.cpp} (61%) diff --git a/software/CMakeLists.txt b/software/CMakeLists.txt index 38bb4ed..cb7662f 100644 --- a/software/CMakeLists.txt +++ b/software/CMakeLists.txt @@ -259,6 +259,7 @@ if(POSIX) system/src/posix/FlashImpl.cpp ) set(LOOP + system/src/SystemTime.hpp system/src/Loop.hpp system/src/posix/Loop.hpp system/src/posix/Loop.inc.hpp @@ -280,7 +281,6 @@ if(POSIX) system/src/posix/StorageImpl.cpp ) set(TERMINAL system/src/Terminal.hpp system/src/posix/Terminal.cpp) - set(TIMER system/src/SystemTime.hpp system/src/Timer.hpp system/src/posix/Timer.cpp) set(USB_DEVICE system/src/UsbDevice.hpp system/src/UsbDevice.cpp @@ -308,6 +308,7 @@ if(EMU) ) set(INPUT system/src/Input.hpp system/src/emu/Input.hpp system/src/emu/Input.cpp) set(LOOP + system/src/SystemTime.hpp system/src/Loop.hpp system/src/posix/Loop.hpp system/src/posix/Loop.inc.hpp @@ -361,7 +362,9 @@ if("nrf52" IN_LIST PLATFORM) ) set(INPUT system/src/Input.hpp system/src/nrf52/Input.cpp) set(LOOP - system/src/Loop.hpp system/src/nrf52/Loop.hpp + system/src/SystemTime.hpp + system/src/Loop.hpp + system/src/nrf52/Loop.hpp system/src/nrf52/Loop.cpp system/src/nrf52/system/gcc_startup_nrf52840.S #system/src/nrf52/system/system_nrf52840.c @@ -386,7 +389,6 @@ if("nrf52" IN_LIST PLATFORM) system/src/Storage.cpp ) set(TERMINAL system/src/Terminal.hpp system/src/nrf52/Terminal.cpp) - set(TIMER system/src/SystemTime.hpp system/src/Timer.hpp system/src/nrf52/Timer.cpp) set(USB_DEVICE system/src/UsbDevice.hpp system/src/UsbDevice.cpp @@ -409,6 +411,7 @@ if("stm32f0" IN_LIST PLATFORM) ) set(INPUT system/src/Input.hpp system/src/stm32f0/gpio.hpp system/src/stm32f0/Input.cpp) set(LOOP + system/src/SystemTime.hpp system/src/Loop.hpp system/src/stm32f0/defs.hpp system/src/stm32f0/Loop.hpp @@ -430,7 +433,6 @@ if("stm32f0" IN_LIST PLATFORM) system/src/Storage.cpp ) set(TERMINAL system/src/Terminal.hpp system/src/stm32f0/Terminal.cpp) - set(TIMER system/src/SystemTime.hpp system/src/Timer.hpp system/src/stm32f0/Timer.cpp) endif() set(SYSTEM @@ -450,7 +452,6 @@ set(SYSTEM ${SPI_MASTER} ${STORAGE} ${TERMINAL} - ${TIMER} ${USB_DEVICE} system/src/FeRamStorage4.cpp system/src/FeRamStorage4.hpp @@ -700,6 +701,7 @@ add_system_test_executable(BusNode) add_system_test_executable(Calendar) add_system_test_executable(Flash) add_system_test_executable(Input) +add_system_test_executable(Loop) add_system_test_executable(Network) add_system_test_executable(QuadratureDecoder) add_system_test_executable(Radio) @@ -707,7 +709,6 @@ add_system_test_executable(Random) add_system_test_executable(Sound) add_system_test_executable(SpiMaster) add_system_test_executable(Storage) -add_system_test_executable(Timer) add_system_test_executable(UsbDevice) diff --git a/software/board/switch/boardConfig.hpp b/software/board/switch/boardConfig.hpp index 3963bd0..ad41d76 100644 --- a/software/board/switch/boardConfig.hpp +++ b/software/board/switch/boardConfig.hpp @@ -34,8 +34,8 @@ constexpr gpio::OutputConfig OUTPUTS[] = { {gpio::PB(2), gpio::Pull::DISABLED, gpio::Speed::LOW, gpio::Drive::PUSH_PULL, true, false, false}, // dummy //{gpio::PB(0), gpio::Pull::DISABLED, gpio::Speed::LOW, gpio::Drive::PUSH_PULL, true, false, false}, // green led //{gpio::PB(1), gpio::Pull::DISABLED, gpio::Speed::LOW, gpio::Drive::PUSH_PULL, true, false, false}, // blue led - {gpio::PC(9), gpio::Pull::DISABLED, gpio::Speed::LOW, gpio::Drive::PUSH_PULL, true, false, false}, // green led - {gpio::PC(8), gpio::Pull::DISABLED, gpio::Speed::LOW, gpio::Drive::PUSH_PULL, true, false, false}, // blue led + {gpio::PC(9), gpio::Pull::DISABLED, gpio::Speed::LOW, gpio::Drive::PUSH_PULL, true, false, false}, // green led STM32F051 Discovry Kit + {gpio::PC(8), gpio::Pull::DISABLED, gpio::Speed::LOW, gpio::Drive::PUSH_PULL, true, false, false}, // blue led STM32F051 Discovry Kit }; constexpr int OUTPUT_COUNT = array::count(OUTPUTS); diff --git a/software/control/src/AlarmInterface.cpp b/software/control/src/AlarmInterface.cpp index b7258e3..db97f84 100644 --- a/software/control/src/AlarmInterface.cpp +++ b/software/control/src/AlarmInterface.cpp @@ -1,5 +1,4 @@ #include "AlarmInterface.hpp" -#include #include #include #include diff --git a/software/control/src/BME680.cpp b/software/control/src/BME680.cpp index a122e6a..299c702 100644 --- a/software/control/src/BME680.cpp +++ b/software/control/src/BME680.cpp @@ -1,5 +1,5 @@ #include "BME680.hpp" -#include +#include #include @@ -116,7 +116,7 @@ AwaitableCoroutine BME680::measure() { co_await this->spi.transfer(2, this->buffer, 0, nullptr); // wait until measurement is ready - co_await Timer::sleep(1s); + co_await loop::sleep(1s); // read measurements this->buffer[0] = READ(0x1D); diff --git a/software/control/src/BusInterface.cpp b/software/control/src/BusInterface.cpp index f596061..6932e72 100644 --- a/software/control/src/BusInterface.cpp +++ b/software/control/src/BusInterface.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include @@ -775,7 +775,7 @@ AwaitableCoroutine BusInterface::readAttribute(int &length, uint8_t *message, De // wait for a response from the device int r = co_await select( this->responseBarrier.wait(length, message, device.data.address, endpointIndex, attribute), - Timer::sleep(TIMEOUT)); + loop::sleep(TIMEOUT)); // check if response was received if (r == 1) { diff --git a/software/control/src/FunctionInterface.cpp b/software/control/src/FunctionInterface.cpp index e38d489..a92981f 100644 --- a/software/control/src/FunctionInterface.cpp +++ b/software/control/src/FunctionInterface.cpp @@ -1,6 +1,6 @@ #include "FunctionInterface.hpp" #include "Cie1931.hpp" -#include +#include #include #include #include @@ -78,7 +78,7 @@ static const TypeInfo typeInfos[] = { co_await function->barrier.wait(info, &message); } else { // on: wait for message or timeout - int s = co_await select(function->barrier.wait(info, &message), Timer::sleep(timeout)); + int s = co_await select(function->barrier.wait(info, &message), loop::sleep(timeout)); if (s == 2) { // timeout: switch off message = 0; @@ -140,16 +140,16 @@ static const TypeInfo typeInfos[] = { // timeout not active and no transition in progress: wait for message co_await function->barrier.wait(info, &message); //Terminal::out << "plug " << dec(info.plug.id) << '\n'; - now = Timer::now(); + now = loop::now(); } else { // on: wait for message or timeout //Terminal::out << "select" << '\n'; bool off = timeoutActive && (!transition || offTime <= endTime); now = off ? offTime : endTime; - int s = co_await select(function->barrier.wait(info, &message), Timer::sleep(now)); + int s = co_await select(function->barrier.wait(info, &message), loop::sleep(now)); // "relaxed" time to prevent lagging behind - now = Timer::now(); + now = loop::now(); if (s == 1) { // switched on or off @@ -293,16 +293,16 @@ static const TypeInfo typeInfos[] = { // timeout not active and no transition in progress: wait for message co_await function->barrier.wait(info, &message); //Terminal::out << "plug " << dec(info.plug.id) << '\n'; - now = Timer::now(); + now = loop::now(); } else { // on: wait for message or timeout //Terminal::out << "select" << '\n'; bool off = timeoutActive && (!transition || offTime <= endTime); now = off ? offTime : endTime; - int s = co_await select(function->barrier.wait(info, &message), Timer::sleep(now)); + int s = co_await select(function->barrier.wait(info, &message), loop::sleep(now)); // "relaxed" time to prevent lagging behind - now = Timer::now(); + now = loop::now(); if (s == 1) { // switched on or off @@ -481,7 +481,7 @@ static const TypeInfo typeInfos[] = { // off: wait for message co_await function->barrier.wait(info, &message); //Terminal::out << "plug " << dec(info.plug.id) << '\n'; - now = Timer::now(); + now = loop::now(); //setColor = true; } else { // on: wait for message or timeout @@ -492,10 +492,10 @@ static const TypeInfo typeInfos[] = { bool off = timeout > 0ms && on && offTime <= now; if (off) now = offTime; - int s = co_await select(function->barrier.wait(info, &message), Timer::sleep(now)); + int s = co_await select(function->barrier.wait(info, &message), loop::sleep(now)); // "relaxed" time to prevent lagging behind - now = Timer::now(); + now = loop::now(); if (s == 1) { // switched on or off @@ -693,7 +693,7 @@ static const TypeInfo typeInfos[] = { auto d = targetPosition - position; // wait for event or timeout with a maximum to regularly report the current position - int s = co_await select(function->barrier.wait(info, &message), Timer::sleep(min(up ? -d : d, 200ms))); + int s = co_await select(function->barrier.wait(info, &message), loop::sleep(min(up ? -d : d, 200ms))); // set invalid plug index when timeout occurred if (s != 1) @@ -701,7 +701,7 @@ static const TypeInfo typeInfos[] = { //Terminal::out << "select " << dec(s) << " plug " << dec(info.plug.id) << '\n'; // get time since last time - auto time = Timer::now(); + auto time = loop::now(); d = time - lastTime; lastTime = time; @@ -724,7 +724,7 @@ static const TypeInfo typeInfos[] = { // up/down or trigger in if (message.value.u8 == 0) { // released: stop if timeout elapsed - if (Timer::now() > startTime + holdTime) + if (loop::now() > startTime + holdTime) targetPosition = position; } else { // up or down pressed @@ -783,7 +783,7 @@ static const TypeInfo typeInfos[] = { // start up = targetPosition < position; state = up ? 1 : 2; - lastTime = startTime = Timer::now(); + lastTime = startTime = loop::now(); } // publish up/down diff --git a/software/control/src/LocalInterface.cpp b/software/control/src/LocalInterface.cpp index cef78f2..8d7b949 100644 --- a/software/control/src/LocalInterface.cpp +++ b/software/control/src/LocalInterface.cpp @@ -1,5 +1,5 @@ #include "LocalInterface.hpp" -#include +#include #include #include #include @@ -239,9 +239,9 @@ Coroutine LocalInterface::readAirSensor(SpiMaster &spi) { // wait #ifdef DEBUG - co_await Timer::sleep(10s); + co_await loop::sleep(10s); #else - co_await Timer::sleep(60s); + co_await loop::sleep(60s); #endif } } diff --git a/software/control/src/Menu.cpp b/software/control/src/Menu.cpp index 5f7c15e..ab16379 100644 --- a/software/control/src/Menu.cpp +++ b/software/control/src/Menu.cpp @@ -1,5 +1,4 @@ #include "Menu.hpp" -#include #include #include #include "tahoma_8pt.hpp" // font diff --git a/software/control/src/RadioInterface.cpp b/software/control/src/RadioInterface.cpp index b77695b..94391ef 100644 --- a/software/control/src/RadioInterface.cpp +++ b/software/control/src/RadioInterface.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include @@ -939,7 +939,7 @@ bool RadioInterface::writeZclCommand(PacketWriter &w, uint8_t zclCounter, int pl } case zcl::Cluster::COLOR_CONTROL: { uint16_t color = clamp(int(message.value.f32 * 65279.0f + 0.5f), 0, 65279); - auto time = Timer::now(); + auto time = loop::now(); auto d = time - endpoint->time; if (d > 100ms || d < 0ms || endpoint->index == plugIndex) { //todo: doing it here does not work with retry @@ -1044,14 +1044,15 @@ void RadioInterface::writeFooter(PacketWriter &w, Radio::SendFlags sendFlags) { w.finish(sendFlags); } -AwaitableCoroutine RadioInterface::readAttribute(uint8_t (&packet)[MESSAGE_LENGTH], ZbDevice &device, +// uint8_t (&packet)[MESSAGE_LENGTH] does not work on MSVC +AwaitableCoroutine RadioInterface::readAttribute(uint8_t *packet, ZbDevice &device, uint8_t dstEndpoint, zcl::Cluster clusterId, zcl::Profile profile, uint8_t srcEndpoint, uint16_t attribute) { uint8_t zclCounter = this->zclCounter++; for (int retry = 0;; ++retry) { // send read attributes { - PacketWriter w(packet); + PacketWriter w(MESSAGE_LENGTH, packet); // nwk header writeNwkData(w, device); @@ -1076,7 +1077,7 @@ AwaitableCoroutine RadioInterface::readAttribute(uint8_t (&packet)[MESSAGE_LENGT int length; int r = co_await select( this->responseBarrier.wait(length, packet, srcEndpoint, zclCounter, - uint16_t(zcl::Command::READ_ATTRIBUTES_RESPONSE)), Timer::sleep(timeout)); + uint16_t(zcl::Command::READ_ATTRIBUTES_RESPONSE)), loop::sleep(timeout)); // check if response was received if (r == 1) @@ -1119,12 +1120,12 @@ optional getString(uint8_t (&packet)[N]) { Coroutine RadioInterface::broadcast() { uint8_t packet[52]; uint8_t sendResult; - auto linkTime = Timer::now() + 1s; + auto linkTime = loop::now() + 1s; auto routeTime = linkTime + 1s; while (true) { // wait until the next timeout auto time = linkTime;//min(linkTime, routeTime); - co_await Timer::sleep(time); + co_await loop::sleep(time); if (time == linkTime) { // broadcast link status every 15 seconds @@ -1233,7 +1234,7 @@ Coroutine RadioInterface::sendBeacon() { co_await Radio::send(RADIO_ZBEE, packet, sendResult); // "cool down" before a new beacon can be sent - co_await Timer::sleep(100ms); + co_await loop::sleep(100ms); } } /* @@ -2752,7 +2753,7 @@ AwaitableCoroutine RadioInterface::handleZbCommission(uint64_t deviceLongAddress if (sendResult != 0) { // wait for a response from the device int r = co_await select(this->responseBarrier.wait(length, packet1, uint8_t(0), zdpCounter, - uint16_t(zb::ZdpCommand::NODE_DESCRIPTOR_RESPONSE)), Timer::sleep(timeout)); + uint16_t(zb::ZdpCommand::NODE_DESCRIPTOR_RESPONSE)), loop::sleep(timeout)); // check if response was received if (r == 1) @@ -2793,7 +2794,7 @@ AwaitableCoroutine RadioInterface::handleZbCommission(uint64_t deviceLongAddress if (sendResult != 0) { // wait for a response from the device int r = co_await select(this->responseBarrier.wait(length, packet1, uint8_t(0), zdpCounter, - uint16_t(zb::ZdpCommand::ACTIVE_ENDPOINT_RESPONSE)), Timer::sleep(timeout)); + uint16_t(zb::ZdpCommand::ACTIVE_ENDPOINT_RESPONSE)), loop::sleep(timeout)); // check if response was received if (r == 1) @@ -2860,7 +2861,7 @@ AwaitableCoroutine RadioInterface::handleZbCommission(uint64_t deviceLongAddress if (sendResult != 0) { // wait for a response from the device int r = co_await select(this->responseBarrier.wait(length, packet2, uint8_t(0), zdpCounter, - uint16_t(zb::ZdpCommand::SIMPLE_DESCRIPTOR_RESPONSE)), Timer::sleep(timeout)); + uint16_t(zb::ZdpCommand::SIMPLE_DESCRIPTOR_RESPONSE)), loop::sleep(timeout)); // check if response was received if (r == 1) @@ -2999,7 +3000,7 @@ AwaitableCoroutine RadioInterface::handleZbCommission(uint64_t deviceLongAddress if (sendResult != 0) { // wait for a response from the device int r = co_await select(this->responseBarrier.wait(length, packet2, uint8_t(0), zdpCounter, - uint16_t(zb::ZdpCommand::BIND_RESPONSE)), Timer::sleep(timeout)); + uint16_t(zb::ZdpCommand::BIND_RESPONSE)), loop::sleep(timeout)); // check if response was received if (r == 1) @@ -3141,7 +3142,7 @@ Coroutine RadioInterface::publish() { continue; // wait for first route reply or timeout (more route replies with lower cost may arrive later) - co_await select(device->routeBarrier.wait(), Timer::sleep(timeout)); + co_await select(device->routeBarrier.wait(), loop::sleep(timeout)); Terminal::out << "Router for " << hex(device->data.shortAddress) << ": " << hex(device->routerAddress) << '\n'; @@ -3199,7 +3200,7 @@ Coroutine RadioInterface::publish() { // wait for a response from the device int length; int r = co_await select(this->responseBarrier.wait(length, packet, endpoint->data->id, - zclCounter, uint16_t(zcl::Command::DEFAULT_RESPONSE)), Timer::sleep(timeout)); + zclCounter, uint16_t(zcl::Command::DEFAULT_RESPONSE)), loop::sleep(timeout)); // check if response was received if (r == 1) { diff --git a/software/control/src/RadioInterface.hpp b/software/control/src/RadioInterface.hpp index 3b80569..c5991f0 100644 --- a/software/control/src/RadioInterface.hpp +++ b/software/control/src/RadioInterface.hpp @@ -359,6 +359,12 @@ class RadioInterface : public Interface { #endif {} + PacketWriter(int N, uint8_t *packet) : EncryptWriter(packet + 1) +#ifdef DEBUG + , end(packet + N) +#endif + {} + void security(zb::SecurityControl securityControl, uint32_t securityCounter) { this->securityControl = this->current; u8(uint8_t(securityControl)); @@ -454,7 +460,7 @@ class RadioInterface : public Interface { zcl::Cluster cluster, Message &message, ZbEndpoint *endpoint); void writeFooter(PacketWriter &w, Radio::SendFlags sendFlags); - [[nodiscard]] AwaitableCoroutine readAttribute(uint8_t (&packet)[MESSAGE_LENGTH], ZbDevice &device, + [[nodiscard]] AwaitableCoroutine readAttribute(uint8_t *packet, ZbDevice &device, uint8_t dstEndpoint, zcl::Cluster clusterId, zcl::Profile profile, uint8_t srcEndpoint, uint16_t attribute); diff --git a/software/control/src/RoomControl.cpp b/software/control/src/RoomControl.cpp index 8e2724d..9a3f264 100644 --- a/software/control/src/RoomControl.cpp +++ b/software/control/src/RoomControl.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include "tahoma_8pt.hpp" // font @@ -458,11 +458,11 @@ Coroutine RoomControl::displayMessageFilter() { continue; // wait for more messages and force resume from event loop in case the message originates from the idle menu - auto timeout = Timer::now() + 100ms; + auto timeout = loop::now() + 100ms; while (true) { ListenerInfo info2; Message message2; - int s = co_await select(barrier.wait(info2, &message2), Timer::sleep(timeout)); + int s = co_await select(barrier.wait(info2, &message2), loop::sleep(timeout)); if (s == 1) { if (this->displaySourcesList[info2.source.interfaceId].contains(info2.source.elementId, info2.source.plugIndex)) { info = info2; @@ -1194,7 +1194,7 @@ Coroutine RoomControl::idleMenu() { // wheel button pressed s = co_await select( Input::trigger(0, 1 << INPUT_WHEEL_BUTTON, index, value), - Timer::sleep(1s)); + loop::sleep(1s)); if (s == 1) { wheelPlugIndex = wheelPlugIndex + 1 >= this->configuration.wheelPlugCount ? 0 : wheelPlugIndex + 1; //Terminal::out << "next " << dec(wheelPlugIndex) << '\n'; @@ -1263,7 +1263,7 @@ AwaitableCoroutine RoomControl::devicesMenu(int interfaceIndex) { break; // show menu and wait for new event until timeout so that we can show newly commissioned devices - co_await select(menu.show(), Timer::sleep(250ms)); + co_await select(menu.show(), loop::sleep(250ms)); } interface.setCommissioning(false); } @@ -1820,7 +1820,7 @@ AwaitableCoroutine RoomControl::measureRunTime(uint8_t deviceId, uint8_t plugInd // start state = up ? 1 : 2; up = !up; - startTime = Timer::now(); + startTime = loop::now(); } else { // stop state = 0; @@ -1841,10 +1841,10 @@ AwaitableCoroutine RoomControl::measureRunTime(uint8_t deviceId, uint8_t plugInd co_await menu.show(); } else { // running: timeout so that the duration gets updated on display - co_await select(menu.show(), Timer::sleep(25ms)); + co_await select(menu.show(), loop::sleep(25ms)); if (state != 0) - duration = (Timer::now() - startTime) / 10ms; + duration = (loop::now() - startTime) / 10ms; } } } @@ -1919,7 +1919,7 @@ AwaitableCoroutine RoomControl::connectionsMenu(Array plugs, break; // show menu and wait for new event until timeout so that we can show endpoints of recommissioned device - co_await select(menu.show(), Timer::sleep(250ms)); + co_await select(menu.show(), loop::sleep(250ms)); } } @@ -2235,7 +2235,7 @@ AwaitableCoroutine RoomControl::plugsMenu(Interface &interface, uint8_t deviceId break; // show menu and wait for new event until timeout so that we can show endpoints of recommissioned device - co_await select(menu.show(), Timer::sleep(250ms)); + co_await select(menu.show(), loop::sleep(250ms)); } } @@ -2276,7 +2276,7 @@ AwaitableCoroutine RoomControl::messageLogger(Interface &interface, uint8_t devi Event &event = queue.getBack(); // show menu or receive event (event gets filled in) - int selected = co_await select(menu.show(), barrier.wait(event.info, &event.message), Timer::sleep(250ms)); + int selected = co_await select(menu.show(), barrier.wait(event.info, &event.message), loop::sleep(250ms)); if (selected == 2 && event.info.source.elementId == deviceId) { // received an event: add new empty event at the back of the queue event.type = interface.getPlugs(deviceId)[event.info.source.plugIndex]; diff --git a/software/control/src/main.cpp b/software/control/src/main.cpp index 22d2d73..e6b6103 100644 --- a/software/control/src/main.cpp +++ b/software/control/src/main.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -14,8 +13,7 @@ */ int main(int argc, const char **argv) { // init drivers - Loop::init(); - Timer::init(); + loop::init(); Calendar::init(); Radio::init(); Network::init(); @@ -47,7 +45,7 @@ int main(int argc, const char **argv) { // the room control application RoomControl roomControl(drivers); - Loop::run(); + loop::run(); return 0; } diff --git a/software/control/test/BME680Test.cpp b/software/control/test/BME680Test.cpp index 44837e9..2523c54 100644 --- a/software/control/test/BME680Test.cpp +++ b/software/control/test/BME680Test.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -90,7 +89,7 @@ Coroutine getId(SpiMaster &spi) { debug::toggleRed(); // wait for 1s - co_await Timer::sleep(1s); + co_await loop::sleep(1s); } } @@ -106,7 +105,7 @@ Coroutine getRegisters(SpiMaster &spi, UsbDevice &usb) { debug::toggleBlue(); // wait for 5s - co_await Timer::sleep(5s); + co_await loop::sleep(5s); } } @@ -132,13 +131,12 @@ Coroutine measure(SpiMaster &spi, UsbDevice &usb) { co_await usb.send(1, string.count(), string.data()); debug::toggleRed(); - co_await Timer::sleep(10s); + co_await loop::sleep(10s); } } int main(void) { - Loop::init(); - Timer::init(); + loop::init(); Output::init(); UsbDeviceImpl usb( [](usb::DescriptorType descriptorType) { @@ -166,6 +164,6 @@ int main(void) { //getId(drivers.airSensor, usb); measure(drivers.airSensor, usb); - - Loop::run(); + + loop::run(); } diff --git a/software/control/test/SSD1309Test.cpp b/software/control/test/SSD1309Test.cpp index 611f5fc..cd202a4 100644 --- a/software/control/test/SSD1309Test.cpp +++ b/software/control/test/SSD1309Test.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -21,7 +20,7 @@ Coroutine draw(SSD1309::Spi spi) { y = (y + 1) & (DISPLAY_HEIGHT - 1); co_await display.set(bitmap); - co_await Timer::sleep(200ms); + co_await loop::sleep(200ms); debug::toggleRed(); } @@ -29,12 +28,11 @@ Coroutine draw(SSD1309::Spi spi) { int main(void) { - Loop::init(); - Timer::init(); + loop::init(); Output::init(); Drivers drivers; draw({drivers.displayCommand, drivers.displayData}); - - Loop::run(); + + loop::run(); } diff --git a/software/node/src/MqttSnBroker.cpp b/software/node/src/MqttSnBroker.cpp index a0aa8bb..a615373 100644 --- a/software/node/src/MqttSnBroker.cpp +++ b/software/node/src/MqttSnBroker.cpp @@ -1,5 +1,5 @@ #include "MqttSnBroker.hpp" -#include +#include #include #include @@ -79,7 +79,7 @@ AwaitableCoroutine MqttSnBroker::connect(Network::Endpoint const &gatewayEndpoin { int length = array::count(message); int s = co_await select(this->ackWaitlist.wait(uint8_t(0), mqttsn::MessageType::CONNACK, - uint16_t(0), length, message), Timer::sleep(RECONNECT_TIME)); + uint16_t(0), length, message), loop::sleep(RECONNECT_TIME)); // check if we received a message if (s == 1) { @@ -114,7 +114,7 @@ AwaitableCoroutine MqttSnBroker::keepAlive() { // ping gateway as long as we are connected while (isGatewayConnected()) { - int s = co_await select(Timer::sleep(KEEP_ALIVE_TIME), this->keepAliveEvent.wait()); + int s = co_await select(loop::sleep(KEEP_ALIVE_TIME), this->keepAliveEvent.wait()); if (s == 1) { if (isGatewayConnected()) { @@ -131,7 +131,7 @@ AwaitableCoroutine MqttSnBroker::keepAlive() { { int length = array::count(message); int s = co_await select(this->ackWaitlist.wait(uint8_t(0), mqttsn::MessageType::PINGRESP, - uint16_t(0), length, message), Timer::sleep(RETRANSMISSION_TIME)); + uint16_t(0), length, message), loop::sleep(RETRANSMISSION_TIME)); if (s == 1) break; } @@ -176,7 +176,7 @@ AwaitableCoroutine MqttSnBroker::keepAlive() { { int length = array::count(message); int s = co_await select(this->ackWaitlist.wait(uint8_t(0), mqttsn::MessageType::SUBACK, msgId, length, - message), Timer::sleep(RETRANSMISSION_TIME)); + message), loop::sleep(RETRANSMISSION_TIME)); // check if still connected if (!isGatewayConnected()) @@ -222,7 +222,7 @@ AwaitableCoroutine MqttSnBroker::keepAlive() { { int length = array::count(message); int s = co_await select(this->ackWaitlist.wait(uint8_t(0), mqttsn::MessageType::UNSUBACK, msgId, length, - message), Timer::sleep(RETRANSMISSION_TIME)); + message), loop::sleep(RETRANSMISSION_TIME)); // check if still connected if (!isGatewayConnected()) @@ -259,7 +259,7 @@ AwaitableCoroutine MqttSnBroker::keepAlive() { { int length = array::count(message); int s = co_await select(this->ackWaitlist.wait(uint8_t(0), mqttsn::MessageType::REGACK, msgId, length, - message), Timer::sleep(RETRANSMISSION_TIME)); + message), loop::sleep(RETRANSMISSION_TIME)); // check if still connected if (!isGatewayConnected()) @@ -570,7 +570,7 @@ Coroutine MqttSnBroker::publish() { int length = array::count(messageData); int s = co_await select(this->ackWaitlist.wait(uint8_t(connectionIndex), mqttsn::MessageType::PUBACK, msgId, length, messageData), - Timer::sleep(RETRANSMISSION_TIME)); + loop::sleep(RETRANSMISSION_TIME)); // check if still connected if (!isConnected(connectionIndex)) @@ -1206,7 +1206,7 @@ Coroutine MqttSnBroker::forward() { int length2 = array::count(message); int s = co_await select(this->ackWaitlist.wait(uint8_t(connectionIndex), mqttsn::MessageType::PUBACK, msgId, length2, message2), - Timer::sleep(RETRANSMISSION_TIME)); + loop::sleep(RETRANSMISSION_TIME)); // check if still connected if (!isConnected(connectionIndex)) diff --git a/software/node/src/MqttSnClient.cpp b/software/node/src/MqttSnClient.cpp index 19c915f..2fe1dd2 100644 --- a/software/node/src/MqttSnClient.cpp +++ b/software/node/src/MqttSnClient.cpp @@ -1,5 +1,5 @@ #include "MqttSnClient.hpp" -#include +#include #include @@ -65,7 +65,7 @@ AwaitableCoroutine MqttSnClient::connect(Result &result, Network::Endpoint const Network::Endpoint source; int length = MAX_MESSAGE_LENGTH; int s = co_await select(Network::receive(NETWORK_MQTT, source, length, this->tempMessage), - Timer::sleep(RETRANSMISSION_TIME)); + loop::sleep(RETRANSMISSION_TIME)); if (s == 1) { // check if the message is from the gateway // todo @@ -126,7 +126,7 @@ AwaitableCoroutine MqttSnClient::disconnect() { { int length = array::count(message); int s = co_await select(this->ackWaitlist.wait(mqttsn::MessageType::DISCONNECT, uint16_t(0), length, message), - Timer::sleep(RETRANSMISSION_TIME)); + loop::sleep(RETRANSMISSION_TIME)); if (s == 1) break; } @@ -164,12 +164,12 @@ AwaitableCoroutine MqttSnClient::registerTopic(Result &result, uint16_t &topicId { int length = array::count(message); int s = co_await select(this->ackWaitlist.wait(mqttsn::MessageType::REGACK, msgId, length, message), - Timer::sleep(RETRANSMISSION_TIME)); + loop::sleep(RETRANSMISSION_TIME)); // check if still connected if (!isConnected()) { // make sure we are resumed from the event loop, not from ping() - co_await Timer::sleep(100ms); + co_await loop::sleep(100ms); result = Result::INVALID_STATE; co_return; } @@ -230,12 +230,12 @@ AwaitableCoroutine MqttSnClient::publish(Result &result, uint16_t topicId, mqtts { int length = array::count(message); int s = co_await select(this->ackWaitlist.wait(mqttsn::MessageType::PUBACK, msgId, length, message), - Timer::sleep(RETRANSMISSION_TIME)); + loop::sleep(RETRANSMISSION_TIME)); // check if still connected if (!isConnected()) { // make sure we are resumed from the event loop, not from ping() - co_await Timer::sleep(100ms); + co_await loop::sleep(100ms); result = Result::INVALID_STATE; break; } @@ -295,12 +295,12 @@ AwaitableCoroutine MqttSnClient::subscribeTopic(Result &result, uint16_t &topicI { int length = array::count(message); int s = co_await select(this->ackWaitlist.wait(mqttsn::MessageType::SUBACK, msgId, length, message), - Timer::sleep(RETRANSMISSION_TIME)); + loop::sleep(RETRANSMISSION_TIME)); // check if still connected if (!isConnected()) { // make sure we are resumed from the event loop, not from ping() - co_await Timer::sleep(100ms); + co_await loop::sleep(100ms); result = Result::INVALID_STATE; co_return; } @@ -354,12 +354,12 @@ AwaitableCoroutine MqttSnClient::unsubscribeTopic(Result &result, String topicFi { int length = array::count(message); int s = co_await select(this->ackWaitlist.wait(mqttsn::MessageType::UNSUBACK, msgId, length, message), - Timer::sleep(RETRANSMISSION_TIME)); + loop::sleep(RETRANSMISSION_TIME)); // check if still connected if (!isConnected()) { // make sure we are resumed from the event loop, not from ping() - co_await Timer::sleep(100ms); + co_await loop::sleep(100ms); result = Result::INVALID_STATE; co_return; } @@ -390,7 +390,7 @@ AwaitableCoroutine MqttSnClient::receive(Result &result, uint16_t &msgId, uint16 // check if still connected if (!isConnected()) { // make sure we are resumed from the event loop, not from ping() - co_await Timer::sleep(100ms); + co_await loop::sleep(100ms); result = Result::INVALID_STATE; co_return; } @@ -440,7 +440,7 @@ AwaitableCoroutine MqttSnClient::ping() { uint8_t message[4]; while (true) { - co_await Timer::sleep(KEEP_ALIVE_TIME); + co_await loop::sleep(KEEP_ALIVE_TIME); for (int retry = 0; ; ++retry) { // send idle ping @@ -454,7 +454,7 @@ AwaitableCoroutine MqttSnClient::ping() { { int length = array::count(message); int s = co_await select(this->ackWaitlist.wait(mqttsn::MessageType::PINGRESP, uint16_t(0), length, message), - Timer::sleep(RETRANSMISSION_TIME)); + loop::sleep(RETRANSMISSION_TIME)); if (s == 1) break; } diff --git a/software/node/src/MqttSnClient.hpp b/software/node/src/MqttSnClient.hpp index b7e5ef0..597668f 100644 --- a/software/node/src/MqttSnClient.hpp +++ b/software/node/src/MqttSnClient.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include #include diff --git a/software/node/test/MqttSnBrokerTest.cpp b/software/node/test/MqttSnBrokerTest.cpp index 5fa3348..d4deb77 100644 --- a/software/node/test/MqttSnBrokerTest.cpp +++ b/software/node/test/MqttSnBrokerTest.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -95,8 +94,7 @@ int main(void) { inTopic += "in"; outTopic += "out"; - Loop::init(); - Timer::init(); + loop::init(); Network::init(); Output::init(); @@ -104,5 +102,5 @@ int main(void) { test.connect(gatewayPort, name); test.function(); - Loop::run(); + loop::run(); } diff --git a/software/node/test/MqttSnClientTest.cpp b/software/node/test/MqttSnClientTest.cpp index 65c820b..d1fd3be 100644 --- a/software/node/test/MqttSnClientTest.cpp +++ b/software/node/test/MqttSnClientTest.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -59,7 +58,7 @@ Coroutine publish() { Terminal::out << "registered topic 'bar' " << dec(bar) << "\n"; while (client.isConnected()) { - co_await Timer::sleep(1s); + co_await loop::sleep(1s); // publish on topics co_await client.publish(result, foo, mqttsn::makeQos(defaultQos), "a"); @@ -73,12 +72,11 @@ Coroutine publish() { } int main(void) { - Loop::init(); - Timer::init(); + loop::init(); Network::init(); Output::init(); publish(); - Loop::run(); + loop::run(); } diff --git a/software/switch/src/main.cpp b/software/switch/src/main.cpp index 99ace4f..2cf25d3 100644 --- a/software/switch/src/main.cpp +++ b/software/switch/src/main.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -102,7 +101,7 @@ class Switch { //Terminal::out << "trigger " << dec(index) << ' ' << dec(int(state)) << '\n'; // configure when at least one button was held for 3s after all were pressed - if (this->configure && Timer::now() > this->allTime + 3s) { + if (this->configure && loop::now() > this->allTime + 3s) { // use button state as configuration int a = this->buttons & 3; if (a != 0) @@ -123,7 +122,7 @@ class Switch { // check if all buttons are pressed if (this->buttons == 0x0f) { - this->allTime = Timer::now(); + this->allTime = loop::now(); this->commission = true; this->configure = true; //Terminal::out << "all\n"; @@ -541,7 +540,7 @@ class Switch { co_await this->drivers.relayDriver.transfer(2, &w, 2, &r); // wait some time until relay contacts react - co_await Timer::sleep(RELAY_TIME); + co_await loop::sleep(RELAY_TIME); } // switch off all half bridges @@ -597,12 +596,11 @@ class Switch { int main() { - Loop::init(); + loop::init(); Output::init(); // for debug signals on pins Input::init(); - Timer::init(); Switch s; - Loop::run(); + loop::run(); } diff --git a/software/system/src/Loop.hpp b/software/system/src/Loop.hpp index 4e36711..6fd2506 100644 --- a/software/system/src/Loop.hpp +++ b/software/system/src/Loop.hpp @@ -1,7 +1,10 @@ #pragma once +#include "SystemTime.hpp" +#include -namespace Loop { + +namespace loop { /** * Initialize the event loop @@ -13,7 +16,25 @@ void init(); */ void run(); +/** + * Get current time in milliseconds + * @return current time + */ +SystemTime now(); + +/** + * Suspend execution using co_await until a given time. + * @param time time point + */ +[[nodiscard]] Awaitable sleep(SystemTime time); + +/** + * Suspend execution using co_await for a given duration. + * @param duration duration + */ +[[nodiscard]] inline Awaitable sleep(SystemDuration duration) {return sleep(now() + duration);} + // busy waiting, only for debug purposes, not very precise void sleepBlocking(int us); -} // namespace Loop +} // namespace loop diff --git a/software/system/src/Timer.hpp b/software/system/src/Timer.hpp deleted file mode 100644 index 47c4e22..0000000 --- a/software/system/src/Timer.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include "SystemTime.hpp" -#include -#include - - -namespace Timer { - -/** - * Initialize the timer - */ -void init(); - -/** - * Get current time in milliseconds - * @return current time - */ -SystemTime now(); - -/** - * Suspend execution using co_await until a given time. - * @param time time point - */ -[[nodiscard]] Awaitable sleep(SystemTime time); - -/** - * Suspend execution using co_await for a given duration. - * @param duration duration - */ -[[nodiscard]] inline Awaitable sleep(SystemDuration duration) {return sleep(now() + duration);} - -} // namespace Timer diff --git a/software/system/src/emu/BusMasterImpl.cpp b/software/system/src/emu/BusMasterImpl.cpp index cfc6063..c49bf75 100644 --- a/software/system/src/emu/BusMasterImpl.cpp +++ b/software/system/src/emu/BusMasterImpl.cpp @@ -72,7 +72,7 @@ BusMasterImpl::BusMasterImpl() : file("busMaster.bin", File::Mode::READ_WRITE) { } // add to list of handlers - Loop::handlers.add(*this); + loop::handlers.add(*this); } Awaitable BusMasterImpl::receive(int &length, uint8_t *data) { diff --git a/software/system/src/emu/BusMasterImpl.hpp b/software/system/src/emu/BusMasterImpl.hpp index e3804cf..d2d7d8a 100644 --- a/software/system/src/emu/BusMasterImpl.hpp +++ b/software/system/src/emu/BusMasterImpl.hpp @@ -7,7 +7,7 @@ #include -class BusMasterImpl : public BusMaster, public Loop::Handler2 { +class BusMasterImpl : public BusMaster, public loop::Handler2 { public: /** * Constructor diff --git a/software/system/src/emu/BusNodeImpl.cpp b/software/system/src/emu/BusNodeImpl.cpp index a21e2db..7d8b2ae 100644 --- a/software/system/src/emu/BusNodeImpl.cpp +++ b/software/system/src/emu/BusNodeImpl.cpp @@ -15,7 +15,7 @@ BusNodeImpl::BusNodeImpl() : file("busNode.bin", File::Mode::READ_WRITE) { } // add to list of handlers - Loop::handlers.add(*this); + loop::handlers.add(*this); } Awaitable BusNodeImpl::receive(int &length, uint8_t *data) { diff --git a/software/system/src/emu/BusNodeImpl.hpp b/software/system/src/emu/BusNodeImpl.hpp index 556f6d6..fda5ec0 100644 --- a/software/system/src/emu/BusNodeImpl.hpp +++ b/software/system/src/emu/BusNodeImpl.hpp @@ -6,7 +6,7 @@ #include -class BusNodeImpl : public BusNode, public Loop::Handler2 { +class BusNodeImpl : public BusNode, public loop::Handler2 { public: /** * Constructor diff --git a/software/system/src/emu/Input.cpp b/software/system/src/emu/Input.cpp index d64e233..2340039 100644 --- a/software/system/src/emu/Input.cpp +++ b/software/system/src/emu/Input.cpp @@ -42,7 +42,7 @@ void set(int index, bool value) { // event loop handler chain -Loop::Handler nextHandler = nullptr; +loop::Handler nextHandler = nullptr; void handle(Gui &gui) { // call next handler in chain Input::nextHandler(gui); @@ -68,7 +68,7 @@ void init() { return; // add to event loop handler chain - Input::nextHandler = Loop::addHandler(handle); + Input::nextHandler = loop::addHandler(handle); // set initial state using config for (int i = 0; i < INPUT_COUNT; ++i) { diff --git a/software/system/src/emu/Loop.cpp b/software/system/src/emu/Loop.cpp index 35348db..8f07e60 100644 --- a/software/system/src/emu/Loop.cpp +++ b/software/system/src/emu/Loop.cpp @@ -4,7 +4,7 @@ #include -namespace Loop { +namespace loop { // opengl window GLFWwindow *window = nullptr; @@ -14,21 +14,9 @@ void nop(Gui &gui) {} Handler nextHandler = nop; Handler addHandler(Handler handler) { Handler h = nextHandler; - Loop::nextHandler = handler; + loop::nextHandler = handler; return h; } -/* -// handler -void Handler2::handle(Gui &) {} - -// handler chain -Handler2 nopHandler; -Handler2 *firstHandler = &nopHandler; -Handler2 *setHandler(Handler2 *handler) { - auto h = firstHandler; - Loop::firstHandler = handler; - return h; -}*/ HandlerList handlers; @@ -56,6 +44,8 @@ static void mouseCallback(GLFWwindow* window, int button, int action, int mods) } void init() { + initTimer(); + // init GLFW glfwSetErrorCallback(errorCallback); if (!glfwInit()) @@ -81,16 +71,16 @@ void init() { glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); //glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GL_TRUE); - Loop::window = glfwCreateWindow(width, height, "RoomControl", NULL, NULL); + loop::window = glfwCreateWindow(width, height, "RoomControl", NULL, NULL); if (!window) { glfwTerminate(); exit(EXIT_FAILURE); } - glfwSetKeyCallback(Loop::window, keyCallback); - glfwSetMouseButtonCallback(Loop::window, mouseCallback); + glfwSetKeyCallback(loop::window, keyCallback); + glfwSetMouseButtonCallback(loop::window, mouseCallback); // make OpenGL context current - glfwMakeContextCurrent(Loop::window); + glfwMakeContextCurrent(loop::window); // load OpenGL functions gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); @@ -101,43 +91,43 @@ void init() { void run() { // check if loop::init() was called - assert(Loop::window != nullptr); + assert(loop::window != nullptr); // emulator user interface Gui gui; int frameCount = 0; //auto start = std::chrono::steady_clock::now(); - while (!glfwWindowShouldClose(Loop::window)) { + while (!glfwWindowShouldClose(loop::window)) { //auto frameStart = std::chrono::steady_clock::now(); // process events glfwPollEvents(); - Loop::handleEvents(false); + loop::handleEvents(false); // mouse gui.doMouse(window); // set viewport int width, height; - glfwGetFramebufferSize(Loop::window, &width, &height); + glfwGetFramebufferSize(loop::window, &width, &height); glViewport(0, 0, width, height); // clear screen glClear(GL_COLOR_BUFFER_BIT); // handle gui - auto it = Loop::handlers.begin(); - while (it != Loop::handlers.end()) { + auto it = loop::handlers.begin(); + while (it != loop::handlers.end()) { // increment iterator beforehand because a handler can remove() itself auto current = it; ++it; current->handle(gui); } - Loop::nextHandler(gui); + loop::nextHandler(gui); // swap render buffer to screen - glfwSwapBuffers(Loop::window); + glfwSwapBuffers(loop::window); // show frames per second /*auto now = std::chrono::steady_clock::now(); @@ -151,8 +141,8 @@ void run() { } // cleanup - glfwDestroyWindow(Loop::window); + glfwDestroyWindow(loop::window); glfwTerminate(); } -} // namespace Loop +} // namespace loop diff --git a/software/system/src/emu/Loop.hpp b/software/system/src/emu/Loop.hpp index aff56cb..6ff9670 100644 --- a/software/system/src/emu/Loop.hpp +++ b/software/system/src/emu/Loop.hpp @@ -5,7 +5,7 @@ #include -namespace Loop { +namespace loop { using Handler = void (*)(Gui &); @@ -15,7 +15,6 @@ using Handler = void (*)(Gui &); Handler addHandler(Handler handler); - /** * Event handler that handles activity of the emulated peripherals on the gui */ @@ -26,4 +25,4 @@ class Handler2 : public LinkedListNode { using HandlerList = LinkedList; extern HandlerList handlers; -} // namespace Loop +} // namespace loop diff --git a/software/system/src/emu/Output.cpp b/software/system/src/emu/Output.cpp index 1326fff..4fb5b5a 100644 --- a/software/system/src/emu/Output.cpp +++ b/software/system/src/emu/Output.cpp @@ -20,7 +20,7 @@ State states[OUTPUT_COUNT]; // event loop handler chain -Loop::Handler nextHandler = nullptr; +loop::Handler nextHandler = nullptr; void handle(Gui &gui) { // call next handler in chain Output::nextHandler(gui); @@ -38,7 +38,7 @@ void init() { return; // add to event loop handler chain - Output::nextHandler = Loop::addHandler(handle); + Output::nextHandler = loop::addHandler(handle); // set initial state using config for (int i = 0; i < OUTPUT_COUNT; ++i) { diff --git a/software/system/src/emu/QuadratureDecoderImpl.cpp b/software/system/src/emu/QuadratureDecoderImpl.cpp index 5db2aee..ac5c9f6 100644 --- a/software/system/src/emu/QuadratureDecoderImpl.cpp +++ b/software/system/src/emu/QuadratureDecoderImpl.cpp @@ -5,7 +5,7 @@ QuadratureDecoderImpl::QuadratureDecoderImpl() { // add to list of handlers - Loop::handlers.add(*this); + loop::handlers.add(*this); } Awaitable QuadratureDecoderImpl::change(int8_t& delta) { diff --git a/software/system/src/emu/QuadratureDecoderImpl.hpp b/software/system/src/emu/QuadratureDecoderImpl.hpp index af35c2d..146a9ca 100644 --- a/software/system/src/emu/QuadratureDecoderImpl.hpp +++ b/software/system/src/emu/QuadratureDecoderImpl.hpp @@ -4,7 +4,7 @@ #include "Loop.hpp" -class QuadratureDecoderImpl : public QuadratureDecoder, public Loop::Handler2 { +class QuadratureDecoderImpl : public QuadratureDecoder, public loop::Handler2 { public: /** * Constructor diff --git a/software/system/src/emu/Radio.cpp b/software/system/src/emu/Radio.cpp index ad45def..dd0f123 100644 --- a/software/system/src/emu/Radio.cpp +++ b/software/system/src/emu/Radio.cpp @@ -348,7 +348,7 @@ void SendParameters::cancel() noexcept { } // event loop handler chain -Loop::Handler nextHandler = nullptr; +loop::Handler nextHandler = nullptr; void handle(Gui &gui) { for (int index = 0; index < RADIO_CONTEXT_COUNT; ++index) { auto &context = Radio::contexts[index]; @@ -478,7 +478,7 @@ void init() { return; // add to event loop handler chain - Radio::nextHandler = Loop::addHandler(handle); + Radio::nextHandler = loop::addHandler(handle); // radio connected via USB int r = libusb_init(NULL); diff --git a/software/system/src/emu/SpiBME680.cpp b/software/system/src/emu/SpiBME680.cpp index 7f7a18f..88c1326 100644 --- a/software/system/src/emu/SpiBME680.cpp +++ b/software/system/src/emu/SpiBME680.cpp @@ -43,7 +43,7 @@ SpiBME680::SpiBME680() { setTemperature(20.0f); // add to list of handlers - Loop::handlers.add(*this); + loop::handlers.add(*this); } Awaitable SpiBME680::transfer(int writeCount, void const *writeData, int readCount, void *readData) { diff --git a/software/system/src/emu/SpiBME680.hpp b/software/system/src/emu/SpiBME680.hpp index 38f52b4..e399776 100644 --- a/software/system/src/emu/SpiBME680.hpp +++ b/software/system/src/emu/SpiBME680.hpp @@ -4,7 +4,7 @@ #include "Loop.hpp" -class SpiBME680 : public SpiMaster, public Loop::Handler2 { +class SpiBME680 : public SpiMaster, public loop::Handler2 { public: /** * Constructor diff --git a/software/system/src/emu/SpiMPQ6526.cpp b/software/system/src/emu/SpiMPQ6526.cpp index aa306c0..0ec66a8 100644 --- a/software/system/src/emu/SpiMPQ6526.cpp +++ b/software/system/src/emu/SpiMPQ6526.cpp @@ -7,7 +7,7 @@ SpiMPQ6526::SpiMPQ6526() : relayStates{Gui::LightState::DISABLED, Gui::LightState::DISABLED, Gui::LightState::DISABLED, Gui::LightState::DISABLED} { // add to list of handlers - Loop::handlers.add(*this); + loop::handlers.add(*this); } Awaitable SpiMPQ6526::transfer(int writeCount, void const *writeData, int readCount, void *readData) { diff --git a/software/system/src/emu/SpiMPQ6526.hpp b/software/system/src/emu/SpiMPQ6526.hpp index d7cbb9e..83c36d4 100644 --- a/software/system/src/emu/SpiMPQ6526.hpp +++ b/software/system/src/emu/SpiMPQ6526.hpp @@ -7,7 +7,7 @@ /** * Emulates a MPQ6526 motor/relay driver */ -class SpiMPQ6526 : public SpiMaster, public Loop::Handler2 { +class SpiMPQ6526 : public SpiMaster, public loop::Handler2 { public: /** * Constructor diff --git a/software/system/src/emu/SpiMR45Vxxx.cpp b/software/system/src/emu/SpiMR45Vxxx.cpp index 66540b1..853f6c7 100644 --- a/software/system/src/emu/SpiMR45Vxxx.cpp +++ b/software/system/src/emu/SpiMR45Vxxx.cpp @@ -18,7 +18,7 @@ SpiMR45Vxxx::SpiMR45Vxxx(std::string const &filename, int size) this->file.resize(size, 0xff); // add to list of handlers - Loop::handlers.add(*this); + loop::handlers.add(*this); } Awaitable SpiMR45Vxxx::transfer(int writeCount, void const *writeData, int readCount, void *readData) { diff --git a/software/system/src/emu/SpiMR45Vxxx.hpp b/software/system/src/emu/SpiMR45Vxxx.hpp index d88f8ca..5cf678b 100644 --- a/software/system/src/emu/SpiMR45Vxxx.hpp +++ b/software/system/src/emu/SpiMR45Vxxx.hpp @@ -9,7 +9,7 @@ /** * Emulates a MR45V064B FeRam an SPI slave device */ -class SpiMR45Vxxx : public SpiMaster, public Loop::Handler2 { +class SpiMR45Vxxx : public SpiMaster, public loop::Handler2 { public: /** * Constructor diff --git a/software/system/src/emu/SpiSSD1309.cpp b/software/system/src/emu/SpiSSD1309.cpp index f331968..868c093 100644 --- a/software/system/src/emu/SpiSSD1309.cpp +++ b/software/system/src/emu/SpiSSD1309.cpp @@ -12,7 +12,7 @@ SpiSSD1309::SpiSSD1309(int width, int height) this->displayBuffer = new uint8_t[width * height]; // add to list of handlers - Loop::handlers.add(*this); + loop::handlers.add(*this); } SpiSSD1309::~SpiSSD1309() { diff --git a/software/system/src/emu/SpiSSD1309.hpp b/software/system/src/emu/SpiSSD1309.hpp index fae6018..9bf89d5 100644 --- a/software/system/src/emu/SpiSSD1309.hpp +++ b/software/system/src/emu/SpiSSD1309.hpp @@ -7,7 +7,7 @@ /** * Emulates a SSD1309 based display as an SPI slave device */ -class SpiSSD1309 : public SpiMaster, public Loop::Handler2 { +class SpiSSD1309 : public SpiMaster, public loop::Handler2 { public: /** * Constructor diff --git a/software/system/src/linux/Ble.cpp b/software/system/src/linux/Ble.cpp index 1c7a446..bfc51a5 100644 --- a/software/system/src/linux/Ble.cpp +++ b/software/system/src/linux/Ble.cpp @@ -1,6 +1,5 @@ #include "../Ble.hpp" #include "../posix/Loop.hpp" -#include "Timer.hpp" #include "bt.hpp" #include #include @@ -18,7 +17,7 @@ constexpr int attCid = 4; char const *results[] = {"E8:85:47:17:BF:5A"}; // emulates a scanner -class Scanner : public Loop::TimeHandler { +class Scanner : public loop::TimeHandler { public: void activate() override { auto time = this->time; @@ -50,7 +49,7 @@ class Scanner : public Loop::TimeHandler { Scanner scanner; -class Context : public Loop::SocketHandler { +class Context : public loop::SocketHandler { public: Waitlist receiveWaitlist; @@ -93,8 +92,8 @@ void init() { Awaitable scan(ScanResult &result) { // add to event loop if necessary if (!Ble::scanner.isInList()) { - Ble::scanner.time = Timer::now(); - Loop::timeHandlers.add(Ble::scanner); + Ble::scanner.time = loop::now(); + loop::timeHandlers.add(Ble::scanner); } // add to wait list @@ -178,7 +177,7 @@ Awaitable receive(int index, int &length, uint8_t *data) { // add to event loop if necessary if (!context.isInList()) - Loop::socketHandlers.add(context); + loop::socketHandlers.add(context); // add to wait list return {context.receiveWaitlist, &length, data}; @@ -193,7 +192,7 @@ Awaitable send(int index, int length, uint8_t const *data) { // add to event loop if necessary if (!context.isInList()) - Loop::socketHandlers.add(context); + loop::socketHandlers.add(context); // add to wait list return {context.sendWaitlist, length, data}; diff --git a/software/system/src/nrf52/BusMasterImpl.cpp b/software/system/src/nrf52/BusMasterImpl.cpp index ea605d1..fc1879b 100644 --- a/software/system/src/nrf52/BusMasterImpl.cpp +++ b/software/system/src/nrf52/BusMasterImpl.cpp @@ -77,7 +77,7 @@ BusMasterImpl::BusMasterImpl(int rxPin, int txPin) : rxPin(rxPin), txPin(txPin) | N(EGU_INTENSET_TRIGGERED2, Set); // add to list of handlers - Loop::handlers.add(*this); + loop::handlers.add(*this); } Awaitable BusMasterImpl::receive(int &length, uint8_t *data) { diff --git a/software/system/src/nrf52/BusMasterImpl.hpp b/software/system/src/nrf52/BusMasterImpl.hpp index 04fb391..c6c9654 100644 --- a/software/system/src/nrf52/BusMasterImpl.hpp +++ b/software/system/src/nrf52/BusMasterImpl.hpp @@ -11,7 +11,7 @@ void UARTE0_UART0_IRQHandler(); void TIMER1_IRQHandler(); } -class BusMasterImpl : public BusMaster, public Loop::Handler2 { +class BusMasterImpl : public BusMaster, public loop::Handler2 { friend void UARTE0_UART0_IRQHandler(); friend void TIMER1_IRQHandler(); public: diff --git a/software/system/src/nrf52/Calendar.cpp b/software/system/src/nrf52/Calendar.cpp index 8a387e2..4b98667 100644 --- a/software/system/src/nrf52/Calendar.cpp +++ b/software/system/src/nrf52/Calendar.cpp @@ -26,7 +26,7 @@ uint8_t hours = 0; uint8_t weekday = 0; // event loop handler chain -Loop::Handler nextHandler = nullptr; +loop::Handler nextHandler = nullptr; void handle() { if (NRF_RTC0->EVENTS_COMPARE[2]) { // clear pending interrupt flags at peripheral and NVIC @@ -61,7 +61,7 @@ void init() { return; // add to event loop handler chain - Calendar::nextHandler = Loop::addHandler(handle); + Calendar::nextHandler = loop::addHandler(handle); // use channel 2 of RTC0 NRF_RTC0->CC[2] = (NRF_RTC0->COUNTER + 16384 + 256) & ~16383; diff --git a/software/system/src/nrf52/Input.cpp b/software/system/src/nrf52/Input.cpp index b387f9b..58ecc91 100644 --- a/software/system/src/nrf52/Input.cpp +++ b/software/system/src/nrf52/Input.cpp @@ -1,5 +1,4 @@ #include "../Input.hpp" -#include "../Timer.hpp" #include "Loop.hpp" #include "gpio.hpp" #include @@ -42,7 +41,7 @@ State states[TRIGGER_COUNT]; Waitlist waitlist; // event loop handler chain -Loop::Handler nextHandler = nullptr; +loop::Handler nextHandler = nullptr; void handle() { if (isInterruptPending(GPIOTE_IRQn)) { // debounce timeout after about 50ms @@ -128,14 +127,14 @@ void init() { // configure triggers if (TRIGGER_COUNT > 0) { - Timer::init(); + //Timer::init(); // check if already initialized if (Input::nextHandler != nullptr) return; // add to event loop handler chain - Input::nextHandler = Loop::addHandler(handle); + Input::nextHandler = loop::addHandler(handle); for (int index = 0; index < TRIGGER_COUNT; ++index) { auto &input = INPUTS[index]; diff --git a/software/system/src/nrf52/Loop.cpp b/software/system/src/nrf52/Loop.cpp index 751aed4..522246e 100644 --- a/software/system/src/nrf52/Loop.cpp +++ b/software/system/src/nrf52/Loop.cpp @@ -2,6 +2,18 @@ #include "nrf52.hpp" +/* + https://infocenter.nordicsemi.com/topic/struct_nrf52/struct/nrf52840.html + + Dependencies: + + Config: + + Resources: + NRF_RTC0 + CC[0] +*/ + // called by system/gcc_startup_nrf52840.S extern "C" { void SystemInit() { @@ -16,7 +28,19 @@ void SystemInit() { } } -namespace Loop { +namespace loop { + +// timer interval is 1024 seconds (2^24 / 16384Hz), given in milliseconds +constexpr int INTERVAL = 1024000; + +uint32_t baseTime = 0; + +// next timeout of a timer in the list +SystemTime next; + +// waiting coroutines +Waitlist waitlist; + // wait for event // see http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHICBGB.html @@ -32,7 +56,7 @@ void waitForEvent() { Handler nextHandler = waitForEvent; Handler addHandler(Handler handler) { Handler h = nextHandler; - Loop::nextHandler = handler; + loop::nextHandler = handler; return h; } @@ -55,13 +79,47 @@ void init() { // disabled interrupts trigger an event and wake up the processor from WFE SCB->SCR = SCB->SCR | SCB_SCR_SEVONPEND_Msk; + + // initialize RTC0 + loop::next.value = INTERVAL - 1; + NRF_RTC0->CC[0] = next.value << 4; + NRF_RTC0->EVTENSET = N(RTC_EVTENSET_OVRFLW, Set); + NRF_RTC0->INTENSET = N(RTC_INTENSET_COMPARE0, Set); + NRF_RTC0->PRESCALER = 1; // 16384Hz + NRF_RTC0->TASKS_START = TRIGGER; } void run() { while (true) { + // check if a sleep time has elapsed + if (NRF_RTC0->EVENTS_COMPARE[0]) { + do { + // clear pending interrupt flags at peripheral and NVIC + NRF_RTC0->EVENTS_COMPARE[0] = 0; + clearInterrupt(RTC0_IRQn); + + auto time = loop::next; + loop::next.value += INTERVAL - 1; + + // resume all coroutines that where timeout occurred + loop::waitlist.resumeAll([time](SystemTime timeout) { + if (timeout == time) + return true; + + // check if this time is the next to elapse + if (timeout < loop::next) + loop::next = timeout; + return false; + }); + NRF_RTC0->CC[0] = ((loop::next.value - loop::baseTime) << (7 + 4)) / 125;//Timer::next.value << 4; + + // repeat until next timeout is in the future + } while (now() >= loop::next); + } + // call all handlers - auto it = Loop::handlers.begin(); - while (it != Loop::handlers.end()) { + auto it = loop::handlers.begin(); + while (it != loop::handlers.end()) { // increment iterator beforehand because a handler can remove() itself auto current = it; ++it; @@ -72,10 +130,39 @@ void run() { // waitForEvent(); // call handler chain of drivers - Loop::nextHandler(); + loop::nextHandler(); } } +SystemTime now() { + // time resolution 1/1000 s + uint32_t counter = NRF_RTC0->COUNTER; + if (NRF_RTC0->EVENTS_OVRFLW) { + NRF_RTC0->EVENTS_OVRFLW = 0; + + // reload counter in case overflow happened after reading the counter + counter = NRF_RTC0->COUNTER; + + // advance base time by one interval (1024 seconds) + loop::baseTime += INTERVAL; + } + return {loop::baseTime + ((counter * 125 + 1024) >> (7 + 4))}; +} + +Awaitable sleep(SystemTime time) { + // check if this time is the next to elapse + if (time < loop::next) { + loop::next = time; + NRF_RTC0->CC[0] = ((time.value - loop::baseTime) << (7 + 4)) / 125; + } + + // check if timeout already elapsed + if (now() >= time) + NRF_RTC0->EVENTS_COMPARE[0] = GENERATED; + + return {loop::waitlist, time}; +} + void sleepBlocking(int us) { auto cycles = us * 8; for (int i = 0; i < cycles; ++i) { @@ -83,4 +170,4 @@ void sleepBlocking(int us) { } } -} // namespace Loop +} // namespace loop diff --git a/software/system/src/nrf52/Loop.hpp b/software/system/src/nrf52/Loop.hpp index 81cd46f..ec4230f 100644 --- a/software/system/src/nrf52/Loop.hpp +++ b/software/system/src/nrf52/Loop.hpp @@ -4,7 +4,7 @@ #include -namespace Loop { +namespace loop { using Handler = void (*)(); @@ -25,4 +25,4 @@ class Handler2 : public LinkedListNode { using HandlerList = LinkedList; extern HandlerList handlers; -} // namespace Loop +} // namespace loop diff --git a/software/system/src/nrf52/QuadratureDecoderImpl.cpp b/software/system/src/nrf52/QuadratureDecoderImpl.cpp index 45c2dc7..d3cc63e 100644 --- a/software/system/src/nrf52/QuadratureDecoderImpl.cpp +++ b/software/system/src/nrf52/QuadratureDecoderImpl.cpp @@ -26,7 +26,7 @@ QuadratureDecoderImpl::QuadratureDecoderImpl(int aPin, int bPin) { NRF_QDEC->TASKS_START = TRIGGER; // add to list of handlers - Loop::handlers.add(*this); + loop::handlers.add(*this); } Awaitable QuadratureDecoderImpl::change(int8_t& delta) { diff --git a/software/system/src/nrf52/QuadratureDecoderImpl.hpp b/software/system/src/nrf52/QuadratureDecoderImpl.hpp index e2a5634..6113b64 100644 --- a/software/system/src/nrf52/QuadratureDecoderImpl.hpp +++ b/software/system/src/nrf52/QuadratureDecoderImpl.hpp @@ -4,7 +4,7 @@ #include "Loop.hpp" -class QuadratureDecoderImpl : public QuadratureDecoder, public Loop::Handler2 { +class QuadratureDecoderImpl : public QuadratureDecoder, public loop::Handler2 { public: /** * Constructor diff --git a/software/system/src/nrf52/Radio.cpp b/software/system/src/nrf52/Radio.cpp index 2404097..cb7fadd 100644 --- a/software/system/src/nrf52/Radio.cpp +++ b/software/system/src/nrf52/Radio.cpp @@ -543,7 +543,7 @@ void SendParameters::cancel() noexcept { // event loop handler chain -Loop::Handler nextHandler = nullptr; +loop::Handler nextHandler = nullptr; void handle() { if (isInterruptPending(SWI0_EGU0_IRQn)) { // check energy detection @@ -617,7 +617,7 @@ void init() { return; // add to event loop handler chain - Radio::nextHandler = Loop::addHandler(handle); + Radio::nextHandler = loop::addHandler(handle); // init random number generator Random::init(); diff --git a/software/system/src/nrf52/SpiMasterImpl.cpp b/software/system/src/nrf52/SpiMasterImpl.cpp index adeef90..436cd91 100644 --- a/software/system/src/nrf52/SpiMasterImpl.cpp +++ b/software/system/src/nrf52/SpiMasterImpl.cpp @@ -51,7 +51,7 @@ SpiMasterImpl::SpiMasterImpl(int sckPin, int mosiPin, int misoPin, int dcPin) | N(SPIM_CONFIG_ORDER, MsbFirst); // add to list of handlers - Loop::handlers.add(*this); + loop::handlers.add(*this); } void SpiMasterImpl::handle() { diff --git a/software/system/src/nrf52/SpiMasterImpl.hpp b/software/system/src/nrf52/SpiMasterImpl.hpp index 697ad83..f30ad0c 100644 --- a/software/system/src/nrf52/SpiMasterImpl.hpp +++ b/software/system/src/nrf52/SpiMasterImpl.hpp @@ -7,7 +7,7 @@ /** * Implementation of SPI hardware interface for nrf52 with multiple virtual channels */ -class SpiMasterImpl : public Loop::Handler2 { +class SpiMasterImpl : public loop::Handler2 { public: /** * Constructor diff --git a/software/system/src/nrf52/Timer.cpp b/software/system/src/nrf52/Timer.cpp deleted file mode 100644 index ff921a0..0000000 --- a/software/system/src/nrf52/Timer.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "../Timer.hpp" -#include "Loop.hpp" -#include "nrf52.hpp" -#include - - -/* - https://infocenter.nordicsemi.com/topic/struct_nrf52/struct/nrf52840.html - - Dependencies: - - Config: - - Resources: - NRF_RTC0 - CC[0] -*/ -namespace Timer { - -// timer interval is 1024 seconds (2^24 / 16384Hz), given in milliseconds -constexpr int INTERVAL = 1024000; - -uint32_t baseTime = 0; - -// next timeout of a timer in the list -SystemTime next; - -// waiting coroutines -Waitlist waitlist; - - -// event loop handler chain -Loop::Handler nextHandler = nullptr; -void handle() { - if (NRF_RTC0->EVENTS_COMPARE[0]) { - do { - // clear pending interrupt flags at peripheral and NVIC - NRF_RTC0->EVENTS_COMPARE[0] = 0; - clearInterrupt(RTC0_IRQn); - - auto time = Timer::next; - Timer::next.value += INTERVAL - 1; - - // resume all coroutines that where timeout occurred - Timer::waitlist.resumeAll([time](SystemTime timeout) { - if (timeout == time) - return true; - - // check if this time is the next to elapse - if (timeout < Timer::next) - Timer::next = timeout; - return false; - }); - NRF_RTC0->CC[0] = ((Timer::next.value - Timer::baseTime) << (7 + 4)) / 125;//Timer::next.value << 4; - - // repeat until next timeout is in the future - } while (now() >= Timer::next); - } - - // call next handler in chain - Timer::nextHandler(); -} - -void init() { - // check if already initialized - if (Timer::nextHandler != nullptr) - return; - - // add to event loop handler chain - Timer::nextHandler = Loop::addHandler(handle); - - // initialize RTC0 - Timer::next.value = INTERVAL - 1; - NRF_RTC0->CC[0] = next.value << 4; - NRF_RTC0->EVTENSET = N(RTC_EVTENSET_OVRFLW, Set); - NRF_RTC0->INTENSET = N(RTC_INTENSET_COMPARE0, Set); - NRF_RTC0->PRESCALER = 1; // 16384Hz - NRF_RTC0->TASKS_START = TRIGGER; -} - -SystemTime now() { - // time resolution 1/1000 s - uint32_t counter = NRF_RTC0->COUNTER; - if (NRF_RTC0->EVENTS_OVRFLW) { - NRF_RTC0->EVENTS_OVRFLW = 0; - - // reload counter in case overflow happened after reading the counter - counter = NRF_RTC0->COUNTER; - - // advance base time by one interval (1024 seconds) - Timer::baseTime += INTERVAL; - } - return {Timer::baseTime + ((counter * 125 + 1024) >> (7 + 4))}; -} - -Awaitable sleep(SystemTime time) { - // check if this time is the next to elapse - if (time < Timer::next) { - Timer::next = time; - NRF_RTC0->CC[0] = ((time.value - Timer::baseTime) << (7 + 4)) / 125; - } - - // check if timeout already elapsed - if (now() >= time) - NRF_RTC0->EVENTS_COMPARE[0] = GENERATED; - - return {Timer::waitlist, time}; -} - -} // namespace Timer diff --git a/software/system/src/nrf52/UsbDeviceImpl.cpp b/software/system/src/nrf52/UsbDeviceImpl.cpp index 69e39f9..7ebd661 100644 --- a/software/system/src/nrf52/UsbDeviceImpl.cpp +++ b/software/system/src/nrf52/UsbDeviceImpl.cpp @@ -33,7 +33,7 @@ UsbDeviceImpl::UsbDeviceImpl( NRF_USBD->ENABLE = N(USBD_ENABLE_ENABLE, Enabled); // add to list of handlers - Loop::handlers.add(*this); + loop::handlers.add(*this); } void UsbDeviceImpl::enableEndpoints(uint8_t inFlags, uint8_t outFlags) { diff --git a/software/system/src/nrf52/UsbDeviceImpl.hpp b/software/system/src/nrf52/UsbDeviceImpl.hpp index 0de659a..c49a78f 100644 --- a/software/system/src/nrf52/UsbDeviceImpl.hpp +++ b/software/system/src/nrf52/UsbDeviceImpl.hpp @@ -6,7 +6,7 @@ /** * Implementation of an SPI master that simply writes info about the transfer operations to Terminal::out */ -class UsbDeviceImpl : public UsbDevice, public Loop::Handler2 { +class UsbDeviceImpl : public UsbDevice, public loop::Handler2 { public: // number of endpoints without endpoint 0 static constexpr int ENDPOINT_COUNT = 7; diff --git a/software/system/src/posix/Calendar.cpp b/software/system/src/posix/Calendar.cpp index 01f82b2..f3fcbf9 100644 --- a/software/system/src/posix/Calendar.cpp +++ b/software/system/src/posix/Calendar.cpp @@ -1,12 +1,11 @@ #include "../Calendar.hpp" -#include "../Timer.hpp" #include "Loop.hpp" #include namespace Calendar { -class Context : public Loop::TimeHandler { +class Context : public loop::TimeHandler { public: void activate() override { // next activation in 1s @@ -30,8 +29,8 @@ void init() { return; Calendar::inited = true; - Calendar::context.time = Timer::now() + 1s; - Loop::timeHandlers.add(Calendar::context); + Calendar::context.time = loop::now() + 1s; + loop::timeHandlers.add(Calendar::context); } ClockTime now() { diff --git a/software/system/src/posix/Loop.cpp b/software/system/src/posix/Loop.cpp index c2f0ba8..a32f9fa 100644 --- a/software/system/src/posix/Loop.cpp +++ b/software/system/src/posix/Loop.cpp @@ -1,21 +1,17 @@ #include "Loop.inc.hpp" -#include #include -namespace Loop { - -bool inited = false; +namespace loop { void init() { - Loop::inited = true; + initTimer(); } void run() { - assert(Loop::inited); while (true) { handleEvents(); } } -} // namespace Loop +} // namespace loop diff --git a/software/system/src/posix/Loop.hpp b/software/system/src/posix/Loop.hpp index 396fc49..13e70b2 100644 --- a/software/system/src/posix/Loop.hpp +++ b/software/system/src/posix/Loop.hpp @@ -10,8 +10,7 @@ using Socket = int; #endif -namespace Loop { - +namespace loop { // list of file descriptors to observe readable/writable events (used in Network.cpp) class SocketHandler : public LinkedListNode { @@ -25,7 +24,6 @@ class SocketHandler : public LinkedListNode { using SocketHandlerList = LinkedList; extern SocketHandlerList socketHandlers; - // timeouts for Timer and Calendar class TimeHandler : public LinkedListNode { public: @@ -37,5 +35,4 @@ class TimeHandler : public LinkedListNode { using TimeHandlerList = LinkedList; extern TimeHandlerList timeHandlers; - -} // namespace Loop +} // namespace loop diff --git a/software/system/src/posix/Loop.inc.hpp b/software/system/src/posix/Loop.inc.hpp index 9fed8f7..828b188 100644 --- a/software/system/src/posix/Loop.inc.hpp +++ b/software/system/src/posix/Loop.inc.hpp @@ -1,5 +1,4 @@ #include "Loop.hpp" -#include "../Timer.hpp" #ifdef _WIN32 #define NOMINMAX #include @@ -14,9 +13,59 @@ #endif -namespace Timer { +namespace loop { + +// SocketHandler + +SocketHandler::~SocketHandler() { +} +SocketHandlerList socketHandlers; + + +// TimeHandler + +TimeHandler::~TimeHandler() { +} +TimeHandlerList timeHandlers; + + + +class Timer : public TimeHandler { +public: + void activate() override { + auto time = this->time; + this->time += SystemDuration::max(); + + // resume all coroutines that where timeout occurred + this->waitlist.resumeAll([this, time](SystemTime timeout) { + if (timeout == time) + return true; + + // check if this time is the next to elapse + if (timeout < this->time) + this->time = timeout; + return false; + }); + } + + // waiting coroutines + Waitlist waitlist; +}; +Timer timer; + + +/** + * Platform dependent function: Initialize timer + * @param wait wait for an event or timeout. Set to false when using a rendering loop, e.g. when using GLFW + */ +static void initTimer() { + // check if not yet initialized + assert(!loop::timer.isInList()); + + loop::timer.time = loop::now() + SystemDuration::max(); + loop::timeHandlers.add(loop::timer); +} -// current time SystemTime now() { #ifdef _WIN32 return {timeGetTime()}; @@ -27,22 +76,16 @@ SystemTime now() { #endif } -} +Awaitable sleep(SystemTime time) { + // check if initTimer() was called + assert(loop::timer.isInList()); -namespace Loop { - -// SocketHandler + // check if this time is the next to elapse + if (time < loop::timer.time) + loop::timer.time = time; -SocketHandler::~SocketHandler() { + return {loop::timer.waitlist, time}; } -SocketHandlerList socketHandlers; - - -// TimeHandler - -TimeHandler::~TimeHandler() { -} -TimeHandlerList timeHandlers; /** @@ -54,10 +97,10 @@ static void handleEvents(bool wait = true) { SystemTime time; bool activated; do { - time = Timer::now(); + time = loop::now(); activated = false; - auto it = Loop::timeHandlers.begin(); - while (it != Loop::timeHandlers.end()) { + auto it = loop::timeHandlers.begin(); + while (it != loop::timeHandlers.end()) { // increment iterator beforehand because a timer can remove() itself auto current = it; ++it; @@ -72,7 +115,7 @@ static void handleEvents(bool wait = true) { // get next timeout auto next = time + SystemDuration::max(); - for (auto &handler : Loop::timeHandlers) { + for (auto &handler : loop::timeHandlers) { if (handler.time < next) next = handler.time; } @@ -80,7 +123,7 @@ static void handleEvents(bool wait = true) { // fill poll infos struct pollfd infos[16]; int count = 0; - for (auto &handler : Loop::socketHandlers) { + for (auto &handler : loop::socketHandlers) { infos[count++] = {handler.socket, handler.events, 0}; } assert(count <= array::count(infos)); @@ -93,8 +136,8 @@ static void handleEvents(bool wait = true) { // activate file descriptors if (r > 0) { int i = 0; - auto it = Loop::socketHandlers.begin(); - while (it != Loop::socketHandlers.end()) { + auto it = loop::socketHandlers.begin(); + while (it != loop::socketHandlers.end()) { // increment iterator beforehand because a socket handler can remove() itself auto current = it; ++it; @@ -113,4 +156,4 @@ static void handleEvents(bool wait = true) { } } -} // namespace Loop +} // namespace loop diff --git a/software/system/src/posix/Network.cpp b/software/system/src/posix/Network.cpp index 1f9da41..6774c57 100644 --- a/software/system/src/posix/Network.cpp +++ b/software/system/src/posix/Network.cpp @@ -38,7 +38,7 @@ Address Address::fromString(String s) { } -class Context : public Loop::SocketHandler { +class Context : public loop::SocketHandler { public: void activate(uint16_t events) override { if (events & POLLIN) { @@ -175,7 +175,7 @@ Awaitable receive(int index, Endpoint& source, int &length, v // add to event loop if necessary if (!context.isInList()) - Loop::socketHandlers.add(context); + loop::socketHandlers.add(context); // add to wait list return {context.receiveWaitlist, &source, &length, data}; @@ -190,7 +190,7 @@ Awaitable send(int index, Endpoint const &destination, int lengt // add to event loop if necessary if (!context.isInList()) - Loop::socketHandlers.add(context); + loop::socketHandlers.add(context); // add to wait list return {context.sendWaitlist, &destination, length, data}; diff --git a/software/system/src/posix/Sound.cpp b/software/system/src/posix/Sound.cpp index b73f6ed..fe8c9da 100644 --- a/software/system/src/posix/Sound.cpp +++ b/software/system/src/posix/Sound.cpp @@ -1,5 +1,4 @@ #include "../Sound.hpp" -#include "../Timer.hpp" #include "Loop.hpp" #include "assert.hpp" #include "util.hpp" @@ -62,7 +61,7 @@ std::vector types; // timeout to check if audio devices need to be stopped -class Timeout : public Loop::TimeHandler { +class Timeout : public loop::TimeHandler { public: void activate() override { // next activation in 1s @@ -210,8 +209,8 @@ void init() { Sound::inited = 2; - Sound::timeout.time = Timer::now() + 1s; - Loop::timeHandlers.add(Sound::timeout); + Sound::timeout.time = loop::now() + 1s; + loop::timeHandlers.add(Sound::timeout); } Array getTypes() { diff --git a/software/system/src/posix/SpiMasterImpl.cpp b/software/system/src/posix/SpiMasterImpl.cpp index d23b6f6..9b9d26f 100644 --- a/software/system/src/posix/SpiMasterImpl.cpp +++ b/software/system/src/posix/SpiMasterImpl.cpp @@ -1,5 +1,4 @@ #include "SpiMasterImpl.hpp" -#include "../Timer.hpp" #include "../Terminal.hpp" #include @@ -7,8 +6,8 @@ Awaitable SpiMasterImpl::transfer(int writeCount, void const *writeData, int readCount, void *readData) { if (!isInList()) { - this->time = Timer::now() + 100ms; // emulate 100ms transfer time - Loop::timeHandlers.add(*this); + this->time = loop::now() + 100ms; // emulate 100ms transfer time + loop::timeHandlers.add(*this); } return {this->waitlist, nullptr, writeCount, writeData, readCount, readData}; } diff --git a/software/system/src/posix/SpiMasterImpl.hpp b/software/system/src/posix/SpiMasterImpl.hpp index d8f4870..d6e232a 100644 --- a/software/system/src/posix/SpiMasterImpl.hpp +++ b/software/system/src/posix/SpiMasterImpl.hpp @@ -6,7 +6,7 @@ /** * Implementation of an SPI master that simply writes info about the transfer operations to Terminal::out */ -class SpiMasterImpl : public SpiMaster, public Loop::TimeHandler { +class SpiMasterImpl : public SpiMaster, public loop::TimeHandler { public: /** * Constructor diff --git a/software/system/src/posix/Timer.cpp b/software/system/src/posix/Timer.cpp deleted file mode 100644 index e323818..0000000 --- a/software/system/src/posix/Timer.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "../Timer.hpp" -#include "Loop.hpp" - - -namespace Timer { - -class Context : public Loop::TimeHandler { -public: - void activate() override { - auto time = this->time; - this->time += SystemDuration::max(); - - // resume all coroutines that where timeout occurred - this->waitlist.resumeAll([this, time](SystemTime timeout) { - if (timeout == time) - return true; - - // check if this time is the next to elapse - if (timeout < this->time) - this->time = timeout; - return false; - }); - } - - // waiting coroutines - Waitlist waitlist; -}; - -bool inited = false; -Context context; - -void init() { - // check if already initialized - if (Timer::inited) - return; - Timer::inited = true; - - Timer::context.time = now() + SystemDuration::max(); - Loop::timeHandlers.add(Timer::context); -} - -Awaitable sleep(SystemTime time) { - // check if Timer::init() was called - assert(Timer::inited); - - // check if this time is the next to elapse - if (time < Timer::context.time) - Timer::context.time = time; - - return {Timer::context.waitlist, time}; -} - -} // namespace Timer diff --git a/software/system/src/posix/UsbDeviceImpl.cpp b/software/system/src/posix/UsbDeviceImpl.cpp index fcffc4e..ca603db 100644 --- a/software/system/src/posix/UsbDeviceImpl.cpp +++ b/software/system/src/posix/UsbDeviceImpl.cpp @@ -1,5 +1,4 @@ #include "UsbDeviceImpl.hpp" -#include "../Timer.hpp" #include "../Terminal.hpp" #include @@ -18,8 +17,8 @@ UsbDeviceImpl::UsbDeviceImpl( //Loop::context.post([onSetConfiguration]() {onSetConfiguration(1);}); // call onSetConfiguration from event loop - this->time = Timer::now(); - Loop::timeHandlers.add(*this); + this->time = loop::now(); + loop::timeHandlers.add(*this); } void UsbDeviceImpl::enableEndpoints(uint8_t inFlags, uint8_t outFlags) { @@ -40,8 +39,8 @@ Awaitable UsbDeviceImpl::receive(int index, int &l assert(index == 1); auto &endpoint = this->endpoints[index - 1]; if (!isInList()) { - this->time = Timer::now() + 10ms; // emulate 10ms transfer time - Loop::timeHandlers.add(*this); + this->time = loop::now() + 10ms; // emulate 10ms transfer time + loop::timeHandlers.add(*this); } return {endpoint.receiveWaitlist, length, data}; } @@ -50,8 +49,8 @@ Awaitable UsbDeviceImpl::send(int index, int length, assert(index == 1); auto &endpoint = this->endpoints[index - 1]; if (!isInList()) { - this->time = Timer::now() + 10ms; // emulate 10ms transfer time - Loop::timeHandlers.add(*this); + this->time = loop::now() + 10ms; // emulate 10ms transfer time + loop::timeHandlers.add(*this); } return {endpoint.sendWaitlist, length, data}; } diff --git a/software/system/src/posix/UsbDeviceImpl.hpp b/software/system/src/posix/UsbDeviceImpl.hpp index cfc411c..25d6153 100644 --- a/software/system/src/posix/UsbDeviceImpl.hpp +++ b/software/system/src/posix/UsbDeviceImpl.hpp @@ -5,7 +5,7 @@ /** * Implementation of an USB device that simply writes info about the transfer operations to Terminal::out */ -class UsbDeviceImpl : public UsbDevice, public Loop::TimeHandler { +class UsbDeviceImpl : public UsbDevice, public loop::TimeHandler { public: /** * Constructor diff --git a/software/system/src/stm32f0/BusNodeImpl.cpp b/software/system/src/stm32f0/BusNodeImpl.cpp index 6341aff..4e44acb 100644 --- a/software/system/src/stm32f0/BusNodeImpl.cpp +++ b/software/system/src/stm32f0/BusNodeImpl.cpp @@ -69,7 +69,7 @@ BusNodeImpl::BusNodeImpl(int rxPin, int txPin) : rxPin(rxPin) { enableInterrupt(TIM16_IRQn); // add to list of handlers - Loop::handlers.add(*this); + loop::handlers.add(*this); } Awaitable BusNodeImpl::receive(int &length, uint8_t *data) { diff --git a/software/system/src/stm32f0/BusNodeImpl.hpp b/software/system/src/stm32f0/BusNodeImpl.hpp index 4ab8bc8..acf87f6 100644 --- a/software/system/src/stm32f0/BusNodeImpl.hpp +++ b/software/system/src/stm32f0/BusNodeImpl.hpp @@ -9,7 +9,7 @@ void USART1_IRQHandler(); void TIM16_IRQHandler(); } -class BusNodeImpl : public BusNode, public Loop::Handler2 { +class BusNodeImpl : public BusNode, public loop::Handler2 { friend void USART1_IRQHandler(); friend void TIM16_IRQHandler(); public: diff --git a/software/system/src/stm32f0/Input.cpp b/software/system/src/stm32f0/Input.cpp index aef10d0..78a9e84 100644 --- a/software/system/src/stm32f0/Input.cpp +++ b/software/system/src/stm32f0/Input.cpp @@ -1,5 +1,4 @@ #include "../Input.hpp" -#include "../Timer.hpp" #include "Loop.hpp" #include "gpio.hpp" #include @@ -37,12 +36,12 @@ State states[TRIGGER_COUNT]; Waitlist waitlist; // event loop handler chain -Loop::Handler nextHandler = nullptr; +loop::Handler nextHandler = nullptr; void handle() { int PR = EXTI->PR; if ((PR & 0xffff) != 0) { // debounce timeout - auto timeout = Timer::now() + 50ms; + auto timeout = loop::now() + 50ms; for (int index = 0; index < TRIGGER_COUNT; ++index) { auto &input = INPUTS[index]; int pos = input.pin & 15; @@ -111,7 +110,7 @@ void handle() { TIM2->CCR2 = Input::next.value; // repeat until next timeout is in the future - } while (Timer::now() >= Input::next); + } while (loop::now() >= Input::next); } // call next handler in chain @@ -126,14 +125,14 @@ void init() { // configure triggers if (TRIGGER_COUNT > 0) { - Timer::init(); + loop::init(); // check if already initialized if (Input::nextHandler != nullptr) return; // add to event loop handler chain - Input::nextHandler = Loop::addHandler(handle); + Input::nextHandler = loop::addHandler(handle); for (int index = 0; index < TRIGGER_COUNT; ++index) { auto &input = INPUTS[index]; diff --git a/software/system/src/stm32f0/Loop.cpp b/software/system/src/stm32f0/Loop.cpp index 127b8df..3b47932 100644 --- a/software/system/src/stm32f0/Loop.cpp +++ b/software/system/src/stm32f0/Loop.cpp @@ -1,13 +1,34 @@ #include "Loop.hpp" #include "defs.hpp" +#include "../SystemTime.hpp" +#include +/* + refernece manual: https://www.st.com/resource/en/reference_manual/dm00031936-stm32f0x1stm32f0x2stm32f0x8-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + + Dependencies: + + Config: + + Resources: + TIM2 + CCR1 +*/ + // called from system/startup_stm32f042x6.s to setup clock and flash before static constructors void SystemInit(void) { // leave clock in default configuration (8MHz) } -namespace Loop { +namespace loop { + +// next timeout of a timer in the list +SystemTime next; + +// waiting coroutines +Waitlist waitlist; + // wait for event // see http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHICBGB.html @@ -24,7 +45,7 @@ void waitForEvent() { Handler nextHandler = waitForEvent; Handler addHandler(Handler handler) { Handler h = nextHandler; - Loop::nextHandler = handler; + loop::nextHandler = handler; return h; } @@ -34,13 +55,48 @@ void init() { // disabled interrupts trigger an event and wake up the processor from WFE // see chapter 5.3.3 in reference manual SCB->SCR = SCB->SCR | SCB_SCR_SEVONPEND_Msk; + + // initialize TIM2 + RCC->APB1ENR = RCC->APB1ENR | RCC_APB1ENR_TIM2EN; + loop::next.value = SystemDuration::max().value; + TIM2->CCR1 = loop::next.value; + TIM2->PSC = (CLOCK + 1000 / 2) / 1000 - 1; // prescaler for 1ms timer resolution + TIM2->EGR = TIM_EGR_UG; // update generation so that prescaler takes effect + TIM2->DIER = TIM_DIER_CC1IE; // interrupt enable for CC1 + TIM2->CR1 = TIM_CR1_CEN; // enable, count up } void run() { while (true) { + // check if a sleep time has elapsed + if (TIM2->SR & TIM_SR_CC1IF) { + do { + // clear pending interrupt flags at peripheral and NVIC + TIM2->SR = ~TIM_SR_CC1IF; + clearInterrupt(TIM2_IRQn); + + auto time = loop::next; + loop::next += SystemDuration::max(); + + // resume all coroutines that where timeout occurred + loop::waitlist.resumeAll([time](SystemTime timeout) { + if (timeout == time) + return true; + + // check if this time is the next to elapse + if (timeout < loop::next) + loop::next = timeout; + return false; + }); + TIM2->CCR1 = loop::next.value; + + // repeat until next timeout is in the future + } while (SystemTime(TIM2->CNT) >= loop::next); + } + // call all handlers - auto it = Loop::handlers.begin(); - while (it != Loop::handlers.end()) { + auto it = loop::handlers.begin(); + while (it != loop::handlers.end()) { // increment iterator beforehand because a handler can remove() itself auto current = it; ++it; @@ -51,8 +107,27 @@ void run() { // waitForEvent(); // call handler chain of drivers - Loop::nextHandler(); + loop::nextHandler(); } } -} // namespace Loop + +SystemTime now() { + return {TIM2->CNT}; +} + +Awaitable sleep(SystemTime time) { + // check if this time is the next to elapse + if (time < loop::next) { + loop::next = time; + TIM2->CCR1 = time.value; + } + + // check if timeout already elapsed + if (SystemTime(TIM2->CNT) >= time) + TIM2->EGR = TIM_EGR_CC1G; // trigger compare event + + return {loop::waitlist, time}; +} + +} // namespace loop diff --git a/software/system/src/stm32f0/Loop.hpp b/software/system/src/stm32f0/Loop.hpp index 9cf5f5a..d955d06 100644 --- a/software/system/src/stm32f0/Loop.hpp +++ b/software/system/src/stm32f0/Loop.hpp @@ -4,7 +4,7 @@ #include -namespace Loop { +namespace loop { using Handler = void (*)(); @@ -24,4 +24,4 @@ class Handler2 : public LinkedListNode { using HandlerList = LinkedList; extern HandlerList handlers; -} // namespace Loop +} // namespace loop diff --git a/software/system/src/stm32f0/SpiMasterImpl.cpp b/software/system/src/stm32f0/SpiMasterImpl.cpp index dd9d056..a97fa01 100644 --- a/software/system/src/stm32f0/SpiMasterImpl.cpp +++ b/software/system/src/stm32f0/SpiMasterImpl.cpp @@ -107,7 +107,7 @@ SpiMasterImpl::SpiMasterImpl(int index, int sckPin, int mosiPin, int misoPin) { RCC->AHBENR = RCC->AHBENR & ~RCC_AHBENR_DMAEN; // add to list of handlers - Loop::handlers.add(*this); + loop::handlers.add(*this); } void SpiMasterImpl::handle() { diff --git a/software/system/src/stm32f0/SpiMasterImpl.hpp b/software/system/src/stm32f0/SpiMasterImpl.hpp index 5c054ec..5321a24 100644 --- a/software/system/src/stm32f0/SpiMasterImpl.hpp +++ b/software/system/src/stm32f0/SpiMasterImpl.hpp @@ -7,7 +7,7 @@ /** * Implementation of SPI hardware interface for stm32f0 with multiple virtual channels */ -class SpiMasterImpl : public Loop::Handler2 { +class SpiMasterImpl : public loop::Handler2 { public: /** * Constructor diff --git a/software/system/src/stm32f0/Timer.cpp b/software/system/src/stm32f0/Timer.cpp deleted file mode 100644 index 75c6df1..0000000 --- a/software/system/src/stm32f0/Timer.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "../Timer.hpp" -#include "Loop.hpp" -#include -#include -#include - - -/* - refernece manual: https://www.st.com/resource/en/reference_manual/dm00031936-stm32f0x1stm32f0x2stm32f0x8-advanced-armbased-32bit-mcus-stmicroelectronics.pdf - - Dependencies: - - Config: - - Resources: - TIM2 - CCR1 -*/ -namespace Timer { - -// next timeout of a timer in the list -SystemTime next; - -// waiting coroutines -Waitlist waitlist; - - -// event loop handler chain -Loop::Handler nextHandler = nullptr; -void handle() { - if (TIM2->SR & TIM_SR_CC1IF) { - do { - // clear pending interrupt flags at peripheral and NVIC - TIM2->SR = ~TIM_SR_CC1IF; - clearInterrupt(TIM2_IRQn); - - auto time = Timer::next; - Timer::next += SystemDuration::max(); - - // resume all coroutines that where timeout occurred - Timer::waitlist.resumeAll([time](SystemTime timeout) { - if (timeout == time) - return true; - - // check if this time is the next to elapse - if (timeout < Timer::next) - Timer::next = timeout; - return false; - }); - TIM2->CCR1 = Timer::next.value; - - // repeat until next timeout is in the future - } while (SystemTime(TIM2->CNT) >= Timer::next); - } - - // call next handler in chain - Timer::nextHandler(); -} - -void init() { - // check if already initialized - if (Timer::nextHandler != nullptr) - return; - - // add to event loop handler chain - Timer::nextHandler = Loop::addHandler(handle); - - // initialize TIM2 - RCC->APB1ENR = RCC->APB1ENR | RCC_APB1ENR_TIM2EN; - Timer::next.value = SystemDuration::max().value; - TIM2->CCR1 = Timer::next.value; - TIM2->PSC = (CLOCK + 1000 / 2) / 1000 - 1;//(CLOCK + 1024 / 2) / 1024 - 1; // prescaler - TIM2->EGR = TIM_EGR_UG; // update generation so that prescaler takes effect - TIM2->DIER = TIM_DIER_CC1IE; // interrupt enable for CC1 - TIM2->CR1 = TIM_CR1_CEN; // enable, count up -} - -SystemTime now() { - return {TIM2->CNT}; -} - -Awaitable sleep(SystemTime time) { - // check if this time is the next to elapse - if (time < Timer::next) { - Timer::next = time; - TIM2->CCR1 = time.value; - } - - // check if timeout already elapsed - if (SystemTime(TIM2->CNT) >= time) - TIM2->EGR = TIM_EGR_CC1G; // trigger compare event - - return {Timer::waitlist, time}; -} - -} // namespace Timer diff --git a/software/system/test/BleTest.cpp b/software/system/test/BleTest.cpp index 5daa864..9c89a4c 100644 --- a/software/system/test/BleTest.cpp +++ b/software/system/test/BleTest.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -235,13 +234,12 @@ Coroutine scan() { } int main() { - Loop::init(); - Timer::init(); + loop::init(); Ble::init(); Terminal::init(); Output::init(); // for debug led's scan(); - Loop::run(); + loop::run(); } diff --git a/software/system/test/BusMasterTest.cpp b/software/system/test/BusMasterTest.cpp index 0f7af3a..877ba37 100644 --- a/software/system/test/BusMasterTest.cpp +++ b/software/system/test/BusMasterTest.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -16,19 +15,18 @@ Coroutine transferBus(BusMaster &busMaster) { //int receiveLength = array::count(receive); - co_await Timer::sleep(1s); + co_await loop::sleep(1s); //Debug::toggleBlueLed(); } } int main() { - Loop::init(); - Timer::init(); + loop::init(); Output::init(); // for debug led's DriversBusMasterTest drivers; transferBus(drivers.busMaster); - Loop::run(); + loop::run(); } diff --git a/software/system/test/BusNodeTest.cpp b/software/system/test/BusNodeTest.cpp index 46542af..a84b70b 100644 --- a/software/system/test/BusNodeTest.cpp +++ b/software/system/test/BusNodeTest.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -16,19 +15,18 @@ Coroutine transferBus(BusNode &busNode) { //int receiveLength = array::count(receive); - co_await Timer::sleep(1s); + co_await loop::sleep(1s); //Debug::toggleBlueLed(); } } int main() { - Loop::init(); - Timer::init(); + loop::init(); Output::init(); // for debug led's DriversBusNodeTest drivers; transferBus(drivers.busNode); - Loop::run(); + loop::run(); } diff --git a/software/system/test/CalendarTest.cpp b/software/system/test/CalendarTest.cpp index 6eb87af..c6582e5 100644 --- a/software/system/test/CalendarTest.cpp +++ b/software/system/test/CalendarTest.cpp @@ -15,11 +15,11 @@ Coroutine handleSecondTick() { } int main() { - Loop::init(); + loop::init(); Calendar::init(); Output::init(); // for debug led's handleSecondTick(); - Loop::run(); + loop::run(); } diff --git a/software/system/test/FlashTest.cpp b/software/system/test/FlashTest.cpp index 659ed65..87e687d 100644 --- a/software/system/test/FlashTest.cpp +++ b/software/system/test/FlashTest.cpp @@ -1,5 +1,4 @@ #include -#include #include #include @@ -47,11 +46,10 @@ void test() { } int main() { - Loop::init(); - Timer::init(); + loop::init(); Output::init(); // for debug led's test(); - Loop::run(); + loop::run(); } diff --git a/software/system/test/InputTest.cpp b/software/system/test/InputTest.cpp index ec2164a..d89aec2 100644 --- a/software/system/test/InputTest.cpp +++ b/software/system/test/InputTest.cpp @@ -22,12 +22,12 @@ Coroutine handleInput() { } int main() { - Loop::init(); + loop::init(); Output::init(); // for debug signals on pins Input::init(); //Drivers drivers; handleInput(); - Loop::run(); + loop::run(); } diff --git a/software/system/test/TimerTest.cpp b/software/system/test/LoopTest.cpp similarity index 61% rename from software/system/test/TimerTest.cpp rename to software/system/test/LoopTest.cpp index 4124f10..4ead622 100644 --- a/software/system/test/TimerTest.cpp +++ b/software/system/test/LoopTest.cpp @@ -1,4 +1,3 @@ -#include #include #include @@ -6,10 +5,10 @@ Coroutine timer1() { while (true) { debug::setRed(true); - co_await Timer::sleep(100ms); + co_await loop::sleep(100ms); debug::setRed(false); - co_await Timer::sleep(1900ms); + co_await loop::sleep(1900ms); } } @@ -17,11 +16,11 @@ Coroutine timer2() { while (true) { debug::toggleGreen(); - auto timeout = Timer::now() + 3s; - co_await Timer::sleep(timeout); + auto timeout = loop::now() + 3s; + co_await loop::sleep(timeout); // test if sleep with elapsed timeout works - co_await Timer::sleep(timeout); + co_await loop::sleep(timeout); } } @@ -30,21 +29,20 @@ Coroutine timer3() { debug::toggleBlue(); // test if time overflow works on nrf52 - auto time = Timer::now(); + auto time = loop::now(); int i = int(time.value >> 20) & 3; - co_await Timer::sleep(500ms + i * 1s); + co_await loop::sleep(500ms + i * 1s); } } int main() { - Loop::init(); + loop::init(); Output::init(); // for debug signals on pins - Timer::init(); timer1(); timer2(); timer3(); - Loop::run(); + loop::run(); } diff --git a/software/system/test/NetworkTest.cpp b/software/system/test/NetworkTest.cpp index 21155a0..22341a6 100644 --- a/software/system/test/NetworkTest.cpp +++ b/software/system/test/NetworkTest.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -21,7 +20,7 @@ Coroutine sender() { while (true) { co_await Network::send(0, destination, array::count(data), data); debug::toggleRed(); - co_await Timer::sleep(1s); + co_await loop::sleep(1s); } } @@ -48,8 +47,7 @@ int main(int argc, char const **argv) { #else int main() { #endif - Loop::init(); - Timer::init(); + loop::init(); Network::init(); Output::init(); // for debug signals on pins @@ -60,5 +58,5 @@ int main() { sender(); receiver(); - Loop::run(); + loop::run(); } diff --git a/software/system/test/QuadratureDecoderTest.cpp b/software/system/test/QuadratureDecoderTest.cpp index 241f0c1..caa5f29 100644 --- a/software/system/test/QuadratureDecoderTest.cpp +++ b/software/system/test/QuadratureDecoderTest.cpp @@ -46,12 +46,12 @@ Coroutine handleDecoder(QuadratureDecoder &decoder) { } int main() { - Loop::init(); + loop::init(); Output::init(); // for debug signals on pins Input::init(); Drivers drivers; handleDecoder(drivers.quadratureDecoder); - Loop::run(); + loop::run(); } diff --git a/software/system/test/RadioTest.cpp b/software/system/test/RadioTest.cpp index a828016..6ec5d17 100644 --- a/software/system/test/RadioTest.cpp +++ b/software/system/test/RadioTest.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -49,7 +48,7 @@ Coroutine send() { while (true) { uint8_t result; - co_await Timer::sleep(1s); + co_await loop::sleep(1s); // send over the air and increment mac counter co_await Radio::send(0, packet1, result); @@ -66,7 +65,7 @@ Coroutine send() { radio::enableReceiver(true);*/ - co_await Timer::sleep(1s); + co_await loop::sleep(1s); // send over the air and increment mac counter co_await Radio::send(0, packet2, result); @@ -95,8 +94,7 @@ Coroutine reply() { int main() { - Loop::init(); - Timer::init(); + loop::init(); Radio::init(); Output::init(); @@ -113,6 +111,6 @@ int main() { send(); //reply(); - - Loop::run(); + + loop::run(); } diff --git a/software/system/test/RandomTest.cpp b/software/system/test/RandomTest.cpp index 390d659..ef83eac 100644 --- a/software/system/test/RandomTest.cpp +++ b/software/system/test/RandomTest.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -79,13 +78,12 @@ Coroutine send(UsbDevice &usb) { co_await usb.send(1, array::count(sendData), sendData); debug::toggleBlue(); - co_await Timer::sleep(1s); + co_await loop::sleep(1s); } } int main() { - Loop::init(); - Timer::init(); + loop::init(); Random::init(); UsbDeviceImpl usb( [](usb::DescriptorType descriptorType) { @@ -109,6 +107,6 @@ int main() { return false; }); Output::init(); // for debug signals on pins - - Loop::run(); + + loop::run(); } diff --git a/software/system/test/SoundTest.cpp b/software/system/test/SoundTest.cpp index d2c1f9a..fa5629c 100644 --- a/software/system/test/SoundTest.cpp +++ b/software/system/test/SoundTest.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -12,7 +11,7 @@ Coroutine soundTest() { while (true) { Sound::play(index); do { - co_await Timer::sleep(1s); + co_await loop::sleep(1s); } while (Sound::isPlaying(index)); debug::toggleBlue(); @@ -21,8 +20,7 @@ Coroutine soundTest() { } int main() { - Loop::init(); - Timer::init(); + loop::init(); Sound::init(); Output::init(); // for debug led's @@ -37,5 +35,5 @@ int main() { soundTest(); - Loop::run(); + loop::run(); } diff --git a/software/system/test/SpiMasterTest.cpp b/software/system/test/SpiMasterTest.cpp index 6d9edd5..50418a2 100644 --- a/software/system/test/SpiMasterTest.cpp +++ b/software/system/test/SpiMasterTest.cpp @@ -1,5 +1,4 @@ #include -#include #include #include @@ -33,13 +32,12 @@ Coroutine writeCommandData(Spi spi) { int main() { - Loop::init(); + loop::init(); Output::init(); // for debug led's - Timer::init(); DriversSpiMasterTest drivers; transferSpi(drivers.transfer); writeCommandData({drivers.command, drivers.data}); - Loop::run(); + loop::run(); } diff --git a/software/system/test/StorageTest.cpp b/software/system/test/StorageTest.cpp index a2642e7..7d8c576 100644 --- a/software/system/test/StorageTest.cpp +++ b/software/system/test/StorageTest.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -52,7 +51,7 @@ void test() { Kiss32Random random; // measure time - auto start = Timer::now(); + auto start = loop::now(); // table of currently stored elements int sizes[64]; @@ -105,7 +104,7 @@ void test() { return fail(); } - auto end = Timer::now(); + auto end = loop::now(); Terminal::out << dec(int((end - start) / 1s)) << "s\n"; @@ -114,11 +113,10 @@ void test() { } int main() { - Loop::init(); - Timer::init(); + loop::init(); Output::init(); // for debug led's test(); - Loop::run(); + loop::run(); } diff --git a/software/system/test/UsbDeviceTest.cpp b/software/system/test/UsbDeviceTest.cpp index fd949da..3f7c19a 100644 --- a/software/system/test/UsbDeviceTest.cpp +++ b/software/system/test/UsbDeviceTest.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -151,8 +150,7 @@ Coroutine echo(UsbDevice &usb) { } int main() { - Loop::init(); - Timer::init(); + loop::init(); UsbDeviceImpl usb( [](usb::DescriptorType descriptorType) { @@ -198,5 +196,5 @@ int main() { // start to receive from usb host echo(usb); - Loop::run(); + loop::run(); } diff --git a/software/tools/src/mdnsSniffer.cpp b/software/tools/src/mdnsSniffer.cpp index f0589a5..46ff2b9 100644 --- a/software/tools/src/mdnsSniffer.cpp +++ b/software/tools/src/mdnsSniffer.cpp @@ -243,7 +243,7 @@ Coroutine sniffer(FILE *file) { * See https://wiki.wireshark.org/HowToDissectAnything to dissect DNS application layer in Wireshark */ int main(int argc, char const *argv[]) { - Loop::init(); + loop::init(); Network::init(); Terminal::init(); @@ -284,7 +284,7 @@ int main(int argc, char const *argv[]) { sniffer(file); Terminal::out << "waiting for mDNS packets on port 5353 ...\n"; - Loop::run(); + loop::run(); } } else { // read from file diff --git a/software/tools/src/radioDevice.cpp b/software/tools/src/radioDevice.cpp index 6c170c3..90447a4 100644 --- a/software/tools/src/radioDevice.cpp +++ b/software/tools/src/radioDevice.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -201,8 +200,7 @@ Coroutine send(UsbDevice &usb, int index) { int main(void) { - Loop::init(); - Timer::init(); + loop::init(); Radio::init(); UsbDeviceImpl usb( [](usb::DescriptorType descriptorType) { @@ -276,5 +274,5 @@ int main(void) { } } - Loop::run(); + loop::run(); }