713 lines
19 KiB
C

/*******************************************************************************
* *
* Copyright 2010 Rheinmetall Canada Inc. *
* *
* No part of this document may be reproduced, stored in *
* a retrieval system, or transmitted, in any form or by any means, *
* electronic, mechanical, photocopying, recording, or otherwise, *
* without the prior written permission of Rheinmetall Canada Inc. *
* *
*******************************************************************************/
/*
Description:
This is a template file for standard C code file.
*/
/* ************************************************************************** */
/* ¤Revision:
000 20100616 JFM,
Original version.
### YYYYMMDD Initial, Bug Identification
Change description.
*/
/* ************************************************************************** */
/* Includes */
#include "define.h"
#include "Uart.h"
#include "Internaluart.h"
#include <stdio.h>
#include <string.h>
//#include "Watchdog.h"
#ifndef NO_EXTERNAL_UART
#include "sc16IS740Driver.h"
#endif
#include "digitalio.h"
//#include "DriveProtocol.h"
#include "terminal.h"
#include "NetworkProtocol.h"
#include "LoraInterface.h"
/* ************************************************************************** */
/* Local variables */
stUartData astUartData[MAX_UART_HANDLE];
const char *gUartStrings[MAX_UART_HANDLE] = { "PRINTF" //UART_1
//,"CU", //UART_2
// ,"CONSOLE" //UART_3
};
/* ************************************************************************** */
/* Private function prototypes */
//void _mon_putc(char c); //override from stdio to redirect stdout on uart 3B
//void _mon_write (const char * s, unsigned int count);
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void InitUart(void)
{
int i;
InternalUartInit();
//InitSC16S740();
memset(&astUartData,0,sizeof(astUartData));
for(i = 0; i < MAX_UART_HANDLE; i++)
{
astUartData[i].iDataPending = 0; //This flag is 0 when : TxPtr == RxPtr OR Uart is transmitting.
astUartData[i].pcTxInPtr = &astUartData[i].acTxCircularBuffer[0];
astUartData[i].pcTxOutPtr = &astUartData[i].acTxCircularBuffer[0];
//memset(&astUartData[i].acTxCircularBuffer[0],0xDE,UART_MAX_TX_BUFF_SIZE);
astUartData[i].pcRxInDataPtr = astUartData[i].pcRxOutDataPtr = &astUartData[i].acRxCircularBuffer[0];
astUartData[i].iNbRxFIFOPendingBytes = 0;
}
//This is a physical mapping of the UARTS.
//DO NOT CHANGE assignments unless hardware changed !
//
astUartData[UART_1].iIsInternal = 1;
astUartData[UART_1].iPhysicalUartPort = INTERNAL_UART_PORT_1; // (232)
astUartData[UART_2].iIsInternal = 1;
astUartData[UART_2].iPhysicalUartPort = INTERNAL_UART_PORT_2; // (232)
#ifndef NO_EXTERNAL_UART
astUartData[UART_3].iIsInternal = 0;
astUartData[UART_3].iPhysicalUartPort = EXT_UART_1; // (SPI - 232 daughter board)
#endif
setbuf(stdout,NULL); //to use printf without \r
fflush(stdout);
UartOpenComPort(NETWORK_UART_PORT,9600,UART_ONE_STOP_BIT,UART_NO_PARITY); //Open Network port
UartOpenComPort(LORA_MODULE_UART_PORT,9600,UART_ONE_STOP_BIT,UART_NO_PARITY); //Open Lora module port
#ifdef USE_PRINTF
//UartOpenComPort(CONSOLE_UART_PORT,115200,UART_ONE_STOP_BIT,UART_NO_PARITY); //Open console port
#endif
}
//-----------------------------------------------------------------------------
int UartResetPort(int p_iUartHandle)
{
if(p_iUartHandle > MAX_UART_HANDLE)
return 0;
//reset the port data structures...
astUartData[p_iUartHandle].iDataPending = 0; //This flag is 0 when : TxPtr == RxPtr OR Uart is transmitting.
astUartData[p_iUartHandle].pcTxInPtr = &astUartData[p_iUartHandle].acTxCircularBuffer[0];
astUartData[p_iUartHandle].pcTxOutPtr = &astUartData[p_iUartHandle].acTxCircularBuffer[0];
astUartData[p_iUartHandle].pcRxInDataPtr = astUartData[p_iUartHandle].pcRxOutDataPtr = &astUartData[p_iUartHandle].acRxCircularBuffer[0];
astUartData[p_iUartHandle].iNbRxFIFOPendingBytes = 0;
if(astUartData[UART_1].iIsInternal == 1)
{
switch(astUartData[p_iUartHandle].iPhysicalUartPort)
{
case INTERNAL_UART_PORT_1:
{
ResetUart1();
break;
}
case INTERNAL_UART_PORT_2:
{
ResetUart2();
break;
}
default:
break;
}
}
else
{
#ifndef NO_EXTERNAL_UART
switch(astUartData[p_iUartHandle].iPhysicalUartPort)
{
case EXT_UART_1:
{
break;
}
default:
break;
}
#endif
}
return 1;
}
//-----------------------------------------------------------------------------
int UartOpenComPort(int p_iUartHandle, int p_iBaudRate, int p_iNbStopBits, int p_iParityEnable)
{
int iStopbits,iParity,iRet;
if(p_iUartHandle >= MAX_UART_HANDLE || p_iUartHandle < 0)
return UART_INVALID_HANDLE;
if(astUartData[p_iUartHandle].iIsInternal == 1)
{
switch(p_iNbStopBits)
{
case UART_ONE_STOP_BIT:
case UART_ONE_HALF_STOP_BIT: //1½ stop bits doesn't exist for internal uart
{
iStopbits = INT_UART_ONE_STOP_BIT;
break;
}
case UART_TWO_STOP_BITS:
{
iStopbits = INT_UART_TWO_STOP_BITS;
break;
}
}
switch(p_iParityEnable)
{
case UART_NO_PARITY:
{
iParity = INT_UART_NO_PARITY;
break;
}
case UART_EVEN_PARITY:
{
iParity = INT_UART_EVEN_PARITY;
break;
}
case UART_ODD_PARTIY:
{
iParity = INT_UART_ODD_PARITY;
break;
}
}
iRet = OpenInternalPort(astUartData[p_iUartHandle].iPhysicalUartPort,
p_iUartHandle,
&astUartData[p_iUartHandle].acTxCircularBuffer[0],
&astUartData[p_iUartHandle].acTxCircularBuffer[UART_MAX_TX_BUFF_SIZE-1],
p_iBaudRate,
iStopbits,
iParity);
}
#ifndef NO_EXTERNAL_UART
else
{
switch(p_iNbStopBits)
{
case UART_ONE_STOP_BIT:
{
iStopbits = ONE_STOP_BIT;
break;
}
case UART_ONE_HALF_STOP_BIT: //1½ stop bits doesn't exist for internal uart
{
iStopbits = ONE_HALF_STOP_BIT;
break;
}
case UART_TWO_STOP_BITS:
{
iStopbits = TWO_STOP_BITS;
break;
}
}
switch(p_iParityEnable)
{
case UART_NO_PARITY:
{
iParity = NO_PARITY;
break;
}
case UART_EVEN_PARITY:
{
iParity = EVEN_PARITY;
break;
}
case UART_ODD_PARTIY:
{
iParity = ODD_PARITY;
break;
}
}
iRet = OpenExternalPort(astUartData[p_iUartHandle].iPhysicalUartPort,
p_iUartHandle,
&astUartData[p_iUartHandle].acTxCircularBuffer[0],
&astUartData[p_iUartHandle].acTxCircularBuffer[UART_MAX_TX_BUFF_SIZE-1],
p_iBaudRate,
iStopbits,
iParity);
}
#endif
return iRet;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//All the uart callback function assignment must be done here !!!
//This must be changed if hardware changes or if port assignment is changed !!!
//
int UartReceiveData(int p_iUartHandle, char *p_pcBuffer, int p_iSize)
{
int i;
stUartData *p_stUartDatPtr = &astUartData[p_iUartHandle];
if(p_iUartHandle < 0 && p_iUartHandle >= MAX_UART_HANDLE)
{
//TODO: Flag a logic error !
return 0;
}
for(i = 0; i < p_iSize; i++)
{
*p_stUartDatPtr->pcRxInDataPtr++ = *p_pcBuffer++;
if(p_stUartDatPtr->pcRxInDataPtr > &p_stUartDatPtr->acRxCircularBuffer[UART_MAX_RX_BUFF_SIZE-1])
{
p_stUartDatPtr->pcRxInDataPtr = &p_stUartDatPtr->acRxCircularBuffer[0]; //wrap pointer
// printf("Wrap\n");
}
}
p_stUartDatPtr->iNbRxFIFOPendingBytes += p_iSize;
if(p_stUartDatPtr->iNbRxFIFOPendingBytes >= UART_MAX_RX_BUFF_SIZE)
PRINTF("RX FIFO Overflow\n");
/* switch(p_iUartHandle)
{
case UART_0:
{
break;
}
case UART_1:
{
break;
}
case UART_2:
{
break;
}
case UART_3:
{
break;
}
case UART_4:
{
break;
}
case UART_5:
{
break;
}
} */
return 1;
}
int UartGetPendingDataSize(int iUartHandle)
{
stUartData *p_stUartDatPtr = &astUartData[iUartHandle];
if(p_stUartDatPtr->pcRxInDataPtr == p_stUartDatPtr->pcRxOutDataPtr)
{
return 0;
}
else if(p_stUartDatPtr->pcRxOutDataPtr < p_stUartDatPtr->pcRxInDataPtr)
{
return(p_stUartDatPtr->pcRxInDataPtr - p_stUartDatPtr->pcRxOutDataPtr);
}
else
{
int size = &p_stUartDatPtr->acRxCircularBuffer[UART_MAX_RX_BUFF_SIZE-1] - p_stUartDatPtr->pcRxOutDataPtr;
size += p_stUartDatPtr->pcRxInDataPtr - &p_stUartDatPtr->acRxCircularBuffer[0];
return size;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int UartTransmitData(int p_iUartHandle, char *p_pcBuffer, int p_iSize)
{
int iRet = 0;
// Case where OutPtr < InPtr
// * = Available space
//
//Top ---->|---------------|
// | * |
//OutPtr ->| |
// | |
// | (p_pcBuffer) | //Available size = (OutPtr - Top) + (Bottom - InPtr)
// | |
//InPtr -->| |
// | * |
// | * |
//Bottom ->|---------------|
// Case where OutPtr > InPtr
// * = Available space
//
//Top ---->|---------------|
// | |
//InPtr -->| |
// | * |
// | * | //available size = OutPtr - InPtr
// | * |
//OutPtr ->| |
// | (p_pcBuffer) |
// | |
//Bottom ->|---------------|
//Check if data buffer fits in remaining circular buffer space
if(astUartData[p_iUartHandle].pcTxOutPtr < astUartData[p_iUartHandle].pcTxInPtr)
{
//Calculate remaining buffer space and check if it's enough to fit requested data buffer
if(p_iSize > ((astUartData[p_iUartHandle].pcTxOutPtr - &astUartData[p_iUartHandle].acTxCircularBuffer[0]) + //Outptr - Top
(&astUartData[p_iUartHandle].acTxCircularBuffer[UART_MAX_TX_BUFF_SIZE-1] - astUartData[p_iUartHandle].pcTxInPtr))) //Bottom - Inptr
{
//Drop remaining packets, flush buffer
astUartData[p_iUartHandle].iDataPending = 0;
astUartData[p_iUartHandle].pcTxInPtr = &astUartData[p_iUartHandle].acTxCircularBuffer[0];
astUartData[p_iUartHandle].pcTxOutPtr = &astUartData[p_iUartHandle].acTxCircularBuffer[0];
return UART_BUFFER_FULL;
}
}
else if(astUartData[p_iUartHandle].pcTxInPtr < astUartData[p_iUartHandle].pcTxOutPtr)
{
//Calculate remaining buffer space and check if it's enough to fit requested data buffer
if(p_iSize > (astUartData[p_iUartHandle].pcTxOutPtr - astUartData[p_iUartHandle].pcTxInPtr))
{
//Drop remaining packets, flush buffer
astUartData[p_iUartHandle].iDataPending = 0; //Force data pending flag to flush buffer
astUartData[p_iUartHandle].pcTxInPtr = &astUartData[p_iUartHandle].acTxCircularBuffer[0];
astUartData[p_iUartHandle].pcTxOutPtr = &astUartData[p_iUartHandle].acTxCircularBuffer[0];
return UART_BUFFER_FULL;
}
}
else //OutPtr = InPtr
{
if(p_iSize > UART_MAX_TX_BUFF_SIZE - 1) //message is too big to fit in buffer !!!
{
//Drop remaining packets, flush buffer
astUartData[p_iUartHandle].iDataPending = 0; //Force data pending flag to flush buffer
astUartData[p_iUartHandle].pcTxInPtr = &astUartData[p_iUartHandle].acTxCircularBuffer[0];
astUartData[p_iUartHandle].pcTxOutPtr = &astUartData[p_iUartHandle].acTxCircularBuffer[0];
return UART_BUFFER_FULL;
}
}
int i;
for(i = 0; i < p_iSize; i++)
{
*astUartData[p_iUartHandle].pcTxInPtr++ = *p_pcBuffer++; //fill circular buffer
if(astUartData[p_iUartHandle].pcTxInPtr > &astUartData[p_iUartHandle].acTxCircularBuffer[UART_MAX_TX_BUFF_SIZE-1]) //check for wrapping
{
astUartData[p_iUartHandle].pcTxInPtr = &astUartData[p_iUartHandle].acTxCircularBuffer[0];
}
}
//Now flag pending data for transmission.
astUartData[p_iUartHandle].iDataPending = 1; //The data send will start on next Main loop processing
return iRet;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//Some data has been entirely sent
//Move output pointer
//
int DataSentNotification(int p_iUartHandle,int DataSize)
{
//Check wrapping.
if(astUartData[p_iUartHandle].pcTxOutPtr + DataSize < &astUartData[p_iUartHandle].acTxCircularBuffer[UART_MAX_TX_BUFF_SIZE])
{
astUartData[p_iUartHandle].pcTxOutPtr += DataSize;
}
else //Pointer must wrap
{
//Top ------>|---------------|
// | * |
//Final Pos->| | // Final Pos = Top + *
// | |
// | (buffer) | // DataSize = & + *
// | | // & = Bottom - OutPtr
//OutPtr --->| | // * = DataSize - &
// | & | // FinalPos = Top + (DataSize - (Bottom - OutPtr))
// | & |
//Bottom --->|---------------|
// if(p_iUartHandle != PRINTF_UART_PORT)
// printf("Out wrap\r");
DataSize -= (&astUartData[p_iUartHandle].acTxCircularBuffer[UART_MAX_TX_BUFF_SIZE] - astUartData[p_iUartHandle].pcTxOutPtr); //p_iSize - (Bottom - OutPtr)
astUartData[p_iUartHandle].pcTxOutPtr = &astUartData[p_iUartHandle].acTxCircularBuffer[0] + DataSize; //Top + new p_iSize
}
//Check if data is pending in buffer
if(astUartData[p_iUartHandle].pcTxOutPtr != astUartData[p_iUartHandle].pcTxInPtr)
{
astUartData[p_iUartHandle].iDataPending = 1;
}
else
{
astUartData[p_iUartHandle].iDataPending = 0;
}
return UART_OK;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//Called by main loop. Check if any uart has data pending to be sent
//
int UartTick(void)
{
int i = 0;
int iRet;
int p_iSize;
char aTempBuffer[UART_MAX_RX_BUFF_SIZE];
TickInternalUart();
//Send...
for(i = 0; i < MAX_UART_HANDLE; i++)
{
if(astUartData[i].iDataPending)
{
char *pcTxInPtr = astUartData[i].pcTxInPtr;
//Check remaining data size.
if(astUartData[i].pcTxOutPtr < pcTxInPtr)
{
p_iSize = pcTxInPtr - astUartData[i].pcTxOutPtr;
}
else
{
p_iSize = ((&astUartData[i].acTxCircularBuffer[UART_MAX_TX_BUFF_SIZE] - astUartData[i].pcTxOutPtr) +
(pcTxInPtr - &astUartData[i].acTxCircularBuffer[0]));
}
if(astUartData[i].iIsInternal) //Uart handle mapped to PIC internal uart
{
astUartData[i].iDataPending = 0;
iRet = SendInternalUartData(astUartData[i].pcTxOutPtr,
p_iSize,
astUartData[i].iPhysicalUartPort,
&astUartData[i].acTxCircularBuffer[0],
&astUartData[i].acTxCircularBuffer[UART_MAX_TX_BUFF_SIZE-1]);
}
#ifndef NO_EXTERNAL_UART
else //mapped to external uart
{
astUartData[i].iDataPending = 0;
iRet = SendExternalUartData(astUartData[i].iPhysicalUartPort, astUartData[i].pcTxOutPtr, p_iSize,&astUartData[i].acTxCircularBuffer[0], &astUartData[i].acTxCircularBuffer[UART_MAX_TX_BUFF_SIZE-1]);
}
#endif
//TODO: manage return values
switch(iRet)
{
case UART_OK:
{
break;
}
case UART_PORT_BUSY:
case UART_BUFFER_FULL:
{
astUartData[i].iDataPending = 1;
break;
}
case UART_PORT_NOT_OPENED:
{
break;
}
}
}
//Receive...
// int iNbPendingData = astUartData[i].iNbRxFIFOPendingBytes; //JFM 2012-09-05
int iNbPendingData = UartGetPendingDataSize(i);
if(iNbPendingData > 0)
{
int byte;
for(byte = 0; byte < iNbPendingData; byte++)
{
aTempBuffer[byte] = *astUartData[i].pcRxOutDataPtr++;
if(astUartData[i].pcRxOutDataPtr > &astUartData[i].acRxCircularBuffer[UART_MAX_RX_BUFF_SIZE-1])
astUartData[i].pcRxOutDataPtr = &astUartData[i].acRxCircularBuffer[0]; //wrap pointer
}
astUartData[i].iNbRxFIFOPendingBytes -= iNbPendingData;
switch(i)
{
// case DRIVE_UART_PORT:
// {
// //printf("drive rx\n");
// DriveProtocolRxData(aTempBuffer,iNbPendingData);
// break;
// }
// case CU_UART_PORT:
// {
// CUProtocolRxData(aTempBuffer,iNbPendingData); // HCAM 20120918
// break;
// }
case NETWORK_UART_PORT:
{
//HEARTBEAT_LED_1_TOGGLE_REG = HEARTBEAT_LED_1_TOGGLE_MASK;
//UartTransmitData(CONSOLE_UART_PORT, aTempBuffer, iNbPendingData);//echo received character
int i = 0;
for(i = 0; i< iNbPendingData; i++)
{
ProtocolAnalyzeNewData(aTempBuffer[i]);
//RxTerminalData(aTempBuffer[i]);
}
break;
}
case LORA_MODULE_UART_PORT:
{
//HEARTBEAT_LED_1_TOGGLE_REG = HEARTBEAT_LED_1_TOGGLE_MASK;
//UartTransmitData(CONSOLE_UART_PORT, aTempBuffer, iNbPendingData);//echo received character
int i = 0;
for(i = 0; i< iNbPendingData; i++)
{
LoraInterfaceRxData(aTempBuffer[i]);
}
break;
}
}
}
}
return UART_OK;
}
//-----------------------------------------------------------------------------
//
// This function is used in the case of a large amount of data to be sent or received
// in a process without going back to main loop.
void UartBlockAndTick(unsigned int TickCount)
{
int i;
// KickWatchdog();
for(i = 0; i < TickCount; i++)
{
UartTick();
}
// KickWatchdog();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
// This function is used in the case of a large amount of data to be sent or received
// in a process without going back to main loop.
int UartBlockUntillBufEmpty(int iUartHandle)
{
if(iUartHandle >= MAX_UART_HANDLE)
return 0;
// KickWatchdog();
while(astUartData[iUartHandle].iDataPending)
{
UartTick();
}
// KickWatchdog();
return 1;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//Overload the stdio character output routine to redirect printfs
//
//void _mon_putc(char c)
//{
// KickWatchdog();
// U2TXREG = c;
// while (U2STAbits.TRMT==0);
//#ifdef USE_BLOCKING_PRINTF
// switch(CONSOLE_UART_PORT)
// {
// case UART_1: //(422) Uart 1B
// {
// if(U1MODEbits.ON == 1)
// {
// U1TXREG = c;
// while (U1STAbits.TRMT==0);
// }
// break;
// }
// case UART_2: //(422) Uart 2A
// {
// if(U2MODEbits.ON == 1)
// {
// U2TXREG = c;
// while (U2STAbits.TRMT==0);
// }
// break;
// }
// }
//#else
// UartTransmitData(PRINTF_UART_PORT, &c, 1);
//#endif
// UartTransmitData(CONSOLE_UART_PORT, &c, 1);
// Nop();
// KickWatchdog();
//}
/*
void _mon_write (const char * s, unsigned int count)
{
#ifdef USE_BLOCKING_PRINTF
int i;
for(i = 0; i < count; i++)
_mon_putc(*s++);
#else
UartTransmitData(UART_10, s, count);
#endif
}*/
//EOF