?? conn1.c
字號:
/*****************************************************************************
*
* Microchip DeviceNet Stack (Explicit Messaging Connection Object Source)
*
*****************************************************************************
* FileName: conn1.c
* Dependencies:
* Processor: PIC18F with CAN
* Compiler: C18 02.20.00 or higher
* Linker: MPLINK 03.40.00 or higher
* Company: Microchip Technology Incorporated
*
* Software License Agreement
*
* The software supplied herewith by Microchip Technology Incorporated
* (the "Company") is intended and supplied to you, the Company's
* customer, for use solely and exclusively with products manufactured
* by the Company.
*
* The software is owned by the Company and/or its supplier, and is
* protected under applicable copyright laws. All rights are reserved.
* Any use in violation of the foregoing restrictions may subject the
* user to criminal sanctions under applicable laws, as well as to
* civil liability for the breach of the terms and conditions of this
* license.
*
* THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES,
* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
* TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
* IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
*
* This file contains Explicit messaging support for the Connection Object
* described in Section 5-4 and Chapter 7 of Volume 1 of the DeviceNet
* specification.
*
*
*
* Author Date Comment
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Ross Fosler 04/28/03 ...
*
*****************************************************************************/
#include "dnet.def" // Global definitions file
#include "typedefs.h"
#include "conn.h" // Connection prototypes and symbols
#include "services.h" // Service codes
#include "errors.h" // Error codes
#include "class.h" // Class codes
#include "route.h" // Global symbols defined by the router
#include "dnet.h" // DeviceNet prototypes and symbols
#include "frag.h" // Fragmentation control
#include "CAN.h" // CAN driver
#define _FRAG_SUCCESS 0
#define _FRAG_TOO_MUCH 1
#define RXFLAG_FIRST_FRAG b0
#define TXFLAG_SEND_ACK b0
#define TXFLAG_ACK_STAT b1
#define TXFLAG_TX_START b2
#define TXFLAG_TX_TIMER_EN b3
#define TXFLAG_TX_AGAIN b4
#define TXFLAG_TX_FIN b5
#pragma udata
/*********************************************************************
* Connection related variables
********************************************************************/
CONN_EXPL uConn1;
unsigned char uConn1RxBuffer[CONN_EXPLICIT_RX_SIZE];
unsigned char uConn1TxBuffer[CONN_EXPLICIT_TX_SIZE];
/*********************************************************************
* Function: unsigned char _Conn1Create(void)
*
* PreCondition: none
*
* Input: none
*
* Output: handle to connection
*
* Side Effects: none
*
* Overview: Returns a handle to the connection
*
* Note: none
********************************************************************/
unsigned char _Conn1Create(void)
{
//Initialize the connection attributes
uConn1.attrib.state = _STATE_ESTABLISHED;
uConn1.attrib.produced_cid.bytes.MSB = uDNet.MACID | 0x80;
uConn1.attrib.produced_cid.bytes.LSB = 0x60;
uConn1.attrib.consumed_cid.bytes.MSB = uDNet.MACID | 0x80;
uConn1.attrib.consumed_cid.bytes.LSB = 0x80;
uConn1.attrib.expected_packet_rate.word = 2500;
uConn1.attrib.wdt_action = _WDT_ACTION_DEFERRED;
_establishFlags.bits.expl = 1;
_existentFlags.bits.expl = 1;
// Setup the pointer and other info for the receiving side
uConn1.rx.pMsg = uConn1RxBuffer;
uConn1.rx.lenMax = CONN_EXPLICIT_RX_SIZE;
uConn1.rx.fragFlags.byte = 0;
uConn1.rx.oldFrag = 0;
// Setup the pointer and other info for the transmitting side
uConn1.tx.pMsg = uConn1TxBuffer;
uConn1.tx.lenMax = CONN_EXPLICIT_TX_SIZE;
uConn1.tx.fragFlags.byte = 0;
uConn1.tx.oldFrag = 0;
// Put 10000 or (rate)x(4), whichever is greater
uConn1.timer.word = (uConn1.attrib.expected_packet_rate.word << 2);
if (uConn1.timer.word < 10000) uConn1.timer.word = 10000;
// Set the time
uConn1.ack_tmr.word = EXPLICIT_ACK_TIMER;
//Issue a request to start receiving the CID
CANSetFilter(uConn1.attrib.consumed_cid.word);
return (1);
}
/*********************************************************************
* Function: unsigned char _Conn1Close(void)
*
* PreCondition:
*
* Input: none
*
* Output: status of the close
*
* Side Effects:
*
* Overview: Closes the specified connection
*
* Note: None
********************************************************************/
unsigned char _Conn1Close(void)
{
// Transition to the non-existent state
uConn1.attrib.state = _STATE_NON_EXISTENT;
_establishFlags.bits.expl = 0;
_existentFlags.bits.expl = 0;
// Issue a request to the driver to stop receiving the message
CANClrFilter(uConn1.attrib.consumed_cid.word);
return(1);
}
/*********************************************************************
* Function: void _Conn1TimerEvent(void)
*
* PreCondition:
*
* Input: none
*
* Output: none
*
* Side Effects:
*
* Overview: Update timer and process any timer events.
*
* Note: None
********************************************************************/
void _Conn1TimerEvent(void)
{
// Process the watchdog if the packet rate is other than 0
if (uConn1.attrib.expected_packet_rate.word)
{
// Adjust the time
uConn1.timer.word -= TICK_RESOLUTION;
// If the wdt expires then change the state of the connection
if (uConn1.timer.word == 0)
{
// Auto delete the connection
if (uConn1.attrib.wdt_action == _WDT_ACTION_AUTO_DELETE)
{
uConn1.attrib.state = _STATE_NON_EXISTENT;
}
else
// Deferred delete (full release is determined outside
// of this instance)
if (uConn1.attrib.wdt_action == _WDT_ACTION_DEFERRED)
{
uConn1.attrib.state = _STATE_DEFERED_DELETE;
}
}
}
#if FRAGMENTATION_ACK
// Process fragmentation timer for acknowledged transmission
if (uConn1.tx.fragFlags.bits.TXFLAG_TX_TIMER_EN == 1)
{
// Adjust ack timer
uConn1.ack_tmr.word -= TICK_RESOLUTION;
// If the ack timer expires then change the frag state
if (uConn1.ack_tmr.word == 0)
{
// Disable the timer
uConn1.tx.fragFlags.bits.TXFLAG_TX_TIMER_EN = 0;
// Reset the time
uConn1.ack_tmr.word = EXPLICIT_ACK_TIMER;
// If a resend has been requested
if (uConn1.tx.fragFlags.bits.TXFLAG_TX_AGAIN == 1)
{
// Kill the message
// Reset the transmit state
uConn1.tx.fragFlags.bits.TXFLAG_TX_START = 0;
uConn1.tx.fragFlags.bits.TXFLAG_TX_FIN = 0;
uConn1.tx.fragFlags.bits.TXFLAG_TX_AGAIN = 0;
// Set flag indicating completion
_txFinFlags.bits.expl = 1;
}
else
{
// Issue a resend
uConn1.tx.fragFlags.bits.TXFLAG_TX_AGAIN = 1;
_txFlag.bits.expl = 1;
}
}
}
#endif
}
/*********************************************************************
* Function: void _Conn1RxEvent(void)
*
* PreCondition:
*
* Input: none
*
* Output: none
*
* Side Effects:
*
* Overview: Process data for this connection.
*
* Note: This event occures when data has been received
* for this connection instance.
********************************************************************/
void _Conn1RxEvent(void)
{
BYTE header, service, frag, count, type, len;
unsigned char *pRxData;
// Set the size of classId depending on what has been specified
#if (CLASS_WIDTH_16BIT)
UINT classId;
#else
BYTE classId;
#endif
// Get the pointer to the buffer
pRxData = CANGetRxDataPtr();
len.byte = CANGetRxCnt();
// Extract the header
header.byte = *pRxData;
#if FRAGMENTATION_ACK
// If fragmented
if (header.bits.b7)
{
// Process only if there is sufficient data to process the connection
if (len.byte > 2)
{
// Point to the frag byte and copy it
pRxData++;
frag.byte = *pRxData;
// Point to the service
pRxData++;
// Get the fragment type and count
type.byte = frag.byte & 0xC0;
count.byte = frag.byte & 0x3F;
// If the header MAC equals the allocated MasterMACID then
// process the message fragment
if (((header.byte ^ uDNet.AllocInfo.MasterMACID) & 0x3F) == 0)
{
// Remember the header
uConn1.rx.header = header.byte;
// Process the fragment
switch (type.byte)
{
// Received first fragment
case 0x00:
// The first fragment must always have a frag byte of 0
if (frag.byte == 0)
{
// Copy the fragment to the buffer
CANGetRxDataTyp2(uConn1.rx.pMsg + 1);
// Store the header
*uConn1.rx.pMsg = header.byte;
// Adjust the length minus the fragment control byte
uConn1.rx.len = len.byte - 1;
// Request to issue an ACK with status
uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 1;
uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT = 0;
_txFlag.bits.expl = 1;
// Reset the old fragment
uConn1.rx.oldFrag = 0;
// Indicate the first fragment has been received
uConn1.rx.fragFlags.bits.RXFLAG_FIRST_FRAG = 1;
}
break;
// Received a middle or last fragment
case 0x40:
case 0x80:
// If this frag is the same as the previous then re-ack
if (uConn1.rx.oldFrag == frag.byte)
{
// Set the status & request the hardware to send the ACK
uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 1;
uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT = 0;
_txFlag.bits.expl = 1;
}
else
// Continue if the first fragment has been received
if (uConn1.rx.fragFlags.bits.RXFLAG_FIRST_FRAG)
{
// Process the current fragment
if (((uConn1.rx.oldFrag + 1) & 0x3F) == count.byte)
{
// if the buffer is large enough
if ((uConn1.rx.len + (len.byte - 1)) < uConn1.rx.lenMax)
{
// Copy this fragment to the buffer
CANGetRxDataTyp2(uConn1.rx.pMsg + uConn1.rx.len);
// Store the length minus the fragment control byte and header
uConn1.rx.len += (len.byte - 2);
// Save the current fragment information
uConn1.rx.oldFrag = frag.byte;
// If this the last fragment in the sequence
if (type.byte == 0x80)
{
// Indicate message has been received
_rxFlag.bits.expl = 1;
}
// Set the status & request the hardware to send the ACK
uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 1;
uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT = 0;
_txFlag.bits.expl = 1;
}
//else send an error ack indicating too much data
else
{
// Set the status & request the hardware to send the ACK
uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 1;
uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT = 1;
_txFlag.bits.expl = 1;
// Reset to the initial state
uConn1.rx.fragFlags.bits.RXFLAG_FIRST_FRAG = 0;
}
}
// Toss the fragment and reset to the first state
else
{
// Reset to the initial state
uConn1.rx.fragFlags.bits.RXFLAG_FIRST_FRAG = 0;
}
}
// Fragment not expected
else
{
// Reset to the initial state
uConn1.rx.fragFlags.bits.RXFLAG_FIRST_FRAG = 0;
}
break;
// Received an ACK
case 0xC0:
// Process ack if expecting it
if (uConn1.tx.fragFlags.bits.TXFLAG_TX_START == 1)
{
// Stop the acknowledge timer if it was running
uConn1.tx.fragFlags.bits.TXFLAG_TX_TIMER_EN = 0;
// Reset the retry flag if it was set
uConn1.tx.fragFlags.bits.TXFLAG_TX_AGAIN = 0;
// If the last transmission has been sent
if (uConn1.tx.fragFlags.bits.TXFLAG_TX_FIN == 1)
{
// Reset the transmit state
uConn1.tx.fragFlags.bits.TXFLAG_TX_START = 0;
uConn1.tx.fragFlags.bits.TXFLAG_TX_FIN = 0;
}
else
{
// Start up the next transmission
_txFlag.bits.expl = 1;
}
}
break;
}
// Put the connection into the established state
uConn1.attrib.state = _STATE_ESTABLISHED;
_establishFlags.bits.expl = 1;
// Reset the connection wdt
uConn1.timer.word = uConn1.attrib.expected_packet_rate.word << 2;
}
}
}
#else
// If fragmented
if (header.bits.b7)
{
// Process only if there is sufficient data to process the connection
if (len.byte > 2)
{
// If the header MAC equals the allocated MasterMACID then
// process the message fragment
if (((header.byte ^ uDNet.AllocInfo.MasterMACID) & 0x3F) == 0)
{
// Request to issue an ACK with error status
uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 1;
uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT = 1;
_txFlag.bits.expl = 1;
}
}
}
#endif
// else process a non-fragmented message
else
{
// Process only if there is sufficient data to process the connection
if (len.byte > 1)
{
// Extract the service ID
service.byte = *(pRxData + 1);
// If the header MAC equals the allocated MasterMACID or if the release
// connection service is requested then process the message.
// (refer to section 5-5.4.2)
#if (CLASS_WIDTH_16BIT)
classId.bytes.LSB = *(pRxData + 2);
classId.bytes.MSB = *(pRxData + 3);
if (((classId.word == CLASS_DEVICENET) && (service.byte == SRVS_RELEASE_CONN)) ||
(header.byte ^ uDNet.AllocInfo.MasterMACID & 0x3F) == 0)
#else
classId.byte = *(pRxData + 2);
if (((classId.byte == CLASS_DEVICENET) && (service.byte == SRVS_RELEASE_CONN)) ||
(header.byte ^ uDNet.AllocInfo.MasterMACID & 0x3F) == 0)
#endif
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -