Gopher2600/hardware/input/driven.go
JetSetIlly 58848acdf9 input system and ports system separated
playback/recorder and driven input systems moved out of the the ports
package and into a new input package. how the input systems interact has
been clarified and improved - for example, it is now posssible for a
playback file to be used to drive two emulations for comparison purposes

the debugger startup procedure has been clarified with two distinct
startup functions for playmode and debugger - each of which take
different arguments. the clarity has allowed the reintroduction of
recording and playback to the main play mode
2021-12-11 08:19:46 +00:00

88 lines
2.6 KiB
Go

// This file is part of Gopher2600.
//
// Gopher2600 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Gopher2600 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Gopher2600. If not, see <https://www.gnu.org/licenses/>.
package input
import (
"github.com/jetsetilly/gopher2600/curated"
"github.com/jetsetilly/gopher2600/hardware/riot/ports"
"github.com/jetsetilly/gopher2600/hardware/television/coords"
)
// handleDrivenEvents checks for input driven from a another emulation.
func (inp *Input) handleDrivenEvents() error {
if inp.checkForDriven {
ev := inp.drivenInputEvent
done := false
for !done {
c := inp.tv.GetCoords()
if coords.Equal(c, ev.Time) {
_, err := inp.ports.HandleInputEvent(ev.InputEvent)
if err != nil {
return err
}
} else if coords.GreaterThan(c, ev.Time) {
return curated.Errorf("input: driven input seen too late. emulations not synced correctly.")
} else {
return nil
}
select {
case inp.drivenInputEvent = <-inp.fromDriver:
if inp.checkForDriven {
curated.Errorf("input: driven input received before previous input was processed")
}
default:
done = true
inp.checkForDriven = false
}
ev = inp.drivenInputEvent
}
}
if inp.fromDriver != nil {
select {
case inp.drivenInputEvent = <-inp.fromDriver:
if inp.checkForDriven {
curated.Errorf("input: driven input received before previous input was processed")
}
inp.checkForDriven = true
default:
}
}
return nil
}
// AttachPassenger should be called by an emulation that wants to be driven by another emulation.
func (inp *Input) AttachPassenger(driver chan ports.TimedInputEvent) error {
if inp.toPassenger != nil {
return curated.Errorf("input: attach passenger: emulation already defined as an input driver")
}
inp.fromDriver = driver
inp.setProcessFunc()
return nil
}
// AttachDriver should be called by an emulation that is prepared to drive another emulation.
func (inp *Input) AttachDriver(passenger chan ports.TimedInputEvent) error {
if inp.fromDriver != nil {
return curated.Errorf("input: attach driver: emulation already defined as being an input passenger")
}
inp.toPassenger = passenger
return nil
}