コード例 #1
0
ファイル: switches.c プロジェクト: Curbfeeler/freewpc
/**
 * Process a switch that has transitioned states.  All debouncing
 * is fully completed prior to this call.
 *
 * The transition is first latched, so that polling the switch level
 * will return the new state.  At the same time, IRQ-level scanning
 * is restarted, so that further transitions can be detected.
 *
 * Second, if the transition requires scheduling, a task is started
 * to handle it.  Eligibility depends on whether or not the switch
 * is declared as an edge switch (meaning it is scheduled on both
 * types of transitions) and whether or not it is an opto (i.e.
 * do we schedule open-to-closed or closed-to-open?)
 *
 * The switch is also known not to be in the debounce queue prior to this
 * function being called.
 */
void switch_transitioned (const U8 sw)
{
	/* Latch the transition.  sw_logical is still an open/closed level.
	 * By clearing the stable/unstable bits, IRQ will begin scanning
	 * for new transitions at this point. */
	disable_irq ();
	bit_toggle (sw_logical, sw);
	bit_off (sw_stable, sw);
	bit_off (sw_unstable, sw);
	enable_irq ();

	/* See if the transition requires scheduling.  It does if the
	   switch is declared 'edge' (it schedules when becoming active
		or inactive), otherwise only becoming active.  Because most
		switches are not edge, check for the active state first. */
	if (switch_poll_logical (sw) || bit_test (mach_edge_switches, sw))
	{
#ifdef CONFIG_BPT
		/* One extra condition : do not schedule any switches when the
		system is paused */
		if (db_paused != 0)
			return;
#endif

		/* Start a task to process the switch event.
		This task may sleep if necessary, but it should be as fast as possible
		and push long-lived operations into separate background tasks.
		It is possible for more than one instance of a task to exist for the same
		switch, if valid debounced transitions occur quickly. */
		task_pid_t tp = task_create_gid (GID_SW_HANDLER, switch_sched_task);
		task_set_arg (tp, sw);
	}
}
コード例 #2
0
ファイル: task_pth.c プロジェクト: Dave2084/freewpc
/* TODO - this function is identical to the 6809 version */
task_pid_t task_create_gid1 (task_gid_t gid, task_function_t fn)
{
	task_pid_t tp = task_find_gid (gid);
	if (tp) 
		return (tp);
	return task_create_gid (gid, fn);
}
コード例 #3
0
ファイル: deff.c プロジェクト: Mole23/freewpc
/** Starts the thread for the currently running display effect. */
static void deff_start_task (const deff_t *deff)
{
	task_pid_t tp;

	deff_debug ("deff_start_task\n");

	/* Stop whatever deff is running now */
	task_kill_gid (GID_DEFF);
	deff_stop_task ();

	/* If this deff pauses kickouts, handle that now */
	if (deff->flags & D_PAUSE)
		kickout_lock (KLOCK_DEFF);

	/* If this deff wants to show the last score, hold
	 * on to that value */
	if (deff->flags & D_SCORE)
		score_deff_set ();

	/* Create a task for the new deff */
	tp = task_create_gid (GID_DEFF, deff->fn);
	if (tp)
	{
		if (deff->page != 0xFF)
			task_set_rom_page (tp, deff->page);
		task_set_duration (tp, TASK_DURATION_INF);
	}
}
コード例 #4
0
ファイル: task_pth.c プロジェクト: Dave2084/freewpc
/* TODO - this function is identical to the 6809 version */
task_pid_t task_recreate_gid (task_gid_t gid, task_function_t fn)
{
	task_kill_gid (gid);
#ifdef PARANOID
	if (task_find_gid (gid))
		fatal (ERR_TASK_KILL_FAILED);
#endif
	return task_create_gid (gid, fn);
}
コード例 #5
0
ファイル: status.c プロジェクト: hydra/freewpc
static void status_report_check (void)
{
	if (task_find_gid (GID_STATUS_REPORT_MONITOR))
	{
		status_report_cancel_delay = TRUE;
	}
	else
		task_create_gid (GID_STATUS_REPORT_MONITOR, status_report_monitor);
}
コード例 #6
0
ファイル: loop.c プロジェクト: hydra/freewpc
static void award_loop (void)
{
	/* Start a timer to go down a level after 10 seconds */
	if (!task_find_gid (GID_LOOP_LEVEL_TIMER))
		task_create_gid (GID_LOOP_LEVEL_TIMER, loop_level_timer_task);
	
	bounded_increment (total_loops, 254);
	deff_start (DEFF_LOOP);	
}
コード例 #7
0
ファイル: rocket.c プロジェクト: SonnyJim/freewpc
CALLSET_ENTRY (rocket, dev_rocket_kick_attempt)
{
	if (in_live_game)
	{
		if (!multi_ball_play ())
			leff_start (LEFF_ROCKET);
		sound_send (SND_ROCKET_KICK_REVVING);
		task_sleep (TIME_500MS);
		task_create_gid (0, rocket_kick_sound);
	}
}
コード例 #8
0
ファイル: amode.c プロジェクト: CardonaPinball/freewpc
void amode_flipper_sound (void)
{
    if (!task_find_gid (GID_AMODE_FLIPPER_SOUND_DEBOUNCE))
    {
        task_create_gid (GID_AMODE_FLIPPER_SOUND_DEBOUNCE,
                         amode_flipper_sound_debounce_timer);
#ifdef MACHINE_AMODE_FLIPPER_SOUND_CODE
        sound_send (MACHINE_AMODE_FLIPPER_SOUND_CODE);
#endif
    }
}
コード例 #9
0
ファイル: slot.c プロジェクト: SonnyJim/freewpc
CALLSET_ENTRY (slot, dev_slot_kick_attempt)
{
	if (in_live_game)
	{
		task_sleep (TIME_200MS);
		while (kickout_locks > 0)
			task_sleep (TIME_500MS);
		/* start Slot kick -> STDM timer for combo.c */
		sound_send (SND_SLOT_KICKOUT_1);
		leff_start (LEFF_SLOT_KICKOUT);
		task_sleep (TIME_500MS);
		task_create_gid (0, slot_kick_sound);
		event_can_follow (slot_kick, outhole, TIME_1S);
	}
}
コード例 #10
0
ファイル: slot.c プロジェクト: CardonaPinball/freewpc
CALLSET_ENTRY (slot, dev_slot_kick_attempt)
{
	/* TODO Hack to hold ball due to the way shot_slot_task works */
	while (deff_get_active () == DEFF_DOOR_AWARD)
		task_sleep (TIME_500MS);

	while (kickout_locks != 0)
		task_sleep (TIME_500MS);
	
	if (in_live_game)
	{
		/* start Slot kick -> STDM timer for combo.c */
		event_can_follow (slot_kick, outhole, TIME_1S);
		sound_send (SND_SLOT_KICKOUT_1);
		leff_start (LEFF_SLOT_KICKOUT);
		task_sleep (TIME_500MS);
		task_create_gid (0, slot_kick_sound);
	}
}
コード例 #11
0
ファイル: rocket.c プロジェクト: CardonaPinball/freewpc
CALLSET_ENTRY (rocket, dev_rocket_kick_attempt)
{
	if (in_live_game)
	{
		/* Wait until the skill shot has finished */
		while (skill_shot_enabled ||
			deff_get_active () == DEFF_SKILL_SHOT_MADE ||
			task_find_gid (GID_SKILL_SWITCH_TRIGGER))
		{
			task_sleep (TIME_500MS);
		}
		if (!multi_ball_play ())
			leff_start (LEFF_ROCKET);
		sound_send (SND_ROCKET_KICK_REVVING);
		deff_start (DEFF_ROCKET);
		task_sleep (TIME_500MS);
		task_create_gid (0, rocket_kick_sound);
	}
}
コード例 #12
0
ファイル: pause.c プロジェクト: Curbfeeler/freewpc
/**
 * Handle the push button that toggles the state of mute/pause if enabled.
 */
CALLSET_ENTRY (mute_and_pause, sw_buyin_button)
{
	if (feature_config.mute_pause == NO)
	{
		return;
	}
	else if (!in_live_game)
	{
		return;
	}
	else if (task_find_gid (GID_MUTE_AND_PAUSE))
	{
		/* Stop mute/pause mode */
		mute_and_pause_stop ();
	}
	else
	{
		/* Start mute/pause mode */
		task_create_gid (GID_MUTE_AND_PAUSE, mute_and_pause_monitor);
	}
}
コード例 #13
0
ファイル: init.c プロジェクト: hydra/freewpc
/** Initialize the FreeWPC program. */
__noreturn__ void freewpc_init (void)
{
    extern __common__ void system_reset (void);

    /* Initialize the platform specifics first */
    VOIDCALL (platform_init);

    /* Reset the blanking and watchdog circuitry.
     * Eventually, the watchdog will be tickled every 1ms
     * by the IRQ; until interrupts are enabled, we will
     * have to do this periodically ourselves. */
    pinio_watchdog_reset ();

    /* Set init complete flag to false.  When everything is
     * ready, we'll change this to a 1. */
    sys_init_complete = 0;
    periodic_ok = 0;
    sys_init_pending_tasks = 0;

    /* Initialize all of the other kernel subsystems,
     * starting with the hardware-centric ones and moving on
     * to software features. */

    /* Initialize the real-time scheduler.  The periodic functions
    are scheduled at compile-time  using the 'gensched' utility. */
    VOIDCALL (tick_init);

    /* Initialize the hardware.
     * After each init call, tickle the watchdog (IRQ isn't enabled yet)
     * to prevent it from expiring and resetting the CPU.
     * We don't use a callset here because there are some ordering
     * dependencies -- some modules must be initialized before others --
     * and gencallset doesn't allow us to express those conditions.
     */
#ifdef DEBUGGER
    db_init ();
    bpt_init ();
    pinio_watchdog_reset ();
#endif
    ac_init ();
    pinio_watchdog_reset ();
    sol_init ();
    pinio_watchdog_reset ();
#ifdef CONFIG_GI
    gi_init ();
    pinio_watchdog_reset ();
#endif
    display_init ();
    pinio_watchdog_reset ();
    switch_init ();
    pinio_watchdog_reset ();
    flipper_init ();
    pinio_watchdog_reset ();
    lamp_init ();
    pinio_watchdog_reset ();
    device_init ();
    pinio_watchdog_reset ();
    free_timer_init ();
    pinio_watchdog_reset ();
    sound_init ();
    pinio_watchdog_reset ();
#if (MACHINE_PIC == 1)
    pic_init ();
    pinio_watchdog_reset ();
#endif

    /* task_init is somewhat special in that it transforms the system
     * from a single task into a multitasking one.  After this, tasks
     * can be spawned if need be.  A task is created for the current
     * thread of execution, too. */
    task_init ();
    pinio_watchdog_reset ();

#ifdef CONFIG_NATIVE
    /* Notify the simulator when the core OS is up and running. */
    sim_init ();
#endif

    /* Initialize the sound board early in a background
     * thread, since it involves polling for data back from it,
     * which may take unknown (or even infinite) time. */
    sys_init_pending_tasks++;
    task_create_gid (GID_SOUND_INIT, sound_board_init);

    /* Enable interrupts (IRQs and FIRQs).  Do this as soon as possible,
     * but not before all of the hardware modules are done. */
    enable_interrupts ();

    /* Initialize everything else.  Some of these are given explicitly
    to force a particular order, since callsets do not guarantee the
    order of invocation.  For most things the order doesn't matter. */
    deff_init ();
    leff_init ();
    test_init ();
    adj_init ();
    log_init ();
    callset_invoke (init);

    /* Check all adjustments and make sure that their checksums are valid.
    If problems are found, those adjustments will be made sane again. */
    csum_area_check_all ();

    /* Enable periodic processing. */
    periodic_ok = 1;
    task_sleep (TIME_16MS);

    /* The system is initialized from a hardware perspective.
     * Now, perform additional final initializations. */
    system_reset ();

    /* The system can run itself now, this task is done! */
    task_exit ();
}
コード例 #14
0
ファイル: music.c プロジェクト: SonnyJim/freewpc
CALLSET_ENTRY (music, slow_down_music)
{
    task_create_gid (GID_MUSIC_SPEED, slow_down_music_task);
}
コード例 #15
0
ファイル: jets.c プロジェクト: SonnyJim/freewpc
void tsm_mode_init (void)
{
	task_create_gid (GID_JETS_ACTIVE_TASK, jets_active_task);
	score_zero (tsm_mode_total);
	init_all_dollars ();
}
コード例 #16
0
ファイル: gumball.c プロジェクト: SonnyJim/freewpc
CALLSET_ENTRY (gumball, sw_far_left_trough)
{
	if (!in_test)
		task_create_gid (GID_FAR_LEFT_TROUGH_MONITOR, sw_far_left_trough_monitor);
}
コード例 #17
0
ファイル: switches.c プロジェクト: Curbfeeler/freewpc
/*
 * The entry point for processing a switch transition.  It performs
 * some of the common switch handling logic before calling all
 * event handlers.  Then it also performs some common post-processing.
 * This function runs in a separate task context for each switch that
 * needs to be processed.
 */
void switch_sched_task (void)
{
	const U8 sw = (U8)task_get_arg ();
	const switch_info_t * const swinfo = switch_lookup (sw);

	/* Ignore any switch that doesn't have a processing function.
	   This shouldn't ever happen if things are working correctly, but it
		was observed on PIC games when the PIC code is broken and reporting
		bad switch returns.  genmachine ensures that all defined switches
		have a non-null value (null_function if nothing needs to be done) */
	if (swinfo->fn == 0)
		goto cleanup;

	/* For test mode : this lets it see what was the last switch
	 * to be scheduled.  Used by the Switch Edges test. */
	sw_last_scheduled = sw;

	log_event (SEV_INFO, MOD_SWITCH, EV_SW_SCHEDULE, sw);

	/* Don't service switches marked SW_IN_GAME if we're
	 * not presently in a game */
	if ((swinfo->flags & SW_IN_GAME) && !in_game)
		goto cleanup;

	/* Don't service switches not marked SW_IN_TEST, unless we're
	 * actually in test mode */
	if (!(swinfo->flags & SW_IN_TEST) && in_test)
		goto cleanup;

	/* If the switch has an associated lamp, then flicker the lamp when
	 * the switch triggers. */
	if ((swinfo->lamp != 0) && in_live_game)
	{
		task_pid_t tp = task_create_gid (GID_SWITCH_LAMP_PULSE,
			switch_lamp_pulse);

		lamp_pulse_data_t *cdata = task_init_class_data (tp, lamp_pulse_data_t);
		cdata->swinfo = swinfo;
	}

	/* If we're in a live game and the switch declares a standard
	 * sound, then make it happen. */
	if ((swinfo->sound != 0) && in_live_game)
		sound_send (swinfo->sound);

#ifdef DEBUGGER
	if (swinfo->fn != null_function && sw < 72)
	{
		dbprintf ("SW: ");
		sprintf_far_string (names_of_switches + sw);
		dbprintf1 ();
#ifdef DEBUG_SWITCH_NUMBER
		dbprintf (" (%d) ", sw);
#endif
		dbprintf ("\n");
	}
#endif

	/* If the switch declares a processing function, call it. */
	if (swinfo->fn)
		callset_pointer_invoke (swinfo->fn);

	/* Declare this as a hardware event that affects the random number
	generator. */
	random_hw_event ();

	/* If a switch is marked SW_PLAYFIELD and we're in a game,
	 * then call the global playfield switch handler and check for
	 * valid playfield.  Also, reset the ball search timer so that
	 * it doesn't expire.
	 */
	if ((swinfo->flags & SW_PLAYFIELD) && in_game)
	{
		callset_invoke (any_pf_switch);

		/* If valid playfield was not asserted yet, then see if this
		 * switch validates it.  Most playfield switches do this right
		 * away, but for some switches, like special solenoids (jets
		 * or slings), which could repeatedly trigger if misaligned,
		 * count the activations and validate only when some number
		 * of different switches have triggered.  Device counting
		 * switches are ignored here, but an 'enter' event will
		 * set it. */
		if (!valid_playfield)
		{
			if (swinfo->flags & SW_NOVALID)
			{
				if (!SW_HAS_DEVICE (swinfo))
					try_validate_playfield (sw);
			}
			else
				set_valid_playfield ();
		}
		ball_search_timer_reset ();
	}

cleanup:
	/* If the switch is part of a device, then let the device
	 * subsystem process the event.  Note this will always occur
	 * regardless of any of the above conditions checked. */
	if (SW_HAS_DEVICE (swinfo))
		device_sw_handler (SW_GET_DEVICE (swinfo));

	task_exit ();
}
コード例 #18
0
ファイル: tz_amode.c プロジェクト: SonnyJim/freewpc
CALLSET_ENTRY (tz_amode, amode_start)
{
	task_create_gid (GID_LOCK_AND_OUTHOLE_MONITOR, lock_and_outhole_monitor);
}
コード例 #19
0
ファイル: burnin.c プロジェクト: Curbfeeler/freewpc
void burnin_init (void)
{
	time_audit_clear (&burnin_duration);
	task_create_gid (GID_WINDOW_THREAD, burnin_thread);
	flipper_enable ();
}
コード例 #20
0
ファイル: music.c プロジェクト: SonnyJim/freewpc
CALLSET_ENTRY (music, speed_up_music)
{
    task_create_gid (GID_MUSIC_SPEED, speed_up_music_task);
}
コード例 #21
0
ファイル: stress.c プロジェクト: Curbfeeler/freewpc
/**
 * This task runs during a switch stress test.  During a game,
 * it randomly invokes switch handlers as if the switches had actually
 * been activated by the pinball.
 */
void switch_stress_task (void)
{
	U8 sw;
	const switch_info_t *swinfo;
	task_pid_t tp;

	/* Delay a few seconds before starting the simulation.  This allows
	time for the Start Button to be used to add players, instead of simulating
	endball. */
	task_sleep_sec (3);

	task_create_peer (switch_stress_flipper_task);
	for (;;)
	{
		task_sleep (TIME_100MS);
		if (in_test)
			continue;

		/* Choose a switch at random.  Skip certain well-known switches that are
		 * never to be activated. */
		sw = random_scaled (NUM_SWITCHES);
#ifdef SW_ALWAYS_CLOSED
		if (sw == SW_ALWAYS_CLOSED)
			continue;
#endif
#ifdef MACHINE_OUTHOLE_SWITCH
		if (sw == MACHINE_OUTHOLE_SWITCH)
			continue;
#endif

		/* Lookup the switch properties.  Skip switches which aren't normally
		 * activated on the playfield.  For switches in a ball container,
		 * simulate device entry there, otherwise simulate a switch event. */
		swinfo = switch_lookup (sw);

		if (SW_HAS_DEVICE (swinfo))
		{
			device_t *dev = device_entry (SW_GET_DEVICE (swinfo));
			if (trough_dev_p (dev))
			{
				/* Don't always trigger the trough device.  The probability
				of a ball drain is treated as proportional to the number of
				balls in play.  So in big multiballs, we allow this to happen
				more frequently.
					We need to do this occasionally so that multiball modes
				will eventually end, else nothing else gets tested. */
				if (random () < CONFIG_STRESS_DRAIN_PROB * live_balls)
					switch_stress_drain ();
			}
			else if (dev->max_count < dev->size)
			{
				/* Don't throw an enter event if the device thinks
				it is full: it has "locked" as many balls as it
				can hold.  The device code will throw a fatal if
				it sees this, which should never happen with real
				balls. */
				dbprintf ("Sim. enter dev %d\n", dev->devno);
				device_call_op (dev, enter);
				task_sleep (TIME_1S);
			}
		}
		else if (swinfo->flags & SW_PLAYFIELD)
		{
			/* Simulate the switch */
			tp = task_create_gid (GID_SW_HANDLER, switch_sched_task);
			task_set_arg (tp, sw);
		}
	}
}
コード例 #22
0
ファイル: timer.c プロジェクト: Dave2084/freewpc
task_pid_t timer_start (task_gid_t gid, U16 ticks, task_function_t fn)
{
	task_pid_t tp = task_create_gid (gid, fn);
	task_set_arg (tp, ticks);
	return (tp);
}