/* main ***********************************************************************/
int main(void) {
    CO_NMT_reset_cmd_t reset = CO_RESET_NOT;

    InitCanLeds();
    DBGU_Configure(115200);
    TRACE_INFO_WP("\n\rCanOpenNode %s (%s %s)\n\r", cVer, __DATE__, __TIME__);
    /* Configure Timer interrupt function for execution every 1 millisecond */
    if (SysTick_Config(SysTick_1ms))
        TRACE_FATAL("SysTick_Config\n\r");
    initTimer(getTimer_us);

    /* Todo: initialize EEPROM */

    /*  Todo: Loading COD */
    TRACE_INFO("Loading COD\n\r");

    /* Verify, if OD structures have proper alignment of initial values */
    TRACE_DEBUG("Checking COD in RAM (size=%d)\n\r", &CO_OD_RAM.LastWord - &CO_OD_RAM.FirstWord);
    if (CO_OD_RAM.FirstWord != CO_OD_RAM.LastWord)
        TRACE_FATAL("Err COD in RAM\n\r");
    TRACE_DEBUG("Checking COD in EEPROM (size=%d)\n\r", &CO_OD_EEPROM.LastWord - &CO_OD_EEPROM.FirstWord);
    if (CO_OD_EEPROM.FirstWord != CO_OD_EEPROM.LastWord)
        TRACE_FATAL("Err COD in EEPROM\n\r");
    TRACE_DEBUG("Checking COD in ROM (size=%d)\n\r", &CO_OD_ROM.LastWord - &CO_OD_ROM.FirstWord);
    if (CO_OD_ROM.FirstWord != CO_OD_ROM.LastWord)
        TRACE_FATAL("Err COD in ROM\n\r");

    /* increase variable each startup. Variable is stored in eeprom. */
    OD_powerOnCounter++;

    TRACE_INFO("CO power-on (BTR=%dk Node=0x%x)\n\r", CO_OD_ROM.CANBitRate, CO_OD_ROM.CANNodeID);
    ttimer tprof;
    while (reset != CO_RESET_APP) {
        /* CANopen communication reset - initialize CANopen objects *******************/
        static uint32_t timer1msPrevious;
        CO_ReturnError_t err;

        /* disable timer interrupts, turn on red LED */
        canTimerOff = 1;
        CanLedsSet(eCoLed_Red);

        /* initialize CANopen */
        err = CO_init();
        if (err) {
            TRACE_FATAL("CO_init\n\r");
            /* CO_errorReport(CO->em, CO_EM_MEMORY_ALLOCATION_ERROR, CO_EMC_SOFTWARE_INTERNAL, err); */
        }

        /* start Timer */
        canTimerOff = 0;

        reset = CO_RESET_NOT;
        timer1msPrevious = CO_timer1ms;

        TRACE_INFO("CO (re)start\n\r");
        while (reset == CO_RESET_NOT) {
            saveTime(&tprof);
            /* loop for normal program execution ******************************************/
            uint32_t timer1msDiff;

            timer1msDiff = CO_timer1ms - timer1msPrevious;
            timer1msPrevious = CO_timer1ms;

            ClearWDT();

            /* CANopen process */
            reset = CO_process(CO, timer1msDiff);

            CanLedsSet((LED_GREEN_RUN(CO->NMT)>0 ? eCoLed_Green : 0) | (LED_RED_ERROR(CO->NMT)>0 ? eCoLed_Red : 0));

            ClearWDT();

            /* (not implemented) eeprom_process(&eeprom); */
            uint32_t t = getTime_us(&tprof);
            OD_performance[ODA_performance_mainCycleTime] = t;
            if (t > OD_performance[ODA_performance_mainCycleMaxTime])
                OD_performance[ODA_performance_mainCycleMaxTime] = t;

        } /*  while (reset != 0) */
    } /*  while (reset != 2) */
    /* program exit ***************************************************************/
    /* save variables to eeprom */
    CO_DISABLE_INTERRUPTS();

    CanLedsSet(eCoLed_None);
    /* (not implemented) eeprom_saveAll(&eeprom); */
    CanLedsSet(eCoLed_Red);
    /* delete CANopen object from memory */
    CO_delete();

    /* reset - by WD */
    return 0;
}
Exemple #2
0
/* main ***********************************************************************/
int main (void){
    unsigned int temp_ui;
    CO_NMT_reset_cmd_t reset = CO_RESET_NOT;

    /* Configure system for maximum performance. plib is necessary for that.*/
    /* SYSTEMConfig(CO_FSYS*1000, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE); */

    /* Enable system multi vectored interrupts */
    INTCONbits.MVEC = 1;
    __builtin_enable_interrupts();

    /* Disable JTAG and trace port */
    DDPCONbits.JTAGEN = 0;
    DDPCONbits.TROEN = 0;


    /* Verify, if OD structures have proper alignment of initial values */
    if(CO_OD_RAM.FirstWord != CO_OD_RAM.LastWord) while(1) CO_clearWDT();
    if(CO_OD_EEPROM.FirstWord != CO_OD_EEPROM.LastWord) while(1) CO_clearWDT();
    if(CO_OD_ROM.FirstWord != CO_OD_ROM.LastWord) while(1) CO_clearWDT();


    /* initialize EEPROM - part 1 */
#ifdef USE_EEPROM
    CO_ReturnError_t eeStatus = CO_EE_init_1(&CO_EEO, (uint8_t*) &CO_OD_EEPROM, sizeof(CO_OD_EEPROM),
                            (uint8_t*) &CO_OD_ROM, sizeof(CO_OD_ROM));
#endif


    programStart();


    /* increase variable each startup. Variable is stored in eeprom. */
    OD_powerOnCounter++;


    while(reset != CO_RESET_APP){
/* CANopen communication reset - initialize CANopen objects *******************/
        CO_ReturnError_t err;
        uint16_t timer1msPrevious;
        uint16_t TMR_TMR_PREV = 0;
        uint8_t nodeId;
        uint16_t CANBitRate;

        /* disable timer and CAN interrupts */
        CO_TMR_ISR_ENABLE = 0;
        CO_CAN_ISR_ENABLE = 0;
        CO_CAN_ISR2_ENABLE = 0;

        /* Read CANopen Node-ID and CAN bit-rate from object dictionary */
        nodeId = OD_CANNodeID;
        if(nodeId<1 || nodeId>127) nodeId = 0x10;
        CANBitRate = OD_CANBitRate;/* in kbps */

        /* initialize CANopen */
        err = CO_init(ADDR_CAN1, nodeId, CANBitRate);
        if(err != CO_ERROR_NO){
            while(1) CO_clearWDT();
            /* CO_errorReport(CO->em, CO_EM_MEMORY_ALLOCATION_ERROR, CO_EMC_SOFTWARE_INTERNAL, err); */
        }


        /* initialize eeprom - part 2 */
#ifdef USE_EEPROM
        CO_EE_init_2(&CO_EEO, eeStatus, CO->SDO, CO->em);
#endif


        /* initialize variables */
        timer1msPrevious = CO_timer1ms;
        OD_performance[ODA_performance_mainCycleMaxTime] = 0;
        OD_performance[ODA_performance_timerCycleMaxTime] = 0;
        reset = CO_RESET_NOT;



        /* Configure Timer interrupt function for execution every 1 millisecond */
        CO_TMR_CON = 0;
        CO_TMR_TMR = 0;
        #if CO_PBCLK > 65000
            #error wrong timer configuration
        #endif
        CO_TMR_PR = CO_PBCLK - 1;  /* Period register */
        CO_TMR_CON = 0x8000;       /* start timer (TON=1) */
        CO_TMR_ISR_FLAG = 0;       /* clear interrupt flag */
        CO_TMR_ISR_PRIORITY = 3;   /* interrupt - set lower priority than CAN (set the same value in interrupt) */

        /* Configure CAN1 Interrupt (Combined) */
        CO_CAN_ISR_FLAG = 0;       /* CAN1 Interrupt - Clear flag */
        CO_CAN_ISR_PRIORITY = 5;   /* CAN1 Interrupt - Set higher priority than timer (set the same value in '#define CO_CAN_ISR_PRIORITY') */
        CO_CAN_ISR2_FLAG = 0;      /* CAN2 Interrupt - Clear flag */
        CO_CAN_ISR2_PRIORITY = 5;  /* CAN Interrupt - Set higher priority than timer (set the same value in '#define CO_CAN_ISR_PRIORITY') */


        communicationReset();


        /* start CAN and enable interrupts */
        CO_CANsetNormalMode(ADDR_CAN1);
        CO_TMR_ISR_ENABLE = 1;
        CO_CAN_ISR_ENABLE = 1;

#if CO_NO_CAN_MODULES >= 2
        CO_CANsetNormalMode(ADDR_CAN2);
        CO_CAN_ISR2_ENABLE = 1;
#endif


        while(reset == CO_RESET_NOT){
/* loop for normal program execution ******************************************/
            uint16_t timer1msCopy, timer1msDiff;

            CO_clearWDT();


            /* calculate cycle time for performance measurement */
            timer1msCopy = CO_timer1ms;
            timer1msDiff = timer1msCopy - timer1msPrevious;
            timer1msPrevious = timer1msCopy;
            uint16_t t0 = CO_TMR_TMR;
            uint16_t t = t0;
            if(t >= TMR_TMR_PREV){
                t = t - TMR_TMR_PREV;
                t = (timer1msDiff * 100) + (t / (CO_PBCLK / 100));
            }
            else if(timer1msDiff){
                t = TMR_TMR_PREV - t;
                t = (timer1msDiff * 100) - (t / (CO_PBCLK / 100));
            }
            else t = 0;
            OD_performance[ODA_performance_mainCycleTime] = t;
            if(t > OD_performance[ODA_performance_mainCycleMaxTime])
                OD_performance[ODA_performance_mainCycleMaxTime] = t;
            TMR_TMR_PREV = t0;


            /* Application asynchronous program */
            programAsync(timer1msDiff);

            CO_clearWDT();


            /* CANopen process */
            reset = CO_process(CO, timer1msDiff, NULL);

            CO_clearWDT();


#ifdef USE_EEPROM
            CO_EE_process(&CO_EEO);
#endif
        }
    }


/* program exit ***************************************************************/
//    CO_DISABLE_INTERRUPTS();

    /* delete objects from memory */
    programEnd();
    CO_delete(ADDR_CAN1);

    /* reset */
    SYSKEY = 0x00000000;
    SYSKEY = 0xAA996655;
    SYSKEY = 0x556699AA;
    RSWRSTSET = 1;
    temp_ui = RSWRST;
    while(1);
}
Exemple #3
0
int main(void)
{


    uint32_t timer1msDiff;  
    uint32_t t;
    static uint32_t timer1msPrevious;

    CO_NMT_reset_cmd_t reset = CO_RESET_NOT;

    HAL_Init();

  /* Configure the system clock to 48 MHz */
     SystemClock_Config();
  
  /* Enable GPIOA Clock                  */
     LED_GPIOA_CLK_ENABLE();

  /* Enable CAN peripherals              */
     CAN_CLK_ENABLE();            
     CAN_GPIO_CLK_ENABLE();
      
    // debug_printf("This is a pass test");
         
  /* Initialize LEDs                     */
    InitCanLeds();  /* -3- Toggle IOs in an infinite loop */

    CanLedsSet(CoLed_Green);
   // CanLedsSet(CoLed_Red);
   // CanLedsSet(CoLed_Blue);
   // CanLedsSet(CoLed_Yellow);
  

  /* Configure Timer interrupt function for execution every 1 ms*/
    TIMER_InitRCC();
    TIMER_InitGeneral();

    /* Program start - Application Call     */
    programStart();


    while (reset != CO_RESET_APP) {
       
    /* disable timer interrupts */
    NVIC_DisableIRQ(TIM2_IRQn);
    
    /* CANopen communication reset - initialize CANopen objects; CanOpen is initialized from within communication reset function */
    communicationReset();   

      /* start Timer interupts*/
      NVIC_EnableIRQ(TIM2_IRQn);

      reset = CO_RESET_NOT;
      timer1msPrevious = timer1ms;

    while (reset == CO_RESET_NOT) {

   /* loop for normal program execution */
      timer1msDiff = timer1ms - timer1msPrevious;
      timer1msPrevious = timer1ms;


    /* Program Async for SDO and NMT messages */
       reset = programAsync(timer1msDiff);


    // t = getTime_us(&tprof);   // 
       t = 100;
       OD_performance[ODA_performance_mainCycleTime] = t;
       if (t > OD_performance[ODA_performance_mainCycleMaxTime])
       OD_performance[ODA_performance_mainCycleMaxTime] = t;

    } /*  while (reset != 0) */
}     /*  while (reset != 2) */
   
    
    /* program exit  */

    CO_DISABLE_INTERRUPTS();

    CanLedsSet(CoLed_None);
    CanLedsSet(CoLed_Red);

    /* delete CANopen object from memory */
    CO_delete();



}
Exemple #4
0
/* main ***********************************************************************/
int main (void){
    CO_NMT_reset_cmd_t reset = CO_RESET_NOT;

    /* Configure microcontroller. */


    /* initialize EEPROM */


    /* increase variable each startup. Variable is stored in EEPROM. */
    OD_powerOnCounter++;


    while(reset != CO_RESET_APP){
/* CANopen communication reset - initialize CANopen objects *******************/
        CO_ReturnError_t err;
        uint16_t timer1msPrevious;

        /* disable timer and CAN interrupts */
        CO_CAN_OK = false;


        /* initialize CANopen */
        err = CO_init(0/* CAN module address */, 10/* NodeID */, 125 /* bit rate */);
        if(err != CO_ERROR_NO){
            while(1);
            /* CO_errorReport(CO->em, CO_EM_MEMORY_ALLOCATION_ERROR, CO_EMC_SOFTWARE_INTERNAL, err); */
        }


        /* set callback functions for task control. */


        /* Configure Timer interrupt function for execution every 1 millisecond */


        /* Configure CAN transmit and receive interrupt */


        /* start CAN */
        CO_CANsetNormalMode(CO->CANmodule[0]);
        CO_CAN_OK = true;

        reset = CO_RESET_NOT;
        timer1msPrevious = CO_timer1ms;

        while(reset == CO_RESET_NOT){
/* loop for normal program execution ******************************************/
            uint16_t timer1msCopy, timer1msDiff;

            timer1msCopy = CO_timer1ms;
            timer1msDiff = timer1msCopy - timer1msPrevious;
            timer1msPrevious = timer1msCopy;


            /* CANopen process */
            reset = CO_process(CO, timer1msDiff);

            /* Nonblocking application code may go here. */

            /* Process EEPROM */
        }
    }


/* program exit ***************************************************************/
    /* stop threads */


    /* delete objects from memory */
    CO_delete(0/* CAN module address */);


    /* reset */
    return 0;
}
Exemple #5
0
CO_ReturnError_t CO_init(
        int32_t                 CANbaseAddress,
        uint8_t                 nodeId,
        uint16_t                bitRate)
{

    int16_t i;
    CO_ReturnError_t err;
#ifndef CO_USE_GLOBALS
    uint16_t errCnt;
#endif
#if CO_NO_TRACE > 0
    uint32_t CO_traceBufferSize[CO_NO_TRACE];
#endif

    /* Verify parameters from CO_OD */
    if(   sizeof(OD_TPDOCommunicationParameter_t) != sizeof(CO_TPDOCommPar_t)
       || sizeof(OD_TPDOMappingParameter_t) != sizeof(CO_TPDOMapPar_t)
       || sizeof(OD_RPDOCommunicationParameter_t) != sizeof(CO_RPDOCommPar_t)
       || sizeof(OD_RPDOMappingParameter_t) != sizeof(CO_RPDOMapPar_t))
    {
        return CO_ERROR_PARAMETERS;
    }

    #if CO_NO_SDO_CLIENT == 1
    if(sizeof(OD_SDOClientParameter_t) != sizeof(CO_SDOclientPar_t)){
        return CO_ERROR_PARAMETERS;
    }
    #endif


    /* Initialize CANopen object */
#ifdef CO_USE_GLOBALS
    CO = &COO;

    CO->CANmodule[0]                    = &COO_CANmodule;
    CO_CANmodule_rxArray0               = &COO_CANmodule_rxArray0[0];
    CO_CANmodule_txArray0               = &COO_CANmodule_txArray0[0];
    for(i=0; i<CO_NO_SDO_SERVER; i++)
        CO->SDO[i]                      = &COO_SDO[i];
    CO_SDO_ODExtensions                 = &COO_SDO_ODExtensions[0];
    CO->em                              = &COO_EM;
    CO->emPr                            = &COO_EMpr;
    CO->NMT                             = &COO_NMT;
    CO->SYNC                            = &COO_SYNC;
    for(i=0; i<CO_NO_RPDO; i++)
        CO->RPDO[i]                     = &COO_RPDO[i];
    for(i=0; i<CO_NO_TPDO; i++)
        CO->TPDO[i]                     = &COO_TPDO[i];
    CO->HBcons                          = &COO_HBcons;
    CO_HBcons_monitoredNodes            = &COO_HBcons_monitoredNodes[0];
  #if CO_NO_SDO_CLIENT == 1
    CO->SDOclient                       = &COO_SDOclient;
  #endif
  #if CO_NO_TRACE > 0
    for(i=0; i<CO_NO_TRACE; i++) {
        CO->trace[i]                    = &COO_trace[i];
        CO_traceTimeBuffers[i]          = &COO_traceTimeBuffers[i][0];
        CO_traceValueBuffers[i]         = &COO_traceValueBuffers[i][0];
        CO_traceBufferSize[i]           = CO_TRACE_BUFFER_SIZE_FIXED;
    }
  #endif
#else
    if(CO == NULL){    /* Use malloc only once */
        CO = &COO;
        CO->CANmodule[0]                    = (CO_CANmodule_t *)    calloc(1, sizeof(CO_CANmodule_t));
        CO_CANmodule_rxArray0               = (CO_CANrx_t *)        calloc(CO_RXCAN_NO_MSGS, sizeof(CO_CANrx_t));
        CO_CANmodule_txArray0               = (CO_CANtx_t *)        calloc(CO_TXCAN_NO_MSGS, sizeof(CO_CANtx_t));
        for(i=0; i<CO_NO_SDO_SERVER; i++){
            CO->SDO[i]                      = (CO_SDO_t *)          calloc(1, sizeof(CO_SDO_t));
        }
        CO_SDO_ODExtensions                 = (CO_OD_extension_t*)  calloc(CO_OD_NoOfElements, sizeof(CO_OD_extension_t));
        CO->em                              = (CO_EM_t *)           calloc(1, sizeof(CO_EM_t));
        CO->emPr                            = (CO_EMpr_t *)         calloc(1, sizeof(CO_EMpr_t));
        CO->NMT                             = (CO_NMT_t *)          calloc(1, sizeof(CO_NMT_t));
        CO->SYNC                            = (CO_SYNC_t *)         calloc(1, sizeof(CO_SYNC_t));
        for(i=0; i<CO_NO_RPDO; i++){
            CO->RPDO[i]                     = (CO_RPDO_t *)         calloc(1, sizeof(CO_RPDO_t));
        }
        for(i=0; i<CO_NO_TPDO; i++){
            CO->TPDO[i]                     = (CO_TPDO_t *)         calloc(1, sizeof(CO_TPDO_t));
        }
        CO->HBcons                          = (CO_HBconsumer_t *)   calloc(1, sizeof(CO_HBconsumer_t));
        CO_HBcons_monitoredNodes            = (CO_HBconsNode_t *)   calloc(CO_NO_HB_CONS, sizeof(CO_HBconsNode_t));
      #if CO_NO_SDO_CLIENT == 1
        CO->SDOclient                       = (CO_SDOclient_t *)    calloc(1, sizeof(CO_SDOclient_t));
      #endif
      #if CO_NO_TRACE > 0
        for(i=0; i<CO_NO_TRACE; i++) {
            CO->trace[i]                    = (CO_trace_t *)        calloc(1, sizeof(CO_trace_t));
            CO_traceTimeBuffers[i]          = (uint32_t *)          calloc(OD_traceConfig[i].size, sizeof(uint32_t));
            CO_traceValueBuffers[i]         = (int32_t *)           calloc(OD_traceConfig[i].size, sizeof(int32_t));
            if(CO_traceTimeBuffers[i] != NULL && CO_traceValueBuffers[i] != NULL) {
                CO_traceBufferSize[i] = OD_traceConfig[i].size;
            } else {
                CO_traceBufferSize[i] = 0;
            }
        }
      #endif
    }

    CO_memoryUsed = sizeof(CO_CANmodule_t)
                  + sizeof(CO_CANrx_t) * CO_RXCAN_NO_MSGS
                  + sizeof(CO_CANtx_t) * CO_TXCAN_NO_MSGS
                  + sizeof(CO_SDO_t) * CO_NO_SDO_SERVER
                  + sizeof(CO_OD_extension_t) * CO_OD_NoOfElements
                  + sizeof(CO_EM_t)
                  + sizeof(CO_EMpr_t)
                  + sizeof(CO_NMT_t)
                  + sizeof(CO_SYNC_t)
                  + sizeof(CO_RPDO_t) * CO_NO_RPDO
                  + sizeof(CO_TPDO_t) * CO_NO_TPDO
                  + sizeof(CO_HBconsumer_t)
                  + sizeof(CO_HBconsNode_t) * CO_NO_HB_CONS
  #if CO_NO_SDO_CLIENT == 1
                  + sizeof(CO_SDOclient_t)
  #endif
                  + 0;
  #if CO_NO_TRACE > 0
    CO_memoryUsed += sizeof(CO_trace_t) * CO_NO_TRACE;
    for(i=0; i<CO_NO_TRACE; i++) {
        CO_memoryUsed += CO_traceBufferSize[i] * 8;
    }
  #endif

    errCnt = 0;
    if(CO->CANmodule[0]                 == NULL) errCnt++;
    if(CO_CANmodule_rxArray0            == NULL) errCnt++;
    if(CO_CANmodule_txArray0            == NULL) errCnt++;
    for(i=0; i<CO_NO_SDO_SERVER; i++){
        if(CO->SDO[i]                   == NULL) errCnt++;
    }
    if(CO_SDO_ODExtensions              == NULL) errCnt++;
    if(CO->em                           == NULL) errCnt++;
    if(CO->emPr                         == NULL) errCnt++;
    if(CO->NMT                          == NULL) errCnt++;
    if(CO->SYNC                         == NULL) errCnt++;
    for(i=0; i<CO_NO_RPDO; i++){
        if(CO->RPDO[i]                  == NULL) errCnt++;
    }
    for(i=0; i<CO_NO_TPDO; i++){
        if(CO->TPDO[i]                  == NULL) errCnt++;
    }
    if(CO->HBcons                       == NULL) errCnt++;
    if(CO_HBcons_monitoredNodes         == NULL) errCnt++;
  #if CO_NO_SDO_CLIENT == 1
    if(CO->SDOclient                    == NULL) errCnt++;
  #endif
  #if CO_NO_TRACE > 0
    for(i=0; i<CO_NO_TRACE; i++) {
        if(CO->trace[i]                 == NULL) errCnt++;
    }
  #endif

    if(errCnt != 0) return CO_ERROR_OUT_OF_MEMORY;
#endif


    CO->CANmodule[0]->CANnormal = false;
    CO_CANsetConfigurationMode(CANbaseAddress);

    /* Verify CANopen Node-ID */
    if(nodeId<1 || nodeId>127) nodeId = 0x10;


    err = CO_CANmodule_init(
            CO->CANmodule[0],
            CANbaseAddress,
            CO_CANmodule_rxArray0,
            CO_RXCAN_NO_MSGS,
            CO_CANmodule_txArray0,
            CO_TXCAN_NO_MSGS,
            bitRate);

    if(err){CO_delete(CANbaseAddress); return err;}

    for (i=0; i<CO_NO_SDO_SERVER; i++)
    {
        uint32_t COB_IDClientToServer;
        uint32_t COB_IDServerToClient;
        if(i==0){
            /*Default SDO server must be located at first index*/
            COB_IDClientToServer = CO_CAN_ID_RSDO + nodeId;
            COB_IDServerToClient = CO_CAN_ID_TSDO + nodeId;
        }else{
            COB_IDClientToServer = OD_SDOServerParameter[i].COB_IDClientToServer;
            COB_IDServerToClient = OD_SDOServerParameter[i].COB_IDServerToClient;
        }

        err = CO_SDO_init(
                CO->SDO[i],
                COB_IDClientToServer,
                COB_IDServerToClient,
                OD_H1200_SDO_SERVER_PARAM+i,
                i==0 ? 0 : CO->SDO[0],
               &CO_OD[0],
                CO_OD_NoOfElements,
                CO_SDO_ODExtensions,
                nodeId,
                CO->CANmodule[0],
                CO_RXCAN_SDO_SRV+i,
                CO->CANmodule[0],
                CO_TXCAN_SDO_SRV+i);
    }

    if(err){CO_delete(CANbaseAddress); return err;}


    err = CO_EM_init(
            CO->em,
            CO->emPr,
            CO->SDO[0],
           &OD_errorStatusBits[0],
            ODL_errorStatusBits_stringLength,
           &OD_errorRegister,
           &OD_preDefinedErrorField[0],
            ODL_preDefinedErrorField_arrayLength,
            CO->CANmodule[0],
            CO_TXCAN_EMERG,
            CO_CAN_ID_EMERGENCY + nodeId);

    if(err){CO_delete(CANbaseAddress); return err;}


    err = CO_NMT_init(
            CO->NMT,
            CO->emPr,
            nodeId,
            500,
            CO->CANmodule[0],
            CO_RXCAN_NMT,
            CO_CAN_ID_NMT_SERVICE,
            CO->CANmodule[0],
            CO_TXCAN_HB,
            CO_CAN_ID_HEARTBEAT + nodeId);

    if(err){CO_delete(CANbaseAddress); return err;}


#if CO_NO_NMT_MASTER == 1
    NMTM_txBuff = CO_CANtxBufferInit(/* return pointer to 8-byte CAN data buffer, which should be populated */
            CO->CANmodule[0], /* pointer to CAN module used for sending this message */
            CO_TXCAN_NMT,     /* index of specific buffer inside CAN module */
            0x0000,           /* CAN identifier */
            0,                /* rtr */
            2,                /* number of data bytes */
            0);               /* synchronous message flag bit */
#endif


    err = CO_SYNC_init(
            CO->SYNC,
            CO->em,
            CO->SDO[0],
           &CO->NMT->operatingState,
            OD_COB_ID_SYNCMessage,
            OD_communicationCyclePeriod,
            OD_synchronousCounterOverflowValue,
            CO->CANmodule[0],
            CO_RXCAN_SYNC,
            CO->CANmodule[0],
            CO_TXCAN_SYNC);

    if(err){CO_delete(CANbaseAddress); return err;}


    for(i=0; i<CO_NO_RPDO; i++){
        CO_CANmodule_t *CANdevRx = CO->CANmodule[0];
        uint16_t CANdevRxIdx = CO_RXCAN_RPDO + i;

        err = CO_RPDO_init(
                CO->RPDO[i],
                CO->em,
                CO->SDO[0],
               &CO->NMT->operatingState,
                nodeId,
                ((i<4) ? (CO_CAN_ID_RPDO_1+i*0x100) : 0),
                0,
                (CO_RPDOCommPar_t*) &OD_RPDOCommunicationParameter[i],
                (CO_RPDOMapPar_t*) &OD_RPDOMappingParameter[i],
                OD_H1400_RXPDO_1_PARAM+i,
                OD_H1600_RXPDO_1_MAPPING+i,
                CANdevRx,
                CANdevRxIdx);

        if(err){CO_delete(CANbaseAddress); return err;}
    }


    for(i=0; i<CO_NO_TPDO; i++){
        err = CO_TPDO_init(
                CO->TPDO[i],
                CO->em,
                CO->SDO[0],
               &CO->NMT->operatingState,
                nodeId,
                ((i<4) ? (CO_CAN_ID_TPDO_1+i*0x100) : 0),
                0,
                (CO_TPDOCommPar_t*) &OD_TPDOCommunicationParameter[i],
                (CO_TPDOMapPar_t*) &OD_TPDOMappingParameter[i],
                OD_H1800_TXPDO_1_PARAM+i,
                OD_H1A00_TXPDO_1_MAPPING+i,
                CO->CANmodule[0],
                CO_TXCAN_TPDO+i);

        if(err){CO_delete(CANbaseAddress); return err;}
    }


    err = CO_HBconsumer_init(
            CO->HBcons,
            CO->em,
            CO->SDO[0],
           &OD_consumerHeartbeatTime[0],
            CO_HBcons_monitoredNodes,
            CO_NO_HB_CONS,
            CO->CANmodule[0],
            CO_RXCAN_CONS_HB);

    if(err){CO_delete(CANbaseAddress); return err;}


#if CO_NO_SDO_CLIENT == 1
    err = CO_SDOclient_init(
            CO->SDOclient,
            CO->SDO[0],
            (CO_SDOclientPar_t*) &OD_SDOClientParameter[0],
            CO->CANmodule[0],
            CO_RXCAN_SDO_CLI,
            CO->CANmodule[0],
            CO_TXCAN_SDO_CLI);

    if(err){CO_delete(CANbaseAddress); return err;}
#endif


#if CO_NO_TRACE > 0
    for(i=0; i<CO_NO_TRACE; i++) {
        CO_trace_init(
            CO->trace[i],
            CO->SDO[0],
            OD_traceConfig[i].axisNo,
            CO_traceTimeBuffers[i],
            CO_traceValueBuffers[i],
            CO_traceBufferSize[i],
            &OD_traceConfig[i].map,
            &OD_traceConfig[i].format,
            &OD_traceConfig[i].trigger,
            &OD_traceConfig[i].threshold,
            &OD_trace[i].value,
            &OD_trace[i].min,
            &OD_trace[i].max,
            &OD_trace[i].triggerTime,
            OD_INDEX_TRACE_CONFIG + i,
            OD_INDEX_TRACE + i);
    }
#endif


    return CO_ERROR_NO;
}
DWORD WINAPI CanOpen_run(LPVOID lpParam)
{
	

	/* initialize EEPROM - part 1 */
#ifdef USE_EEPROM
	CO_ReturnError_t eeStatus = CO_EE_init_1(&CO_EEO, (uint8_t*)&CO_OD_EEPROM, sizeof(CO_OD_EEPROM),
		(uint8_t*)&CO_OD_ROM, sizeof(CO_OD_ROM));
#endif

	programStart();

	/* increase variable each startup. Variable is stored in eeprom. */
	OD_powerOnCounter++;

	while (reset != CO_RESET_APP) {
		/* CANopen communication reset - initialize CANopen objects *******************/
		CO_ReturnError_t err;
		uint16_t timer1msPrevious;
		uint16_t TMR_TMR_PREV = 0;
		uint8_t nodeId;
		uint16_t CANBitRate;

		/* disable CAN and CAN interrupts */
		CO_CAN_ISR_ENABLE = 0;
		CO_CAN_ISR2_ENABLE = 0;

		/* Read CANopen Node-ID and CAN bit-rate from object dictionary */
		nodeId = OD_CANNodeID;
		if (nodeId<1 || nodeId>127) nodeId = 0x10;
		CANBitRate = OD_CANBitRate;/* in kbps */

								   /* initialize CANopen */
		err = CO_init(ADDR_CAN1, nodeId, CANBitRate);
		if (err != CO_ERROR_NO) {
			//FIXME do something here?
			/* CO_errorReport(CO->em, CO_EM_MEMORY_ALLOCATION_ERROR, CO_EMC_SOFTWARE_INTERNAL, err); */
		}


		/* initialize eeprom - part 2 */
#ifdef USE_EEPROM
		CO_EE_init_2(&CO_EEO, eeStatus, CO->SDO[0], CO->em);
#endif


		/* Configure callback functions */
		CO_SYNC_initCallback(CO->SYNC, CANrx_lockCbSync);

		/* initialize variables */
		timer1msPrevious = CO_timer1ms;
		OD_performance[ODA_performance_mainCycleMaxTime] = 0;
		OD_performance[ODA_performance_timerCycleMaxTime] = 0;
		reset = CO_RESET_NOT;

		/* Configure Timer interrupt function for execution every 1 millisecond */
		/* Not sure if this is the best type of timer to use */
		/* The jitter on the timing is not great */
		BOOL success = CreateTimerQueueTimer(
			&m_timerHandle,
			NULL,
			TimerProc,
			NULL,
			0,
			1, //Period in ms
			WT_EXECUTEINTIMERTHREAD);

#if CO_PBCLK > 65000
#error wrong timer configuration
#endif
		communicationReset();

		/* start CAN and enable interrupts */
		CO_CANsetNormalMode(CO->CANmodule[0]);
		
#if CO_NO_CAN_MODULES >= 2
		CO_CANsetNormalMode(CO->CANmodule[1]);
		CO_CAN_ISR2_ENABLE = 1;
#endif


		while (reset == CO_RESET_NOT) {
			/* loop for normal program execution ******************************************/
			uint16_t timer1msCopy, timer1msDiff;

			/* calculate cycle time for performance measurement */
			
			timer1msCopy = CO_timer1ms;
			timer1msDiff = timer1msCopy - timer1msPrevious;
			timer1msPrevious = timer1msCopy;

			LARGE_INTEGER Frequency;
			LARGE_INTEGER StartingTime;
			LARGE_INTEGER ElapsedMicroseconds;

			QueryPerformanceFrequency(&Frequency);
			QueryPerformanceCounter(&StartingTime);
			ElapsedMicroseconds.QuadPart = StartingTime.QuadPart - li_main.QuadPart;
			ElapsedMicroseconds.QuadPart *= 1000000;
			ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;

			double t = ElapsedMicroseconds.QuadPart / 1000.0;
			t = 1000.0 / t;

			OD_performance[ODA_performance_mainCycleTime] = t;

			if (t > OD_performance[ODA_performance_mainCycleMaxTime])
					OD_performance[ODA_performance_mainCycleMaxTime] = t;
	
			li_main = StartingTime;

			/* Application asynchronous program */
			programAsync(timer1msDiff);

			/* Pump the SDO master */
			/* TODO In theory we should support as many masters as is defined in OD*/
			canprocessSDOmaster(timer1msDiff);

			/* CANopen process */
			reset = CO_process(CO, timer1msDiff, NULL);

			Sleep(1); //add some grace time to the thread as we do not want to hammer the async thread at 100%

		}
#ifdef USE_EEPROM
			CO_EE_process(&CO_EEO);
#endif
		}

		/* program exit ***************************************************************/

		/* delete objects from memory */
		programEnd();
		CO_delete(ADDR_CAN1);

		// fix me graceful shutdown on win32
		return 0;
}
Exemple #7
0
int main (int argc, char *argv[]) {
    CO_NMT_reset_cmd_t reset = CO_RESET_NOT;
    CO_ReturnError_t odStorStatus_rom, odStorStatus_eeprom;
    int CANdevice0Index = 0;
    int opt;
    bool_t firstRun = true;

    char* CANdevice = NULL;         /* CAN device, configurable by arguments. */
    int nodeId = -1;                /* Set to 1..127 by arguments */
    bool_t rebootEnable = false;    /* Configurable by arguments */
#ifndef CO_SINGLE_THREAD
    bool_t commandEnable = false;   /* Configurable by arguments */
#endif

    if(argc < 3 || strcmp(argv[1], "--help") == 0){
        printUsage(argv[0]);
        exit(EXIT_SUCCESS);
    }


    /* Get program options */
    while((opt = getopt(argc, argv, "i:p:rc:s:a:")) != -1) {
        switch (opt) {
            case 'i': nodeId = strtol(optarg, NULL, 0);     break;
            case 'p': rtPriority = strtol(optarg, NULL, 0); break;
            case 'r': rebootEnable = true;                  break;
#ifndef CO_SINGLE_THREAD
            case 'c':
                /* In case of empty string keep default name, just enable interface. */
                if(strlen(optarg) != 0) {
                    CO_command_socketPath = optarg;
                }
                commandEnable = true;
                break;
#endif
            case 's': odStorFile_rom = optarg;              break;
            case 'a': odStorFile_eeprom = optarg;           break;
            default:
                printUsage(argv[0]);
                exit(EXIT_FAILURE);
        }
    }

    if(optind < argc) {
        CANdevice = argv[optind];
        CANdevice0Index = if_nametoindex(CANdevice);
    }

    if(nodeId < 1 || nodeId > 127) {
        fprintf(stderr, "Wrong node ID (%d)\n", nodeId);
        printUsage(argv[0]);
        exit(EXIT_FAILURE);
    }

    if(rtPriority != -1 && (rtPriority < sched_get_priority_min(SCHED_FIFO)
                         || rtPriority > sched_get_priority_max(SCHED_FIFO))) {
        fprintf(stderr, "Wrong RT priority (%d)\n", rtPriority);
        printUsage(argv[0]);
        exit(EXIT_FAILURE);
    }

    if(CANdevice0Index == 0) {
        char s[120];
        snprintf(s, 120, "Can't find CAN device \"%s\"", CANdevice);
        CO_errExit(s);
    }


    printf("%s - starting CANopen device with Node ID %d(0x%02X)", argv[0], nodeId, nodeId);


    /* Verify, if OD structures have proper alignment of initial values */
    if(CO_OD_RAM.FirstWord != CO_OD_RAM.LastWord) {
        fprintf(stderr, "Program init - %s - Error in CO_OD_RAM.\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    if(CO_OD_EEPROM.FirstWord != CO_OD_EEPROM.LastWord) {
        fprintf(stderr, "Program init - %s - Error in CO_OD_EEPROM.\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    if(CO_OD_ROM.FirstWord != CO_OD_ROM.LastWord) {
        fprintf(stderr, "Program init - %s - Error in CO_OD_ROM.\n", argv[0]);
        exit(EXIT_FAILURE);
    }


    /* initialize Object Dictionary storage */
    odStorStatus_rom = CO_OD_storage_init(&odStor, (uint8_t*) &CO_OD_ROM, sizeof(CO_OD_ROM), odStorFile_rom);
    odStorStatus_eeprom = CO_OD_storage_init(&odStorAuto, (uint8_t*) &CO_OD_EEPROM, sizeof(CO_OD_EEPROM), odStorFile_eeprom);


    /* Catch signals SIGINT and SIGTERM */
    if(signal(SIGINT, sigHandler) == SIG_ERR)
        CO_errExit("Program init - SIGINIT handler creation failed");
    if(signal(SIGTERM, sigHandler) == SIG_ERR)
        CO_errExit("Program init - SIGTERM handler creation failed");

    /* increase variable each startup. Variable is automatically stored in non-volatile memory. */
    printf(", count=%u ...\n", ++OD_powerOnCounter);


    while(reset != CO_RESET_APP && reset != CO_RESET_QUIT && CO_endProgram == 0) {
/* CANopen communication reset - initialize CANopen objects *******************/
        CO_ReturnError_t err;

        printf("%s - communication reset ...\n", argv[0]);


#ifndef CO_SINGLE_THREAD
        /* Wait other threads (command interface). */
        pthread_mutex_lock(&CO_CAN_VALID_mtx);
#endif

        /* Wait rt_thread. */
        if(!firstRun) {
            CO_LOCK_OD();
            CO->CANmodule[0]->CANnormal = false;
            CO_UNLOCK_OD();
        }


        /* Enter CAN configuration. */
        CO_CANsetConfigurationMode(CANdevice0Index);


        /* initialize CANopen */
        err = CO_init(CANdevice0Index, nodeId, 0);
        if(err != CO_ERROR_NO) {
            char s[120];
            snprintf(s, 120, "Communication reset - CANopen initialization failed, err=%d", err);
            CO_errExit(s);
        }


        /* initialize OD objects 1010 and 1011 and verify errors. */
        CO_OD_configure(CO->SDO[0], OD_H1010_STORE_PARAM_FUNC, CO_ODF_1010, (void*)&odStor, 0, 0U);
        CO_OD_configure(CO->SDO[0], OD_H1011_REST_PARAM_FUNC, CO_ODF_1011, (void*)&odStor, 0, 0U);
        if(odStorStatus_rom != CO_ERROR_NO) {
            CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, (uint32_t)odStorStatus_rom);
        }
        if(odStorStatus_eeprom != CO_ERROR_NO) {
            CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, (uint32_t)odStorStatus_eeprom + 1000);
        }


        /* Configure callback functions for task control */
        CO_EM_initCallback(CO->em, taskMain_cbSignal);
        CO_SDO_initCallback(CO->SDO[0], taskMain_cbSignal);
        CO_SDOclient_initCallback(CO->SDOclient, taskMain_cbSignal);

        CO_SYNC_initCallback(CO->SYNC, CANrx_lockCbSync);


        /* Initialize time */
        CO_time_init(&CO_time, CO->SDO[0], &OD_time.epochTimeBaseMs, &OD_time.epochTimeOffsetMs, 0x2130);


        /* First time only initialization. */
        if(firstRun) {
            firstRun = false;

            /* Configure epoll for mainline */
            mainline_epoll_fd = epoll_create(4);
            if(mainline_epoll_fd == -1)
                CO_errExit("Program init - epoll_create mainline failed");

            /* Init mainline */
            taskMain_init(mainline_epoll_fd, &OD_performance[ODA_performance_mainCycleMaxTime]);


#ifdef CO_SINGLE_THREAD
            /* Init taskRT */
            CANrx_taskTmr_init(mainline_epoll_fd, TMR_TASK_INTERVAL_NS, &OD_performance[ODA_performance_timerCycleMaxTime]);

            OD_performance[ODA_performance_timerCycleTime] = TMR_TASK_INTERVAL_NS/1000; /* informative */

            /* Set priority for mainline */
            if(rtPriority > 0) {
                struct sched_param param;

                param.sched_priority = rtPriority;
                if(sched_setscheduler(0, SCHED_FIFO, &param) != 0)
                    CO_errExit("Program init - mainline set scheduler failed");
            }
#else
            /* Configure epoll for rt_thread */
            rt_thread_epoll_fd = epoll_create(2);
            if(rt_thread_epoll_fd == -1)
                CO_errExit("Program init - epoll_create rt_thread failed");

            /* Init taskRT */
            CANrx_taskTmr_init(rt_thread_epoll_fd, TMR_TASK_INTERVAL_NS, &OD_performance[ODA_performance_timerCycleMaxTime]);

            OD_performance[ODA_performance_timerCycleTime] = TMR_TASK_INTERVAL_NS/1000; /* informative */

            /* Create rt_thread */
            if(pthread_create(&rt_thread_id, NULL, rt_thread, NULL) != 0)
                CO_errExit("Program init - rt_thread creation failed");

            /* Set priority for rt_thread */
            if(rtPriority > 0) {
                struct sched_param param;

                param.sched_priority = rtPriority;
                if(pthread_setschedparam(rt_thread_id, SCHED_FIFO, &param) != 0)
                    CO_errExit("Program init - rt_thread set scheduler failed");
            }
#endif

#ifndef CO_SINGLE_THREAD
            /* Initialize socket command interface */
            if(commandEnable) {
                if(CO_command_init() != 0) {
                    CO_errExit("Socket command interface initialization failed");
                }
                printf("%s - Command interface on socket '%s' started ...\n", argv[0], CO_command_socketPath);
            }
#endif

            /* Execute optional additional application code */
            app_programStart();
        }


        /* Execute optional additional application code */
        app_communicationReset();


        /* start CAN */
        CO_CANsetNormalMode(CO->CANmodule[0]);
#ifndef CO_SINGLE_THREAD
        pthread_mutex_unlock(&CO_CAN_VALID_mtx);
#endif


        reset = CO_RESET_NOT;

        printf("%s - running ...\n", argv[0]);


        while(reset == CO_RESET_NOT && CO_endProgram == 0) {
/* loop for normal program execution ******************************************/
            int ready;
            struct epoll_event ev;

            ready = epoll_wait(mainline_epoll_fd, &ev, 1, -1);

            if(ready != 1) {
                if(errno != EINTR) {
                    CO_error(0x11100000L + errno);
                }
            }

#ifdef CO_SINGLE_THREAD
            else if(CANrx_taskTmr_process(ev.data.fd)) {
                /* code was processed in the above function. Additional code process below */
                INCREMENT_1MS(CO_timer1ms);
                /* Detect timer large overflow */
                if(OD_performance[ODA_performance_timerCycleMaxTime] > TMR_TASK_OVERFLOW_US && rtPriority > 0) {
                    CO_errorReport(CO->em, CO_EM_ISR_TIMER_OVERFLOW, CO_EMC_SOFTWARE_INTERNAL, 0x22400000L | OD_performance[ODA_performance_timerCycleMaxTime]);
                }
            }
#endif

            else if(taskMain_process(ev.data.fd, &reset, CO_timer1ms)) {
                uint16_t timer1msDiff;
                static uint16_t tmr1msPrev = 0;

                /* Calculate time difference */
                timer1msDiff = CO_timer1ms - tmr1msPrev;
                tmr1msPrev = CO_timer1ms;

                /* code was processed in the above function. Additional code process below */

                /* Execute optional additional application code */
                app_programAsync(timer1msDiff);

                CO_OD_storage_autoSave(&odStorAuto, CO_timer1ms, 60000);
            }

            else {
                /* No file descriptor was processed. */
                CO_error(0x11200000L);
            }
        }
    }


/* program exit ***************************************************************/
    /* join threads */
#ifndef CO_SINGLE_THREAD
    if(commandEnable) {
        if(CO_command_clear() != 0) {
            CO_errExit("Socket command interface removal failed");
        }
    }
#endif

    CO_endProgram = 1;
#ifndef CO_SINGLE_THREAD
    if(pthread_join(rt_thread_id, NULL) != 0) {
        CO_errExit("Program end - pthread_join failed");
    }
#endif

    /* Execute optional additional application code */
    app_programEnd();

    /* Store CO_OD_EEPROM */
    CO_OD_storage_autoSave(&odStorAuto, 0, 0);
    CO_OD_storage_autoSaveClose(&odStorAuto);

    /* delete objects from memory */
    CANrx_taskTmr_close();
    taskMain_close();
    CO_delete(CANdevice0Index);

    printf("%s on %s (nodeId=0x%02X) - finished.\n\n", argv[0], CANdevice, nodeId);

    /* Flush all buffers (and reboot) */
    if(rebootEnable && reset == CO_RESET_APP) {
        sync();
        if(reboot(LINUX_REBOOT_CMD_RESTART) != 0) {
            CO_errExit("Program end - reboot failed");
        }
    }

    exit(EXIT_SUCCESS);
}
/* main ***********************************************************************/
int main (void){
    CO_NMT_reset_cmd_t reset = CO_RESET_NOT;

    /* Initialize two CAN led diodes */
    TRISAbits.TRISA0 = 0; LATAbits.LATA0 = 0;
    TRISAbits.TRISA1 = 0; LATAbits.LATA1 = 1;
    #define CAN_RUN_LED        LATAbits.LATA0
    #define CAN_ERROR_LED      LATAbits.LATA1

    /* Initialize other LED diodes for RPDO */
    TRISAbits.TRISA2 = 0; LATAbits.LATA2 = 0;
    TRISAbits.TRISA3 = 0; LATAbits.LATA3 = 0;
    TRISAbits.TRISA4 = 0; LATAbits.LATA4 = 0;
    TRISAbits.TRISA5 = 0; LATAbits.LATA5 = 0;
    TRISAbits.TRISA6 = 0; LATAbits.LATA6 = 0;
    TRISAbits.TRISA7 = 0; LATAbits.LATA7 = 0;


    /* Configure Oscillator */
    /* Fosc = Fin*M/(N1*N2), Fcy=Fosc/2 */
    /* Fosc = 8M*24(2*2) = 48MHz -> Fcy = 24MHz */
    PLLFBD=22;              /*  M=24 */
    CLKDIVbits.PLLPOST=0;   /*  N1=2 */
    CLKDIVbits.PLLPRE=0;    /*  N2=2 */
    OSCTUN=0;               /*  Tune FRC oscillator, if FRC is used */
    while(OSCCONbits.LOCK!=1) ClrWdt(); /* wait for PLL to lock */


    /* Verify, if OD structures have proper alignment of initial values */
    if(CO_OD_RAM.FirstWord != CO_OD_RAM.LastWord) while(1) ClrWdt();
    if(CO_OD_EEPROM.FirstWord != CO_OD_EEPROM.LastWord) while(1) ClrWdt();
    if(CO_OD_ROM.FirstWord != CO_OD_ROM.LastWord) while(1) ClrWdt();


    /* initialize EEPROM */
        /* (not implemented) */

    /* increase variable each startup. Variable is stored in eeprom. */
    OD_powerOnCounter++;

    while(reset != CO_RESET_APP){
/* CANopen communication reset - initialize CANopen objects *******************/
        static uint16_t timer1msPrevious;
        CO_ReturnError_t err;

        /* disable timer and CAN interrupts, turn on red LED */
        CO_TMR_ISR_ENABLE = 0;
        CO_CAN_ISR_ENABLE = 0;
        CAN_RUN_LED = 0;
        CAN_ERROR_LED = 1;

        /* Initialize digital outputs */
        TRISAbits.TRISA2 = 0; LATAbits.LATA2 = 0;
        TRISAbits.TRISA3 = 0; LATAbits.LATA3 = 0;
        TRISAbits.TRISA4 = 0; LATAbits.LATA4 = 0;
        TRISAbits.TRISA5 = 0; LATAbits.LATA5 = 0;
        TRISAbits.TRISA6 = 0; LATAbits.LATA6 = 0;
        TRISAbits.TRISA7 = 0; LATAbits.LATA7 = 0;
        OD_writeOutput8Bit[0] = 0;
        OD_writeOutput8Bit[1] = 0;


        /* initialize CANopen */
        err = CO_init();
        if(err != CO_ERROR_NO){
            while(1) ClrWdt();
            /* CO_errorReport(CO->em, CO_EM_MEMORY_ALLOCATION_ERROR, CO_EMC_SOFTWARE_INTERNAL, err); */
        }

        /* start CAN */
        CO_CANsetNormalMode(ADDR_CAN1);


        /* Configure Timer interrupt function for execution every 1 millisecond */
        CO_TMR_CON = 0;
        CO_TMR_TMR = 0;
        CO_TMR_PR = CO_FCY - 1;    /* Period register */
        CO_TMR_CON = 0x8000;       /* start timer (TON=1) */
        CO_timer1ms = 0;
        CO_TMR_ISR_FLAG = 0;       /* clear interrupt flag */
        CO_TMR_ISR_PRIORITY = 3;   /* interrupt - set lower priority than CAN */
        CO_TMR_ISR_ENABLE = 1;     /* enable interrupt */
        /* Configure CAN1 Interrupt (Combined) */
        CO_CAN_ISR_FLAG = 0;       /* CAN1 Interrupt - Clear flag */
        CO_CAN_ISR_PRIORITY = 5;   /* CAN1 Interrupt - Set higher priority than timer */
        CO_CAN_ISR_ENABLE = 1;     /* CAN1 Interrupt - Enable interrupt */

        reset = CO_RESET_NOT;
        timer1msPrevious = CO_timer1ms;

        while(reset == CO_RESET_NOT){
/* loop for normal program execution ******************************************/
            uint16_t timer1msCopy, timer1msDiff;
            static uint16_t TMR_TMR_PREV = 0;

            timer1msCopy = CO_timer1ms;
            timer1msDiff = timer1msCopy - timer1msPrevious;
            timer1msPrevious = timer1msCopy;

            ClrWdt();

            /* calculate cycle time for performance measurement */
            uint16_t t0 = CO_TMR_TMR;
            uint16_t t = t0;
            if(t >= TMR_TMR_PREV){
                t = t - TMR_TMR_PREV;
                t = (timer1msDiff * 100) + (t / (CO_FCY / 100));
            }
            else if(timer1msDiff){
                t = TMR_TMR_PREV - t;
                t = (timer1msDiff * 100) - (t / (CO_FCY / 100));
            }
            else t = 0;
            OD_performance[ODA_performance_mainCycleTime] = t;
            if(t > OD_performance[ODA_performance_mainCycleMaxTime])
                OD_performance[ODA_performance_mainCycleMaxTime] = t;
            TMR_TMR_PREV = t0;

            /* CANopen process */
            reset = CO_process(CO, timer1msDiff);

            CAN_RUN_LED = LED_GREEN_RUN(CO->NMT);
            CAN_ERROR_LED = LED_RED_ERROR(CO->NMT);

            ClrWdt();

            /* (not implemented) eeprom_process(&eeprom); */
        }
    }
/* program exit ***************************************************************/
    /* save variables to eeprom */
    RESTORE_CPU_IPL(7);           /* disable interrupts */
    CAN_RUN_LED = 0;
    /* CAN_ERROR_LED = 0; */
    /* (not implemented) eeprom_saveAll(&eeprom); */
    CAN_ERROR_LED = 1;

    /* delete CANopen object from memory */
    CO_delete();

    /* reset */
    return 0;
}