public virtual IEnumerator<ITask> ReserveDevicePortHandler(ReserveDevicePort reservation)
        {
            //Debugger.Break();
            AttachResponse response;
            // If the device will be detached.
            if (reservation.Body.Connection.Port == LegoNxtPort.NotConnected)
            {
                response = new AttachResponse(reservation.Body.Connection, reservation.Body.DeviceModel);
                reservation.ResponsePort.Post(response);
                yield break;
            }

            switch (reservation.Body.Connection.Port)
            {
                case LegoNxtPort.A:
                case LegoNxtPort.EncoderA:
                    reservation.Body.Connection.Port = LegoNxtPort.MotorA;
                    break;
                case LegoNxtPort.B:
                case LegoNxtPort.EncoderB:
                    reservation.Body.Connection.Port = LegoNxtPort.MotorB;
                    break;
                case LegoNxtPort.C:
                case LegoNxtPort.EncoderC:
                    reservation.Body.Connection.Port = LegoNxtPort.MotorC;
                    break;
                case LegoNxtPort.AnyMotorPort:
                case LegoNxtPort.AnySensorPort:

                    lock(_state.Runtime.Devices)
                    {
                        // See if the device is already attached.
                        foreach (AttachRequest device in _state.Runtime.Devices.Values)
                        {
                            if (device.Registration != null
                                && device.Registration.ServiceUri != null
                                && device.Registration.ServiceUri.Equals(reservation.Body.ServiceUri, StringComparison.InvariantCultureIgnoreCase))
                            {
                                response = new AttachResponse(device.Registration.Connection, reservation.Body.DeviceModel);
                                reservation.ResponsePort.Post(response);

                                yield break;
                            }
                        }
                    }

                    if (reservation.Body.Connection.Port == LegoNxtPort.AnyMotorPort)
                    {
                        // Use the next available Motor Port
                        if (!_state.Runtime.Devices.ContainsKey(LegoNxtPort.MotorA.ToString())
                            || string.IsNullOrEmpty(_state.Runtime.Devices[LegoNxtPort.MotorA.ToString()].Registration.ServiceUri))
                            reservation.Body.Connection.Port = LegoNxtPort.MotorA;
                        else if (!_state.Runtime.Devices.ContainsKey(LegoNxtPort.MotorB.ToString())
                            || string.IsNullOrEmpty(_state.Runtime.Devices[LegoNxtPort.MotorB.ToString()].Registration.ServiceUri))
                            reservation.Body.Connection.Port = LegoNxtPort.MotorB;
                        else if (!_state.Runtime.Devices.ContainsKey(LegoNxtPort.MotorC.ToString())
                            || string.IsNullOrEmpty(_state.Runtime.Devices[LegoNxtPort.MotorC.ToString()].Registration.ServiceUri))
                            reservation.Body.Connection.Port = LegoNxtPort.MotorC;
                        else
                            reservation.Body.Connection.Port = LegoNxtPort.NotConnected;
                    }
                    else if (reservation.Body.Connection.Port == LegoNxtPort.AnySensorPort)
                    {
                        if (reservation.Body.DeviceType == LegoDeviceType.DigitalSensor)
                        {
                            bool done = !_state.Runtime.Connected;

                            yield return Arbiter.Receive(false, TestPortForI2CSensor(LegoNxtPort.Sensor1, reservation.Body.DeviceModel),
                                delegate(bool success)
                                {
                                    if (success)
                                        reservation.Body.Connection.Port = LegoNxtPort.Sensor1;
                                    done = success;
                                });

                            //if (!done)
                            //    yield return Arbiter.Receive(false, TestPortForI2CSensor(LegoNxtPort.Sensor2, reservation.Body.DeviceModel),
                            //        delegate(bool success)
                            //        {
                            //            if (success)
                            //                reservation.Body.Connection.Port = LegoNxtPort.Sensor2;
                            //            done = success;
                            //        });

                            //if (!done)
                            //    yield return Arbiter.Receive(false, TestPortForI2CSensor(LegoNxtPort.Sensor3, reservation.Body.DeviceModel),
                            //        delegate(bool success)
                            //        {
                            //            if (success)
                            //                reservation.Body.Connection.Port = LegoNxtPort.Sensor3;
                            //            done = success;
                            //        });

                            //if (!done)
                            //{
                            //    LogInfo(LogGroups.Console, "Checking for I2C Sensor on Port 4");
                            //    yield return Arbiter.Receive(false, TestPortForI2CSensor(LegoNxtPort.Sensor4, reservation.Body.DeviceModel),
                            //        delegate(bool success)
                            //        {
                            //            LogInfo(LogGroups.Console, "Found I2C Sensor on Port 4: " + success.ToString());
                            //            if (success)
                            //                reservation.Body.Connection.Port = LegoNxtPort.Sensor4;
                            //            done = success;
                            //        });
                            //}

                        }
                    }

                    break;

            }

            // If we weren't able to assign the Port, exit
            if ( reservation.Body.Connection.Port == LegoNxtPort.NotConnected
                || reservation.Body.Connection.Port == LegoNxtPort.AnyMotorPort
                || reservation.Body.Connection.Port == LegoNxtPort.AnySensorPort
                || reservation.Body.Connection.Port == LegoNxtPort.A
                || reservation.Body.Connection.Port == LegoNxtPort.B
                || reservation.Body.Connection.Port == LegoNxtPort.C
                || reservation.Body.Connection.Port == LegoNxtPort.EncoderA
                || reservation.Body.Connection.Port == LegoNxtPort.EncoderB
                || reservation.Body.Connection.Port == LegoNxtPort.EncoderC)
            {
                reservation.Body.Connection.Port = LegoNxtPort.NotConnected;
            }
            else // Reserve the connection
            {
                _state.Runtime.Devices[reservation.Body.Connection.ToString()] = new AttachRequest(reservation.Body);
            }

            response = new AttachResponse(reservation.Body.Connection, reservation.Body.DeviceModel);
            reservation.ResponsePort.Post(response);

            yield break;
        }
예제 #2
0
        public async Task Attach(CancellationToken cancellationToken)
        {
            System.Diagnostics.Debug.Assert(CurrentState == State.Idle);

            SocketPermission permission = new SocketPermission(
                NetworkAccess.Connect,
                TransportType.Tcp,
                kServerHostname,
                kServerPort);

            permission.Demand();

            IPAddress  ipAddress  = new IPAddress(new byte[] { 127, 0, 0, 1 });
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, kServerPort);

            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
                                ProtocolType.Tcp);
            socket.Blocking          = false;
            socket.NoDelay           = true;
            socket.ReceiveBufferSize = 1024 * 1024;
            socket.SendBufferSize    = 1024 * 1024;
            socket.ReceiveTimeout    = 0;
            socket.SendTimeout       = 0;

            OnStateChanged(State.Attaching);

            while (true)
            {
                Task task = Task.Factory.FromAsync(socket.BeginConnect, socket.EndConnect, ipEndPoint, null);
                try {
                    await task.WithCancellation(cancellationToken);
                } catch (OperationCanceledException) {
                    socket.Close();
                    socket = null;
                    OnStateChanged(State.Idle);
                    return;
                } catch (SocketException e) {
                    if (e.SocketErrorCode == SocketError.ConnectionRefused)
                    {
                        // Not found - emulator may still be starting.
                        System.Diagnostics.Debug.WriteLine("Connection refused; trying again...");
                        continue;
                    }
                    OnStateChanged(State.Idle);
                    return;
                }
                break;
            }

            // Start recv pump.
            Dispatch.Issue(() => ReceivePump());

            var fbb = BeginRequest();

            AttachRequest.StartAttachRequest(fbb);
            int requestDataOffset = AttachRequest.EndAttachRequest(fbb);
            var response          = await CommitRequest(fbb, RequestData.AttachRequest, requestDataOffset);

            System.Diagnostics.Debug.Assert(response.ResponseDataType ==
                                            ResponseData.AttachResponse);
            var attachResponse = new AttachResponse();

            response.GetResponseData(attachResponse);

            // Open mmap to share memory.
            memoryHandle = FileMapping.OpenFileMapping(
                FileMapAccess.FILE_MAP_ALL_ACCESS, false, attachResponse.MemoryFile);
            if (memoryHandle.IsInvalid)
            {
                System.Diagnostics.Debug.Fail("Unable to open target memory");
                Detach();
                return;
            }

            // Open mmap to code cache.
            codeCacheHandle =
                FileMapping.OpenFileMapping(FileMapAccess.FILE_MAP_ALL_ACCESS, false,
                                            attachResponse.CodeCacheFile);
            if (codeCacheHandle.IsInvalid)
            {
                System.Diagnostics.Debug.Fail("Unable to open target code cache");
                Detach();
                return;
            }
            codeCachePtr = FileMapping.MapViewOfFileEx(
                codeCacheHandle, FileMapAccess.FILE_MAP_ALL_ACCESS, 0, 0,
                attachResponse.CodeCacheSize, attachResponse.CodeCacheBase);

            // Setup the memory system. This maps the emulator memory into our address
            // space.
            if (!Memory.InitializeMapping(memoryHandle))
            {
                Detach();
                return;
            }

            OnStateChanged(State.Attached);
        }
        public virtual IEnumerator<ITask> AttachAndSubscribeHandler(AttachAndSubscribe attach)
        {
            AttachResponse response;
            // Disconnect request
            if (attach.Body.Registration.Connection.Port == LegoNxtPort.NotConnected)
            {
                // Check if the sensor was already registered.
                UnregisterDevice(attach.Body.Registration.ServiceUri);

                response = new AttachResponse(attach.Body.Registration.Connection, attach.Body.Registration.DeviceModel);
                attach.ResponsePort.Post(response);

                yield break;
            }

            // Invalid Ports, return a fault
            if (attach.Body.Registration.Connection.Port == LegoNxtPort.AnyMotorPort
                || attach.Body.Registration.Connection.Port == LegoNxtPort.AnySensorPort
                || attach.Body.Registration.Connection.Port == LegoNxtPort.A
                || attach.Body.Registration.Connection.Port == LegoNxtPort.B
                || attach.Body.Registration.Connection.Port == LegoNxtPort.C
                || attach.Body.Registration.Connection.Port == LegoNxtPort.EncoderA
                || attach.Body.Registration.Connection.Port == LegoNxtPort.EncoderB
                || attach.Body.Registration.Connection.Port == LegoNxtPort.EncoderC)
            {
                attach.ResponsePort.Post(
                    Fault.FromException(
                        new ArgumentOutOfRangeException(
                            string.Format("Invalid {0} Port: {1}", attach.Body.Registration.DeviceModel, attach.Body.Registration.Connection))));

                yield break;
            }

            // Convert all inherited LegoCommand types to LegoCommands.
            NormalizeAttachRequest(attach.Body);

            string priorUri = null;
            string connectionKey = attach.Body.Registration.Connection.ToString();
            if (_state.Runtime.Devices.ContainsKey(connectionKey))
            {
                priorUri = _state.Runtime.Devices[connectionKey].Registration.ServiceUri;
                if (priorUri != attach.Body.Registration.ServiceUri)
                    UnregisterDevice(priorUri);
            }

            _state.Runtime.Devices[connectionKey] = attach.Body;

            if (!string.IsNullOrEmpty(priorUri) && !priorUri.Equals(attach.Body.Registration.ServiceUri, StringComparison.InvariantCultureIgnoreCase))
            {
                // Send Notification to prior service that it has been disconnected
                PortSet<DsspDefaultLookup, DsspDefaultDrop> priorServicePort = ServiceForwarder<PortSet<DsspDefaultLookup, DsspDefaultDrop>>(priorUri);
                priorServicePort.Post(DsspDefaultDrop.Instance);
            }

            if (_state.Runtime.Connected)
            {
                if (attach.Body.InitializationCommands != null)
                {
                    foreach (LegoCommand cmd in attach.Body.InitializationCommands.Commands)
                    {
                        // Send Initialization Sequence.
                        yield return Arbiter.Choice(_brickPort.SendCommand(cmd),
                            delegate(LegoResponse ok) { },
                            delegate(Fault fault) { LogError(fault); });
                    }
                }
            }

            attach.Body.Registration.SubscriberUri = attach.Body.Subscriber;
            attach.Body.Timestamp = DateTime.Now;

            // Register for periodic Polling.
            if (attach.Body.PollingCommands != null
                && attach.Body.PollingCommands.Commands != null
                && attach.Body.PollingCommands.Commands.Count > 0)
            {
                _pollingPort.Post(new PollingEntry(attach.Body));
            }

            response = new AttachResponse(attach.Body.Registration.Connection, attach.Body.Registration.DeviceModel);

            yield return Arbiter.Choice(SelectiveSubscribe(attach),
                delegate(SubscribeResponseType ok)
                {
                    attach.ResponsePort.Post(response);
                },
                attach.ResponsePort.Post
            );

            yield break;
        }