#include "Modbus_Monitor.h"
//#include "measure.h"

static MODBUS_MONITOR_DATA_TPDF      MODBUS_MonitorData;



extern uint32_t Ctime;//C倍电流时间 min
extern uint32_t Ie;//额定电流（实际值）
extern uint32_t	 Tripbit;//脱扣标志位,0未脱扣，1已脱扣，需要复位。
extern uint8_t		 FaultLEDFlash;//灯闪烁标志，全亮(5)：过载，闪一次：不平衡，闪两次：堵转，闪三次：阻塞，闪四次：接地
extern uint8_t GNDProtectEn;//接地保护使能，0关闭，1使能。
extern uint8_t       ModbusWriteFlag;

 
 
 
void MODBUS_ReadMonitorData(void)
{
		//to be modified start
		//copy and switch function data to modbus struct format
	if(!nrf_gpio_pin_read(BLE_KEY))										//读蓝牙模式下数据
	{
		MODBUS_MonitorData.Ia=	(short)currFact[0]*10;
		MODBUS_MonitorData.Ib=	(short)currFact[1]*10;	
		MODBUS_MonitorData.Ic=	(short)currFact[2]*10;
		MODBUS_MonitorData.RunStatus = Tripbit;
		MODBUS_MonitorData.FaultStatus = FaultLEDFlash;
		
		MODBUS_MonitorData.TripLevel = A_LEVEL_BLE;
		MODBUS_MonitorData.RatedCurrentLevel = B_LEVEL_BLE;
		MODBUS_MonitorData.PhaseProtectOn_Off = T1_LEVEL_BLE;
		MODBUS_MonitorData.JamProtectOn_Off = T2_LEVEL_BLE;
		MODBUS_MonitorData.StallProtectOn_Off = STALL_BLE;
		MODBUS_MonitorData.ResetOn_Off = IMBA_BLE;
		MODBUS_MonitorData.GrandProtectOn_Off = Grand_BLE;
			
	}
	else																//读本地模式下数据
	{
		MODBUS_MonitorData.Ia=	(short)currFact[0]*10;
		MODBUS_MonitorData.Ib=	(short)currFact[1]*10;	
		MODBUS_MonitorData.Ic=	(short)currFact[2]*10;
		MODBUS_MonitorData.RunStatus = Tripbit;
		MODBUS_MonitorData.FaultStatus = FaultLEDFlash;     //FaultLEDFlash
	
		MODBUS_MonitorData.TripLevel = Ctime;
		MODBUS_MonitorData.RatedCurrentLevel = Ie;
		MODBUS_MonitorData.PhaseProtectOn_Off = nrf_gpio_pin_read(T1_LEVEL);
		MODBUS_MonitorData.JamProtectOn_Off = nrf_gpio_pin_read(T2_LEVEL);
		MODBUS_MonitorData.StallProtectOn_Off = nrf_gpio_pin_read(STALL);
		MODBUS_MonitorData.ResetOn_Off = nrf_gpio_pin_read(IMBA);
		MODBUS_MonitorData.GrandProtectOn_Off = GNDProtectEn;

	}
			
		//to be modified end
}



static const MODBUS_PARAMETER_INFO_TPDF ModbusParameterInfo[] =
{
  {0x0001,sizeof(MODBUS_MonitorData),&MODBUS_MonitorData,MB_BIT_03|MB_BIT_06|MB_BIT_10,MODBUS_ReadMonitorData,NULL,NULL,NULL,},
};



#if MARCO_IAP
//#include "IAP_Modbus.h"
#endif //MARCO_IAP

#include "SEGGER_RTT.h"

#if MARCO_FREERTOS
QueueHandle_t	MODBUS_ReceiveQueue MY_DATA_UNINIT;	
QueueHandle_t	MODBUS_TransmitQueue MY_DATA_UNINIT;
#endif

UART_DATA_TPDF	MODBUS_UartData;

void CopySorceDataToModbus(UART_DATA_TPDF* TempStructPtr)
{
		MODBUS_UartData.Length = TempStructPtr->Length;
		memcpy(MODBUS_UartData.Buff,TempStructPtr->Buff,TempStructPtr->Length);
}


void ResponseModbus(void)
{
		UART_DATA_TPDF TxStruct;
		TxStruct.Length = ModbusParameter.TransmitLength;
		memcpy(TxStruct.Buff,ModbusParameter.TransmitBuffer,ModbusParameter.TransmitLength);
	
		#if MARCO_FREERTOS
				if(MODBUS_UartData.ucDataSources == 1)//UART_RS485
				{		
						xQueueSend(RS485_SendQueue,&TxStruct,1000);
				}
				else if(MODBUS_UartData.ucDataSources == 0)//UART_HPLC
				{
						xQueueSend(UART_SendQueue,&TxStruct,1000);
				}
				else//BT
				{
						xQueueSend(tBtSendQueue,&TxStruct,1000);
				}
		#else
				//to be modified start
				//copy frame data to be transmitted to rx_tx_task
		Modbus_SendBuffer.Length = TxStruct.Length;
		memcpy(Modbus_SendBuffer.Buff, TxStruct.Buff, Modbus_SendBuffer.Length);
						
						
						
				//to be modified end
		#endif
		
	
		
}






/********************************interface start**********************************/
MODBUS_SET	ModbusSet;
MODBUS_SUPER_SET	ModbusSuperSet;

#if MARCO_FREERTOS
SemaphoreHandle_t ModbusMutex;
#endif
unsigned char ReadModbusSet(MODBUS_SET* TempPtr)
{
		#if MARCO_FREERTOS
				if(ModbusMutex==NULL)
						return 1;
				xSemaphoreTake(ModbusMutex,portMAX_DELAY);
		#endif
		TempPtr->SlaveAddr = ModbusSet.SlaveAddr;
		#if MARCO_FREERTOS
				xSemaphoreGive(ModbusMutex);
		#endif
		return 0;
	
}

unsigned char SetModbusSet(MODBUS_SET* TempPtr,unsigned char TempParameterIndex)
{
		#if MARCO_FREERTOS
				if(ModbusMutex==NULL)
						return 1;
				xSemaphoreTake(ModbusMutex,portMAX_DELAY);
		#endif
		switch(TempParameterIndex)
		{
				case 0:
						ModbusSet.SlaveAddr = TempPtr->SlaveAddr;
						break;	
		}
		#if MARCO_FREERTOS
				xSemaphoreGive(ModbusMutex);
		#endif
		return 0;
}

/********************************interface end**********************************/





#if MARCO_IAP
		MODBUS_IAP_DATA_TPDF				MODBUS_IAP_Data;

		void MODBUS_Read_IAP_DataStatus(void)
		{
				MODBUS_IAP_Data.Status = IAP_Get_Status();
			
					
		}
		void MODBUS_Write_IAP_DataCommand(unsigned short TempAddr,unsigned short TempData)
		{
				switch(TempAddr)
				{
						case 0xFF00:
								IAP_Command_Process(TempData);
								
								break;
				}
		}

		void MODBUS_Write_IAP_DataCode(unsigned short TempAddr,unsigned short TempData)
		{	
				
				if(((TempAddr - 0xFF01)>=0)&&((TempAddr - 0xFF01)<=127))
				{
						MODBUS_IAP_Data.Code[TempAddr - 0xFF01] = TempData;
				}	
		}

		void MODBUS_MultipleWrite_IAP_DataCode(void)
		{
				unsigned short TempIndex = 0;
				unsigned char TempArray[128] = {0};
				unsigned char i = 0;
				
				TempIndex = MODBUS_IAP_Data.Code[0];
				for(i=0;i<64;i++)
				{
						TempArray[i*2 + 0] = (unsigned char)(MODBUS_IAP_Data.Code[1+i]>>8);
						TempArray[i*2 + 1] = (unsigned char)(MODBUS_IAP_Data.Code[1+i]);
				}
				WriteCodeToExternalFlash(TempIndex,TempArray,128);
				#if MARCO_SEGGER_RTT_DEBUG
				SEGGER_RTT_printf(0, "MODBUS_MultipleWrite_IAP_DataCode %X \n",MODBUS_IAP_Data.Code[0]);	
				#endif
		}

#endif //MARCO_IAP

































unsigned char IsSuperSlaveAddr_OK(unsigned char TempAddr)
{
		if(ModbusSuperSet.SuperSlaveAddr == TempAddr)
		{
				return 0;
		}
		else
		{
				return 1;
		}
}




unsigned char IsSlaveAddr_OK(unsigned char TempAddr)
{
		if(ModbusSet.SlaveAddr == TempAddr)
		{
				return 0;
		}
		else
		{
				return 1;
		}
}


MODBUS_EXCEPTION_CODE_ENUM WriteHoldRegisters(void)
{
		return EXCEPTION_CODE_1;
}

unsigned char IsAddressLegal(MODBUS_PARAMETER_INFO_TPDF* TempPtr,unsigned short TempAddr,unsigned char TempLength)
{
		unsigned short i;
		if(TempPtr!=NULL)
		{
				for(i=TempAddr;i<(TempAddr+TempLength);i++)
				{
						if((i<TempPtr->BaseAddr)||(i>=(TempPtr->BaseAddr+TempPtr->Length)))
						{
								return 1;
						}
				}
		}
		return 0;
}


MODBUS_EXCEPTION_CODE_ENUM GetHoldingRegisterData(unsigned char* TempPtr,unsigned short TempAddr,unsigned char TempLength)
{
		MODBUS_PARAMETER_INFO_TPDF* TempInfoPtr;
		unsigned char i;
	
		TempInfoPtr = (MODBUS_PARAMETER_INFO_TPDF*)ModbusParameterInfo;
		unsigned char TempInfoLength;
		TempInfoLength = sizeof(ModbusParameterInfo)/sizeof(MODBUS_PARAMETER_INFO_TPDF);
		for(i=0;i<TempInfoLength;i++)
		{
				if((TempAddr>=TempInfoPtr->BaseAddr)&&(TempAddr<(TempInfoPtr->BaseAddr+TempInfoPtr->Length)))
				{
						if(IsAddressLegal(TempInfoPtr,TempAddr,TempLength) != 0)
						{
								return EXCEPTION_CODE_2;
						}
						break;
				}
				TempInfoPtr++;
		}
		
		if(i==TempInfoLength)
		{
				return EXCEPTION_CODE_2;
		}
		if((TempInfoPtr->FunctionBit&MB_BIT_03)==0)
		{
				return EXCEPTION_CODE_2;
		}
		if(TempInfoPtr->preReadCallback!=NULL)
				TempInfoPtr->preReadCallback();
		
		unsigned short* TempShortPtr;
		TempShortPtr = (unsigned short*)TempInfoPtr->Pointer;
		for(i=0;i<TempLength;i++)
		{
				*(TempPtr+(i*2)) = (unsigned char)(*(TempShortPtr+(TempAddr-TempInfoPtr->BaseAddr)+i)>>8);
				*(TempPtr+(i*2+1)) = (unsigned char)(*(TempShortPtr+(TempAddr-TempInfoPtr->BaseAddr)+i));
		}
		return EXCEPTION_CODE_NULL;
}

MODBUS_EXCEPTION_CODE_ENUM WriteOneHoldingRegister(unsigned short TempDataAddr,unsigned short TempData)
{	
		MODBUS_PARAMETER_INFO_TPDF* TempInfoPtr;
		unsigned char i;
	
		TempInfoPtr = (MODBUS_PARAMETER_INFO_TPDF*)ModbusParameterInfo;
		unsigned char TempInfoLength;
		TempInfoLength = sizeof(ModbusParameterInfo)/sizeof(MODBUS_PARAMETER_INFO_TPDF);
		for(i=0;i<TempInfoLength;i++)
		{
				if(
							(TempDataAddr>=TempInfoPtr->BaseAddr)&&
							(TempDataAddr<(TempInfoPtr->BaseAddr+TempInfoPtr->Length))&&
							(TempInfoPtr->FunctionBit&MB_BIT_06)
				)
				{
						#if MARCO_SEGGER_RTT_DEBUG
						SEGGER_RTT_printf(0, "write one holding break %X \n",i);	
						#endif

//						*((uint16_t*)&MODBUS_MonitorData+TempDataAddr-1) = (uint16_t)(TempData) ;
						ModbusWriteFlag=1;
						
						switch(TempDataAddr)
						{
							case 6:
								A_LEVEL_BLE = TempData;
								break;
							case 7:
								B_LEVEL_BLE = TempData;
								break;
							case 8:
								T1_LEVEL_BLE = TempData;
								break;
							case 9:
								T2_LEVEL_BLE = TempData;
								break;
							case 10:
								STALL_BLE = TempData;
								break;
							case 11:
								IMBA_BLE = TempData;
								break;
							case 12:
								Grand_BLE = TempData;	
								break;
							case 13:
								Resetbit_BLE = TempData;
								
								break;
							case 14:
								Stopbit_BLE = TempData;		
								break;
						}
					
//						(unsigned char)(*(TempShortPtr+(TempAddr-TempInfoPtr->BaseAddr)+i)) = *(TempPtr+(i*2+1));
							
						break;
				}
				
				TempInfoPtr++;
		}
		if(i==TempInfoLength)
		{	
				#if MARCO_SEGGER_RTT_DEBUG
				SEGGER_RTT_printf(0, "return is\n",i);	
				#endif
				return EXCEPTION_CODE_2;
		}

		if(TempInfoPtr->postWriteCallback!=NULL)
		{		
				TempInfoPtr->postWriteCallback(TempDataAddr,TempData);
		}
		else
		{
		}
		return EXCEPTION_CODE_NULL;
}


MODBUS_EXCEPTION_CODE_ENUM WriteOneOfMultipleHoldingRegister(unsigned short TempDataAddr,unsigned short TempData)
{	
		MODBUS_PARAMETER_INFO_TPDF* TempInfoPtr;
//		unsigned char i;
	
		TempInfoPtr = (MODBUS_PARAMETER_INFO_TPDF*)ModbusParameterInfo;
//		unsigned char TempInfoLength;
//		TempInfoLength = sizeof(ModbusParameterInfo)/sizeof(MODBUS_PARAMETER_INFO_TPDF);
//		SEGGER_RTT_printf(0, " TempDataAddr %d  %d \n", TempDataAddr, TempData);	//打印写寄存器地址与值
		switch(TempDataAddr)
		{
			case 6:
				A_LEVEL_BLE = TempData;
				break;
			case 7:
				B_LEVEL_BLE = TempData;
				break;
			case 8:
				T1_LEVEL_BLE = TempData;
				break;
			case 9:
				T2_LEVEL_BLE = TempData;
				break;
			case 10:
				STALL_BLE = TempData;
				break;
			case 11:
				IMBA_BLE = TempData;
				break;
		}
	
		
//		for(i=0;i<TempInfoLength;i++)
//		{
//				if(
//							(TempDataAddr>=TempInfoPtr->BaseAddr)&&
//							(TempDataAddr<(TempInfoPtr->BaseAddr+TempInfoPtr->Length))&&
//							(TempInfoPtr->FunctionBit&MB_BIT_10)
//				)
//				{
//					SEGGER_RTT_printf(0, " come in %d \n", 22);
//						break;
//				}
//				TempInfoPtr++;
//		}
//		if(i==TempInfoLength)
//		{	
//				#if MARCO_SEGGER_RTT_DEBUG
//				SEGGER_RTT_printf(0, "return is\n",i);	
//				#endif
//				return EXCEPTION_CODE_2;
//		}

		if(TempInfoPtr->postWriteCallback!=NULL)
		{		
				TempInfoPtr->postWriteCallback(TempDataAddr,TempData);
		}
		else
		{
		}
		return EXCEPTION_CODE_NULL;
}


MODBUS_EXCEPTION_CODE_ENUM WriteMultipleHoldingRegister(unsigned short TempDataAddr)
{	
		MODBUS_PARAMETER_INFO_TPDF* TempInfoPtr;
		unsigned char i;
	
		TempInfoPtr = (MODBUS_PARAMETER_INFO_TPDF*)ModbusParameterInfo;
		unsigned char TempInfoLength;
		TempInfoLength = sizeof(ModbusParameterInfo)/sizeof(MODBUS_PARAMETER_INFO_TPDF);
		for(i=0;i<TempInfoLength;i++)
		{
				if((TempDataAddr>=TempInfoPtr->BaseAddr)&&(TempDataAddr<(TempInfoPtr->BaseAddr+TempInfoPtr->Length)))
				{
						#if MARCO_SEGGER_RTT_DEBUG
						SEGGER_RTT_printf(0, "multiple break %X \n",i);	
						#endif
						break;
				}
				TempInfoPtr++;
		}
		if(i==TempInfoLength)
		{
				return EXCEPTION_CODE_2;
		}
		if((TempInfoPtr->FunctionBit&MB_BIT_10)==0)
		{
				return EXCEPTION_CODE_2;
		}
		if(TempInfoPtr->postMultipleWriteCallback!=NULL)
				TempInfoPtr->postMultipleWriteCallback();
		return EXCEPTION_CODE_NULL;
}





#if MARCO_FREERTOS
		void MODBUS_RTU_TaskFunction(void const * argument)
		{
				ModbusSet.SlaveAddr = 0x01;
				ModbusMutex = xSemaphoreCreateMutex();
				MODBUS_ReceiveQueue	= xQueueCreate(1,sizeof(UART_DATA_TPDF));
				MODBUS_TransmitQueue	= xQueueCreate(1,sizeof(UART_DATA_TPDF));
				vTaskDelay(2000);
				
				for(;;)
				{
						if(MODBUS_ReceiveQueue)
						{
								if(xQueueReceive(MODBUS_ReceiveQueue,&MODBUS_UartData,portMAX_DELAY)==pdTRUE)
								{
										MODBUS_Process(MODBUS_UartData.aBuff,MODBUS_UartData.tLength);
								}
						}
						else
						{
								vTaskDelay(1000);
						}
				}
		}
#else
		void MODBUS_RTU_TaskFunction(void const * argument)
		{
				ModbusSet.SlaveAddr = 0x01;
				ModbusSuperSet.SuperSlaveAddr = 0xFA;
				//to be modified start
				//copy received frame data to MODBUS_UartData
				CopySorceDataToModbus(&Modbus_ReceiveBuffer);
			
						
						
				//to be modified end
				MODBUS_Process(MODBUS_UartData.Buff,MODBUS_UartData.Length);
				ResponseModbus();
		}
#endif
