/// <summary> /// 同期キャラクタ検出を行う。キャラクタ検出を行ったら、その完了ポイントへの、インデックスを返す。 /// 同期キャラクタは、読み出しバッファに収納される。 /// キャラクタ検出できなければ、インデックスはバッファ長と同じ。 /// </summary> int synchronation(int[] waveform, int offset) { byte data = 0; int cnt = 16; int index = offset; for (; index < waveform.Length; index+=4) { // char sync if (waveform[index] > 0) data |= 0x80; if (data == _syncCharactor) { System.Diagnostics.Debug.WriteLine(String.Format("Sync: 0x{0:X}.", data)); _recoveryData = 0; _recoveryBitPos = 0; _state = RecoveryState.DATA_EDGE; return (index + 4); } // nosignal cnt--; if (cnt < 0) { _state = RecoveryState.SYNC_EDGE; return index; } data >>= 1; } return index; }
/// <summary> /// データをリカバリします。これを読み出したあとは、HasReceivedが有効ならば、データバッファを読み出してください。次に呼び出したとき、このバッファは破壊されています。 /// </summary> /// <param name="waveform"></param> public void Recovery(int[] waveform) { int index = _indexOffset; while (index < waveform.Length) { switch (_state) { case RecoveryState.SYNC_EDGE: index = syncEdgeDetection(waveform, index); break; case RecoveryState.SYNC: index = synchronation(waveform, index); break; case RecoveryState.DATA_EDGE: index = dataEdgeDetection(waveform, index); break; case RecoveryState.DATA: index = dataRecovery(waveform, index); break; default: _state = RecoveryState.SYNC_EDGE; return; } } _indexOffset = index - waveform.Length; }
/// <summary> /// エッジ検出。 /// </summary> int syncEdgeDetection(int[] waveform, int offset) { int index = offset; for (; index < waveform.Length; index++) { // edge detection if (waveform[index] > 0) { _state = RecoveryState.SYNC; return (index + 1 + 4); } } return index; }
/// <summary> /// データ再生を行う。 /// </summary> int dataRecovery(int[] waveform, int offset) { int index = offset; for (; index < waveform.Length; index += 4) { // char sync if (waveform[index] > 0) _recoveryData |= 0x80; if (_recoveryBitPos >= 7) { System.Diagnostics.Debug.WriteLine(String.Format("Receiving: 0x{0:X}.", _recoveryData)); _rcvBuf.Add(_recoveryData); _recoveryData = 0; _recoveryBitPos = 0; _state = RecoveryState.DATA_EDGE; return (index + 4); } _recoveryBitPos++; _recoveryData >>= 1; } return index; }
int dataEdgeDetection(int[] waveform, int offset) { int index = offset; int cnt = 4; for (; index < waveform.Length; index++) { // edge detection if (waveform[index] > 0) { _recoveryData = 0; _state = RecoveryState.DATA; return (index + 1 + 4); } cnt--; if (cnt < 0) { _queue.Enqueue(_rcvBuf.ToArray()); _rcvBuf.Clear(); _state = RecoveryState.SYNC_EDGE; return index; } } return index; }
/// <summary> /// 強制的に同期状態に遷移します /// </summary> public void Resynchronize() { _rcvBuf.Clear(); _state = RecoveryState.SYNC_EDGE; }
public override string ReadLine() { // Send any commands that are queue before moving on to the internal stream. string nextCommand = queuedCommands.ReadLine(); if (nextCommand != null) { return nextCommand; } switch (recoveryState) { // heat the extrude to remove it from the part case RecoveryState.RemoveHeating: // TODO: make sure we heat up all the extruders that we need to (all that are used) queuedCommands.Add("G21; set units to millimeters"); queuedCommands.Add("M107; fan off"); queuedCommands.Add("T0; set the active extruder to 0"); queuedCommands.Add("G90; use absolute coordinates"); queuedCommands.Add("G92 E0; reset the expected extruder position"); queuedCommands.Add("M82; use absolute distance for extrusion"); queuedCommands.Add("M109 S{0}".FormatWith(ActiveSliceSettings.Instance.Helpers.ExtruderTemperature(0))); recoveryState = RecoveryState.Raising; return ""; // remove it from the part case RecoveryState.Raising: queuedCommands.Add("M114 ; get current position"); queuedCommands.Add("G91 ; move relative"); queuedCommands.Add("G1 Z10 F{0}".FormatWith(MovementControls.ZSpeed)); queuedCommands.Add("G90 ; move absolute"); recoveryState = RecoveryState.Homing; return ""; // if top homing, home the extruder case RecoveryState.Homing: if (ActiveSliceSettings.Instance.GetValue<bool>(SettingsKey.z_homes_to_max)) { queuedCommands.Add("G28"); } else { // home x queuedCommands.Add("G28 X0"); // home y queuedCommands.Add("G28 Y0"); // move to the place we can home z from Vector2 recoveryPositionXy = ActiveSliceSettings.Instance.GetValue<Vector2>(SettingsKey.recover_position_before_z_home); queuedCommands.Add("G1 X{0:0.###}Y{1:0.###}F{2}".FormatWith(recoveryPositionXy.x, recoveryPositionXy.y, MovementControls.XSpeed)); // home z queuedCommands.Add("G28 Z0"); } recoveryState = RecoveryState.FindingRecoveryLayer; return ""; // This is to recover printing if an out a filament occurs. // Help the user move the extruder down to just touching the part case RecoveryState.FindingRecoveryLayer: if (false) // help the user get the head to the right position { // move to above the completed print // move over a know good part of the model at the current top layer (extrude vertex from gcode) // let the user move down until they like the height // calculate that position and continue } else // we are resuming because of disconnect or reset, skip this { recoveryState = RecoveryState.SkippingGCode; goto case RecoveryState.SkippingGCode; } case RecoveryState.SkippingGCode: // run through the gcode that the device expected looking for things like temp // and skip everything else until we get to the point we left off last time int commandCount = 0; boundsOfSkippedLayers = RectangleDouble.ZeroIntersection; while (internalStream.FileStreaming.PercentComplete(internalStream.LineIndex) < percentDone) { string line = internalStream.ReadLine(); if(line == null) { break; } commandCount++; // make sure we don't parse comments if(line.Contains(";")) { line = line.Split(';')[0]; } lastDestination = GetPosition(line, lastDestination); if (commandCount > 100) { boundsOfSkippedLayers.ExpandToInclude(lastDestination.position.Xy); if (boundsOfSkippedLayers.Bottom < 10) { int a = 0; } } // check if the line is something we want to send to the printer (like a temp) if (line.StartsWith("M109") || line.StartsWith("M104") || line.StartsWith("T") || line.StartsWith("M106") || line.StartsWith("M107")) { return line; } } recoveryState = RecoveryState.PrimingAndMovingToStart; // make sure we always- pick up the last movement boundsOfSkippedLayers.ExpandToInclude(lastDestination.position.Xy); return ""; case RecoveryState.PrimingAndMovingToStart: { if (ActiveSliceSettings.Instance.GetValue("z_homes_to_max") == "0") // we are homed to the bed { // move to the height we can recover printing from Vector2 recoverPositionXy = ActiveSliceSettings.Instance.GetValue<Vector2>(SettingsKey.recover_position_before_z_home); queuedCommands.Add(CreateMovementLine(new PrinterMove(new VectorMath.Vector3(recoverPositionXy.x, recoverPositionXy.y, lastDestination.position.z), 0, MovementControls.ZSpeed))); } double extruderWidth = ActiveSliceSettings.Instance.GetValue<double>(SettingsKey.nozzle_diameter); // move to a position outside the printed bounds queuedCommands.Add(CreateMovementLine(new PrinterMove( new Vector3(boundsOfSkippedLayers.Left - extruderWidth*2, boundsOfSkippedLayers.Bottom + boundsOfSkippedLayers.Height / 2, lastDestination.position.z), 0, MovementControls.XSpeed))); // let's prime the extruder queuedCommands.Add("G1 E10 F{0}".FormatWith(MovementControls.EFeedRate(0))); // extrude 10 queuedCommands.Add("G1 E9"); // and retract a bit // move to the actual print position queuedCommands.Add(CreateMovementLine(new PrinterMove(lastDestination.position, 0, MovementControls.XSpeed))); /// reset the printer to know where the filament should be queuedCommands.Add("G92 E{0}".FormatWith(lastDestination.extrusion)); recoveryState = RecoveryState.PrintingSlow; } return ""; case RecoveryState.PrintingSlow: { string lineToSend = internalStream.ReadLine(); if (lineToSend == null) { return null; } if (!GCodeFile.IsLayerChange(lineToSend)) { // have not seen the end of this layer so keep printing slow if (LineIsMovement(lineToSend)) { PrinterMove currentMove = GetPosition(lineToSend, lastDestination); PrinterMove moveToSend = currentMove; moveToSend.feedRate = recoverFeedRate; lineToSend = CreateMovementLine(moveToSend, lastDestination); lastDestination = currentMove; return lineToSend; } return lineToSend; } } // we only fall through to here after seeing the next "; Layer:" recoveryState = RecoveryState.PrintingToEnd; return ""; case RecoveryState.PrintingToEnd: return internalStream.ReadLine(); } return null; }