⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mlssslv.c

📁 MicoCANOpen很好的学习源代码
💻 C
字号:
/**************************************************************************
MODULE:    MLSS
CONTAINS:  MicroCANopen - Support for MicroLSS - Layer Setting Services
COPYRIGHT: Embedded Systems Academy, Inc. 2002-2007.
           All rights reserved. www.microcanopen.com
           This software was written in accordance to the guidelines at
           www.esacademy.com/software/softwarestyleguide.pdf
DISCLAIM:  Read and understand our disclaimer before using this code!
           www.esacademy.com/disclaim.htm
LICENSE:   THIS IS THE EDUCATIONAL VERSION OF MICROCANOPEN
           See file license_educational.txt or
           www.microcanopen.com/license_educational.txt
           A commercial MicroCANopen license is available at
           www.CANopenStore.com
VERSION:   3.30, ESA 30-JAN-07
           $LastChangedDate: 2006-03-29 00:44:08 -0800 (Wed, 29 Mar 2006) $
           $LastChangedRevision: 86 $
***************************************************************************/ 

#include "mco.h"
#include "mcohw.h"
#include "mlss.h"

#if USE_MICROLSS == 1
// Only use this file if project is configured for LSS Slave

// process image from user_xxxx.c
extern UNSIGNED8 MEM_NEAR gProcImg[];

/**************************************************************************
EXTERNAL GLOBAL VARIABLES
**************************************************************************/ 

// This structure holds all node specific configuration
extern MCO_CONFIG MEM_FAR gMCOConfig;


/**************************************************************************
PRIVATE VARIABLES
**************************************************************************/ 

// The 128bit LSS_ID with vendor, product, rev and serial
UNSIGNED32 LSS_ID[4];          // contains the 1018h Object, the LSSID

struct {
  UNSIGNED8  active;           // TRUE if node is in LSS mode
  UNSIGNED8  operation_mode;   // Node is in operation mode. If not=>configuration
  UNSIGNED8  new_node_id;      // New configured node ID
  UNSIGNED8  old_node_id;      // Original (pre-configured) node ID
  UNSIGNED8  node_id_set;      // Flag to indicate if node ID is configured
  UNSIGNED8  new_node_bps;     // New configured baudrate
  UNSIGNED8  mLSS_state;       // In MicroLSS mode, shows which 32bit part we
                               // are currently working on
} mLSS;


// This structure holds the current transmit/response message
CAN_MSG MEM_FAR mTxCAN;


/*******************************************************************************
PRIVATE FUNCTIONS
*******************************************************************************/


/****************************************************************
DOES:    Extracts dword in CANopen byte order from memory location
RETURNS: UNSIGNED32
*****************************************************************/
UNSIGNED32 LSS_GetDword (
  UNSIGNED8 *pDat
  )
{
  UNSIGNED32 lvalue;
  UNSIGNED8  i;

  lvalue  = 0x00000000L;
  pDat   += 3;   // Set pointer to MSB
  for (i=0; i<4; i++)
  {
    lvalue <<= 8;
    lvalue  |= *pDat--;
  }

  return lvalue;
}


/****************************************************************
DOES:    Initializes CAN buffer for LSS response, sets byte 0
RETURNS: 
*****************************************************************/
void LSS_InitResponse (
  UNSIGNED8 data0
  )
{
  UNSIGNED8 i;

  mTxCAN.ID      = LSS_SLAVE_ID;
  mTxCAN.LEN     = 8;
  mTxCAN.BUF[0]  = data0;
  for (i = 1; i < 8; i++)
  {
    mTxCAN.BUF[i] = 0;
  }

  return;
}


/****************************************************************
DOES:    LSS Switch Mode Global Command
GLOBALS: Sets mLSS.active status flag to FALSE if end-of-LSS
RETURNS: 
*****************************************************************/
UNSIGNED8 LSS_SwitchModeGlobal (
  UNSIGNED8 *pDat
  )
{
  if (*(pDat+1) == 1)
  {
    mLSS.operation_mode = FALSE;
    
    if (gMCOConfig.heartbeat_msg.BUF[0] != NMTSTATE_LSS)
    {
      gMCOConfig.heartbeat_msg.BUF[0] = NMTSTATE_LSS;
      mLSS.active           = TRUE;
    }
  }
  else
  {
    mLSS.operation_mode = TRUE;    

    // If a node is configured, a switch back into operation mode
    // means the node leaves LSS and initializes into CANopen NMT
    if (mLSS.node_id_set)
    {
      // Set module-internal LSS status to leave mLSS. The next call
      // of LSS_Do_LSS() will then re-initialize the node with LSS
      // parameters.
      mLSS.active = FALSE;

      return TRUE;
    }
  }

  return FALSE;
}


/****************************************************************
DOES:    LSS Configure Node ID Command
RETURNS: -
*****************************************************************/
void LSS_ConfigureNodeID (
  UNSIGNED8 *pDat
  )
{
UNSIGNED8 node_id;

  // This command is only accepted in configuration mode but
  // outside of "configure bit timing"!
  if (mLSS.operation_mode) 
  {
    return;
  }

  // Prepare answer
  LSS_InitResponse(LSS_CONF_NID);

  node_id = *(pDat+1);  // Byte 1 in message is node id

  if (node_id > 127)
  {
    mTxCAN.BUF[1] = 1;  // Node ID out of range
  }
  else if (node_id <= 1)
  { // use this to reset all saved LSS info
    mTxCAN.BUF[1] = 1;  // Node ID out of range

    // Erase all current settings
    NVOL_WriteByte(NVOL_LSSNID,0xFF);
    NVOL_WriteByte(NVOL_LSSBPS,0xFF);
    NVOL_WriteByte(NVOL_LSSENA,0xFF);
    NVOL_WriteByte(NVOL_LSSCHK,0xFF);

  }
  else
  {
    mTxCAN.BUF[1] = 0;  // Node ID accepted
      
    mLSS.new_node_id = node_id;
    mLSS.node_id_set = TRUE;

    gMCOConfig.Node_ID = node_id;

   // Memorize this as old node ID for inquiry command
   mLSS.old_node_id    = node_id;
  }

  // Sending message
  if (!MCOHW_PushMessage(&mTxCAN))
  {
    MCOUSER_FatalError(0x0602);
  }
}
  

/****************************************************************
DOES:    LSS Store Configuration Command
RETURNS: -
*****************************************************************/
void LSS_StoreConfiguration(void)
{
UNSIGNED8 lss_chk;

  // This command is only accepted in configuration mode
  if (mLSS.operation_mode)
  {
    return;
  }

  LSS_InitResponse(LSS_STOR_CONF);

  NVOL_WriteByte(NVOL_LSSNID,mLSS.new_node_id);
 
  // After LSS configuration is saved, disable LSS on startup
  NVOL_WriteByte(NVOL_LSSENA,NVOL_LSSENA_VAL);

  // Save checksum
  lss_chk = mLSS.new_node_id;
  lss_chk += NVOL_LSSENA_VAL;
  NVOL_WriteByte(NVOL_LSSCHK,lss_chk);

  if ( (NVOL_ReadByte(NVOL_LSSNID) != mLSS.new_node_id)  ||
       (NVOL_ReadByte(NVOL_LSSENA) != 0x00) ||
       (NVOL_ReadByte(NVOL_LSSCHK) != lss_chk)
     )
  {
    // Storage media access error
    mTxCAN.BUF[1] = 0x02;
  }

  // Sending response
  if (!MCOHW_PushMessage(&mTxCAN))
  {
    MCOUSER_FatalError(0x0602);
  }

  return;
}
  

/****************************************************************
DOES:    LSS Load Configuration Command
RETURNS: -
*****************************************************************/
void LSS_LoadConfiguration (
  UNSIGNED16 *Baudrate,  // returns CAN baudrate, here default
  UNSIGNED8 *Node_ID    // returns CANopen node ID (0-127)
  )
{
UNSIGNED8 nodeid;
UNSIGNED8 lssena;
UNSIGNED8 lsschk;

  // This implementation is for Node ID only, not baudrate
  *Baudrate = gMCOConfig.Baudrate;

  if (gMCOConfig.Node_ID != 0)
  { // only do this if node id is unknown
    *Node_ID = gMCOConfig.Node_ID;
    return;
  }

  // Initialize access to non-volatile memory
  NVOL_Init();

  // Get values
  nodeid = NVOL_ReadByte(NVOL_LSSNID);
  lssena = NVOL_ReadByte(NVOL_LSSENA);
  lsschk = NVOL_ReadByte(NVOL_LSSCHK);

  if ((nodeid > 0) && (nodeid < 128) && ( lsschk == (nodeid+lssena)))
  { // valid LSS configuration found
    *Node_ID = nodeid;
  }
  else
  {
    *Node_ID = 0;
  }
}


/****************************************************************
DOES:    LSS Identify Remote Slaves Commands
RETURNS: -
*****************************************************************/
void LSS_IdentifyRemoteSlaves (
  UNSIGNED8 *pDat
  )
{
// Values received in MicroLSS Master Message
UNSIGNED32 IDNumber;    // current LSS_ID Subindex IDnumber (32bit)
UNSIGNED8  BitChecked;  // current bit requested 0..31 (0x80 for init/restart)
UNSIGNED8  LSSSub;      // current LSS_ID subindex 0..3 (vendor,product,rev,serial)
UNSIGNED8  LSSNext;     // next state for the MicroLSS states

UNSIGNED32 mask;        // compare mask
UNSIGNED8 found;        // return value

  // Initialize variables
  mask = 0;
  found = 0;
 
  // extract 32-bit value from CAN message bytes 1-4
  IDNumber = LSS_GetDword(pDat+1);
  BitChecked = pDat[5]; // 0..31
  LSSSub = pDat[6]; // 0..3 
  LSSNext = pDat[7];

  switch (*pDat)
  {
    case LSS_MICROLSS:
      found = 0;
      if (BitChecked & 0x80)
      { // MicroLSS initialization
        found = 1;
        mLSS.mLSS_state = 0;
      }
      else if (LSSSub == mLSS.mLSS_state)
      { // we are still "on go" for the next 32bit value
        mask = 0xFFFFFFFF << BitChecked;
        if ((LSS_ID[LSSSub] & mask) == (IDNumber & mask))
        { // match
          found = 1;  
          // Set new state as commanded by MicroLSS master
          mLSS.mLSS_state = LSSNext; 
          if (BitChecked == 0)
          { // 32bit scan completed with success
            if (LSSSub == 3)
            { // All done and matched, scan completed, NODE IDENTIFIED
              // Switch node to configuration mode now!
              mLSS.operation_mode = FALSE;
              mLSS.active = TRUE;
              gMCOConfig.heartbeat_msg.BUF[0] = NMTSTATE_LSS;
            }
          }
        }
      }
      
      if (found == 1)
      { // Send a response as long as found
        // Send confirmation
        LSS_InitResponse(LSS_ID_SLAVE);
        // Sending message
        if (!MCOHW_PushMessage(&mTxCAN))
        {
          MCOUSER_FatalError(0x0602);
        }
      }
    default:
      break;
  }

  return;
}


/*******************************************************************************
GLOBAL FUNCTIONS
*******************************************************************************/

/****************************************************************
DOES:    Process all LSS messages. 
RETURNS: 
*****************************************************************/
void LSS_HandleMsg (
  UNSIGNED8 Len,
  UNSIGNED8 *pDat
  )
{
  // Allow LSS commands only in pure-LSS and stopped mode  
  if ( (gMCOConfig.heartbeat_msg.BUF[0] != NMTSTATE_LSS) &&
       (gMCOConfig.heartbeat_msg.BUF[0] != NMTSTATE_STOP) )
  {
    return;
  }

  if (Len == 8)   // must be 8 bytes long!
  {
    switch (*pDat)
    {
      case LSS_SWMOD_GLOB:
        LSS_SwitchModeGlobal(pDat);
        break;

      case LSS_CONF_NID:
        if (gMCOConfig.heartbeat_msg.BUF[0] == NMTSTATE_LSS)
          LSS_ConfigureNodeID(pDat);
        break;

      case LSS_STOR_CONF:
        if (gMCOConfig.heartbeat_msg.BUF[0] == NMTSTATE_LSS)
          LSS_StoreConfiguration();
        break;

      case LSS_MICROLSS:
        if (gMCOConfig.heartbeat_msg.BUF[0] == NMTSTATE_LSS)
          LSS_IdentifyRemoteSlaves(pDat);
        break;

      default:
        break;
    }
  }
}


/****************************************************************
DOES:    Check and update LSS status
RETURNS: FALSE: LSS is finished for this node
         TRUE:  Otherwise (LSS is still in process)
*****************************************************************/
UNSIGNED8 LSS_DoLSS(void)
{
UNSIGNED8 ret_val;

  ret_val = FALSE;
  if (mLSS.active)
  {
    ret_val = TRUE;
  }
  else
  {
    // Has LSS just been finished?
    if (gMCOConfig.heartbeat_msg.BUF[0] == NMTSTATE_LSS)
    {
      // Re-init
      MCOUSER_ResetCommunication();
      ret_val = TRUE;
    }
  }
  return ret_val;
}


/****************************************************************
DOES:    Initialize LSS mechanism (variables etc.)
GLOBALS: Sets mLSS.active status flag to TRUE
         Sets gMCOConfig.nmt_state to NMTSTATE_LSS
RETURNS: -
*****************************************************************/
void LSS_Init(
  UNSIGNED8 node_id
  )
{

  LSS_ID[0] = OD_VENDOR_ID;
  LSS_ID[1] = OD_PRODUCT_CODE;
  LSS_ID[2] = OD_REVISION;
  LSS_ID[3] = LSS_GetDword(&(gProcImg[P101804_SERIAL_NUMBER]));

  // Init MicroLSS state machine
  mLSS.mLSS_state = 0;

  // The Node ID is not yet set
  mLSS.node_id_set    = FALSE;

  // After reset, the node is in operation mode
  mLSS.operation_mode = TRUE;

  // Pre-set LSS baudrate and node ID to default values
  mLSS.new_node_bps   = 4; // 125kbps
  mLSS.new_node_id    = node_id;

  // Memorize the old node ID for inquiry command
  mLSS.old_node_id    = node_id;

  if (node_id != 0)
  { // Stop here if node ID is known
    return;
  }

  // Set receive filter for LSS master message 
  if (!MCOHW_SetCANFilter(LSS_MASTER_ID))
  {
    MCOUSER_FatalError(0x0601);
  }

  // We only get here if node must go in LSS state
  gMCOConfig.heartbeat_msg.BUF[0] = NMTSTATE_LSS;
  mLSS.active         = TRUE;

}

#endif 

/*******************************************************************************
END OF FILE
*******************************************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -