📄 can.c
字号:
/* ------------------------------------------------------------------------ */
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 + -