📄 dsp_modem.c
字号:
u16 i; // Loop index.
u16 uReturnChar; // character from uart_read.
if(uUartBufferPointerIn != uUartBufferPointerOut) // UART data is available.
{
ulUartCounter = 0L; // Reset counter for use as timeout.
uAutoPollPause = 1; // Used to temporarily suspend auto poll.
// (this has no effect on a Slave)
// MASTER is receiving a command from the host.
if(uUartState == UART_RECEIVE_COMMAND) // MASTER is receiving command
{
// If we run into problems reading only one character at a time, this while loop instead of the
// proceding 'if' will read in all available UART characters.
// while( (UART_LSR_REG & UART_LSR_DR) && ( (uPlcState!=PLC_RECEIVE_POLLING) || (uUartCommandIndex < ((COMMAND_SIZE*2)-2)) ) )
// Don't receive last parm of command until any AutoPoll requests have been completed
if( ( (uPlcState!=PLC_RECEIVE_POLLING)&&(ulBerDelayCounter>ulBerDelay) ) || (uUartCommandIndex < ((COMMAND_SIZE*2)-2)) )
{
uart_read((u16*)&uUartCommand, uUartCommandIndex, 1); // read in a single character
uUartCommandIndex++; // Index in bytes.
if(uUartCommandIndex == COMMAND_SIZE*2) // MASTER has command ready to process. (COMMAND_SIZE*2 bytes)
{
uUartCommandIndex = 0; // Reset for next time.
ulAutoPollCounter = 0; // Delay periodic polling while executing commands from host.
ProcessMasterCommand();
}
}
}
// MASTER is receiving data. Don't make this a simple "if", we want to process
// the command between receiving command and receiving data.
else if(uUartState == UART_RECEIVE_DATA)
{
// Currently only data coming is Flash data to be programmed, but another
// possiblility would be sending generic data out the modem. A flag for
// different cases should be set in the commnand and tested here.
// For now just assume it's flash data and call Jim's routine.
// Don't receive last byte of data until the previous flash command has finished (or an error occurs).
if( ((uUartDataIndex+1) < uUartDataLength) || (uFlashWriteStatus != FLASH_STATUS_WRITING) )
{
if(uFlashWriteStatus >= FLASH_STATUS_TIMEOUT) // An error occurred.
{
WriteUARTValue(UART_TARGET_HOST, FLASH_ERROR + uFlashWriteStatus);
uUartState = UART_RECEIVE_COMMAND;
uFlashWriteStatus = FLASH_STATUS_COMPLETE;
}
else // read in the next character.
{
ulAutoPollCounter = 0; // Delay periodic polling while receiving data.
uart_read((u16*)&uUartDataArray, uUartDataIndex++, 1); // read in a single character
if(uUartDataIndex == uUartDataLength) // A full line received.
{
uUartState = UART_RECEIVE_COMMAND;
// Respond to host. This allows the host to send the next line of data.
WriteUARTValue(UART_TARGET_HOST, SUCCESS);
// This will result in the WriteFlash routine running.
uFlashWriteStatus = FLASH_STATUS_WRITING;
ulFlashWriteCounter = 0L; // Reset timeout counter
}
}
}
}
// MASTER or SLAVE is receiving data from eMeter.
else if(uUartState == UART_RECEIVE_RESPONSE)
{
if(uBoard == BOARD_MASTER)
{
// Data from the emeter has to go to the host.
// The host receives a fixed number of characters every read, and since the
// emeter return size is variable, we'll pad the response and send the maximum
// that could fit in a PLC packet, or 122 bytes (we'll be reading the same
// kind of data from the slave, so this is reasonable).
//
// We can't send response data directly to the host, because the single
// 16C550 handles both data streams and we need to reconfigure it first.
// So we'll buffer the characters in upUartResponseBuffer[] and send the
// buffer when we receive an end of line character. The global pointer,
// uUartResponseIndex, will be initialized by the command function.
// read in a single character
uReturnChar = uart_read((u16*)upUartResponseBuffer, uUartResponseIndex++, 1);
// Test for end of response.
if( (uReturnChar == 0xD) // Check for '\r'
|| (uUartResponseIndex >= 122) ) // No more room - something went wrong...
{
// Fill in remaining bytes with 0.
// This loop operates on a word-by-word basis. The (index+1)/2 will move us
// to the next word if we ended on an odd byte.
for(i=(uUartResponseIndex+1)/2; i<122/2; i++)
{
upUartResponseBuffer[i] = 0;
}
WriteUART(UART_TARGET_HOST, 122/2, (u16*)upUartResponseBuffer);
ulAutoPollCounter = 0L;
uAutoPollPause=0; // Release AutoPoll.
uUartState = UART_RECEIVE_COMMAND;
}
}
else // uBoard == BOARD_SLAVE
{
// read in a single character
uReturnChar = uart_read((u16*)txUserDataArray, uUartResponseIndex++, 1);
// Test for end of response.
if( (uReturnChar == 0xD) // Check for '\r'
|| (uUartResponseIndex >= 126) ) // No more room - something went wrong...
{
// Fill in the rest of the buffer with zeros
for(i=(uUartResponseIndex+1)/2; i<126/2; i++)
{
txUserDataArray[i] = 0;
}
uTransmitPacketReady = 1;
uPlcState = PLC_RECEIVE_COMMAND;
uUartState = UART_IDLE;
}
}
}
}
}
//==========================================================================================
// Function: SendPLC()
//
// Description: Manage outgoing PL data.
//
// Revision History:
//==========================================================================================
void SendPLC(void)
{
if( (uTransmitPacketReady==1) // Outgoing packet ready
&& (agcState!=AgcHold) // & not receiving data
&& (preambleDetCount == 0) ) // & not receiving preamble
{
uCommandBlock = 0; // Re-enable packet reception.
// Almost all slave commands come through this
// point eventually so re-enable here instead of in
// each command. The two exceptions are BER and
// broadcast e-meter commands which are handled
// separately.
TransmitPacket(); // Send out packet txUserDataArray[]
uTransmitPacketReady = 0; // Reset flag.
agcState = AgcIdle; // Turn off AGC hold in case it got turned on by our transmit signal.
}
}
//==========================================================================================
// Function: SendUART()
//
// Description: Manage outgoing UART data.
// In order to keep all data on a word boundary, it is always sent in two
// byte pairs. Because there is no way to see exactly how much room there
// is in the FIFO (can only check TEMT for empty or THRE for full), this
// function waits for a completely empty FIFO before sending any characters
// to prevent idle waiting for characters to be transmitted (which would
// occur if there was only room for one byte and we had to wait for THRE
// before sending the second half of a word). When the FIFO is empty,
// eight words are sent (if there are that many to send).
//
// Revision History:
//==========================================================================================
void SendUART(void)
{
static u16 index = 0;
u16 uSentWords = 0; // Keep track of bytes sent out each pass
u16 uStartingTarget; // Local flag - Used to prevent switching targets
// before all data is sent.
// Check if the FIFO is empty.
if(UART_LSR_REG & UART_LSR_TEMT)
{
UART_IER_REG &= 0xFFFD; // disable transmit empty interrupt. This is only
// enabled for the end of an emeter transmission.
// If there's data to go out, set the appropriate target.
if(UARTDataOut[index].count != 0)
{
if(UARTDataOut[index].target == UART_TARGET_EMETER)
{
SelectUARTTarget(UART_TARGET_EMETER);
SelectRS485Direction(RS485_TALK);
}
else
{
SelectUARTTarget(UART_TARGET_HOST);
}
uStartingTarget = uUARTTarget; // Note the target - can only send to one
// target in amy given pass through the loop.
}
// Send out up to 8 words (FIFO is 16 bytes). Must be to same target.
// Further, if the target is the emeter, can only send a single message - even
// if there's room in the fifo for more characters.
while( (UARTDataOut[index].count > 0)
&& (uSentWords++ < 8)
&& (uStartingTarget == UARTDataOut[index].target) )
{
// For the RS485 we're sending ASCII, which is stored with one char in each
// word. So if the Target is EMETER, do not send the high byte.
if(UARTDataOut[index].target == UART_TARGET_HOST)
{
// Send high byte to 16C550
UART_THR_REG = (UARTDataOut[index].dataPtr[0] & 0xFF00) >> 8;
}
// Send low byte (regardless of target).
UART_THR_REG = UARTDataOut[index].dataPtr[0] & 0xFF;
UARTDataOut[index].dataPtr++; // Increment pointer to next word
if(--UARTDataOut[index].count == 0) // Decrement count and test for end
{
// At the end of an emeter packet enable the interrupt so we can switch
// to listen right away in order to not miss a response.
if(uStartingTarget == UART_TARGET_EMETER)
{
UART_IER_REG |= 0x02; // Allow transmit empty interrupt.
uSentWords = 10; // Don't allow any more to go out. As soon as the
// last word of the string we just sent is
// transmitted, the RS485 will be switched
// to LISTEN (so additional bytes sent
// wouldn't go out anyway).
uHoldOffPLC = 1;
uLastByteFlag = 1;
}
if(++index == SIZE_UART_OUT_ARRAY) // Check for end of array
{
index = 0;
}
}
}
}
DebugDelay(); // Flush C54x if in debug mode.
}
//==========================================================================================
// Function: BERTest()
//
// Description: Handles sending BER packets from master to slave for BER testing.
//
// Revision History:
//==========================================================================================
void BERTest(void)
{
static u16 uFirstPass = 1;
if( (uBerTestInProgress == 1)
&& (uBoard == BOARD_MASTER)
&& (uPlcState != PLC_RECEIVE_RESPONSE)
&& (ulBerCounter < ulNumBerPackets)
&& (uTransmitPacketReady == 0) ) // Make sure the last one went out.
{
if(uFirstPass == 1) // Only do this once per packet
{
uFirstPass = 0;
ulBerDelayCounter = 0L;
}
// Now wait an addition time for the slave to process the last packet.
else if(ulBerDelayCounter > ulBerDelay) // This many Timer0 interrupts. (62 usec/int)
{
memset(txUserDataArray, 0, DATA_BUFFER_LEN*sizeof(txUserDataArray[0])); // Fill User Data buffer with zeroes
*(u32*)&txUserDataArray[0] = ulBERSlaveAddr; // Dest address
*(u32*)&txUserDataArray[2] = ulMyAddr; // Source address
txUserDataArray[4] = SC_BER; // This is a BER packet.
txUserDataArray[5] = (u16) (ulBerCounter>>16); // Send count used to check for
txUserDataArray[6] = (u16) (ulBerCounter & 0xFFFF); // missed packets.
ulBerCounter++;
uTransmitPacketReady = 1;
ulAutoPollCounter = 0; // Delay periodic polling while performing BER test.
uFirstPass = 1;
SendPLC(); // Get it out here before ReceiveUART has a chance to corrupt.
}
}
if( (ulBerCounter == ulNumBerPackets) // We've completed the test.
&& (uBerTestInProgress == 1)
&& (uTransmitPacketReady == 0) ) // Make sure the last one went out.
{
memset(txUserDataArray, 0, DATA_BUFFER_LEN*sizeof(txUserDataArray[0])); // Fill User Data buffer with zeroes
uBerTestInProgress = 0; // Stop sending packets.
ulAutoPollCounter = 0L;
uAutoPollPause = 0; // Release AutoPoll.
// Send command to slave signalling end of test so it stops counting CRC errors
*(u32*)&txUserDataArray[0] = ulBERSlaveAddr; // Dest address
*(u32*)&txUserDataArray[2] = ulMyAddr;
txUserDataArray[4] = SC_ABORT_BER; // Command number = slave abort BER.
uTransmitPacketReady = 1; // Send completed command to the SLAVE.
SendPLC(); // Get it out here before ReceiveUART has a chance to corrupt.
}
}
//==========================================================================================
// Function: AutoPoll()
//
// Description: Handles idle polling of SLAVE when appropriate.
//
// Revision History:
//==========================================================================================
void AutoPoll(void)
{
if( (uAutoPoll==1)
&& (uAutoPollPause==0)
&& (uBoard==BOARD_MASTER)
&& (ulAutoPollCounter>AUTO_POLL_COUNT)
&& (uTransmitPacketReady == 0) // Make sure the last one went out.
&& (uPlcState==PLC_IGNORE) )
{
// Issue periodic polling command.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -