示例#1
0
        public async Task <IReadOnlyList <WifiLedBulb> > Scan(int millisecondsTimeout)
        {
            //Delete old bulb list
            m_discoveredBulbs.Clear();

            //Create UDP Client for discovery broadcast
            using (UdpClient discovery_client = new UdpClient())
            {
                //Send magic packet to get controllers to announce themselves
                IPEndPoint ip    = new IPEndPoint(IPAddress.Broadcast, DISCOVERY_PORT);
                byte[]     bytes = Encoding.ASCII.GetBytes("HF-A11ASSISTHREAD");
                discovery_client.Send(bytes, bytes.Length, ip);

                //Listen for their return packets
                IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, DISCOVERY_PORT);
                m_cancelScanSource = new CancellationTokenSource(millisecondsTimeout);

                while (true)
                {
                    //Hack in a way to allow a CancellationToken for ReceiveAsync
                    //Based heavily on https://stackoverflow.com/questions/19404199/how-to-to-make-udpclient-receiveasync-cancelable
                    var receive_task = discovery_client.ReceiveAsync();
                    var tcs          = new TaskCompletionSource <bool>();
                    using (m_cancelScanSource.Token.Register(s => tcs.TrySetResult(true), null))
                    {
                        if (await Task.WhenAny(receive_task, tcs.Task) == receive_task)
                        {
                            //ReceiveAsync was successful, parse the reply
                            string   message   = Encoding.ASCII.GetString(receive_task.Result.Buffer);
                            string[] bulb_data = message.Split(',');
                            var      bulb      = new WifiLedBulb(bulb_data[0], bulb_data[1], bulb_data[2]);
                            m_discoveredBulbs.Add(bulb);
                            DiscoveredBulb?.Invoke(bulb);
                        }
                        else
                        {
                            //Cancelled (or timed out), close out socket
                            discovery_client.Close();
                            m_cancelScanSource.Dispose();
                            m_cancelScanSource = null;
                            break;
                        }
                    }
                }
            }
            return(m_discoveredBulbs.AsReadOnly());
        }
        /*Scan
         * Sends out a UDP packet over the network and listens for response
         * returns a Task... still need to investigate how this works
         * assuming it returns null until an actual return value is sent,
         * in this case a List of Bulb objects.
         *
         * @params:
         * millisecondsTimeout: timeout for each individual bulb if no response is received. (non functional)
         * maxRetries: retries after not hearing from a single bulb (non functional)
         */
        public async Task <List <Bulb> > Scan(int millisecondsTimeout = 2000, int maxRetries = 2)
        {
            //Delete old bulb list
            m_discoveredBulbs.Clear();

            //Create UDP Client for discovery broadcast
            using (UdpClient discovery_client = new UdpClient())
            {
                //Send magic packet to get controllers to announce themselves
                IPEndPoint ip = new IPEndPoint(IPAddress.Broadcast, DISCOVERY_PORT);



                m_cancelScanSource = new CancellationTokenSource(millisecondsTimeout);
                Console.WriteLine("sending magic packet");
                discovery_client.Send(MAGIC_UDP_PACKET, MAGIC_UDP_PACKET.Length, ip); //Send magic packet to get controllers to announce themselves
                IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, DISCOVERY_PORT);  //Listen for their return packets


                while (true)
                {
                    //Hack in a way to allow a CancellationToken for ReceiveAsync
                    //Based heavily on https://stackoverflow.com/questions/19404199/how-to-to-make-udpclient-receiveasync-cancelable
                    var receive_task = discovery_client.ReceiveAsync();
                    var tcs          = new TaskCompletionSource <bool>();

                    //??? confused about the using identifier and wrapping curly brackets
                    using (m_cancelScanSource.Token.Register(s => tcs.TrySetResult(true), null))
                    {
                        //if the cancellation token isn't true continue, else break the loop
                        if (await Task.WhenAny(receive_task, tcs.Task) == receive_task)
                        {
                            //ReceiveAsync was successful, encode the reply into ASCII and parse
                            string message = Encoding.ASCII.GetString(receive_task.Result.Buffer);

                            Console.WriteLine(message);

                            //When encoded to ASCII and converted to a string, data arrives in this pattern:
                            // 'ipaddress,macaddress,typeid'
                            // for example "192.168.1.21,6001940ED006,ZJ2101"

                            // split the data and save to variables
                            string[] bulb_data  = message.Split(',');
                            string   ipAddress  = bulb_data[0];
                            string   macAddress = bulb_data[1];
                            string   typeID     = bulb_data[2];

                            //instantiate a bulb object in "BulbsFactory" Class. Could just as easily be a...
                            //BulbsFactory method.
                            var bulb = BulbsFactory.CreateBulb(ipAddress, macAddress, typeID);

                            // If BulbsFactory can't figure out what the bulb type is, it will set to null
                            // We dont add null bulbs to our list of Bulb objects. So we 'continue',
                            // skipping bulbList.Add(bulb);
                            if (bulb == null)
                            {
                                continue;
                            }

                            //add our newly created Bulb object to a list so that we may access it later
                            m_discoveredBulbs.Add(bulb);
                            DiscoveredBulb?.Invoke(bulb);
                        }
                        else     //Cancelled (or timed out), close out socket
                        {
                            Console.WriteLine(m_discoveredBulbs.Count);


                            //close our port so it doesn't timeout causing errors
                            discovery_client.Close();

                            //??? destroy our cancelationsource
                            m_cancelScanSource.Dispose();
                            //??? set our cancelationsource to null. This may be why scanRetry isn't working
                            m_cancelScanSource = null;

                            //break out of the first  'while (true)' loop as we have no more bulbs to add
                            break;
                        }
                    }
                }
            }

            return(m_discoveredBulbs);
        }