const Error *Amp::UpdateEvents( uint16 stat, uint32 events, uint16 inputs )
{
   cml.Debug( "Amp %d status 0x%08x 0x%04x 0x%04x\n", GetNodeID(), events, stat, inputs );
   uint32 mask = 0;

   if(  stat & DRIVESTAT_SPACK    ) mask |= AMPEVENT_SPACK;
   if(  stat & DRIVESTAT_MOVEDONE ) mask |= AMPEVENT_MOVEDONE;
   if( ~stat & DRIVESTAT_TRJ      ) mask |= AMPEVENT_TRJDONE;
   if( ~stat & DRIVESTAT_QSTOP    ) mask |= AMPEVENT_QUICKSTOP;
   if(  stat & DRIVESTAT_ABORT    ) mask |= AMPEVENT_ABORT;
   if(  stat & DRIVESTAT_HOMECAP  ) mask |= AMPEVENT_HOME_CAPTURE;

   if( events & ERROR_EVENTS      ) mask |= AMPEVENT_ERROR;
   if( events & ESTAT_FAULT       ) mask |= AMPEVENT_FAULT;
   if( events & ESTAT_TRK_WARN    ) mask |= AMPEVENT_POSWARN;
   if( events & ESTAT_TRK_WIN     ) mask |= AMPEVENT_POSWIN;
   if( events & ESTAT_VEL_WIN     ) mask |= AMPEVENT_VELWIN;
   if( events & ESTAT_PWM_DISABLE ) mask |= AMPEVENT_DISABLED;
   if( events & ESTAT_POSLIM      ) mask |= AMPEVENT_POSLIM;    
   if( events & ESTAT_NEGLIM      ) mask |= AMPEVENT_NEGLIM;
   if( events & ESTAT_SOFTLIM_POS ) mask |= AMPEVENT_SOFTLIM_POS;
   if( events & ESTAT_SOFTLIM_NEG ) mask |= AMPEVENT_SOFTLIM_NEG;
   if( events & ESTAT_SOFT_DISABLE) mask |= AMPEVENT_SOFTDISABLE;
   if( events & ESTAT_PHASE_INIT  ) mask |= AMPEVENT_PHASE_INIT;

   // On new move aborts, do some clean up.
   if( mask & AMPEVENT_ABORT )
   {
      uint32 old = eventMap.getMask();

      if( !(old & AMPEVENT_ABORT) )
         MoveAborted();
   }

   // Do the same thing if the amplifier is disabled while 
   // a trajectory was in progress
   if( mask & AMPEVENT_DISABLED )
   {
      uint32 old = eventMap.getMask();

      if( !(old & AMPEVENT_TRJDONE) )
         MoveAborted();
   }

   // Change the bits that this function is responsible for.
   // for now, that's everything but the node guarding 
   // and PVT buffer empty bits.
   eventMap.changeBits( ~(AMPEVENT_PVT_EMPTY|AMPEVENT_NODEGUARD), mask );

   // Update the input pins state
   inputStateMap.setMask( (uint32)inputs );

   return 0;
}
Exemple #2
0
// This is called by the interrupt service routine to execute steps.
// It returns true if it needs to be called again on the DDA of the new current move, otherwise false.
// This must be as fast as possible, because it determines the maximum movement speed.
bool DDA::Step()
{
	bool repeat;
	uint32_t numReps = 0;
	do
	{
		// Keep this loop as fast as possible, in the case that there are no endstops to check!
		// Check endstop switches and Z probe if asked
		if (endStopsToCheck != 0)											// if any homing switches or the Z probe is enabled in this move
		{
			if ((endStopsToCheck & ZProbeActive) != 0)						// if the Z probe is enabled in this move
			{
				// Check whether the Z probe has been triggered. On a delta at least, this must be done separately from endstop checks,
				// because we have both a high endstop and a Z probe, and the Z motor is not the same thing as the Z axis.
				switch (reprap.GetPlatform()->GetZProbeResult())
				{
				case EndStopHit::lowHit:
					MoveAborted();											// set the state to completed and recalculate the endpoints
					reprap.GetMove()->ZProbeTriggered(this);
					break;

				case EndStopHit::lowNear:
					ReduceHomingSpeed();
					break;

				default:
					break;
				}
			}

			for (size_t drive = 0; drive < AXES; ++drive)
			{
				if ((endStopsToCheck & (1 << drive)) != 0)
				{
					switch(reprap.GetPlatform()->Stopped(drive))
					{
					case EndStopHit::lowHit:
						endStopsToCheck &= ~(1 << drive);					// clear this check so that we can check for more
						if (endStopsToCheck == 0 || reprap.GetMove()->IsCoreXYAxis(drive))	// if no more endstops to check, or this axis uses shared motors
						{
							MoveAborted();
						}
						else
						{
							StopDrive(drive);
						}
						reprap.GetMove()->HitLowStop(drive, this);
						break;

					case EndStopHit::highHit:
						endStopsToCheck &= ~(1 << drive);					// clear this check so that we can check for more
						if (endStopsToCheck == 0 || reprap.GetMove()->IsCoreXYAxis(drive))	// if no more endstops to check, or this axis uses shared motors
						{
							MoveAborted();
						}
						else
						{
							StopDrive(drive);
						}
						reprap.GetMove()->HitHighStop(drive, this);
						break;

					case EndStopHit::lowNear:
						// Only reduce homing speed if there are no more axes to be homed.
						// This allows us to home X and Y simultaneously.
						if (endStopsToCheck == (1 << drive))
						{
							ReduceHomingSpeed();
						}
						break;

					default:
						break;
					}
				}
			}

			if (state == completed)		// we may have completed the move due to triggering an endstop switch or Z probe
			{
				break;
			}
		}

		// Generate any steps that are now due, overdue, or will be due very shortly
		DriveMovement* dm = firstDM;
		if (dm == nullptr)				// I don't think this should happen, but best to be sure
		{
			state = completed;
			break;
		}

		const uint32_t elapsedTime = (Platform::GetInterruptClocks() - moveStartTime) + minInterruptInterval;
		while (elapsedTime >= dm->nextStepTime)		// if the next step is due
		{
			size_t drive = dm->drive;
			++numReps;
			reprap.GetPlatform()->StepHigh(drive);
			firstDM = dm->nextDM;
			bool moreSteps = (isDeltaMovement && drive < AXES)
								? dm->CalcNextStepTimeDelta(*this, drive, true)
								: dm->CalcNextStepTimeCartesian(*this, drive, true);
			if (moreSteps)
			{
				InsertDM(dm);
			}
			else if (firstDM == nullptr)
			{
				state = completed;
				reprap.GetPlatform()->StepLow(drive);
				goto quit;			// yukky multi-level break, but saves us another test in this time-critical code
			}
			reprap.GetPlatform()->StepLow(drive);
			dm = firstDM;

//uint32_t t3 = Platform::GetInterruptClocks() - t2;
//if (t3 > maxCalcTime) maxCalcTime = t3;
//if (t3 < minCalcTime) minCalcTime = t3;
		}

		repeat = reprap.GetPlatform()->ScheduleInterrupt(firstDM->nextStepTime + moveStartTime);
	} while (repeat);

quit:
	if (numReps > maxReps)
	{
		maxReps = numReps;
	}

	if (state == completed)
	{
		uint32_t finishTime = moveStartTime + clocksNeeded;		// calculate how long this move should take
		Move *move = reprap.GetMove();
		move->CurrentMoveCompleted();							// tell Move that the current move is complete
		return move->StartNextMove(finishTime);					// schedule the next move
	}
	return false;
}