diff --git a/apple2Setup.go b/apple2Setup.go index 7ce320e..1cf1d65 100644 --- a/apple2Setup.go +++ b/apple2Setup.go @@ -153,9 +153,13 @@ func (a *Apple2) AddFujinet(slot int, trace bool) { c.trace = trace a.insertCard(c, slot) - d := NewSmartPortFujinet(c) - d.trace = trace - c.AddDevice(0, d) + net := NewSmartPortFujinetNetwork(c) + net.trace = trace + c.AddDevice(net) + + clock := NewSmartPortFujinetClock(c) + clock.trace = trace + c.AddDevice(clock) } // AddVidHD adds a card with the signature of VidHD diff --git a/cardSmartport.go b/cardSmartport.go index 61d3587..5586509 100644 --- a/cardSmartport.go +++ b/cardSmartport.go @@ -53,7 +53,7 @@ func (c *CardSmartPort) LoadImage(filename string, trace bool) error { } // LoadImage loads a disk image -func (c *CardSmartPort) AddDevice(unt uint8, device smartPortDevice) { +func (c *CardSmartPort) AddDevice(device smartPortDevice) { c.devices = append(c.devices, device) c.hardDiskBlocks = 0 // Needed for the PRODOS status } @@ -136,8 +136,8 @@ func (c *CardSmartPort) exec(call *smartPortCall) uint8 { } if c.trace { - fmt.Printf("[CardSmartPort] Command %v on slot %v, unit %v => result %s.\n", - call, c.slot, call.unit(), smartPortErrorMessage(result)) + fmt.Printf("[CardSmartPort] Command %v on slot %v => result %s.\n", + call, c.slot, smartPortErrorMessage(result)) } return result } diff --git a/smartPortFujinetClock.go b/smartPortFujinetClock.go new file mode 100644 index 0000000..4515c73 --- /dev/null +++ b/smartPortFujinetClock.go @@ -0,0 +1,91 @@ +package izapple2 + +import ( + "fmt" + "time" +) + +/* + +A clock device that could be implemented by Fujinet: + +*/ + +// SmartPortFujinetClock represents a Fujinet clock device +type SmartPortFujinetClock struct { + host *CardSmartPort // For DMA + trace bool +} + +// NewSmartPortFujinetClock creates a new fujinet device +func NewSmartPortFujinetClock(host *CardSmartPort) *SmartPortFujinetClock { + var d SmartPortFujinetClock + d.host = host + return &d +} + +func (d *SmartPortFujinetClock) exec(call *smartPortCall) uint8 { + var result uint8 + + switch call.command { + + case smartPortCommandOpen: + result = smartPortNoError + + case smartPortCommandClose: + result = smartPortNoError + + case smartPortCommandStatus: + address := call.param16(2) + result = d.status(call.statusCode(), address) + + default: + // Prodos device command not supported + result = smartPortErrorIO + } + + if d.trace { + fmt.Printf("[SmartPortFujinetClock] Command %v, return %s \n", + call, smartPortErrorMessage(result)) + } + + return result +} + +func (d *SmartPortFujinetClock) status(code uint8, dest uint16) uint8 { + + switch code { + case smartPortStatusCodeDevice: + // See iwmNetwork::encode_status_reply_packet() + d.host.a.mmu.pokeRange(dest, []uint8{ + 0, // NA for a clock + 0, 0, 0, // Block size is 0 + }) + + case smartPortStatusCodeDeviceInfo: + // See iwmNetwork::encode_status_reply_packet() + d.host.a.mmu.pokeRange(dest, []uint8{ + smartPortStatusCodeTypeRead & smartPortStatusCodeTypeOnline, + 0, 0, 0, // Block size is 0 + 8, 'F', 'N', '_', 'C', 'L', 'O', 'C', 'K', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', + 0x0f, // Type clock. See http://www.1000bit.it/support/manuali/apple/technotes/smpt/tn.smpt.4.html + 0x00, // Subtype + 0x00, 0x01, // Firmware version + }) + + case 'T': + // Get time + now := time.Now() + d.host.a.mmu.pokeRange(dest, []uint8{ + uint8(now.Year() / 100), + uint8(now.Year() % 100), + uint8(now.Month()), + uint8(now.Day()), + uint8(now.Hour()), + uint8(now.Minute()), + uint8(now.Second()), + }) + } + + return smartPortNoError // The return code is always success +} diff --git a/smartPortFujinet.go b/smartPortFujinetNetwork.go similarity index 77% rename from smartPortFujinet.go rename to smartPortFujinetNetwork.go index 64b7d3f..1c60f5c 100644 --- a/smartPortFujinet.go +++ b/smartPortFujinetNetwork.go @@ -17,8 +17,8 @@ See: */ -// SmartPortFujinet represents a Fujinet device -type SmartPortFujinet struct { +// SmartPortFujinetNetwork represents a Fujinet device +type SmartPortFujinetNetwork struct { host *CardSmartPort // For DMA trace bool @@ -32,16 +32,16 @@ type SmartPortFujinet struct { //connected uint8 } -// NewSmartPortFujinet creates a new fujinet device -func NewSmartPortFujinet(host *CardSmartPort) *SmartPortFujinet { - var d SmartPortFujinet +// NewSmartPortFujinetNetwork creates a new fujinet device +func NewSmartPortFujinetNetwork(host *CardSmartPort) *SmartPortFujinetNetwork { + var d SmartPortFujinetNetwork d.host = host d.errorCode = fujinet.NoError return &d } -func (d *SmartPortFujinet) exec(call *smartPortCall) uint8 { +func (d *SmartPortFujinetNetwork) exec(call *smartPortCall) uint8 { var result uint8 switch call.command { @@ -73,16 +73,16 @@ func (d *SmartPortFujinet) exec(call *smartPortCall) uint8 { } if d.trace { - fmt.Printf("[SmartPortFujinet] Command %v, return %s \n", + fmt.Printf("[SmartPortFujinetNetwork] Command %v, return %s \n", call, smartPortErrorMessage(result)) } return result } -func (d *SmartPortFujinet) read(pos uint32, length uint16, dest uint16) uint8 { +func (d *SmartPortFujinetNetwork) read(pos uint32, length uint16, dest uint16) uint8 { if d.trace { - fmt.Printf("[SmartPortFujinet] Read %v bytes from pos %v into $%x.\n", + fmt.Printf("[SmartPortFujinetNetwork] Read %v bytes from pos %v into $%x.\n", length, pos, dest) } @@ -94,7 +94,7 @@ func (d *SmartPortFujinet) read(pos uint32, length uint16, dest uint16) uint8 { return smartPortNoError } -func (d *SmartPortFujinet) control(data []uint8, code uint8) uint8 { +func (d *SmartPortFujinetNetwork) control(data []uint8, code uint8) uint8 { switch code { case 'O': // Open URL @@ -121,10 +121,10 @@ func (d *SmartPortFujinet) control(data []uint8, code uint8) uint8 { return smartPortNoError } -func (d *SmartPortFujinet) controlJsonParse() { +func (d *SmartPortFujinetNetwork) controlJsonParse() { // See FNJSON::parse() if d.trace { - fmt.Printf("[SmartPortFujinet] control-parse()\n") + fmt.Printf("[SmartPortFujinetNetwork] control-parse()\n") } data, errorCode := d.protocol.ReadAll() @@ -137,9 +137,9 @@ func (d *SmartPortFujinet) controlJsonParse() { d.errorCode = d.jsonData.Parse(data) } -func (d *SmartPortFujinet) controlJsonQuery(query []uint8) { +func (d *SmartPortFujinetNetwork) controlJsonQuery(query []uint8) { if d.trace { - fmt.Printf("[SmartPortFujinet] control-query('%s')\n", query) + fmt.Printf("[SmartPortFujinetNetwork] control-query('%s')\n", query) } if d.jsonData != nil { @@ -148,7 +148,7 @@ func (d *SmartPortFujinet) controlJsonQuery(query []uint8) { } } -func (d *SmartPortFujinet) controlChannelMode(mode uint8) { +func (d *SmartPortFujinetNetwork) controlChannelMode(mode uint8) { // See iwmNetwork::channel_mode() if d.trace { fmt.Printf("control-channel-mode(%v)\n", mode) @@ -162,10 +162,10 @@ func (d *SmartPortFujinet) controlChannelMode(mode uint8) { // The rest of the cases do not change the mode } -func (d *SmartPortFujinet) controlOpen(method uint8, translation uint8, rawUrl string) { +func (d *SmartPortFujinetNetwork) controlOpen(method uint8, translation uint8, rawUrl string) { // See iwmNetwork::open() if d.trace { - fmt.Printf("[SmartPortFujinet] control-open(%v, %v, '%s'\n", method, translation, rawUrl) + fmt.Printf("[SmartPortFujinetNetwork] control-open(%v, %v, '%s'\n", method, translation, rawUrl) } if d.protocol != nil { @@ -193,7 +193,7 @@ func (d *SmartPortFujinet) controlOpen(method uint8, translation uint8, rawUrl s d.jsonChannelMode = false } -func (d *SmartPortFujinet) status(code uint8, dest uint16) uint8 { +func (d *SmartPortFujinetNetwork) status(code uint8, dest uint16) uint8 { switch code { case smartPortStatusCodeDevice: