#include "ModbusRTUSlave.h"
#include "bsp_uart.h"
ui8 ModBus_Addr=3;//本从机地址
extern u16 avg_advalue[14];

ui8 Modbus_InputIO[2]={0};//输入开关量寄存器
bit Modbus_OutputIO=0;
ui16 Modbus_HoldReg[16]={0};//保持寄存器
//void (*bsp_uart_send_buff)(uchar len);
void Flash_EraseBlock(unsigned int fui_Address)
{
	while(1)
	{
		LVDC &=~ 0x08;			  //清除LVD中断标志位
		P0_0=0;		
		if((LVDC&0x08)==0)		break;
	}
	EA=0;
	INSCON =0x80;	
	IAP_CMD = 0xF00F;				//Flash解锁
	IAP_ADDR = fui_Address;	//写入擦除地址
	IAP_CMD = 0xD22D;				//选择操作方式， 扇区擦除
	IAP_CMD = 0xE11E; 			//触发后IAP_ADDRL&IAP_ADDRH指向0xFF，同时自动锁定
	INSCON =0x00;	
	EA=1;
}
/**
  * @说明  	写入一个字节数据到Flash里面
  *         该函数需绝对地址编译，详情请查阅IAP操作应用手册
  * @参数  	fui_Address ：FLASH地址
  *	@参数	  fucp_SaveData：写入的数据
  * @返回值 无
  * @注		  写之前必须先对操作的扇区进行擦除
  */
void FLASH_WriteData(unsigned char fuc_SaveData, unsigned int fui_Address)
{
	while(1)
	{
		LVDC &=~ 0x08;			   //清除LVD中断标志位
		P0_0=0;		
		if((LVDC&0x08)==0)		break;
	}
	EA=0;
	INSCON =0x80;	
	IAP_DATA = fuc_SaveData;
	IAP_CMD=0xF00F;				   //Flash解锁
	IAP_ADDR = fui_Address;
	IAP_CMD=0xB44B;				   //字节编程
	IAP_CMD=0xE11E;				   //触发一次操作
	INSCON =0x00;	
	EA=1;
}
/**
  * @说明  	写入任意长度的数据到FLASH里面
  *         该函数需绝对地址编译，详情请查阅IAP操作应用手册
  * @参数  	fui_Address ：FLASH起始地址
  *	@参数	  fuc_Length ： 写入数据长度
  *			    取值范围：0x00-0xFF
  *	@参数  *fucp_SaveArr：写入的数据存放区域的首地址
  * @返回值 无
  * @注		  写之前必须先对操作的扇区进行擦除
  */
void Flash_WriteArr(unsigned int fui_Address,unsigned char fuc_Length,unsigned char *fucp_SaveArr)
{
	unsigned char fui_i = 0;
	EA=0;
	for(fui_i=0;fui_i<fuc_Length;fui_i++)
	{
		FLASH_WriteData(*(fucp_SaveArr++), fui_Address++); 
	}
	EA=1;
}

/**
  * @说明  	从FLASH里面读取任意长度的数据
  * @参数  	fui_Address ：FLASH起始地址
  *	@参数	  fuc_Length ：读取数据长度
  *			    取值范围：0x00-0xFF
  *	@参数	 *fucp_SaveArr：读取数据存放的区域首地址
  * @返回值 无
  * @注		  无
  */
void Flash_ReadArr(unsigned int fui_Address,unsigned char fuc_Length,unsigned char *fucp_SaveArr)
{
	INSCON =0x80;	
	while(fuc_Length--)
	*(fucp_SaveArr++)=*((unsigned char code *)(fui_Address++));//读取数据
	INSCON =0x00;
}
void Modbus_RTU_Init(void)//u8* rxbuf,u8* txbuf,void (*f)(uchar len)
{
	u8 i=0;
//	guc_Uartbuf = guc_Uartbuf;//rxbuf;
//	guc_UartTxbuf = guc_UartTxbuf;//txbuf;
	//bsp_uart_send_buff=bsp_uart_send_buff;//f;
	Flash_ReadArr(0x0000,32,(u8*)Modbus_HoldReg);
	if(Modbus_HoldReg[14] !=0) ModBus_Addr=Modbus_HoldReg[14];
	for(i=0;i<14;i++)
	{
		if(Modbus_HoldReg[i] == 0) 
					Modbus_HoldReg[i]=1024;
	}
}

void Set_InputIO_Value(u16 index,bit value)
{
	u8 byteindex;
	u8 bitindex;
	byteindex = index / 8;
	bitindex = index % 8;
	if(value==1)
		Modbus_InputIO[byteindex] |= 1 << (bitindex);
	else
		Modbus_InputIO[byteindex] &= ~(1<< (bitindex));
}
u16 startRegAddr;
u16 RegNum;
u16 calCRC;

void Modbus_02_Solve(void)
{
		u16 ByteNum;
		u16 i;
		RegNum= (((u16)guc_Uartbuf[4])<<8)|guc_Uartbuf[5];//???????
		if((startRegAddr+RegNum)<=14)//?????+??????
		{
				guc_UartTxbuf[0]=guc_Uartbuf[0];
				guc_UartTxbuf[1]=guc_Uartbuf[1];
				ByteNum=RegNum/8;//???
				if(RegNum%8) ByteNum+=1;//????????,????+1
				guc_UartTxbuf[2]=ByteNum;//?????????
				for(i=0;i<RegNum;i++)
				{
						if(i%8==0) guc_UartTxbuf[3+i/8]=0x00;
						guc_UartTxbuf[3+i/8]>>=1;//?????
						guc_UartTxbuf[3+i/8]|=(Modbus_InputIO[(startRegAddr+i)/8]<<(7-(startRegAddr+i)%8))&0x80;
						if(i==RegNum-1)//?????????
						{
								if(RegNum%8) guc_UartTxbuf[3+i/8]>>=8-(RegNum%8);//????????????,???MSB??0
						}
				}
				calCRC=crc16(guc_UartTxbuf,ByteNum+3);
				guc_UartTxbuf[ByteNum+3]=(calCRC>>8)&0xFF;
				guc_UartTxbuf[ByteNum+4]=calCRC&0xFF;
				bsp_uart_send_buff(ByteNum+5);
		}
		else//?????+??????
		{
				guc_UartTxbuf[0]=guc_Uartbuf[0];
				guc_UartTxbuf[1]=guc_Uartbuf[1]|0x80;
				guc_UartTxbuf[2]=0x02; //???
				bsp_uart_send_buff(3);
		}
}
//读保持寄存器
void Modbus_03_Solve(void)
{
        u8 i;
        RegNum= (((u16)guc_Uartbuf[4])<<8)|guc_Uartbuf[5];
        if((startRegAddr+RegNum)<=16)
        {
                guc_UartTxbuf[0]=guc_Uartbuf[0];
                guc_UartTxbuf[1]=guc_Uartbuf[1];
                guc_UartTxbuf[2]=RegNum*2;
                for(i=0;i<RegNum;i++)
                {
                        guc_UartTxbuf[3+i*2]=(Modbus_HoldReg[startRegAddr+i]>>8)&0xFF;//高位在前
                        guc_UartTxbuf[4+i*2]=Modbus_HoldReg[startRegAddr+i]&0xFF; //低位在后
                }
                calCRC=crc16(guc_UartTxbuf,RegNum*2+3);
                guc_UartTxbuf[RegNum*2+4]=calCRC&0xFF;
                guc_UartTxbuf[RegNum*2+3]=(calCRC>>8)&0xFF;
                bsp_uart_send_buff(RegNum*2+5);
        }
        else
        {
                guc_UartTxbuf[0]=guc_Uartbuf[0];
                guc_UartTxbuf[1]=guc_Uartbuf[1]|0x80;
                guc_UartTxbuf[2]=0x02; 
                bsp_uart_send_buff(3);
        }
}
//写单个输出线圈
void Modbus_05_Solve(void)
{
	u8 i;
        if(startRegAddr==0)//?????????
        {
                if((guc_Uartbuf[4]==0xFF)||(guc_Uartbuf[5]==0xFF)) Modbus_OutputIO=1;
                else Modbus_OutputIO=0;
                guc_UartTxbuf[0]=guc_Uartbuf[0];
                guc_UartTxbuf[1]=guc_Uartbuf[1];
                guc_UartTxbuf[2]=guc_Uartbuf[2];
                guc_UartTxbuf[3]=guc_Uartbuf[3];
                guc_UartTxbuf[4]=guc_Uartbuf[4];
                guc_UartTxbuf[5]=guc_Uartbuf[5];
								guc_UartTxbuf[6]=guc_Uartbuf[6];
								guc_UartTxbuf[7]=guc_Uartbuf[7];
								if(Modbus_OutputIO == 1)
								{
									if(ModBus_Addr == 1){
										for(i=0;i<11;i++){
											Modbus_HoldReg[i] = avg_advalue[i+3];
										}
									}else{
										for(i=0;i<14;i++){
											Modbus_HoldReg[i] = avg_advalue[i];
										}
									}
									for(i=0;i<8;i++){
										
										Flash_EraseBlock((u16)(i*4));
										Flash_WriteArr((u16)(i*4),4,(u8*)&Modbus_HoldReg[i*2]);
									}
								}
                bsp_uart_send_buff(8);
        }
        else//?????????
        {
                guc_UartTxbuf[0]=guc_Uartbuf[0];
                guc_UartTxbuf[1]=guc_Uartbuf[1]|0x80;
                guc_UartTxbuf[2]=0x02; //???
                bsp_uart_send_buff(3);
        }
}

//写单个保持寄存器
void Modbus_06_Solve(void)
{
	u16 EEPROM_ADDR;
		if(startRegAddr<14)
		{
			Modbus_HoldReg[startRegAddr] = guc_Uartbuf[5];//?????
			Modbus_HoldReg[startRegAddr] |= ((u16)guc_Uartbuf[4])<<8;//?????
			
			guc_UartTxbuf[0]=guc_Uartbuf[0];
			guc_UartTxbuf[1]=guc_Uartbuf[1];
			guc_UartTxbuf[2]=guc_Uartbuf[2];
			guc_UartTxbuf[3]=guc_Uartbuf[3];
			guc_UartTxbuf[4]=guc_Uartbuf[4];
			guc_UartTxbuf[5]=guc_Uartbuf[5];
			
			calCRC=crc16(guc_UartTxbuf,6);
			guc_UartTxbuf[7]=calCRC&0xFF;
			guc_UartTxbuf[6]=(calCRC>>8)&0xFF;

			EEPROM_ADDR=startRegAddr/2*4;
			Flash_EraseBlock(EEPROM_ADDR);
			Flash_WriteArr(EEPROM_ADDR,4,(u8*)&Modbus_HoldReg[startRegAddr/2*2]);
			bsp_uart_send_buff(8);
		}
//		else if(startRegAddr == 14){
//				ModBus_Addr = guc_Uartbuf[5];
//				Modbus_HoldReg[14]=guc_Uartbuf[5];
//				guc_UartTxbuf[0]=guc_Uartbuf[0];
//				guc_UartTxbuf[1]=guc_Uartbuf[1];
//				guc_UartTxbuf[2]=guc_Uartbuf[2];
//				guc_UartTxbuf[3]=guc_Uartbuf[3];
//				guc_UartTxbuf[4]=guc_Uartbuf[4];
//				guc_UartTxbuf[5]=guc_Uartbuf[5];
//				
//				calCRC=crc16(guc_UartTxbuf,6);
//				guc_UartTxbuf[7]=calCRC&0xFF;
//				guc_UartTxbuf[6]=(calCRC>>8)&0xFF;

//				EEPROM_ADDR=startRegAddr/2*4;
//				Flash_EraseBlock(EEPROM_ADDR);
//				Flash_WriteArr(EEPROM_ADDR,4,(u8*)&Modbus_HoldReg[startRegAddr/2*2]);
//				bsp_uart_send_buff(8);					
//		}
		else
		{
				guc_UartTxbuf[0]=guc_Uartbuf[0];
				guc_UartTxbuf[1]=guc_Uartbuf[1]|0x80;
				guc_UartTxbuf[2]=0x02;
				bsp_uart_send_buff(3);			
		}
}

//MODBUSRTU SLAVE服务程序，放在主循环内使用

void ModBusRtuSlave_Service(u8 framelen)
{
	u16 recCRC;
	u16 calCRC;
	//u16 EEPROM_ADDR;
	if(guc_Uartbuf[0]==ModBus_Addr)//???? && ModBus_Addr !=0xFF
	{
		if((guc_Uartbuf[1]==0x02)|| (guc_Uartbuf[1]==03) ||(guc_Uartbuf[1]==05) || (guc_Uartbuf[1]==0x06))//允许的功能码
		{
			startRegAddr=(((u16)guc_Uartbuf[2])<<8)|guc_Uartbuf[3];//起始地址
			calCRC=crc16(guc_Uartbuf,framelen-2);//CRC计算
			recCRC=guc_Uartbuf[framelen-1]|(((u16)guc_Uartbuf[framelen-2])<<8);//接收到的CRC
			if(calCRC==recCRC)//CRC校验
			{
				/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				switch(guc_Uartbuf[1])//????????????
				{       
					case 02: //读取多个输入线圈
					{
						Modbus_02_Solve();
						break;
					}
					case 03: //读取多个保持寄存器
					{
						Modbus_03_Solve();
						break;
					}                                                              
					case 05: //写单个线圈
					{
						Modbus_05_Solve();
						break;
					}
					case 06: //写单个保持寄存器
					{
						Modbus_06_Solve();
						break;
					}																			 
				}
							////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
			}
			else//CRC校验失败
			{
				guc_UartTxbuf[0]=guc_Uartbuf[0];
				guc_UartTxbuf[1]=guc_Uartbuf[1]|0x80;
				guc_UartTxbuf[2]=0x04;
				bsp_uart_send_buff(3);
			} 			
		}
		else//错误的功能码
		{
			guc_UartTxbuf[0]=guc_Uartbuf[0];
			guc_UartTxbuf[1]=guc_Uartbuf[1]|0x80;
			guc_UartTxbuf[2]=0x01;
			bsp_uart_send_buff(3);
		}
	}
}
