

//2014.1.18 第一版(稳定测试过)
//注意事项: 在单片机启动后发送的前两个字节需要无效数据, 因为有时候
//会丢失. 如果丢失的话一般是丢失第一个字节, 为了保险起见, 就发送两个.

//目前包括 Connect 和中断中建立连接两个地方

//2014.1.19 增加了电脑端虚拟访问类型, 计划把控件ID改为常量, 这样可以共享一个虚拟电脑端类型

link VT code {} = #.Cloud.code;
link unit CHIP {} = #.MCU;

public uint16 max_length = #const 20;

//public uint32 baud = #const 9600;
//public uint32 baud = #const 38400;
public uint32 baud = #const 115200;

public [uint8*max_length] buffer;
uint8 length;

public [->uint8 * 32] FlagList;
bool DataIsOK;
bool EventIsOK;
bool Connected;
uint8 ErrNumber;
uint8 DataLength;

public bool isBusy;
public bool isNeed;


//虚拟类型--电脑端内存模型
VT linka
{
	type = [uint16] uint32;
}
void set_uint32( uint16 addr, uint32 data )
{
	#.linker.SetValue( addr.8(uint8), addr.0(uint8), data );
}
uint32 get_uint32( uint16 addr )
{
	return #.linker.GetValue( addr.8(uint8), 0x80 + addr.0(uint8) );
}
//----------------------------------------------------
//串口初始化,波特率:9600,8个数据位,1个停止位,没有奇偶校验
public void OS_init()
{
	RDE_DIR = 1;
	RDE_OUT = 0;
	
	RXD_DIR = 0;
	RXD_OUT = 1;
	
	TXD_DIR = 1;
	TXD_OUT = 1;
	
	//7 = 1: 清空发送标志
	//5 = 1: 发送就绪
	CHIP.UCSRA = 0b0110_0000;
	//7 = 1: 使能发送中断
	//4 = 1: 允许接收
	//3 = 1: 允许发送
	CHIP.UCSRB = 0b1001_1000;
	CHIP.UCSRC = 0x86;
	
	//Baud = (Fosc/16) / (UBRR + 1)
	//UBRR = (Fosc/16) / Boud - 1
	//Fosc = 11.0592MHz
	//Baud = 9600
	//CHIP.UBRRH = 0;
	//CHIP.UBRRL = 71;
	uint16 UBRR = 6912 / (uint16)(baud / 100) - 1;
	CHIP.UBRRH = UBRR.8(uint8);
	CHIP.UBRRL = UBRR.0(uint8);
	
	length = 0;
	
	ErrNumber = 0;
	DataLength = 0;
	DataIsOK = false;
	EventIsOK = false;
	Connected = false;
	
	isBusy = false;
	isNeed = false;
}
//----------------------------------------------------
//数据接收中断
interrupt [CHIP.WATCH.usart_RXC]
void RXC()
{
	decode();
}
//---------------------------------------------------
//串口协议解码器
public void decode()
{
	//必须在中断程序中读取 UDR,否则在退出后会重新进入中断
	buffer[length] = CHIP.UDR;
	length + 1;
	
	//+++++++++++++++++++++++
	//通信协议解析 0x55 N * * * ... * * * SUM
	uint8 L = length;
	uint8 Head = buffer[0];
	
	//判断协议头部
	if( L == 1 && Head != 0x55 ) {
		length = 0;
		//WriteByte( 0x55 );
		return;
	}
	if( L == 2 ) {
		DataLength = buffer[1];
		return;
	}
	if( L < DataLength + 3 ) return;
	uint8 CMD = buffer[2];
	uint8 SUM = buffer[L - 1];
	
	length = 0;
	
	//通信协议解析完成
	//+++++++++++++++++++++++
	
	//建立通信标志
	if( DataLength == 0 ) {
		StartWrite();
		
		//前导字节
		SendNullData();
		
		if( Connected ) {
			WriteByte( 0x55 );
		}
		else {
			WriteByte( 0xAA );
		}
		EndWrite();
		
		//如果已经连接, 启动看门狗并等待触发复位
		if( Connected ) {
			#asm "CLI"
			CHIP.WDTCR = 0b0000_1000;
			repeat {}
		}
		Connected = true;
		return;
	}
	//解析GUI协议, 分为事件和通信两种
	if( CMD == 0 ) {
		DataIsOK = true;
		return;
	}
	if( CMD == 1 ) {
		uint8 ID = buffer[3];
		uint8 EI = buffer[4];
		FlagList[ID] = FlagList[ID] | EI;
		EventIsOK = true;
		return;
	}
	if( CMD == 2 ) {
		EventIsOK = true;
		return;
	}
}
//---------------------------------------------------
//建立连接
public void Connect()
{
	//重启系统
	StartWrite();
	SendNullData();
	WriteByte( 0x55 );
	WriteByte( 0x02 );
	WriteByte( 0x00 );
	WriteByte( 0x00 );
	WriteByte( 0x00 );
	EndWrite();
	
	repeat {
		repeat until CHIP.UCSRA.7(bit) == 1; {}
		decode();
		if( Connected ) return;
	}
}
//---------------------------------------------------
//获取事件标志
public void GetEventFlag()
{
	return;
	
	repeat until !isNeed; {}
	
	isBusy = true;
	
	StartWrite();
	WriteByte( 0x55 );
	WriteByte( 6 );
	WriteByte( 0 );
	WriteByte( 3 );
	WriteByte( 0 );
	WriteByte( 0 );
	WriteByte( 0 );
	WriteByte( 0 );
	WriteByte( 0 );
	EndWrite();
	repeat until EventIsOK; {}
	EventIsOK = false;
	
	isBusy = false;
}
//---------------------------------------------------
//发送一个字符串
public void SetString( uint8 ID, uint8 Command, [code uint16*?] string )
{
	isBusy = true;
	
	StartWrite();
	WriteByte( 0xAA );
	WriteByte( 0 );
	WriteByte( ID ); //发给指定ID的控件
	WriteByte( Command ); //命令类型
	repeat first int16 i = 0; each i + 1; {
		if( string[ i ] == 0 ) {
			break;
		}
		uint16 char = string[ i ];
		WriteByte( char.0(uint8) );
		WriteByte( char.8(uint8) );
	}
	WriteByte( 0 );
	WriteByte( 0 );
	EndWrite();
	
	isBusy = false;
}
//---------------------------------------------------
//发送一个参数
public void SetValue( uint8 ID, uint8 Command, uint32 data )
{
	isBusy = true;
	
	StartWrite();
	WriteByte( 0x55 );
	WriteByte( 6 );
	WriteByte( ID ); //发给指定ID的控件
	WriteByte( Command ); //命令类型
	WriteByte( data.0(uint8) );
	WriteByte( data.8(uint8) );
	WriteByte( data.16(uint8) );
	WriteByte( data.24(uint8) );
	WriteByte( 0 );
	EndWrite();
	
	isBusy = false;
}
//---------------------------------------------------
//读取一个参数
public uint32 GetValue( uint8 vID, uint8 Command )
{
	isBusy = true;
	
	StartWrite();
	WriteByte( 0x55 );
	WriteByte( 2 );
	WriteByte( vID ); //发给指定数字框
	WriteByte( Command ); //读取参数
	WriteByte( 0 );
	EndWrite();
	
	repeat until DataIsOK; {}
	DataIsOK = false;
	uint32 D;
	D.0(uint8) = buffer[4];
	D.8(uint8) = buffer[5];
	D.16(uint8) = buffer[6];
	D.24(uint8) = buffer[7];
	
	isBusy = false;
	return D;
}
//----------------------------------------------------
//发送前导无效字节, 前导字节作为缓冲. 因为有时候第一个字节会丢失
void SendNullData()
{
	WriteByte( 0x00 );
	WriteByte( 0x00 );
}
//----------------------------------------------------
//发送一个字节
void WriteByte( uint8 data )
{
	CHIP.UDR = data;
	repeat until CHIP.UCSRA.5(bit) == 1; {}
	CHIP.UCSRA.5(bit) = 1;
	//delay(); 这个延时很重要! 去掉之后可以接收但是发送有错
}
//---------------------------------------------------
//485通信时需要这两个延时
void StartWrite()
{
	RDE_OUT = 1;
}
void EndWrite()
{
	//repeat 200 times; 有时候不稳定
	repeat 500 times; {}
	
	RDE_OUT = 0;
}






