/*
* FreeModbus Libary: BARE Port
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: portserial.c,v 1.1 2006/08/22 21:35:13 wolti Exp $
*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
/* ----------------------- static variables ---------------------------------*/
static eMBParity eCurrParity;
/* ----------------------- functions ---------------------------------*/
UCHAR CalcParity( UCHAR ucData );
/* ----------------------- Start implementation -----------------------------*/
void
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
/* If xRXEnable enable serial receive interrupts. If xTxENable enable
* transmitter empty interrupts.
*/
if(xRxEnable == TRUE)
{
set_bit(rcsta, CREN);
set_bit(pie1, RCIE);
//485 status determined by xTxEnable state
}
else
{
clear_bit(pie1, RCIE);
clear_bit(rcsta, CREN);
//485 status determined by xTxEnable state
}
if(xTxEnable == TRUE)
{
set_bit(pie1, TXIE);
TRANSMIT_ON_485();
//Allow time for bus to turn around.
delay_10us(1);
}
else
{
clear_bit(pie1, TXIE);
//Bad way to do this, but wait for TX complete
while(txsta.TRMT == 0);
RECEIVE_ON_485();
}
//Enable peripheral and global ints
set_bit(intcon, GIEL);
// set_bit(intcon, GIEH);
}
BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
BOOL ucReturn;
/* prevent compiler warning. */
(void)ucPORT;
/* Only supporting RTU so always 8 data bits */
(void)ucDataBits;
set_bit(rcsta, SPEN);
//Int priority low
clear_bit(ipr1, RCIP);
clear_bit(ipr1, TXIP);
// Make sure serial pins are NOT digital outputs
set_bit(trisb, 1);
set_bit(trisb, 4);
// Turn off A/D for serial pins
set_bit(adcon1, 5);
set_bit(adcon1, 6);
baudctl = 0x08; //Set BRG16 bit
//Set 16 bit baudrate count
spbrg = (4000000/(16*ulBaudRate)) - 1;
//Save parity since it is generated programatically
eCurrParity = eParity;
//Since RTU only, for tx parity will be on 9th data bit or
// 9th data bit set to 0 to be 2nd stop bit
set_bit(txsta, TX9);
set_bit(rcsta, RX9);
if(eParity == MB_PAR_NONE)
{
//Do not receive 9th bit in case sender doesn't have 2 stop bits.
clear_bit(rcsta, RX9);
//Clear 9th data bit for case of no parity to do 2 stop bits.
clear_bit(txsta, TX9D);
}
//Leave transmit enabled
set_bit(txsta, TXEN);
vMBPortSerialEnable( FALSE, FALSE );
return TRUE;
}
BOOL
xMBPortSerialPutByte( CHAR ucByte )
{
/* Put a byte in the UARTs transmit buffer. This function is called
* by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
* called. */
/* We need to generate TX parity, if enabled */
switch(eCurrParity)
{
case MB_PAR_EVEN:
if(CalcParity(ucByte) == 0 )
{
clear_bit(txsta, TX9D);
}
else
{
set_bit(txsta, TX9D);
}
break;
case MB_PAR_ODD:
if(CalcParity(ucByte) == 0 )
{
set_bit(txsta, TX9D);
}
else
{
clear_bit(txsta, TX9D);
}
break;
}
//Write the data byte
txreg = ucByte;
return TRUE;
}
BOOL
xMBPortSerialGetByte( CHAR * pucByte )
{
/* Return the byte in the UARTs receive buffer. This function is called
* by the protocol stack
*/
*pucByte = rcreg;
return TRUE;
}
void vMBPortClose( void )
{
}
/******************************************************************************
* Name: CalcParity
* Description: Calculates parity of ucData
* Uses:
*
* Returns: Parity of ucData in bit 0 of returned UCHAR: 0 = even, 1 = odd
*
* NOTE: For TX of 9 bit Even Parity, send the bit returned here in the 9th bit.
* For TX of 9 bit Odd Parity, send the complement of the returned bit in the 9th bit.
* For RX of 9 Bit Even Parity, parity is good if returned bit matches 9th RX bit.
* For RX of 9 bit Odd Parity, parity is good if returned bit is complement of 9th RX bit.
*****************************************************************************/
UCHAR CalcParity( UCHAR ucData )
{
asm
{
movf _ucData, W
;8-bit parity
;This routine will leave the parity of ucData in _ucData.0
;while blenderizing most of the rest of _ucData
swapf _ucData, W ;x = abcdefgh w = efghabcd
xorwf _ucData, F ;x = abcdefgh w = efghabcd
rrcf _ucData, W ;x = abcdefgh w = -abcdefg
xorwf _ucData, F ;x = abcdefgh w = -abcdefg
; at this point, the parity for half the bits
; (a, b, e, and f) is in bit 2 of X, and the
; parity for the other half (bits c, d, g, and h)
; is in bit 0 of X.
btfsc _ucData, 2 ; if the parity of (a,b,e,f) is 0,
; then the parity of (a,b,c,d,e,f,g,h)
; is equal to the parity of (c,d,g,h)...
; which is already in bit 0, so skip ahead.
incf _ucData, F ; otherwise, the parity of (a,b,e,f) is 1,
; so the parity of (a,b,c,d,e,f,g,h) is
; NOT equal to the parity of (c,d,g,h).
; invert bit 0.
; at this point, bit 0 of _ucData contains the parity of
; (a,b,c,d,e,f,g,h).
}
return ucData & 0x01;
}
Copyright © 2006 SourceBoost Technologies