Exemplo n.º 1
0
Arquivo: sol.c Projeto: Mole23/freewpc
/**
 * Pulse a solenoid with a specific duty/time.
 */
void
sol_req_start_specific (U8 sol, U8 mask, U8 time)
{
	dbprintf ("Starting pulse %d now.\n", sol);

	/* If the timer is nonzero, another request is already running.
	This shouldn't happen.  The solenoid code takes care not to start
	a request when something is already active.  The test mode code
	calls this directly and bypasses those checks, but it enforces a delay
	between pulses so it shouldn't occur. */
	if (sol_pulse_timer != 0)
	{
		nonfatal (ERR_SOL_REQUEST);
		return;
	}

	req_reg_write = sol_get_write_reg (sol);
	if (req_reg_write == (IOPTR)0)
		return;

	req_reg_read = sol_get_read_reg (sol);
	req_bit = sol_get_bit (sol);
	sol_pulse_duty = mask;
	req_inverted = sol_inverted (sol) ? 0xFF : 0x00;

	/* This must be last, as it triggers the IRQ code */
	sol_pulse_timer = time / 4;
}
Exemplo n.º 2
0
void score_multiplier_set (U8 m)
{
	if (m == 0)
	{
		nonfatal (ERR_ZERO_SCORE_MULT);
		m = 1;
	}
	global_score_multiplier = m;
}
Exemplo n.º 3
0
/** Requests that a device 'unlock' a ball. */
void device_unlock_ball (device_t *dev)
{
	if (dev->max_count > 0)
	{
		dbprintf ("Unlock ball in devno %d\n", dev->devno);
		device_disable_lock (dev);
		device_request_kick (dev);
	}
	else
		nonfatal (ERR_UNLOCK_EMPTY_DEVICE);
}
Exemplo n.º 4
0
/** Adds to the current score.  The input score is given as a BCD-string. */
static void score_award (const bcd_t *s)
{
	if (in_tilt)
		return;
	if (!in_game)
	{
		nonfatal (ERR_SCORE_NOT_IN_GAME);
		return;
	}

	score_add (current_score, s);
	score_update_request ();
	replay_check_current ();
}
Exemplo n.º 5
0
/** Like score_add_byte, but modifies the current player's score.
 * This function is analogous to score_award(). */
void score_award_compact (U8 offset, bcd_t val)
{
	U8 mult;

	if (in_tilt)
		return;
	if (!in_live_game)
	{
		nonfatal (ERR_SCORE_NOT_IN_GAME);
		return;
	}

	mult = global_score_multiplier;
	do {
		score_add_byte (current_score, offset, val);
		mult--;
	} while (mult != 0);
	score_update_request ();
	replay_check_current ();
}
Exemplo n.º 6
0
/** Remove a virtual ball from the device, not seen by any switches. */
void device_remove_virtual (device_t *dev)
{
	if (dev->virtual_count > 0)
	{
		/* Update counts.  We avoid calling device_sw_handler here
		because there is no possibility for any error or need for retry.
		The change is instantaneous.  The device state remains idle. */
		dev->virtual_count--;
		dev->actual_count--;
		dev->previous_count--;

		/* Throw the usual events on releases */
		device_update_globals ();
		device_call_op (dev, kick_success);
	}
	else
	{
		nonfatal (ERR_VIRTUAL_DEVICE_COUNT);
	}
}
Exemplo n.º 7
0
static void
hexify_file (char *filename, char *target)
{
  bfd *abfd;
  char *dot;
  char *hex_file;

  if (get_file_size (filename) < 1)
    return;

  abfd = bfd_openr (filename, target);
  if (abfd == NULL)
    {
      nonfatal (filename);
      return;
    }

  if (bfd_check_format (abfd, bfd_object))
    {
      if (verbose)
        printf ("\n");

      /* strip extension from filename if present */
      dot = strrchr (filename, '.');
      if (dot)
        dot[0] = '\0';

      /* create a new name with .hex extension */
      hex_file = malloc (strlen (filename) + strlen (".hex") + 1);
      sprintf (hex_file, "%s%s", filename, ".hex");

      exit_status = write_hex_file (hex_file, abfd);

      if (verbose)
        printf ("\n");

      free (hex_file);
    }

  bfd_close (abfd);
}
Exemplo n.º 8
0
void Args::getArgs( vector<string> vargs ) {
	/*
	Read command line and update args.
	*/
	vector<string>::const_iterator p; 
	bool placed = false; /* set when placement indicator met */
	bool filein = false; /* set when file met */

	for ( p=vargs.begin(); p != vargs.end(); p++ ) {

		if ( *p == OPT_HELP ) {

			usage();
		}
		else if ( *p == OPT_OUTFILE ) {

			p++;
			if ( p == vargs.end() ) 
				fatal( "missing argument" );

			setFileOut( *p );	
		}
		else if ( *p == OPT_BMP ) { out_format = K_BMP; }
		else if ( *p == OPT_JPG ) { out_format = K_JPG; }
		else if ( *p == OPT_PNG ) { out_format = K_PNG; }
		else if ( *p == OPT_COST1 ) { cost_fx = C1; }
		else if ( *p == OPT_COST2 ) { cost_fx = C2; }
		else if ( *p == OPT_IPLACE0 ) { k_pin = PI0; }
		else if ( *p == OPT_IPLACE1 ) { k_pin = PI1; }
		else if ( *p == OPT_RANDPL ) { k_ran = true; }
		else if ( *p == OPT_REFIN ) { 

			p++;
			if ( p == vargs.end() ) 
				fatal( "missing argument" );
			k_ref = true; 
			nb_refinements = (int) atoi( (*p).c_str() );
			nb_refinements *= REF_ITERS;

		}
		else if ( *p == OPT_COSTRED ) {

			p++;
			if ( p == vargs.end() ) 
				fatal( "missing argument" );

			cost_reduction = (int) atoi( (*p).c_str() );
			if ( ( cost_reduction < 10 ) || ( cost_reduction > 30 ) )
				nonfatal( "warning: cost reduction may be too large or too small." );
		}
		else if ( *p == OPT_RATIO ) {

			p++;
			if ( p == vargs.end() ) 
				fatal( "missing argument" );

			ratio = (float) atof( (*p).c_str() );
			if ( ( ratio < 0 ) || ( ratio > 1 ) )
				nonfatal( "warning: cost reduction may be too large or too small." );
		}
		else if ( *p == OPT_PLACE_RANDOM ) {

			if ( placed )
				fatal("syntax error, you should not specify several placement functions.");
			placed = true;
			placement = P1;
		}
		else if ( *p == OPT_PLACE_ENTMAT ) {

			if ( placed )
				fatal("syntax error, you should not specify several placement functions.");
			placed = true;
			placement = P2;
		}
		else if ( *p == OPT_PLACE_SUBMAT ) {

			if ( placed )
				fatal("syntax error, you should not specify several placement functions.");
			placed = true;
			placement = P3;
		}
		else if ( *p == OPT_MIRROR ) { k_mir = true; }
		else if ( *p == OPT_ROTATIO ) { k_rot = true; }
		else if ( *p == OPT_VERBOSE ) { k_ver = true; }
		else if ( *p == OPT_XCOEFSIZ ) {

			p++;
			if ( p == vargs.end() ) 
				fatal( "missing argument" );
			xcoef = (int) atoi( (*p).c_str() );
		}
		else if ( *p == OPT_YCOEFSIZ ) {

			p++;
			if ( p == vargs.end() ) 
				fatal( "missing argument" );
			ycoef = (int) atoi( (*p).c_str() );
		}
		else {
			if ( filein )
				fatal("unknown argument.");
			setFileIn( *p );
			filein = true;
		}
	}

	if ( !filein ) {

		nonfatal("please specify an input file.");
		usage();
	}

	placement0 = placement;

}
Exemplo n.º 9
0
/** The core function for handling a device.
 * This function is invoked (within its own task context) whenever
 * a switch closure occurs on a device, or when a request is made to
 * kick a ball from a device.
 * The update task will get killed and restarted anytime a switch
 * closure occurs on the device, so it may be interrupted, but only
 * while it is sleeping.
 */
void device_update (void)
{
	device_t *dev = &device_table[device_getgid () - DEVICE_GID_BASE];

wait_and_recount:
	/* We are really interested in the total count of the
	 * device, not which switches contributed to it.
	 * Since multiple switch transitions occur as a ball
	 * "slides through", don't act on a transition right
	 * away.  Instead, wait awhile until no further transitions
	 * occur, so that the count is stable.  If another closure on
	 * this device happens while we sleep here, this task will
	 * be killed and restarted.
	 */
	task_sleep (dev->props->settle_delay);

start_update:
	task_sleep (TIME_50MS);

	/* The device is probably stable now.  Poll all of the
	 * switches and recount */
	device_recount (dev);

	device_update_globals ();
	device_debug (dev);

	dbprintf ("Updating device %s\n", dev->props->name);

	/*****************************************
	 * Handle "count" changes
	 *****************************************/
	if (dev->state == DEV_STATE_IDLE)
	{
		/* Device is idle */
		if (dev->actual_count == dev->previous_count)
		{
			/* Switch closures were detected but in the end, after becoming
			 * stable, the count did not change.  This is OK, perhaps
			 * there is some vibration...
			 * Also, when transitioning back to idle after a device kick,
			 * we repoll the switches one extra time and if all is well,
			 * we'll end up here.
			 */
		}
		else if (dev->actual_count < dev->previous_count)
		{
			/* Also unusual in that a ball came out of the device without
			 * explicitly kicking it.  (Although this can happen in test mode.)
			 * Note that the number of balls in play went up */
			if (in_game)
			{
				device_call_op (dev, surprise_release);
				device_add_live ();
			}
		}
		else if (dev->actual_count > dev->previous_count)
		{
			/* More typical : when idle, the count should only go up.
			 * Treat this as an enter event (or multiple events, if the
			 * count goes up by more than 1). */
			U8 enter_count = dev->actual_count - dev->previous_count;
			if (!trough_dev_p (dev))
				set_valid_playfield ();
			while (enter_count > 0)
			{
				callset_invoke (any_device_enter);
				device_call_op (dev, enter);
				enter_count--;
			}
		}
	}
	else if ((dev->state == DEV_STATE_RELEASING) && (dev->kicks_needed > 0))
	{
		/* Device is in the middle of a release cycle.
		 * See if the count changed. */
		if (unlikely (dev->actual_count >= dev->previous_count))
		{
			/* After attempting a release, the count did not go down ... the kick
			 * probably failed, and we should retry up to a point.  Since dev->state
			 * is unchanged below, the kick attempt will get reinvoked. */

			/* Note: during multiball, it is possible for a second ball to enter
			the device immediately after the kick.  The kick didn't
			really fail, but there's no way to tell the difference. */

			dev->kick_errors++;
			dbprintf ("Kick error %d\n", dev->kick_errors);
			device_call_op (dev, kick_failure);

			if (dev->kick_errors == (trough_dev_p (dev) ? 20 : 7))
			{
				/* OK, we tried too many times and still no ball came out.
				 * Cancel all kick requests for this device unless it is
				 * the trough */
				nonfatal (ERR_FAILED_KICK);
				dev->kicks_needed = 0;
				dev->state = DEV_STATE_IDLE;
			}
			else
			{
				/* Wait awhile before trying again.  The more we fail, the longer
				the delay in between tries. */
				if (dev->kick_errors <= 3)
					task_sleep_sec (1);
				else
					task_sleep_sec (5);
			}
		}
		else if (dev->actual_count < dev->previous_count)
		{
			/* The count decreased as expected.
			 * As we only kick 1 ball at a time, then really it
			 * only should have gone down by 1, but the logic
			 * should work even if more than 1 ball is ejected. */
			U8 kicked_balls = dev->previous_count - dev->actual_count;

			/* If too many balls were kicked, throw an error.
			Only process as many as were requested. */
			if (kicked_balls > dev->kicks_needed)
			{
				nonfatal (ERR_KICK_TOO_MANY); /* akin to ERR_IDLE_BALL_LOST */
				kicked_balls = dev->kicks_needed;
			}

			/* Throw a kick success event for each ball that was kicked */
			while (kicked_balls > 0)
			{
				device_call_op (dev, kick_success);
				dev->kicks_needed--;
				kicked_balls--;
			}

			/* Go back to idle state.  If there are more kicks left, we will
			switch back to DEV_STATE_RELEASING again later.  The point is not to
			stay in DEV_STATE_RELEASING when we have not actually kicked the ball;
			if the request is held up for some reason, we want switch closures to
			be processed correctly. */
			dev->state = DEV_STATE_IDLE;
		}
	}

	/*****************************************
	 * Handle global count changes
	 *****************************************/
	device_update_globals ();

	/************************************************
	 * Handle counts larger than the device supports
	 ************************************************/
	if (dev->kicks_needed == 0 && dev->actual_count > dev->max_count)
	{
		/* When there are more balls in the device than we normally want
		to keep here, we must kick one of them out.  If multiple kicks
		are needed, this check will occur again in the future. */
		dev->kicks_needed++;
		dev->kick_errors = 0;
		/* TODO - device_request_kick (dev); would be more appropriate,
		 * but that doesn't work when called from device context due
		 * to live balls getting bumped */
	}

	/************************************************
	 * Handle kicking out balls
	 ************************************************/
	if (dev->kicks_needed > 0)
	{
		if (dev->actual_count == 0)
		{
			/* Container has fewer balls in it than we
			 * would like */
			dbprintf ("Can't kick when no balls available!\n");
			dev->kicks_needed = 0;
		}
		else if (kickout_locked_p () && !trough_dev_p (dev))
		{
			/* Container ready to kick, but 1 or more
			 * locks are held so we must wait. */
			goto start_update;
		}
		else if (!device_call_boolean_op (dev, kick_request))
		{
			/* Inform other modules that a kick was requested.
			These handlers can return FALSE to delay (but not
			cancel) the kick. */
			goto start_update;
		}
			/* TODO - if multiple devices want to kick at the same time,
			 * they should be staggered a bit.  Another case should be
			 * added here. */
		else
		{
			/* The container is ready to kick */

			/* Mark state as releasing if still idle */
			if (dev->state == DEV_STATE_IDLE)
				dev->state = DEV_STATE_RELEASING;

			/* TODO - keep track of all pending kick attempts.  Use a
			bit variable per device.  If other devices are in the
			process of kicking, wait */

			/* Generate events that a kick attempt is coming */
			callset_invoke (any_kick_attempt);
			device_call_op (dev, kick_attempt);

			/* Pulse the solenoid. */
			sol_request (dev->props->sol);

			/* In timed games, a device kick will pause the game timer.
			 * TODO : this should be a global event that other modules
			 * can catch as well.  Deal with this like we do slowtimers. */
			timed_game_pause (TIME_1S);

			/* We don't know if the kick was successful or not yet, so wait
			and see what happens. */
			goto wait_and_recount;
		}
	}

	/* Just before exiting this task, poll the switches one more time,
	and see if something has changed during the update.  It is important
	that no task context switches take place here, otherwise there would
	be a race condition where a switch closure gets missed. */
	device_recount (dev);
	if (dev->actual_count != dev->previous_count)
		goto start_update;

	task_exit ();
}