From 93c9a3aba7d48fd89516406590868d54bb2c94bc Mon Sep 17 00:00:00 2001
From: Alberto Nidasio <alberto.nidasio@skywarder.eu>
Date: Tue, 12 Jul 2022 12:08:13 +0000
Subject: [PATCH] [CanProtocol] Divided con into .cpp file

---
 cmake/boardcore.cmake                         |   1 +
 src/shared/drivers/canbus/CanProtocol.cpp     | 173 ++++++++++++
 src/shared/drivers/canbus/CanProtocol.h       | 252 +++++-------------
 .../drivers/canbus/test-can-protocol.cpp      |  19 +-
 4 files changed, 257 insertions(+), 188 deletions(-)
 create mode 100644 src/shared/drivers/canbus/CanProtocol.cpp

diff --git a/cmake/boardcore.cmake b/cmake/boardcore.cmake
index 49c7e5016..6521be856 100644
--- a/cmake/boardcore.cmake
+++ b/cmake/boardcore.cmake
@@ -46,6 +46,7 @@ foreach(OPT_BOARD ${BOARDS})
         ${SBS_BASE}/src/shared/drivers/adc/InternalADC.cpp
         ${SBS_BASE}/src/shared/drivers/canbus/Canbus.cpp
         ${SBS_BASE}/src/shared/drivers/canbus/CanInterrupt.cpp
+        ${SBS_BASE}/src/shared/drivers/canbus/CanProtocol.cpp
         ${SBS_BASE}/src/shared/drivers/i2c/stm32f2_f4_i2c.cpp
         ${SBS_BASE}/src/shared/drivers/interrupt/external_interrupts.cpp
         ${SBS_BASE}/src/shared/drivers/timer/PWM.cpp
diff --git a/src/shared/drivers/canbus/CanProtocol.cpp b/src/shared/drivers/canbus/CanProtocol.cpp
new file mode 100644
index 000000000..1f405fabd
--- /dev/null
+++ b/src/shared/drivers/canbus/CanProtocol.cpp
@@ -0,0 +1,173 @@
+/* Copyright (c) 2022 Skyward Experimental Rocketry
+ * Author: Federico Mandelli
+ *
+ * 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.
+ */
+
+#include "CanProtocol.h"
+
+namespace Boardcore
+{
+
+namespace Canbus
+{
+
+CanData data[N_PACKET];
+
+CanProtocol::CanProtocol(CanbusDriver* can) { this->can = can; }
+
+CanProtocol::~CanProtocol() { (*can).~CanbusDriver(); }
+
+CanData CanProtocol::getPacket()
+{
+    miosix::Lock<miosix::FastMutex> l(mutex);
+
+    if (!buffer.isEmpty())
+        return buffer.pop();
+    else
+        return {};
+}
+
+bool CanProtocol::isBufferEmpty()
+{
+    miosix::Lock<miosix::FastMutex> l(mutex);
+    return buffer.isEmpty();
+}
+
+void CanProtocol::waitBufferEmpty() { buffer.waitUntilNotEmpty(); }
+
+void CanProtocol::sendData(CanData dataToSend)
+{
+    CanPacket packet = {};
+    uint8_t tempLen  = dataToSend.length - 1;
+    uint32_t tempId  = dataToSend.canId;
+
+    // Send the first packet
+    packet.ext = true;
+    packet.id  = (tempId << shiftSequentialInfo) | firstPacket |
+                (63 - (tempLen & leftToSend));
+    packet.length = byteForInt(dataToSend.payload[0]);
+    for (int k = 0; k < packet.length; k++)
+        packet.data[k] = dataToSend.payload[0] >> (8 * k);
+    can->send(packet);
+    tempLen--;
+
+    for (int i = 1; i < dataToSend.length; i++)
+    {
+        tempId = dataToSend.canId;
+        packet.id =
+            (tempId << shiftSequentialInfo) | (63 - (tempLen & leftToSend));
+        packet.length = byteForInt(dataToSend.payload[i]);
+
+        for (int k = 0; k < packet.length; k++)
+            packet.data[k] = dataToSend.payload[i] >> (8 * k);
+
+        can->send(packet);
+        tempLen--;
+    }
+}
+
+uint8_t CanProtocol::byteForInt(uint64_t number)
+{
+    uint8_t i;
+
+    for (i = 1; i <= 8; i++)
+    {
+        number >>= 8;
+        if (number == 0)
+            return i;
+    }
+
+    return i;
+}
+
+void CanProtocol::run()
+{
+    while (!shouldStop())
+    {
+        // Wait for the next packet
+        can->getRXBuffer().waitUntilNotEmpty();
+
+        // If the buffer is not empty retrieve the packet
+        if (!can->getRXBuffer().isEmpty())
+        {
+            CanPacket packet = can->getRXBuffer().pop().packet;
+
+            // Discard the sequence number
+            uint32_t idNoSeq = packet.id >> shiftSequentialInfo;
+            uint8_t sourceId = (idNoSeq & source) >> shiftSource;
+
+            // Check for maximum size
+            if (sourceId < N_PACKET)
+            {
+                if (data[sourceId].canId == -1 ||
+                    ((data[sourceId].canId & source) >> shiftSource) ==
+                        sourceId)
+                {
+                    uint8_t left = 63 - (packet.id & leftToSend);
+
+                    // Check if it is the first packet in the sequence
+                    if ((packet.id & firstPacket) >> shiftFirstPacket)
+                    {
+                        data[sourceId].length = left + 1;
+                        data[sourceId].canId  = idNoSeq;
+                    }
+
+                    if ((data[sourceId].length - (data[sourceId].nRec + 1)) ==
+                        left)
+                    {
+                        uint64_t tempPayload = 0;
+
+                        for (int f = 0; f < packet.length; f++)
+                        {
+                            uint64_t tempData = packet.data[f];
+                            tempPayload = tempPayload | (tempData << (f * 8));
+                        }
+
+                        if (data[sourceId].length - left - 1 >= 0 &&
+                            data[sourceId].length - left - 1 <
+                                32)  // check for index
+                        {
+                            data[sourceId]
+                                .payload[data[sourceId].length - left - 1] =
+                                tempPayload;
+                            data[sourceId].nRec++;
+                        }
+                    }
+
+                    if (data[sourceId].nRec == data[sourceId].length &&
+                        data[sourceId].nRec != 0)
+                    {
+                        miosix::Lock<miosix::FastMutex> l(mutex);
+                        buffer.put(data[sourceId]);
+
+                        // Empties the struct
+                        data[sourceId].canId  = -1;
+                        data[sourceId].nRec   = 0;
+                        data[sourceId].length = 0;
+                    }
+                }
+            }
+        }
+    }
+}
+
+}  // namespace Canbus
+
+}  // namespace Boardcore
diff --git a/src/shared/drivers/canbus/CanProtocol.h b/src/shared/drivers/canbus/CanProtocol.h
index a496f5799..7e9efa91f 100644
--- a/src/shared/drivers/canbus/CanProtocol.h
+++ b/src/shared/drivers/canbus/CanProtocol.h
@@ -28,50 +28,53 @@
 
 #include "Canbus.h"
 
-#define NPACKET 3  // equals the number of boards in the can system
+#define N_PACKET 3  ///< Number of boards on the bus.
 
 namespace Boardcore
 {
+
 namespace Canbus
 {
 
 /**
- * The id of a can packet is composed of 29 bits
- * priority     4 bit
- * type         6 bit
- * source       4 bit
- * destination  4 bit
- * idType       4 bit
- * firstPacket  1 bit
- * leftToSend   6 bit
+ * The id of a can packet is composed of 29 bits and will be divided such as:
+ * - Priority           4 bit - priority    \
+ * - Type               6 bit - type        |
+ * - Source             4 bit - source      | 22 bits
+ * - Destination        4 bit - destination |
+ * - Type id            4 bit - idType      /
+ * - First packet flag  1 bit - firstPacket \ 7 bits
+ * - Remaining packets  6 bit - leftToSend  /
  * shiftNameOfField the number of shift needed to reach that field
  */
 
 /**
- * @brief The mask of the ID without the sequential information (firstPacket and
- * leftToSend) CompleteID = (IDMask << shiftSequentialInfo)||
- * SequentialInformation
+ * @brief The mask of the ID without the sequential information.
+ *
+ * CompleteID = (IDMask << shiftSequentialInfo) || SequentialInformation
  */
 
 /**
- * @brief enum that contains how the canId without sequential is composed
+ * @brief Enumeration that contains masks of the elements composing the can
+ * packet id without sequential information.
  */
 enum IDMask
 {
     priority         = 0x3C0000,
-    shiftPriority    = 18,  // number of bit before priority
-    type             = 0x3F000,
+    shiftPriority    = 18,
+    type             = 0x03F000,
     shiftType        = 12,
-    source           = 0xF00,
+    source           = 0x000F00,
     shiftSource      = 8,
-    destination      = 0xF0,
+    destination      = 0x0000F0,
     shiftDestination = 4,
-    idType           = 0xF,
+    idType           = 0x00000F,
     shiftIdType      = 0
 };
 
 /**
- * @brief enum that contains how the Sequential information are composed
+ * @brief @brief Enumeration that contains masks of the elements composing the
+ * sequential information.
  */
 enum SequentialInformation
 {
@@ -81,199 +84,90 @@ enum SequentialInformation
     shiftLeftToSend     = 0,
     shiftSequentialInfo = 7
 };
+
 /**
- * @brief Generic struct that contains a logical can packet
- * i.e. 1 accelerometer packet 3*4byte (acc: x,y,z)+timestamp, will be 4
+ * @brief Generic struct that contains a logical can packet.
+ *
+ * i.e. 1 accelerometer packet 3 * 4byte (acc: x,y,z)  +timestamp, will be 4
  * canPacket but a single canData.
  */
 struct CanData
 {
-    int32_t canId =
-        -1;  // the id of the can packet without the last 7 bits (sequence bit)
-    uint8_t len;
+    int32_t canId = -1;  ///< Id of the packet without the sequential info.
+    uint8_t length;
     uint8_t nRec = 0;
     uint64_t payload[32];
-} data[NPACKET];
+};
 
 /**
- * @brief Canbus protocol, given an initialized can this class takes care of
- * sending the multiple packet of CanData with the corresponding id and
- * receiving single CanPacket that are then reframed as one Candata.
+ * @brief Canbus protocol implementation.
+ *
+ * Given a can interface this class takes care of sending CanData packets
+ * segmented into multiple CanPackets and receiving single CanPackets that are
+ * then reframed as CanData.
  */
 class CanProtocol : public ActiveObject
 {
 private:
-    miosix::FastMutex
-        mutex;          // todo add mutex and create get data in can protocol
+    // TODO: Add mutex and create get data in can protocol
+    miosix::FastMutex mutex;
     CanbusDriver* can;  // the physical can
-    IRQCircularBuffer<CanData, NPACKET>
+    IRQCircularBuffer<CanData, N_PACKET>
         buffer;  // the buffer used to send data from CanProtocol to CanHandler
 
 public:
     /**
-     * @brief Construct a new CanProtocol object
-     * @param can CanbusDriver pointer.
+     * @brief Construct a new CanProtocol object.
+     *
+     * @param can Pointer to a CanbusDriver object.
      */
-    CanProtocol(CanbusDriver* can) { this->can = can; }
-    /* Destructor */
-    ~CanProtocol() { (*can).~CanbusDriver(); }
+    explicit CanProtocol(CanbusDriver* can);
+
+    ~CanProtocol();
 
     /**
-     * @brief return the packet, if buffer is empty return an empty packet
+     * @brief Returns the first packet in the buffer.
+     *
+     * If buffer is empty return an empty packet.
      * @warning Should be called only after checking isEmpty()
      */
-    CanData
-    getPacket()  // return the packet, if buffer is empty return an empty packet
-    {
-        CanData temp;
-        miosix::Lock<miosix::FastMutex> l(mutex);
-        if (!buffer.isEmpty())
-        {
-            temp = buffer.pop();
-        }
-
-        return temp;
-    }
+    CanData getPacket();
 
-    bool isEmpty()
-    {
-        miosix::Lock<miosix::FastMutex> l(mutex);
-        return buffer.isEmpty();
-    }
+    bool isBufferEmpty();
 
-    void waitEmpty() { buffer.waitUntilNotEmpty(); }
+    void waitBufferEmpty();
 
     /**
-     * @brief Count the number of byte needed to encode a uint64_t number
+     * @brief Sends a CanData object on the bus.
+     *
+     * Takes a CanData object, splits it into multiple CanPackets with the
+     * correct sequential id.
+     * @warning requires @param data to be not empty.
+     *
+     * @param data Contains the id e the data of the packet to send.
      */
-    uint8_t byteForInt(uint64_t number)
-    {
-        uint8_t i;
-        for (i = 1; i <= 8; i++)
-        {
-            number = number >> 8;
-            if (number == 0)
-                return i;
-        }
-        return i;
-    }
+    void sendData(CanData dataToSend);
+
+private:
     /**
-     * @brief Takes a canData, it splits it into single canpacket with the
-     * correct sequential id
-     * @param toSend = containing the id e the data of the packet to send
-     * @warning requires toSend to be not empty
+     * @brief Count the number of bytes needed to encode a uint64_t number.
      */
-    void sendCan(CanData toSend)  //@requires toSen to not be empty
-    {
-        CanPacket packet;
-        uint8_t tempLen = toSend.len - 1;
-        uint32_t tempId = toSend.canId;
-        packet.ext      = true;
-        packet.id       = (tempId << shiftSequentialInfo) | firstPacket |
-                    (63 - (tempLen & leftToSend));
-        packet.length = byteForInt(toSend.payload[0]);
-        for (int k = 0; k < packet.length; k++)
-        {
-            packet.data[k] = toSend.payload[0] >> (8 * k);
-        }
-        tempLen--;
-        can->send(packet);
-        for (int i = 1; i < toSend.len; i++)
-        {
-            tempId    = toSend.canId;
-            packet.id = (tempId << shiftSequentialInfo) | !(firstPacket) |
-                        (63 - (tempLen & leftToSend));
-            packet.length = byteForInt(toSend.payload[i]);
-            for (int k = 0; k < packet.length; k++)
-            {
-                packet.data[k] = toSend.payload[i] >> (8 * k);
-            }
-            can->send(packet);
-            tempLen--;
-        }
-    }
+    uint8_t byteForInt(uint64_t number);
 
-protected:
     /**
-     * @brief Keeps listening on hte canbus for packets, once received it checks
-     * if they are expected (that id is already present in data), if they are
-     * they are added to the list. once we receive the correct amount of packet
-     * we send it to can handler.
+     * @brief Keeps listening on the canbus for packets.
+     *
+     * Once a packet is received, it checks if it is expected (that id is
+     * already present in data), if that is the case, it is added to the list.
+     * Once we receive the correct amount of packet we send it to can handler.
+     *
+     * For now if a packet is missed/received in the wrong order the whole
+     * packet will be lost once we receive a new first packet without warning
+     * CanHandler.
      */
-    void run() override  // for now if a packet is missed/received in the wrong
-                         // order the whole packet will be lost once we receive
-                         // a new first packet without warning canhandler
-    {
-        uint32_t idNoSeq;
-        uint8_t sourceId;
-        CanPacket packet;
-        // Infinite loop
-        while (true)
-        {
-            can->getRXBuffer().waitUntilNotEmpty();
-            if (!can->getRXBuffer().isEmpty())
-            {
-
-                packet  = can->getRXBuffer().pop().packet;
-                idNoSeq = packet.id >>
-                          shiftSequentialInfo;  // discard the sequence number
-                sourceId = (idNoSeq & source) >> shiftSource;
-                if (sourceId >= 0 &&
-                    sourceId < NPACKET)  // check for maximum size
-                {
-
-                    if (data[sourceId].canId == -1 ||
-                        ((data[sourceId].canId & source) >> shiftSource) ==
-                            sourceId)
-                    {
-                        uint8_t left = 63 - (packet.id & leftToSend);
-
-                        if ((packet.id & firstPacket) >>
-                            shiftFirstPacket)  // it is a first
-                                               // packet of a data;
-                        {
-                            data[sourceId].len   = left + 1;
-                            data[sourceId].canId = idNoSeq;
-                        }
-                        if ((data[sourceId].len - (data[sourceId].nRec + 1)) ==
-                            left)
-                        {
-
-                            uint64_t tempPayload = 0;
-                            for (int f = 0; f < packet.length; f++)
-                            {
-                                uint64_t tempData = packet.data[f];
-                                tempPayload =
-                                    tempPayload | (tempData << (f * 8));
-                            }
-
-                            if (data[sourceId].len - left - 1 >= 0 &&
-                                data[sourceId].len - left - 1 <
-                                    32)  // check for index
-                            {
-
-                                data[sourceId]
-                                    .payload[data[sourceId].len - left - 1] =
-                                    tempPayload;
-                                data[sourceId].nRec++;
-                            }
-                        }
-
-                        if (data[sourceId].nRec == data[sourceId].len &&
-                            data[sourceId].nRec != 0)
-                        {
-                            miosix::Lock<miosix::FastMutex> l(mutex);
-                            buffer.put(data[sourceId]);
-                            // empties the struct
-                            data[sourceId].canId = -1;
-                            data[sourceId].nRec  = 0;
-                            data[sourceId].len   = 0;
-                        }
-                    }
-                }
-            }
-        }
-    }
+    void run() override;
 };
+
 }  // namespace Canbus
+
 }  // namespace Boardcore
diff --git a/src/tests/drivers/canbus/test-can-protocol.cpp b/src/tests/drivers/canbus/test-can-protocol.cpp
index 9f8eef1ed..b37018743 100644
--- a/src/tests/drivers/canbus/test-can-protocol.cpp
+++ b/src/tests/drivers/canbus/test-can-protocol.cpp
@@ -60,18 +60,19 @@ void sendData(CanProtocol* protocol, CanData* toSend)
         TRACE("send\n");
         {
             miosix::Lock<miosix::FastMutex> l(mutex);
-            (*protocol).sendCan(*toSend);
+            (*protocol).sendData(*toSend);
         }
         Thread::sleep(SLP);
     }
 }
 bool equal(CanData* first, CanData* second)
 {
-    if ((*first).canId != (*second).canId || (*first).len != (*second).len)
+    if ((*first).canId != (*second).canId ||
+        (*first).length != (*second).length)
     {
         return false;
     }
-    for (int i = 0; i < (*first).len; i++)
+    for (int i = 0; i < (*first).length; i++)
     {
         if ((*first).payload[i] != (*second).payload[i])
             return false;
@@ -109,7 +110,7 @@ int main()
     protocol.start();
 
     toSend1.canId      = 0x200;
-    toSend1.len        = 8;
+    toSend1.length     = 8;
     toSend1.payload[0] = 0xffffffffffffffff;
     toSend1.payload[1] = 2;
     toSend1.payload[2] = 78022;
@@ -122,25 +123,25 @@ int main()
 
     Thread::sleep(10);
     toSend2.canId      = 0x100;
-    toSend2.len        = 4;
+    toSend2.length     = 4;
     toSend2.payload[0] = 0xffffff;
     toSend2.payload[1] = 2;
     toSend2.payload[2] = 0x123ff;
     toSend2.payload[3] = 1;
     std::thread secondSend(sendData, &protocol, &toSend2);
     TRACE("start \n");
+
     for (;;)
     {
-
-        protocol.waitEmpty();
+        protocol.waitBufferEmpty();
         CanData temp = protocol.getPacket();
         TRACE("received packet \n");
         if ((!equal(&temp, &toSend1) && !equal(&temp, &toSend2)))
         {
             TRACE("Error\n");
             TRACE("Received  %lu\n", temp.canId);
-            TRACE("Received %d\n", temp.len);
-            for (int i = 0; i < temp.len; i++)
+            TRACE("Received %d\n", temp.length);
+            for (int i = 0; i < temp.length; i++)
             {
                 TRACE("Received payload %d:  %llu,\n", i, temp.payload[i]);
             }
-- 
GitLab