diff --git a/bacnet-stack/ports/pic18/dlmstp.c b/bacnet-stack/ports/pic18/dlmstp.c index 299da643..8940742e 100644 --- a/bacnet-stack/ports/pic18/dlmstp.c +++ b/bacnet-stack/ports/pic18/dlmstp.c @@ -33,24 +33,105 @@ #include "mstp.h" #include "dlmstp.h" #include "rs485.h" -#include "npdu.h" +#include "npdu.h" +#include "eeprom.h" + +// Number of MS/TP Packets Rx/Tx +uint16_t MSTP_Packets = 0; /* receive buffer */ -#pragma udata MSTPPortData +#pragma udata MSTP_RxData static DLMSTP_PACKET Receive_Buffer; /* temp buffer for NPDU insertion */ -static uint8_t PDU_Buffer[MAX_MPDU]; /* local MS/TP port data - shared with RS-485 */ +#pragma udata MSTP_PortData volatile struct mstp_port_struct_t MSTP_Port; +#pragma udata + +#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;} + +// This defines the number of edit fields for this module +#define MAX_EDIT_FIELD 1 +static uint8_t EditField = 0; +/* ************************************************************************* + DESCRIPTION: This function handles incrementing or decrementing our + EditField + RETURN: none + ALGORITHM: none + NOTES: Pass a #>0 to increment #<0 to decrement + *************************************************************************** */ +void dlmstp_SetEditField( + signed char state) /* direction our editfield is moving */ +{ + if (state > 0) + { + if (++EditField > MAX_EDIT_FIELD) + EditField = 0; + } + else if (state < 0) + { + if (EditField) + EditField--; + else + EditField = MAX_EDIT_FIELD; + } + else + EditField = 0; +} + +/* ************************************************************************* + DESCRIPTION: Gets the current edit field for this module + RETURN: the current edit field + ALGORITHM: none + NOTES: none + *************************************************************************** */ +uint8_t dlmstp_GetEditField(void) +{ + return (EditField); +} + +void dlmstp_millisecond_timer(void) +{ + INCREMENT_AND_LIMIT_UINT16(MSTP_Port.SilenceTimer); +} + +void dlmstp_reinit(void) +{ + RS485_Reinit(); + dlmstp_set_my_address(DEFAULT_MAC_ADDRESS); + dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES); + dlmstp_set_max_master(DEFAULT_MAX_MASTER); +} void dlmstp_init(void) -{ +{ + uint8_t data; + /* initialize buffer */ Receive_Buffer.ready = false; Receive_Buffer.pdu_len = 0; /* initialize hardware */ - RS485_Initialize(); - MSTP_Init(&MSTP_Port, MSTP_Port.This_Station); + RS485_Initialize(); + MSTP_Port.InputBuffer = &Receive_Buffer.pdu[0]; + MSTP_Init(&MSTP_Port); + data = I2C_Read_Byte( + EEPROM_DEVICE_ADDRESS, + EEPROM_MSTP_MAC_ADDR); + if (data <= 127) + MSTP_Port.This_Station = data; + else + dlmstp_set_my_address(DEFAULT_MAC_ADDRESS); + data = I2C_Read_Byte( + EEPROM_DEVICE_ADDRESS, + EEPROM_MSTP_MAX_MASTER_ADDR); + if (data <= 127) + MSTP_Port.Nmax_master = data; + else + dlmstp_set_max_master(DEFAULT_MAX_MASTER); + MSTP_Port.Nmax_info_frames = + I2C_Read_Byte( + EEPROM_DEVICE_ADDRESS, + EEPROM_MSTP_MAX_INFO_FRAMES_ADDR); } void dlmstp_cleanup(void) @@ -68,10 +149,11 @@ int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */ unsigned npdu_len = 0; uint8_t frame_type = 0; uint8_t destination = 0; /* destination address */ - BACNET_ADDRESS src; + BACNET_ADDRESS src; + unsigned i = 0; /* loop counter */ if (MSTP_Port.TxReady == false) { - if (npdu_data->confirmed_message) + if (npdu_data->data_expecting_reply) MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY; else MSTP_Port.TxFrameType = @@ -81,72 +163,65 @@ int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */ if (dest && dest->mac_len == 1) { destination = dest->mac[0]; } else { -#if PRINT_ENABLED - fprintf(stderr, "mstp: invalid destination MAC address!\n"); -#endif return -2; } dlmstp_get_my_address(&src); - npdu_len = npdu_encode_pdu(&PDU_Buffer[0], dest, &src, npdu_data); - if ((8 /* header len */ + npdu_len + pdu_len) > MAX_MPDU) { -#if PRINT_ENABLED - fprintf(stderr, "mstp: PDU is too big to send!\n"); -#endif + if ((8 /* header len */ + pdu_len) > MAX_MPDU) { return -4; } - memmove(&PDU_Buffer[npdu_len], pdu, pdu_len); bytes_sent = MSTP_Create_Frame( (uint8_t *) & MSTP_Port.TxBuffer[0], sizeof(MSTP_Port.TxBuffer), MSTP_Port.TxFrameType, destination, - MSTP_Port.This_Station, &PDU_Buffer[0], npdu_len + pdu_len); + MSTP_Port.This_Station, pdu, pdu_len); MSTP_Port.TxLength = bytes_sent; MSTP_Port.TxReady = true; + MSTP_Packets++; } return bytes_sent; } - -/* called about once a millisecond */ -void dlmstp_millisecond_timer(void) -{ - MSTP_Millisecond_Timer(&MSTP_Port); -} - -/* returns the number of octets in the PDU, or zero on failure */ -/* This function is expecting to be polled. */ -uint16_t dlmstp_receive(BACNET_ADDRESS * src, /* source address */ - uint8_t * pdu, /* PDU data */ - uint16_t max_pdu, /* amount of space available in the PDU */ - unsigned timeout) -{ - uint16_t pdu_len = 0; - - (void) timeout; + +void dlmstp_task(void) +{ + uint8_t bytes_remaining; + bool received_frame; + /* only do receive state machine while we don't have a frame */ if ((MSTP_Port.ReceivedValidFrame == false) && - (MSTP_Port.ReceivedInvalidFrame == false)) { - RS485_Check_UART_Data(&MSTP_Port); - MSTP_Receive_Frame_FSM(&MSTP_Port); + (MSTP_Port.ReceivedInvalidFrame == false)) + { + do { + bytes_remaining = RS485_Check_UART_Data(&MSTP_Port); + MSTP_Receive_Frame_FSM(&MSTP_Port); + received_frame = MSTP_Port.ReceivedValidFrame || + MSTP_Port.ReceivedInvalidFrame; + if (received_frame) + break; + } while (bytes_remaining); } /* only do master state machine while rx is idle */ if (MSTP_Port.receive_state == MSTP_RECEIVE_STATE_IDLE) { while (MSTP_Master_Node_FSM(&MSTP_Port)) {}; + //MSTP_Master_Node_FSM(&MSTP_Port); } - /* see if there is a packet available */ - if (Receive_Buffer.ready) { - memmove(src, &Receive_Buffer.address, - sizeof(Receive_Buffer.address)); - pdu_len = Receive_Buffer.pdu_len; - memmove(&pdu[0], &Receive_Buffer.pdu[0], max_pdu); + /* see if there is a packet available, and a place + to put the reply (if necessary) and process it */ + if (Receive_Buffer.ready && !MSTP_Port.TxReady) { + if (Receive_Buffer.pdu_len) { + MSTP_Packets++; + npdu_handler( + &Receive_Buffer.address, + &Receive_Buffer.pdu[0], + Receive_Buffer.pdu_len); + } Receive_Buffer.ready = false; } - RS485_Process_Tx_Message(); - - return pdu_len; + + return; } - + void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address) { int i = 0; @@ -171,33 +246,30 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address) } /* for the MS/TP state machine to use for putting received data */ -uint16_t dlmstp_put_receive(uint8_t src, /* source MS/TP address */ - uint8_t * pdu, /* PDU data */ - uint16_t pdu_len) -{ - if (Receive_Buffer.ready) { - /* FIXME: what to do when we miss a message? */ - pdu_len = 0; - } else if (pdu_len < sizeof(Receive_Buffer.pdu)) { - dlmstp_fill_bacnet_address(&Receive_Buffer.address, src); - Receive_Buffer.pdu_len = pdu_len; - memmove(Receive_Buffer.pdu, pdu, pdu_len); - Receive_Buffer.ready = true; - } else { - /* FIXME: message too large? */ - pdu_len = 0; - } - - return pdu_len; +uint16_t dlmstp_put_receive( + uint8_t src, /* source MS/TP address */ + uint8_t * pdu, /* PDU data */ + uint16_t pdu_len) /* amount of PDU data */ +{ + /* PDU is already in the Receive_Buffer */ + dlmstp_fill_bacnet_address(&Receive_Buffer.address, src); + Receive_Buffer.pdu_len = pdu_len; + Receive_Buffer.ready = true; } void dlmstp_set_my_address(uint8_t mac_address) { - /* FIXME: Master Nodes can only have address 1-127 */ - MSTP_Port.This_Station = mac_address; + /* Master Nodes can only have address 0-127 */ + if (mac_address <= 127) + MSTP_Port.This_Station = mac_address; return; } + +uint8_t dlmstp_my_address(void) +{ + return MSTP_Port.This_Station; +} /* This parameter represents the value of the Max_Info_Frames property of */ /* the node's Device object. The value of Max_Info_Frames specifies the */ @@ -224,8 +296,9 @@ unsigned dlmstp_max_info_frames(void) /* less than or equal to 127. If Max_Master is not writable in a node, */ /* its value shall be 127. */ void dlmstp_set_max_master(uint8_t max_master) -{ - MSTP_Port.Nmax_master = max_master; +{ + if (max_master <= 127) + MSTP_Port.Nmax_master = max_master; return; } diff --git a/bacnet-stack/ports/pic18/mstp.c b/bacnet-stack/ports/pic18/mstp.c index e21e515c..834133d4 100644 --- a/bacnet-stack/ports/pic18/mstp.c +++ b/bacnet-stack/ports/pic18/mstp.c @@ -81,14 +81,14 @@ /* The number of tokens received or used before a Poll For Master cycle */ /* is executed: 50. */ -const unsigned Npoll = 50; +#define Npoll 50 /* The number of retries on sending Token: 1. */ -const unsigned Nretry_token = 1; +#define Nretry_token 1 /* The minimum number of DataAvailable or ReceiveError events that must be */ /* seen by a receiving node in order to declare the line "active": 4. */ -const uint8_t Nmin_octets = 4; +#define Nmin_octets 4 /* The minimum time without a DataAvailable or ReceiveError event within */ /* a frame before a receiving node may discard the frame: 60 bit times. */ @@ -96,56 +96,56 @@ const uint8_t Nmin_octets = 4; /* not to exceed 100 milliseconds.) */ /* At 9600 baud, 60 bit times would be about 6.25 milliseconds */ /* const uint16_t Tframe_abort = 1 + ((1000 * 60) / 9600); */ -const uint16_t Tframe_abort = 30; +#define Tframe_abort 30 /* The maximum idle time a sending node may allow to elapse between octets */ /* of a frame the node is transmitting: 20 bit times. */ -const unsigned Tframe_gap = 20; +#define Tframe_gap 20 /* The time without a DataAvailable or ReceiveError event before declaration */ /* of loss of token: 500 milliseconds. */ -const uint16_t Tno_token = 500; +#define Tno_token 500 /* The maximum time after the end of the stop bit of the final */ /* octet of a transmitted frame before a node must disable its */ /* EIA-485 driver: 15 bit times. */ -const unsigned Tpostdrive = 15; +#define Tpostdrive 15 /* The maximum time a node may wait after reception of a frame that expects */ /* a reply before sending the first octet of a reply or Reply Postponed */ /* frame: 250 milliseconds. */ -const uint16_t Treply_delay = 10; +/* note: we always send a reply postponed since a message other than + the reply may be in the transmit queue */ +#define Treply_delay 10 /* The minimum time without a DataAvailable or ReceiveError event */ /* that a node must wait for a station to begin replying to a */ /* confirmed request: 255 milliseconds. (Implementations may use */ /* larger values for this timeout, not to exceed 300 milliseconds.) */ -const uint16_t Treply_timeout = 255; +#define Treply_timeout 255 /* Repeater turnoff delay. The duration of a continuous logical one state */ /* at the active input port of an MS/TP repeater after which the repeater */ /* will enter the IDLE state: 29 bit times < Troff < 40 bit times. */ -const unsigned Troff = 30; +#define Troff 30 /* The width of the time slot within which a node may generate a token: */ /* 10 milliseconds. */ -const uint16_t Tslot = 10; +#define Tslot 10 /* The maximum time a node may wait after reception of the token or */ /* a Poll For Master frame before sending the first octet of a frame: */ /* 15 milliseconds. */ -const uint16_t Tusage_delay = 15; +#define Tusage_delay 15 /* The minimum time without a DataAvailable or ReceiveError event that a */ /* node must wait for a remote node to begin using a token or replying to */ /* a Poll For Master frame: 20 milliseconds. (Implementations may use */ /* larger values for this timeout, not to exceed 100 milliseconds.) */ -const uint16_t Tusage_timeout = 30; +#define Tusage_timeout 20 /* we need to be able to increment without rolling over */ #define INCREMENT_AND_LIMIT_UINT8(x) {if (x < 0xFF) x++;} -#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;} - bool MSTP_Line_Active(volatile struct mstp_port_struct_t *mstp_port) { @@ -227,14 +227,6 @@ void MSTP_Create_And_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* FIXME: be sure to reset SilenceTimer after each octet is sent! */ } -/* Millisecond Timer - called every millisecond */ -void MSTP_Millisecond_Timer(volatile struct mstp_port_struct_t *mstp_port) -{ - INCREMENT_AND_LIMIT_UINT16(mstp_port->SilenceTimer); - INCREMENT_AND_LIMIT_UINT16(mstp_port->ReplyPostponedTimer); - return; -} - #if PRINT_ENABLED_RECEIVE char *mstp_receive_state_text(int state) { @@ -471,26 +463,8 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port) } /* NoData */ else if (mstp_port->DataLength == 0) { - /* CHEAT: it is very difficult to respond to - poll for master in the Master Node state machine - before Tusage_timeout, so we will do it here. */ - if ((mstp_port->FrameType == FRAME_TYPE_POLL_FOR_MASTER) && - (mstp_port->DestinationAddress == mstp_port->This_Station) && - (mstp_port->master_state == MSTP_MASTER_STATE_IDLE)) - { - MSTP_Create_And_Send_Frame(mstp_port, - FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER, - mstp_port->SourceAddress, mstp_port->This_Station, - NULL, 0); - /* don't indicate that a frame has been received */ - mstp_port->ReceivedInvalidFrame = false; - mstp_port->ReceivedValidFrame = false; - } - else - { - /* indicate that a frame with no data has been received */ - mstp_port->ReceivedValidFrame = true; - } + /* indicate that a frame with no data has been received */ + mstp_port->ReceivedValidFrame = true; /* wait for the start of the next frame. */ mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; } @@ -780,10 +754,6 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) break; /* ReceivedPFM */ case FRAME_TYPE_POLL_FOR_MASTER: - /* CHEAT: we cheat a little and this is really handled in the - receive state machine since it is difficult to respond - quick enough (i.e. faster than Tusage_timeout of the - other node which could be 20ms). */ MSTP_Create_And_Send_Frame(mstp_port, FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER, mstp_port->SourceAddress, mstp_port->This_Station, @@ -796,9 +766,9 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) mstp_port->DataLength); break; case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: - mstp_port->ReplyPostponedTimer = 0; + //mstp_port->ReplyPostponedTimer = 0; /* indicate successful reception to the higher layers */ - dlmstp_put_receive(mstp_port->SourceAddress, /* source MS/TP address */ + dlmstp_put_receive(mstp_port->SourceAddress, (uint8_t *) & mstp_port->InputBuffer[0], mstp_port->DataLength); /* broadcast DER just remains IDLE */ @@ -806,7 +776,6 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) MSTP_BROADCAST_ADDRESS) { mstp_port->master_state = MSTP_MASTER_STATE_ANSWER_DATA_REQUEST; - transition_now = true; } break; case FRAME_TYPE_TEST_REQUEST: @@ -831,7 +800,12 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) /* NothingToSend */ mstp_port->FrameCount = mstp_port->Nmax_info_frames; mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + transition_now = true; + } else if (mstp_port->SilenceTimer > Tusage_delay) { + /* if we missed our timing deadline, another token will be sent */ + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; } else { + /* don't send it if we are too late in getting out */ uint8_t destination = mstp_port->TxBuffer[3]; RS485_Send_Frame(mstp_port, (uint8_t *) & mstp_port->TxBuffer[0], mstp_port->TxLength); @@ -859,7 +833,6 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) } mstp_port->TxReady = false; } - transition_now = true; break; /* In the WAIT_FOR_REPLY state, the node waits for */ /* a reply from another node. */ @@ -931,6 +904,7 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) /* then this node may send another information frame */ /* before passing the token. */ mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; } /* Npoll changed in Errata SSPC-135-2004 */ else if (mstp_port->TokenCount < (Npoll - 1)) { @@ -942,6 +916,7 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) mstp_port->FrameCount = 0; mstp_port->TokenCount++; mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; } else { /* SendToken */ /* Npoll changed in Errata SSPC-135-2004 */ @@ -995,7 +970,6 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) mstp_port->RetryCount = 0; mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER; } - transition_now = true; break; /* The PASS_TOKEN state listens for a successor to begin using */ /* the token that this node has just attempted to pass. */ @@ -1037,7 +1011,6 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) /* find a new successor to TS */ mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER; - transition_now = true; } } break; @@ -1076,7 +1049,6 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) /* enter the POLL_FOR_MASTER state to find a new successor to TS. */ mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER; - transition_now = true; } } break; @@ -1108,9 +1080,9 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) /* enter the IDLE state to synchronize with the network. */ /* This action drops the token. */ mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + transition_now = true; } mstp_port->ReceivedValidFrame = false; - transition_now = true; } else if ((mstp_port->SilenceTimer >= Tusage_timeout) || (mstp_port->ReceivedInvalidFrame == true)) { if (mstp_port->SoleMaster == true) { @@ -1120,6 +1092,7 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) mstp_port->FrameCount = 0; /* mstp_port->TokenCount++; removed in 2004 */ mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; } else { if (mstp_port->Next_Station != mstp_port->This_Station) { /* DoneWithPFM */ @@ -1151,18 +1124,21 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) mstp_port->FrameCount = 0; mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; } } } mstp_port->ReceivedInvalidFrame = false; - transition_now = true; } break; /* The ANSWER_DATA_REQUEST state is entered when a */ /* BACnet Data Expecting Reply, a Test_Request, or */ /* a proprietary frame that expects a reply is received. */ case MSTP_MASTER_STATE_ANSWER_DATA_REQUEST: - if (mstp_port->ReplyPostponedTimer <= Treply_delay) { + /* FIXME: if we knew the APDU type received, we could + see if the next message was that same APDU type */ + if ((mstp_port->SilenceTimer <= Treply_delay) && + mstp_port->TxReady) { /* Reply */ /* If a reply is available from the higher layers */ /* within Treply_delay after the reception of the */ @@ -1178,28 +1154,6 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) mstp_port->TxLength); mstp_port->TxReady = false; mstp_port->master_state = MSTP_MASTER_STATE_IDLE; - transition_now = true; - } - /* Test Request */ - /* If a receiving node can successfully receive and return */ - /* the information field, it shall do so. If it cannot receive */ - /* and return the entire information field but can detect */ - /* the reception of a valid Test_Request frame */ - /* (for example, by computing the CRC on octets as */ - /* they are received), then the receiving node shall discard */ - /* the information field and return a Test_Response containing */ - /* no information field. If the receiving node cannot detect */ - /* the valid reception of frames with overlength information fields, */ - /* then no response shall be returned. */ - else if (mstp_port->FrameType == FRAME_TYPE_TEST_REQUEST) { - MSTP_Create_And_Send_Frame(mstp_port, - FRAME_TYPE_TEST_RESPONSE, - mstp_port->SourceAddress, - mstp_port->This_Station, - (uint8_t *) & mstp_port->InputBuffer[0], - mstp_port->DataLength); - mstp_port->master_state = MSTP_MASTER_STATE_IDLE; - transition_now = true; } } /* DeferredReply */ @@ -1217,7 +1171,6 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) mstp_port->SourceAddress, mstp_port->This_Station, NULL, 0); mstp_port->master_state = MSTP_MASTER_STATE_IDLE; - transition_now = true; } break; default: @@ -1228,8 +1181,10 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) return transition_now; } -void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port, - uint8_t this_station_mac) +/* note: This_Station should be set with the MAC address */ +/* note: Nmax_info_frames should be set */ +/* note: Nmax_master should be set */ +void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port) { int i; /*loop counter */ @@ -1252,19 +1207,21 @@ void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port, for (i = 0; i < sizeof(mstp_port->InputBuffer); i++) { mstp_port->InputBuffer[i] = 0; } - mstp_port->Next_Station = this_station_mac; - mstp_port->Poll_Station = this_station_mac; + mstp_port->Next_Station = mstp_port->This_Station; + mstp_port->Poll_Station = mstp_port->This_Station; mstp_port->ReceivedInvalidFrame = false; mstp_port->ReceivedValidFrame = false; mstp_port->RetryCount = 0; mstp_port->SilenceTimer = 0; - mstp_port->ReplyPostponedTimer = 0; +// mstp_port->ReplyPostponedTimer = 0; mstp_port->SoleMaster = false; mstp_port->SourceAddress = 0; mstp_port->TokenCount = 0; - mstp_port->This_Station = this_station_mac; + #if 0 + // these are adjustable, so should already be set mstp_port->Nmax_info_frames = DEFAULT_MAX_INFO_FRAMES; mstp_port->Nmax_master = DEFAULT_MAX_MASTER; + #endif /* An array of octets, used to store PDU octets prior to being transmitted. */ /* This array is only used for APDU messages */ diff --git a/bacnet-stack/ports/pic18/mstp.h b/bacnet-stack/ports/pic18/mstp.h index d7c74bfd..cdbb8ce7 100644 --- a/bacnet-stack/ports/pic18/mstp.h +++ b/bacnet-stack/ports/pic18/mstp.h @@ -72,24 +72,24 @@ /* receive FSM states */ typedef enum { - MSTP_RECEIVE_STATE_IDLE, - MSTP_RECEIVE_STATE_PREAMBLE, - MSTP_RECEIVE_STATE_HEADER, - MSTP_RECEIVE_STATE_HEADER_CRC, - MSTP_RECEIVE_STATE_DATA + MSTP_RECEIVE_STATE_IDLE = 0, + MSTP_RECEIVE_STATE_PREAMBLE = 1, + MSTP_RECEIVE_STATE_HEADER = 2, + MSTP_RECEIVE_STATE_HEADER_CRC = 3, + MSTP_RECEIVE_STATE_DATA = 4 } MSTP_RECEIVE_STATE; /* master node FSM states */ typedef enum { - MSTP_MASTER_STATE_INITIALIZE, - MSTP_MASTER_STATE_IDLE, - MSTP_MASTER_STATE_USE_TOKEN, - MSTP_MASTER_STATE_WAIT_FOR_REPLY, - MSTP_MASTER_STATE_DONE_WITH_TOKEN, - MSTP_MASTER_STATE_PASS_TOKEN, - MSTP_MASTER_STATE_NO_TOKEN, - MSTP_MASTER_STATE_POLL_FOR_MASTER, - MSTP_MASTER_STATE_ANSWER_DATA_REQUEST + MSTP_MASTER_STATE_INITIALIZE = 0, + MSTP_MASTER_STATE_IDLE = 1, + MSTP_MASTER_STATE_USE_TOKEN = 2, + MSTP_MASTER_STATE_WAIT_FOR_REPLY = 3, + MSTP_MASTER_STATE_DONE_WITH_TOKEN = 4, + MSTP_MASTER_STATE_PASS_TOKEN = 5, + MSTP_MASTER_STATE_NO_TOKEN = 6, + MSTP_MASTER_STATE_POLL_FOR_MASTER = 7, + MSTP_MASTER_STATE_ANSWER_DATA_REQUEST = 8 } MSTP_MASTER_STATE; struct mstp_port_struct_t { @@ -103,7 +103,6 @@ struct mstp_port_struct_t { unsigned ReceiveError:1; /* There is data in the buffer */ unsigned DataAvailable:1; - unsigned FramingError:1; /* TRUE if we got a framing error */ unsigned ReceivedInvalidFrame:1; /* A Boolean flag set to TRUE by the Receive State Machine */ /* if a valid frame is received. */ @@ -112,9 +111,6 @@ struct mstp_port_struct_t { /* A Boolean flag set to TRUE by the master machine if this node is the */ /* only known master node. */ unsigned SoleMaster:1; - /* After receiving a frame this value will be TRUE until Tturnaround */ - /* has expired */ - unsigned Turn_Around_Waiting:1; /* stores the latest received data */ uint8_t DataRegister; /* Used to accumulate the CRC on the data field of a frame. */ @@ -141,7 +137,7 @@ struct mstp_port_struct_t { /* An array of octets, used to store octets as they are received. */ /* InputBuffer is indexed from 0 to InputBufferSize-1. */ /* The maximum size of a frame is 501 octets. */ - uint8_t InputBuffer[MAX_MPDU]; + uint8_t *InputBuffer; /* "Next Station," the MAC address of the node to which This Station passes */ /* the token. If the Next_Station is unknown, Next_Station shall be equal to */ /* This_Station. */ @@ -164,7 +160,9 @@ struct mstp_port_struct_t { /* A timer used to measure and generate Reply Postponed frames. It is */ /* incremented by a timer process and is cleared by the Master Node State */ /* Machine when a Data Expecting Reply Answer activity is completed. */ - uint16_t ReplyPostponedTimer; +/* note: we always send a reply postponed since a message other than + the reply may be in the transmit queue */ +// uint16_t ReplyPostponedTimer; /* Used to store the Source Address of a received frame. */ uint8_t SourceAddress; @@ -207,20 +205,24 @@ struct mstp_port_struct_t { #define DEFAULT_MAX_INFO_FRAMES 1 #define DEFAULT_MAX_MASTER 127 +#define DEFAULT_MAC_ADDRESS 127 /* The minimum time after the end of the stop bit of the final octet of a */ /* received frame before a node may enable its EIA-485 driver: 40 bit times. */ /* At 9600 baud, 40 bit times would be about 4.166 milliseconds */ -#define Tturnaround 40; +/* At 19200 baud, 40 bit times would be about 2.083 milliseconds */ +/* At 38400 baud, 40 bit times would be about 1.041 milliseconds */ +/* At 57600 baud, 40 bit times would be about 0.694 milliseconds */ +/* At 76800 baud, 40 bit times would be about 0.520 milliseconds */ +/* At 115200 baud, 40 bit times would be about 0.347 milliseconds */ +/* 40 bits is 4 octets including a start and stop bit with each octet */ +#define Tturnaround 40 #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ - void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port, - uint8_t this_station_mac); - void MSTP_Millisecond_Timer(volatile struct mstp_port_struct_t - *mstp_port); + void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port); void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port); bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t diff --git a/bacnet-stack/ports/pic18/rs485.c b/bacnet-stack/ports/pic18/rs485.c index 529c3e20..b7a77c52 100644 --- a/bacnet-stack/ports/pic18/rs485.c +++ b/bacnet-stack/ports/pic18/rs485.c @@ -29,86 +29,27 @@ #include #include #include +#include #include "hardware.h" #include "mstp.h" +#include "comm.h" +#include "eeprom.h" /* public port info */ extern volatile struct mstp_port_struct_t MSTP_Port; -static uint32_t RS485_Baud_Rate = 9600; +/* the baud rate is adjustable */ +uint32_t RS485_Baud_Rate = 9600; + +/* the ISR and other use this for status and control */ +COMSTAT RS485_Comstat; + +//#pragma udata MSTPPortData +/* the buffer for receiving characters */ +volatile uint8_t RS485_Rx_Buffer[MAX_MPDU]; /* UART transmission buffer and index */ -static volatile uint8_t RS485_Tx_Buffer[MAX_MPDU]; -static volatile uint8_t RS485_Tx_Index = 0; -static volatile uint8_t RS485_Tx_Length = 0; -static volatile char RS485_Tx_Postdrive_Delay = 0; -static struct { - unsigned TransmitStart:1; /* TRUE if we are requested to transmit */ - unsigned TransmitComplete:1; /* TRUE if we are finished transmitting frame */ -} RS485_Flags; - -/* Duplicate of the RCSTA reg used due to the double buffering of the */ -/* fifo. Reading the RCREG reg will cause the second RCSTA reg to be */ -/* loaded if there is one. */ -struct _rcstabits { - unsigned char RX9D:1; - unsigned char OERR:1; - unsigned char FERR:1; - unsigned char ADDEN:1; - unsigned char CREN:1; - unsigned char SREN:1; - unsigned char RX9:1; - unsigned char SPEN:1; -}; - -volatile static enum { - RS485_STATE_IDLE = 0, - RS485_STATE_RX_DATA = 1, - RS485_STATE_RX_CHECKSUM = 2, - RS485_STATE_RX_PROCESS = 3, - RS485_STATE_TX_DATA = 4, - RS485_STATE_WAIT_FOR_ACK = 5, - RS485_STATE_WAIT_COMPLETE = 6, - RS485_STATE_TX_GLOBAL_ACK = 7, - RS485_STATE_TX_POSTDRIVE_DELAY = 8, - RS485_STATE_ERROR = 9, - RS485_STATE_RX_TEST = 10, - RS485_STATE_RX_TEST_EEPROM = 11, - RS485_STATE_RX_TEST_DELAY = 12, - RS485_STATE_TX_TEST_WAIT = 13, - RS485_STATE_TX_TEST = 14 -} RS485_State; - -/**************************************************************************** -* DESCRIPTION: Processes the RS485 message to be sent -* RETURN: none -* ALGORITHM: none -* NOTES: none -*****************************************************************************/ -void RS485_Process_Tx_Message(void) -{ - if (RS485_Flags.TransmitComplete) - RS485_Flags.TransmitComplete = FALSE; - /* start a new transmisstion if we are ready */ - if (RS485_Flags.TransmitStart && (RS485_State == RS485_STATE_IDLE)) { - /* Disable the receiver */ - USART_RX_INT_DISABLE(); - USART_CONTINUOUS_RX_DISABLE(); - /* Enable the transmit line driver and interrupts */ - RS485_TRANSMIT_ENABLE(); - RS485_State = RS485_STATE_TX_DATA; - /* Configure the ISR handler for an outgoing message */ - RS485_Tx_Index = 0; - /* update the flags for beginning a send */ - RS485_Flags.TransmitComplete = FALSE; - RS485_Flags.TransmitStart = FALSE; - /* send the first byte */ - USART_TRANSMIT(RS485_Tx_Buffer[0]); - USART_TX_SETUP(); - } - - return; -} +volatile uint8_t RS485_Tx_Buffer[MAX_MPDU]; /**************************************************************************** * DESCRIPTION: Transmits a frame using the UART @@ -118,106 +59,53 @@ void RS485_Process_Tx_Message(void) *****************************************************************************/ void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port specific data */ uint8_t * buffer, /* frame to send (up to 501 bytes of data) */ - uint16_t nbytes) -{ /* number of bytes of data (up to 501) */ - /* do we check for tx buffer in-use? */ - /* Or do we just stop the in-progress transmission? */ - /* Drop any transmission in progress, but don't worry about */ - /* cleaning up the hardware - the start routine will handle that */ - - /* Disable the interrupt since it depends on the global transmit buffer. */ - USART_TX_INT_DISABLE(); - switch (RS485_State) { - case RS485_STATE_TX_DATA: - case RS485_STATE_WAIT_FOR_ACK: - case RS485_STATE_WAIT_COMPLETE: - case RS485_STATE_TX_GLOBAL_ACK: - RS485_State = RS485_STATE_IDLE; - break; - } - - /* load the frame */ - RS485_Tx_Length = 0; - while (buffer && nbytes) { - RS485_Tx_Buffer[RS485_Tx_Length] = *buffer; - buffer++; - nbytes--; - RS485_Tx_Length++; - /* check bounds - should this error be indicated somehow? */ - /* perhaps not send the message? */ - if (RS485_Tx_Length >= MAX_MPDU) - break; - } - /* signal the task to start sending when it is ready */ - RS485_Flags.TransmitStart = TRUE; - mstp_port->SilenceTimer = 0; - - return; -} - -/**************************************************************************** -* DESCRIPTION: Processes the next RS485 byte for transmit -* RETURN: none -* ALGORITHM: none -* NOTES: Called by interrupt service routine (ISR) -*****************************************************************************/ -void RS485_Transmit_Interrupt(void) + uint16_t nbytes) /* number of bytes of data (up to 501) */ { - uint8_t data; /* data byte to send */ - - switch (RS485_State) { - case RS485_STATE_TX_DATA: - RS485_Tx_Index++; - if (RS485_Tx_Index < RS485_Tx_Length) { - data = RS485_Tx_Buffer[RS485_Tx_Index]; - USART_TRANSMIT(data); - MSTP_Port.SilenceTimer = 0; - - } else { - /* wait until the last bit is sent */ - while (!USART_TX_EMPTY()); - RS485_TRANSMIT_DISABLE(); - /* wait 2 characters after sending (min=15 bit times) */ - RS485_Tx_Postdrive_Delay = 2; - RS485_State = RS485_STATE_TX_POSTDRIVE_DELAY; - USART_TRANSMIT(0); - } - break; - case RS485_STATE_TX_POSTDRIVE_DELAY: - /* after the message is sent, we wait a certain */ - /* number of character times to get a delay */ - if (RS485_Tx_Postdrive_Delay) { - RS485_Tx_Postdrive_Delay--; - if (RS485_Tx_Postdrive_Delay == 0) - RS485_State = RS485_STATE_WAIT_COMPLETE; - USART_TRANSMIT(0); - } else - RS485_State = RS485_STATE_WAIT_COMPLETE; - break; - case RS485_STATE_WAIT_COMPLETE: - /* wait until the last delay bit is shifted */ - while (!USART_TX_EMPTY()); - USART_TX_INT_DISABLE(); - RS485_Flags.TransmitComplete = TRUE; - RS485_State = RS485_STATE_IDLE; - USART_RX_SETUP(); - break; - default: - break; - } + uint16_t i = 0; /* loop counter */ + uint8_t turnaround_time; + if (!buffer) return; -} -/**************************************************************************** -* DESCRIPTION: Returns the value of Transmit Complete flag. -* RETURN: none -* ALGORITHM: none -* NOTES: none -*****************************************************************************/ -bool RS485_Tx_Complete(void) -{ - return RS485_Flags.TransmitComplete; + /* bounds check */ + if (nbytes >= sizeof(RS485_Tx_Buffer)) + return; + + /* buffer is full. Wait for ISR to transmit. */ + while (RS485_Comstat.Tx_Bytes) {}; + + /* wait 40 bit times since reception */ + if (RS485_Baud_Rate == 9600) + turnaround_time = 4; + else if (RS485_Baud_Rate == 19200) + turnaround_time = 2; + else + turnaround_time = 1; + + while (mstp_port->SilenceTimer < turnaround_time) {}; + + RS485_Comstat.TxHead = 0; + memcpy((void *)&RS485_Tx_Buffer[0], (void *)buffer, nbytes); + + //for (i = 0; i < nbytes; i++) { + // /* put the data into the buffer */ + // RS485_Tx_Buffer[i] = *buffer; + // buffer++; + //} + RS485_Comstat.Tx_Bytes = nbytes; + /* disable the receiver */ + PIE3bits.RC2IE = 0; + RCSTA2bits.CREN = 0; + /* enable the transceiver */ + RS485_TX_ENABLE = 1; + RS485_RX_DISABLE = 1; + /* enable the transmitter */ + TXSTA2bits.TXEN = 1; + PIE3bits.TX2IE = 1; + /* per MSTP spec, sort of */ + mstp_port->SilenceTimer = 0; + + return; } /**************************************************************************** @@ -226,58 +114,101 @@ bool RS485_Tx_Complete(void) * ALGORITHM: none * NOTES: none *****************************************************************************/ -void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port) +uint8_t RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port) { - struct _rcstabits rcstabits; /* reading it more than once gets wrong data */ - /* check for data */ - if (USART_RX_COMPLETE()) { - /* Read the data and the Rx status reg */ - rcstabits = USART_RX_STATUS(); - mstp_port->DataRegister = USART_RECEIVE(); - - /* Check for buffer overrun error */ - if (rcstabits.OERR) { - /* clear the error */ - USART_CONTINUOUS_RX_DISABLE(); - USART_CONTINUOUS_RX_ENABLE(); - /* let the state machine know */ - mstp_port->ReceiveError = TRUE; - } - /* Check for framing errors */ - else if (USART_RX_FRAME_ERROR()) { - /* let the state machine know */ - mstp_port->FramingError = TRUE; - mstp_port->ReceiveError = TRUE; - } - /* We read a good byte */ - else { - /* state machine will clear this */ - mstp_port->DataAvailable = TRUE; - } + if (RS485_Comstat.Rx_Bytes) + { + mstp_port->DataRegister = RS485_Rx_Buffer[RS485_Comstat.RxTail]; + if (RS485_Comstat.RxTail >= (sizeof(RS485_Rx_Buffer)-1)) + RS485_Comstat.RxTail = 0; + else + RS485_Comstat.RxTail++; + RS485_Comstat.Rx_Bytes--; + /* errors? let the state machine know */ + if (RS485_Comstat.Rx_Bufferoverrun) + { + RS485_Comstat.Rx_Bufferoverrun = FALSE; + mstp_port->ReceiveError = TRUE; + } + /* We read a good byte */ + else + mstp_port->DataAvailable = TRUE; } - return; + return RS485_Comstat.Rx_Bytes; +} +/* ************************************************************************* + DESCRIPTION: Receives RS485 data stream + + RETURN: none + + ALGORITHM: none + + NOTES: none + *************************************************************************** */ +void RS485_Interrupt_Rx(void) +{ + char dummy; + + if ((RCSTA2bits.FERR) || (RCSTA2bits.OERR)) + { + /* Clear the error */ + RCSTA2bits.CREN = 0; + RCSTA2bits.CREN = 1; + RS485_Comstat.Rx_Bufferoverrun = TRUE; + dummy = RCREG2; + } + else if (RS485_Comstat.Rx_Bytes < sizeof(RS485_Rx_Buffer)) + { + RS485_Rx_Buffer[RS485_Comstat.RxHead] = RCREG2; + if (RS485_Comstat.RxHead >= (sizeof(RS485_Rx_Buffer)-1)) + RS485_Comstat.RxHead = 0; + else + RS485_Comstat.RxHead++; + RS485_Comstat.Rx_Bytes++; + } + else + { + RS485_Comstat.Rx_Bufferoverrun = TRUE; + dummy = RCREG2; + (void)dummy; + } } -/**************************************************************************** -* DESCRIPTION: Receives a data byte from the USART -* RETURN: none -* ALGORITHM: none -* NOTES: none -*****************************************************************************/ -void RS485_Receive_Interrupt(void) -{ - /* get as many bytes as we can get */ - for (;;) { - RS485_Check_UART_Data(&MSTP_Port); - if (MSTP_Port.ReceiveError || MSTP_Port.DataAvailable) - MSTP_Receive_Frame_FSM(&MSTP_Port); - else - break; - } +/* ************************************************************************* + DESCRIPTION: Transmits a byte using the UART out the RS485 port - return; + RETURN: none + + ALGORITHM: none + + NOTES: none + *************************************************************************** */ +void RS485_Interrupt_Tx(void) +{ + if (RS485_Comstat.Tx_Bytes) + { + /* Get the data byte */ + TXREG2 = RS485_Tx_Buffer[RS485_Comstat.TxHead]; + /* point to the next byte */ + RS485_Comstat.TxHead++; + /* reduce the buffer size */ + RS485_Comstat.Tx_Bytes--; + } + else + { + /* wait for the USART to be empty */ + while (!TXSTA2bits.TRMT); + /* disable this interrupt */ + PIE3bits.TX2IE = 0; + /* enable the receiver */ + RS485_TX_ENABLE = 0; + RS485_RX_DISABLE = 0; + // FIXME: might not be necessary + PIE3bits.RC2IE = 1; + RCSTA2bits.CREN = 1; + } } /**************************************************************************** @@ -312,56 +243,11 @@ void RS485_Set_Baud_Rate(uint32_t baud) else RS485_Baud_Rate = 115200; -} - -void RS485_Initialize_Baud(void) -{ - /* setup USART Baud Rate Generator */ - /* see BAUD RATES FOR ASYNCHRONOUS MODE in Data Book */ - /* Fosc=20MHz - BRGH=1 BRGH=0 - Rate SPBRG Rate SPBRG - ------- ----- ------- ----- - 9615 129 9469 32 - 19230 64 19530 15 - 37878 32 78130 3 - 56818 21 104200 2 - 113630 10 312500 0 - 250000 4 - 625000 1 - 1250000 0 - */ - switch (RS485_Baud_Rate) { - case 19200: - SPBRG = 64; - TXSTAbits.BRGH = 1; - break; - case 38400: - SPBRG = 32; - TXSTAbits.BRGH = 1; - break; - case 57600: - SPBRG = 21; - TXSTAbits.BRGH = 1; - break; - case 76800: - SPBRG = 3; - TXSTAbits.BRGH = 0; - break; - case 115200: - SPBRG = 10; - TXSTAbits.BRGH = 1; - break; - case 9600: - default: - SPBRG = 129; - TXSTAbits.BRGH = 1; - break; - } - /* select async mode */ - TXSTAbits.SYNC = 0; - /* serial port enable */ - RCSTAbits.SPEN = 1; + I2C_Write_Block( + EEPROM_DEVICE_ADDRESS, + (char *)&RS485_Baud_Rate, + sizeof(RS485_Baud_Rate), + EEPROM_MSTP_BAUD_RATE_ADDR); } /**************************************************************************** @@ -371,17 +257,120 @@ void RS485_Initialize_Baud(void) * ALGORITHM: none * NOTES: none *****************************************************************************/ +void RS485_Initialize_Port(void) +{ + + /* Reset USART registers to POR state */ + TXSTA2 = 0; + RCSTA2 = 0; + /* configure USART for receiving */ + /* since the TX will handle setting up for transmit */ + RCSTA2bits.CREN = 1; + /* Interrupt on receipt */ + PIE3bits.RC2IE = 1; + /* enable the transmitter, disable its interrupt */ + TXSTA2bits.TXEN = 1; + PIE3bits.TX2IE = 0; + /* setup USART Baud Rate Generator */ + /* see BAUD RATES FOR ASYNCHRONOUS MODE in Data Book */ + /* Fosc=20MHz + BRGH=1 BRGH=0 + Rate SPBRG Rate SPBRG + ------- ----- ------- ----- + 9615 129 9469 32 + 19230 64 19530 15 + 37878 32 78130 3 + 56818 21 104200 2 + 113630 10 312500 0 + 250000 4 + 625000 1 + 1250000 0 + */ + switch (RS485_Baud_Rate) + { + case 19200: + SPBRG2 = 64; + TXSTA2bits.BRGH = 1; + break; + case 38400: + SPBRG2 = 32; + TXSTA2bits.BRGH = 1; + break; + case 57600: + SPBRG2 = 21; + TXSTA2bits.BRGH = 1; + break; + case 76800: + SPBRG2 = 3; + TXSTA2bits.BRGH = 0; + break; + case 115200: + SPBRG2 = 10; + TXSTA2bits.BRGH = 1; + break; + case 9600: + SPBRG2 = 129; + TXSTA2bits.BRGH = 1; + break; + default: + SPBRG2 = 129; + TXSTA2bits.BRGH = 1; + RS485_Set_Baud_Rate(9600); + break; + } + /* select async mode */ + TXSTA2bits.SYNC = 0; + /* enable transmitter */ + TXSTA2bits.TXEN = 1; + /* serial port enable */ + RCSTA2bits.SPEN = 1; + /* since we are using RS485, + we need to explicitly say + transmit enable or not */ + RS485_RX_DISABLE = 0; + RS485_TX_ENABLE = 0; +} + +/**************************************************************************** +* DESCRIPTION: Disables the RS485 hardware +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Disable_Port(void) +{ + RCSTA2 &= 0x4F; /* Disable the receiver */ + TXSTA2bits.TXEN = 0; /* and transmitter */ + PIE3 &= 0xCF; /* Disable both interrupts */ +} + +void RS485_Reinit(void) +{ + RS485_Set_Baud_Rate(9600); +} + +/**************************************************************************** +* DESCRIPTION: Initializes the data and the port +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ void RS485_Initialize(void) { - RS485_Initialize_Baud(); - /* configure interrupts */ - USART_TX_INT_DISABLE(); - USART_RX_INT_ENABLE(); - /* configure USART for receiving */ - /* since the TX will handle setting up for transmit */ - USART_CONTINUOUS_RX_ENABLE(); - /* since we are using RS485, - we need to explicitly say - transmit enable or not */ - RS485_TRANSMIT_DISABLE(); + /* Init the Rs485 buffers */ + RS485_Comstat.RxHead = 0; + RS485_Comstat.RxTail = 0; + RS485_Comstat.Rx_Bytes = 0; + RS485_Comstat.Rx_Bufferoverrun = FALSE; + RS485_Comstat.TxHead = 0; + RS485_Comstat.TxTail = 0; + RS485_Comstat.Tx_Bytes = 0; + + I2C_Read_Block( + EEPROM_DEVICE_ADDRESS, + (char *)&RS485_Baud_Rate, + sizeof(RS485_Baud_Rate), + EEPROM_MSTP_BAUD_RATE_ADDR); + + RS485_Initialize_Port(); } diff --git a/bacnet-stack/ports/pic18/rs485.h b/bacnet-stack/ports/pic18/rs485.h index 1f0c18db..3c72fdc8 100644 --- a/bacnet-stack/ports/pic18/rs485.h +++ b/bacnet-stack/ports/pic18/rs485.h @@ -38,18 +38,35 @@ #include #include "mstp.h" +#include "comm.h" + +extern COMSTAT RS485_Comstat; +extern volatile uint8_t RS485_Rx_Buffer[MAX_MPDU]; +extern volatile uint8_t RS485_Tx_Buffer[MAX_MPDU]; +extern uint32_t RS485_Baud_Rate; + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ + void RS485_Reinit(void); void RS485_Initialize(void); + void RS485_Disable(void); + void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port specific data */ uint8_t * buffer, /* frame to send (up to 501 bytes of data) */ uint16_t nbytes); /* number of bytes of data (up to 501) */ - void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port); /* port specific data */ + uint8_t RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port); /* port specific data */ + + void RS485_Interrupt_Rx(void); + + void RS485_Interrupt_Tx(void); + + uint32_t RS485_Get_Baud_Rate(void); + void RS485_Set_Baud_Rate(uint32_t baud); #ifdef __cplusplus }