2019-04-02 12:30:27 +02:00
|
|
|
/*
|
|
|
|
* Licensed under the GNU General Public License version 2 with exceptions. See
|
|
|
|
* LICENSE file in the project root for full license information
|
|
|
|
*/
|
2019-01-30 11:07:46 +01:00
|
|
|
#include <stddef.h>
|
|
|
|
#include "esc.h"
|
|
|
|
#include "esc_coe.h"
|
|
|
|
#include "esc_foe.h"
|
2019-04-03 17:58:46 +02:00
|
|
|
#include "esc_eoe.h"
|
2019-01-30 11:07:46 +01:00
|
|
|
#include "ecat_slv.h"
|
|
|
|
|
2019-01-20 15:35:23 +01:00
|
|
|
#define IS_RXPDO(index) ((index) >= 0x1600 && (index) < 0x1800)
|
|
|
|
#define IS_TXPDO(index) ((index) >= 0x1A00 && (index) < 0x1C00)
|
|
|
|
|
2019-01-30 11:07:46 +01:00
|
|
|
/* Global variables used by the stack */
|
2019-04-02 12:30:27 +02:00
|
|
|
uint8_t MBX[MBXBUFFERS * MAX(MBXSIZE,MBXSIZEBOOT)];
|
|
|
|
_MBXcontrol MBXcontrol[MBXBUFFERS];
|
|
|
|
_SMmap SMmap2[MAX_MAPPINGS_SM2];
|
|
|
|
_SMmap SMmap3[MAX_MAPPINGS_SM3];
|
|
|
|
_ESCvar ESCvar;
|
2019-01-30 11:07:46 +01:00
|
|
|
|
|
|
|
/* Private variables */
|
|
|
|
static volatile int watchdog;
|
2019-04-09 12:05:20 +02:00
|
|
|
|
|
|
|
#if MAX_MAPPINGS_SM2 > 0
|
2019-04-02 12:30:27 +02:00
|
|
|
static uint8_t rxpdo[MAX_RXPDO_SIZE] __attribute__((aligned (8)));
|
2019-04-09 12:05:20 +02:00
|
|
|
#else
|
|
|
|
extern uint8_t * rxpdo;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if MAX_MAPPINGS_SM3 > 0
|
2019-04-02 12:30:27 +02:00
|
|
|
static uint8_t txpdo[MAX_TXPDO_SIZE] __attribute__((aligned (8)));
|
2019-04-09 12:05:20 +02:00
|
|
|
#else
|
|
|
|
extern uint8_t * txpdo;
|
|
|
|
#endif
|
2019-01-30 11:07:46 +01:00
|
|
|
|
2019-04-02 21:30:33 +02:00
|
|
|
/** Function to pre-qualify the incoming SDO download.
|
2019-01-30 11:07:46 +01:00
|
|
|
*
|
|
|
|
* @param[in] index = index of SDO download request to check
|
|
|
|
* @param[in] sub-index = sub-index of SDO download request to check
|
2019-01-20 15:35:23 +01:00
|
|
|
* @return SDO abort code, or 0 on success
|
2019-01-30 11:07:46 +01:00
|
|
|
*/
|
2020-06-22 15:01:06 +02:00
|
|
|
uint32_t ESC_download_pre_objecthandler (uint16_t index,
|
2019-01-30 11:07:46 +01:00
|
|
|
uint8_t subindex,
|
|
|
|
void * data,
|
|
|
|
size_t size,
|
2019-04-02 21:26:46 +02:00
|
|
|
uint16_t flags)
|
2019-01-30 11:07:46 +01:00
|
|
|
{
|
2019-01-20 15:35:23 +01:00
|
|
|
if (IS_RXPDO (index) ||
|
|
|
|
IS_TXPDO (index) ||
|
|
|
|
index == RX_PDO_OBJIDX ||
|
|
|
|
index == TX_PDO_OBJIDX)
|
|
|
|
{
|
2020-07-02 11:11:26 +02:00
|
|
|
uint8_t minSub = ((flags & COMPLETE_ACCESS_FLAG) == 0) ? 0 : 1;
|
|
|
|
if (subindex > minSub && COE_maxSub (index) != 0)
|
2019-01-20 15:35:23 +01:00
|
|
|
{
|
2020-06-22 15:01:06 +02:00
|
|
|
return ABORT_SUBINDEX0_NOT_ZERO;
|
2019-01-20 15:35:23 +01:00
|
|
|
}
|
|
|
|
}
|
2019-01-30 11:07:46 +01:00
|
|
|
|
2019-01-20 15:35:23 +01:00
|
|
|
if (ESCvar.pre_object_download_hook)
|
2019-01-30 11:07:46 +01:00
|
|
|
{
|
2020-06-22 15:01:06 +02:00
|
|
|
return (ESCvar.pre_object_download_hook) (index,
|
2019-01-30 11:07:46 +01:00
|
|
|
subindex,
|
|
|
|
data,
|
|
|
|
size,
|
2019-04-02 21:26:46 +02:00
|
|
|
flags);
|
2019-01-30 11:07:46 +01:00
|
|
|
}
|
|
|
|
|
2020-06-22 15:01:06 +02:00
|
|
|
return 0;
|
2019-01-30 11:07:46 +01:00
|
|
|
}
|
|
|
|
|
2019-04-02 21:30:33 +02:00
|
|
|
/** Hook called from the slave stack SDO Download handler to act on
|
2019-01-30 11:07:46 +01:00
|
|
|
* user specified Index and Sub-index.
|
|
|
|
*
|
|
|
|
* @param[in] index = index of SDO download request to handle
|
|
|
|
* @param[in] sub-index = sub-index of SDO download request to handle
|
2020-06-22 15:01:06 +02:00
|
|
|
* @return SDO abort code, or 0 on success
|
2019-01-30 11:07:46 +01:00
|
|
|
*/
|
2020-06-22 15:01:06 +02:00
|
|
|
uint32_t ESC_download_post_objecthandler (uint16_t index, uint8_t subindex, uint16_t flags)
|
2019-01-30 11:07:46 +01:00
|
|
|
{
|
2019-01-20 15:35:23 +01:00
|
|
|
if (ESCvar.post_object_download_hook != NULL)
|
2019-01-30 11:07:46 +01:00
|
|
|
{
|
2020-06-22 15:01:06 +02:00
|
|
|
return (ESCvar.post_object_download_hook)(index, subindex, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Function to pre-qualify the incoming SDO upload.
|
|
|
|
*
|
|
|
|
* @param[in] index = index of SDO upload request to handle
|
|
|
|
* @param[in] sub-index = sub-index of SDO upload request to handle
|
|
|
|
* @return SDO abort code, or 0 on success
|
|
|
|
*/
|
|
|
|
uint32_t ESC_upload_pre_objecthandler (uint16_t index,
|
|
|
|
uint8_t subindex,
|
|
|
|
void * data,
|
|
|
|
size_t size,
|
|
|
|
uint16_t flags)
|
|
|
|
{
|
|
|
|
if (ESCvar.pre_object_upload_hook != NULL)
|
|
|
|
{
|
|
|
|
return (ESCvar.pre_object_upload_hook) (index,
|
|
|
|
subindex,
|
|
|
|
data,
|
|
|
|
size,
|
|
|
|
flags);
|
2019-01-30 11:07:46 +01:00
|
|
|
}
|
2020-06-22 15:01:06 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Hook called from the slave stack SDO Upload handler to act on
|
|
|
|
* user specified Index and Sub-index.
|
|
|
|
*
|
|
|
|
* @param[in] index = index of SDO upload request to handle
|
|
|
|
* @param[in] sub-index = sub-index of SDO upload request to handle
|
|
|
|
* @return SDO abort code, or 0 on success
|
|
|
|
*/
|
|
|
|
uint32_t ESC_upload_post_objecthandler (uint16_t index, uint8_t subindex, uint16_t flags)
|
|
|
|
{
|
|
|
|
if (ESCvar.post_object_upload_hook != NULL)
|
|
|
|
{
|
|
|
|
return (ESCvar.post_object_upload_hook)(index, subindex, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2019-01-30 11:07:46 +01:00
|
|
|
}
|
|
|
|
|
2019-04-02 21:30:33 +02:00
|
|
|
/** Hook called from the slave stack ESC_stopoutputs to act on state changes
|
2019-01-30 11:07:46 +01:00
|
|
|
* forcing us to stop outputs. Here we can set them to a safe state.
|
|
|
|
*/
|
|
|
|
void APP_safeoutput (void)
|
|
|
|
{
|
|
|
|
DPRINT ("APP_safeoutput\n");
|
|
|
|
|
|
|
|
if(ESCvar.safeoutput_override != NULL)
|
|
|
|
{
|
|
|
|
(ESCvar.safeoutput_override)();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-02 21:30:33 +02:00
|
|
|
/** Write local process data to Sync Manager 3, Master Inputs.
|
2019-01-30 11:07:46 +01:00
|
|
|
*/
|
|
|
|
void TXPDO_update (void)
|
|
|
|
{
|
|
|
|
if(ESCvar.txpdo_override != NULL)
|
|
|
|
{
|
|
|
|
(ESCvar.txpdo_override)();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-04-09 12:05:20 +02:00
|
|
|
if (MAX_MAPPINGS_SM3 > 0)
|
|
|
|
{
|
|
|
|
COE_pdoPack (txpdo, ESCvar.sm3mappings, SMmap3);
|
|
|
|
}
|
2019-04-02 12:30:27 +02:00
|
|
|
ESC_write (ESC_SM3_sma, txpdo, ESCvar.ESC_SM3_sml);
|
2019-01-30 11:07:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-02 21:30:33 +02:00
|
|
|
/** Read Sync Manager 2 to local process data, Master Outputs.
|
2019-01-30 11:07:46 +01:00
|
|
|
*/
|
|
|
|
void RXPDO_update (void)
|
|
|
|
{
|
|
|
|
if(ESCvar.rxpdo_override != NULL)
|
|
|
|
{
|
|
|
|
(ESCvar.rxpdo_override)();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-04-02 12:30:27 +02:00
|
|
|
ESC_read (ESC_SM2_sma, rxpdo, ESCvar.ESC_SM2_sml);
|
2019-04-09 12:05:20 +02:00
|
|
|
if (MAX_MAPPINGS_SM2 > 0)
|
|
|
|
{
|
|
|
|
COE_pdoUnpack (rxpdo, ESCvar.sm2mappings, SMmap2);
|
|
|
|
}
|
2019-01-30 11:07:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-02 21:30:33 +02:00
|
|
|
/* Set the watchdog count value, don't have any affect when using
|
|
|
|
* HW watchdog 0x4xx
|
|
|
|
*
|
|
|
|
* @param[in] watchdogcnt = new watchdog count value
|
|
|
|
*/
|
|
|
|
void APP_setwatchdog (int watchdogcnt)
|
|
|
|
{
|
|
|
|
CC_ATOMIC_SET(ESCvar.watchdogcnt, watchdogcnt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Function to update local I/O, call read ethercat outputs, call
|
2019-01-30 11:07:46 +01:00
|
|
|
* write ethercat inputs. Implement watch-dog counter to count-out if we have
|
|
|
|
* made state change affecting the App.state.
|
|
|
|
*/
|
|
|
|
void DIG_process (uint8_t flags)
|
|
|
|
{
|
|
|
|
/* Handle watchdog */
|
|
|
|
if((flags & DIG_PROCESS_WD_FLAG) > 0)
|
|
|
|
{
|
|
|
|
if (CC_ATOMIC_GET(watchdog) > 0)
|
|
|
|
{
|
|
|
|
CC_ATOMIC_SUB(watchdog, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((CC_ATOMIC_GET(watchdog) <= 0) &&
|
|
|
|
((CC_ATOMIC_GET(ESCvar.App.state) & APPSTATE_OUTPUT) > 0))
|
|
|
|
{
|
|
|
|
DPRINT("DIG_process watchdog expired\n");
|
|
|
|
ESC_ALstatusgotoerror((ESCsafeop | ESCerror), ALERR_WATCHDOG);
|
|
|
|
}
|
|
|
|
else if(((CC_ATOMIC_GET(ESCvar.App.state) & APPSTATE_OUTPUT) == 0))
|
|
|
|
{
|
|
|
|
CC_ATOMIC_SET(watchdog, ESCvar.watchdogcnt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle Outputs */
|
|
|
|
if ((flags & DIG_PROCESS_OUTPUTS_FLAG) > 0)
|
|
|
|
{
|
|
|
|
if(((CC_ATOMIC_GET(ESCvar.App.state) & APPSTATE_OUTPUT) > 0) &&
|
|
|
|
(ESCvar.ALevent & ESCREG_ALEVENT_SM2))
|
|
|
|
{
|
|
|
|
RXPDO_update();
|
|
|
|
CC_ATOMIC_SET(watchdog, ESCvar.watchdogcnt);
|
|
|
|
/* Set outputs */
|
|
|
|
cb_set_outputs();
|
|
|
|
}
|
|
|
|
else if (ESCvar.ALevent & ESCREG_ALEVENT_SM2)
|
|
|
|
{
|
|
|
|
RXPDO_update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Call application */
|
|
|
|
if ((flags & DIG_PROCESS_APP_HOOK_FLAG) > 0)
|
|
|
|
{
|
|
|
|
/* Call application callback if set */
|
|
|
|
if (ESCvar.application_hook != NULL)
|
|
|
|
{
|
|
|
|
(ESCvar.application_hook)();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle Inputs */
|
|
|
|
if ((flags & DIG_PROCESS_INPUTS_FLAG) > 0)
|
|
|
|
{
|
|
|
|
if(CC_ATOMIC_GET(ESCvar.App.state) > 0)
|
|
|
|
{
|
|
|
|
/* Update inputs */
|
|
|
|
cb_get_inputs();
|
|
|
|
TXPDO_update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-02 21:30:33 +02:00
|
|
|
/*
|
2019-01-30 11:07:46 +01:00
|
|
|
* Handler for SM change, SM0/1, AL CONTROL and EEPROM events, the application
|
|
|
|
* control what interrupts that should be served and re-activated with
|
|
|
|
* event mask argument
|
|
|
|
*/
|
|
|
|
void ecat_slv_worker (uint32_t event_mask)
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
/* Check the state machine */
|
|
|
|
ESC_state();
|
|
|
|
/* Check the SM activation event */
|
|
|
|
ESC_sm_act_event();
|
|
|
|
|
|
|
|
/* Check mailboxes */
|
|
|
|
while ((ESC_mbxprocess() > 0) || (ESCvar.txcue > 0))
|
|
|
|
{
|
|
|
|
ESC_coeprocess();
|
2019-02-20 14:17:59 +01:00
|
|
|
#if USE_FOE
|
2019-01-30 11:07:46 +01:00
|
|
|
ESC_foeprocess();
|
2019-04-02 12:33:06 +02:00
|
|
|
#endif
|
|
|
|
#if USE_EOE
|
|
|
|
ESC_eoeprocess();
|
2019-02-20 14:17:59 +01:00
|
|
|
#endif
|
2019-01-30 11:07:46 +01:00
|
|
|
ESC_xoeprocess();
|
|
|
|
}
|
2019-04-02 12:33:06 +02:00
|
|
|
#if USE_EOE
|
|
|
|
ESC_eoeprocess_tx();
|
|
|
|
#endif
|
2019-01-30 11:07:46 +01:00
|
|
|
/* Call emulated eeprom handler if set */
|
|
|
|
if (ESCvar.esc_hw_eep_handler != NULL)
|
|
|
|
{
|
|
|
|
(ESCvar.esc_hw_eep_handler)();
|
|
|
|
}
|
|
|
|
|
|
|
|
CC_ATOMIC_SET(ESCvar.ALevent, ESC_ALeventread());
|
|
|
|
|
|
|
|
}while(ESCvar.ALevent & event_mask);
|
|
|
|
|
|
|
|
ESC_ALeventmaskwrite(ESC_ALeventmaskread() | event_mask);
|
|
|
|
}
|
|
|
|
|
2019-04-02 21:30:33 +02:00
|
|
|
/*
|
2019-01-30 11:07:46 +01:00
|
|
|
* Polling function. It should be called periodically for an application
|
|
|
|
* when only SM2/DC interrupt is active.
|
|
|
|
* Read and handle events for the EtherCAT state, status, mailbox and eeprom.
|
|
|
|
*/
|
|
|
|
void ecat_slv_poll (void)
|
|
|
|
{
|
|
|
|
/* Read local time from ESC*/
|
|
|
|
ESC_read (ESCREG_LOCALTIME, (void *) &ESCvar.Time, sizeof (ESCvar.Time));
|
|
|
|
ESCvar.Time = etohl (ESCvar.Time);
|
|
|
|
|
|
|
|
/* Check the state machine */
|
|
|
|
ESC_state();
|
|
|
|
/* Check the SM activation event */
|
|
|
|
ESC_sm_act_event();
|
|
|
|
|
|
|
|
/* Check mailboxes */
|
|
|
|
if (ESC_mbxprocess())
|
|
|
|
{
|
|
|
|
ESC_coeprocess();
|
2019-02-20 14:17:59 +01:00
|
|
|
#if USE_FOE
|
2019-01-30 11:07:46 +01:00
|
|
|
ESC_foeprocess();
|
2019-04-02 12:33:06 +02:00
|
|
|
#endif
|
|
|
|
#if USE_EOE
|
|
|
|
ESC_eoeprocess();
|
2019-02-20 14:17:59 +01:00
|
|
|
#endif
|
2019-01-30 11:07:46 +01:00
|
|
|
ESC_xoeprocess();
|
|
|
|
}
|
2019-04-02 12:33:06 +02:00
|
|
|
#if USE_EOE
|
|
|
|
ESC_eoeprocess_tx();
|
|
|
|
#endif
|
2019-01-30 11:07:46 +01:00
|
|
|
|
|
|
|
/* Call emulated eeprom handler if set */
|
|
|
|
if (ESCvar.esc_hw_eep_handler != NULL)
|
|
|
|
{
|
|
|
|
(ESCvar.esc_hw_eep_handler)();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-02 21:30:33 +02:00
|
|
|
/*
|
|
|
|
* Poll all events in a free-run application
|
|
|
|
*/
|
2019-01-30 11:07:46 +01:00
|
|
|
void ecat_slv (void)
|
|
|
|
{
|
|
|
|
ecat_slv_poll();
|
|
|
|
DIG_process(DIG_PROCESS_WD_FLAG | DIG_PROCESS_OUTPUTS_FLAG |
|
|
|
|
DIG_PROCESS_APP_HOOK_FLAG | DIG_PROCESS_INPUTS_FLAG);
|
|
|
|
}
|
|
|
|
|
2019-04-02 21:30:33 +02:00
|
|
|
/*
|
2019-01-30 11:07:46 +01:00
|
|
|
* Initialize the slave stack.
|
|
|
|
*/
|
|
|
|
void ecat_slv_init (esc_cfg_t * config)
|
|
|
|
{
|
|
|
|
DPRINT ("Slave stack init started\n");
|
|
|
|
|
|
|
|
/* Init watchdog */
|
|
|
|
watchdog = config->watchdog_cnt;
|
|
|
|
|
|
|
|
/* Call stack configuration */
|
|
|
|
ESC_config (config);
|
|
|
|
/* Call HW init */
|
|
|
|
ESC_init (config);
|
|
|
|
|
|
|
|
/* wait until ESC is started up */
|
|
|
|
while ((ESCvar.DLstatus & 0x0001) == 0)
|
|
|
|
{
|
|
|
|
ESC_read (ESCREG_DLSTATUS, (void *) &ESCvar.DLstatus,
|
|
|
|
sizeof (ESCvar.DLstatus));
|
|
|
|
ESCvar.DLstatus = etohs (ESCvar.DLstatus);
|
|
|
|
}
|
|
|
|
|
2019-02-20 14:17:59 +01:00
|
|
|
#if USE_FOE
|
2019-01-30 11:07:46 +01:00
|
|
|
/* Init FoE */
|
2020-07-01 21:31:27 +02:00
|
|
|
FOE_init ();
|
2019-02-20 14:17:59 +01:00
|
|
|
#endif
|
2019-01-30 11:07:46 +01:00
|
|
|
|
2019-04-02 12:33:06 +02:00
|
|
|
#if USE_EOE
|
|
|
|
/* Init EoE */
|
2020-07-01 21:31:27 +02:00
|
|
|
EOE_init ();
|
2019-04-02 12:33:06 +02:00
|
|
|
#endif
|
|
|
|
|
2019-01-30 11:07:46 +01:00
|
|
|
/* reset ESC to init state */
|
|
|
|
ESC_ALstatus (ESCinit);
|
|
|
|
ESC_ALerror (ALERR_NONE);
|
2020-07-01 21:31:27 +02:00
|
|
|
ESC_stopmbx ();
|
|
|
|
ESC_stopinput ();
|
|
|
|
ESC_stopoutput ();
|
|
|
|
/* Init Object Dictionary default values */
|
|
|
|
COE_initDefaultValues ();
|
2019-01-30 11:07:46 +01:00
|
|
|
}
|