⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dsp_modem.c

📁 DSP 5409 plc应用程序,调试通过,是用在电力线通讯上的演示程序.
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -