OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5497|回复: 8

(CANOPEN)如何通过程序发送SDO,PDO报文?

[复制链接]

5

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
122
金钱
122
注册时间
2018-7-10
在线时间
30 小时
发表于 2018-8-14 13:32:44 | 显示全部楼层 |阅读模式
20金钱
(移植的CANFESTIVAL)我目前做到一直不停发送BOOTUP,但是SDO报文始终没办法发送。(通过CANPRO来调试的)CANPRO上面始终不显示是否接收到报文。
有大佬能详细说一下具体步骤吗?
最好能详细说明一下哪一步该调用哪个函数为什么调用这个函数。
sdo.c
------------------------------------------------------------------------------------------------------
/*
   This file is part of CanFestival, a library implementing CanOpen Stack.
pdo
---------------------------------------------------------------------------------------------------------------
/*
  This file is part of CanFestival, a library implementing CanOpen
  Stack.

  Copyright (C): Edouard TISSERANT and Francis DUPIN

  See COPYING file for copyrights details.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
  USA
*/
#include "pdo.h"
#include "objacces.h"
#include "canfestival.h"
#include "sysdep.h"

/*!
** @file   pdo.c
** @Author Edouard TISSERANT and Francis DUPIN
** @date   Tue Jun  5 09:32:32 2007
**
** @brief
**
**
*/

/*!
**
**
** @param d
** @param TPDO_com TPDO communication parameters OD entry
** @param TPDO_map TPDO mapping parameters OD entry
**
** @return
**/

UNS8 buildPDO (CO_Data * d, UNS8 numPdo, Message * pdo)
{
  const indextable *TPDO_com = d->objdict + d->firstIndex->PDO_TRS + numPdo;
  const indextable *TPDO_map = d->objdict + d->firstIndex->PDO_TRS_MAP + numPdo;

  UNS8 prp_j = 0x00;
  UNS32 offset = 0x00000000;
  const UNS8 *pMappingCount = (UNS8 *) TPDO_map->pSubindex[0].pObject;

  pdo->cob_id = (UNS16) UNS16_LE(*(UNS32*)TPDO_com->pSubindex[1].pObject & 0x7FF);
  pdo->rtr = NOT_A_REQUEST;

  MSG_WAR (0x3009, "  PDO CobId is : ",
           *(UNS32 *) TPDO_com->pSubindex[1].pObject);
  MSG_WAR (0x300D, "  Number of objects mapped : ", *pMappingCount);

  do
    {
      UNS8 dataType;            /* Unused */
      UNS8 tmp[] = { 0, 0, 0, 0, 0, 0, 0, 0 };  /* temporary space to hold bits */

      /* pointer fo the var which holds the mapping parameter of an mapping entry  */
      UNS32 *pMappingParameter =
        (UNS32 *) TPDO_map->pSubindex[prp_j + 1].pObject;
      UNS16 index = (UNS16) ((*pMappingParameter) >> 16);
      UNS32 Size = (UNS32) (*pMappingParameter & (UNS32) 0x000000FF);     /* Size in bits */

      /* get variable only if Size != 0 and Size is lower than remaining bits in the PDO */
      if (Size && ((offset + Size) <= 64))
        {
          UNS32 ByteSize = 1 + ((Size - 1) >> 3);        /*1->8 => 1 ; 9->16 => 2, ... */
          UNS8 subIndex =
            (UNS8) (((*pMappingParameter) >> (UNS8) 8) & (UNS32) 0x000000FF);

          MSG_WAR (0x300F, "  got mapping parameter : ", *pMappingParameter);
          MSG_WAR (0x3050, "    at index : ", TPDO_map->index);
          MSG_WAR (0x3051, "    sub-index : ", prp_j + 1);

          if (getODentry (d, index, subIndex, tmp, &ByteSize, &dataType, 0) !=
              OD_SUCCESSFUL)
            {
              MSG_ERR (0x1013,
                       " Couldn't find mapped variable at index-subindex-size : ",
                       (UNS32) (*pMappingParameter));
              return 0xFF;
            }
          /* copy bit per bit in little endian */
          CopyBits ((UNS8) Size, ((UNS8 *) tmp), 0, 0,
                    (UNS8 *) & pdo->data[offset >> 3], (UNS8)(offset % 8), 0);

          offset += Size;
        }
      prp_j++;
    }
  while (prp_j < *pMappingCount);

  pdo->len = (UNS8)(1 + ((offset - 1) >> 3));

  MSG_WAR (0x3015, "  End scan mapped variable", 0);

  return 0;
}

/*!
**
**
** @param d
** @param cobId
**
** @return
**/
UNS8
sendPDOrequest (CO_Data * d, UNS16 RPDOIndex)
{
  UNS16 *pwCobId;
  UNS16 offset = d->firstIndex->PDO_RCV;
  UNS16 lastIndex = d->lastIndex->PDO_RCV;

  if (!d->CurrentCommunicationState.csPDO)
    {
      return 0;
    }

  /* Sending the request only if the cobid have been found on the PDO
     receive */
  /* part dictionary */

  MSG_WAR (0x3930, "sendPDOrequest RPDO Index : ", RPDOIndex);

  if (offset && RPDOIndex >= 0x1400)
    {
      offset += RPDOIndex - 0x1400;
      if (offset <= lastIndex)
        {
          /* get the CobId */
          pwCobId = d->objdict[offset].pSubindex[1].pObject;

          MSG_WAR (0x3930, "sendPDOrequest cobId is : ", *pwCobId);
          {
            Message pdo;
            pdo.cob_id = UNS16_LE(*pwCobId);
            pdo.rtr = REQUEST;
            pdo.len = 0;
            return canSend (d->canHandle, &pdo);
          }
        }
    }
  MSG_ERR (0x1931, "sendPDOrequest : RPDO Index not found : ", RPDOIndex);
  return 0xFF;
}


/*!
**
**
** @param d
** @param m
**
** @return
**/
UNS8
proceedPDO (CO_Data * d, Message * m)
{
  UNS8 numPdo;
  UNS8 numMap;                  /* Number of the mapped varable */
  UNS8 *pMappingCount = NULL;   /* count of mapped objects... */
  /* pointer to the var which is mapped to a pdo... */
  /*  void *     pMappedAppObject = NULL;   */
  /* pointer fo the var which holds the mapping parameter of an
     mapping entry */
  UNS32 *pMappingParameter = NULL;
  UNS8 *pTransmissionType = NULL;       /* pointer to the transmission
                                           type */
  UNS16 *pwCobId = NULL;
  UNS8 Size;
  UNS8 offset;
  UNS8 status;
  UNS32 objDict;
  UNS16 offsetObjdict;
  UNS16 lastIndex;

  status = state2;

  MSG_WAR (0x3935, "proceedPDO, cobID : ", (UNS16_LE(m->cob_id) & 0x7ff));
  offset = 0x00;
  numPdo = 0;
  numMap = 0;
  if ((*m).rtr == NOT_A_REQUEST)
    {
      offsetObjdict = d->firstIndex->PDO_RCV;
      lastIndex = d->lastIndex->PDO_RCV;

      if (offsetObjdict)
        while (offsetObjdict <= lastIndex)
          {
            switch (status)
              {

              case state2:
                pwCobId = d->objdict[offsetObjdict].pSubindex[1].pObject;
                if (*pwCobId == UNS16_LE(m->cob_id))
                  {
                    /* The cobId is recognized */
                    status = state4;
                    MSG_WAR (0x3936, "cobId found at index ",
                             0x1400 + numPdo);
                    break;
                  }
                else
                  {
                    /* received cobId does not match */
                    numPdo++;
                    offsetObjdict++;
                    status = state2;
                    break;
                  }

              case state4:     /* Get Mapped Objects Number */
                /* The cobId of the message received has been found in the
                   dictionnary. */
                offsetObjdict = d->firstIndex->PDO_RCV_MAP;
                lastIndex = d->lastIndex->PDO_RCV_MAP;
                pMappingCount =
                  (UNS8 *) (d->objdict + offsetObjdict +
                            numPdo)->pSubindex[0].pObject;
                numMap = 0;
                while (numMap < *pMappingCount)
                  {
                    UNS8 tmp[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
                    UNS32 ByteSize;
                    pMappingParameter =
                      (UNS32 *) (d->objdict + offsetObjdict +
                                 numPdo)->pSubindex[numMap + 1].pObject;
                    if (pMappingParameter == NULL)
                      {
                        MSG_ERR (0x1937, "Couldn't get mapping parameter : ",
                                 numMap + 1);
                        return 0xFF;
                      }
                    /* Get the addresse of the mapped variable. */
                    /* detail of *pMappingParameter : */
                    /* The 16 hight bits contains the index, the medium 8 bits
                       contains the subindex, */
                    /* and the lower 8 bits contains the size of the mapped
                       variable. */

                    Size = (UNS8) (*pMappingParameter & (UNS32) 0x000000FF);

                    /* set variable only if Size != 0 and
                     * Size is lower than remaining bits in the PDO */
                    if (Size && ((offset + Size) <= (m->len << 3)))
                      {
                        /* copy bit per bit in little endian */
                        CopyBits (Size, (UNS8 *) & m->data[offset >> 3],
                                  offset % 8, 0, ((UNS8 *) tmp), 0, 0);
                        /*1->8 => 1 ; 9->16 =>2, ... */
                        ByteSize = (UNS32)(1 + ((Size - 1) >> 3));

                        objDict =
                          setODentry (d, (UNS16) ((*pMappingParameter) >> 16),
                                      (UNS8) (((*pMappingParameter) >> 8) &
                                              0xFF), tmp, &ByteSize, 0);

                        if (objDict != OD_SUCCESSFUL)
                          {
                            MSG_ERR (0x1938,
                                     "error accessing to the mapped var : ",
                                     numMap + 1);
                            MSG_WAR (0x2939, "         Mapped at index : ",
                                     (*pMappingParameter) >> 16);
                            MSG_WAR (0x2940, "                subindex : ",
                                     ((*pMappingParameter) >> 8) & 0xFF);
                            return 0xFF;
                          }

                        MSG_WAR (0x3942,
                                 "Variable updated by PDO cobid : ",
                                 UNS16_LE(m->cob_id));
                        MSG_WAR (0x3943, "         Mapped at index : ",
                                 (*pMappingParameter) >> 16);
                        MSG_WAR (0x3944, "                subindex : ",
                                 ((*pMappingParameter) >> 8) & 0xFF);
                        offset += Size;
                      }
                    numMap++;
                  }             /* end loop while on mapped variables */
                if (d->RxPDO_EventTimers)
                {
                    TIMEVAL EventTimerDuration = *(UNS16 *)d->objdict[offsetObjdict].pSubindex[5].pObject;
                    if(EventTimerDuration){
                        DelAlarm (d->RxPDO_EventTimers[numPdo]);
                        d->RxPDO_EventTimers[numPdo] = SetAlarm (d, numPdo, d->RxPDO_EventTimers_Handler,
                        MS_TO_TIMEVAL (EventTimerDuration), 0);
                    }
                }
                return 0;

              }                 /* end switch status */
          }                     /* end while */
    }                           /* end if Donnees */
  else if ((*m).rtr == REQUEST)
    {
      MSG_WAR (0x3946, "Receive a PDO request cobId : ", UNS16_LE(m->cob_id));
      status = state1;
      offsetObjdict = d->firstIndex->PDO_TRS;
      lastIndex = d->lastIndex->PDO_TRS;
      if (offsetObjdict)
        while (offsetObjdict <= lastIndex)
          {
            /* study of all PDO stored in the objects dictionary */

            switch (status)
              {

              case state1:     /* check the CobId */
                /* get CobId of the dictionary which match to the received PDO
                 */
                pwCobId =
                   (d->objdict +
                             offsetObjdict)->pSubindex[1].pObject;
                if (*pwCobId == UNS16_LE(m->cob_id))
                  {
                    status = state4;
                    break;
                  }
                else
                  {
                    numPdo++;
                    offsetObjdict++;
                  }
                status = state1;
                break;


              case state4:     /* check transmission type */
                pTransmissionType =
                  (UNS8 *) d->objdict[offsetObjdict].pSubindex[2].pObject;
                /* If PDO is to be sampled and send on RTR, do it */
                if ((*pTransmissionType == TRANS_RTR))
                  {
                    status = state5;
                    break;
                  }
                /* RTR_SYNC means data prepared at SYNC, transmitted on RTR */
                else if ((*pTransmissionType == TRANS_RTR_SYNC))
                  {
                    if (d->PDO_status[numPdo].
                        transmit_type_parameter & PDO_RTR_SYNC_READY)
                      {
                        /*Data ready, just send */
                        canSend (d->canHandle,
                                 &d->PDO_status[numPdo].last_message);
                        return 0;
                      }
                    else
                      {
                        /* if SYNC did never occur, transmit current data */
                        /* DS301 do not tell what to do in such a case... */
                        MSG_ERR (0x1947,
                                 "Not ready RTR_SYNC TPDO send current data : ",
                                 UNS16_LE(m->cob_id));
                        status = state5;
                      }
                    break;
                  }
                else if ((*pTransmissionType == TRANS_EVENT_PROFILE) ||
                         (*pTransmissionType == TRANS_EVENT_SPECIFIC))
                  {
                    /* Zap all timers and inhibit flag */
                    d->PDO_status[numPdo].event_timer =
                      DelAlarm (d->PDO_status[numPdo].event_timer);
                    d->PDO_status[numPdo].inhibit_timer =
                      DelAlarm (d->PDO_status[numPdo].inhibit_timer);
                    d->PDO_status[numPdo].transmit_type_parameter &=
                      ~PDO_INHIBITED;
                    /* Call  PDOEventTimerAlarm for this TPDO,
                     * this will trigger emission et reset timers */
                    PDOEventTimerAlarm (d, numPdo);
                    return 0;
                  }
                else
                  {
                    /* The requested PDO is not to send on request. So, does
                       nothing. */
                    MSG_WAR (0x2947, "PDO is not to send on request : ",
                             UNS16_LE(m->cob_id));
                    return 0xFF;
                  }

              case state5:     /* build and send requested PDO */
                {
                  Message pdo;
                  if (buildPDO (d, numPdo, &pdo))
                    {
                      MSG_ERR (0x1948, " Couldn't build TPDO number : ", numPdo);
                      return 0xFF;
                    }
                  canSend (d->canHandle, &pdo);
                  return 0;
                }
              }                 /* end switch status */
          }                     /* end while */
    }                           /* end if Requete */

  return 0;
}

/*!
**
**
** @param NbBits
** @param SrcByteIndex
** @param SrcBitIndex
** @param SrcBigEndian
** @param DestByteIndex
** @param DestBitIndex
** @param DestBigEndian
**/
void
CopyBits (UNS8 NbBits, UNS8 * SrcByteIndex, UNS8 SrcBitIndex,
          UNS8 SrcBigEndian, UNS8 * DestByteIndex, UNS8 DestBitIndex,
          UNS8 DestBigEndian)
{
  /* This loop copy as many bits that it can each time, crossing */
  /* successively bytes */
  // boundaries from LSB to MSB.
  while (NbBits > 0)
    {
      /* Bit missalignement between src and dest */
      INTEGER8 Vect = DestBitIndex - SrcBitIndex;

      /* We can now get src and align it to dest */
      UNS8 Aligned =
        Vect > 0 ? *SrcByteIndex << Vect : *SrcByteIndex >> -Vect;

      /* Compute the nb of bit we will be able to copy */
      UNS8 BoudaryLimit = (Vect > 0 ? 8 - DestBitIndex : 8 - SrcBitIndex);
      UNS8 BitsToCopy = BoudaryLimit > NbBits ? NbBits : BoudaryLimit;

      /* Create a mask that will serve in: */
      UNS8 Mask =
        ((0xff << (DestBitIndex + BitsToCopy)) |
         (0xff >> (8 - DestBitIndex)));

      /* - Filtering src */
      UNS8 Filtered = Aligned & ~Mask;

      /* - and erase bits where we write, preserve where we don't */
      *DestByteIndex &= Mask;

      /* Then write. */
      *DestByteIndex |= Filtered;

      /*Compute next time cursors for src */
      if ((SrcBitIndex += BitsToCopy) > 7)      /* cross boundary ? */
        {
          SrcBitIndex = 0;      /* First bit */
          SrcByteIndex += (SrcBigEndian ? -1 : 1);      /* Next byte */
        }


      /*Compute next time cursors for dest */
      if ((DestBitIndex += BitsToCopy) > 7)
        {
          DestBitIndex = 0;     /* First bit */
          DestByteIndex += (DestBigEndian ? -1 : 1);    /* Next byte */
        }

      /*And decrement counter. */
      NbBits -= BitsToCopy;
    }

}

void sendPdo(CO_Data * d, UNS32 pdoNum, Message * pdo)
{
  /*store_as_last_message */
  d->PDO_status[pdoNum].last_message = *pdo;
  MSG_WAR (0x396D, "sendPDO cobId :", UNS16_LE(pdo->cob_id));
  MSG_WAR (0x396E, "     Nb octets  : ", pdo->len);

  canSend (d->canHandle, pdo);
}


/*!
**
**
** @param d
**
** @return
**/

UNS8
sendPDOevent (CO_Data * d)
{
  /* Calls _sendPDOevent specifying it is not a sync event */
  return _sendPDOevent (d, 0);
}

UNS8
sendOnePDOevent (CO_Data * d, UNS8 pdoNum)
{
  UNS16 offsetObjdict;
  Message pdo;
  if (!d->CurrentCommunicationState.csPDO ||
      (d->PDO_status[pdoNum].transmit_type_parameter & PDO_INHIBITED))
    {
      return 0;
    }

  offsetObjdict = (UNS16) (d->firstIndex->PDO_TRS + pdoNum);

  MSG_WAR (0x3968, "  PDO is on EVENT. Trans type : ",
           *((UNS8 *) d->objdict[offsetObjdict].pSubindex[2].pObject));

  memset(&pdo, 0, sizeof(pdo));
  if (buildPDO (d, pdoNum, &pdo))
    {
      MSG_ERR (0x3907, " Couldn't build TPDO number : ",
               pdoNum);
      return 0;
    }

  /*Compare new and old PDO */
  if (d->PDO_status[pdoNum].last_message.cob_id == pdo.cob_id
      && d->PDO_status[pdoNum].last_message.len == pdo.len
      && memcmp(d->PDO_status[pdoNum].last_message.data,
                                        pdo.data, 8) == 0
    )
    {
      /* No changes -> go to next pdo */
      return 0;
    }
  else
    {

      TIMEVAL EventTimerDuration;
      TIMEVAL InhibitTimerDuration;

      MSG_WAR (0x306A, "Changes TPDO number : ", pdoNum);
      /* Changes detected -> transmit message */
      EventTimerDuration =
        *(UNS16 *) d->objdict[offsetObjdict].pSubindex[5].
        pObject;
      InhibitTimerDuration =
        *(UNS16 *) d->objdict[offsetObjdict].pSubindex[3].
        pObject;

      /* Start both event_timer and inhibit_timer */
      if (EventTimerDuration)
        {
          DelAlarm (d->PDO_status[pdoNum].event_timer);
          d->PDO_status[pdoNum].event_timer =
            SetAlarm (d, pdoNum, &PDOEventTimerAlarm,
                      MS_TO_TIMEVAL (EventTimerDuration), 0);
        }

      if (InhibitTimerDuration)
        {
          DelAlarm (d->PDO_status[pdoNum].inhibit_timer);
          d->PDO_status[pdoNum].inhibit_timer =
            SetAlarm (d, pdoNum, &PDOInhibitTimerAlarm,
                      US_TO_TIMEVAL (InhibitTimerDuration *
                                     100), 0);
          /* and inhibit TPDO */
          d->PDO_status[pdoNum].transmit_type_parameter |=
            PDO_INHIBITED;
        }

      sendPdo(d, pdoNum, &pdo);
    }
    return 1;
}

void
PDOEventTimerAlarm (CO_Data * d, UNS32 pdoNum)
{
  /* This is needed to avoid deletion of re-attribuated timer */
  d->PDO_status[pdoNum].event_timer = TIMER_NONE;
  /* force emission of PDO by artificially changing last emitted */
  d->PDO_status[pdoNum].last_message.cob_id = 0;
  sendOnePDOevent (d, (UNS8) pdoNum);
}

void
PDOInhibitTimerAlarm (CO_Data * d, UNS32 pdoNum)
{
  /* This is needed to avoid deletion of re-attribuated timer */
  d->PDO_status[pdoNum].inhibit_timer = TIMER_NONE;
  /* Remove inhibit flag */
  d->PDO_status[pdoNum].transmit_type_parameter &= ~PDO_INHIBITED;
  sendOnePDOevent (d, (UNS8) pdoNum);
}

void
_RxPDO_EventTimers_Handler(CO_Data *d, UNS32 pdoNum)
{
}

/*!
**
**
** @param d
** @param isSyncEvent
**
** @return
**/

UNS8 _sendPDOevent (CO_Data * d, UNS8 isSyncEvent)
{
  UNS8 pdoNum = 0x00;           /* number of the actual processed pdo-nr. */
  UNS8 *pTransmissionType = NULL;
  UNS8 status = state3;
  UNS16 offsetObjdict = d->firstIndex->PDO_TRS;
  UNS16 offsetObjdictMap = d->firstIndex->PDO_TRS_MAP;
  UNS16 lastIndex = d->lastIndex->PDO_TRS;

  if (!d->CurrentCommunicationState.csPDO)
    {
      return 0;
    }


  /* study all PDO stored in the objects dictionary */
  if (offsetObjdict)
    {
      Message pdo;/* = Message_Initializer;*/
      memset(&pdo, 0, sizeof(pdo));
      while (offsetObjdict <= lastIndex)
        {
          switch (status)
            {
            case state3:
              if ( /* bSubCount always 5 with objdictedit -> check disabled */
                   /*d->objdict[offsetObjdict].bSubCount < 5 ||*/
                   /* check if TPDO is not valid */
                   *(UNS32 *) d->objdict[offsetObjdict].pSubindex[1].
                   pObject & 0x80000000)
                {
                  MSG_WAR (0x3960, "Not a valid PDO ", 0x1800 + pdoNum);
                  /*Go next TPDO */
                  status = state11;
                  break;
                }
              /* get the PDO transmission type */
              pTransmissionType =
                (UNS8 *) d->objdict[offsetObjdict].pSubindex[2].pObject;
              MSG_WAR (0x3962, "Reading PDO at index : ", 0x1800 + pdoNum);

              /* check if transmission type is SYNCRONOUS */
              /* message transmited every n SYNC with n=TransmissionType */
              if (isSyncEvent &&
                  (*pTransmissionType >= TRANS_SYNC_MIN) &&
                  (*pTransmissionType <= TRANS_SYNC_MAX) &&
                  (++d->PDO_status[pdoNum].transmit_type_parameter ==
                   *pTransmissionType))
                {
                  /*Reset count of SYNC */
                  d->PDO_status[pdoNum].transmit_type_parameter = 0;
                  MSG_WAR (0x3964, "  PDO is on SYNCHRO. Trans type : ",
                           *pTransmissionType);
                  memset(&pdo, 0, sizeof(pdo));
                  /*{
                    Message msg_init = Message_Initializer;
                    pdo = msg_init;
                  }*/
                  if (buildPDO (d, pdoNum, &pdo))
                    {
                      MSG_ERR (0x1906, " Couldn't build TPDO number : ",
                               pdoNum);
                      status = state11;
                      break;
                    }
                  status = state5;
                  /* If transmission RTR, with data sampled on SYNC */
                }
              else if (isSyncEvent && (*pTransmissionType == TRANS_RTR_SYNC))
                {
                  if (buildPDO
                      (d, pdoNum, &d->PDO_status[pdoNum].last_message))
                    {
                      MSG_ERR (0x1966, " Couldn't build TPDO number : ",
                               pdoNum);
                      d->PDO_status[pdoNum].transmit_type_parameter &=
                        ~PDO_RTR_SYNC_READY;
                    }
                  else
                    {
                      d->PDO_status[pdoNum].transmit_type_parameter |=
                        PDO_RTR_SYNC_READY;
                    }
                  status = state11;
                  break;
                  /* If transmission on Event and not inhibited, check for changes */
                }
              else
                if ( (isSyncEvent && (*pTransmissionType == TRANS_SYNC_ACYCLIC))
                     ||
                     (!isSyncEvent && (*pTransmissionType == TRANS_EVENT_PROFILE || *pTransmissionType == TRANS_EVENT_SPECIFIC)
                       && !(d->PDO_status[pdoNum].transmit_type_parameter & PDO_INHIBITED)))
                {
                  sendOnePDOevent(d, pdoNum);
                  status = state11;
                }
              else
                {
                  MSG_WAR (0x306C,
                           "  PDO is not on EVENT or synchro or not at this SYNC. Trans type : ",
                           *pTransmissionType);
                  status = state11;
                }
              break;
            case state5:       /*Send the pdo */
              sendPdo(d, pdoNum, &pdo);
              status = state11;
              break;
            case state11:      /*Go to next TPDO */
              pdoNum++;
              offsetObjdict++;
              offsetObjdictMap++;
              MSG_WAR (0x3970, "next pdo index : ", pdoNum);
              status = state3;
              break;

            default:
              MSG_ERR (0x1972, "Unknown state has been reached :", status);
              return 0xFF;
            }                   /* end switch case */

        }                       /* end while */
    }
  return 0;
}

/*!
**
**
** @param d
** @param OD_entry
** @param bSubindex
** @return always 0
**/

UNS32 TPDO_Communication_Parameter_Callback (CO_Data * d,
                                       const indextable * OD_entry,
                                       UNS8 bSubindex)
{
  /* If PDO are actives */
  if (d->CurrentCommunicationState.csPDO)
    switch (bSubindex)
      {
      case 2:                  /* Changed transmition type */
      case 3:                  /* Changed inhibit time */
      case 5:                  /* Changed event time */
        {
          const indextable *TPDO_com = d->objdict + d->firstIndex->PDO_TRS;
          UNS8 numPdo = (UNS8) (OD_entry - TPDO_com);    /* number of the actual processed pdo-nr. */

          /* Zap all timers and inhibit flag */
          d->PDO_status[numPdo].event_timer =
            DelAlarm (d->PDO_status[numPdo].event_timer);
          d->PDO_status[numPdo].inhibit_timer =
            DelAlarm (d->PDO_status[numPdo].inhibit_timer);
          d->PDO_status[numPdo].transmit_type_parameter = 0;
          /* Call  PDOEventTimerAlarm for this TPDO, this will trigger emission et reset timers */
          PDOEventTimerAlarm (d, numPdo);
          return 0;
        }

      default:                 /* other subindex are ignored */
        break;
      }
  return 0;
}

void PDOInit (CO_Data * d)
{
  /* For each TPDO mapping parameters */
  UNS16 pdoIndex = 0x1800;      /* OD index of TDPO */

  UNS16 offsetObjdict = d->firstIndex->PDO_TRS;
  UNS16 lastIndex = d->lastIndex->PDO_TRS;
  if (offsetObjdict)
    while (offsetObjdict <= lastIndex)
      {
        /* Assign callbacks to sensible TPDO mapping subindexes */
        UNS32 errorCode;
        ODCallback_t *CallbackList;
        /* Find callback list */
        scanIndexOD (d, pdoIndex, &errorCode, &CallbackList);
        if (errorCode == OD_SUCCESSFUL && CallbackList)
          {
            /*Assign callbacks to corresponding subindex */
            /* Transmission type */
            CallbackList[2] = &TPDO_Communication_Parameter_Callback;
            /* Inhibit time */
            CallbackList[3] = &TPDO_Communication_Parameter_Callback;
            /* Event timer */
            CallbackList[5] = &TPDO_Communication_Parameter_Callback;
          }
        pdoIndex++;
        offsetObjdict++;
      }

  /* Trigger a non-sync event */
  _sendPDOevent (d, 0);
}

void
PDOStop (CO_Data * d)
{
  /* For each TPDO mapping parameters */
  UNS8 pdoNum = 0x00;           /* number of the actual processed pdo-nr. */
  UNS16 offsetObjdict = d->firstIndex->PDO_TRS;
  UNS16 lastIndex = d->lastIndex->PDO_TRS;
  if (offsetObjdict)
    while (offsetObjdict <= lastIndex)
      {
        /* Delete TPDO timers */
        d->PDO_status[pdoNum].event_timer =
          DelAlarm (d->PDO_status[pdoNum].event_timer);
        d->PDO_status[pdoNum].inhibit_timer =
          DelAlarm (d->PDO_status[pdoNum].inhibit_timer);
        /* Reset transmit type parameter */
        d->PDO_status[pdoNum].transmit_type_parameter = 0;
        d->PDO_status[pdoNum].last_message.cob_id = 0;
        pdoNum++;
        offsetObjdict++;
      }
}


   Copyright (C): Edouard TISSERANT and Francis DUPIN

   See COPYING file for copyrights details.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
/*!
** @file   sdo.c
** @author Edouard TISSERANT and Francis DUPIN
** @date   Tue Jun  5 09:32:32 2007
**
** @brief
**
**
*/

/* #define DEBUG_WAR_CONSOLE_ON */
/* #define DEBUG_ERR_CONSOLE_ON */

#include <stdlib.h>

#include "canfestival.h"
#include "sysdep.h"

/* Uncomment if your compiler does not support inline functions */
#define NO_INLINE

#ifdef NO_INLINE
#define INLINE
#else
#define INLINE inline
#endif

/*Internals prototypes*/

UNS8 GetSDOClientFromNodeId( CO_Data* d, UNS8 nodeId );

/*!
** Called by writeNetworkDict
**
** @param d
** @param nodeId
** @param index
** @param subIndex
** @param count
** @param dataType
** @param data
** @param Callback
** @param endianize
**
** @return
**/
INLINE UNS8 _writeNetworkDict (CO_Data* d, UNS8 nodeId, UNS16 index,
                UNS8 subIndex, UNS32 count, UNS8 dataType, void *data, SDOCallback_t Callback, UNS8 endianize, UNS8 useBlockMode);

/*!
** Called by readNetworkDict
**
** @param d
** @param nodeId
** @param index
** @param subIndex
** @param dataType
** @param Callback
**
** @return
**/
INLINE UNS8 _readNetworkDict (CO_Data* d, UNS8 nodeId, UNS16 index, UNS8 subIndex,
                UNS8 dataType, SDOCallback_t Callback, UNS8 useBlockMode);


/***************************************************************************/
/* SDO (un)packing macros */

/** Returns the command specifier (cs, ccs, scs) from the first byte of the SDO
*/
#define getSDOcs(byte) (byte >> 5)

/** Returns the number of bytes without data from the first byte of the SDO. Coded in 2 bits
*/
#define getSDOn2(byte) ((byte >> 2) & 3)

/** Returns the number of bytes without data from the first byte of the SDO. Coded in 3 bits
*/
#define getSDOn3(byte) ((byte >> 1) & 7)

/** Returns the transfer type from the first byte of the SDO
*/
#define getSDOe(byte) ((byte >> 1) & 1)

/** Returns the size indicator from the first byte of the SDO
*/
#define getSDOs(byte) (byte & 1)

/** Returns the indicator of end transmission from the first byte of the SDO
*/
#define getSDOc(byte) (byte & 1)

/** Returns the toggle from the first byte of the SDO
*/
#define getSDOt(byte) ((byte >> 4) & 1)

/** Returns the index from the bytes 1 and 2 of the SDO
*/
#define getSDOindex(byte1, byte2) (((UNS16)byte2 << 8) | ((UNS16)byte1))

/** Returns the subIndex from the byte 3 of the SDO
*/
#define getSDOsubIndex(byte3) (byte3)

/** Returns the subcommand in SDO block transfer
*/
#define getSDOblockSC(byte) (byte & 3)


/*!
**
**
** @param d
** @param id
**/
void SDOTimeoutAlarm(CO_Data* d, UNS32 id)
{
        UNS16 offset;
        UNS8 nodeId;
        /* Get the client->server cobid.*/
        offset = d->firstIndex->SDO_CLT;
        if ((offset == 0) || ((offset+d->transfers[id].CliServNbr) > d->lastIndex->SDO_CLT)) {
                return ;
        }
        nodeId = (UNS8) *((UNS32*) d->objdict[offset+d->transfers[id].CliServNbr].pSubindex[3].pObject);
        MSG_ERR(0x1A01, "SDO timeout. SDO response not received.", 0);
        MSG_WAR(0x2A02, "server node id : ", nodeId);
        MSG_WAR(0x2A02, "         index : ", d->transfers[id].index);
        MSG_WAR(0x2A02, "      subIndex : ", d->transfers[id].subIndex);
        /* Reset timer handler */
        d->transfers[id].timer = TIMER_NONE;
        /*Set aborted state*/
        d->transfers[id].state = SDO_ABORTED_INTERNAL;
        /* Sending a SDO abort */
        sendSDOabort(d, d->transfers[id].whoami, d->transfers[id].CliServNbr,
                        d->transfers[id].index, d->transfers[id].subIndex, SDOABT_TIMED_OUT);
        d->transfers[id].abortCode = SDOABT_TIMED_OUT;
        /* Call the user function to inform of the problem.*/
        if(d->transfers[id].Callback)
                /*If ther is a callback, it is responsible to close SDO transfer (client)*/
                (*d->transfers[id].Callback)(d, nodeId);
        /*Reset the line if (whoami == SDO_SERVER) or the callback did not close the line.
          Otherwise this sdo transfer would never be closed. */
        if(d->transfers[id].abortCode == SDOABT_TIMED_OUT)
                resetSDOline(d, (UNS8)id);
}

#define StopSDO_TIMER(id) \
        MSG_WAR(0x3A05, "StopSDO_TIMER for line : ", line);\
d->transfers[id].timer = DelAlarm(d->transfers[id].timer);

#define StartSDO_TIMER(id) \
        MSG_WAR(0x3A06, "StartSDO_TIMER for line : ", line);\
d->transfers[id].timer = SetAlarm(d,id,&SDOTimeoutAlarm,MS_TO_TIMEVAL(SDO_TIMEOUT_MS),0);

#define RestartSDO_TIMER(id) \
        MSG_WAR(0x3A07, "restartSDO_TIMER for line : ", line);\
if(d->transfers[id].timer != TIMER_NONE) { StopSDO_TIMER(id) StartSDO_TIMER(id) }

/*!
** Reset all sdo buffers
**
** @param d
**/
void resetSDO (CO_Data* d)
{
        UNS8 j;

        /* transfer structure initialization */
        for (j = 0 ; j < SDO_MAX_SIMULTANEOUS_TRANSFERS ; j++)
                resetSDOline(d, j);
}

/*!
**
**
** @param d
** @param line
**
** @return
**/
UNS32 SDOlineToObjdict (CO_Data* d, UNS8 line)
{
        UNS32 size;
        UNS32 errorCode;
        MSG_WAR(0x3A08, "Enter in SDOlineToObjdict ", line);
        /* if SDO initiated with e=0 and s=0 count is null, offset carry effective size*/
        if( d->transfers[line].count == 0)
                d->transfers[line].count = d->transfers[line].offset;
        size = d->transfers[line].count;

#ifdef SDO_DYNAMIC_BUFFER_ALLOCATION
        if (size > SDO_MAX_LENGTH_TRANSFER)
        {
                errorCode = setODentry(d, d->transfers[line].index, d->transfers[line].subIndex,
                                (void *) d->transfers[line].dynamicData, &size, 1);
        }
        else
        {
                errorCode = setODentry(d, d->transfers[line].index, d->transfers[line].subIndex,
                                (void *) d->transfers[line].data, &size, 1);
        }
#else //SDO_DYNAMIC_BUFFER_ALLOCATION
        errorCode = setODentry(d, d->transfers[line].index, d->transfers[line].subIndex,
                        (void *) d->transfers[line].data, &size, 1);
#endif //SDO_DYNAMIC_BUFFER_ALLOCATION

        if (errorCode != OD_SUCCESSFUL)
                return errorCode;
        MSG_WAR(0x3A08, "exit of SDOlineToObjdict ", line);
        return 0;

}

/*!
**
**
** @param d
** @param line
**
** @return
**/
UNS32 objdictToSDOline (CO_Data* d, UNS8 line)
{
    UNS32  size = SDO_MAX_LENGTH_TRANSFER;
        UNS8  dataType;
        UNS32 errorCode;

        MSG_WAR(0x3A05, "objdict->line index : ", d->transfers[line].index);
        MSG_WAR(0x3A06, "  subIndex : ", d->transfers[line].subIndex);

#ifdef SDO_DYNAMIC_BUFFER_ALLOCATION
    /* Try to use the static buffer.                                            */
        errorCode = getODentry(d,         d->transfers[line].index,
                        d->transfers[line].subIndex,
                        (void *)d->transfers[line].data,
                        &size, &dataType, 1);
    if (errorCode == SDOABT_OUT_OF_MEMORY) {
        /* The static buffer is too small, try again using a dynamic buffer.      *
        * 'size' now contains the real size of the requested object.             */
        if (size <= SDO_DYNAMIC_BUFFER_ALLOCATION_SIZE) {
            d->transfers[line].dynamicData = (UNS8 *) malloc(size * sizeof(UNS8));
            if (d->transfers[line].dynamicData != NULL) {
                d->transfers[line].dynamicDataSize = size;
                errorCode = getODentry(d,
                d->transfers[line].index,
                d->transfers[line].subIndex,
                (void *) d->transfers[line].dynamicData,
                &d->transfers[line].dynamicDataSize,
                &dataType,
                1);
            }
        }
    }
#else //SDO_DYNAMIC_BUFFER_ALLOCATION
        errorCode = getODentry(d,         d->transfers[line].index,
                        d->transfers[line].subIndex,
                        (void *)d->transfers[line].data,
                        &size, &dataType, 1);
#endif //SDO_DYNAMIC_BUFFER_ALLOCATION

        if (errorCode != OD_SUCCESSFUL)
                return errorCode;

        d->transfers[line].count = size;
        d->transfers[line].offset = 0;

        return 0;
}

/*!
**
**
** @param d
** @param line
** @param nbBytes
** @param data
**
** @return
**/
UNS8 lineToSDO (CO_Data* d, UNS8 line, UNS32 nbBytes, UNS8* data) {
        UNS8 i;
        UNS32 offset;

#ifndef SDO_DYNAMIC_BUFFER_ALLOCATION
        if ((d->transfers[line].offset + nbBytes) > SDO_MAX_LENGTH_TRANSFER) {
                MSG_ERR(0x1A10,"SDO Size of data too large. Exceed SDO_MAX_LENGTH_TRANSFER", nbBytes);
                return 0xFF;
        }
#endif //SDO_DYNAMIC_BUFFER_ALLOCATION

        if ((d->transfers[line].offset + nbBytes) > d->transfers[line].count) {
                MSG_ERR(0x1A11,"SDO Size of data too large. Exceed count", nbBytes);
                return 0xFF;
        }
        offset = d->transfers[line].offset;
#ifdef SDO_DYNAMIC_BUFFER_ALLOCATION
        if (d->transfers[line].count <= SDO_MAX_LENGTH_TRANSFER)
        {
                for (i = 0 ; i < nbBytes ; i++)
                        * (data + i) = d->transfers[line].data[offset + i];
        }
        else
        {
                if (d->transfers[line].dynamicData == NULL)
                {
                        MSG_ERR(0x1A11,"SDO's dynamic buffer not allocated. Line", line);
                        return 0xFF;
                }
                for (i = 0 ; i < nbBytes ; i++)
                        * (data + i) = d->transfers[line].dynamicData[offset + i];
        }
#else //SDO_DYNAMIC_BUFFER_ALLOCATION
        for (i = 0 ; i < nbBytes ; i++)
                * (data + i) = d->transfers[line].data[offset + i];
#endif //SDO_DYNAMIC_BUFFER_ALLOCATION
        d->transfers[line].offset = d->transfers[line].offset + nbBytes;
        return 0;
}

/*!
**
**
** @param d
** @param line
** @param nbBytes
** @param data
**
** @return
**/
UNS8 SDOtoLine (CO_Data* d, UNS8 line, UNS32 nbBytes, UNS8* data)
{
        UNS8 i;
        UNS32 offset;
#ifndef SDO_DYNAMIC_BUFFER_ALLOCATION
        if ((d->transfers[line].offset + nbBytes) > SDO_MAX_LENGTH_TRANSFER) {
                MSG_ERR(0x1A15,"SDO Size of data too large. Exceed SDO_MAX_LENGTH_TRANSFER", nbBytes);
                return 0xFF;
        }
#endif //SDO_DYNAMIC_BUFFER_ALLOCATION

        offset = d->transfers[line].offset;
#ifdef SDO_DYNAMIC_BUFFER_ALLOCATION
        {
                UNS8* lineData = d->transfers[line].data;
                if ((d->transfers[line].offset + nbBytes) > SDO_MAX_LENGTH_TRANSFER) {
                        if (d->transfers[line].dynamicData == NULL) {
                                d->transfers[line].dynamicData = (UNS8*) malloc(SDO_DYNAMIC_BUFFER_ALLOCATION_SIZE);
                                d->transfers[line].dynamicDataSize = SDO_DYNAMIC_BUFFER_ALLOCATION_SIZE;

                                if (d->transfers[line].dynamicData == NULL) {
                                        MSG_ERR(0x1A15,"SDO allocating dynamic buffer failed, size", SDO_DYNAMIC_BUFFER_ALLOCATION_SIZE);
                                        return 0xFF;
                                }
                                //Copy present data
                                memcpy(d->transfers[line].dynamicData, d->transfers[line].data, offset);
                        }
                        else if ((d->transfers[line].offset + nbBytes) > d->transfers[line].dynamicDataSize)
                        {
                                UNS8* newDynamicBuffer = (UNS8*) realloc(d->transfers[line].dynamicData, d->transfers[line].dynamicDataSize + SDO_DYNAMIC_BUFFER_ALLOCATION_SIZE);
                                if (newDynamicBuffer == NULL) {
                                        MSG_ERR(0x1A15,"SDO reallocating dynamic buffer failed, size", d->transfers[line].dynamicDataSize + SDO_DYNAMIC_BUFFER_ALLOCATION_SIZE);
                                        return 0xFF;
                                }
                                d->transfers[line].dynamicData = newDynamicBuffer;
                                d->transfers[line].dynamicDataSize += SDO_DYNAMIC_BUFFER_ALLOCATION_SIZE;
                        }
                        lineData = d->transfers[line].dynamicData;
                }

                for (i = 0 ; i < nbBytes ; i++)
                        lineData[offset + i] = * (data + i);
        }
#else //SDO_DYNAMIC_BUFFER_ALLOCATION
        for (i = 0 ; i < nbBytes ; i++)
                d->transfers[line].data[offset + i] = * (data + i);
#endif //SDO_DYNAMIC_BUFFER_ALLOCATION

        d->transfers[line].offset = d->transfers[line].offset + nbBytes;
        return 0;
}

/*!
**
**
** @param d
** @param CliServNbr
** @param whoami
** @param index
** @param subIndex
** @param abortCode
**
** @return
**/
UNS8 failedSDO (CO_Data* d, UNS8 CliServNbr, UNS8 whoami, UNS16 index,
                UNS8 subIndex, UNS32 abortCode)
{
        UNS8 err;
        UNS8 line;
        err = getSDOlineOnUse( d, CliServNbr, whoami, &line );
        if (!err) /* If a line on use have been found.*/
                MSG_WAR(0x3A20, "FailedSDO : line found : ", line);
        if ((! err) && (whoami == SDO_SERVER)) {
                resetSDOline( d, line );
                MSG_WAR(0x3A21, "FailedSDO : line released : ", line);
        }
        if ((! err) && (whoami == SDO_CLIENT)) {
                StopSDO_TIMER(line);
                d->transfers[line].state = SDO_ABORTED_INTERNAL;
                d->transfers[line].abortCode = abortCode;
        }
        MSG_WAR(0x3A22, "Sending SDO abort ", 0);
        err = sendSDOabort(d, whoami, CliServNbr, index, subIndex, abortCode);
        if (err) {
                MSG_WAR(0x3A23, "Unable to send the SDO abort", 0);
                return 0xFF;
        }
        return 0;
}

/*!
**
**
** @param d
** @param line
**/
void resetSDOline ( CO_Data* d, UNS8 line )
{
        UNS32 i;
        MSG_WAR(0x3A25, "reset SDO line nb : ", line);
        initSDOline(d, line, 0, 0, 0, SDO_RESET);
        for (i = 0 ; i < SDO_MAX_LENGTH_TRANSFER ; i++)
                d->transfers[line].data = 0;
        d->transfers[line].whoami = 0;
        d->transfers[line].abortCode = 0;
}

/*!
**
**
** @param d
** @param line
** @param CliServNbr
** @param index
** @param subIndex
** @param state
**
** @return
**/
UNS8 initSDOline (CO_Data* d, UNS8 line, UNS8 CliServNbr, UNS16 index, UNS8 subIndex, UNS8 state)
{
        MSG_WAR(0x3A25, "init SDO line nb : ", line);
        if (state == SDO_DOWNLOAD_IN_PROGRESS       || state == SDO_UPLOAD_IN_PROGRESS ||
        state == SDO_BLOCK_DOWNLOAD_IN_PROGRESS || state == SDO_BLOCK_UPLOAD_IN_PROGRESS){
                StartSDO_TIMER(line)
        }else{
                StopSDO_TIMER(line)
        }
        d->transfers[line].CliServNbr = CliServNbr;
        d->transfers[line].index = index;
        d->transfers[line].subIndex = subIndex;
        d->transfers[line].state = state;
        d->transfers[line].toggle = 0;
        d->transfers[line].count = 0;
        d->transfers[line].offset = 0;
    d->transfers[line].peerCRCsupport = 0;
    d->transfers[line].blksize = 0;
    d->transfers[line].ackseq = 0;
    d->transfers[line].objsize = 0;
    d->transfers[line].lastblockoffset = 0;
    d->transfers[line].seqno = 0;
    d->transfers[line].endfield = 0;
    d->transfers[line].rxstep = RXSTEP_INIT;
        d->transfers[line].dataType = 0;
        d->transfers[line].Callback = NULL;
#ifdef SDO_DYNAMIC_BUFFER_ALLOCATION
        free(d->transfers[line].dynamicData);
        d->transfers[line].dynamicData = 0;
        d->transfers[line].dynamicDataSize = 0;
#endif //SDO_DYNAMIC_BUFFER_ALLOCATION
        return 0;
}

/*!
**
**
** @param d
** @param whoami
** @param line
**
** @return
**/
UNS8 getSDOfreeLine ( CO_Data* d, UNS8 whoami, UNS8 *line )
{

        UNS8 i;

        for (i = 0 ; i < SDO_MAX_SIMULTANEOUS_TRANSFERS ; i++){
                if ( d->transfers.state == SDO_RESET ) {
                        *line = i;
                        d->transfers.whoami = whoami;
                        return 0;
                } /* end if */
        } /* end for */
        MSG_ERR(0x1A25, "Too many SDO in progress. Aborted.", i);
        return 0xFF;
}

/*!
**
**
** @param d
** @param CliServNbr
** @param whoami
** @param line
**
** @return
**/
UNS8 getSDOlineOnUse (CO_Data* d, UNS8 CliServNbr, UNS8 whoami, UNS8 *line)
{

        UNS8 i;

        for (i = 0 ; i < SDO_MAX_SIMULTANEOUS_TRANSFERS ; i++){
                if ( (d->transfers.state != SDO_RESET) &&
                                (d->transfers.state != SDO_ABORTED_INTERNAL) &&
                                (d->transfers.CliServNbr == CliServNbr) &&
                                (d->transfers.whoami == whoami) ) {
                        if (line) *line = i;
                        return 0;
                }
        }
        return 0xFF;
}

/*!
**
**
** @param d
** @param CliServNbr
** @param whoami
** @param line
**
** @return
**/
UNS8 getSDOlineToClose (CO_Data* d, UNS8 CliServNbr, UNS8 whoami, UNS8 *line)
{

        UNS8 i;

        for (i = 0 ; i < SDO_MAX_SIMULTANEOUS_TRANSFERS ; i++){
                if ( (d->transfers.state != SDO_RESET) &&
                                (d->transfers.CliServNbr == CliServNbr) &&
                                (d->transfers.whoami == whoami) ) {
                        if (line) *line = i;
                        return 0;
                }
        }
        return 0xFF;
}


/*!
**
**
** @param d
** @param CliServNbr
** @param whoami
**
** @return
**/
UNS8 closeSDOtransfer (CO_Data* d, UNS8 nodeId, UNS8 whoami)
{
        UNS8 err;
        UNS8 line;
    UNS8 CliNbr;
        /* First let's find the corresponding SDO client in our OD  */
        CliNbr = GetSDOClientFromNodeId(d, nodeId);
        if(CliNbr >= 0xFE)
                return SDO_ABORTED_INTERNAL;
    err = getSDOlineToClose(d, CliNbr, whoami, &line);
        if (err) {
                MSG_WAR(0x2A30, "No SDO communication to close", 0);
                return 0xFF;
        }
        resetSDOline(d, line);
        return 0;
}

/*!
**
**
** @param d
** @param line
** @param nbBytes
**
** @return
**/
UNS8 getSDOlineRestBytes (CO_Data* d, UNS8 line, UNS32 * nbBytes)
{
        /* SDO initiated with e=0 and s=0 have count set to null */
        if (d->transfers[line].count == 0)
                * nbBytes = 0;
        else
                * nbBytes = d->transfers[line].count - d->transfers[line].offset;
        return 0;
}

/*!
**
**
** @param d
** @param line
** @param nbBytes
**
** @return
**/
UNS8 setSDOlineRestBytes (CO_Data* d, UNS8 line, UNS32 nbBytes)
{
#ifndef SDO_DYNAMIC_BUFFER_ALLOCATION
        if (nbBytes > SDO_MAX_LENGTH_TRANSFER) {
                MSG_ERR(0x1A35,"SDO Size of data too large. Exceed SDO_MAX_LENGTH_TRANSFER", nbBytes);
                return 0xFF;
        }
#endif //SDO_DYNAMIC_BUFFER_ALLOCATION

        d->transfers[line].count = nbBytes;
        return 0;
}

/*!
**
**
** @param d
** @param whoami
** @param CliServNbr
** @param pData
**
** @return
**/
UNS8 sendSDO (CO_Data* d, UNS8 whoami, UNS8 CliServNbr, UNS8 *pData)
{
        UNS16 offset;
        UNS8 i;
        Message m;

        MSG_WAR(0x3A38, "sendSDO",0);
        if( !((d->nodeState == Operational) ||  (d->nodeState == Pre_operational ))) {
                MSG_WAR(0x2A39, "unable to send the SDO (not in op or pre-op mode", d->nodeState);
                return 0xFF;
        }

        /*get the server->client cobid*/
        if ( whoami == SDO_SERVER )        {
                offset = d->firstIndex->SDO_SVR;
                if ((offset == 0) || ((offset+CliServNbr) > d->lastIndex->SDO_SVR)) {
                        MSG_ERR(0x1A42, "SendSDO : SDO server not found", 0);
                        return 0xFF;
                }
                m.cob_id = (UNS16) *((UNS32*) d->objdict[offset+CliServNbr].pSubindex[2].pObject);
                MSG_WAR(0x3A41, "I am server Tx cobId : ", m.cob_id);
        }
        else {                        /*case client*/
                /* Get the client->server cobid.*/
                offset = d->firstIndex->SDO_CLT;
                if ((offset == 0) || ((offset+CliServNbr) > d->lastIndex->SDO_CLT)) {
                        MSG_ERR(0x1A42, "SendSDO : SDO client not found", 0);
                        return 0xFF;
                }
                m.cob_id = (UNS16) *((UNS32*) d->objdict[offset+CliServNbr].pSubindex[1].pObject);
                MSG_WAR(0x3A41, "I am client Tx cobId : ", m.cob_id);
        }
        /* message copy for sending */
        m.rtr = NOT_A_REQUEST;
        /* the length of SDO must be 8 */
        m.len = 8;
        for (i = 0 ; i < 8 ; i++) {
                m.data =  pData;
        }
        return canSend(d->canHandle,&m);
}

/*!
**
**
** @param d
** @param whoami
** @param index
** @param subIndex
** @param abortCode
**
** @return
**/
UNS8 sendSDOabort (CO_Data* d, UNS8 whoami, UNS8 CliServNbr, UNS16 index, UNS8 subIndex, UNS32 abortCode)
{
        UNS8 data[8];
        UNS8 ret;

        MSG_WAR(0x2A50,"Sending SDO abort ", abortCode);
        data[0] = 0x80;
        /* Index */
        data[1] = index & 0xFF; /* LSB */
        data[2] = (index >> 8) & 0xFF; /* MSB */
        /* Subindex */
        data[3] = subIndex;
        /* Data */
        data[4] = (UNS8)(abortCode & 0xFF);
        data[5] = (UNS8)((abortCode >> 8) & 0xFF);
        data[6] = (UNS8)((abortCode >> 16) & 0xFF);
        data[7] = (UNS8)((abortCode >> 24) & 0xFF);
        ret = sendSDO(d, whoami, CliServNbr, data);

        return ret;
}

/*!
**
**
** @param d
** @param m
**
** @return
**/
UNS8 proceedSDO (CO_Data* d, Message *m)
{
        UNS8 err;
        UNS8 cs;
        UNS8 line;
        UNS32 nbBytes;                 /* received or to be transmited. */
        UNS8 nodeId = 0;          /* The node Id of the server if client otherwise unused */
        UNS8 CliServNbr;
        UNS8 whoami = SDO_UNKNOWN;  /* SDO_SERVER or SDO_CLIENT.*/
        UNS32 errorCode; /* while reading or writing in the local object dictionary.*/
        UNS8 data[8];    /* data for SDO to transmit */
        UNS16 index;
        UNS8 subIndex;
        UNS32 abortCode;
        UNS32 i;
        UNS8        j;
        UNS32 *pCobId = NULL;
        UNS16 offset;
        UNS16 lastIndex;
        UNS8 SubCommand;        /* Block transfer only */
    UNS8 SeqNo;         /* Sequence number in block transfer */
    UNS8 AckSeq;        /* Sequence number of last segment that was received successfully */
        UNS8 NbBytesNoData; /* Number of bytes that do not contain data in last segment of block transfer */

        MSG_WAR(0x3A60, "proceedSDO ", 0);
        whoami = SDO_UNKNOWN;
        /* Looking for the cobId in the object dictionary. */
        /* Am-I a server ? */
        offset = d->firstIndex->SDO_SVR;
        lastIndex = d->lastIndex->SDO_SVR;
        j = 0;
        if(offset) while (offset <= lastIndex) {
                if (d->objdict[offset].bSubCount <= 1) {
                        MSG_ERR(0x1A61, "Subindex 1  not found at index ", 0x1200 + j);
                        return 0xFF;
                }
                /* Looking for the cobid received. */
                pCobId = (UNS32*) d->objdict[offset].pSubindex[1].pObject;
                if ( *pCobId == UNS16_LE(m->cob_id) ) {
                        whoami = SDO_SERVER;
                        MSG_WAR(0x3A62, "proceedSDO. I am server. index : ", 0x1200 + j);
                        /* Defining Server number = index minus 0x1200 where the cobid received is defined. */
                        CliServNbr = j;
                        break;
                }
                j++;
                offset++;
        } /* end while */
        if (whoami == SDO_UNKNOWN) {
                /* Am-I client ? */
                offset = d->firstIndex->SDO_CLT;
                lastIndex = d->lastIndex->SDO_CLT;
                j = 0;
                if(offset) while (offset <= lastIndex) {
                        if (d->objdict[offset].bSubCount <= 3) {
                                MSG_ERR(0x1A63, "Subindex 3  not found at index ", 0x1280 + j);
                                return 0xFF;
                        }
                        /* Looking for the cobid received. */
                        pCobId = (UNS32*) d->objdict[offset].pSubindex[2].pObject;
                        if (*pCobId == UNS16_LE(m->cob_id) ) {
                                whoami = SDO_CLIENT;
                                MSG_WAR(0x3A64, "proceedSDO. I am client index : ", 0x1280 + j);
                                /* Defining Client number = index minus 0x1280 where the cobid received is defined. */
                                CliServNbr = j;
                                /* Reading the server node ID, if client it is mandatory in the OD */
                                nodeId = *((UNS8*) d->objdict[offset].pSubindex[3].pObject);
                                break;
                        }
                        j++;
                        offset++;
                } /* end while */
        }
        if (whoami == SDO_UNKNOWN) {
                return 0xFF;/* This SDO was not for us ! */
        }

        /* Test if the size of the SDO is ok */
        if ( (*m).len != 8) {
                MSG_ERR(0x1A67, "Error size SDO", 0);
                failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_GENERAL_ERROR);
                return 0xFF;
        }

        if (whoami == SDO_CLIENT) {
                MSG_WAR(0x3A68, "I am CLIENT number ", CliServNbr);
        }
        else {
                MSG_WAR(0x3A69, "I am SERVER number ", CliServNbr);
        }

        /* Look for an SDO transfer already initiated. */
        err = getSDOlineOnUse( d, CliServNbr, whoami, &line );

        /* Let's find cs value, first it is set as "not valid" */
        cs = 0xFF;
        /* Special cases for block transfer : in frames with segment data cs is not spécified */
           if (!err) {
                if ((whoami == SDO_SERVER) && (d->transfers[line].state == SDO_BLOCK_DOWNLOAD_IN_PROGRESS) ||
                        (whoami == SDO_CLIENT) && (d->transfers[line].state == SDO_BLOCK_UPLOAD_IN_PROGRESS)) {               
                        if(m->data[0] == 0x80)        /* If first byte is 0x80 it is an abort frame (seqno = 0 not allowed) */
                                cs = 4;
                        else
                                cs = 6;
                }
        }
        /* Other cases : cs is specified */
        if (cs == 0xFF)
                cs = getSDOcs(m->data[0]);

        /* Testing the command specifier */
        /* Allowed : cs = 0, 1, 2, 3, 4, 5, 6 */
        /* cs = other : Not allowed -> abort. */
        switch (cs) {

                case 0:
                        /* I am SERVER */
                        if (whoami == SDO_SERVER) {
                                /* Receiving a download segment data : an SDO transfer should have been yet initiated. */
                                if (!err)
                                        err = d->transfers[line].state != SDO_DOWNLOAD_IN_PROGRESS;
                                if (err) {
                                        MSG_ERR(0x1A70, "SDO error : Received download segment for unstarted trans. index 0x1200 + ",
                                                        CliServNbr);
                                        failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
                                        return 0xFF;
                                }
                                /* Reset the wathdog */
                                RestartSDO_TIMER(line)
                                        MSG_WAR(0x3A71, "Received SDO download segment defined at index 0x1200 + ", CliServNbr);
                                index = d->transfers[line].index;
                                subIndex = d->transfers[line].subIndex;
                                /* Toggle test. */
                                if (d->transfers[line].toggle != getSDOt(m->data[0])) {
                                        MSG_ERR(0x1A72, "SDO error : Toggle error : ", getSDOt(m->data[0]));
                                        failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_TOGGLE_NOT_ALTERNED);
                                        return 0xFF;
                                }
                                /* Nb of data to be downloaded */
                                nbBytes = 7 - getSDOn3(m->data[0]);
                                /* Store the data in the transfer structure. */
                                err = SDOtoLine(d, line, nbBytes, (*m).data + 1);
                                if (err) {
                                        failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                        return 0xFF;
                                }
                                /* Sending the SDO response, CS = 1 */
                                data[0] = (1 << 5) | (d->transfers[line].toggle << 4);
                                for (i = 1 ; i < 8 ; i++)
                                        data = 0;
                                MSG_WAR(0x3A73, "SDO. Send response to download request defined at index 0x1200 + ", CliServNbr);
                                sendSDO(d, whoami, CliServNbr, data);
                                /* Inverting the toggle for the next segment. */
                                d->transfers[line].toggle = ! d->transfers[line].toggle & 1;
                                /* If it was the last segment, */
                                if (getSDOc(m->data[0])) {
                                        /* Transfering line data to object dictionary. */
                                        /* The code does not use the "d" of initiate frame. So it is safe if e=s=0 */
                                        errorCode = SDOlineToObjdict(d, line);
                                        if (errorCode) {
                                                MSG_ERR(0x1A54, "SDO error : Unable to copy the data in the object dictionary", 0);
                                                failedSDO(d, CliServNbr, whoami, index, subIndex, errorCode);
                                                return 0xFF;
                                        }
                                        /* Release of the line */
                                        resetSDOline(d, line);
                                        MSG_WAR(0x3A74, "SDO. End of download defined at index 0x1200 + ", CliServNbr);
                                }
                        } /* end if SERVER */
                        else { /* if CLIENT */
                                /* I am CLIENT */
                                /* It is a request for a previous upload segment. We should find a line opened for this.*/
                                if (!err)
                                        err = d->transfers[line].state != SDO_UPLOAD_IN_PROGRESS;
                                if (err) {
                                        MSG_ERR(0x1A75, "SDO error : Received segment response for unknown trans. from nodeId", nodeId);
                                        failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
                                        return 0xFF;
                                }
                                /* Reset the wathdog */
                                RestartSDO_TIMER(line)
                                        index = d->transfers[line].index;
                                subIndex = d->transfers[line].subIndex;
                                /* test of the toggle; */
                                if (d->transfers[line].toggle != getSDOt(m->data[0])) {
                                        MSG_ERR(0x1A76, "SDO error : Received segment response Toggle error. from nodeId", nodeId);
                                        failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_TOGGLE_NOT_ALTERNED);
                                        return 0xFF;
                                }
                                /* nb of data to be uploaded */
                                nbBytes = 7 - getSDOn3(m->data[0]);
                                /* Storing the data in the line structure. */
                                err = SDOtoLine(d, line, nbBytes, (*m).data + 1);
                                if (err) {
                                        failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                        return 0xFF;
                                }
                                /* Inverting the toggle for the next segment. */
                                d->transfers[line].toggle = ! d->transfers[line].toggle & 1;
                                /* If it was the last segment,*/
                                if ( getSDOc(m->data[0])) {
                                        /* Put in state finished */
                                        /* The code is safe for the case e=s=0 in initiate frame. */
                                        StopSDO_TIMER(line)
                                                d->transfers[line].state = SDO_FINISHED;
                                        if(d->transfers[line].Callback) (*d->transfers[line].Callback)(d,nodeId);

                                        MSG_WAR(0x3A77, "SDO. End of upload from node : ", nodeId);
                                }
                                else { /* more segments to receive */
                                        /* Sending the request for the next segment. */
                                        data[0] = (3 << 5) | (d->transfers[line].toggle << 4);
                                        for (i = 1 ; i < 8 ; i++)
                                                data = 0;
                                        sendSDO(d, whoami, CliServNbr, data);
                                        MSG_WAR(0x3A78, "SDO send upload segment request to nodeId", nodeId);
                                }
                        } /* End if CLIENT */
                        break;

                case 1:
                        /* I am SERVER */
                        /* Receive of an initiate download */
                        if (whoami == SDO_SERVER) {
                                index = getSDOindex(m->data[1],m->data[2]);
                                subIndex = getSDOsubIndex(m->data[3]);
                                MSG_WAR(0x3A79, "Received SDO Initiate Download (to store data) defined at index 0x1200 + ",
                                                CliServNbr);
                                MSG_WAR(0x3A80, "Writing at index : ", index);
                                MSG_WAR(0x3A80, "Writing at subIndex : ", subIndex);

                                /* Search if a SDO transfer have been yet initiated */
                                if (! err) {
                                        MSG_ERR(0x1A81, "SDO error : Transmission yet started.", 0);
                                        failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_LOCAL_CTRL_ERROR);
                                        return 0xFF;
                                }
                                /* No line on use. Great ! */
                                /* Try to open a new line. */
                                err = getSDOfreeLine( d, whoami, &line );
                                if (err) {
                                        MSG_ERR(0x1A82, "SDO error : No line free, too many SDO in progress. Aborted.", 0);
                                        failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_LOCAL_CTRL_ERROR);
                                        return 0xFF;
                                }
                                initSDOline(d, line, CliServNbr, index, subIndex, SDO_DOWNLOAD_IN_PROGRESS);

                                if (getSDOe(m->data[0])) { /* If SDO expedited */
                                        /* nb of data to be downloaded */
                                        nbBytes = 4 - getSDOn2(m->data[0]);
                                        /* Storing the data in the line structure. */
                                        d->transfers[line].count = nbBytes;
                                        err = SDOtoLine(d, line, nbBytes, (*m).data + 4);

                                        if (err) {
                                                failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                                return 0xFF;
                                        }

                                        /* SDO expedited -> transfer finished. Data can be stored in the dictionary. */
                                        /*The line will be reseted when it is downloading in the dictionary. */
                                        MSG_WAR(0x3A83, "SDO Initiate Download is an expedited transfer. Finished. ", 0);
                                        /* Transfering line data to object dictionary. */
                                        errorCode = SDOlineToObjdict(d, line);
                                        if (errorCode) {
                                                MSG_ERR(0x1A84, "SDO error : Unable to copy the data in the object dictionary", 0);
                                                failedSDO(d, CliServNbr, whoami, index, subIndex, errorCode);
                                                return 0xFF;
                                        }
                                        /* Release of the line. */
                                        resetSDOline(d, line);
                                }
                                else {/* So, if it is not an expedited transfer */
                                        if (getSDOs(m->data[0])) {
                                                nbBytes = (m->data[4]) + ((UNS32)(m->data[5])<<8) + ((UNS32)(m->data[6])<<16) + ((UNS32)(m->data[7])<<24);
                                                err = setSDOlineRestBytes(d, line, nbBytes);
                                                if (err) {
                                                        failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                                        return 0xFF;
                                                }
                                        }
                                }
                                /*Sending a SDO, cs=3*/
                                data[0] = 3 << 5;
                                data[1] = index & 0xFF;        /* LSB */
                                data[2] = (index >> 8) & 0xFF; /* MSB */
                                data[3] = subIndex;
                                for (i = 4 ; i < 8 ; i++)
                                        data = 0;
                                sendSDO(d, whoami, CliServNbr, data);
                        } /* end if I am SERVER */
                        else {
                                /* I am CLIENT */
                                /* It is a response for a previous download segment. We should find a line opened for this. */
                                if (!err)
                                        err = d->transfers[line].state != SDO_DOWNLOAD_IN_PROGRESS;
                                if (err) {
                                        MSG_ERR(0x1A85, "SDO error : Received segment response for unknown trans. from nodeId", nodeId);
                                        failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
                                        return 0xFF;
                                }
                                /* Reset the wathdog */
                                RestartSDO_TIMER(line)
                                        index = d->transfers[line].index;
                                subIndex = d->transfers[line].subIndex;
                                /* test of the toggle; */
                                if (d->transfers[line].toggle != getSDOt(m->data[0])) {
                                        MSG_ERR(0x1A86, "SDO error : Received segment response Toggle error. from nodeId", nodeId);
                                        failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_TOGGLE_NOT_ALTERNED);
                                        return 0xFF;
                                }

                                /* End transmission or downloading next segment. We need to know if it will be the last one. */
                                getSDOlineRestBytes(d, line, &nbBytes);
                                if (nbBytes == 0) {
                                        MSG_WAR(0x3A87, "SDO End download. segment response received. OK. from nodeId", nodeId);
                                        StopSDO_TIMER(line)
                                                d->transfers[line].state = SDO_FINISHED;
                                        if(d->transfers[line].Callback) (*d->transfers[line].Callback)(d,nodeId);
                                        return 0x00;
                                }
                                /* At least one transfer to send.        */
                                if (nbBytes > 7) {
                                        /* several segments to download.*/
                                        /* code to send the next segment. (cs = 0; c = 0) */
                                        d->transfers[line].toggle = ! d->transfers[line].toggle & 1;
                                        data[0] = (d->transfers[line].toggle << 4);
                                        err = lineToSDO(d, line, 7, data + 1);
                                        if (err) {
                                                failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                                return 0xFF;
                                        }
                                }
                                else {
                                        /* Last segment. */
                                        /* code to send the last segment. (cs = 0; c = 1)*/
                                        d->transfers[line].toggle = ! d->transfers[line].toggle & 1;
                                        data[0] = (UNS8)((d->transfers[line].toggle << 4) | ((7 - nbBytes) << 1) | 1);
                                        err = lineToSDO(d, line, nbBytes, data + 1);
                                        if (err) {
                                                failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                                return 0xFF;
                                        }
                                        for (i = nbBytes + 1 ; i < 8 ; i++)
                                                data = 0;
                                }
                                MSG_WAR(0x3A88, "SDO sending download segment to nodeId", nodeId);
                                sendSDO(d, whoami, CliServNbr, data);
                        } /* end if I am a CLIENT */
                        break;

                case 2:
                        /* I am SERVER */
                        /* Receive of an initiate upload.*/
                        if (whoami == SDO_SERVER) {
                                index = getSDOindex(m->data[1],m->data[2]);
                                subIndex = getSDOsubIndex(m->data[3]);
                                MSG_WAR(0x3A89, "Received SDO Initiate upload (to send data) defined at index 0x1200 + ",
                                                CliServNbr);
                                MSG_WAR(0x3A90, "Reading at index : ", index);
                                MSG_WAR(0x3A91, "Reading at subIndex : ", subIndex);
                                /* Search if a SDO transfer have been yet initiated*/
                                if (! err) {
                                        MSG_ERR(0x1A92, "SDO error : Transmission yet started at line : ", line);
                                        MSG_WAR(0x3A93, "Server Nbr = ", CliServNbr);
                                        failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_LOCAL_CTRL_ERROR);
                                        return 0xFF;
                                }
                                /* No line on use. Great !*/
                                /* Try to open a new line.*/
                                err = getSDOfreeLine( d, whoami, &line );
                                if (err) {
                                        MSG_ERR(0x1A71, "SDO error : No line free, too many SDO in progress. Aborted.", 0);
                                        failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_LOCAL_CTRL_ERROR);
                                        return 0xFF;
                                }
                                initSDOline(d, line, CliServNbr, index, subIndex, SDO_UPLOAD_IN_PROGRESS);
                                /* Transfer data from dictionary to the line structure. */
                                errorCode = objdictToSDOline(d, line);

                                if (errorCode) {
                                        MSG_ERR(0x1A94, "SDO error : Unable to copy the data from object dictionary. Err code : ",
                                                        errorCode);
                                        failedSDO(d, CliServNbr, whoami, index, subIndex, errorCode);
                                        return 0xFF;
                                }
                                /* Preparing the response.*/
                                getSDOlineRestBytes(d, line, &nbBytes);        /* Nb bytes to transfer ? */
                                if (nbBytes > 4) {
                                        /* normal transfer. (segmented). */
                                        /* code to send the initiate upload response. (cs = 2) */
                                        data[0] = (2 << 5) | 1;
                                        data[1] = index & 0xFF;        /* LSB */
                                        data[2] = (index >> 8) & 0xFF; /* MSB */
                                        data[3] = subIndex;
                                        data[4] = (UNS8) nbBytes;
                                        data[5] = (UNS8) (nbBytes >> 8);
                                        data[6] = (UNS8) (nbBytes >> 16);
                                        data[7] = (UNS8) (nbBytes >> 24);
                                        MSG_WAR(0x3A95, "SDO. Sending normal upload initiate response defined at index 0x1200 + ", nodeId);
                                        sendSDO(d, whoami, CliServNbr, data);
                                }
                                else {
                                        /* Expedited upload. (cs = 2 ; e = 1) */
                                        data[0] = (UNS8)((2 << 5) | ((4 - nbBytes) << 2) | 3);
                                        data[1] = index & 0xFF;        /* LSB */
                                        data[2] = (index >> 8) & 0xFF; /* MSB */
                                        data[3] = subIndex;
                                        err = lineToSDO(d, line, nbBytes, data + 4);
                                        if (err) {
                                                failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                                return 0xFF;
                                        }
                                        for (i = 4 + nbBytes ; i < 8 ; i++)
                                                data = 0;
                                        MSG_WAR(0x3A96, "SDO. Sending expedited upload initiate response defined at index 0x1200 + ",
                                                        CliServNbr);
                                        sendSDO(d, whoami, CliServNbr, data);
                                        /* Release the line.*/
                                        resetSDOline(d, line);
                                }
                        } /* end if I am SERVER*/
                        else {
                                /* I am CLIENT */
                                /* It is the response for the previous initiate upload request.*/
                                /* We should find a line opened for this. */
                                if (!err)
                                        err = d->transfers[line].state != SDO_UPLOAD_IN_PROGRESS;
                                if (err) {
                                        MSG_ERR(0x1A97, "SDO error : Received response for unknown upload request from nodeId", nodeId);
                                        failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
                                        return 0xFF;
                                }
                                /* Reset the wathdog */
                                RestartSDO_TIMER(line)
                                        index = d->transfers[line].index;
                                subIndex = d->transfers[line].subIndex;

                                if (getSDOe(m->data[0])) { /* If SDO expedited */
                                        /* nb of data to be uploaded */
                                        nbBytes = 4 - getSDOn2(m->data[0]);
                                        /* Storing the data in the line structure. */
                                        err = SDOtoLine(d, line, nbBytes, (*m).data + 4);
                                        if (err) {
                                                failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                                return 0xFF;
                                        }
                                        /* SDO expedited -> transfer finished. data are available via  getReadResultNetworkDict(). */
                                        MSG_WAR(0x3A98, "SDO expedited upload finished. Response received from node : ", nodeId);
                                        StopSDO_TIMER(line)
                                                d->transfers[line].count = nbBytes;
                                        d->transfers[line].state = SDO_FINISHED;
                                        if(d->transfers[line].Callback) (*d->transfers[line].Callback)(d,nodeId);
                                        return 0;
                                }
                                else { /* So, if it is not an expedited transfer */
                                        /* Storing the nb of data to receive. */
                                        if (getSDOs(m->data[0])) {
                                                nbBytes = m->data[4] + ((UNS32)(m->data[5])<<8) + ((UNS32)(m->data[6])<<16) + ((UNS32)(m->data[7])<<24);
                                                err = setSDOlineRestBytes(d, line, nbBytes);
                                                if (err) {
                                                        failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                                        return 0xFF;
                                                }
                                        }
                                        /* Requesting next segment. (cs = 3) */
                                        data[0] = 3 << 5;
                                        for (i = 1 ; i < 8 ; i++)
                                                data = 0;
                                        MSG_WAR(0x3A99, "SDO. Sending upload segment request to node : ", nodeId);
                                        sendSDO(d, whoami, CliServNbr, data);
                                }
                        } /* End if CLIENT */
                        break;

                case 3:
                        /* I am SERVER */
                        if (whoami == SDO_SERVER) {
                                /* Receiving a upload segment. */
                                /* A SDO transfer should have been yet initiated. */
                                if (!err)
                                        err = d->transfers[line].state != SDO_UPLOAD_IN_PROGRESS;
                                if (err) {
                                        MSG_ERR(0x1AA0, "SDO error : Received upload segment for unstarted trans. index 0x1200 + ",
                                                        CliServNbr);
                                        failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
                                        return 0xFF;
                                }
                                /* Reset the wathdog */
                                RestartSDO_TIMER(line)
                                        MSG_WAR(0x3AA1, "Received SDO upload segment defined at index 0x1200 + ", CliServNbr);
                                index = d->transfers[line].index;
                                subIndex = d->transfers[line].subIndex;
                                /* Toggle test.*/
                                if (d->transfers[line].toggle != getSDOt(m->data[0])) {
                                        MSG_ERR(0x1AA2, "SDO error : Toggle error : ", getSDOt(m->data[0]));
                                        failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_TOGGLE_NOT_ALTERNED);
                                        return 0xFF;
                                }
                                /* Uploading next segment. We need to know if it will be the last one. */
                                getSDOlineRestBytes(d, line, &nbBytes);
                                if (nbBytes > 7) {
                                        /* The segment to transfer is not the last one.*/
                                        /* code to send the next segment. (cs = 0; c = 0) */
                                        data[0] = (d->transfers[line].toggle << 4);
                                        err = lineToSDO(d, line, 7, data + 1);
                                        if (err) {
                                                failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                                return 0xFF;
                                        }
                                        /* Inverting the toggle for the next tranfert. */
                                        d->transfers[line].toggle = ! d->transfers[line].toggle & 1;
                                        MSG_WAR(0x3AA3, "SDO. Sending upload segment defined at index 0x1200 + ", CliServNbr);
                                        sendSDO(d, whoami, CliServNbr, data);
                                }
                                else {
                                        /* Last segment. */
                                        /* code to send the last segment. (cs = 0; c = 1) */
                                        data[0] = (UNS8)((d->transfers[line].toggle << 4) | ((7 - nbBytes) << 1) | 1);
                                        err = lineToSDO(d, line, nbBytes, data + 1);
                                        if (err) {
                                                failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                                return 0xFF;
                                        }
                                        for (i = nbBytes + 1 ; i < 8 ; i++)
                                                data = 0;
                                        MSG_WAR(0x3AA4, "SDO. Sending last upload segment defined at index 0x1200 + ", CliServNbr);
                                        sendSDO(d, whoami, CliServNbr, data);
                                        /* Release the line */
                                        resetSDOline(d, line);
                                }
                        } /* end if SERVER*/
                        else {
                                /* I am CLIENT */
                                /* It is the response for the previous initiate download request. */
                                /* We should find a line opened for this. */
                                if (!err)
                                        err = d->transfers[line].state != SDO_DOWNLOAD_IN_PROGRESS;
                                if (err) {
                                        MSG_ERR(0x1AA5, "SDO error : Received response for unknown download request from nodeId", nodeId);
                                        failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
                                        return 0xFF;
                                }
                                /* Reset the watchdog */
                                RestartSDO_TIMER(line)
                                        index = d->transfers[line].index;
                                subIndex = d->transfers[line].subIndex;
                                /* End transmission or requesting  next segment. */
                                getSDOlineRestBytes(d, line, &nbBytes);
                                if (nbBytes == 0) {
                                        MSG_WAR(0x3AA6, "SDO End download expedited. Response received. from nodeId", nodeId);
                                        StopSDO_TIMER(line)
                                                d->transfers[line].state = SDO_FINISHED;
                                        if(d->transfers[line].Callback) (*d->transfers[line].Callback)(d,nodeId);
                                        return 0x00;
                                }
                                if (nbBytes > 7) {
                                        /* more than one request to send */
                                        /* code to send the next segment. (cs = 0; c = 0)        */
                                        data[0] = (d->transfers[line].toggle << 4);
                                        err = lineToSDO(d, line, 7, data + 1);
                                        if (err) {
                                                failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                                return 0xFF;
                                        }
                                }
                                else {
                                        /* Last segment.*/
                                        /* code to send the last segment. (cs = 0; c = 1)        */
                                        data[0] = (UNS8)((d->transfers[line].toggle << 4) | ((7 - nbBytes) << 1) | 1);
                                        err = lineToSDO(d, line, nbBytes, data + 1);
                                        if (err) {
                                                failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                                return 0xFF;
                                        }
                                        for (i = nbBytes + 1 ; i < 8 ; i++)
                                                data = 0;
                                }
                                MSG_WAR(0x3AA7, "SDO sending download segment to nodeId", nodeId);
                                sendSDO(d, whoami, CliServNbr, data);

                        } /* end if I am a CLIENT                */
                        break;

                case 4:
                        abortCode =
                                (UNS32)m->data[4] |
                                ((UNS32)m->data[5] << 8) |
                                ((UNS32)m->data[6] << 16) |
                                ((UNS32)m->data[7] << 24);
                        /* Received SDO abort. */
                        if (whoami == SDO_SERVER) {
                                if (!err) {
                                        resetSDOline( d, line );
                                        MSG_WAR(0x3AA8, "SD0. Received SDO abort. Line released. Code : ", abortCode);
                                }
                                else
                                        MSG_WAR(0x3AA9, "SD0. Received SDO abort. No line found. Code : ", abortCode);
                                /* Tips : The end user has no way to know that the server node has received an abort SDO. */
                                /* Its is ok, I think.*/
                        }
                        else { /* If I am CLIENT */
                                if (!err) {
                                        /* The line *must* be released by the core program. */
                                        StopSDO_TIMER(line)
                                                d->transfers[line].state = SDO_ABORTED_RCV;
                                        d->transfers[line].abortCode = abortCode;
                                        MSG_WAR(0x3AB0, "SD0. Received SDO abort. Line state ABORTED. Code : ", abortCode);
                                        if(d->transfers[line].Callback) (*d->transfers[line].Callback)(d,nodeId);
                                }
                                else
                                        MSG_WAR(0x3AB1, "SD0. Received SDO abort. No line found. Code : ", abortCode);
                        }
                        break;
                case 5: /* Command specifier for data transmission - the client or server is the data producer */
                        SubCommand = getSDOblockSC(m->data[0]);
                        if (whoami == SDO_SERVER) { /* Server block upload */
                                if (SubCommand == SDO_BCS_INITIATE_UPLOAD_REQUEST) {
                                    index = getSDOindex(m->data[1],m->data[2]);
                                    subIndex = getSDOsubIndex(m->data[3]);
                                    MSG_WAR(0x3AB2, "Received SDO Initiate block upload defined at index 0x1200 + ",
                                                CliServNbr);
                                    MSG_WAR(0x3AB3, "Reading at index : ", index);
                                    MSG_WAR(0x3AB4, "Reading at subIndex : ", subIndex);
                                    /* Search if a SDO transfer have been yet initiated */
                                    if (! err) {
                                            MSG_ERR(0x1A93, "SDO error : Transmission yet started at line : ", line);
                                            MSG_WAR(0x3AB5, "Server Nbr = ", CliServNbr);
                                            failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_LOCAL_CTRL_ERROR);
                                            return 0xFF;
                                    }
                                    /* No line on use. Great !*/
                                    /* Try to open a new line.*/
                                    err = getSDOfreeLine( d, whoami, &line );
                                    if (err) {
                                            MSG_ERR(0x1A73, "SDO error : No line free, too many SDO in progress. Aborted.", 0);
                                            failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_LOCAL_CTRL_ERROR);
                                            return 0xFF;
                                    }
                                    initSDOline(d, line, CliServNbr, index, subIndex, SDO_BLOCK_UPLOAD_IN_PROGRESS);
                    d->transfers[line].peerCRCsupport = ((m->data[0])>>2) & 1;
                    d->transfers[line].blksize = m->data[4];
                                    /* Transfer data from dictionary to the line structure. */
                                    errorCode = objdictToSDOline(d, line);
                                    if (errorCode) {
                                            MSG_ERR(0x1A95, "SDO error : Unable to copy the data from object dictionary. Err code : ",
                                                        errorCode);
                                            failedSDO(d, CliServNbr, whoami, index, subIndex, errorCode);
                                            return 0xFF;
                                    }
                                    /* Preparing the response.*/
                                    getSDOlineRestBytes(d, line, &nbBytes);        /* get Nb bytes to transfer */
                    d->transfers[line].objsize = nbBytes;
                    data[0] = (6 << 5) | (1 << 1) | SDO_BSS_INITIATE_UPLOAD_RESPONSE;
                                        data[1] = index & 0xFF;        /* LSB */
                                        data[2] = (index >> 8) & 0xFF; /* MSB */
                                        data[3] = subIndex;
                                        data[4] = (UNS8) nbBytes;
                                        data[5] = (UNS8) (nbBytes >> 8);
                                        data[6] = (UNS8) (nbBytes >> 16);
                                        data[7] = (UNS8) (nbBytes >> 24);
                                        MSG_WAR(0x3A9A, "SDO. Sending normal block upload initiate response defined at index 0x1200 + ", nodeId);
                                        sendSDO(d, whoami, CliServNbr, data);
                }
                                else if (SubCommand == SDO_BCS_END_UPLOAD_REQUEST) {
                                    MSG_WAR(0x3AA2, "Received SDO block END upload request defined at index 0x1200 + ", CliServNbr);
                                    /* A SDO transfer should have been yet initiated. */
                                    if (!err)
                                            err = d->transfers[line].state != SDO_BLOCK_UPLOAD_IN_PROGRESS;
                                    if (err) {
                                            MSG_ERR(0x1AA1, "SDO error : Received block upload request for unstarted trans. index 0x1200 + ",
                                                            CliServNbr);
                                            failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
                                            return 0xFF;
                                    }
                    /* Release the line */
                                        resetSDOline(d, line);
                }
                                else if ((SubCommand == SDO_BCS_UPLOAD_RESPONSE) || (SubCommand == SDO_BCS_START_UPLOAD)) {
                                    /* A SDO transfer should have been yet initiated. */
                                    if (!err)
                                            err = d->transfers[line].state != SDO_BLOCK_UPLOAD_IN_PROGRESS;
                                    if (err) {
                                            MSG_ERR(0x1AA1, "SDO error : Received block upload response for unstarted trans. index 0x1200 + ",
                                                            CliServNbr);
                                            failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
                                            return 0xFF;
                                    }
                                    /* Reset the wathdog */
                                    RestartSDO_TIMER(line);
                                    /* Uploading first or next block */
                                    index = d->transfers[line].index;
                                    subIndex = d->transfers[line].subIndex;
                    if (SubCommand == SDO_BCS_UPLOAD_RESPONSE) {
                                            MSG_WAR(0x3AA2, "Received SDO block upload response defined at index 0x1200 + ", CliServNbr);
                        d->transfers[line].blksize = m->data[2];
                        AckSeq = (m->data[1]) & 0x7f;
                        getSDOlineRestBytes(d, line, &nbBytes);
                        if((nbBytes == 0) && (AckSeq == d->transfers[line].seqno)){ /* Si tout est envoyé et confirmé re&#231;u on envoi un block end upload response */
                            data[0] = (6 << 5) | ((d->transfers[line].endfield) << 2) | SDO_BSS_END_UPLOAD_RESPONSE;
                            for (i = 1 ; i < 8 ; i++)
                                                        data = 0;
                                                MSG_WAR(0x3AA5, "SDO. Sending block END upload response defined at index 0x1200 + ", CliServNbr);
                                                sendSDO(d, whoami, CliServNbr, data);
                            break;
                        }
                        else
                            d->transfers[line].offset = d->transfers[line].lastblockoffset + 7 * AckSeq;
                        if(d->transfers[line].offset > d->transfers[line].count) { /* Bad AckSeq reveived (too high) */
                                                MSG_ERR(0x1AA1, "SDO error : Received upload response with bad ackseq index 0x1200 + ",
                                                            CliServNbr);
                                                failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
                                                return 0xFF;
                        }
                                   }
                    else
                                            MSG_WAR(0x3AA2, "Received SDO block START upload defined at index 0x1200 + ", CliServNbr);
                    d->transfers[line].lastblockoffset = (UNS8) d->transfers[line].offset;
                    for(SeqNo = 1 ; SeqNo <= d->transfers[line].blksize ; SeqNo++) {
                        d->transfers[line].seqno = SeqNo;
                                        getSDOlineRestBytes(d, line, &nbBytes);
                        if (nbBytes > 7) {
                                                /* The segment to transfer is not the last one.*/
                                                data[0] = SeqNo;
                                                err = lineToSDO(d, line, 7, data + 1);
                                                if (err) {
                                                        failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                                        return 0xFF;
                                                }
                                                MSG_WAR(0x3AA5, "SDO. Sending upload segment defined at index 0x1200 + ", CliServNbr);
                                                sendSDO(d, whoami, CliServNbr, data);
                                        }
                                        else {
                                                /* Last segment is in this block */
                                                data[0] = 0x80 | SeqNo;
                                                err = lineToSDO(d, line, nbBytes, data + 1);
                                                if (err) {
                                                        failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                                        return 0xFF;
                                                }
                                                for (i = nbBytes + 1 ; i < 8 ; i++)
                                                        data = 0;
                                                MSG_WAR(0x3AA5, "SDO. Sending last upload segment defined at index 0x1200 + ", CliServNbr);
                                                sendSDO(d, whoami, CliServNbr, data);
                            d->transfers[line].endfield = (UNS8) (7 - nbBytes);
                            break;
                                        }
                    }
                }
                        }      /* end if SERVER */
                        else { /* if CLIENT (block download) */
                if ((SubCommand == SDO_BSS_INITIATE_DOWNLOAD_RESPONSE) || (SubCommand == SDO_BSS_DOWNLOAD_RESPONSE)) {
                    /* We should find a line opened for this. */
                    if (!err)
                        err = d->transfers[line].state != SDO_BLOCK_DOWNLOAD_IN_PROGRESS;
                    if (err) {
                        MSG_ERR(0x1AAA, "SDO error : Received response for unknown block download request from node id", nodeId);
                        failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
                        return 0xFF;
                    }
                    /* Reset the watchdog */
                    RestartSDO_TIMER(line)
                    if (SubCommand == SDO_BSS_INITIATE_DOWNLOAD_RESPONSE) {
                           index = d->transfers[line].index;
                        subIndex = d->transfers[line].subIndex;
                        d->transfers[line].peerCRCsupport = ((m->data[0])>>2) & 1;
                        d->transfers[line].blksize = m->data[4];
                    }
                    else {
                            d->transfers[line].blksize = m->data[2];
                        AckSeq = (m->data[1]) & 0x7f;
                        getSDOlineRestBytes(d, line, &nbBytes);
                        if((nbBytes == 0) && (AckSeq == d->transfers[line].seqno)){ /* Si tout est envoyé et confirmé re&#231;u on envoi un block end download request */
                            data[0] = (6 << 5) | ((d->transfers[line].endfield) << 2) | SDO_BCS_END_DOWNLOAD_REQUEST;
                            for (i = 1 ; i < 8 ; i++)
                                                        data = 0;
                                                MSG_WAR(0x3AA5, "SDO. Sending block END download request defined at index 0x1200 + ", CliServNbr);
                                                sendSDO(d, whoami, CliServNbr, data);
                            break;
                        }
                        else
                            d->transfers[line].offset = d->transfers[line].lastblockoffset + 7 * AckSeq;
                        if(d->transfers[line].offset > d->transfers[line].count) { /* Bad AckSeq reveived (too high) */
                                                MSG_ERR(0x1AA1, "SDO error : Received upload segment with bad ackseq index 0x1200 + ",
                                                            CliServNbr);
                                                failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
                                                return 0xFF;
                        }
                                        }
                         d->transfers[line].lastblockoffset = (UNS8) d->transfers[line].offset;
                        for(SeqNo = 1 ; SeqNo <= d->transfers[line].blksize ; SeqNo++) {
                        d->transfers[line].seqno = SeqNo;
                                        getSDOlineRestBytes(d, line, &nbBytes);
                        if (nbBytes > 7) {
                                                /* The segment to transfer is not the last one.*/
                                                data[0] = SeqNo;
                                                err = lineToSDO(d, line, 7, data + 1);
                                                if (err) {
                                                        failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                                        return 0xFF;
                                                }
                                                MSG_WAR(0x3AAB, "SDO. Sending download segment to node id ", nodeId);
                                                sendSDO(d, whoami, CliServNbr, data);
                                        }
                                        else {
                                                /* Last segment is in this block */
                                                data[0] = 0x80 | SeqNo;
                                                err = lineToSDO(d, line, nbBytes, data + 1);
                                                if (err) {
                                                        failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
                                                        return 0xFF;
                                                }
                                                for (i = nbBytes + 1 ; i < 8 ; i++)
                                                        data = 0;
                                                MSG_WAR(0x3AAB, "SDO. Sending last download segment to node id ", nodeId);
                                                sendSDO(d, whoami, CliServNbr, data);
                            d->transfers[line].endfield = (UNS8) (7 - nbBytes);
                            break;
                                        }
                    }
                                }
                                else if (SubCommand == SDO_BSS_END_DOWNLOAD_RESPONSE) {
                                        MSG_WAR(0x3AAC, "SDO End block download response from nodeId", nodeId);
                                        StopSDO_TIMER(line)
                                        d->transfers[line].state = SDO_FINISHED;
                                        if(d->transfers[line].Callback) (*d->transfers[line].Callback)(d,nodeId);
                                        return 0x00;
                                }
                                else {
                                    MSG_ERR(0x1AAB, "SDO error block download : Received wrong subcommand from nodeId", nodeId);
                                    failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
                                    return 0xFF;
                                }
                        }      /* end if CLIENT */
                        break;
                case 6: /* Command specifier for data reception - the client or server is the data consumer */
                        if (whoami == SDO_SERVER) { /* Server block download */
                                if (err) {
                                        /* Nothing already started */
                                        SubCommand = (m->data[0]) & 1;
                                        if (SubCommand != SDO_BCS_INITIATE_DOWNLOAD_REQUEST) {
                                        MSG_ERR(0x1AAC, "SDO error block download : Received wrong subcommand from node id", nodeId);
                                        failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
                                        return 0xFF;
                                    }
                                        index = getSDOindex(m->data[1],m->data[2]);
                                        subIndex = getSDOsubIndex(m->data[3]);
                                        MSG_WAR(0x3A9B, "Received SDO block download initiate defined at index 0x1200 + ",
                                                CliServNbr);
                                        MSG_WAR(0x3A9B, "Writing at index : ", index);
                                        MSG_WAR(0x3A9B, "Writing at subIndex : ", subIndex);
                                        /* Try to open a new line. */
                                        err = getSDOfreeLine( d, whoami, &line );
                                        if (err) {
                                                MSG_ERR(0x1A89, "SDO error : No line free, too many SDO in progress. Aborted.", 0);
                                                failedSDO(d, CliServNbr, whoami, index, subIndex, SDOABT_LOCAL_CTRL_ERROR);
                                                return 0xFF;
                                        }
                                        initSDOline(d, line, CliServNbr, index, subIndex, SDO_BLOCK_DOWNLOAD_IN_PROGRESS);
                    d->transfers[line].rxstep = RXSTEP_STARTED;
                    d->transfers[line].peerCRCsupport = ((m->data[0])>>2) & 1;
                                        if ((m->data[0]) & 2)        /* if data set size is indicated */
                            d->transfers[line].objsize = (UNS32)m->data[4] + (UNS32)m->data[5]*256 + (UNS32)m->data[6]*256*256 + (UNS32)m->data[7]*256*256*256;
                    data[0] = (5 << 5) | SDO_BSS_INITIATE_DOWNLOAD_RESPONSE;
                                        data[1] = (UNS8) index;        /* LSB */
                                        data[2] = (UNS8) (index >> 8); /* MSB */
                                        data[3] = subIndex;
                                        data[4] = SDO_BLOCK_SIZE;
                                        data[5] = data[6] = data[7] = 0;
                                        MSG_WAR(0x3AAD, "SDO. Sending block download initiate response - index 0x1200 + ", CliServNbr);
                                        sendSDO(d, whoami, CliServNbr, data);
                                }
                                else if (d->transfers[line].rxstep == RXSTEP_STARTED) {
                                        MSG_WAR(0x3A9B, "Received SDO block download data segment - index 0x1200 + ", CliServNbr);
                                RestartSDO_TIMER(line)
                                        SeqNo = m->data[0] & 0x7F;
                                        if (m->data[0] & 0x80) {        /* Last segment ? */
                                            if(SeqNo == (d->transfers[line].seqno + 1)) {
                                                        d->transfers[line].rxstep = RXSTEP_END;
                                                        d->transfers[line].seqno = SeqNo;
                                                        /* Store the data temporary because we don't know yet how many bytes do not contain data */
                                                        memcpy(d->transfers[line].tmpData, m->data, 8);
                                                }
                                                data[0] = (5 << 5) | SDO_BSS_DOWNLOAD_RESPONSE;
                                                data[1] = d->transfers[line].seqno;
                                                data[2] = SDO_BLOCK_SIZE;
                                                data[3] = data[4] = data[5] = data[6] = data[7] = 0;
                                                MSG_WAR(0x3AAE, "SDO. Sending block download response - index 0x1200 + ", CliServNbr);
                                                sendSDO(d, whoami, CliServNbr, data);
                        d->transfers[line].seqno = 0;
                                        }
                                        else {
                                                   if (SeqNo == (d->transfers[line].seqno + 1)) {       
                                                        d->transfers[line].seqno = SeqNo;
                                                        /* Store the data in the transfer structure. */
                                                        err = SDOtoLine(d, line, 7, (*m).data + 1);
                                                        if (err) {
                                                                failedSDO(d, CliServNbr, whoami, d->transfers[line].index,  d->transfers[line].subIndex, SDOABT_GENERAL_ERROR);
                                                                return 0xFF;
                                                        }
                                                }
                                                if (SeqNo == SDO_BLOCK_SIZE) {
                                                        data[0] = (5 << 5) | SDO_BSS_DOWNLOAD_RESPONSE;
                                                        data[1] = d->transfers[line].seqno;
                                                        data[2] = SDO_BLOCK_SIZE;
                                                        data[3] = data[4] = data[5] = data[6] = data[7] = 0;
                                                        MSG_WAR(0x3AAE, "SDO. Sending block download response - index 0x1200 + ", CliServNbr);
                                                        sendSDO(d, whoami, CliServNbr, data);
                            d->transfers[line].seqno = 0;
                                                }
                                        }
                                }
                                else if (d->transfers[line].rxstep == RXSTEP_END) { /* endphase */
                                        MSG_WAR(0x3A9B, "Received SDO block download end request - index 0x1200 + ", CliServNbr);
                                        /* here store remaining bytes in tmpData to line, check size and confirm or abort */
                                        if ((m->data[0] & 1) != SDO_BCS_END_DOWNLOAD_REQUEST) {
                                            MSG_ERR(0x1AAD, "SDO error block download : Received wrong subcommand - index 0x1200 + ", CliServNbr);
                                            failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
                                            return 0xFF;
                                        }
                                RestartSDO_TIMER(line)
                                        NbBytesNoData = (m->data[0]>>2) & 0x07;
                                        /* Store the data in the transfer structure. */
                                        err = SDOtoLine(d, line, 7-NbBytesNoData, d->transfers[line].tmpData + 1);
                                        if (err) {
                                                failedSDO(d, CliServNbr, whoami, d->transfers[line].index,  d->transfers[line].subIndex, SDOABT_GENERAL_ERROR);
                                                return 0xFF;
                                        }
                                        if(d->transfers[line].objsize){ /* If size was indicated in the initiate request */
                                                if (d->transfers[line].objsize != d->transfers[line].offset){
                                                            MSG_ERR(0x1AAE, "SDO error block download : sizes do not match - index 0x1200 + ", CliServNbr);
                                                            failedSDO(d, CliServNbr, whoami, d->transfers[line].index, d->transfers[line].subIndex, SDOABT_LOCAL_CTRL_ERROR);
                                                            return 0xFF;
                                                }
                                        }
                                        data[0] = (5 << 5) | SDO_BSS_END_DOWNLOAD_RESPONSE;
                                        for (i = 1 ; i < 8 ; i++)
                                                data = 0;
                                        MSG_WAR(0x3AAF, "SDO. Sending block download end response - index 0x1200 + ", CliServNbr);
                                        sendSDO(d, whoami, CliServNbr, data);
                                        /* Transfering line data to object dictionary. */
                                        errorCode = SDOlineToObjdict(d, line);
                                        if (errorCode) {
                                                MSG_ERR(0x1AAF, "SDO error : Unable to copy the data in the object dictionary", 0);
                                                failedSDO(d, CliServNbr, whoami, d->transfers[line].index, d->transfers[line].subIndex, errorCode);
                                                return 0xFF;
                                        }
                                        /* Release of the line */
                                        resetSDOline(d, line);
                                        MSG_WAR(0x3AAF, "SDO. End of block download defined at index 0x1200 + ", CliServNbr);
                                }
                    }      /* end if SERVER */
                    else { /* if CLIENT (block upload) */
                                if (err) {
                                       /* Nothing already started */
                                    MSG_ERR(0x1AAD, "SDO error block upload : no transmission started", nodeId);
                                    failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
                                    return 0xFF;
                                }
                            RestartSDO_TIMER(line)
                                if (d->transfers[line].rxstep == RXSTEP_INIT) {
                                    if ((m->data[0] & 1) == SDO_BSS_INITIATE_UPLOAD_RESPONSE) {
                                            MSG_WAR(0x3A9C, "Received SDO block upload response from node id ", nodeId);
                                                d->transfers[line].rxstep = RXSTEP_STARTED;
                        d->transfers[line].peerCRCsupport = ((m->data[0])>>2) & 1;
                                            if ((m->data[0]) & 2)        /* if data set size is indicated */
                                d->transfers[line].objsize = (UNS32)m->data[4] + (UNS32)m->data[5]*256 + (UNS32)m->data[6]*256*256 + (UNS32)m->data[7]*256*256*256;
                        data[0] = (5 << 5) | SDO_BCS_START_UPLOAD;
                                            for (i = 1 ; i < 8 ; i++)
                                                    data = 0;
                        MSG_WAR(0x3AB6, "SDO. Sending block upload start to node id ", nodeId);
                                            sendSDO(d, whoami, CliServNbr, data);
                    }
                }
                                else if (d->transfers[line].rxstep == RXSTEP_STARTED) {
                                        SeqNo = m->data[0] & 0x7F;
                                        if (m->data[0] & 0x80) {        /* Last segment ? */
                                            if(SeqNo == (d->transfers[line].seqno + 1)) {
                                                        d->transfers[line].rxstep = RXSTEP_END;
                                                        d->transfers[line].seqno = SeqNo;
                                                        /* Store the data temporary because we don't know yet how many bytes do not contain data */
                                                        memcpy(d->transfers[line].tmpData, m->data, 8);
                                                }
                                                data[0] = (5 << 5) | SDO_BCS_UPLOAD_RESPONSE;
                                                data[1] = d->transfers[line].seqno;
                                                data[2] = SDO_BLOCK_SIZE;
                                                data[3] = data[4] = data[5] = data[6] = data[7] = 0;
                                                MSG_WAR(0x3AB7, "SDO. Sending block upload response to node id ", nodeId);
                                                sendSDO(d, whoami, CliServNbr, data);
                        d->transfers[line].seqno = 0;
                                        }
                                        else {
                                                   if (SeqNo == (d->transfers[line].seqno + 1)) {       
                                                        d->transfers[line].seqno = SeqNo;
                                                        /* Store the data in the transfer structure. */
                                                        err = SDOtoLine(d, line, 7, (*m).data + 1);
                                                        if (err) {
                                                                failedSDO(d, CliServNbr, whoami, d->transfers[line].index,  d->transfers[line].subIndex, SDOABT_GENERAL_ERROR);
                                                                return 0xFF;
                                                        }
                                                }
                                                if (SeqNo == SDO_BLOCK_SIZE) {
                                                        data[0] = (5 << 5) | SDO_BCS_UPLOAD_RESPONSE;
                                                        data[1] = d->transfers[line].seqno;
                                                        data[2] = SDO_BLOCK_SIZE;
                                                        data[3] = data[4] = data[5] = data[6] = data[7] = 0;
                                                        MSG_WAR(0x3AAE, "SDO. Sending block upload response to node id ", nodeId);
                                                        sendSDO(d, whoami, CliServNbr, data);
                            d->transfers[line].seqno = 0;
                                                }
                                        }
                                }
                                else if (d->transfers[line].rxstep == RXSTEP_END) { /* endphase */
                                        /* here store remaining bytes in tmpData to line, check size and confirm or abort */
                                        if ((m->data[0] & 1) != SDO_BSS_END_UPLOAD_RESPONSE) {
                                            MSG_ERR(0x1AAD, "SDO error block upload : Received wrong subcommand from node id ", nodeId);
                                            failedSDO(d, CliServNbr, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
                                            return 0xFF;
                                        }
                                        NbBytesNoData = (m->data[0]>>2) & 0x07;
                                        /* Store the data in the transfer structure. */
                                        err = SDOtoLine(d, line, 7-NbBytesNoData, d->transfers[line].tmpData + 1);
                                        if (err) {
                                                failedSDO(d, CliServNbr, whoami, d->transfers[line].index,  d->transfers[line].subIndex, SDOABT_GENERAL_ERROR);
                                                return 0xFF;
                                        }
                                        if(d->transfers[line].objsize){ /* If size was indicated in the initiate request */
                                                if (d->transfers[line].objsize != d->transfers[line].offset){
                                                            MSG_ERR(0x1AAE, "SDO error block download : sizes do not match - from node id ", nodeId);
                                                            failedSDO(d, CliServNbr, whoami, d->transfers[line].index, d->transfers[line].subIndex, SDOABT_LOCAL_CTRL_ERROR);
                                                            return 0xFF;
                                                }
                                        }
                                        data[0] = (5 << 5) | SDO_BCS_END_UPLOAD_REQUEST;
                                        for (i = 1 ; i < 8 ; i++)
                                                data = 0;
                                        MSG_WAR(0x3AAF, "SDO. Sending block upload end request to node id ", nodeId);
                                        sendSDO(d, whoami, CliServNbr, data);
                                        MSG_WAR(0x3AAF, "SDO. End of block upload request", 0);
                    StopSDO_TIMER(line)
                                        d->transfers[line].state = SDO_FINISHED;
                                    if(d->transfers[line].Callback) (*d->transfers[line].Callback)(d,nodeId);
                                }
                        }      /* end if CLIENT */
                        break;
                default:
                        /* Error : Unknown cs */
                        MSG_ERR(0x1AB2, "SDO. Received unknown command specifier : ", cs);
                        return 0xFF;

        } /* End switch */
        return 0;
}


/*!
**
**
** @param d
** @param nodeId
**
** @return
**         0xFF : No SDO client available
**     0xFE : Not found
**     otherwise : SDO client number
**/
UNS8 GetSDOClientFromNodeId( CO_Data* d, UNS8 nodeId )
{
        UNS8 SDOfound = 0;
        UNS8 CliNbr;
        UNS16 lastIndex;
        UNS16 offset;
        UNS8 nodeIdServer;

        offset = d->firstIndex->SDO_CLT;
        lastIndex = d->lastIndex->SDO_CLT;
        if (offset == 0) {
                MSG_ERR(0x1AC6, "No SDO client index found for nodeId ", nodeId);
                return 0xFF;
        }
        CliNbr = 0;
        while (offset <= lastIndex) {
                if (d->objdict[offset].bSubCount <= 3) {
                        MSG_ERR(0x1AC8, "Subindex 3  not found at index ", 0x1280 + CliNbr);
                        return 0xFF;
                }
                /* looking for the server nodeId */
                nodeIdServer = *((UNS8*) d->objdict[offset].pSubindex[3].pObject);
                MSG_WAR(0x1AD2, "index : ", 0x1280 + CliNbr);
                MSG_WAR(0x1AD3, "nodeIdServer : ", nodeIdServer);

                if(nodeIdServer == nodeId) {
                        SDOfound = 1;
                        break;
                }
                offset++;
                CliNbr++;
        } /* end while */
        if (!SDOfound) {
                MSG_WAR(0x1AC9, "SDO No preset client found to communicate with node : ", nodeId);
                return 0xFE;
        }
        MSG_WAR(0x3AD0,"        SDO client defined at index  : ", 0x1280 + CliNbr);

        return CliNbr;
}


/*!
**
**
** @param d
** @param nodeId
** @param index
** @param subIndex
** @param count
** @param dataType
** @param data
** @param Callback
** @param endianize
**
** @return
**/
INLINE UNS8 _writeNetworkDict (CO_Data* d, UNS8 nodeId, UNS16 index,
                UNS8 subIndex, UNS32 count, UNS8 dataType, void *data, SDOCallback_t Callback, UNS8 endianize, UNS8 useBlockMode)
{
        UNS8 err;
        UNS8 line;
        UNS8 CliNbr;
        UNS32 j;
        UNS8 i;
        UNS8 buf[8];

        MSG_WAR(0x3AC0, "Send SDO to write in the dictionary of node : ", nodeId);
        MSG_WAR(0x3AC1, "                                   At index : ", index);
        MSG_WAR(0x3AC2, "                                   subIndex : ", subIndex);
        MSG_WAR(0x3AC3, "                                   nb bytes : ", count);

        /* First let's find the corresponding SDO client in our OD  */
        CliNbr = GetSDOClientFromNodeId( d, nodeId);
        if(CliNbr >= 0xFE)
                return CliNbr;
        /* Verify that there is no SDO communication yet. */
        err = getSDOlineOnUse(d, CliNbr, SDO_CLIENT, &line);
        if (!err) {
                MSG_ERR(0x1AC4, "SDO error : Communication yet established. with node : ", nodeId);
                return 0xFF;
        }
        /* Taking the line ... */
        err = getSDOfreeLine( d, SDO_CLIENT, &line );
        if (err) {
                MSG_ERR(0x1AC5, "SDO error : No line free, too many SDO in progress. Aborted for node : ", nodeId);
                return (0xFF);
        }
        else
                MSG_WAR(0x3AE1, "Transmission on line : ", line);
    if(useBlockMode) {
            initSDOline(d, line, CliNbr, index, subIndex, SDO_BLOCK_DOWNLOAD_IN_PROGRESS);
            d->transfers[line].objsize = count;
    }
    else
            initSDOline(d, line, CliNbr, index, subIndex, SDO_DOWNLOAD_IN_PROGRESS);
        d->transfers[line].count = count;
        d->transfers[line].dataType = dataType;
#ifdef SDO_DYNAMIC_BUFFER_ALLOCATION
        {
                UNS8* lineData = d->transfers[line].data;
                if (count > SDO_MAX_LENGTH_TRANSFER)
                {
                        d->transfers[line].dynamicData = (UNS8*) malloc(count);
                        d->transfers[line].dynamicDataSize = count;
                        if (d->transfers[line].dynamicData == NULL)
                        {
                                MSG_ERR(0x1AC9, "SDO. Error. Could not allocate enough bytes : ", count);
                                return 0xFE;
                        }
                        lineData = d->transfers[line].dynamicData;
                }
#endif //SDO_DYNAMIC_BUFFER_ALLOCATION

                /* Copy data to transfers structure. */
                for (j = 0 ; j < count ; j++) {
#ifdef SDO_DYNAMIC_BUFFER_ALLOCATION
# ifdef CANOPEN_BIG_ENDIAN
                        if (dataType == 0 && endianize)
                                lineData[count - 1 - j] = ((char *)data)[j];
                        else /* String of bytes. */
                                lineData[j] = ((char *)data)[j];
#  else
                        lineData[j] = ((char *)data)[j];
#  endif
                }
#else //SDO_DYNAMIC_BUFFER_ALLOCATION
# ifdef CANOPEN_BIG_ENDIAN
                if (dataType == 0 && endianize)
                        d->transfers[line].data[count - 1 - j] = ((char *)data)[j];
                else /* String of bytes. */
                        d->transfers[line].data[j] = ((char *)data)[j];
#  else
                d->transfers[line].data[j] = ((char *)data)[j];
#  endif
#endif //SDO_DYNAMIC_BUFFER_ALLOCATION
        }
    if(useBlockMode) {
            buf[0] = (6 << 5) | (1 << 1 );   /* CCS = 6 , CC = 0 , S = 1 , CS = 0 */
            for (i = 0 ; i < 4 ; i++)
                    buf[i+4] = (UNS8)((count >> (i<<3))); /* i*8 */
    }
    else {
            /* Send the SDO to the server. Initiate download, cs=1. */
            if (count <= 4) { /* Expedited transfer */
                    buf[0] = (UNS8)((1 << 5) | ((4 - count) << 2) | 3);
                    for (i = 4 ; i < 8 ; i++)
                            buf = d->transfers[line].data[i - 4];
                    d->transfers[line].offset = count;
            }
            else { /** Normal transfer */
                    buf[0] = (1 << 5) | 1;
                    for (i = 0 ; i < 4 ; i++)
                            buf[i+4] = (UNS8)((count >> (i<<3))); /* i*8 */
            }
    }
        buf[1] = index & 0xFF;        /* LSB */
        buf[2] = (index >> 8) & 0xFF; /* MSB */
        buf[3] = subIndex;

        d->transfers[line].Callback = Callback;

        err = sendSDO(d, SDO_CLIENT, CliNbr, buf);
        if (err) {
                MSG_ERR(0x1AD1, "SDO. Error while sending SDO to node : ", nodeId);
                /* release the line */
                resetSDOline(d, line);
                return 0xFF;
        }


        return 0;
}

/*!
**
**
** @param d
** @param nodeId
** @param index
** @param subIndex
** @param count
** @param dataType
** @param data
** @param useBlockMode
**
** @return
**/
UNS8 writeNetworkDict (CO_Data* d, UNS8 nodeId, UNS16 index,
                UNS8 subIndex, UNS32 count, UNS8 dataType, void *data, UNS8 useBlockMode)
{
        return _writeNetworkDict (d, nodeId, index, subIndex, count, dataType, data, NULL, 1, useBlockMode);
}

/*!
**
**
** @param d
** @param nodeId
** @param index
** @param subIndex
** @param count
** @param dataType
** @param data
** @param Callback
** @param useBlockMode
**
** @return
**/
UNS8 writeNetworkDictCallBack (CO_Data* d, UNS8 nodeId, UNS16 index,
                UNS8 subIndex, UNS32 count, UNS8 dataType, void *data, SDOCallback_t Callback, UNS8 useBlockMode)
{
        return _writeNetworkDict (d, nodeId, index, subIndex, count, dataType, data, Callback, 1, useBlockMode);
}

UNS8 writeNetworkDictCallBackAI (CO_Data* d, UNS8 nodeId, UNS16 index,
                UNS8 subIndex, UNS32 count, UNS8 dataType, void *data, SDOCallback_t Callback, UNS8 endianize, UNS8 useBlockMode)
{
        UNS8 ret;
        UNS16 lastIndex;
        UNS16 offset;
        UNS8 nodeIdServer;
        UNS8 i;

        ret = _writeNetworkDict (d, nodeId, index, subIndex, count, dataType, data, Callback, endianize, useBlockMode);
        if(ret == 0xFE)
        {
                offset = d->firstIndex->SDO_CLT;
                lastIndex = d->lastIndex->SDO_CLT;
                if (offset == 0)
                {
                        MSG_ERR(0x1AC6, "writeNetworkDict : No SDO client index found", 0);
                        return 0xFF;
                }
                i = 0;
                while (offset <= lastIndex)
                {
                        if (d->objdict[offset].bSubCount <= 3)
                        {
                                MSG_ERR(0x1AC8, "Subindex 3  not found at index ", 0x1280 + i);
                                return 0xFF;
                        }
                        nodeIdServer = *(UNS8*) d->objdict[offset].pSubindex[3].pObject;
                        if(nodeIdServer == 0)
                        {
                                *(UNS32*)d->objdict[offset].pSubindex[1].pObject = (UNS32)(0x600 + nodeId);
                                *(UNS32*)d->objdict[offset].pSubindex[2].pObject = (UNS32)(0x580 + nodeId);
                                *(UNS8*) d->objdict[offset].pSubindex[3].pObject = nodeId;
                                return _writeNetworkDict (d, nodeId, index, subIndex, count, dataType, data, Callback, endianize, useBlockMode);
                        }
                        offset++;
                }
                return 0xFF;
        }
        else if(ret == 0)
        {
                return 0;
        }
        else
        {
                return 0xFF;
        }
}

/*!
**
**
** @param d
** @param nodeId
** @param index
** @param subIndex
** @param dataType
** @param Callback
** @param useBlockMode
**
** @return
**/
INLINE UNS8 _readNetworkDict (CO_Data* d, UNS8 nodeId, UNS16 index, UNS8 subIndex, UNS8 dataType, SDOCallback_t Callback, UNS8 useBlockMode)
{
        UNS8 err;
        UNS8 i;
        UNS8 CliNbr;
        UNS8 line;
        UNS8 data[8];

        MSG_WAR(0x3AD5, "Send SDO to read in the dictionary of node : ", nodeId);
        MSG_WAR(0x3AD6, "                                  At index : ", index);
        MSG_WAR(0x3AD7, "                                  subIndex : ", subIndex);

        /* First let's find the corresponding SDO client in our OD  */
        CliNbr = GetSDOClientFromNodeId( d, nodeId);
        if(CliNbr >= 0xFE)
                return CliNbr;

        /* Verify that there is no SDO communication yet. */
        err = getSDOlineOnUse(d, CliNbr, SDO_CLIENT, &line);
        if (!err) {
                MSG_ERR(0x1AD8, "SDO error : Communication yet established. with node : ", nodeId);
                return 0xFF;
        }
        /* Taking the line ... */
        err = getSDOfreeLine( d, SDO_CLIENT, &line );
        if (err) {
                MSG_ERR(0x1AD9, "SDO error : No line free, too many SDO in progress. Aborted for node : ", nodeId);
                return (0xFF);
        }
        else
                MSG_WAR(0x3AE0, "Transmission on line : ", line);

    if(useBlockMode) {
            initSDOline(d, line, CliNbr, index, subIndex, SDO_BLOCK_UPLOAD_IN_PROGRESS);
            /* Send the SDO to the server. Initiate block upload, cs=0. */
            d->transfers[line].dataType = dataType;
            data[0] = (5 << 5) | SDO_BCS_INITIATE_UPLOAD_REQUEST;
            data[1] = index & 0xFF;        /* LSB */
            data[2] = (index >> 8) & 0xFF; /* MSB */
            data[3] = subIndex;
            data[4] = SDO_BLOCK_SIZE;
            for (i = 5 ; i < 8 ; i++)
                    data = 0;
    }
    else {
            initSDOline(d, line, CliNbr, index, subIndex, SDO_UPLOAD_IN_PROGRESS);
            /* Send the SDO to the server. Initiate upload, cs=2. */
            d->transfers[line].dataType = dataType;
            data[0] = (2 << 5);
            data[1] = index & 0xFF;        /* LSB */
            data[2] = (index >> 8) & 0xFF; /* MSB */
            data[3] = subIndex;
            for (i = 4 ; i < 8 ; i++)
                    data = 0;
    }
        d->transfers[line].Callback = Callback;
        err = sendSDO(d, SDO_CLIENT, CliNbr, data);
        if (err) {
                MSG_ERR(0x1AE5, "SDO. Error while sending SDO to node : ", nodeId);
                /* release the line */
                resetSDOline(d, line);
                return 0xFF;
        }
        return 0;
}

/*!
**
**
** @param d
** @param nodeId
** @param index
** @param subIndex
** @param dataType
** @param useBlockMode
**
** @return
**/
UNS8 readNetworkDict (CO_Data* d, UNS8 nodeId, UNS16 index, UNS8 subIndex, UNS8 dataType, UNS8 useBlockMode)
{
        return _readNetworkDict (d, nodeId, index, subIndex, dataType, NULL, useBlockMode);
}

/*!
**
**
** @param d
** @param nodeId
** @param index
** @param subIndex
** @param dataType
** @param Callback
** @param useBlockMode
**
** @return
**/
UNS8 readNetworkDictCallback (CO_Data* d, UNS8 nodeId, UNS16 index, UNS8 subIndex, UNS8 dataType, SDOCallback_t Callback, UNS8 useBlockMode)
{
        return _readNetworkDict (d, nodeId, index, subIndex, dataType, Callback, useBlockMode);
}

UNS8 readNetworkDictCallbackAI (CO_Data* d, UNS8 nodeId, UNS16 index, UNS8 subIndex, UNS8 dataType, SDOCallback_t Callback, UNS8 useBlockMode)
{
        UNS8 ret;
        UNS16 lastIndex;
        UNS16 offset;
        UNS8 nodeIdServer;
        UNS8 i;

        ret = _readNetworkDict (d, nodeId, index, subIndex, dataType, Callback, useBlockMode);
        if(ret == 0xFE)
        {
                offset = d->firstIndex->SDO_CLT;
                lastIndex = d->lastIndex->SDO_CLT;
                if (offset == 0)
                {
                        MSG_ERR(0x1AC6, "writeNetworkDict : No SDO client index found", 0);
                        return 0xFF;
                }
                i = 0;
                while (offset <= lastIndex)
                {
                        if (d->objdict[offset].bSubCount <= 3)
                        {
                                MSG_ERR(0x1AC8, "Subindex 3  not found at index ", 0x1280 + i);
                                return 0xFF;
                        }
                        nodeIdServer = *(UNS8*) d->objdict[offset].pSubindex[3].pObject;
                        if(nodeIdServer == 0)
                        {
                                *(UNS32*)d->objdict[offset].pSubindex[1].pObject = (UNS32)(0x600 + nodeId);
                                *(UNS32*)d->objdict[offset].pSubindex[2].pObject = (UNS32)(0x580 + nodeId);
                                *(UNS8*) d->objdict[offset].pSubindex[3].pObject = nodeId;
                                return _readNetworkDict (d, nodeId, index, subIndex, dataType, Callback, useBlockMode);
                        }
                        offset++;
                }
                return 0xFF;
        }
        else if(ret == 0)
        {
                return 0;
        }
        else
        {
                return 0xFF;
        }
}

/*!
**
**
** @param d
** @param nodeId
** @param data
** @param size : *size MUST contain the size of *data buffer before calling
**                     The function set it to the actual number of written bytes
** @param abortCode
**
** @return
**    SDO_PROVIDED_BUFFER_TOO_SMALL if *data is not big enough
**    or any transmission status value.
**/
UNS8 getReadResultNetworkDict (CO_Data* d, UNS8 nodeId, void* data, UNS32 *size,
                UNS32 * abortCode)
{
        UNS32 i;
        UNS8 err;
        UNS8 CliNbr;
        UNS8 line;
        * abortCode = 0;

        /* First let's find the corresponding SDO client in our OD  */
        CliNbr = GetSDOClientFromNodeId(d, nodeId);
        if(CliNbr >= 0xFE) {
        *size = 0;
                return SDO_ABORTED_INTERNAL;
    }

        /* Looking for the line tranfert. */
        err = getSDOlineOnUse(d, CliNbr, SDO_CLIENT, &line);
        if (err) {
                MSG_ERR(0x1AF0, "SDO error : No line found for communication with node : ", nodeId);
        *size = 0;
        return SDO_ABORTED_INTERNAL;
        }

    /* If transfer not finished just return, but if aborted set abort code and size to 0 */
    if (d->transfers[line].state != SDO_FINISHED) {
            if((d->transfers[line].state == SDO_ABORTED_RCV) || (d->transfers[line].state == SDO_ABORTED_INTERNAL)) {
            *abortCode = d->transfers[line].abortCode;
            *size = 0;
        }
                return d->transfers[line].state;
    }

        /* if SDO initiated with e=0 and s=0 count is null, offset carry effective size*/
        if( d->transfers[line].count == 0)
                d->transfers[line].count = d->transfers[line].offset;

    /* Check if the provided buffer is big enough */
    if(*size < d->transfers[line].count) {
                *size = 0;
                return SDO_PROVIDED_BUFFER_TOO_SMALL;
    }

    /* Give back actual size */
    *size = d->transfers[line].count;

        /* Copy payload to data pointer */
#ifdef SDO_DYNAMIC_BUFFER_ALLOCATION
        {
                UNS8 *lineData = d->transfers[line].data;

                if (d->transfers[line].dynamicData && d->transfers[line].dynamicDataSize)
                {
                        lineData = d->transfers[line].dynamicData;
                }
                for  ( i = 0 ; i < *size ; i++) {
# ifdef CANOPEN_BIG_ENDIAN
                        if (d->transfers[line].dataType != visible_string)
                                ( (char *) data)[*size - 1 - i] = lineData;
                        else /* String of bytes. */
                                ( (char *) data) = lineData;
# else
                        ( (char *) data) = lineData;
# endif
                }
        }
#else //SDO_DYNAMIC_BUFFER_ALLOCATION
        for  ( i = 0 ; i < *size ; i++) {
# ifdef CANOPEN_BIG_ENDIAN
                if (d->transfers[line].dataType != visible_string)
                        ( (char *) data)[*size - 1 - i] = d->transfers[line].data;
                else /* String of bytes. */
                        ( (char *) data) = d->transfers[line].data;
# else
                ( (char *) data) = d->transfers[line].data;
# endif
        }
#endif //SDO_DYNAMIC_BUFFER_ALLOCATION
    resetSDOline(d, line);
        return SDO_FINISHED;
}

/*!
**
**
** @param d
** @param nodeId
** @param abortCode
**
** @return
**/
UNS8 getWriteResultNetworkDict (CO_Data* d, UNS8 nodeId, UNS32 * abortCode)
{
        UNS8 line = 0;
        UNS8 err;
        UNS8 CliNbr;
        * abortCode = 0;

        /* First let's find the corresponding SDO client in our OD  */
        CliNbr = GetSDOClientFromNodeId(d, nodeId);
        if(CliNbr >= 0xFE)
                return SDO_ABORTED_INTERNAL;

        /* Looking for the line tranfert. */
        err = getSDOlineOnUse(d, CliNbr, SDO_CLIENT, &line);
        if (err) {
                MSG_ERR(0x1AF1, "SDO error : No line found for communication with node : ", nodeId);
                return SDO_ABORTED_INTERNAL;
        }
        * abortCode = d->transfers[line].abortCode;
    if (d->transfers[line].state != SDO_FINISHED)
            return d->transfers[line].state;
    resetSDOline(d, line);
        return SDO_FINISHED;
}

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165377
金钱
165377
注册时间
2010-12-1
在线时间
2111 小时
发表于 2018-8-15 01:34:09 | 显示全部楼层
回复

使用道具 举报

160

主题

967

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2097
金钱
2097
注册时间
2014-3-7
在线时间
491 小时
发表于 2018-9-4 15:13:20 | 显示全部楼层
这种帖子谁会看?
回复

使用道具 举报

160

主题

967

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2097
金钱
2097
注册时间
2014-3-7
在线时间
491 小时
发表于 2018-9-5 15:15:18 | 显示全部楼层
4.3通讯对象

CANOpen协议共有6种通讯对象,分别是:PDO、SDO、SYNC、TIME、EMCY、NMT。这6种通讯对象完成了CANOpen协议的所有通讯功能。其中我们只介绍使用较多的PDO、SDO、NMT(4.4)。

4.3.1通信对象IDCOB-ID

CANOpen协议的通讯对象主要利用了CAN协议中的数据帧和远程帧。为了区分不同的通讯对象,CANOpen协议利用数据帧/远程帧中的ID。其中第7位到第10位为功能代码。第0位到第6位为节点ID,用以区分不同节点的相同功能。这样就允许最多127个从节点与主节点通讯。


图28 COB-ID的结构

下面是预定义的各通讯对象的COB-ID


表3各通讯对象对应的COB-ID

其中绿色部分为广播的通讯对象,蓝色部分为点对点的通讯对象。

COB-ID的大小也决定了通讯对象的优先级,其中NMT的优先级最高,PDO的优先级高于SDO。

4.3.2Process Data Object

CANOpen中的实时数据传输是由PDO来完成的。PDO的传输采用了生产者消费者模式。共有两种PDO,TPDO和RPDO。TPDO用来传输数据,支持TPDO的节点都是PDO数据的生产者。RPDO用来接收PDO数据,支持RPDO的节点是PDO数据的消费者。从表3可以看出,一个节点最多支持4个TPDO(分别是180h+NodeID、280h +NodeID、380h +NodeID、480h +NodeID)和4个RPDO(分别是200h +NodeID、300h +NodeID、400h +NodeID、500h +NodeID)。每一个PDO都对应一些参数,包括通讯参数和映射参数。

4.3.2.1PDO的参数

PDO的参数包括两部分,通讯参数和映射参数.他们占据了对象字典中从1400到1BFF之间的位置.


表4 PDO参数在对象字典中的位置

PDO的通讯参数定义了COB-ID,传输类型(同步,异步,循环,时间出发),inhibit time(两个PDO的最小间隔)等,见表5.

表6给出了PDO的映射参数.一个PDO最多可以映射到64个对象。每一项的含义见图29。最高16位是对象字典的索引,后面8位是子索引。最低8位是数据长度。关于PDO映射的详细介绍见4.3.2.2


表5 PDO通讯参数


表6 PDO映射参数


图29 PDO映射参数解释

4.3.2.2PDO映射

PDO的内容没有固定的形式,它的数据段可以是1到8个字节长。使用PDO的一个基本的出发点是发射端和接收端都知道PDO中的数据的含义。图30说明了具体的工作原理。PDO采用了生产者和消费者模式。生产者按照TPDO的映射参数从对象字典中抽取数据形成PDO的数据。当消费者接收到PDO的数据后,就会按照RPDO的映射关系,将PDO中的数据解析出来,填入对应的数据字典中。

图31给出了生产者生成PDO0数据的具体过程。首先生产者从[1800,01]中得到COB-ID。然后从[1A00,01]中获取第一个对象。[1A00,01]中的值为0x20000108h,那么第一个对象为[2000,01],对应值为A,在PDO中占0x8位。接着是第二个对象[2003,03],对应值为G,在PDO中占0x10位。最后是对象[2003,01],对应值F,在PDO中占0x8位。这样一个有数据A、G、F组成的,32位的PDO就形成了。


图30 TPDO与RPDO[2]


图31 PDO数据的形成

4.3.3SDO

SDO(Service Data Object)使用Client-Server模式建立起点到点的通讯并实现了对对象字典中条目的读写。其中被访问的对象字典的所在设备作为Server,访问对象字典的设备作为client。参考下图。SDO采用的请求应答模式,每次SDO访问都会有2条CAN的数据帧对应。一条是请求,一条是应答。


图32 client-server模式

SDO主要提供3种服务:段传输,块传输,中止传输。下面分别来介绍这三种服务是如何实现的。

[size=14.6667px]4.3.3.1段传输

下面是SDO段传输Download过程中的示意图。首先由client端发起,然后Server端应答。这样一来一回。知道把数据传输完毕。当传输的数据长度小于4时,一次应答就可把数据传输完毕。


图33SDO段下载时的client,server端数据应答


图34初始化SDO下载的命令字


图35SDO段下载的命令字

图34、35标出了在SDO段下载的初始化和数据传输阶段的命令字。其中:

  • ccs: client命令标识符
    • 0:段下载请求
    • 1:初始化下载请求
    • 2:初始化上传请求
    • 3:段上传请求


  • scs: server命令表示符
    • 0:段上传响应
    • 1:段下载相应
    • 2:初始化上传响应
    • 3初始化下载响应


  • n:指示不含数据的字节数.
  • e:传输类型
    • 0:普通传输
    • 1:快速传输(输出长度<=4)


  • s:大小指示器
  • m:指示数据的索引和子索引.
  • d:数据
  • X:总是0
  • reserved:预留,总是0
  • c:指示是否还有数据需要下载/上传
  • t:触发位。这个位没发送一次数据会反转一下。

SDO段上传的过程与段下载的过程类似,只是命令字不同。可参考图36图37


图36初始化SDO上传命令字


图37SDO段上传命令字

4.3.3.2块传输

块传输的主要目的是为了提高传输效率。它与段传输的主要区别在于:块传输时,可以传输多次数据之后,才会有一次应答,如图38。CANOpen将数据分为多个block,每个block又由1-127个segment组成。在传输完一个block的数据之后,才会有一次的应答。



图38块传输时的client,server数据应答

4.3.3.3中止传输

无论CAN设备处于段传输还是块传输中,都可以使用中止传输协议(图39)来中止传输。


图39中止SDO传输命令字

协议的命令字解释如下:

  • cs:命令标识符
    • 4:中止传输请求
  • X:总是0
  • m:标识索引和子索引.
  • d:中止码(7中止码表.

下表是对各中止码的解释


表7中止码表


回复

使用道具 举报

17

主题

237

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1312
金钱
1312
注册时间
2017-3-1
在线时间
259 小时
发表于 2019-1-3 14:40:02 | 显示全部楼层
正在canfestival学习中,建议发个工程吧,这一陀看着多难受
回复

使用道具 举报

13

主题

264

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
5349
金钱
5349
注册时间
2017-8-14
在线时间
239 小时
发表于 2019-1-3 21:42:31 | 显示全部楼层
本帖最后由 zml13917492379 于 2019-1-3 22:16 编辑

我们的 CANWeb 简单,功能类似CANOpen,Web可视化CAN编程,并提供 源程序及说明,使用案例见链接:
http://www.openedv.com/forum.php ... 09854&highlight=CAN
详细资料扣扣群204408503自行下载
回复

使用道具 举报

1

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
99
金钱
99
注册时间
2019-3-28
在线时间
14 小时
发表于 2019-3-28 20:21:09 | 显示全部楼层
你好,楼主,你这个移植的软件是什么呀,关键是新建工程这里
回复

使用道具 举报

8

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
181
金钱
181
注册时间
2017-7-24
在线时间
48 小时
发表于 2019-4-23 08:35:00 来自手机 | 显示全部楼层
楼主。请问下你做出来了吗?我也是移植过来了,可是不知道怎么用SDO
回复

使用道具 举报

0

主题

3

帖子

0

精华

新手上路

积分
39
金钱
39
注册时间
2021-6-30
在线时间
8 小时
发表于 2021-7-1 21:16:20 | 显示全部楼层
随风的风 发表于 2019-4-23 08:35
楼主。请问下你做出来了吗?我也是移植过来了,可是不知道怎么用SDO

你好,请问怎么移植呢
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-27 14:28

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表