在前两篇中,路由器已经刷入OpenWrt系统并安装了Ser2net等相关软件,如今就能够写一个客户端与路由器进行Socket通讯。一共有三个应用,桌面应用采用WPF编写,Windows Phone应用采用Windows Phone 8.1 Runtime架构,Win8应用也是Runtime,其实直接把WinPhone代码复制过去就能够直接生成一个Win8应用。windows
本篇记录主要记录WinPhone应用编写过程。数组
应用功能:利用重力感应控制小车左转、右转、前进、后退,点击视频能够查看车载摄像头视频画面。服务器
先贴图,基本界面是这样,大部分都是拖出来的,尚未进行认真布局。架构
利用Visual Studio 建立一个Windows Phone 8.1空白应用程序(Runtime版本)。而后就能够把上面一大堆TextBlock和Button控件拖出来。app
左上角一堆TextBlock分别是X-axis(加速度计x值),Y-axis(加速度计y值),Z-axis(加速度计z值),X二、Y2是红线上面一点的坐标。异步
中间那个”山“,左右两个是ProcessingBar(进度条),下面一条是蓝色的线,中间红色的线以两条线的交点为原点,随着手机左右摇摆而转动。async
MSDN参考:http://msdn.microsoft.com/library/windows/apps/br226882布局
这里用的是StreamSocket Class。ui
1 try 2 { 3 StatusText.Text = "正在尝试链接。。。"; 4 //新建hostname,用服务器ip地址初始化 5 HostName serverHost = new HostName("192.168.1.1"); 6 //调用链接异步方法,2001为ser2net程序的端口号 7 await clientSocket.ConnectAsync(serverHost, "2001"); 8 connected = true; 9 StatusText.Text = "Connection established" + Environment.NewLine; 10 } 11 catch (Exception exception) 12 { 13 StatusText.Text = "Connect failed with error:" + exception.Message; 14 }
MSDN参考http://msdn.microsoft.com/zh-cn/library/windows/apps/windows.storage.streams.datawriter.aspxthis
主要利用的是DataWriter Class
1 uint len = 0; 2 byte[] bytedata = new byte[10]; 3 //data是要传送的string,将其转化为Byte[]数组进行传送 4 bytedata = Encoding.UTF8.GetBytes(data); 5 try 6 { 7 StatusText.Text = "Trying to send data..."; 8 //新建DataWriter对象,用StreamSocket.OutputStream进行初始化 9 using(DataWriter writer = new DataWrite(clientSocket.OutputStream)) 10 { 11 //获取要传送的字节数组的长度 12 len = writer.MeasureString(data); 13 //向输出流写入数据 14 writer.WriteBytes(bytedata); 15 await writer.StoreAsync(); 16 await writer.FlushAsync(); 17 writer.DetachStream(); 18 19 20 } 21 22 StatusText.Text = "Data " + data + " was sent."; 23 } 24 catch (Exception) 25 { 26 StatusText.Text = "Send data or receive failed with error: "; 27 28 29 }
MSDN参考:http://msdn.microsoft.com/zh-cn/library/windows/apps/windows.storage.streams.datareader
接收数据不像发送那样,须要发送的时候直接调用方法便可。接收数据须要单独用一个线程进行周期性的检查,不如我这里就是没100ms(delay的值)接收一次,若有数据便显示在文本框中。
1 //利用线程池对象建立一个周期性工做的计时器。 2 //调用的方法是ThreadPoolTimer.CreateTimer(TimerElapsedHandler, TimeSpan) 3 //其中第一个参数是即时结束事件处理委托,这里用Lambda表达式 处理。 4 5 ThreadPoolTimer timer = ThreadPoolTimer.CreatePeriodicTimer( 6 async (source) => 7 { 8 if (!connected) 9 { 10 StatusText.Text = "Must be connected to send!"; 11 return; 12 } 13 //建立DataReader对象,用输入流初始化 14 DataReader reader = new DataReader(clientSocket.InputStream); 15 //异步方法,载入一个字节 16 reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8; 17 reader.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian; 18 await reader.LoadAsync(1); 19 while (reader.UnconsumedBufferLength > 0) 20 { 21 22 s += reader.ReadString(reader.UnconsumedBufferLength); 23 if (s.Length == 50) 24 s = ""; 25 } 26 reader.DetachStream(); 27 //建立要提交到线程池的工做项来更新UI 28 //RunAsync参考:http://msdn.microsoft.com/zh-cn/library/windows/apps/windows.system.threading.threadpool.runasync.aspx 29 30 31 await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, 32 () => 33 { 34 ReceiveDataBlock.Text = s; 35 } 36 ); 37 }, delay 38 39 );
MSDN参考:http://msdn.microsoft.com/zh-cn/library/windows/apps/xaml/hh465272.aspx
参考文档能够直接复制过来就用。
1 private async void ReadingChanged(object sender, AccelerometerReadingChangedEventArgs e) 2 { 3 await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => 4 { 5 this.reading = e.Reading; 6 //三个文本框中分别显示出当前加速度计x,y,z的值 7 txtXAxis.Text = String.Format("{0,5:0.00}", reading.AccelerationX); 8 txtYAxis.Text = String.Format("{0,5:0.00}", reading.AccelerationY); 9 txtZAxis.Text = String.Format("{0,5:0.00}", reading.AccelerationZ); 10 if (!(Math.Abs(this.PreviousY-reading.AccelerationY)<=0.02)) 11 { 12 //计算红线端点的坐标,显示在对应的文本框中 13 Pointer.X2 = (-140 * Math.Sin(Math.PI / 2 * reading.AccelerationY) + 320); 14 Pointer.Y2 = (-140 * Math.Cos(Math.PI / 2 * reading.AccelerationY) + 280); 15 X.Text =string.Format("{0,5:0.00}", Pointer.X2); 16 Y.Text =string.Format("{0,5:0.00}", Pointer.Y2); 17 int i=(int)Math.Abs(reading.AccelerationY*10); 18 string s=i.ToString(); 19 //z<0.5 向前走 20 if(reading.AccelerationZ<=0.5) 21 { 22 if (!(Math.Abs(reading.AccelerationY - previous) < 0.05)) 23 { 24 if (reading.AccelerationY > 0) 25 //发送控制数据 26 SendData("ADL" + s + "A"); 27 else if (reading.AccelerationY < 0) 28 SendData("ADR" + s + "A"); 29 sentBack = false; 30 } 31 } 32 //z>0.5 向后退 33 else if (reading.AccelerationZ > 0.5&&sentBack==false) 34 { 35 SendData("ADB0A"); 36 sentBack = true; 37 } 38 previous = reading.AccelerationY; 39 } 40 }); 41 42 43 }
至此,即可以正常像小车发送数据进行重力感应控制了。