📄 mlssslv.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 + -