Gopher2600/setup/setup.go
JetSetIlly cd2a00d4ba logger.Log() and logger.Logf() now require a logger.Permission instance
the logger.Permission interface indicates whether the environment making
the logging request is allowed to create new log entries. the
environment.Environment type satisifies the Permission interface

logger.Allow is provided as a convienient way of indicating the the log
entry should always be created
2024-04-30 11:23:40 +01:00

118 lines
3.4 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 setup
import (
"errors"
"fmt"
"github.com/jetsetilly/gopher2600/cartridgeloader"
"github.com/jetsetilly/gopher2600/database"
"github.com/jetsetilly/gopher2600/hardware"
"github.com/jetsetilly/gopher2600/logger"
"github.com/jetsetilly/gopher2600/resources"
)
// *** NOTE ***
// remove DisablePeriphFingerprint field from VCS type once setup package has
// been updated to handle peripherals/controllers correctly
// the location of the setupDB file.
const setupDBFile = "setupDB"
// setupEntry is the generic entry type in the setupDB.
type setupEntry interface {
database.Entry
// match the hash stored in the database with the user supplied hash
matchCartHash(hash string) bool
// apply changes indicated in the entry to the VCS. returned string value
// will be used for log message
apply(vcs *hardware.VCS) (string, error)
}
// when starting a database session we must add the details of the entry types
// that will be found in the database.
func initDBSession(db *database.Session) error {
// add entry types
if err := db.RegisterEntryType(panelSetupEntryType, deserialisePanelSetupEntry); err != nil {
return err
}
if err := db.RegisterEntryType(patchEntryType, deserialisePatchEntry); err != nil {
return err
}
if err := db.RegisterEntryType(televisionEntryType, deserialiseTelevisionEntry); err != nil {
return err
}
return nil
}
// AttachCartridge to the VCS and apply setup information from the setupDB.
// This function should be preferred to the hardware.VCS.AttachCartridge()
// function in almost all cases.
func AttachCartridge(vcs *hardware.VCS, cartload cartridgeloader.Loader, resetVCS bool) error {
err := vcs.AttachCartridge(cartload, resetVCS)
if err != nil {
// not adding the "setup" prefix for this. the setup package has not
// added any value yet and it would just be noise
return err
}
dbPth, err := resources.JoinPath(setupDBFile)
if err != nil {
return fmt.Errorf("setup: %w", err)
}
db, err := database.StartSession(dbPth, database.ActivityReading, initDBSession)
if err != nil {
if errors.Is(err, database.NotAvailable) {
// silently ignore absence of setup database
return nil
}
return fmt.Errorf("setup: %w", err)
}
defer db.EndSession(false)
onSelect := func(ent database.Entry) error {
// database entry should also satisfy setupEntry interface
set, ok := ent.(setupEntry)
if !ok {
return fmt.Errorf("setup: attach cartridge: database entry does not satisfy setupEntry interface")
}
if set.matchCartHash(vcs.Mem.Cart.Hash) {
msg, err := set.apply(vcs)
if err != nil {
return err
}
logger.Logf(logger.Allow, "setup", msg)
}
return nil
}
_, err = db.SelectAll(onSelect)
if err != nil {
return fmt.Errorf("setup: %w", err)
}
return nil
}