Skip to content

Commit

Permalink
snes: introduce UseDeviceMemory; introduce ExclusiveUse and BaseDevic…
Browse files Browse the repository at this point in the history
…eDriver
  • Loading branch information
JamesDunne committed Jun 14, 2021
1 parent 0734ce7 commit dafd48b
Show file tree
Hide file tree
Showing 9 changed files with 224 additions and 145 deletions.
154 changes: 74 additions & 80 deletions cmd/sni/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,29 +69,23 @@ func (s *deviceMemoryService) Read(
return
}

gerr = snes.UseDevice(rctx, uri, func(ctx context.Context, dev snes.Device) (err error) {
// TODO: could offer stateful binding of device to peer
//peer.FromContext(ctx)
err = dev.UseMemory(ctx, func(mctx context.Context, memory snes.DeviceMemory) (merr error) {
var mrsp []snes.MemoryReadResponse
mrsp, merr = memory.MultiReadMemory(mctx, snes.MemoryReadRequest{
Address: request.Request.Address,
Size: int(request.Request.Size),
})
if merr != nil {
return
}

rsp = &sni.SingleReadMemoryResponse{
Uri: request.Uri,
Response: &sni.ReadMemoryResponse{
Address: request.Request.Address,
Data: mrsp[0].Data,
},
}
return
gerr = snes.UseDeviceMemory(rctx, uri, func(mctx context.Context, memory snes.DeviceMemory) (err error) {
var mrsp []snes.MemoryReadResponse
mrsp, err = memory.MultiReadMemory(mctx, snes.MemoryReadRequest{
Address: request.Request.Address,
Size: int(request.Request.Size),
})
if err != nil {
return
}

rsp = &sni.SingleReadMemoryResponse{
Uri: request.Uri,
Response: &sni.ReadMemoryResponse{
Address: request.Request.Address,
Data: mrsp[0].Data,
},
}
return
})

Expand All @@ -112,29 +106,23 @@ func (s *deviceMemoryService) Write(
return
}

gerr = snes.UseDevice(rctx, uri, func(ctx context.Context, dev snes.Device) (err error) {
// TODO: could offer stateful binding of device to peer
//peer.FromContext(ctx)
err = dev.UseMemory(ctx, func(mctx context.Context, memory snes.DeviceMemory) (merr error) {
var mrsp []snes.MemoryWriteResponse
mrsp, merr = memory.MultiWriteMemory(mctx, snes.MemoryWriteRequest{
Address: request.Request.Address,
Data: request.Request.Data,
})
if merr != nil {
return
}

rsp = &sni.SingleWriteMemoryResponse{
Uri: request.Uri,
Response: &sni.WriteMemoryResponse{
Address: mrsp[0].Address,
Size: uint32(mrsp[0].Size),
},
}
return
gerr = snes.UseDeviceMemory(rctx, uri, func(mctx context.Context, memory snes.DeviceMemory) (err error) {
var mrsp []snes.MemoryWriteResponse
mrsp, err = memory.MultiWriteMemory(mctx, snes.MemoryWriteRequest{
Address: request.Request.Address,
Data: request.Request.Data,
})
if err != nil {
return
}

rsp = &sni.SingleWriteMemoryResponse{
Uri: request.Uri,
Response: &sni.WriteMemoryResponse{
Address: mrsp[0].Address,
Size: uint32(mrsp[0].Size),
},
}
return
})

Expand All @@ -156,29 +144,32 @@ func (s *deviceMemoryService) MultiRead(
}

var grsps []*sni.ReadMemoryResponse
gerr = snes.UseDevice(gctx, uri, func(ctx context.Context, dev snes.Device) error {
return dev.UseMemory(ctx, func(mctx context.Context, memory snes.DeviceMemory) (err error) {
reads := make([]snes.MemoryReadRequest, 0, len(request.Requests))
for _, req := range request.Requests {
reads = append(reads, snes.MemoryReadRequest{
Address: req.Address,
Size: int(req.Size),
})
}
gerr = snes.UseDeviceMemory(gctx, uri, func(mctx context.Context, memory snes.DeviceMemory) (err error) {
reads := make([]snes.MemoryReadRequest, 0, len(request.Requests))
for _, req := range request.Requests {
reads = append(reads, snes.MemoryReadRequest{
Address: req.Address,
Size: int(req.Size),
})
}

var mrsps []snes.MemoryReadResponse
mrsps, err = memory.MultiReadMemory(mctx, reads...)
grsps = make([]*sni.ReadMemoryResponse, 0, len(mrsps))
for _, mrsp := range mrsps {
grsps = append(grsps, &sni.ReadMemoryResponse{
Address: mrsp.Address,
Data: mrsp.Data,
})
}
var mrsps []snes.MemoryReadResponse
mrsps, err = memory.MultiReadMemory(mctx, reads...)
if err != nil {
return
})
}

grsps = make([]*sni.ReadMemoryResponse, 0, len(mrsps))
for _, mrsp := range mrsps {
grsps = append(grsps, &sni.ReadMemoryResponse{
Address: mrsp.Address,
Data: mrsp.Data,
})
}
return
})
if gerr != nil {
grsp = nil
return
}

Expand All @@ -200,29 +191,32 @@ func (s *deviceMemoryService) MultiWrite(
}

var grsps []*sni.WriteMemoryResponse
gerr = snes.UseDevice(gctx, uri, func(ctx context.Context, dev snes.Device) error {
return dev.UseMemory(ctx, func(mctx context.Context, memory snes.DeviceMemory) (err error) {
writes := make([]snes.MemoryWriteRequest, 0, len(request.Requests))
for _, req := range request.Requests {
writes = append(writes, snes.MemoryWriteRequest{
Address: req.Address,
Data: req.Data,
})
}
gerr = snes.UseDeviceMemory(gctx, uri, func(mctx context.Context, memory snes.DeviceMemory) (err error) {
writes := make([]snes.MemoryWriteRequest, 0, len(request.Requests))
for _, req := range request.Requests {
writes = append(writes, snes.MemoryWriteRequest{
Address: req.Address,
Data: req.Data,
})
}

var mrsps []snes.MemoryWriteResponse
mrsps, err = memory.MultiWriteMemory(mctx, writes...)
grsps = make([]*sni.WriteMemoryResponse, 0, len(mrsps))
for _, mrsp := range mrsps {
grsps = append(grsps, &sni.WriteMemoryResponse{
Address: mrsp.Address,
Size: uint32(mrsp.Size),
})
}
var mrsps []snes.MemoryWriteResponse
mrsps, err = memory.MultiWriteMemory(mctx, writes...)
if err != nil {
return
})
}

grsps = make([]*sni.WriteMemoryResponse, 0, len(mrsps))
for _, mrsp := range mrsps {
grsps = append(grsps, &sni.WriteMemoryResponse{
Address: mrsp.Address,
Size: uint32(mrsp.Size),
})
}
return
})
if gerr != nil {
grsp = nil
return
}

Expand Down
58 changes: 58 additions & 0 deletions snes/basedriver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package snes

import (
"context"
"sync"
)

type BaseDeviceDriver struct {
driver DeviceDriver

// track opened devices by URI
devicesRw sync.RWMutex
devicesMap map[string]Device
}

func (b *BaseDeviceDriver) UseDevice(ctx context.Context, deviceKey string, openDevice func() (Device, error), use DeviceUser) (err error) {
var device Device
var ok bool

b.devicesRw.RLock()
device, ok = b.devicesMap[deviceKey]
b.devicesRw.RUnlock()

if !ok {
device, err = openDevice()
if err != nil {
return
}

b.devicesRw.Lock()
if b.devicesMap == nil {
b.devicesMap = make(map[string]Device)
}
b.devicesMap[deviceKey] = device
b.devicesRw.Unlock()
}

err = device.ExclusiveUse(ctx, use)

if device.IsClosed() {
b.devicesRw.Lock()
if b.devicesMap == nil {
b.devicesMap = make(map[string]Device)
}
delete(b.devicesMap, deviceKey)
b.devicesRw.Unlock()
}

return
}

func (b *BaseDeviceDriver) Get(deviceKey string) (Device, bool) {
b.devicesRw.RLock()
device, ok := b.devicesMap[deviceKey]
b.devicesRw.RUnlock()

return device, ok
}
9 changes: 6 additions & 3 deletions snes/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,17 @@ type MemoryWriteResponse struct {
Size int
}

type MemoryUser func(context context.Context, memory DeviceMemory) error
type DeviceMemoryUser func(context context.Context, memory DeviceMemory) error

// Device acts as an exclusive-access gateway to the subsystems of the SNES device
type Device interface {
IsClosed() bool

// UseMemory provides exclusive access to the memory subsystem of the device to the user func
UseMemory(context context.Context, user MemoryUser) error
// ExclusiveUse provides exclusive access to the entire device to the user func
ExclusiveUse(ctx context.Context, user DeviceUser) error

// UseMemory provides exclusive access to only the memory subsystem of the device to the user func
UseMemory(ctx context.Context, user DeviceMemoryUser) error
}

type DeviceMemory interface {
Expand Down
23 changes: 23 additions & 0 deletions snes/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ type DeviceUser func(context.Context, Device) error

// DeviceDriver extends Driver
type DeviceDriver interface {
DeviceKey(uri *url.URL) string

// OpenDevice creates a Device interface for a specific device
OpenDevice(uri *url.URL) (Device, error)

Expand Down Expand Up @@ -136,3 +138,24 @@ func UseDevice(ctx context.Context, uri *url.URL, user DeviceUser) (err error) {

return drv.UseDevice(ctx, uri, user)
}

func UseDeviceMemory(ctx context.Context, uri *url.URL, user DeviceMemoryUser) (err error) {
var ok bool
var gendrv Driver
gendrv, ok = DriverByName(uri.Scheme)
if !ok {
err = fmt.Errorf("driver not found by name '%s'", uri.Scheme)
return
}

var drv DeviceDriver
drv, ok = gendrv.(DeviceDriver)
if !ok {
err = fmt.Errorf("driver named '%s' is not a DeviceDriver", uri.Scheme)
return
}

return drv.UseDevice(ctx, uri, func(ctx context.Context, device Device) error {
return device.UseMemory(ctx, user)
})
}
9 changes: 9 additions & 0 deletions snes/fxpakpro/driver.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fxpakpro

import (
"context"
"fmt"
"go.bug.st/serial"
"go.bug.st/serial/enumerator"
Expand Down Expand Up @@ -135,6 +136,14 @@ func (d *Driver) OpenQueue(dd snes.DeviceDescriptor) (snes.Queue, error) {
return c, err
}

func (d *Driver) OpenDevice(uri *url.URL) (snes.Device, error) {
panic("implement me")
}

func (d *Driver) UseDevice(ctx context.Context, uri *url.URL, user snes.DeviceUser) error {
panic("implement me")
}

func init() {
if util.IsTruthy(env.GetOrDefault("SNI_FXPAKPRO_DISABLE", "0")) {
log.Printf("disabling fxpakpro snes driver\n")
Expand Down
23 changes: 22 additions & 1 deletion snes/mock/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ package mock
import (
"context"
"sni/snes"
"sync"
"time"
)

type Device struct {
lock sync.Mutex

frameTicker *time.Ticker

WRAM []byte
Expand All @@ -29,7 +32,25 @@ func (d *Device) IsClosed() bool {
return false
}

func (d *Device) UseMemory(context context.Context, user snes.MemoryUser) error {
func (d *Device) ExclusiveUse(context context.Context, user snes.DeviceUser) error {
if user == nil {
return nil
}

defer d.lock.Unlock()
d.lock.Lock()

return user(context, d)
}

func (d *Device) UseMemory(context context.Context, user snes.DeviceMemoryUser) error {
if user == nil {
return nil
}

defer d.lock.Unlock()
d.lock.Lock()

return user(context, d)
}

Expand Down
Loading

0 comments on commit dafd48b

Please sign in to comment.