private static void UwpFirmata_SysexMessageReceived(Microsoft.Maker.Firmata.UwpFirmata caller, Microsoft.Maker.Firmata.SysexCallbackEventArgs argv) { var data = argv.getDataBuffer().ToArray(); switch (argv.getCommand()) { case Distance: distance = (ulong)(data[0] + (data[1] * 128)); distanceDataAvailable = true; break; case Protocol_Version: HandleFirmataVersion(data); break; default: break; } }
/// <summary> /// Initializes the Remote Arduino Provider and stores the handles to the 4 controllers. Only runs once. /// </summary> private static async Task InitAsync() { await semaphoreSlim.WaitAsync(); try { if (!initialized) { // Change this to true for Bluetooth and false for USB bool UseBluetooth = false; bool configurationFound = false; DeviceInformation connectedDeviceInformation = null; if (UseBluetooth) { // This assumes that there is only one BT SPP device on the computer. If there are multiple devices // the you will need to identify the device from the list returned from FindAllAsync() and use // that one as the device to pass to the arduino provider string spp_aqs = RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort); DeviceInformationCollection deviceList = await DeviceInformation.FindAllAsync(spp_aqs); if (deviceList.Count > 0) { DeviceInformation device = deviceList[0]; // Remember to ensure that the Firmata Sketch has the baud rate set to the same default as the BT device ArduinoProviders.ArduinoProvider.Configuration = new ArduinoProviders.ArduinoConnectionConfiguration(device, 57600); configurationFound = true; } else { Debug.WriteLine("No bluetooth connected Arduino found"); } } else { Selector selector = new Selector(); IEnumerable <ArduinoDeviceListEntry> list = await selector.GetDeviceList(); if (list.Count() > 0) { var listArray = list.ToArray(); connectedDeviceInformation = listArray[0].DeviceInformation; ArduinoProviders.ArduinoProvider.Configuration = new ArduinoProviders.ArduinoConnectionConfiguration(connectedDeviceInformation, 57600); configurationFound = true; } else { Debug.WriteLine("No USB Connected Ardino found"); } } // we can't use a null check on Configuration as it will auto allocate and be in an invalid state if (configurationFound) { // Check our firmata and make sure we are good, if not we will flash the device with our required MakeCode specific firmata int retry = 2; bool FirmwareUploadRequired = false; while (retry-- > 0) { FirmwareUploadRequired = false; try { if (firmataProvider == null) { firmataProvider = new ArduinoProviders.ArduinoFirmataProvider(); } bool firmataInitOk = false; try { firmataInitOk = await firmataProvider.InitializeAsync(); } catch (Exception e) { Debug.WriteLine(e.Message); } if (firmataInitOk == true) { // there is a firmata version on the device now. Check if it is what we need. int MajorVersion = firmataProvider.FirmataInstance.getFirmwareVersionMajor(); int MinorVersion = firmataProvider.FirmataInstance.getFirmwareVersionMinor(); String FirmwareName = firmataProvider.FirmataInstance.getFirmwareName(); Debug.WriteLine($"Arduino with Firmata found Version {MajorVersion}.{MinorVersion} {FirmwareName}"); if (String.Compare(FirmwareName, "MakeCodeFirmata.ino", StringComparison.OrdinalIgnoreCase) != 0) { // Not the makecode firmware so need to upload it FirmwareUploadRequired = true; } else { // Makecode firmware, but is it the required version? // TODO: Version check } } else { // No firmata on the device FirmwareUploadRequired = true; } } catch (Exception ex) { Debug.WriteLine("Failed to get Firmata Instance: " + ex.Message); FirmwareUploadRequired = true; } if (FirmwareUploadRequired) { Debug.WriteLine("Firmata update required"); // Need to close our current connection if any if (firmataProvider != null) { firmataProvider.Dispose(); firmataProvider = null; ArduinoProvider.Close(); } Arduino arduino = Arduino.GetArduino(connectedDeviceInformation.Id); await arduino.Connect(); var programmer = arduino.GetProgrammer(); await programmer.Program("ms-appx:///BlockCode/MakeCodeFirmata/MakeCodeFirmata.ino.standard.hex", 28672); // Now let the arduino go so we can reopen it in non progamming mode. arduino.Dispose(); // And we will let it cycle again to verify Debug.WriteLine("Arduino Firmata updated "); return; } else { // Have a good firmware so store it and setup our callback uwpFirmata = firmataProvider.FirmataInstance; uwpFirmata.SysexMessageReceived += UwpFirmata_SysexMessageReceived; retry = 0; } } if (uwpFirmata == null) { // not going to be able to go on. Debug.WriteLine("Arduino Firmata Initalization failed"); return; } // Now that we have a good firmata we can do the other connections Windows.Devices.LowLevelDevicesController.DefaultProvider = new ArduinoProviders.ArduinoProvider(); gpioController = await GpioController.GetDefaultAsync(); pwmController = await PwmController.GetDefaultAsync(); adcController = await AdcController.GetDefaultAsync(); i2cController = await I2cController.GetDefaultAsync(); if ( (gpioController != null) && (pwmController != null) && (adcController != null) && (i2cController != null) && (uwpFirmata != null) ) { // We got good initialzation initialized = true; } } else { // Something went wrong with init Debug.WriteLine("Arduino Initalization failed"); } } else { // Duplicate initalization, we can just ignore this } } catch (Exception e) { Debug.WriteLine("Arduino Initalization failed: " + e.Message); } finally { // When the task is ready, release the semaphore. It is vital to ALWAYS release the semaphore when we are ready, // or else we will end up with a Semaphore that is forever locked. // This is why it is important to do the Release within a try...finally clause; // program execution may crash or take a different path, this way you are guaranteed execution semaphoreSlim.Release(); } }