resolved created peripheral

This commit is contained in:
2025-11-29 20:06:04 +01:00
parent 2dc6f4a38a
commit d1fda9f075
8 changed files with 112 additions and 42 deletions

View File

@@ -27,8 +27,8 @@ type FTDIFinder struct {
scanEvery time.Duration // Scans peripherals periodically
onArrival func(context.Context, Peripheral) // When a peripheral arrives
onRemoval func(context.Context, Peripheral) // When a peripheral goes away
onArrival func(context.Context, Peripheral, bool) // When a peripheral arrives
onRemoval func(context.Context, Peripheral) // When a peripheral goes away
}
// NewFTDIFinder creates a new FTDI finder
@@ -41,7 +41,7 @@ func NewFTDIFinder(scanEvery time.Duration) *FTDIFinder {
}
// OnArrival is the callback function when a new peripheral arrives
func (f *FTDIFinder) OnArrival(cb func(context.Context, Peripheral)) {
func (f *FTDIFinder) OnArrival(cb func(context.Context, Peripheral, bool)) {
f.onArrival = cb
}
@@ -62,8 +62,8 @@ func (f *FTDIFinder) Initialize() error {
}
// Create creates a new peripheral, based on the peripheral information (manually created)
func (f *FTDIFinder) Create(ctx context.Context, peripheralInfo PeripheralInfo) (string, error) {
return "", nil
func (f *FTDIFinder) Create(ctx context.Context, peripheralInfo PeripheralInfo) error {
return nil
}
// Remove removes an existing peripheral (manually created)
@@ -147,7 +147,7 @@ func (f *FTDIFinder) scanPeripherals(ctx context.Context) error {
peripheral := NewFTDIPeripheral(peripheralData)
if f.onArrival != nil {
f.onArrival(ctx, peripheral)
f.onArrival(ctx, peripheral, false)
}
}
}

View File

@@ -22,8 +22,8 @@ type MIDIFinder struct {
scanEvery time.Duration // Scans peripherals periodically
onArrival func(context.Context, Peripheral) // When a peripheral arrives
onRemoval func(context.Context, Peripheral) // When a peripheral goes away
onArrival func(context.Context, Peripheral, bool) // When a peripheral arrives
onRemoval func(context.Context, Peripheral) // When a peripheral goes away
}
// NewMIDIFinder creates a new MIDI finder
@@ -36,7 +36,7 @@ func NewMIDIFinder(scanEvery time.Duration) *MIDIFinder {
}
// OnArrival is the callback function when a new peripheral arrives
func (f *MIDIFinder) OnArrival(cb func(context.Context, Peripheral)) {
func (f *MIDIFinder) OnArrival(cb func(context.Context, Peripheral, bool)) {
f.onArrival = cb
}
@@ -52,8 +52,8 @@ func (f *MIDIFinder) Initialize() error {
}
// Create creates a new peripheral, based on the peripheral information (manually created)
func (f *MIDIFinder) Create(ctx context.Context, peripheralInfo PeripheralInfo) (string, error) {
return "", nil
func (f *MIDIFinder) Create(ctx context.Context, peripheralInfo PeripheralInfo) error {
return nil
}
// Remove removes an existing peripheral (manually created)
@@ -201,7 +201,7 @@ func (f *MIDIFinder) scanPeripherals(ctx context.Context) error {
f.detected[sn] = peripheral
if f.onArrival != nil {
f.onArrival(ctx, discovery)
f.onArrival(ctx, discovery, false)
}
}
}

View File

@@ -18,26 +18,31 @@ type OS2LFinder struct {
detected map[string]*OS2LPeripheral // The list of saved peripherals
onArrival func(context.Context, Peripheral) // When a peripheral arrives
onRemoval func(context.Context, Peripheral) // When a peripheral goes away
eventBus EventBus // The hardware event bus
onArrival func(context.Context, Peripheral, bool) // When a peripheral arrives
onRemoval func(context.Context, Peripheral) // When a peripheral goes away
}
// NewOS2LFinder creates a new OS2L finder
func NewOS2LFinder() *OS2LFinder {
func NewOS2LFinder(eventBus EventBus) *OS2LFinder {
log.Trace().Str("file", "OS2LFinder").Msg("OS2L finder created")
return &OS2LFinder{
detected: make(map[string]*OS2LPeripheral),
eventBus: eventBus,
}
}
// Initialize initializes the finder
func (f *OS2LFinder) Initialize() error {
// Subscribe to all OS2L peripherals that are added to the project
f.eventBus.SubscribeType(f.GetName(), f)
log.Trace().Str("file", "OS2LFinder").Msg("OS2L finder initialized")
return nil
}
// OnArrival is the callback function when a new peripheral arrives
func (f *OS2LFinder) OnArrival(cb func(context.Context, Peripheral)) {
func (f *OS2LFinder) OnArrival(cb func(context.Context, Peripheral, bool)) {
f.onArrival = cb
}
@@ -47,7 +52,7 @@ func (f *OS2LFinder) OnRemoval(cb func(context.Context, Peripheral)) {
}
// Create creates a new peripheral, based on the peripheral information (manually created)
func (f *OS2LFinder) Create(ctx context.Context, peripheralInfo PeripheralInfo) (string, error) {
func (f *OS2LFinder) Create(ctx context.Context, peripheralInfo PeripheralInfo) error {
// If the SerialNumber is empty, generate another one
if peripheralInfo.SerialNumber == "" {
peripheralInfo.SerialNumber = strings.ToUpper(fmt.Sprintf("%08x", rand.Intn(1<<32)))
@@ -56,7 +61,7 @@ func (f *OS2LFinder) Create(ctx context.Context, peripheralInfo PeripheralInfo)
// Create a new OS2L peripheral
peripheral, err := NewOS2LPeripheral(peripheralInfo)
if err != nil {
return "", fmt.Errorf("unable to create the OS2L peripheral: %w", err)
return fmt.Errorf("unable to create the OS2L peripheral: %w", err)
}
// Set the event callback
@@ -67,9 +72,9 @@ func (f *OS2LFinder) Create(ctx context.Context, peripheralInfo PeripheralInfo)
f.detected[peripheralInfo.SerialNumber] = peripheral
if f.onArrival != nil {
f.onArrival(ctx, peripheral)
f.onArrival(ctx, peripheral, true) // Ask to register the peripheral in the project
}
return peripheralInfo.SerialNumber, err
return err
}
// Remove removes an existing peripheral (manually created)

View File

@@ -40,6 +40,51 @@ const (
PeripheralStatusActivated PeripheralStatus = "PERIPHERAL_ACTIVATED"
)
// EventBus handles events between hardware and finders
type EventBus struct {
register map[string][]PeripheralFinder // Register is a map[peripheralType (string)][]Finder
}
// SubscribeType is called from finders that want to subscribe for a peripheral loaded in project
func (b *EventBus) SubscribeType(protocolName string, finder PeripheralFinder) {
// Check if we need to initialize the slice (key not found)
if _, found := b.register[protocolName]; !found {
b.register[protocolName] = make([]PeripheralFinder, 0)
}
// Add the finder to the list of subscription
b.register[protocolName] = append(b.register[protocolName], finder)
}
// EmitSavedPeripheral emits a peripheral loaded event for all the finders suscribed to the peripheral type
func (b *EventBus) EmitSavedPeripheral(ctx context.Context, peripheralInfo PeripheralInfo) (string, error) {
finders, found := b.register[peripheralInfo.ProtocolName]
if !found {
return "", nil
}
for _, finder := range finders {
err := finder.Create(ctx, peripheralInfo)
if err != nil {
log.Err(err).Str("finder", finder.GetName()).Str("S/N", peripheralInfo.SerialNumber).Msg("unable to create the peripheral")
}
}
return "", nil
}
// EmitUnsavedPeripheral emits a peripheral unloaded event for all the finders suscribed to the peripheral type
func (b *EventBus) EmitUnsavedPeripheral(ctx context.Context, peripheral Peripheral) (string, error) {
finders, found := b.register[peripheral.GetInfo().ProtocolName]
if !found {
return "", nil
}
for _, finder := range finders {
err := finder.Remove(ctx, peripheral)
if err != nil {
log.Err(err).Str("finder", finder.GetName()).Str("S/N", peripheral.GetInfo().SerialNumber).Msg("unable to remove the peripheral")
}
}
return "", nil
}
// Manager is the class who manages the hardware
type Manager struct {
mu sync.Mutex
@@ -48,6 +93,8 @@ type Manager struct {
finders map[string]PeripheralFinder // The map of peripherals finders
peripherals map[string]Peripheral // The current list of peripherals
savedPeripherals map[string]PeripheralInfo // The list of stored peripherals
eventBus EventBus // The hardware event bus
}
// NewManager creates a new hardware manager
@@ -57,14 +104,28 @@ func NewManager() *Manager {
finders: make(map[string]PeripheralFinder),
peripherals: make(map[string]Peripheral, 0),
savedPeripherals: make(map[string]PeripheralInfo, 0),
eventBus: EventBus{
make(map[string][]PeripheralFinder),
},
}
}
// CreatePeripheral asks the providers to create a new peripheral
func (h *Manager) CreatePeripheral(ctx context.Context, peripheralInfo PeripheralInfo) {
// Emit an event to the hardware event bus
h.eventBus.EmitSavedPeripheral(ctx, peripheralInfo)
}
// RegisterPeripheral registers a new peripheral
func (h *Manager) RegisterPeripheral(ctx context.Context, peripheralData PeripheralInfo) (string, error) {
h.mu.Lock()
defer h.mu.Unlock()
// Do not save if the peripheral doesn't have a S/N
if peripheralData.SerialNumber == "" {
return "", nil
}
h.savedPeripherals[peripheralData.SerialNumber] = peripheralData
runtime.EventsEmit(ctx, string(PeripheralStatusUpdated), peripheralData, PeripheralStatusDisconnected)
@@ -112,6 +173,8 @@ func (h *Manager) UnregisterPeripheral(ctx context.Context, peripheralData Perip
log.Err(err).Str("sn", peripheralData.SerialNumber).Msg("unable to disconnect the peripheral")
return nil
}
// Emit the unload event
h.eventBus.EmitUnsavedPeripheral(ctx, peripheral)
}
delete(h.savedPeripherals, peripheralData.SerialNumber)
runtime.EventsEmit(ctx, string(PeripheralUnload), peripheralData)
@@ -147,7 +210,7 @@ func (h *Manager) Start(ctx context.Context) error {
// Register all the finders to use as hardware scanners
h.RegisterFinder(NewFTDIFinder(3 * time.Second))
h.RegisterFinder(NewOS2LFinder())
h.RegisterFinder(NewOS2LFinder(h.eventBus))
h.RegisterFinder(NewMIDIFinder(3 * time.Second))
for finderName, finder := range h.finders {
@@ -174,7 +237,12 @@ func (h *Manager) Start(ctx context.Context) error {
}
// OnPeripheralArrival is called when a peripheral arrives in the system
func (h *Manager) OnPeripheralArrival(ctx context.Context, peripheral Peripheral) {
func (h *Manager) OnPeripheralArrival(ctx context.Context, peripheral Peripheral, needSave bool) {
// Save the peripheral in the project if needed
if needSave {
h.RegisterPeripheral(ctx, peripheral.GetInfo())
}
// Add the peripheral to the detected hardware
h.peripherals[peripheral.GetInfo().SerialNumber] = peripheral

View File

@@ -45,11 +45,12 @@ type PeripheralInfo struct {
// PeripheralFinder represents how compatible peripheral drivers are implemented
type PeripheralFinder interface {
Initialize() error // Initializes the protocol
Create(ctx context.Context, peripheralInfo PeripheralInfo) (string, error) // Manually create a peripheral
OnArrival(cb func(context.Context, Peripheral)) // Callback function when a peripheral arrives
OnRemoval(cb func(context.Context, Peripheral)) // Callback function when a peripheral goes away
Start(context.Context) error // Start the detection
WaitStop() error // Waiting for finder to close
GetName() string // Get the name of the finder
Initialize() error // Initializes the protocol
Create(ctx context.Context, peripheralInfo PeripheralInfo) error // Manually create a peripheral
Remove(ctx context.Context, peripheral Peripheral) error // Manually remove a peripheral
OnArrival(cb func(context.Context, Peripheral, bool)) // Callback function when a peripheral arrives
OnRemoval(cb func(context.Context, Peripheral)) // Callback function when a peripheral goes away
Start(context.Context) error // Start the detection
WaitStop() error // Waiting for finder to close
GetName() string // Get the name of the finder
}