commit d54d2f07cf55f262267ac5bae4ff1549e315a0a6
Author: Thomas Schöpping <tschoepp@cit-ec.uni-bielefeld.de>
Date:   Fri Mar 16 11:43:09 2018 +0100

    Major overhaul (to version 1.1.0):
    - The bootloader toolchain now works with 32 bit device IDs (DiWheelDrive 1.1 = 0x01000101; PowerManagement 1.1 = 0x01010101; LightRing 1.0 = 0x017F0100).
      However, the system is still compatible to the old numbering scheme and legacy IDs for compatibility reasons.
      As a result, the new bootloader can be used with the old SerialBoot tool and vice versa.
    - In order to allow for 32 bit IDs, the CAN communication as modified.
      Packages which are larger than a single transmit are split into multiple CAN messages.
      An according handshaking mechanism (receiver acknowledges everey message) has been implemented.
      The device ID is not coded into the CAN message identifier anymore, but is transmitted as the first four bytes of the first CAN message of a XCP package transmission.
      However, the two lowermost bit of the CAN message identifier are now used as indicator flags for acknowledgment and subsequent transmission for simple filtering.
    - The bootloaders will not "double blink" the LED anymore, but indicate the XCP connection status.
    - The bootloader version has been incremented to 1.1.0.

diff --git a/Target/Source/ARMCM3_STM32/can.c b/Target/Source/ARMCM3_STM32/can.c
index 1dcafc6..c5da070 100644
--- a/Target/Source/ARMCM3_STM32/can.c
+++ b/Target/Source/ARMCM3_STM32/can.c
@@ -23,20 +23,25 @@
 * You should have received a copy of the GNU General Public License along with OpenBLT.
 * If not, see <http://www.gnu.org/licenses/>.
 *
-* A special exception to the GPL is included to allow you to distribute a combined work 
-* that includes OpenBLT without being obliged to provide the source code for any 
+* A special exception to the GPL is included to allow you to distribute a combined work
+* that includes OpenBLT without being obliged to provide the source code for any
 * proprietary components. The exception text is included at the bottom of the license
 * file <license.html>.
-* 
+*
 * \endinternal
 ****************************************************************************************/
 
+#define CAN_DEBUG       (0)
 
 /****************************************************************************************
 * Include files
 ****************************************************************************************/
 #include "boot.h"                                /* bootloader generic header          */
 
+#if (CAN_DEBUG > 0)
+#include <helper.h>
+#endif
+
 
 #if (BOOT_COM_CAN_ENABLE > 0 || BOOT_GATE_CAN_ENABLE > 0)
 /****************************************************************************************
@@ -58,7 +63,7 @@ typedef struct
   volatile blt_int32u RDTR;
   volatile blt_int32u RDLR;
   volatile blt_int32u RDHR;
-} tCanRxFIFOMailBox; 
+} tCanRxFIFOMailBox;
 
 /** \brief CAN filter register layout. */
 typedef struct
@@ -92,7 +97,7 @@ typedef struct
   volatile blt_int32u FA1R;
   blt_int32u          RESERVED5[8];
   tCanFilter          sFilterRegister[14];
-} tCanRegs;                                           
+} tCanRegs;
 
 
 /****************************************************************************************
@@ -144,9 +149,9 @@ typedef struct t_can_bus_timing
 * Local constant declarations
 ****************************************************************************************/
 /** \brief CAN bittiming table for dynamically calculating the bittiming settings.
- *  \details According to the CAN protocol 1 bit-time can be made up of between 8..25 
- *           time quanta (TQ). The total TQ in a bit is SYNC + TSEG1 + TSEG2 with SYNC 
- *           always being 1. The sample point is (SYNC + TSEG1) / (SYNC + TSEG1 + SEG2) * 
+ *  \details According to the CAN protocol 1 bit-time can be made up of between 8..25
+ *           time quanta (TQ). The total TQ in a bit is SYNC + TSEG1 + TSEG2 with SYNC
+ *           always being 1. The sample point is (SYNC + TSEG1) / (SYNC + TSEG1 + SEG2) *
  *           100%. This array contains possible and valid time quanta configurations with
  *           a sample point between 68..78%.
  */
@@ -175,17 +180,17 @@ static const tCanBusTiming canTiming[] =
 
 
 /************************************************************************************//**
-** \brief     Search algorithm to match the desired baudrate to a possible bus 
+** \brief     Search algorithm to match the desired baudrate to a possible bus
 **            timing configuration.
 ** \param     baud The desired baudrate in kbps. Valid values are 10..1000.
 ** \param     prescaler Pointer to where the value for the prescaler will be stored.
 ** \param     tseg1 Pointer to where the value for TSEG2 will be stored.
 ** \param     tseg2 Pointer to where the value for TSEG2 will be stored.
-** \return    BLT_TRUE if the CAN bustiming register values were found, BLT_FALSE 
+** \return    BLT_TRUE if the CAN bustiming register values were found, BLT_FALSE
 **            otherwise.
 **
 ****************************************************************************************/
-static blt_bool CanGetSpeedConfig(blt_int16u baud, blt_int16u *prescaler, 
+static blt_bool CanGetSpeedConfig(blt_int16u baud, blt_int16u *prescaler,
                                   blt_int8u *tseg1, blt_int8u *tseg2)
 {
   blt_int8u  cnt;
@@ -229,10 +234,10 @@ void CanInit(void)
   commandSend = BLT_FALSE;
 #endif /* BOOT_GATE_CAN_ENABLE > 0 */
 
-  /* the current implementation supports CAN1. throw an assertion error in case a 
-   * different CAN channel is configured.  
+  /* the current implementation supports CAN1. throw an assertion error in case a
+   * different CAN channel is configured.
    */
-  ASSERT_CT(BOOT_COM_CAN_CHANNEL_INDEX == 0); 
+  ASSERT_CT(BOOT_COM_CAN_CHANNEL_INDEX == 0);
   /* obtain bittiming configuration information */
   result = CanGetSpeedConfig(BOOT_COM_CAN_BAUDRATE/1000, &prescaler, &tseg1, &tseg2);
   ASSERT_RT(result == BLT_TRUE);
@@ -275,8 +280,8 @@ void CanInit(void)
   /* 32-bit scale for the filter */
   CANx->FS1R |= CAN_BIT_FILTER0;
   /* open up the acceptance filter to receive all messages */
-  CANx->sFilterRegister[0].FR1 = 0; 
-  CANx->sFilterRegister[0].FR2 = 0; 
+  CANx->sFilterRegister[0].FR1 = 0;
+  CANx->sFilterRegister[0].FR2 = 0;
   /* select id/mask mode for the filter */
   CANx->FM1R &= ~CAN_BIT_FILTER0;
   /* FIFO 0 assignation for the filter */
@@ -296,12 +301,10 @@ void CanInit(void)
 ** \return    none.
 **
 ****************************************************************************************/
-void CanTransmitPacket(blt_int8u *data, blt_int8u len, blt_int8u deviceID)
+void CanTransmitPacket(blt_int8u *data, blt_int8u len, blt_int32u deviceID)
 {
   /* make sure that transmit mailbox 0 is available */
   ASSERT_RT((CANx->TSR&CAN_BIT_TME0) == CAN_BIT_TME0);
-  /* build the message identifier */
-  CANx->sTxMailBox[0].TIR &= CAN_BIT_TXRQ;
 
   blt_int32u address;
 #if (BOOT_GATE_CAN_ENABLE > 0)
@@ -311,7 +314,7 @@ void CanTransmitPacket(blt_int8u *data, blt_int8u len, blt_int8u deviceID)
 #if (BOOT_GATE_CAN_ENABLE > 0)
     commandSend = BLT_FALSE;
   } else {
-    address = ((blt_int32u)BOOT_COM_CAN_RX_MSG_ID | (blt_int32u)deviceID);
+    address = (blt_int32u)BOOT_COM_CAN_RX_MSG_ID;
     commandSend = BLT_TRUE;
   }
 #endif /* BOOT_GATE_CAN_ENABLE > 0 */
@@ -320,20 +323,45 @@ void CanTransmitPacket(blt_int8u *data, blt_int8u len, blt_int8u deviceID)
   blt_int8u canData[8];
   blt_int8u restLen = len;
   blt_int8u canIdx = 0;
+  blt_int32u ackMsgId;
+  blt_int8u ackMsgLen;
 
   /* send the given package in 8 byte packages */
   while (restLen > 0) {
-
+    /* build the message identifier */
+    CANx->sTxMailBox[0].TIR &= CAN_BIT_TXRQ;
     CANx->sTxMailBox[0].TIR |= (address << 21);
-    /* store the message date length code (DLC) */
-    if (restLen > 7) {
-      CANx->sTxMailBox[0].TDTR = 8;
-    } else {
-      CANx->sTxMailBox[0].TDTR = restLen+1;
+
+    /* if this is the first transmission of this packet */
+    if (restLen == len) {
+
+      /* store the message date length code (DLC) */
+      CANx->sTxMailBox[0].TDTR = (restLen > 4) ? 8 : restLen+1+4;
+
+      /* store the device ID */
+      canData[0] = (blt_int8u)(0xFF & (deviceID >> 0));
+      canData[1] = (blt_int8u)(0xFF & (deviceID >> 8));
+      canData[2] = (blt_int8u)(0xFF & (deviceID >> 16));
+      canData[3] = (blt_int8u)(0xFF & (deviceID >> 24));
+
+      /* store the remaining packet length */
+      canData[4] = restLen;
+
+      canIdx = 5;
+    }
+    /* if this is a succeeding transmission of this packet */
+    else {
+
+      /* store the message date length code (DLC) */
+      CANx->sTxMailBox[0].TDTR = (restLen > 7) ? 8 : restLen+1;
+
+      /* store the remaining packet length */
+      canData[0] = restLen;
+
+      canIdx = 1;
     }
-    /* Load max 8 bytes into message data bytes */
-    canData[0] = restLen;
-    canIdx = 1;
+
+    /* store the packet payload */
     while (restLen > 0 && canIdx < 8) {
       canData[canIdx] = data[len-restLen];
       canIdx++;
@@ -344,6 +372,7 @@ void CanTransmitPacket(blt_int8u *data, blt_int8u len, blt_int8u deviceID)
       canData[canIdx] = 0;
       canIdx++;
     }
+
     /* store the message data bytes */
     CANx->sTxMailBox[0].TDLR = (((blt_int32u)canData[3] << 24) | \
                                 ((blt_int32u)canData[2] << 16) | \
@@ -353,6 +382,7 @@ void CanTransmitPacket(blt_int8u *data, blt_int8u len, blt_int8u deviceID)
                                 ((blt_int32u)canData[6] << 16) | \
                                 ((blt_int32u)canData[5] <<  8) | \
                                 ((blt_int32u)canData[4]));
+
     /* request the start of message transmission */
     CANx->sTxMailBox[0].TIR |= CAN_BIT_TXRQ;
     /* wait for transmit completion */
@@ -362,6 +392,52 @@ void CanTransmitPacket(blt_int8u *data, blt_int8u len, blt_int8u deviceID)
       CopService();
     }
 
+    /* wait for the acknowledgement transmission */
+    while ((CANx->RF0R&(blt_int32u)0x00000003) == 0) {
+      /* keep the watchdog happy */
+      CopService();
+    }
+
+    /* read out the message identifier, length and payload */
+    ackMsgId = (blt_int32u)0x000007FF & (CANx->sFIFOMailBox[0].RIR >> 21);
+    ackMsgLen = (blt_int8u)0x0F & CANx->sFIFOMailBox[0].RDTR;
+    canData[0] = (blt_int8u)0xFF & CANx->sFIFOMailBox[0].RDLR;
+    canData[1] = (blt_int8u)0xFF & (CANx->sFIFOMailBox[0].RDLR >> 8);
+    canData[2] = (blt_int8u)0xFF & (CANx->sFIFOMailBox[0].RDLR >> 16);
+    canData[3] = (blt_int8u)0xFF & (CANx->sFIFOMailBox[0].RDLR >> 24);
+    canData[4] = (blt_int8u)0xFF & CANx->sFIFOMailBox[0].RDHR;
+    canData[5] = (blt_int8u)0xFF & (CANx->sFIFOMailBox[0].RDHR >> 8);
+    canData[6] = (blt_int8u)0xFF & (CANx->sFIFOMailBox[0].RDHR >> 16);
+    canData[7] = (blt_int8u)0xFF & (CANx->sFIFOMailBox[0].RDHR >> 24);
+
+#if (CAN_DEBUG > 0)
+    /* verification:
+     * - ID must be "address & BOOT_COM_CAN_MSG_ACK"
+     * - length must be 1
+     * - canData[0] must b equal to restLen
+     */
+    if (ackMsgId != (address | (blt_int32u)BOOT_COM_CAN_MSG_ACK) ||
+        ackMsgLen != 1 ||
+        canData[0] != restLen) {
+      /* some error occurred */
+      blinkSOS(1);
+      msleep(500);
+      visualizeData((blt_int8u*)&ackMsgId, 2, 1);
+      msleep(500);
+      visualizeByte(ackMsgLen, 1);
+      msleep(500);
+      visualizeByte(canData[0], 1);
+      msleep(500);
+      visualizeByte(restLen, 1);
+      blinkSOSinf();
+    }
+#endif /* CAN_DEBUG > 0 */
+
+    /* release FIFO0 */
+    CANx->RF0R |= CAN_BIT_RFOM0;
+
+    /* modify address so that receivers can filter */
+    address |= (blt_int32u)BOOT_COM_CAN_MSG_SUBSEQUENT;
   }
 } /*** end of CanTransmitPacket ***/
 
@@ -385,30 +461,33 @@ blt_int8u CanReceivePacket(blt_int8u *data)
   blt_int8u canData[8];
   blt_int8u restLen;
   blt_int8u canLength;
+  blt_int8u idx;
 
-  /* check if a new message was received */
-  if ((CANx->RF0R&(blt_int32u)0x00000003) > 0)
-  {
-    /* read out the message identifier */
-    rxMsgId = (blt_int32u)0x000007FF & (CANx->sFIFOMailBox[0].RIR >> 21);
-    /* is this the packet identifier */
-
-    blt_int32u compID;
+  blt_int32u compID;
 #if (BOOT_GATE_CAN_ENABLE > 0)
-    if (commandSend == BLT_TRUE) {
-      compID = (blt_int32u)BOOT_COM_CAN_TX_MSG_ID;
-    } else {
+  if (commandSend == BLT_TRUE) {
+    compID = (blt_int32u)BOOT_COM_CAN_TX_MSG_ID;
+  } else {
 #endif /* BOOT_GATE_CAN_ENABLE > 0 */
-      compID = (blt_int32u)BOOT_COM_CAN_RX_MSG_ID | (blt_int32u)BOOT_COM_DEVICE_ID;
+    compID = (blt_int32u)BOOT_COM_CAN_RX_MSG_ID;
 #if (BOOT_GATE_CAN_ENABLE > 0)
-    }
+  }
 #endif /* BOOT_GATE_CAN_ENABLE > 0 */
 
+  /* check if a new message was received  or is more to come */
+  while ((CANx->RF0R&(blt_int32u)0x00000003) > 0 || receivedLen < toReceive)
+  {
+    /* wait for a transmission if required */
+    while (receivedLen < toReceive && (CANx->RF0R&(blt_int32u)0x00000003) == 0) {
+      /* keep the watchdog happy */
+      CopService();
+    }
+
+    /* read out the message identifier */
+    rxMsgId = (blt_int32u)0x000007FF & (CANx->sFIFOMailBox[0].RIR >> 21);
+    /* is this the packet identifier */
     if (rxMsgId == compID)
     {
-#if (BOOT_GATE_CAN_ENABLE > 0)
-      commandSend = BLT_FALSE;
-#endif /* BOOT_GATE_CAN_ENABLE > 0 */
       result = BLT_TRUE;
 
       /* save length */
@@ -423,39 +502,143 @@ blt_int8u CanReceivePacket(blt_int8u *data)
       canData[6] = (blt_int8u)0xFF & (CANx->sFIFOMailBox[0].RDHR >> 16);
       canData[7] = (blt_int8u)0xFF & (CANx->sFIFOMailBox[0].RDHR >> 24);
 
-      /* Store rest length of package and check if possible */
+#if (CAN_DEBUG > 0)
+      if ((receivedLen == 0 && (rxMsgId & (blt_int32u)BOOT_COM_CAN_MSG_SUBSEQUENT) != 0) ||
+          (receivedLen > 0 && (rxMsgId & (blt_int32u)BOOT_COM_CAN_MSG_SUBSEQUENT) == 0)) {
+        blinkSOS(4);
+        msleep(500);
+        visualizeByte(toReceive, 1);
+        msleep(500);
+        visualizeByte(receivedLen, 1);
+        msleep(500);
+        visualizeData((blt_int8u*)&rxMsgId, 2, 1);
+        msleep(500);
+        blinkSOSinf();
+      }
+#endif /* CAN_DEBUG > 0 */
+
+      /* if this is the first transmission of this packet */
       if (receivedLen == 0) {
-        toReceive = canData[0];
-        lastLen = canData[0];
-      } else {
+        /* abort if the message was meant for someone else */
+        blt_int32u deviceID = (((blt_int32u)canData[3]) << 24) | \
+                              (((blt_int32u)canData[2]) << 16) | \
+                              (((blt_int32u)canData[1]) <<  8) | \
+                              (((blt_int32u)canData[0]));
+#if (BOOT_GATE_ENABLE > 0)
+        if ((commandSend == BLT_TRUE && deviceID == 0) ||
+            (commandSend != BLT_TRUE && (deviceID == (blt_int32u)BOOT_COM_DEVICE_ID) || deviceID == (blt_int32u)BOOT_COM_DEVICE_LEGACY_ID)) {
+#else
+        if (deviceID == (blt_int32u)BOOT_COM_DEVICE_ID ||
+            deviceID == (blt_int32u)BOOT_COM_DEVICE_LEGACY_ID) {
+#endif
+          /* store length of the packet */
+          toReceive = canData[4];
+          lastLen = canData[4];
+          idx = 5;
+
+          /* modify the listening address for filtering of subsequent transmissions */
+          compID |= (blt_int32u)BOOT_COM_CAN_MSG_SUBSEQUENT;
+        } else {
+          /* release FIFO0 */
+          CANx->RF0R |= CAN_BIT_RFOM0;
+          break;
+        }
+      }
+      /* if this is a subsequent transmission of a packet */
+      else {
+        /* store rest length and check if possible */
         restLen = canData[0];
-        if (lastLen-restLen != 7) {
-          // package has been lost - but nothing happens
+#if (CAN_DEBUG > 0)
+        if (restLen != toReceive-receivedLen ||
+            canLength > restLen+1 ||
+            lastLen-restLen != ((lastLen==toReceive) ? 3 : 7)) {
+          /* transmission has been lost */
+          blinkSOS(2);
+          msleep(500);
+          visualizeData((blt_int8u*)&rxMsgId, 4, 1);
+          msleep(500);
+          visualizeByte(toReceive, 1);
+          msleep(500);
+          visualizeByte(receivedLen, 1);
+          msleep(500);
+          visualizeByte(lastLen, 1);
+          msleep(500);
+          visualizeByte(restLen, 1);
+          msleep(500);
+          visualizeByte(canLength, 1);
+          msleep(500);
+          visualizeData(readData, receivedLen, 1);
+          blinkSOSinf();
         }
+#endif /* CAN_DEBUG > 0 */
         lastLen = restLen;
+        idx = 1;
       }
 
-      /* store data in data package */
-      blt_int8u idx;
-      for (idx=1; idx < canLength; idx++) {
+      /* store the payload */
+      for (; idx < canLength; idx++) {
         readData[receivedLen] = canData[idx];
         receivedLen++;
       }
 
+      /* release FIFO0 */
+      CANx->RF0R |= CAN_BIT_RFOM0;
+
+      /* send acknowledgement */
+      CANx->sTxMailBox[0].TIR &= CAN_BIT_TXRQ;
+      CANx->sTxMailBox[0].TIR |= ((rxMsgId | (blt_int32u)BOOT_COM_CAN_MSG_ACK) << 21);
+      CANx->sTxMailBox[0].TDTR = 1;
+      CANx->sTxMailBox[0].TDLR = (((blt_int32u)0 << 24) | \
+                                  ((blt_int32u)0 << 16) | \
+                                  ((blt_int32u)0 <<  8) | \
+                                  ((blt_int32u)(toReceive-receivedLen)));
+      CANx->sTxMailBox[0].TDHR = (((blt_int32u)0 << 24) | \
+                                  ((blt_int32u)0 << 16) | \
+                                  ((blt_int32u)0 <<  8) | \
+                                  ((blt_int32u)0));
+
+      /* request the start of message transmission */
+      CANx->sTxMailBox[0].TIR |= CAN_BIT_TXRQ;
+      /* wait for transmit completion */
+      while ((CANx->TSR&CAN_BIT_TME0) == 0)
+      {
+        /* keep the watchdog happy */
+        CopService();
+      }
+
       /* check if full package has been received */
-      if (receivedLen >= toReceive) {
-        receivedLen = 0;
+      if (receivedLen == toReceive) {
+#if (BOOT_GATE_CAN_ENABLE > 0)
+        commandSend = BLT_FALSE;
+#endif /* BOOT_GATE_CAN_ENABLE > 0 */
         for (idx = 0; idx < toReceive; idx++) {
           data[idx] = readData[idx];
         }
         length = toReceive;
+        /* reset static variables */
+        receivedLen = 0;
+        toReceive = 0;
+        break;
       } else {
+#if (CAN_DEBUG > 0)
+        if (receivedLen > toReceive) {
+          /* something strange happened */
+          blinkSOS(3);
+          msleep(500);
+          visualizeByte(toReceive, 1);
+          msleep(500);
+          visualizeByte(receivedLen, 1);
+          blinkSOSinf();
+        }
+#endif /* CAN_DEBUG > 0 */
         length = 0;
       }
+    } else {
+      /* release FIFO0 */
+      CANx->RF0R |= CAN_BIT_RFOM0;
     }
-    /* release FIFO0 */
-    CANx->RF0R |= CAN_BIT_RFOM0;
   }
+
   return length;
 } /*** end of CanReceivePacket ***/
 #endif /* BOOT_COM_CAN_ENABLE > 0  || BOOT_GATE_CAN_ENABLE > 0 */
