In a previous blog I covered the use of the FTDI D2XX driver on a Windows 10 IoT Core Raspberry PI 2. This covered a missing plank from the Win10RPI2 armour that was much called for. It facilitates the use of USB-Serial devices based upon the  FTDI chipset of which there are many. Jark took an idea I had to use the FTDI ARM Windows RT D2XX driver for the RT Surface 1 & 2 and created a comprehensive Universal Windows App that used the driver. His GitHub project contains complete instructions to install the driver on a RPI2. This project is though an App.  What about a using it in a Startup Task on a headless RPI2? A blocking issue has arisen.

 

Links:

D2xx WinRT Guide: http://www.ftdichip.com/Support/Documents/InstallGuides/AN_271%20D2xx%20WinRT%20Guide.pdf

An old link the explains what error 28 is. It says driver not loaded.

 

 

 

image

 

Discussion

In the IoT Samples is the HeadlessBlinky project which shows how to implement a Startup Task on Headless IoT Device. On such a device, you run a Startup Task ,created as Windows Runtime Component, instead of a Startup App, One developer has reported that the FTDI driver fails to list any FTDI devices when called from a Startup Task, particularly on a Headless RPI2. See the discussion: https://github.com/Jark/FTDISample/issues/4

 

The issue seems to be that although the driver appears to be loaded it doesn’t work for a headless scenario, I have written a much simpler version of the code to use the FTDI D2XX driver that only implements the code in the driver’s documentation (see the PDF above). The solution has two  projects. One that is a UW App and the headless Startup Task version. Both use the exact same code, in a static class FTDISimple. The code for that follows:

namespace FTDISimple
{
    static class FTDISimple
    {
        private static ThreadPoolTimer timer;
        private static FTManager ftManager;
        private static bool deviceNotStarted;
        public static int Timeout { get; set; } = 10000;
        public static int TimerPeriod { get; set; } = 500;

        public static void Init()
        {
            deviceNotStarted = true;
            InitFTDI();
            timer = ThreadPoolTimer.CreatePeriodicTimer(Timer_Tick, TimeSpan.FromMilliseconds(TimerPeriod));
        }

        private static void InitFTDI()
        {
            try
            {
                ftManager = new FTManager();
                string ver = FTManager.GetLibraryVersion();
                System.Diagnostics.Debug.WriteLine(ver);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
            }
        }

        
        public static void StartDevice()
        {
            deviceNotStarted = false;
            IList<IFTDeviceInfoNode> deviceList = ftManager.GetDeviceList();
            foreach (IFTDeviceInfoNode deviceInfo in deviceList)
            {
                Debug.WriteLine("Device Type: {0}\r\nSerial Number: {1}\r\nDescription: {2}\r\n\r\n ", deviceInfo.DeviceType.ToString(), deviceInfo.SerialNumber, deviceInfo.Description);
                if (deviceInfo.Description == "My USB Product")
                {
                }
            }
        }

        public static async void OpenDevice(IFTDeviceInfoNode deviceInfo)
        {
            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

            cancellationTokenSource.CancelAfter(Timeout);
            var myDevice = ftManager.OpenByDescription(deviceInfo.Description);
            await myDevice.SetBaudRateAsync(9600);
            await myDevice.SetFlowControlAsync(FLOW_CONTROL.RTS_CTS, 0x00, 0x00);
            await myDevice.SetDataCharacteristicsAsync(WORD_LENGTH.BITS_8, STOP_BITS.BITS_1, PARITY.NONE);
            await myDevice.SetLatencyTimerAsync(16);
            var action = ThreadPool.RunAsync(async (source) => {
                byte dataTx = new byte[10]; for (int i = 0; i < dataTx.Length; i++) dataTx[i] = (byte)(i + 60);
                dataTx[7] = (byte)0;
                dataTx[8] = (byte)'\r';
                dataTx[9] = (byte)'\n';
                while (!cancellationTokenSource.Token.IsCancellationRequested)
                {
                    byte dataRx = new byte[10];
                    await myDevice.WriteAsync(dataTx, 10);
                    await myDevice.ReadAsync(dataRx, 10);
                }
            }, WorkItemPriority.Normal);
        }


        private static void Timer_Tick(ThreadPoolTimer timer)
        {
            //value = (value == GpioPinValue.High) ? GpioPinValue.Low : GpioPinValue.High;
            // pin.Write(value);
            if (ftManager != null)
            {
                try
                {
                    IList<IFTDeviceInfoNode> deviceList = ftManager.GetDeviceList();
                    if (deviceNotStarted)
                        if (deviceList.Count != 0)
                            StartDevice();
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                }
            }
        }
    }
}

The Universal Windows app runs OK:

'FTDISimple.exe' (CoreCLR: CoreCLR_UWP_Domain): Loaded 'C:\Users\DefaultAccount\AppData\Local\DevelopmentFiles\398a995c-e7ff-438c-82de-37fc1bebbb30VS.Debug_ARM.david\System.Globalization.dll'. Module was built without symbols.
1.0.2.0
Device Type: FT232R
Serial Number: 
Description: 

Whereas with the Startup Task, the highlighted (yellow) line in the code above fails (as per yellow line below):

'backgroundTaskHost.exe' (CoreCLR: CoreCLR_UWP_Domain): Loaded 'C:\Users\DefaultAccount\AppData\Local\DevelopmentFiles\FTDISimpleHeadless-uwpVS.Debug_ARM.david\System.Threading.dll'. Cannot find or open the PDB file.
Exception thrown: 'System.InvalidOperationException' in FTDI.D2xx.WinRT.winmd
1.0.2.0
The thread 0x9e8 has exited with code 0 (0x0).

So the instantiation of the FTManager fails in the Windows Runtime Component. The class is actually created (its not null) but some aspect of it fails. Perhaps there is some UI aspect to the FTDI code?

 

Added: Debug Traces for Startup Task showing  complete Debug Windows for above: Win 10 IoT Core- FTDISimpleIoT Debug Trace for StartupTask

 

image

FTDIManager immediately after its instantiation, so its not null.

 

Next:

Need to discuss this Microsoft and FTDI as we only have the binaries for the FTDI driver.