//#############################################################################################################################################################################################################
#include "IdiBusSerialLine.h"
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
IdiBusSerialLine::IdiBusSerialLine(void) : IdiBusSerial()
{
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
uint8_t IdiBusSerialLine::sendMMES (IdiBusMMES *MMES)
{
 if ( MMES->IsValid() == 0 ) { return IDIERMST_INVALID_TX_REQUEST_FORMAT; }
 
 uint8_t *TxMesBuf = this->getTxBufPointer();
 if ( TxMesBuf == NULL ) { return IDIERMST_TX_MES; }
 
 uint8_t *RxMesBuf = this->getRxBufPointer();
 uint8_t DataPos;

 // Fill Header
 TxMesBuf[IDIMMES_ADDR_Pos] =  MMES->SlAddr;
 TxMesBuf[IDIMMES_MMPS_Pos] = (MMES->MMPS.LongMes          << IDIMMES_MMPS_LONG_MES_Pos)    |
						      (IDIMMES_MMPS_MES_TYPE_MMES  << IDIMMES_MMPS_MES_TYPE_Pos)    | 
							  (0x00U                       << IDIMMES_MMPS_FAST_FUNC_Pos)   |
							  (MMES->MMPS.AlarmMes         << IDIMMES_MMPS_ALARM_FRAME_Pos) | 
							  (MMES->MMPS.EncryptedAes     << IDIMMES_MMPS_ENCRYPTED_AES_Pos); 
 TxMesBuf[IDIMMES_DEV_Pos]  = (MMES->DEV.NUM << IDIMMES_DEV_NUM_Pos)   | (MMES->DEV.ALLCH << IDIMMES_DEV_ALLCH_Pos);
 TxMesBuf[IDIMMES_CHNL_Pos] = (MMES->CHNL.NUM << IDIMMES_CHNL_NUM_Pos) | (MMES->CHNL.ALLSAME << IDIMMES_CHNL_ALLSAME_Pos);
 DataPos = IDIMMES_CHNL_Pos + 1;

 // If Not Fast Function add command/function
 if ( MMES->ComFunc < 16 ) { TxMesBuf[IDIMMES_MMPS_Pos] |= (MMES->ComFunc << IDIMMES_MMPS_FAST_FUNC_Pos); }
 else                      { TxMesBuf[DataPos++] = MMES->ComFunc; }
 
 // Fill Data
 if ( MMES->TxDataLength != 0 ) { memcpy(&TxMesBuf[DataPos], &MMES->TxData[0], MMES->TxDataLength); }
 
 // Add CRC
 uint16_t CRC = MODBUS_CRC16::CRC16_TF(&TxMesBuf[0], (uint16_t)(DataPos + MMES->TxDataLength));
 TxMesBuf[DataPos + MMES->TxDataLength]     = (uint8_t)(CRC >> 8);
 TxMesBuf[DataPos + MMES->TxDataLength + 1] = (uint8_t) CRC;
 
 if ( this->SendRequestSync(DataPos + MMES->TxDataLength + MODBUS_CRC16_SIZE) == 0 ) { return IDIERMST_TX_MES; }
			 
 IDIBUS_SERIAL_ERROR_STATUS_TYPE SerialError = this->GetErrorStatus();
 uint16_t RxMessageLength;
 
 if      ( SerialError.BF.TimeoutERR != 0 )                                                                    { return IDIERMST_RCV_TIMEOUT; }
 else if ( (SerialError.SumVar != 0) || ((RxMessageLength = this->GetRxBufCounter()) < IDISMES_MIN_MES_SIZE) ) { return IDIERMST_MES_RX_INTEGRITY;   }
 else
	{
	 uint16_t CRC = MODBUS_CRC16::CRC16_TF( &RxMesBuf[0], (uint16_t)(RxMessageLength-MODBUS_CRC16_SIZE) );
	 uint16_t ReceivedCRC = ((uint16_t)RxMesBuf[RxMessageLength-2] << 8) | RxMesBuf[RxMessageLength-1];
	 if      ( CRC != ReceivedCRC )							{ return IDIERMST_CRC; }
	 else if ( RxMesBuf[IDISMES_ADDR_Pos] != MMES->SlAddr ) { return IDIERMST_INVALID_ADDR_NUM; }
	 else
		{
		 MMES->RxDataLength = RxMessageLength - (IDISMES_ERROR_Pos + MODBUS_CRC16_SIZE);
		 MMES->RxData = &RxMesBuf[IDISMES_ERROR_Pos];
		 return IDIER_NOPE;
		}
	}
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
uint8_t IdiBusSerialLine::sendMMESG (IdiBusMMESG *MMESG)
{
 if ( MMESG->IsValid() == 0 ) { return IDIERMST_INVALID_TX_REQUEST_FORMAT ; }

 uint8_t *TxMesBuf = this->getTxBufPointer();
 if ( TxMesBuf == NULL ) { return IDIERMST_TX_MES; }
 
 uint8_t *RxMesBuf = this->getRxBufPointer();
 uint8_t DataPos;
 
 // Fill Header
 TxMesBuf[IDIMMES_ADDR_Pos] =  MMESG->SlAddr;
 TxMesBuf[IDIMMES_MMPS_Pos] = (MMESG->MMPS.LongMes         << IDIMMES_MMPS_LONG_MES_Pos)    |
						      (IDIMMES_MMPS_MES_TYPE_MMESG << IDIMMES_MMPS_MES_TYPE_Pos)    | 
							  (0x00	                      << IDIMMES_MMPS_FAST_FUNC_Pos)    |
							  (MMESG->MMPS.AlarmMes        << IDIMMES_MMPS_ALARM_FRAME_Pos) | 
							  (MMESG->MMPS.EncryptedAes    << IDIMMES_MMPS_ENCRYPTED_AES_Pos);
 DataPos = IDIMMES_MMPS_Pos + 1;
 // If Not Fast Function add command/function
 if ( MMESG->ComFunc < 16 ) { TxMesBuf[IDIMMES_MMPS_Pos] |= (MMESG->ComFunc << IDIMMES_MMPS_FAST_FUNC_Pos); }
 else                       { TxMesBuf[DataPos++] = MMESG->ComFunc; }

 // Fill Data
 if ( MMESG->TxDataLength != 0 ) { memcpy(&TxMesBuf[DataPos], &MMESG->TxData[0], MMESG->TxDataLength); }
 
 // Add CRC
 uint16_t CRC = MODBUS_CRC16::CRC16_TF(&TxMesBuf[0], (uint16_t)(DataPos + MMESG->TxDataLength));
 TxMesBuf[DataPos + MMESG->TxDataLength]     = (uint8_t)(CRC >> 8);
 TxMesBuf[DataPos + MMESG->TxDataLength + 1] = (uint8_t) CRC;
 
 if ( MMESG->IsGroupAddr() != 0 )
	{
	 if ( this->WriteSync(DataPos + MMESG->TxDataLength + MODBUS_CRC16_SIZE) == 0 ) { return IDIERMST_TX_MES; }
	 return IDIER_NOPE;
	}
	else //Module commands
		{
		 if ( this->SendRequestSync(DataPos + MMESG->TxDataLength + MODBUS_CRC16_SIZE) == 0 ) { return IDIERMST_TX_MES; }
			 
		 uint16_t RxMessageLength;
		 IDIBUS_SERIAL_ERROR_STATUS_TYPE SerialError = this->GetErrorStatus();
		 
		 if      ( SerialError.BF.TimeoutERR != 0 )                                                                     { return IDIERMST_RCV_TIMEOUT; }
		 else if ( (SerialError.SumVar != 0) || ((RxMessageLength = this->GetRxBufCounter()) < IDISMES_MIN_MES_SIZE) )  { return IDIERMST_TX_MES; }
		 else
			{
			 uint16_t CRC = MODBUS_CRC16::CRC16_TF( &RxMesBuf[0], (uint16_t)(RxMessageLength-MODBUS_CRC16_SIZE) );
			 uint16_t ReceivedCRC = ((uint16_t)RxMesBuf[RxMessageLength-2] << 8) | RxMesBuf[RxMessageLength-1];
			 if      ( CRC != ReceivedCRC )							 { return IDIERMST_CRC; }
			 else if ( RxMesBuf[IDISMES_ADDR_Pos] != MMESG->SlAddr ) { return IDIERMST_INVALID_ADDR_NUM; }
				{
				 MMESG->RxDataLength = RxMessageLength - (IDISMES_ERROR_Pos + MODBUS_CRC16_SIZE);
				 MMESG->RxData = &RxMesBuf[IDISMES_ERROR_Pos];
				 return IDIER_NOPE;
				}
			}
 		}
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//#############################################################################################################################################################################################################
