diff --git a/src/shared/drivers/canbus/CanDriver/BusLoadEstimation.h b/src/shared/drivers/canbus/CanDriver/BusLoadEstimation.h index 66bf37394c23a1fc14617028d1b350e0c830a968..d635553acec07638bffa7aa20876123429fbe2de 100644 --- a/src/shared/drivers/canbus/CanDriver/BusLoadEstimation.h +++ b/src/shared/drivers/canbus/CanDriver/BusLoadEstimation.h @@ -27,7 +27,7 @@ #include <cstdint> -#include "CanData.h" +#include "CanDriverData.h" using miosix::FastMutex; using miosix::Lock; diff --git a/src/shared/drivers/canbus/CanDriver/CanDriver.h b/src/shared/drivers/canbus/CanDriver/CanDriver.h index 07006aa3752021ebad17d7fe3a25ff13d19562da..f9d9b493268bd321000865bcfa0e05692ccc51f4 100644 --- a/src/shared/drivers/canbus/CanDriver/CanDriver.h +++ b/src/shared/drivers/canbus/CanDriver/CanDriver.h @@ -26,7 +26,7 @@ #include <miosix.h> #include <utils/collections/IRQCircularBuffer.h> -#include "CanData.h" +#include "CanDriverData.h" #include "Filters.h" using miosix::Thread; diff --git a/src/shared/drivers/canbus/CanDriver/CanData.h b/src/shared/drivers/canbus/CanDriver/CanDriverData.h similarity index 100% rename from src/shared/drivers/canbus/CanDriver/CanData.h rename to src/shared/drivers/canbus/CanDriver/CanDriverData.h diff --git a/src/shared/drivers/canbus/CanProtocol/CanProtocol.cpp b/src/shared/drivers/canbus/CanProtocol/CanProtocol.cpp index 5f6189f22817e0f9811ffaa1b4650db14eed2c61..f8454775b2842f3feb099b0d088397d50832149d 100644 --- a/src/shared/drivers/canbus/CanProtocol/CanProtocol.cpp +++ b/src/shared/drivers/canbus/CanProtocol/CanProtocol.cpp @@ -94,6 +94,24 @@ bool CanProtocol::enqueueMsg(const CanMessage& msg) return true; } +bool CanProtocol::addFilter(uint8_t src, uint64_t dst) +{ + if (src > 0xF || dst > 0xF) + return false; + + // The filter mask will cover only the source and destination bits + uint32_t mask = static_cast<uint32_t>(CanProtocolIdMask::SOURCE) | + static_cast<uint32_t>(CanProtocolIdMask::DESTINATION); + + uint32_t id = + src << static_cast<uint8_t>(CanProtocolShiftInformation::SOURCE) | + dst << static_cast<uint8_t>(CanProtocolShiftInformation::DESTINATION); + + Mask32FilterBank filterBank(id, mask, 1, 1, 0, 0, 0); + + return can->addFilter(filterBank); +} + void CanProtocol::sendMessage(const CanMessage& msg) { CanPacket packet = {}; @@ -105,7 +123,7 @@ void CanProtocol::sendMessage(const CanMessage& msg) // The number of left to send packets packet.id = static_cast<uint32_t>(msg.id) | ((static_cast<uint32_t>(0x3F) - leftToSend) & - static_cast<uint32_t>(CanPacketIdMask::LEFT_TO_SEND)); + static_cast<uint32_t>(CanProtocolIdMask::LEFT_TO_SEND)); packet.length = byteForUint64(msg.payload[0]); // Splits payload[0] in the right number of uint8_t @@ -119,10 +137,11 @@ void CanProtocol::sendMessage(const CanMessage& msg) // Prepare the remaining packets for (int i = 1; i < msg.length; i++) { - packet.id = static_cast<uint32_t>(msg.id) | - static_cast<uint32_t>(CanPacketIdMask::FIRST_PACKET_FLAG) | - ((static_cast<uint32_t>(0x3F) - leftToSend) & - static_cast<uint32_t>(CanPacketIdMask::LEFT_TO_SEND)); + packet.id = + static_cast<uint32_t>(msg.id) | + static_cast<uint32_t>(CanProtocolIdMask::FIRST_PACKET_FLAG) | + ((static_cast<uint32_t>(0x3F) - leftToSend) & + static_cast<uint32_t>(CanProtocolIdMask::LEFT_TO_SEND)); packet.length = byteForUint64(msg.payload[i]); // Splits payload[i] in the right number of uint8_t @@ -151,17 +170,18 @@ void CanProtocol::runReceiver() uint8_t leftToReceive = static_cast<uint32_t>(0x3F) - - (pkt.id & static_cast<uint32_t>(CanPacketIdMask::LEFT_TO_SEND)); + (pkt.id & + static_cast<uint32_t>(CanProtocolIdMask::LEFT_TO_SEND)); // Check if the packet is the first in the sequence, if this is the // case then the previous message is overriden if ((pkt.id & static_cast<uint32_t>( - CanPacketIdMask::FIRST_PACKET_FLAG)) == 0) + CanProtocolIdMask::FIRST_PACKET_FLAG)) == 0) { // If it is we save the id (without the sequence number) and the // message length msg.id = pkt.id & static_cast<uint32_t>( - CanPacketIdMask::MESSAGE_INFORMATION); + CanProtocolIdMask::MESSAGE_INFORMATION); msg.length = leftToReceive + 1; // Reset the number of received packets @@ -171,8 +191,8 @@ void CanProtocol::runReceiver() // Accept the packet only if it has the expected id // clang-format off if (msg.id != -1 && - (pkt.id & static_cast<uint32_t>(CanPacketIdMask::MESSAGE_INFORMATION)) == - (msg.id & static_cast<uint32_t>(CanPacketIdMask::MESSAGE_INFORMATION))) + (pkt.id & static_cast<uint32_t>(CanProtocolIdMask::MESSAGE_INFORMATION)) == + (msg.id & static_cast<uint32_t>(CanProtocolIdMask::MESSAGE_INFORMATION))) // clang-format on { // Check if the packet is expected in the sequence. The received diff --git a/src/shared/drivers/canbus/CanProtocol/CanProtocol.h b/src/shared/drivers/canbus/CanProtocol/CanProtocol.h index 1526ca461cbaca68edc80532b500001ae828219f..a8792d7c08016fbbd3f9192d2bd3927bb1a4b962 100644 --- a/src/shared/drivers/canbus/CanProtocol/CanProtocol.h +++ b/src/shared/drivers/canbus/CanProtocol/CanProtocol.h @@ -28,6 +28,7 @@ #include <utils/collections/SyncCircularBuffer.h> #include "CanProtocolData.h" +#include "CanProtocolTypes.h" namespace Boardcore { @@ -35,66 +36,6 @@ namespace Boardcore namespace Canbus { -/** - * The CanProtocol allows to transmit arbitrarily sized messages over the CanBus - * overcoming the 8 byte limitation of each single packet. - * - * Our CanProtocol uses the extended can packet, the 29 bits id is divided such - * as: - * - Priority 4 bit - priority \ - * - Primary type 6 bit - primaryType | - * - Source 4 bit - source | 22 bits - Message informations - * - Destination 4 bit - destination | - * - Secondary type 4 bit - secondaryType / - * - First packet flag 1 bit - firstPacket \ 7 bits - Sequential informations - * - Remaining packets 6 bit - leftToSend / - * shiftNameOfField the number of shift needed to reach that field - * - * The id is split into 2 parts: - * - Message information: Common to every packet of a given message - * - Sequential information: Used to distinguish between packets - * - * The sender splits into multiple packets a message that is then recomposed on - * the receiver end. The message informations are encoded into the packets id, - * therefore they have an effect on packets priorities. - */ - -/** - * @brief Masks of the elements composing can packets ids. - */ -enum class CanPacketIdMask : uint32_t -{ - PRIORITY = 0x1E000000, - PRIMARY_TYPE = 0x01F80000, - SOURCE = 0x00078000, - DESTINATION = 0x00003800, - SECONDARY_TYPE = 0x00000780, - - MESSAGE_INFORMATION = 0x1FFFFF80, - - FIRST_PACKET_FLAG = 0x00000040, - LEFT_TO_SEND = 0x0000003F, - - SEQUENTIAL_INFORMATION = 0x0000007F -}; - -enum ShiftInformation : uint8_t -{ - // Shift values for message informations - PRIORITY = 25, - PRIMARY_TYPE = 19, - SOURCE = 15, - DESCRIPTION = 11, - SECONDARY_TYPE = 7, - - // Shift values for sequential informations - FIRST_PACKET_FLAG = 6, - LEFT_TO_SEND = 0, - - // Position of the message infos relative to the entire can packet id - SEQUENTIAL_INFORMATION = 7 -}; - /** * @brief Canbus protocol implementation. * @@ -133,6 +74,16 @@ public: */ void stop(); + /** + * @brief Adds a filter to the can peripheral to receive only messages from + * the given source and targeted to the given destination. + * + * @param src Message source. + * @param dst Message destination. + * @return True if the filter was added successfully. + */ + bool addFilter(uint8_t src, uint64_t dst); + /** * @brief Non-blocking send function, puts the messages in a queue. * Message is discarded if the queue is full. @@ -142,6 +93,18 @@ public: */ bool enqueueMsg(const CanMessage& msg); + /** + * @brief Non-blocking send function for a generic data type. + * + * @warning There must be a function called with this prototype: + * CanMessage toCanMessage(const T& t); + * + * @param t The class to be logged. + */ + template <typename T> + bool enqueueData(uint8_t priority, uint8_t primaryType, uint8_t source, + uint8_t destination, uint8_t secondaryType, const T& t); + private: /** * @brief Blocking send function, puts the CanMessage object on the bus. @@ -207,6 +170,28 @@ private: PrintLogger logger = Logging::getLogger("canprotocol"); }; +template <typename T> +bool CanProtocol::enqueueData(uint8_t priority, uint8_t primaryType, + uint8_t source, uint8_t destination, + uint8_t secondaryType, const T& t) +{ + if (priority > 0xF || primaryType > 0x3F || source > 0xF || + destination > 0xF || secondaryType > 0xF) + return false; + + CanMessage msg = toCanMessage(t); + + // clang-format off + msg.id = priority << static_cast<uint32_t>(CanProtocolShiftInformation::PRIORITY); + msg.id |= primaryType << static_cast<uint32_t>(CanProtocolShiftInformation::PRIMARY_TYPE); + msg.id |= source << static_cast<uint32_t>(CanProtocolShiftInformation::SOURCE); + msg.id |= destination << static_cast<uint32_t>(CanProtocolShiftInformation::DESTINATION); + msg.id |= secondaryType << static_cast<uint32_t>(CanProtocolShiftInformation::SECONDARY_TYPE); + // clang-format off + + return enqueueMsg(msg); +} + } // namespace Canbus } // namespace Boardcore diff --git a/src/shared/drivers/canbus/CanProtocol/CanProtocolData.h b/src/shared/drivers/canbus/CanProtocol/CanProtocolData.h index 7eb3c8808a43a60d70f52a1f778a1bb89e7212f1..1a2b3b62e9835dddd237d74915342fc7e618ca4e 100644 --- a/src/shared/drivers/canbus/CanProtocol/CanProtocolData.h +++ b/src/shared/drivers/canbus/CanProtocol/CanProtocolData.h @@ -30,6 +30,89 @@ namespace Boardcore namespace Canbus { +/** + * The CanProtocol allows to transmit arbitrarily sized messages over the CanBus + * overcoming the 8 byte limitation of each single packet. + * + * Our CanProtocol uses the extended can packet, the 29 bits id is divided such + * as: + * - Priority 4 bit \ + * - Primary type 6 bit | + * - Source 4 bit | 22 bits - Message informations + * - Destination 4 bit | + * - Secondary type 4 bit / + * - First packet flag 1 bit \ 7 bits - Sequential informations + * - Remaining packets 6 bit / + * shiftNameOfField the number of shift needed to reach that field + * + * The id is split into 2 parts: + * - Message information: Common to every packet of a given message + * - Sequential information: Used to distinguish between packets + * + * The sender splits into multiple packets a message that is then recomposed on + * the receiver end. The message informations are encoded into the packets id, + * therefore they have an effect on packets priorities. + */ +/** + * The CanProtocol allows to transmit arbitrarily sized messages over the CanBus + * overcoming the 8 byte limitation of each single packet. + * + * Our CanProtocol uses the extended can packet, the 29 bits id is divided such + * as: + * - Priority 4 bit \ + * - Primary type 6 bit | + * - Source 4 bit | 22 bits - Message informations + * - Destination 4 bit | + * - Secondary type 4 bit / + * - First packet flag 1 bit \ 7 bits - Sequential informations + * - Remaining packets 6 bit / + * shiftNameOfField the number of shift needed to reach that field + * + * The id is split into 2 parts: + * - Message information: Common to every packet of a given message + * - Sequential information: Used to distinguish between packets + * + * The sender splits into multiple packets a message that is then recomposed on + * the receiver end. The message informations are encoded into the packets id, + * therefore they have an effect on packets priorities. + */ + +/** + * @brief Masks of the elements composing can packets ids. + */ +enum class CanProtocolIdMask : uint32_t +{ + PRIORITY = 0x1E000000, + PRIMARY_TYPE = 0x01F80000, + SOURCE = 0x00078000, + DESTINATION = 0x00003800, + SECONDARY_TYPE = 0x00000780, + + MESSAGE_INFORMATION = 0x1FFFFF80, + + FIRST_PACKET_FLAG = 0x00000040, + LEFT_TO_SEND = 0x0000003F, + + SEQUENTIAL_INFORMATION = 0x0000007F +}; + +enum CanProtocolShiftInformation : uint8_t +{ + // Shift values for message informations + PRIORITY = 25, + PRIMARY_TYPE = 19, + SOURCE = 15, + DESTINATION = 11, + SECONDARY_TYPE = 7, + + // Shift values for sequential informations + FIRST_PACKET_FLAG = 6, + LEFT_TO_SEND = 0, + + // Position of the message infos relative to the entire can packet id + SEQUENTIAL_INFORMATION = 7 +}; + /** * @brief Generic struct that contains a can protocol message. * @@ -46,6 +129,37 @@ struct CanMessage int32_t id = -1; ///< Id of the message without sequential infos. uint8_t length = 0; ///< Length of the message content. uint64_t payload[65]; + + uint8_t getPriority() + { + return id >> + static_cast<uint8_t>(CanProtocolShiftInformation::PRIORITY); + } + + uint8_t getPrimaryType() + { + return (id | static_cast<uint32_t>(CanProtocolIdMask::PRIMARY_TYPE)) >> + static_cast<uint8_t>(CanProtocolShiftInformation::PRIMARY_TYPE); + } + + uint8_t getSource() + { + return (id | static_cast<uint32_t>(CanProtocolIdMask::SOURCE)) >> + static_cast<uint8_t>(CanProtocolShiftInformation::SOURCE); + } + + uint8_t getDestination() + { + return (id | static_cast<uint32_t>(CanProtocolIdMask::DESTINATION)) >> + static_cast<uint8_t>(CanProtocolShiftInformation::DESTINATION); + } + + uint8_t getSecondaryType() + { + return (id | + static_cast<uint32_t>(CanProtocolIdMask::SECONDARY_TYPE)) >> + static_cast<uint8_t>(CanProtocolShiftInformation::PRIMARY_TYPE); + } }; inline bool operator==(const CanMessage& lhs, const CanMessage& rhs) diff --git a/src/shared/drivers/canbus/CanProtocol/CanProtocolTypes.h b/src/shared/drivers/canbus/CanProtocol/CanProtocolTypes.h new file mode 100644 index 0000000000000000000000000000000000000000..b84db80a9c1e530dc9666af6c2e9951a7e3ed7f6 --- /dev/null +++ b/src/shared/drivers/canbus/CanProtocol/CanProtocolTypes.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2022 Skyward Experimental Rocketry + * Author: Alberto Nidasio + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include <sensors/analog/Pitot/PitotData.h> + +#include <cstring> + +#include "CanProtocolData.h" + +namespace Boardcore +{ + +inline Canbus::CanMessage toCanMessage(const PitotData& data) +{ + Canbus::CanMessage message; + + uint32_t tmp; + memcpy(&tmp, &(data.airspeed), sizeof(tmp)); + + message.id = -1; + message.length = 1; + message.payload[0] = (data.timestamp & ~0x3) << 30; + message.payload[0] |= tmp; + + return message; +} + +} // namespace Boardcore diff --git a/src/shared/logger/Logger.h b/src/shared/logger/Logger.h index 496b1cf311900f722a7070447cb9234f864791f4..7d404ae83eb064d15f9ef793e0f3cac9867eb11b 100644 --- a/src/shared/logger/Logger.h +++ b/src/shared/logger/Logger.h @@ -124,7 +124,7 @@ public: */ void logStats(); -public: +private: Logger(); static std::string getFileName(int logNumber); diff --git a/src/tests/drivers/canbus/CanProtocol/test-can-protocol.cpp b/src/tests/drivers/canbus/CanProtocol/test-can-protocol.cpp index de42a9c3d9b3cd911b44f0b628fd5eee14a66ef2..2fcc424502a10db5c3936d2924a264120219e2cd 100644 --- a/src/tests/drivers/canbus/CanProtocol/test-can-protocol.cpp +++ b/src/tests/drivers/canbus/CanProtocol/test-can-protocol.cpp @@ -20,21 +20,25 @@ * THE SOFTWARE. */ -#include <drivers/canbus/CanDriver/BusLoadEstimation.h> -#include <drivers/canbus/CanDriver/CanDriver.h> #include <drivers/canbus/CanProtocol/CanProtocol.h> +#include <drivers/timer/TimestampTimer.h> #include <scheduler/TaskScheduler.h> -#include <utils/collections/CircularBuffer.h> - -#include <functional> -#include <thread> using namespace std; using namespace miosix; using namespace Boardcore; using namespace Canbus; -void print(CanMessage data) { printf("Received packet %lu\n", data.id); } +void print(CanMessage data) +{ + printf("Received packet:\n"); + printf("\tpriority: %d\n", data.getPriority()); + printf("\tprimary type: %d\n", data.getPrimaryType()); + printf("\tsource: %d\n", data.getSource()); + printf("\tdestination: %d\n", data.getDestination()); + printf("\tsecondary type: %d\n", data.getSecondaryType()); + printf("\n"); +} int main() { @@ -57,25 +61,21 @@ int main() // Start the protocol protocol.start(); - CanMessage msg1, msg2; - + CanMessage msg1; msg1.id = 0x200; msg1.length = 2; msg1.payload[0] = 0xffffffffffffffff; msg1.payload[1] = 0x0123456789ABCDEF; - msg2.id = 0x100; - msg2.length = 1; - msg2.payload[0] = 0; - TaskScheduler scheduler; scheduler.addTask([&]() { protocol.enqueueMsg(msg1); }, 1000); scheduler.addTask( [&]() { - msg2.payload[0]++; - protocol.enqueueMsg(msg2); + PitotData data{TimestampTimer::getTimestamp(), 23}; + + protocol.enqueueData(0xF, 0xA, 0x1, 0x2, 0xB, data); }, 2000);