在前兩篇中,路由器已經刷入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 }
至此,即可以正常像小車發送數據進行重力感應控制了。