examples/AppliSlave_Linux/appli.c
author frdupin
Tue, 19 Dec 2006 16:30:57 +0100
changeset 60 a8723422e0dd
parent 0 4472ee7c6c3e
permissions -rwxr-xr-x
prototypes in c-ansi style
/*
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 <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>

#include <applicfg.h>
#include <timerhw.h>
#include <linuxCan.h>

#include "def.h"
#include "can.h"
#include "canOpenDriver.h"
#include "sdo.h"
#include "pdo.h"
#include "init.h"
#include "timer.h"
#include "lifegrd.h"

#include "nmtSlave.h"

// Adlink 7841 or Peak PCI/CAN board
// ---------------------------------

// Baudrate values for Peak board :
// CAN_BAUD_1M CAN_BAUD_500K CAN_BAUD_250K CAN_BAUD_125K CAN_BAUD_100K CAN_BAUD_50K
// CAN_BAUD_20K CAN_BAUD_10K CAN_BAUD_5K

#ifdef CAN_BAUD_250K
# define BAUDRATE CAN_BAUD_250K
#else
// Appli have been compiled for Adlink-arbraca. Baudrate not used
# define BAUDRATE 0
#endif

s_BOARD board = {"1", BAUDRATE};


// The variables sent or updated by PDO
// -----------------------------------------------------
extern UNS8 seconds;		// Mapped at index 0x2000, subindex 0x1
extern UNS8 minutes;		// Mapped at index 0x2000, subindex 0x2
extern UNS8 hours;		// Mapped at index 0x2000, subindex 0x3
extern UNS8 day;		// Mapped at index 0x2000, subindex 0x4
extern UNS32 canopenErrNB;	// Mapped at index 0x6000, subindex 0x0
extern UNS32 canopenErrVAL;	// Mapped at index 0x6001, subindex 0x0

// Required definition variables
// -----------------------------
// The variables that you should define for debugging.
// They are used by the macro MSG_ERR and MSG_WAR in applicfg.h
// if the node is a slave, they can be mapped in the object dictionnary.
// if not null, allow the printing of message to the console
// Could be managed by PDO
UNS8 printMsgErrToConsole = 1;
UNS8 printMsgWarToConsole = 1;



/*************************User's variables declaration**************************/
struct tm date;
struct tm *ptrdate;
struct tm date_prec;
time_t  tme;
UNS8 lastSecond;
e_nodeState lastState;
pthread_t threadRcvMsg;
pthread_t threadHeartbeatAndSDO;
UNS8 sendingError = 0;


/******************************prototypes*****************************/
/* You *must* have these 2 functions in your code*/
void heartbeatError(UNS8 heartbeatID);
void SD0timeoutError(UNS8 bus_id, UNS8 line);

UNS8 scanSDOtimeout(void);
void preOperational(void);
void operational(void); 
void stopped(void);
void waitMessage(void);
void waitMessage_heartbeat(void);

/*********************************************************************/
void heartbeatError(UNS8 heartbeatID)
{
  MSG_ERR(0x1F00, "!!! No heart beat received from node : ", heartbeatID);
}

/*****************************************************************************/
void SD0timeoutError (UNS8 bus_id, UNS8 line)
{
  // Informations on what occurs are in transfers[bus_id][line]....
  // See scanSDOtimeout() in sdo.c
}

/*********************************** THREADS **********************************/
//------------------------------------------------------------------------------
// Wait for a received message
void waitMessage( void )
{       
  while (1) {
    receiveMsgHandler(0); // blocked until new message
  }
}

//------------------------------------------------------------------------------
// Heartbeat Manager (sending and receiving) and test SDO timeout
void heartbeatAndSDO(void)
{
  while (1) {
    heartbeatMGR();
    // Check if some SDO response are missing
    scanSDOtimeout();
    // Sleep 10 ms
    usleep(10000);	
  }
}

/*********************************************************************/
void preOperational( void )
{	
  /* Init some variables */
  canopenErrNB = 0;
  canopenErrVAL = 0;
}


/********************************************************************/
void operational( void )
{
  /* read systeme date */
  tme = time (&tme);
  ptrdate = gmtime(&tme);
  date = *ptrdate;
  
  /* Update the dictionary */
  day = date.tm_mday;
  hours = date.tm_hour;
  minutes = date.tm_min;
  seconds = date.tm_sec;
  

  if ( date_prec.tm_min != date.tm_min ) {
    MSG_WAR(0x3F00, "event : minutes change -> node decides to send it. Value : ", date.tm_min);
    sendPDOevent( 0, &minutes );
    date_prec = date;
  }
  if (canopenErrNB == 0)
    sendingError = 0;

  if (lastSecond != seconds) {
    MSG_WAR (0x3F50, "Seconds = ", seconds);
    if ((seconds == 50) && (sendingError == 0))
      {
	MSG_ERR(0x1F55, "DEMO of ERROR. Sent by PDO. Value : ", 0xABCD);
	sendingError = 1;
      }
    
    if (canopenErrNB) {
      MSG_WAR(0x3F56, "ERROR nb : ",  canopenErrNB);
    }
    lastSecond = seconds;
    
  }
}


/*****************************************************************************/
void stopped( void )
{
}

void help()
{
  printf("**************************************************************\n");
  printf("*  AppliSlave                                                *\n");
  printf("*                [-b b]                                      *\n");
  printf("*                                                            *\n");
  printf("*     b : bus [default 1]                                    *\n");
  printf("*                                                            *\n");
  printf("*  This exemple run AppliSlave on bus 0                      *\n");
  printf("*   AppliSlave -b 0                                          *\n");
  printf("*                                                            *\n");
  printf("**************************************************************\n");
}

/****************************************************************************/
/***************************  MAIN  *****************************************/
/****************************************************************************/
int main(int argc,char **argv)
{

  HANDLE ok;
  UNS32 *    pSize;
  UNS32      size;
  pSize = &size;
  char c;
  extern char *optarg;

  while ((c = getopt(argc, argv, "-b:")) != EOF)
  {
    switch(c)
    {
      case 'b' :
        if (optarg[0] == 0)
        {
          help();
          exit(1);
        }
        board.busname = optarg;
        break;
      default:
        help();
        exit(1);
    }
  }

  // Global initialization before launching the threads. (also done in init mode.
  /* Defining the node Id */
  setNodeId(0x05);
  MSG_WAR(0x3F06, "My node ID is : ", getNodeId()); 
  initCANopenMain();
  initTimer( );
  heartbeatInit();
  initResetMode();

  /* Launch the thread to receive the messages */
  pthread_create( &threadRcvMsg, NULL, (void *)&waitMessage, NULL); 
  /* Launch the thread to manage the heartbeat */
  pthread_create( &threadHeartbeatAndSDO, NULL, (void *)&heartbeatAndSDO, NULL); 

  /* open the communication with the board */
  ok = f_can_open(& board);
  if (ok == NULL) {
    MSG_ERR(0x1F02,"Unable to open the board", 0);
    MSG_ERR(0x1F03,"Edit includeMakefileLinux to verify that the application is configured for the good board", 0);
    exit (-1);
  }
  else {
    MSG_WAR(0x3F03, "Board 1 opened ", 0);
    /* slave's state initialization */
    setState(Initialisation);
    lastState = Unknown_state;


    while(1) { /* slave's state machine */
      switch( getState() ) {	
      case Initialisation:
	if (lastState != getState()) 
	  MSG_WAR(0X3F05, "I am in INITIALISATION mode ", 0);
        /* Defining the node Id */
	setNodeId(0x05);
	MSG_WAR(0x3F06, "My node ID is : ", getNodeId()); 
	  // Node identity ?
	{
	  UNS8 *data;
	  UNS8 size;
	  UNS8 dataType;
	  // Manufacturer Device name (default = empty string)
	  getODentry(0x1008, 0x0, (void **)&data, &size, &dataType, 0);
	  MSG_WAR(0x3F09, data, 0);
	  // Manufacturer Hardware version. (default = compilation. date)
	  getODentry(0x1009, 0x0, (void **)&data, &size, &dataType, 0);
	  MSG_WAR(0x3F09, data, 0);
	  // Manufacturer Software version. (default = compilation. time)
	  getODentry(0x100A, 0x0, (void **)&data, &size, &dataType, 0);
	  MSG_WAR(0x3F09, data, 0);
	}

	initCANopenMain();
	initTimer( );
	heartbeatInit();
	initResetMode();
	/* the slave send an NMT trame to say to the master 
	   that it is going to enter into operational state 
	   In fact, you must send the boot-up when you are in 
	   operational mode !
	*/
  
	/* change automatically into pre_operational state */ 
	lastState = getState();
	setState(Pre_operational);
	break;
					
      case Pre_operational:
	if (lastState != getState())
	  {
	  MSG_WAR(0X3F11, "I am in PRE_OPERATIONAL mode ", 0);
	  // Some stuff to do when the node enter in pre-operational mode
	  initPreOperationalMode();
	  }
	if (lastState == Initialisation)
	  slaveSendBootUp(0);
	lastState = getState();
	preOperational( );	
	break;
					
      case Operational:
	if (lastState != getState())
	  MSG_WAR(0X3F12, "I am in OPERATIONAL mode ", 0);
	lastState = getState();
	operational( );
	break;
			
      case Stopped:
	if (lastState !=  getState())
	  MSG_WAR(0X3F13, "I am in STOPPED mode", 0);
	lastState = getState();
	stopped( );
	break;
      }//end switch case
      // Sleep 10 ms
      usleep(10000);	
    }//end while
  }//end else

 
  return 0;	
}