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

📄 can.c

📁 AVR平台下的CanOpen协议桟源码包括应用
💻 C
📖 第 1 页 / 共 3 页
字号:
/* ------------------------------------------------------------------------ */

BYTE can_read( BYTE *pdlc, BYTE **ppmsg_data )
{
  BYTE cntr, object_no;

  /* Need undisturbed access to buffer management variables !
     (because even the get_buf_xxx() functions may alter variables,
     due to the (self-correcting) majority voting mechanism) */
  CAN_INT_DISABLE();

  cntr = get_buf_cntr();

  /* Is any message available in the buffer ? */
  if( cntr > 0 )
    {
      BYTE index, *msg;

      index     = get_buf_index();
      msg       = CanMsgBuf[index];
      *pdlc     = msg[MSG_DLC_I];
      object_no = msg[MSG_OBJECT_I];

      /* We don't make a copy of the data in the buffer
	 (so make sure it does not get overwritten: see 'canint_handler()');
	 return a pointer that points to the databytes in the message buffer */
      *ppmsg_data = msg;

      /* Make sure the message in the buffer is valid;
	 skip any 'empty' buffers (although this should be very unlikely...) */
      if( bits_in_byte(msg[MSG_VALID_I]) >= 6 )
	{
	  /* Not valid..., skip this message... */
	  object_no = NO_OBJECT;
	}

      /* Mark buffer as empty
	 (NB: the contained message has not been handled yet!) */
      msg[MSG_VALID_I] = BUF_EMPTY;

      /* Decrement the messages-in-buffer counter */
      --cntr;
      MsgCounter1 = cntr;  MsgCounter2 = cntr;  MsgCounter3 = cntr;

      /* Increment the buffer(-out) index to point to
	 the next message to be handled (next time around) */
      index = (index + 1) & CAN_BUFS_MASK;
      MsgOutIndex1 = index;  MsgOutIndex2 = index;  MsgOutIndex3 = index;

#ifdef __CAN_REFRESH__
      /* Refresh the descriptors of one of the receiving buffers */
      can_recv_descriptor_refresh();
#endif /* __CAN_REFRESH__ */
    }
  else
    {
      object_no = NO_OBJECT;
    }

  CAN_INT_ENABLE();

  return object_no;;
}

/* ------------------------------------------------------------------------ */

void can_write( BYTE object_no, BYTE len, BYTE *msg_data )
{
  BYTE addr;
  signed char byt;

  /* Legal message object ? */
  if( object_no > C91_MSG_BUFFERS-1 ) return;

  CAN_INT_DISABLE(); /* Need undisturbed access to CAN-controller ! */

#ifdef __CAN_REFRESH__
  /* Refresh descriptor registers for this CAN message */
  can_descriptor_refresh( object_no );
#endif /* __CAN_REFRESH__ */

  /* Determine object's message buffer address */
  addr = C91_MSGS_I + (object_no * C91_MSG_SIZE);

  /* Write the data bytes to the message buffer;
     go from MSB to byte 0...! */
  for( byt=len-1; byt>=0; --byt ) can_write_reg( addr+byt, msg_data[byt] );

  /* Set the appropriate transmission request bit */
  if( object_no > C91_MSG_BUFFERS_PER_RRR-1 )
    can_write_reg( C91_TRANSMIT_REQ2_I,
		   BIT(object_no - C91_MSG_BUFFERS_PER_RRR) );
  else
    can_write_reg( C91_TRANSMIT_REQ1_I, BIT(object_no) );

#ifdef __CAN_REFRESH__
  /* Refresh the descriptors of one of the receiving buffers */
  /* ### Don't: you may loose a message */
  //can_recv_descriptor_refresh();
#endif /* __CAN_REFRESH__ */

  CAN_INT_ENABLE();
}

/* ------------------------------------------------------------------------ */

void can_write_bootup( void )
{
  BYTE can_data[C91_BOOTUP_LEN];
  BYTE ng;

  /* RTR bit (for NodeGuard message) -if present- must be temporarily removed
     when sending the BOOTUP message (Bootup and NodeGuard use the same
     message buffer!) and is restored by can_rtr_enable() */
  CAN_INT_DISABLE();
  ng = can_read_reg( C91_DR00_I+C91_NODEGUARD*2+1 );
  can_write_reg( C91_DR00_I+C91_NODEGUARD*2+1, ng & (~C91_DR_RTR_MASK) );
  CAN_INT_ENABLE();

  /* Send the CANopen Bootup message */
  can_data[0] = 0;
  can_write( C91_BOOTUP, C91_BOOTUP_LEN, can_data );

  /* Restore RTR bit, if required */
  can_rtr_enable( pdo_rtr_required() );
}

/* ------------------------------------------------------------------------ */

void can_write_emergency( BYTE err_low,
			  BYTE err_high,
			  BYTE mfct_field_0,
			  BYTE mfct_field_1,
			  BYTE mfct_field_2,
			  BYTE mfct_field_3,
			  BYTE canopen_err_bit )
{
  BYTE msg_data[8];

  /* CANopen error code */
  msg_data[0] = err_low;
  msg_data[1] = err_high;

  /* Update CANopen Error Register */
  CANopenErrorReg |= canopen_err_bit;

  /* Add CANopen Error Register (OD object 0x1001) to message */
  msg_data[2] = CANopenErrorReg;

  /* CANopen manufacturer specific error field */
  msg_data[3] = mfct_field_0;
  msg_data[4] = mfct_field_1;
  msg_data[5] = mfct_field_2;
  msg_data[6] = mfct_field_3;
  msg_data[7] = (CanEmgToggle & 0x80);

  /* Make sure the message does not get lost:
     wait for the previous one to be sent */
  {
    BYTE delay=0;
    while( can_transmitting(C91_EMERGENCY) && delay < 50 )
      {
	/* So wait, but not forever... */
	timer2_delay_ms( 1 );
	++delay;
      }
  }

  can_write( C91_EMERGENCY, C91_EMERGENCY_LEN, msg_data );

  /* Toggle the toggle bit */
  CanEmgToggle ^= 0x80;
}

/* ------------------------------------------------------------------------ */

void can_check_for_errors( void )
{
  BYTE interrupts, status;

  CAN_INT_DISABLE();

  interrupts = can_read_reg( C91_INTERRUPT_I );

  /* Detect whether a Nodeguarding message has been (automatically) serviced
     and if so, toggle the toggle-bit ! */
  if( interrupts & C91_REMOTE_FRAME_INT )
    {
      /* Invert the toggle bit */
      NodeGuardToggle ^= 0x80;

      /* Reset the RTR interrupt bit */
      can_write_reg( C91_INTERRUPT_I, (BYTE)(~C91_REMOTE_FRAME_INT) );

      /* Reset the Life Guarding time-out counter */
      TIMER1_DISABLE();
      LifeGuardCntr = 0;
      TIMER1_ENABLE();

      /* Update toggle bit in NodeGuard message buffer */
      can_write_reg( C91_MSGS_I + (C91_NODEGUARD*C91_MSG_SIZE),
		     NodeState | (NodeGuardToggle & 0x80) );
    }

  CAN_INT_ENABLE();

  /* Filter out error bits */
  interrupts &= (C91_WARNING_LEVEL_INT | C91_BUS_OFF_INT |
		 C91_ERROR_PASSIVE_INT | C91_TRANSM_CHECK_INT);

  if( interrupts )
    {
      BYTE err_cntr;

      ++CanErrorCntr;

      /* Save error counter: restored in case of initalization */
      err_cntr = CanErrorCntr;

      CAN_INT_DISABLE();
      status = can_read_reg( C91_MODE_STATUS_I );
      CAN_INT_ENABLE();

      if( interrupts & C91_BUS_OFF_INT )
	{
	  /* Aye... we're off the bus, try to recover,
	     but not before taking a break... */
	  timer2_delay_ms( 50 );
	  timer2_delay_ms( 50 );

	  ++CanBusOffCnt;
#ifdef __VARS_IN_EEPROM__
	  CanBusOffMaxCnt = eeprom_read( EE_CAN_BUSOFF_MAXCNT );
#endif /* __VARS_IN_EEPROM__ */

	  /* Regain access to CAN-bus,
	     unless the number of re-inits exceeds a preset value */
	  if( CanBusOffCnt <= CanBusOffMaxCnt ) can_init( FALSE );

	  /* Restore error counter */
	  CanErrorCntr = err_cntr;
	}

      can_write_emergency( 0x00, 0x81, interrupts, status,
			   err_cntr, CanBusOffCnt, ERRREG_COMMUNICATION );

      /* Reset interrupt bits (except the Remote Frame interrupt) */
      CAN_INT_DISABLE();
      can_write_reg( C91_INTERRUPT_I, (~interrupts) | C91_REMOTE_FRAME_INT );
      CAN_INT_ENABLE();
    }

  if( (CanBufFull & TRUE) == TRUE )
    {
      /* Report it: 'CAN overrun' emergency type */
      can_write_emergency( 0x10, 0x81, 0, 0, 0, 0, ERRREG_COMMUNICATION );
      CanBufFull = FALSE;
    }
}

/* ------------------------------------------------------------------------ */

BOOL can_transmitting( BYTE object_no )
{
  BOOL not_ready;
  not_ready = TRUE;

  CAN_INT_DISABLE();

  if( object_no < C91_MSG_BUFFERS_PER_RRR )
    {
      not_ready = can_read_reg(C91_TRANSMIT_REQ1_I) & BIT(object_no);
    }
  else
    {
      object_no -= C91_MSG_BUFFERS_PER_RRR;
      not_ready = can_read_reg(C91_TRANSMIT_REQ2_I) & BIT(object_no);
    }

  CAN_INT_ENABLE();

  return not_ready;
}

/* ------------------------------------------------------------------------ */

void can_rtr_enable( BOOL enable )
{
  BYTE ctrl, ng, delay;

  CAN_INT_DISABLE();

  ctrl = can_read_reg( C91_CONTROL_I );
  ng   = can_read_reg( C91_DR00_I + C91_NODEGUARD*2+1 );

#ifdef __VARS_IN_EEPROM__
  /* Refresh variable with copy in EEPROM */
  RtrDisabled = eeprom_read( EE_RTR_DISABLED );
#endif

  /* Set or reset Monitor Mode bit and at the same time
     reset or set RTR bit for automatic NodeGuard reply */
  if( enable == FALSE || RtrDisabled )
    {
      ctrl &= ~C91_MONITOR_MODE;
      ng   |= C91_DR_RTR_MASK;
    }
  else
    {
      ctrl |= C91_MONITOR_MODE;
      ng   &= ~C91_DR_RTR_MASK;
    }
  can_write_reg( C91_CONTROL_I, ctrl );

  /* Refresh the corresponding Descriptor Registers */
  can_write_reg( C91_DR00_I + C91_RTR*2,   CAN_DESCRIPTOR[C91_RTR][0] );
  can_write_reg( C91_DR00_I + C91_RTR*2+1, CAN_DESCRIPTOR[C91_RTR][1] );

  CAN_INT_ENABLE();

  /* Don't touch BOOTUP/NODEGUARD buffer until *after* a message has been sent.
     The following doesn't fully guarantee the message has been sent,
     but we'd like to keep it simple... */
  delay = 0;
  while( can_transmitting(C91_BOOTUP) && delay < 50 )
    {
      timer2_delay_ms( 1 );
      ++delay;
    }

  CAN_INT_DISABLE();

  can_write_reg( C91_DR00_I + C91_NODEGUARD*2+1, ng );

  /* Keep node state in NodeGuard message buffer up-to-date
     (in case we now switch from non-automatic (see guarding.c) to
     automatic reply, and at boot-up) */
  can_write_reg( C91_MSGS_I + (C91_NODEGUARD*C91_MSG_SIZE),
		 NodeState | (NodeGuardToggle & 0x80) );

  CAN_INT_ENABLE();
}

/* ------------------------------------------------------------------------ */

BOOL can_set_rtr_disabled( BOOL disable )
{
  if( disable > 1 ) return FALSE;
  if( disable )
    RtrDisabled = TRUE;
  else
    RtrDisabled = FALSE;

#ifdef __VARS_IN_EEPROM__
  if( eeprom_read( EE_RTR_DISABLED ) != RtrDisabled )
    eeprom_write( EE_RTR_DISABLED, RtrDisabled );
#endif /* __VARS_IN_EEPROM__ */

  /* Configure the CAN-controller */
  can_rtr_enable( pdo_rtr_required() );

  return TRUE;
}

/* ------------------------------------------------------------------------ */

BOOL can_get_rtr_disabled( void )
{
#ifdef __VARS_IN_EEPROM__
  RtrDisabled = eeprom_read( EE_RTR_DISABLED );
#endif /* __VARS_IN_EEPROM__ */

  return RtrDisabled;
}

/* ------------------------------------------------------------------------ */

#ifdef __CAN_REFRESH__
static void can_descriptor_refresh( BYTE object_no )
{
  BYTE desc_hi, desc_lo, addr;

  desc_hi = CAN_DESCRIPTOR[object_no][0];
  desc_lo = CAN_DESCRIPTOR[object_no][1];

  /* NMT and SYNC are broadcast messages: Node-ID is not in */
  if( object_no != C91_NMT && object_no != C91_SYNC )
    {
#ifdef __VARS_IN_EEPROM__
      /* ### Not in interrupt routine */
      //NodeID = eeprom_read( EE_NODEID );
#endif /* __VARS_IN_EEPROM__ */

      /* Node-ID is included in COB-ID */
      desc_hi |= (NodeID >> 3);
      desc_lo |= (NodeID << 5);
    }

  /* Write descriptor bytes */
  addr = C91_DR00_I + object_no*2;
  can_write_reg( addr, desc_hi );
  ++addr;
  can_write_reg( addr, desc_lo );
}
#endif /* __CAN_REFRESH__ */

/* ------------------------------------------------------------------------ */

#ifdef __CAN_REFRESH__
static void can_recv_descriptor_refresh( void )
{
  BYTE i;
  /* Find a next CAN-controller buffer which is a receiver
     and refresh its descriptor */
  for( i=0; i<C91_MSG_BUFFERS; ++i )
    {
      /* Modulo increment of index */
      CanRefreshIndex = (CanRefreshIndex + 1) & (C91_MSG_BUFFERS-1);

      if( CANBUF_IS_RECV[CanRefreshIndex] )
	{
	  can_descriptor_refresh( CanRefreshIndex );
	  /* Refresh only one descriptor at a time... */
	  break;
	}
    }
}
#endif /* __CAN_REFRESH__ */

/* ------------------------------------------------------------------------ */

BYTE canopen_init_state( void )
{
  BYTE state;

#ifdef __VARS_IN_EEPROM__
  CANopenOpStateInit = eeprom_read( EE_CANOPEN_OPSTATE_INIT );

⌨️ 快捷键说明

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