Example #1
0
        private static void TransmitTask(Win32Serial.Device device)
        {
            // Create write overlapped structure for async operation
            var overlapped = Win32Serial.Device.CreateOverlapped();

            uint       numbytes;
            int        i     = 1;
            const uint size  = MessageBody.SerialSize;
            int        limit = 15;

            if (Options.TestCount.HasValue)
            {
                limit = Options.TestCount.Value;
            }
            while (!Options.Test || i <= limit)
            {
                // Come up with a new message

                var tempData = new MessageBody
                {
                    Machine = new Machine
                    {
                        Temperature = Rnd.NextDouble() * 100.0,
                        Pressure    = Rnd.NextDouble() * 100.0,
                    },
                    Ambient = new Ambient
                    {
                        Temperature = Rnd.NextDouble() * 100.0,
                        Humidity    = Rnd.Next(24, 27)
                    },
                    Number = i
                };

                // Async write, using overlapped structure
                var message = tempData.SerialEncode;
                device.Write(Encoding.ASCII.GetBytes(message), size, out numbytes, ref overlapped);
                Log.WriteLineVerbose($"Write {i} Started");

                // Block until write completes
                device.GetOverlappedResult(ref overlapped, out numbytes, true);

                Log.WriteLine($"Write {i} Completed. Wrote {numbytes} bytes: \"{message}\"");
                i++;
                Thread.Sleep(1000);
            }
            Environment.Exit(0);
        }
Example #2
0
        private static async void ReaderTask(SerialPort device)
        {
            try
            {
                //
                // Continuously read from serial device
                // and send those values to edge hub.
                //

                int i = 1;
                while (true)
                {
                    try
                    {
                        string message = device.ReadLine();
                        Log.WriteLine($"Read {i} Completed. Received {message.Length} bytes: \"{message}\"");

                        // Translate it into a messagebody
                        if (Options.UseEdge)
                        {
                            var tempData = new MessageBody();
                            tempData.SerialEncode = message;
                            tempData.TimeCreated  = DateTime.Now;
                            if (tempData.isValid)
                            {
                                string dataBuffer   = JsonConvert.SerializeObject(tempData);
                                var    eventMessage = new Message(Encoding.UTF8.GetBytes(dataBuffer));
                                Log.WriteLine($"SendEvent: [{dataBuffer}]");
                                await ioTHubModuleClient.SendEventAsync("temperatureOutput", eventMessage);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.WriteLineException(ex);
                    }

                    i++;
                }
            }
            catch (Exception ex)
            {
                Log.WriteLineException(ex);
            }
        }
        private static MessageBody ResultsToMessage(ScoringOutput outcome)
        {
            var resultVector = outcome.softmaxout_1.GetAsVectorView();

            // Find the top 3 probabilities
            List <float> topProbabilities = new List <float>()
            {
                0.0f, 0.0f, 0.0f
            };
            List <int> topProbabilityLabelIndexes = new List <int>()
            {
                0, 0, 0
            };

            // SqueezeNet returns a list of 1000 options, with probabilities for each, loop through all
            for (int i = 0; i < resultVector.Count(); i++)
            {
                // is it one of the top 3?
                for (int j = 0; j < 3; j++)
                {
                    if (resultVector[i] > topProbabilities[j])
                    {
                        topProbabilityLabelIndexes[j] = i;
                        topProbabilities[j]           = resultVector[i];
                        break;
                    }
                }
            }

            var message = new MessageBody();

            message.results = new LabelResult[3];

            for (int i = 0; i < 3; i++)
            {
                message.results[i] = new LabelResult()
                {
                    label = labels[topProbabilityLabelIndexes[i]], confidence = topProbabilities[i]
                };
            }

            return(message);
        }
        private static void TransmitTask(Win32Serial.Device device)
        {
            // Create write overlapped structure for async operation
            var overlapped = Win32Serial.Device.CreateOverlapped();

            uint       numbytes;
            int        i    = 1;
            const uint size = MessageBody.SerialSize;

            while (true)
            {
                Thread.Sleep(1000);

                // Come up with a new message

                var tempData = new MessageBody
                {
                    Machine = new Machine
                    {
                        Temperature = Rnd.NextDouble() * 100.0,
                        Pressure    = Rnd.NextDouble() * 100.0,
                    },
                    Ambient = new Ambient
                    {
                        Temperature = Rnd.NextDouble() * 100.0,
                        Humidity    = Rnd.Next(24, 27)
                    },
                    Number = i
                };

                // Async write, using overlapped structure
                var message = tempData.SerialEncode;
                device.Write(Encoding.ASCII.GetBytes(message), size, out numbytes, ref overlapped);
                Console.WriteLine($"{DateTime.Now.ToLocalTime()} Write {i} Started");

                // Block until write completes
                device.GetOverlappedResult(ref overlapped, out numbytes, true);

                Console.WriteLine($"{DateTime.Now.ToLocalTime()} Write {i} Completed. Wrote {numbytes} bytes: \"{message}\"");
                i++;
            }
        }
Example #5
0
        private static void TransmitTask(SerialPort device)
        {
            int i     = 1;
            int limit = 5;

            if (Options.TestCount.HasValue)
            {
                limit = Options.TestCount.Value;
            }
            while (!Options.Test || i <= limit)
            {
                // Come up with a new message

                var tempData = new MessageBody
                {
                    Machine = new Machine
                    {
                        Temperature = Rnd.NextDouble() * 100.0,
                        Pressure    = Rnd.NextDouble() * 100.0,
                    },
                    Ambient = new Ambient
                    {
                        Temperature = Rnd.NextDouble() * 100.0,
                        Humidity    = Rnd.Next(24, 27)
                    },
                    Number = i
                };

                // Async write, using overlapped structure
                var message = tempData.SerialEncode;
                device.WriteLine(message);
                Log.WriteLine($"Write {i} Completed. Wrote {message.Length} bytes: \"{message}\"");

                Thread.Sleep(1000);
                i++;
            }
            Environment.Exit(0);
        }
Example #6
0
        static async Task <int> Main(string[] args)
        {
            try
            {
                //
                // Parse options
                //

                Options = new AppOptions();
                Options.Parse(args);

                if (Options.ShowList)
                {
                }
                if (Options.Exit)
                {
                    return(-1);
                }
                if (string.IsNullOrEmpty(Options.FileName))
                {
                    throw new ApplicationException("Please use --file to specify which file to use");
                }


                //
                // Init module client
                //

                if (Options.UseEdge)
                {
                    Log.WriteLine($"{AppOptions.AppName} module starting.");
                    await BlockTimer("Initializing Azure IoT Edge", async() => await InitEdge());
                }

                cts = new CancellationTokenSource();
                AssemblyLoadContext.Default.Unloading += (ctx) => cts.Cancel();
                Console.CancelKeyPress += (sender, cpe) => cts.Cancel();


                //
                // Load model
                //

                MLModel model = null;
                Console.WriteLine($"Loading model from: '{Options.ModelPath}', Exists: '{File.Exists(Options.ModelPath)}'");
                await BlockTimer($"Loading modelfile '{Options.ModelPath}' on the {(Options.UseGpu ? "GPU" : "CPU")}",
                                 async() =>
                {
                    var d    = Directory.GetCurrentDirectory();
                    var path = d + "\\" + Options.ModelPath;

                    StorageFile modelFile = await AsAsync(StorageFile.GetFileFromPathAsync(path));
                    model = await MLModel.CreateFromStreamAsync(modelFile);
                });


                do
                {
                    //
                    // Open file
                    //
                    var rows = new List <DataRow>();
                    try
                    {
                        using (var fs = new StreamReader(Options.FileName))
                        {
                            // I just need this one line to load the records from the file in my List<CsvLine>
                            rows = new CsvHelper.CsvReader(fs).GetRecords <DataRow>().ToList();
                            Console.WriteLine($"Loaded {rows.Count} row(s)");
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                    }
                    Console.WriteLine(rows);


                    //
                    // Main loop
                    //

                    foreach (var row in rows)
                    {
                        //
                        // Evaluate model
                        //

                        var inputShape = new long[2] {
                            1, 4
                        };
                        var inputFeatures = new float[4] {
                            row.Temperature, row.Pressure, row.Humidity, row.ExternalTemperature
                        };

                        MLModelVariable result    = null;
                        var             evalticks = await BlockTimer("Running the model",
                                                                     async() =>
                        {
                            result = await model.EvaluateAsync(new MLModelVariable()
                            {
                                Variable = TensorFloat.CreateFromArray(inputShape, inputFeatures)
                            });
                        });

                        //
                        // Print results
                        //

                        var message = new MessageBody
                        {
                            result = result.Variable.GetAsVectorView().First()
                        };
                        message.metrics.evaltimeinms = evalticks;
                        var json = JsonConvert.SerializeObject(message);
                        Log.WriteLineRaw($"Recognized {json}");

                        //
                        // Send results to Edge
                        //

                        if (Options.UseEdge)
                        {
                            var eventMessage = new Message(Encoding.UTF8.GetBytes(json));
                            await ioTHubModuleClient.SendEventAsync("resultsOutput", eventMessage);

                            // Let's not totally spam Edge :)
                            await Task.Delay(500);
                        }


                        Console.WriteLine("Waiting 1 second...");
                        Thread.Sleep(1000);
                    }
                }while (Options.RunForever && !cts.Token.IsCancellationRequested);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                return(-1);
            }

            return(0);
        }
        static async Task Main(string[] args)
        {
            try
            {
                //
                // Parse options
                //

                Options = new AppOptions();

                Options.Parse(args);

                if (Options.Exit)
                {
                    return;
                }

                //
                // Open Device
                //

                using (var device = await Si7021.Open())
                {
                    if (null == device)
                    {
                        throw new ApplicationException($"Unable to open sensor. Please ensure that no other applications are using this device.");
                    }

                    //
                    // Dump device info
                    //

                    Log.WriteLineRaw($"Model: {device.Model}");
                    Log.WriteLineRaw($"Serial Number: {device.SerialNumber}");
                    Log.WriteLineRaw($"Firmware Rev: {device.FirmwareRevision}");

                    //
                    // Init module client
                    //

                    if (Options.UseEdge)
                    {
                        Init().Wait();
                    }

                    //
                    // Launch background thread to obtain readings
                    //


                    var background = Task.Run(async() =>
                    {
                        while (true)
                        {
                            device.Update();

                            var message = new MessageBody();
                            message.Ambient.Temperature = device.Temperature;
                            message.Ambient.Humidity    = device.Humidity;
                            message.TimeCreated         = DateTime.Now;

                            string dataBuffer = JsonConvert.SerializeObject(message);
                            var eventMessage  = new Message(Encoding.UTF8.GetBytes(dataBuffer));
                            Log.WriteLineRaw($"SendEvent: [{dataBuffer}]");

                            if (Options.UseEdge)
                            {
                                await ioTHubModuleClient.SendEventAsync("temperatureOutput", eventMessage);
                            }

                            await Task.Delay(1000);
                        }
                    });

                    //
                    // Wait until the app unloads or is cancelled
                    //

                    var cts = new CancellationTokenSource();
                    AssemblyLoadContext.Default.Unloading += (ctx) => cts.Cancel();
                    Console.CancelKeyPress += (sender, cpe) => cts.Cancel();
                    WhenCancelled(cts.Token).Wait();
                }
            }
            catch (Exception ex)
            {
                Log.WriteLineException(ex);
            }
        }
Example #8
0
        /// <summary>
        /// Module behavior:
        ///        Sends data periodically (with default frequency of 5 seconds).
        ///        Data trend:
        ///         - Machine Temperature regularly rises from 21C to 100C in regularly with jitter
        ///         - Machine Pressure correlates with Temperature 1 to 10psi
        ///         - Ambient temperature stable around 21C
        ///         - Humidity is stable with tiny jitter around 25%
        ///                Method for resetting the data stream
        /// </summary>
        static async Task SendEvents(
            ModuleClient moduleClient,
            int messageCount,
            SimulatorParameters sim,
            CancellationTokenSource cts)
        {
            int    count       = 1;
            double currentTemp = sim.TempMin;
            double normal      = (sim.PressureMax - sim.PressureMin) / (sim.TempMax - sim.TempMin);

            while (!cts.Token.IsCancellationRequested && (SendUnlimitedMessages(messageCount) || messageCount >= count))
            {
                if (Reset)
                {
                    currentTemp = sim.TempMin;
                    Reset.Set(false);
                }

                if (currentTemp > sim.TempMax)
                {
                    currentTemp += Rnd.NextDouble() - 0.5;  // add value between [-0.5..0.5]
                }
                else
                {
                    currentTemp += -0.25 + (Rnd.NextDouble() * 1.5);  // add value between [-0.25..1.25] - average +0.5
                }

                if (sendData)
                {
                    var events = new List <MessageEvent> ();

                    // Add Desired Number of Events into the Message
                    for (int i = 0; i < eventCount; i++)
                    {
                        events.Add(new MessageEvent {
                            DeviceId    = Environment.GetEnvironmentVariable("DEVICE") ?? Environment.MachineName,
                            TimeStamp   = DateTime.UtcNow,
                            Temperature = new SensorReading {
                                Value  = currentTemp,
                                Units  = "degC",
                                Status = 200
                            },
                            Pressure = new SensorReading {
                                Value  = sim.PressureMin + ((currentTemp - sim.TempMin) * normal),
                                Units  = "psig",
                                Status = 200
                            },
                            SuctionPressure = new SensorReading {
                                Value  = sim.PressureMin + 4 + ((currentTemp - sim.TempMin) * normal),
                                Units  = "psig",
                                Status = 200
                            },
                            DischargePressure = new SensorReading {
                                Value  = sim.PressureMin + 1 + ((currentTemp - sim.TempMin) * normal),
                                Units  = "psig",
                                Status = 200
                            },
                            Flow = new SensorReading {
                                Value  = Rnd.Next(78, 82),
                                Units  = "perc",
                                Status = 200
                            }
                        });
                        currentTemp += -0.25 + (Rnd.NextDouble() * 1.5);
                    }

                    var msgBody = new MessageBody {
                        Asset  = Environment.GetEnvironmentVariable("ASSET") ?? "whidbey",
                        Source = Environment.MachineName,
                        Events = events
                    };

                    string dataBuffer   = JsonConvert.SerializeObject(msgBody);
                    var    eventMessage = new Message(Encoding.UTF8.GetBytes(dataBuffer));
                    eventMessage.Properties.Add("sequenceNumber", count.ToString());
                    eventMessage.Properties.Add("batchId", BatchId.ToString());
                    Console.WriteLine($"\t{DateTime.Now.ToLocalTime()}> Sending message: {count}, Body: [{dataBuffer}]");

                    await moduleClient.SendEventAsync("temperatureOutput", eventMessage);

                    count++;
                }

                await Task.Delay(messageDelay, cts.Token);
            }

            if (messageCount < count)
            {
                Console.WriteLine($"Done sending {messageCount} messages");
            }
        }
Example #9
0
        private static void UpdateWebServerPayloads(MessageBody message, byte[] data, byte[] annotatedData)
        {
            try
            {
                ResultPayload payload = new ResultPayload()
                {
                    Result = message
                };
                string summaryText = "-";
                if ((message.results != null) && (message.metrics != null))
                {
                    long   totalEvaluations = _stats.TotalEvaluationSuccessCount;
                    double confidence       = 0.0;
                    string lastLabel        = "";

                    _stats.TotalEvaluationSuccessCount = _stats.TotalEvaluationSuccessCount + 1;
                    if (message.results.Length > 0)
                    {
                        summaryText =
                            $"Matched : {message.results[0].label} - Confidence ={message.results[0].confidence.ToString("P")} - Eval Time {message.metrics.evaltimeinms} ms";
                        confidence = message.results[0].confidence;
                        lastLabel  = message.results[0].label;
                    }
                    else
                    {
                        summaryText = $"No Match - Eval Time {message.metrics.evaltimeinms} ms";
                    }

                    //update eval ms stats
                    try
                    {
                        if (totalEvaluations > 0)
                        {
                            _stats.AverageEvaluationMs =
                                ((_stats.AverageEvaluationMs * ((double)totalEvaluations) +
                                  ((double)message.metrics.evaltimeinms)) / ((double)totalEvaluations + 1));
                        }
                        else
                        {
                            _stats.AverageEvaluationMs = (double)message.metrics.evaltimeinms;
                        }
                    }
                    catch (Exception)
                    {
                    }

                    //update match totals
                    try
                    {
                        if (lastLabel != "")
                        {
                            if (totalEvaluations > 0)
                            {
                                _stats.AverageConfidence =
                                    ((_stats.AverageConfidence * ((double)totalEvaluations) + ((double)confidence)) /
                                     ((double)totalEvaluations + 1));
                            }
                            else
                            {
                                _stats.AverageConfidence = (double)confidence;
                            }

                            lock (_objLock)
                            {
                                LabelSummary ls = _stats.MatchSummary.FirstOrDefault(o => o.Label == lastLabel);
                                if (ls == null)
                                {
                                    ls = new LabelSummary()
                                    {
                                        Label = lastLabel, TotalMatches = 1
                                    };
                                    _stats.MatchSummary.Add(ls);
                                }
                                else
                                {
                                    ls.TotalMatches = ls.TotalMatches + 1;
                                }
                            }
                        }
                    }
                    catch (Exception)
                    {
                    }
                }
                else if (message.metrics == null)
                {
                    _stats.TotalEvaluationFailCount = _stats.TotalEvaluationFailCount + 1;
                    summaryText = $"Evaluation Failed";
                }
                else
                {
                    _stats.TotalEvaluationSuccessCount = _stats.TotalEvaluationSuccessCount + 1;
                    summaryText = $"No Match - Eval Time {message.metrics.evaltimeinms} ms";
                }

                payload.Statistics = _stats;


                if ((data != null) && (annotatedData != null))
                {
                    payload.ImageSnapshot = Convert.ToBase64String(data);
                    SetLatestFrameData(JsonConvert.SerializeObject(payload), JsonConvert.SerializeObject(_stats),
                                       annotatedData);
                }
            }
            catch (Exception e)
            {
                Log.WriteLineRaw($"Failed to create Result Payload : {e.Message}");
            }
        }
Example #10
0
        static async Task <int> Main(string[] args)
        {
            try
            {
                //
                // Parse options
                //

                Options = new AppOptions();

                Options.Parse(args);

                if (Options.ShowList)
                {
                    var devices = await FrameSource.GetSourceNamesAsync();

                    Log.WriteLine("Available cameras:");

                    foreach (var device in devices)
                    {
                        Log.WriteLine(device);
                    }
                }

                if (Options.Exit)
                {
                    return(-1);
                }

                if (!Options.UseImages)
                {
                    if (string.IsNullOrEmpty(Options.DeviceId))
                    {
                        throw new ApplicationException("Please use --device to specify which camera to use");
                    }
                }

                try
                {
                    string sv            = AnalyticsInfo.VersionInfo.DeviceFamilyVersion;
                    ulong  v             = ulong.Parse(sv);
                    ulong  v1            = (v & 0xFFFF000000000000L) >> 48;
                    ulong  v2            = (v & 0x0000FFFF00000000L) >> 32;
                    ulong  v3            = (v & 0x00000000FFFF0000L) >> 16;
                    ulong  v4            = (v & 0x000000000000FFFFL);
                    var    systemVersion = $"{v1}.{v2}.{v3}.{v4}";

                    _stats.CurrentVideoDeviceId = Options.DeviceId;
                    _stats.Platform             = $"{AnalyticsInfo.VersionInfo.DeviceFamily} - {System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE") ?? "Unknown"} - {systemVersion}";
                }
                catch (Exception)
                {
                }


                //
                // Init module client
                //

                if (Options.UseEdge)
                {
                    Log.WriteLine($"{AppOptions.AppName} module starting.");
                    await BlockTimer("Initializing Azure IoT Edge", async() => await InitEdge());
                }

                cts = new CancellationTokenSource();
                AssemblyLoadContext.Default.Unloading += (ctx) => cts.Cancel();
                Console.CancelKeyPress += (sender, cpe) => cts.Cancel();

                //
                // Load model
                //

                ScoringModel model = null;
                await BlockTimer($"Loading modelfile '{Options.ModelPath}' on the {(Options.UseGpu ? "GPU" : "CPU")}",
                                 async() =>
                {
                    var d    = Directory.GetCurrentDirectory();
                    var path = d + "\\" + Options.ModelPath;
                    StorageFile modelFile = await AsAsync(StorageFile.GetFileFromPathAsync(path));
                    model = await ScoringModel.CreateFromStreamAsync(modelFile, Options.UseGpu);
                });

                _stats.OnnxModelLoaded  = true;
                _stats.CurrentOnnxModel = Options.ModelPath;
                _stats.IsGpu            = Options.UseGpu;

                // WebServer Code


                HttpServer httpsv            = null;
                bool       HttpServerStarted = false;

                if (Options.RunForever)
                {
                    try
                    {
                        Log.WriteLine($"Start HTTP Server on port : " + Options.WebServerPort.ToString());
                        httpsv = new HttpServer(Options.WebServerPort);
                        httpsv.Start();
                        httpsv.OnGet += HttpsvOnOnGet;

                        HttpServerStarted = true;
                        Log.WriteLine($"- HTTP Server Started.");
                        Log.WriteLine($"");
                    }
                    catch (Exception e)
                    {
                        HttpServerStarted = false;
                        Log.WriteLine($"Exiting - Websockets Server Failed to start : " + e.Message);
                    }
                }


                //
                // Open camera
                //

                FrameSource     frameSource     = null;
                ImageFileSource imageFileSource = null;

                if (Options.UseImages)
                {
                    imageFileSource = new ImageFileSource();
                    imageFileSource.ScanUpdateQueue(Options.ImagePath);
                }
                else
                {
                    frameSource = new FrameSource();
                    await frameSource.StartAsync(Options.DeviceId, Options.UseGpu);
                }

                _stats.DeviceInitialized = true;
                SetLatestStatsPayload(JsonConvert.SerializeObject(_stats));

                //
                // Main loop
                //
                do
                {
                    ScoringOutput outcome   = null;
                    int           evalticks = 0;
                    Log.WriteLineVerbose("Getting frame...");

                    byte[]      data          = new byte[] { };
                    byte[]      annotatedData = new byte[] { };
                    MessageBody message       = null;

                    //
                    // Use Image File Source or fall back to Webcam Source if not specified
                    //
                    if (Options.UseImages)
                    {
                        var(fileName, sbmp) = await imageFileSource.GetNextImageAsync(Options.ImagePath, cts.Token);

                        using (var vf = VideoFrame.CreateWithSoftwareBitmap(sbmp))
                        {
                            ImageFeatureValue imageTensor = ImageFeatureValue.CreateFromVideoFrame(vf);


                            _stats.TotalFrames = _stats.TotalFrames + 1;

                            //
                            // Evaluate model
                            //

                            var ticksTaken = await BlockTimer($"Running the model",
                                                              async() =>
                            {
                                var input = new ScoringInput()
                                {
                                    data = imageTensor
                                };
                                outcome = await model.EvaluateAsync(input);
                            });

                            evalticks = ticksTaken;

                            message = ResultsToMessage(outcome);
                            message.metrics.evaltimeinms = evalticks;
                            _stats.TotalEvaluations      = _stats.TotalEvaluations + 1;
                            message.imgSrc = fileName;

                            string summaryText = "";

                            if (message.results.Length > 0)
                            {
                                summaryText = $"Matched : {message.results[0].label} - Confidence ={message.results[0].confidence.ToString("P")} - Eval Time {message.metrics.evaltimeinms} ms";
                            }
                            data = await ImageUtils.GetConvertedImage(sbmp);

                            annotatedData = await ImageUtils.AnnotateImage(sbmp, $"Current Image : {fileName ?? "-"}", summaryText);
                        }
                    }
                    else
                    {
                        using (var frame = await frameSource.GetFrameAsync())
                        {
                            var inputImage = frame.VideoMediaFrame.GetVideoFrame();
                            ImageFeatureValue imageTensor = ImageFeatureValue.CreateFromVideoFrame(inputImage);

                            _stats.TotalFrames = _stats.TotalFrames + 1;

                            //
                            // Evaluate model
                            //
                            var ticksTaken = await BlockTimer("Running the model",
                                                              async() =>
                            {
                                var input = new ScoringInput()
                                {
                                    data = imageTensor
                                };
                                outcome = await model.EvaluateAsync(input);
                            });

                            evalticks = ticksTaken;

                            message = ResultsToMessage(outcome);
                            message.metrics.evaltimeinms = evalticks;
                            _stats.TotalEvaluations      = _stats.TotalEvaluations + 1;

                            string summaryText = "";

                            if (message.results.Length > 0)
                            {
                                summaryText = $"Matched : {message.results[0].label} - Confidence ={message.results[0].confidence.ToString("P")} - Eval Time {message.metrics.evaltimeinms} ms";
                            }
                            data = await ImageUtils.GetConvertedImage(inputImage.SoftwareBitmap);

                            annotatedData = await ImageUtils.AnnotateImage(inputImage.SoftwareBitmap, $"Current Webcam : {Options.DeviceId ?? "-"}", summaryText);
                        }
                    }

                    if (message != null)
                    {
                        //
                        // Print results
                        //
                        message.metrics.evaltimeinms = evalticks;
                        var json = JsonConvert.SerializeObject(message,
                                                               new JsonSerializerSettings
                        {
                            //won't print null imgSrc if null
                            NullValueHandling = NullValueHandling.Ignore
                        });
                        Log.WriteLineRaw($"Inferenced: {json}");

                        if (Options.UseWebServer)
                        {
                            //
                            // Update the latest webserver payload snapshots with data from inferencing
                            //
                            UpdateWebServerPayloads(message, data, annotatedData);
                        }

                        //
                        // Send results to Edge
                        //


                        if (Options.UseEdge)
                        {
                            var eventMessage = new Message(Encoding.UTF8.GetBytes(json));
                            await ioTHubModuleClient.SendEventAsync("resultsOutput", eventMessage);

                            // Let's not totally spam Edge :)
                            await Task.Delay(500);
                        }
                        else if (Options.UseImages)
                        {
                            //slow it down a little..
                            await Task.Delay(TimeSpan.FromSeconds(5));
                        }
                    }
                }while (Options.RunForever && !cts.Token.IsCancellationRequested);

                if (frameSource != null)
                {
                    await frameSource.StopAsync();
                }


                if (HttpServerStarted)
                {
                    try
                    {
                        Log.WriteLine($"- Stopping Web Server.");
                        httpsv.OnGet -= HttpsvOnOnGet;
                        httpsv.Stop();
                        httpsv = null;
                        Log.WriteLine($"- Web Server Stopped.");
                    }
                    catch (Exception)
                    {
                    }
                }

                return(0);
            }
            catch (Exception ex)
            {
                Log.WriteLineException(ex);
                return(-1);
            }
        }