This article reworks the previous few articles that use BT Serial and the connectivity  so that USB virtual serial is used for communication. It covers in detail USB Serial connectivity between a UWP app and an Arduino devices as well as with a Windows 10 IoT-Core device (eg RPI).

 

Code Repository : https://github.com/djaus2/SurfPad

Status: Bluetooth and USB Serial connectivity between UWP app and Arduino device implemented.

 

Articles

  1. The UI
  2. Json Configuration
  3. Text Output
  4. Bluetooth Connectivity-Connectivity
  5. Bluetooth Connectivity-Arduino Software

    Bluetooth Connectivity-UWP Software
    Bluetooth Connectivity-Win 10 IoT-Core Remote App 

  6. USB Serial Connectivity (this)

  7. SurfPad States

 

The USB Serial Terminal

The app reuses some code from a previous GitHub project: iotAzureSensors 
It reworks the SerialTerminal.xaml  XAML page and its codebehind page SerialTerminal.xaml.cs form the IoTCoreMenu project within that repository project.

Code now on GitHub. Look at the Pages/USBSerialTerminal.xaml.cs page.

 

USB Serial Connectivity

USB Serial on Arduino Uno

When used as the connectivity between the UWP UI app an the remote app (sketch) on an Arduino device, connectivity is straight forward as the USB cable used to download the sketch from a development machine, and to also power the Arduino device, can also be used as a USB Serial conduit.

USB Serial on RPI

With the Raspberry PI things are a bit mre complex as the USB Serial cable used to power the RPI from the development machine is only a power connection. It dose not support USB Serial. In the early days of Windows 10  IOT-Core on a RPI, serial connectivity was a vexed question. The support for USB to SErial chipsets was very underdone*. Indeed the  most popular chipset FTDI wasn’t supported. Also UART0 on Pins 9 and 10 was implemented. As a community discussion, I suggested using the FTDI driver for the RT Surface (Windows 8/8.1) be ported which was taken up and subsequently implemented. See the discussion and links at:

Win 10 IoT Core: FTDI Serial Driver on embedded101.com

* Silicon Labs Chipset (eg CP2102EK USB-UART Bridge Eval Kit) was supported and worked for me then.

 

Subsequently support for FTDI chipset was added to IOT-Core and the native UART (UART0) was also added.

So if you want to implement USB-Serial from a RPI to a desktop/laptop etc., you need to implement the USB-Serial at both end of the connection. At the desktop and at RPI. You may plug a USB-Serial dongle (eg FTDI ) into both ends and connect their DB9 with a serial crossover cable. Not as simple as with the Arduino device. Or you might use, say, a SparkFun USB to Serial Breakout connected to the RPI Tx and Rx 3.3V UART0 signals on Pins 8 and 10 respectively into RS232 Signals encoded in a USB connection that can be plugged via cable in to a desktop USB 2/3 Host port.

 

USB Serial Code

The outline of the connectivity code follows. The State Machine for the connectivity is covered elsewhere in these articles.

UWP UI App USB Serial Code

image The USBSerialTerminal page method ListAvailablePorts gets a list of serial devices from a query to the DeviceInformation class. That list is filtered on the DeviceId string that accepts strings that include USB or FTDI. This removes and Bluetooth serial devices. If there is only one device in the list or if a Device Id is listed in the configuration data then it is automatically opened.

ConnectSerial opens the serial port and sets its serial configuration. It can also automatically start the Listen thread.

The WriteAsync method  takes as string and asynchronously writes it to the DataWriter which was created from the SerialPort OutputStream.

The Listen thread repeatedly calls the RecvAsync method.

The RecvAsync method creates a Task from the DataReader which was created from the SerialPort InputStream. This thread awaits the reception of bytes by the DataReader that are then read into a buffer where they can be processed, for example into a string.

 

private async void ListAvailablePorts() { bool done = false; try { string aqs = SerialDevice.GetDeviceSelector(); var dis = await DeviceInformation.FindAllAsync(aqs); listofDevices.Clear(); if (numDevices != 0) { for (int i = 0; i < numDevices; i++) { if ((dis[i].Name.Contains("USB")) || (dis[i].Id.Contains("FTDI"))) this.listofDevices.Add(dis[i]); } //User selects the USB Serial device from the list DeviceListSource.Source = this.listofDevices; comPortInput.IsEnabled = true; ConnectDevices.SelectedIndex = -1; //Actual code (see GitHub repository) here contains code to automatically connect // ..if device Id (disi.Id is listed in the Json Configuration data. // .. or if only one device connect to it. } } catch (Exception ex) { } }

USBSerialTerminal ListAvailablePorts() method

 

public async Task<bool> ConnectSerial(DeviceInformation entry) { bool ret = false; try { serialPort = await SerialDevice.FromIdAsync(entry.Id); if (serialPort == null) {; return false; } // Configure serial settings serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000); serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000); serialPort.BaudRate = MainPage.cBAUD; serialPort.Parity = SerialParity.None; serialPort.StopBits = SerialStopBitCount.One; serialPort.DataBits = 8; // Create cancellation token object to close I/O operations when closing the device ReadCancellationTokenSource = new CancellationTokenSource(); ret = true; } catch (Exception ex) { } return ret; }

USBSerialTerminal ConnectSerial() Method

 

public async void SendCh(char ch) { string msg = "" + ch; .... // Create the DataWriter object and attach to OutputStream dataWriteObject = new DataWriter(serialPort.OutputStream); //Launch the WriteAsync task to perform the write await WriteAsync(msg); ... } private async Task WriteAsync(string msg) { Task<UInt32> storeAsyncTask; if (msg.Length != 0) { // Load the text from the sendText input text box to the dataWriter object dataWriteObject.WriteString(msg); // Launch an async task to complete the write operation storeAsyncTask = dataWriteObject.StoreAsync().AsTask(); UInt32 bytesWritten = await storeAsyncTask; } else { } }

USBSerialTerminal WriteAsync() Method

 

private async void Listen() { ReadCancellationTokenSource = new CancellationTokenSource(); try { if (serialPort != null) { dataReaderObject = new DataReader(serialPort.InputStream); // keep reading the serial input while (true) { await ReadAsync(ReadCancellationTokenSource.Token); } } } catch (Exception ex) { } finally { // Cleanup once complete } }

USBSerialTerminal Listen() Thread

 

private async Task ReadAsync(CancellationToken cancellationToken) { Task<UInt32> loadAsyncTask; uint ReadBufferLength = 1024; // If task cancellation was requested, comply cancellationToken.ThrowIfCancellationRequested(); // Set InputStreamOptions to complete the asynchronous read operation when one or more bytes is available dataReaderObject.InputStreamOptions = InputStreamOptions.Partial; // Create a task object to wait for data on the serialPort.InputStream loadAsyncTask = dataReaderObject.LoadAsync(ReadBufferLength).AsTask(cancellationToken); // Launch the task and wait UInt32 bytesRead = await loadAsyncTask; if (bytesRead > 0) { try { byte bytes = new byte[bytesRead]; dataReaderObject.ReadBytes(bytes); string currenbtRecvdText = Encoding.UTF8.GetString(bytes); ... ... } catch (Exception ex) { } } }

USBSerialTerminal RecvAsync Method

 

Arduino Remote App (Sketch) USB Serial Code

setup() { Serial.begin(9600); while (!Serial) { } Serial.print((char)StartedSignal); }

The Arduino Remote App (Sketch) setup() function

 

void loopUSBSerial() { thisByte = Serial.peek(); if (thisByte != -1) { thisByte = Serial.read(); //Each char is interpretted as byte representing a keypress //The byte is the id of button pressed + ' ' (so are printable switch (thisByte) { } }

The Arduino Remote App (Sketch) loop() function

 

RPI USB Serial Code as the  Remote App

The connectivity is the same as the desktop UWP code.