Exemplo n.º 1
0
 /// <summary>
 /// Initialize physical transfer and perform initial data transfer.
 /// This is only called once on initialization
 /// </summary>
 /// <returns>Asynchronous task</returns>
 public static bool Connect() => DataTransfer.PerformFullTransfer(false);
Exemplo n.º 2
0
        /// <summary>
        /// Perform communication with the RepRapFirmware controller
        /// </summary>
        /// <returns>Asynchronous task</returns>
        public static async Task Run()
        {
            do
            {
                // Check if an emergency stop has been requested
                if (_emergencyStopRequested && DataTransfer.WriteEmergencyStop())
                {
                    _emergencyStopRequested = false;
                    Console.WriteLine("[info] Emergency stop");
                    DataTransfer.PerformFullTransfer();
                }

                // Check if a firmware reset has been requested
                if (_resetRequested && DataTransfer.WriteReset())
                {
                    _resetRequested = false;
                    Console.WriteLine("[info] Resetting controller");
                    DataTransfer.PerformFullTransfer();
                }

                // Check if a firmware update is supposed to be performed
                if (_iapStream != null && _firmwareStream != null)
                {
                    await Invalidate("Firmware update imminent");
                    await PerformFirmwareUpdate();

                    if (Program.UpdateOnly)
                    {
                        // Stop after installing the firmware update
                        break;
                    }
                }

                // Invalidate data if a controller reset has been performed
                if (DataTransfer.HadReset())
                {
                    _emergencyStopRequested = _resetRequested = false;
                    await Invalidate("Controller has been reset");
                }

                // Check for changes of the print status.
                // The packet providing file info has be sent first because it includes a time_t value that must reside on a 64-bit boundary!
                if (_printStarted)
                {
                    using (Model.Provider.AccessReadOnly())
                    {
                        _printStarted = !DataTransfer.WritePrintStarted(Model.Provider.Get.Job.File);
                    }
                }
                else if (_printStoppedReason.HasValue && DataTransfer.WritePrintStopped(_printStoppedReason.Value))
                {
                    _printStoppedReason = null;
                }

                // Deal with heightmap requests
                using (await _heightmapLock.LockAsync())
                {
                    // Check if the heightmap is supposed to be set
                    if (_setHeightmapRequest != null && DataTransfer.WriteHeightMap(_heightmapToSet))
                    {
                        _setHeightmapRequest.SetResult(null);
                        _setHeightmapRequest = null;
                    }

                    // Check if the heightmap is requested
                    if (_getHeightmapRequest != null && !_isHeightmapRequested)
                    {
                        _isHeightmapRequested = DataTransfer.WriteGetHeightMap();
                    }
                }

                // Process incoming packets
                for (int i = 0; i < DataTransfer.PacketsToRead; i++)
                {
                    PacketHeader?packet;

                    try
                    {
                        packet = DataTransfer.ReadPacket();
                        if (!packet.HasValue)
                        {
                            Console.WriteLine("[err] Read invalid packet");
                            break;
                        }
                        await ProcessPacket(packet.Value);
                    }
                    catch (ArgumentOutOfRangeException)
                    {
                        DataTransfer.DumpMalformedPacket();
                        throw;
                    }
                }
                _bytesReserved = 0;

                // Process pending codes, macro files and requests for resource locks/unlocks as well as flush requests
                bool dataProcessed;
                do
                {
                    dataProcessed = false;
                    foreach (ChannelInformation channel in _channels)
                    {
                        using (channel.Lock())
                        {
                            if (!channel.IsBlocked)
                            {
                                if (channel.ProcessRequests())
                                {
                                    // Something could be processed
                                    dataProcessed = true;
                                }
                                else
                                {
                                    // Cannot do any more on this channel
                                    channel.IsBlocked = true;
                                }
                            }
                        }
                    }
                }while (dataProcessed);

                // Request object model updates
                if (DateTime.Now - _lastQueryTime > TimeSpan.FromMilliseconds(Settings.ModelUpdateInterval))
                {
                    DataTransfer.WriteGetObjectModel(_moduleToQuery);
                    _lastQueryTime = DateTime.Now;
                }

                // Update filament assignment per extruder drive
                lock (_extruderFilamentUpdates)
                {
                    if (_extruderFilamentUpdates.TryPeek(out Tuple <int, string> filamentMapping) &&
                        DataTransfer.WriteAssignFilament(filamentMapping.Item1, filamentMapping.Item2))
                    {
                        _extruderFilamentUpdates.Dequeue();
                    }
                }

                // Do another full SPI transfer
                DataTransfer.PerformFullTransfer();
                _channels.ResetBlockedChannels();

                // Wait a moment
                await Task.Delay(Settings.SpiPollDelay, Program.CancelSource.Token);
            }while (!Program.CancelSource.IsCancellationRequested);
        }
Exemplo n.º 3
0
        private static async Task PerformFirmwareUpdate()
        {
            // Notify clients that we are now installing a firmware update
            using (await Model.Provider.AccessReadWriteAsync())
            {
                Model.Provider.Get.State.Status = MachineStatus.Updating;
            }

            // Get the CRC16 checksum of the firmware binary
            byte[] firmwareBlob = new byte[_firmwareStream.Length];
            await _firmwareStream.ReadAsync(firmwareBlob, 0, (int)_firmwareStream.Length);

            ushort crc16 = CRC16.Calculate(firmwareBlob);

            // Send the IAP binary to the firmware
            Console.Write("[info] Flashing IAP binary");
            bool dataSent;

            do
            {
                dataSent = DataTransfer.WriteIapSegment(_iapStream);
                DataTransfer.PerformFullTransfer();
                Console.Write('.');
            }while (dataSent);
            Console.WriteLine();

            _iapStream.Close();
            _iapStream = null;

            // Start the IAP binary
            DataTransfer.StartIap();

            // Send the firmware binary to the IAP program
            int numRetries = 0;

            do
            {
                if (numRetries != 0)
                {
                    Console.WriteLine("Error");
                }

                Console.Write("[info] Flashing RepRapFirmware");
                _firmwareStream.Seek(0, SeekOrigin.Begin);
                while (DataTransfer.FlashFirmwareSegment(_firmwareStream))
                {
                    Console.Write('.');
                }
                Console.WriteLine();

                Console.Write("[info] Verifying checksum... ");
            }while (++numRetries < 3 && !DataTransfer.VerifyFirmwareChecksum(_firmwareStream.Length, crc16));

            if (numRetries == 3)
            {
                Console.WriteLine("Error");

                // Failed to flash the firmware
                await Utility.Logger.LogOutput(MessageType.Error, "Could not flash the firmware binary after 3 attempts. Please install it manually via bossac.");

                Program.CancelSource.Cancel();
            }
            else
            {
                Console.WriteLine("OK");

                // Wait for the IAP binary to restart the controller
                DataTransfer.WaitForIapReset();
                Console.WriteLine("[info] Firmware update successful!");
            }

            _firmwareStream.Close();
            _firmwareStream = null;

            using (_firmwareUpdateLock.Lock())
            {
                _firmwareUpdateRequest.SetResult(null);
                _firmwareUpdateRequest = null;
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Perform communication with the RepRapFirmware controller
        /// </summary>
        /// <returns>Asynchronous task</returns>
        public static async Task Run()
        {
            do
            {
                // Check if an emergency stop has been requested
                if (_emergencyStopRequested && DataTransfer.WriteEmergencyStop())
                {
                    _emergencyStopRequested = false;
                    Console.WriteLine("[info] Emergency stop");
                    DataTransfer.PerformFullTransfer();
                }

                // Check if a firmware reset has been requested
                if (_resetRequested && DataTransfer.WriteReset())
                {
                    _resetRequested = false;
                    Console.WriteLine("[info] Resetting controller");
                    DataTransfer.PerformFullTransfer();
                }

                // Check if a firmware update is supposed to be performed
                if (_iapStream != null && _firmwareStream != null)
                {
                    await InvalidateData("Firmware update imminent");
                    await PerformFirmwareUpdate();
                }

                // Invalidate data if a controller reset has been performed
                if (DataTransfer.HadReset())
                {
                    Console.WriteLine("[info] Controller has been reset");
                    await InvalidateData("Controller reset");
                }

                // Check for changes of the print status.
                // The packet providing file info has be sent first because it includes a time_t value that must reside on a 64-bit boundary!
                if (_printStarted)
                {
                    using (Model.Provider.AccessReadOnly())
                    {
                        _printStarted = !DataTransfer.WritePrintStarted(Model.Provider.Get.Job.File);
                    }
                }
                else if (_printStoppedReason.HasValue && DataTransfer.WritePrintStopped(_printStoppedReason.Value))
                {
                    _printStoppedReason = null;
                }

                // Deal with heightmap requests
                using (_heightmapLock.Lock())
                {
                    // Check if the heightmap is supposed to be set
                    if (_heightmapToSet != null && DataTransfer.WriteHeightMap(_heightmapToSet))
                    {
                        _heightmapToSet = null;
                        _setHeightmapRequest.SetResult(null);
                        _setHeightmapRequest = null;
                    }

                    // Check if the heightmap is requested
                    if (_getHeightmapRequest != null && !_heightmapRequested)
                    {
                        _heightmapRequested = DataTransfer.WriteGetHeightMap();
                    }
                }

                // Process incoming packets
                DateTime startTime = DateTime.Now;
                for (int i = 0; i < DataTransfer.PacketsToRead; i++)
                {
                    Communication.PacketHeader?packet;

                    try
                    {
                        packet = DataTransfer.ReadPacket();
                        if (!packet.HasValue)
                        {
                            Console.WriteLine("[err] Read invalid packet");
                            break;
                        }
                    }
                    catch (ArgumentOutOfRangeException)
                    {
                        DataTransfer.DumpMalformedPacket();
                        throw;
                    }

                    await ProcessPacket(packet.Value);

                    if (DateTime.Now - startTime > TimeSpan.FromMilliseconds(250))
                    {
                        Console.WriteLine($"WARN: Packet with request {packet?.Request} took longer than 250ms!");
                    }
                    startTime = DateTime.Now;
                }
                _bytesReserved = 0;

                // Process pending codes, macro files and requests for resource locks/unlocks as well as flush requests
                bool dataProcessed;
                List <CodeChannel> blockedChannels = new List <CodeChannel>();
                do
                {
                    dataProcessed = false;
                    foreach (CodeChannel channel in CodeChannels)
                    {
                        if (!blockedChannels.Contains(channel))
                        {
                            using (Channels[channel].Lock())
                            {
                                if (Channels[channel].ProcessRequests())
                                {
                                    // Something could be done on this channel
                                    dataProcessed = true;
                                }
                                else
                                {
                                    // Don't call Process() again for this channel if it returned false before
                                    blockedChannels.Add(channel);
                                }
                            }
                        }
                    }
                } while (dataProcessed);

                if (DateTime.Now - startTime > TimeSpan.FromMilliseconds(250))
                {
                    Console.WriteLine("WARN: Channel processing took longer than 250ms!");
                }
                startTime = DateTime.Now;

                // Request object model updates
                if (IsIdle || DateTime.Now - _lastQueryTime > TimeSpan.FromMilliseconds(Settings.MaxUpdateDelay))
                {
                    DataTransfer.WriteGetObjectModel(_moduleToQuery);
                    _lastQueryTime = DateTime.Now;
                }

                if (DateTime.Now - startTime > TimeSpan.FromMilliseconds(250))
                {
                    Console.WriteLine("WARN: Object model processing took longer than 250ms!");
                }
                startTime = DateTime.Now;

                // Do another full SPI transfer
                DataTransfer.PerformFullTransfer();
                if (DateTime.Now - startTime > TimeSpan.FromMilliseconds(250))
                {
                    Console.WriteLine("WARN: SPI transfer took longer than 250ms!");
                }

                // Wait a moment
                if (IsIdle)
                {
                    await Task.Delay(Settings.SpiPollDelay, Program.CancelSource.Token);
                }
            } while (!Program.CancelSource.IsCancellationRequested);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Perform communication with the RepRapFirmware controller
        /// </summary>
        /// <returns>Asynchronous task</returns>
        public static async Task Run()
        {
            if (Settings.NoSpiTask)
            {
                await Task.Delay(-1, Program.CancellationToken);

                return;
            }

            do
            {
                using (await _firmwareActionLock.LockAsync(Program.CancellationToken))
                {
                    // Check if an emergency stop has been requested
                    if (_firmwareHaltRequest != null && DataTransfer.WriteEmergencyStop())
                    {
                        _logger.Warn("Emergency stop");
                        DataTransfer.PerformFullTransfer();

                        _firmwareHaltRequest.SetResult(null);
                        _firmwareHaltRequest = null;
                    }

                    // Check if a firmware reset has been requested
                    if (_firmwareResetRequest != null && DataTransfer.WriteReset())
                    {
                        _logger.Warn("Resetting controller");
                        DataTransfer.PerformFullTransfer();

                        _firmwareResetRequest.SetResult(null);
                        _firmwareResetRequest = null;

                        if (!Settings.NoTerminateOnReset)
                        {
                            // Wait for the program to terminate and don't perform any extra transfers
                            await Task.Delay(-1, Program.CancellationToken);
                        }
                    }
                }

                // Check if a firmware update is supposed to be performed
                using (await _firmwareUpdateLock.LockAsync(Program.CancellationToken))
                {
                    if (_iapStream != null && _firmwareStream != null)
                    {
                        await Invalidate("Firmware update imminent");

                        try
                        {
                            await PerformFirmwareUpdate();

                            _firmwareUpdateRequest?.SetResult(null);
                            _firmwareUpdateRequest = null;
                        }
                        catch (Exception e)
                        {
                            _firmwareUpdateRequest?.SetException(e);
                            _firmwareUpdateRequest = null;

                            if (e is OperationCanceledException)
                            {
                                _logger.Debug(e, "Firmware update cancelled");
                            }
                            else
                            {
                                throw;
                            }
                        }

                        _iapStream = _firmwareStream = null;
                    }
                }

                // Invalidate data if a controller reset has been performed
                if (DataTransfer.HadReset())
                {
                    await Invalidate("Controller has been reset");
                }

                // Check for changes of the print status.
                // The packet providing file info has be sent first because it includes a time_t value that must reside on a 64-bit boundary!
                if (_printStarted)
                {
                    using (await Model.Provider.AccessReadOnlyAsync())
                    {
                        _printStarted = !DataTransfer.WritePrintStarted(Model.Provider.Get.Job.File);
                    }
                }
                else
                {
                    using (await _printStopppedReasonLock.LockAsync(Program.CancellationToken))
                    {
                        if (_printStoppedReason != null && DataTransfer.WritePrintStopped(_printStoppedReason.Value))
                        {
                            _printStoppedReason = null;
                        }
                    }
                }

                // Deal with heightmap requests
                using (await _heightmapLock.LockAsync(Program.CancellationToken))
                {
                    // Check if the heightmap is supposed to be set
                    if (_setHeightmapRequest != null && DataTransfer.WriteHeightMap(_heightmapToSet))
                    {
                        _setHeightmapRequest.SetResult(null);
                        _setHeightmapRequest = null;
                    }

                    // Check if the heightmap is requested
                    if (_getHeightmapRequest != null && !_isHeightmapRequested)
                    {
                        _isHeightmapRequested = DataTransfer.WriteGetHeightMap();
                    }
                }

                // Process incoming packets
                for (int i = 0; i < DataTransfer.PacketsToRead; i++)
                {
                    PacketHeader?packet;

                    try
                    {
                        packet = DataTransfer.ReadPacket();
                        if (packet == null)
                        {
                            _logger.Error("Read invalid packet");
                            break;
                        }
                        await ProcessPacket(packet.Value);
                    }
                    catch (ArgumentOutOfRangeException)
                    {
                        DataTransfer.DumpMalformedPacket();
                        throw;
                    }
                }
                _bytesReserved = 0;

                // Process pending codes, macro files and requests for resource locks/unlocks as well as flush requests
                await _channels.Run();

                // Request object model updates
                if (DateTime.Now - _lastQueryTime > TimeSpan.FromMilliseconds(Settings.ModelUpdateInterval))
                {
                    if (DataTransfer.ProtocolVersion == 1)
                    {
                        using (await Model.Provider.AccessReadOnlyAsync())
                        {
                            if (Model.Provider.Get.Boards.Count == 0 && DataTransfer.WriteGetLegacyConfigResponse())
                            {
                                // We no longer support regular status responses except to obtain the board name for updating the firmware
                                _lastQueryTime = DateTime.Now;
                            }
                        }
                    }
                    else
                    {
                        bool objectModelQueried = false;
                        lock (_pendingModelQueries)
                        {
                            // Query specific object model values on demand
                            if (_pendingModelQueries.TryPeek(out Tuple <string, string> modelQuery) &&
                                DataTransfer.WriteGetObjectModel(modelQuery.Item1, modelQuery.Item2))
                            {
                                objectModelQueried = true;
                                _pendingModelQueries.Dequeue();
                            }
                        }

                        if (!objectModelQueried && DataTransfer.WriteGetObjectModel(string.Empty, "d99fn"))
                        {
                            // Query live values in regular intervals
                            _lastQueryTime = DateTime.Now;
                        }
                    }
                }

                // Ask for expressions to be evaluated
                lock (_evaluateExpressionRequests)
                {
                    int numEvaluationsSent = 0;
                    foreach (EvaluateExpressionRequest request in _evaluateExpressionRequests)
                    {
                        if (!request.Written)
                        {
                            if (DataTransfer.WriteEvaluateExpression(request.Channel, request.Expression))
                            {
                                request.Written = true;

                                numEvaluationsSent++;
                                if (numEvaluationsSent >= Consts.MaxEvaluationRequestsPerTransfer)
                                {
                                    break;
                                }
                            }
                        }
                    }
                }

                // Send pending messages
                lock (_messagesToSend)
                {
                    while (_messagesToSend.TryPeek(out Tuple <MessageTypeFlags, string> message))
                    {
                        if (DataTransfer.WriteMessage(message.Item1, message.Item2))
                        {
                            _messagesToSend.Dequeue();
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                // Update filament assignment per extruder drive. This must happen when config.g has finished or M701 is requested
                if (!Macro.RunningConfig || _assignFilaments)
                {
                    lock (_extruderFilamentUpdates)
                    {
                        while (_extruderFilamentUpdates.TryPeek(out Tuple <int, string> filamentMapping))
                        {
                            if (DataTransfer.WriteAssignFilament(filamentMapping.Item1, filamentMapping.Item2))
                            {
                                _extruderFilamentUpdates.Dequeue();
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    _assignFilaments = false;
                }

                // Do another full SPI transfe
                DataTransfer.PerformFullTransfer();
                _channels.ResetBlockedChannels();

                // Wait a moment unless instructions are being sent rapidly to RRF
                bool skipDelay;
                using (await Model.Provider.AccessReadOnlyAsync())
                {
                    skipDelay = Model.Provider.Get.State.Status == MachineStatus.Updating;
                }
                if (!skipDelay)
                {
                    await Task.Delay(Settings.SpiPollDelay, Program.CancellationToken);
                }
            }while (true);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Perform the firmware update internally
        /// </summary>
        /// <returns>Asynchronous task</returns>
        private static async Task PerformFirmwareUpdate()
        {
            using (await Model.Provider.AccessReadWriteAsync())
            {
                Model.Provider.Get.State.Status = MachineStatus.Updating;
            }
            DataTransfer.Updating = true;

            try
            {
                // Get the CRC16 checksum of the firmware binary
                byte[] firmwareBlob = new byte[_firmwareStream.Length];
                await _firmwareStream.ReadAsync(firmwareBlob, 0, (int)_firmwareStream.Length);

                ushort crc16 = CRC16.Calculate(firmwareBlob);

                // Send the IAP binary to the firmware
                _logger.Info("Flashing IAP binary");
                bool dataSent;
                do
                {
                    dataSent = DataTransfer.WriteIapSegment(_iapStream);
                    DataTransfer.PerformFullTransfer();
                    if (_logger.IsDebugEnabled)
                    {
                        Console.Write('.');
                    }
                }while (dataSent);
                if (_logger.IsDebugEnabled)
                {
                    Console.WriteLine();
                }

                // Start the IAP binary
                DataTransfer.StartIap();

                // Send the firmware binary to the IAP program
                int numRetries = 0;
                do
                {
                    if (numRetries != 0)
                    {
                        _logger.Error("Firmware checksum verification failed");
                    }

                    _logger.Info("Flashing RepRapFirmware");
                    _firmwareStream.Seek(0, SeekOrigin.Begin);
                    while (DataTransfer.FlashFirmwareSegment(_firmwareStream))
                    {
                        if (_logger.IsDebugEnabled)
                        {
                            Console.Write('.');
                        }
                    }
                    if (_logger.IsDebugEnabled)
                    {
                        Console.WriteLine();
                    }

                    _logger.Info("Verifying checksum");
                }while (++numRetries < 3 && !DataTransfer.VerifyFirmwareChecksum(_firmwareStream.Length, crc16));

                if (numRetries == 3)
                {
                    // Failed to flash the firmware
                    await Logger.LogOutput(MessageType.Error, "Could not flash the firmware binary after 3 attempts. Please install it manually via bossac.");

                    Program.CancelSource.Cancel();
                }
                else
                {
                    // Wait for the IAP binary to restart the controller
                    await DataTransfer.WaitForIapReset();

                    _logger.Info("Firmware update successful");
                }
            }
            finally
            {
                DataTransfer.Updating = false;
                // Machine state is reset when the next status response is processed
            }
        }
Exemplo n.º 7
0
 /// <summary>
 /// Initialize physical transfer and perform initial data transfer.
 /// This is only called once on initialization
 /// </summary>
 /// <returns>Asynchronous task</returns>
 public static Task <bool> Connect() => DataTransfer.PerformFullTransfer(false);