create subpackages for different endpoints type

This commit is contained in:
2025-11-30 19:57:34 +01:00
parent 1c8607800a
commit ac56ca3b35
21 changed files with 176 additions and 184 deletions

8
app.go
View File

@@ -3,8 +3,12 @@ package main
import (
"context"
"dmxconnect/hardware"
genericmidi "dmxconnect/hardware/genericMIDI"
"dmxconnect/hardware/genericftdi"
"dmxconnect/hardware/os2l"
"fmt"
"io"
"time"
"github.com/rs/zerolog/log"
@@ -29,6 +33,10 @@ type App struct {
func NewApp() *App {
// Create a new hadware manager
hardwareManager := hardware.NewManager()
// Register all the providers to use as hardware scanners
hardwareManager.RegisterProvider(genericftdi.NewProvider(3 * time.Second))
hardwareManager.RegisterProvider(os2l.NewProvider())
hardwareManager.RegisterProvider(genericmidi.NewProvider(3 * time.Second))
return &App{
hardwareManager: hardwareManager,
projectSave: "",

View File

@@ -26,8 +26,8 @@ echo [INFO] Git version detected: %GIT_TAG%
echo [INFO] Mode selectionne : %MODE%
echo [INFO] Moving to the C++ folder...
cd /d "%~dp0hardware\cpp" || (
echo [ERROR] Impossible d'accéder à hardware\cpp
cd /d "%~dp0hardware\genericftdi\cpp" || (
echo [ERROR] Impossible d'accéder à hardware\genericftdi\cpp
exit /b 1
)

View File

@@ -1,22 +0,0 @@
@REM windres dmxSender.rc dmxSender.o
@REM windres detectFTDI.rc detectFTDI.o
@REM g++ -o dmxSender.exe dmxSender.cpp dmxSender.o -I"include" -L"lib" -lftd2xx -mwindows
@REM g++ -o detectFTDI.exe detectFTDI.cpp detectFTDI.o -I"include" -L"lib" -lftd2xx -mwindows
@REM g++ -o dmxSender.exe dmxSender.cpp -I"include" -L"lib" -lftd2xx
@REM g++ -o detectFTDI.exe detectFTDI.cpp -I"include" -L"lib" -lftd2xx
@REM g++ -c dmxSender.cpp -o dmxSender.o -I"include" -L"lib" -lftd2xx -mwindows
@REM g++ -c dmxSender_wrapper.cpp -o dmxSender_wrapper.o -I"include" -L"lib" -lftd2xx -mwindows
@REM g++ -shared -o ../../build/bin/libdmxSender.dll src/dmxSender.cpp -fPIC -Wl,--out-implib,../../build/bin/libdmxSender.dll.a -L"lib" -lftd2xx
@REM Compiling DETECTFTDI library
g++ -shared -o ../../build/bin/libdetectFTDI.dll src/detectFTDI.cpp -fPIC -Wl,--out-implib,../../build/bin/libdetectFTDI.dll.a -L"lib" -lftd2xx -mwindows
@REM Compiling DMXSENDER library
g++ -shared -o ../../build/bin/libdmxSender.dll src/dmxSender.cpp -fPIC -Wl,--out-implib,../../build/bin/libdmxSender.dll.a -L"lib" -lftd2xx -mwindows
@REM g++ -shared -o libdmxSender.so dmxSender.cpp -fPIC -I"include" -L"lib" -lftd2xx -mwindows

View File

@@ -1,7 +1,8 @@
package hardware
package genericftdi
import (
"context"
"dmxconnect/hardware"
"sync"
"unsafe"
@@ -13,36 +14,36 @@ import (
/*
#include <stdlib.h>
#cgo LDFLAGS: -L${SRCDIR}/../build/bin -ldmxSender
#cgo LDFLAGS: -L${SRCDIR}/../../build/bin -ldmxSender
#include "cpp/include/dmxSenderBridge.h"
*/
import "C"
// FTDIEndpoint contains the data of an FTDI endpoint
type FTDIEndpoint struct {
// Endpoint contains the data of an FTDI endpoint
type Endpoint struct {
wg sync.WaitGroup
info EndpointInfo // The endpoint basic data
dmxSender unsafe.Pointer // The command object for piloting the DMX ouptut
info hardware.EndpointInfo // The endpoint basic data
dmxSender unsafe.Pointer // The command object for piloting the DMX ouptut
}
// NewFTDIEndpoint creates a new FTDI endpoint
func NewFTDIEndpoint(info EndpointInfo) *FTDIEndpoint {
// NewEndpoint creates a new FTDI endpoint
func NewEndpoint(info hardware.EndpointInfo) *Endpoint {
log.Info().Str("file", "FTDIEndpoint").Str("name", info.Name).Str("s/n", info.SerialNumber).Msg("FTDI endpoint created")
return &FTDIEndpoint{
return &Endpoint{
info: info,
dmxSender: nil,
}
}
// Connect connects the FTDI endpoint
func (p *FTDIEndpoint) Connect(ctx context.Context) error {
func (p *Endpoint) Connect(ctx context.Context) error {
// Check if the device has already been created
if p.dmxSender != nil {
return errors.Errorf("the DMX device has already been created!")
}
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusConnecting)
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusConnecting)
// Create the DMX sender
p.dmxSender = C.dmx_create()
@@ -51,7 +52,7 @@ func (p *FTDIEndpoint) Connect(ctx context.Context) error {
serialNumber := C.CString(p.info.SerialNumber)
defer C.free(unsafe.Pointer(serialNumber))
if C.dmx_connect(p.dmxSender, serialNumber) != C.DMX_OK {
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusDisconnected)
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusDisconnected)
log.Error().Str("file", "FTDIEndpoint").Str("s/n", p.info.SerialNumber).Msg("unable to connect the DMX device")
return errors.Errorf("unable to connect '%s'", p.info.SerialNumber)
}
@@ -63,13 +64,13 @@ func (p *FTDIEndpoint) Connect(ctx context.Context) error {
_ = p.Disconnect(ctx)
}()
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusDeactivated)
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusDeactivated)
log.Trace().Str("file", "FTDIEndpoint").Str("s/n", p.info.SerialNumber).Msg("DMX device connected successfully")
return nil
}
// Disconnect disconnects the FTDI endpoint
func (p *FTDIEndpoint) Disconnect(ctx context.Context) error {
func (p *Endpoint) Disconnect(ctx context.Context) error {
// Check if the device has already been created
if p.dmxSender == nil {
return errors.Errorf("the DMX device has not been connected!")
@@ -81,12 +82,12 @@ func (p *FTDIEndpoint) Disconnect(ctx context.Context) error {
// Reset the pointer to the endpoint
p.dmxSender = nil
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusDisconnected)
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusDisconnected)
return nil
}
// Activate activates the FTDI endpoint
func (p *FTDIEndpoint) Activate(ctx context.Context) error {
func (p *Endpoint) Activate(ctx context.Context) error {
// Check if the device has already been created
if p.dmxSender == nil {
return errors.Errorf("the DMX sender has not been created!")
@@ -103,14 +104,14 @@ func (p *FTDIEndpoint) Activate(ctx context.Context) error {
C.dmx_setValue(p.dmxSender, C.uint16_t(1), C.uint8_t(255))
C.dmx_setValue(p.dmxSender, C.uint16_t(5), C.uint8_t(255))
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusActivated)
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusActivated)
log.Trace().Str("file", "FTDIEndpoint").Str("s/n", p.info.SerialNumber).Msg("DMX device activated successfully")
return nil
}
// Deactivate deactivates the FTDI endpoint
func (p *FTDIEndpoint) Deactivate(ctx context.Context) error {
func (p *Endpoint) Deactivate(ctx context.Context) error {
// Check if the device has already been created
if p.dmxSender == nil {
return errors.Errorf("the DMX device has not been created!")
@@ -123,18 +124,18 @@ func (p *FTDIEndpoint) Deactivate(ctx context.Context) error {
return errors.Errorf("unable to deactivate the DMX sender!")
}
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusDeactivated)
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusDeactivated)
log.Trace().Str("file", "FTDIEndpoint").Str("s/n", p.info.SerialNumber).Msg("DMX device deactivated successfully")
return nil
}
// SetSettings sets a specific setting for this endpoint
func (p *FTDIEndpoint) SetSettings(ctx context.Context, settings map[string]any) error {
func (p *Endpoint) SetSettings(ctx context.Context, settings map[string]any) error {
return errors.Errorf("unable to set the settings: not implemented")
}
// SetDeviceProperty sends a command to the specified device
func (p *FTDIEndpoint) SetDeviceProperty(ctx context.Context, channelNumber uint32, channelValue byte) error {
func (p *Endpoint) SetDeviceProperty(ctx context.Context, channelNumber uint32, channelValue byte) error {
// Check if the device has already been created
if p.dmxSender == nil {
return errors.Errorf("the DMX device has not been created!")
@@ -153,17 +154,17 @@ func (p *FTDIEndpoint) SetDeviceProperty(ctx context.Context, channelNumber uint
}
// GetSettings gets the endpoint settings
func (p *FTDIEndpoint) GetSettings() map[string]interface{} {
func (p *Endpoint) GetSettings() map[string]interface{} {
return map[string]interface{}{}
}
// GetInfo gets all the endpoint information
func (p *FTDIEndpoint) GetInfo() EndpointInfo {
func (p *Endpoint) GetInfo() hardware.EndpointInfo {
return p.info
}
// WaitStop wait about the endpoint to close
func (p *FTDIEndpoint) WaitStop() error {
func (p *Endpoint) WaitStop() error {
log.Info().Str("file", "FTDIEndpoint").Str("s/n", p.info.SerialNumber).Msg("waiting for FTDI endpoint to close...")
p.wg.Wait()
log.Info().Str("file", "FTDIEndpoint").Str("s/n", p.info.SerialNumber).Msg("FTDI endpoint closed!")

View File

@@ -1,7 +1,8 @@
package hardware
package genericftdi
import (
"context"
"dmxconnect/hardware"
"fmt"
goRuntime "runtime"
"sync"
@@ -13,45 +14,45 @@ import (
/*
#include <stdlib.h>
#cgo LDFLAGS: -L${SRCDIR}/../build/bin -ldetectFTDI
#cgo LDFLAGS: -L${SRCDIR}/../../build/bin -ldetectFTDI
#include "cpp/include/detectFTDIBridge.h"
*/
import "C"
// FTDIProvider manages all the FTDI endpoints
type FTDIProvider struct {
// Provider manages all the FTDI endpoints
type Provider struct {
wg sync.WaitGroup
mu sync.Mutex
detected map[string]*FTDIEndpoint // Detected endpoints
detected map[string]*Endpoint // Detected endpoints
scanEvery time.Duration // Scans endpoints periodically
onArrival func(context.Context, Endpoint) // When a endpoint arrives
onRemoval func(context.Context, Endpoint) // When a endpoint goes away
onArrival func(context.Context, hardware.Endpoint) // When a endpoint arrives
onRemoval func(context.Context, hardware.Endpoint) // When a endpoint goes away
}
// NewFTDIProvider creates a new FTDI provider
func NewFTDIProvider(scanEvery time.Duration) *FTDIProvider {
// NewProvider creates a new FTDI provider
func NewProvider(scanEvery time.Duration) *Provider {
log.Trace().Str("file", "FTDIProvider").Msg("FTDI provider created")
return &FTDIProvider{
return &Provider{
scanEvery: scanEvery,
detected: make(map[string]*FTDIEndpoint),
detected: make(map[string]*Endpoint),
}
}
// OnArrival is the callback function when a new endpoint arrives
func (f *FTDIProvider) OnArrival(cb func(context.Context, Endpoint)) {
func (f *Provider) OnArrival(cb func(context.Context, hardware.Endpoint)) {
f.onArrival = cb
}
// OnRemoval i the callback when a endpoint goes away
func (f *FTDIProvider) OnRemoval(cb func(context.Context, Endpoint)) {
func (f *Provider) OnRemoval(cb func(context.Context, hardware.Endpoint)) {
f.onRemoval = cb
}
// Initialize initializes the FTDI provider
func (f *FTDIProvider) Initialize() error {
func (f *Provider) Initialize() error {
// Check platform
if goRuntime.GOOS != "windows" {
log.Error().Str("file", "FTDIProvider").Str("platform", goRuntime.GOOS).Msg("FTDI provider not compatible with your platform")
@@ -62,17 +63,17 @@ func (f *FTDIProvider) Initialize() error {
}
// Create creates a new endpoint, based on the endpoint information (manually created)
func (f *FTDIProvider) Create(ctx context.Context, endpointInfo EndpointInfo) (EndpointInfo, error) {
return EndpointInfo{}, nil
func (f *Provider) Create(ctx context.Context, endpointInfo hardware.EndpointInfo) (hardware.EndpointInfo, error) {
return hardware.EndpointInfo{}, nil
}
// Remove removes an existing endpoint (manually created)
func (f *FTDIProvider) Remove(ctx context.Context, endpoint Endpoint) error {
func (f *Provider) Remove(ctx context.Context, endpoint hardware.Endpoint) error {
return nil
}
// Start starts the provider and search for endpoints
func (f *FTDIProvider) Start(ctx context.Context) error {
func (f *Provider) Start(ctx context.Context) error {
f.wg.Add(1)
go func() {
ticker := time.NewTicker(f.scanEvery)
@@ -96,12 +97,12 @@ func (f *FTDIProvider) Start(ctx context.Context) error {
}
// GetName returns the name of the driver
func (f *FTDIProvider) GetName() string {
func (f *Provider) GetName() string {
return "FTDI"
}
// scanEndpoints scans the FTDI endpoints
func (f *FTDIProvider) scanEndpoints(ctx context.Context) error {
func (f *Provider) scanEndpoints(ctx context.Context) error {
log.Trace().Str("file", "FTDIProvider").Msg("FTDI scan triggered")
count := int(C.get_endpoints_number())
@@ -117,7 +118,7 @@ func (f *FTDIProvider) scanEndpoints(ctx context.Context) error {
C.get_ftdi_devices((*C.FTDIEndpointC)(devicesPtr), C.int(count))
currentMap := make(map[string]EndpointInfo)
currentMap := make(map[string]hardware.EndpointInfo)
for i := 0; i < count; i++ {
d := devices[i]
@@ -126,7 +127,7 @@ func (f *FTDIProvider) scanEndpoints(ctx context.Context) error {
desc := C.GoString(d.description)
// isOpen := d.isOpen != 0
currentMap[sn] = EndpointInfo{
currentMap[sn] = hardware.EndpointInfo{
SerialNumber: sn,
Name: desc,
// IsOpen: isOpen,
@@ -144,7 +145,7 @@ func (f *FTDIProvider) scanEndpoints(ctx context.Context) error {
// If the scanned endpoint isn't in the detected list, create it
if _, known := f.detected[sn]; !known {
endpoint := NewFTDIEndpoint(endpointData)
endpoint := NewEndpoint(endpointData)
if f.onArrival != nil {
f.onArrival(ctx, endpoint)
@@ -169,7 +170,7 @@ func (f *FTDIProvider) scanEndpoints(ctx context.Context) error {
}
// WaitStop stops the provider
func (f *FTDIProvider) WaitStop() error {
func (f *Provider) WaitStop() error {
log.Trace().Str("file", "FTDIProvider").Msg("stopping the FTDI provider...")
// Wait for goroutines to stop

View File

@@ -0,0 +1,7 @@
@REM Compiling DETECTFTDI library
g++ -shared -o ../../../build/bin/libdetectFTDI.dll src/detectFTDI.cpp -fPIC -Wl,--out-implib,../../../build/bin/libdetectFTDI.dll.a -L"lib" -lftd2xx -mwindows
@REM Compiling DMXSENDER library
g++ -shared -o ../../../build/bin/libdmxSender.dll src/dmxSender.cpp -fPIC -Wl,--out-implib,../../../build/bin/libdmxSender.dll.a -L"lib" -lftd2xx -mwindows
@REM g++ -shared -o libdmxSender.so dmxSender.cpp -fPIC -I"include" -L"lib" -lftd2xx -mwindows

View File

@@ -1,7 +1,8 @@
package hardware
package genericmidi
import (
"context"
"dmxconnect/hardware"
"fmt"
"sync"
@@ -10,30 +11,30 @@ import (
"gitlab.com/gomidi/midi"
)
// MIDIDevice represents the device to control
type MIDIDevice struct {
ID string // Device ID
Mapping MappingInfo // Device mapping configuration
// Device represents the device to control
type Device struct {
ID string // Device ID
Mapping hardware.MappingInfo // Device mapping configuration
}
// ------------------- //
// MIDIEndpoint contains the data of a MIDI endpoint
type MIDIEndpoint struct {
// Endpoint contains the data of a MIDI endpoint
type Endpoint struct {
wg sync.WaitGroup
inputPorts []midi.In
outputsPorts []midi.Out
info EndpointInfo // The endpoint info
info hardware.EndpointInfo // The endpoint info
settings map[string]interface{} // The settings of the endpoint
devices []MIDIDevice // All the MIDI devices that the endpoint can handle
devices []Device // All the MIDI devices that the endpoint can handle
}
// NewMIDIEndpoint creates a new MIDI endpoint
func NewMIDIEndpoint(endpointData EndpointInfo, inputs []midi.In, outputs []midi.Out) *MIDIEndpoint {
// NewEndpoint creates a new MIDI endpoint
func NewEndpoint(endpointData hardware.EndpointInfo, inputs []midi.In, outputs []midi.Out) *Endpoint {
log.Trace().Str("file", "MIDIEndpoint").Str("name", endpointData.Name).Str("s/n", endpointData.SerialNumber).Msg("MIDI endpoint created")
return &MIDIEndpoint{
return &Endpoint{
info: endpointData,
inputPorts: inputs,
outputsPorts: outputs,
@@ -42,19 +43,19 @@ func NewMIDIEndpoint(endpointData EndpointInfo, inputs []midi.In, outputs []midi
}
// Connect connects the MIDI endpoint
func (p *MIDIEndpoint) Connect(ctx context.Context) error {
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusConnecting)
func (p *Endpoint) Connect(ctx context.Context) error {
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusConnecting)
// Open input ports
for _, port := range p.inputPorts {
err := port.Open()
if err != nil {
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusDisconnected)
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusDisconnected)
return fmt.Errorf("unable to open the MIDI IN port: %w", err)
}
port.SetListener(func(msg []byte, delta int64) {
// Emit the event to the front
runtime.EventsEmit(ctx, string(EndpointEventEmitted), p.info.SerialNumber, msg)
runtime.EventsEmit(ctx, string(hardware.EndpointEventEmitted), p.info.SerialNumber, msg)
log.Debug().Str("message", string(msg)).Int64("delta", delta).Msg("message received")
})
log.Info().Str("name", port.String()).Msg("port open successfully")
@@ -67,13 +68,13 @@ func (p *MIDIEndpoint) Connect(ctx context.Context) error {
_ = p.Disconnect(ctx)
}()
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusDeactivated)
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusDeactivated)
return nil
}
// Disconnect disconnects the MIDI endpoint
func (p *MIDIEndpoint) Disconnect(ctx context.Context) error {
func (p *Endpoint) Disconnect(ctx context.Context) error {
// Close all inputs ports
for _, port := range p.inputPorts {
err := port.Close()
@@ -81,47 +82,47 @@ func (p *MIDIEndpoint) Disconnect(ctx context.Context) error {
return fmt.Errorf("unable to close the MIDI IN port: %w", err)
}
}
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusDisconnected)
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusDisconnected)
return nil
}
// Activate activates the MIDI endpoint
func (p *MIDIEndpoint) Activate(ctx context.Context) error {
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusActivated)
func (p *Endpoint) Activate(ctx context.Context) error {
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusActivated)
return nil
}
// Deactivate deactivates the MIDI endpoint
func (p *MIDIEndpoint) Deactivate(ctx context.Context) error {
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusDeactivated)
func (p *Endpoint) Deactivate(ctx context.Context) error {
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusDeactivated)
return nil
}
// SetSettings sets a specific setting for this endpoint
func (p *MIDIEndpoint) SetSettings(ctx context.Context, settings map[string]any) error {
func (p *Endpoint) SetSettings(ctx context.Context, settings map[string]any) error {
p.settings = settings
return nil
}
// SetDeviceProperty - not implemented for this kind of endpoint
func (p *MIDIEndpoint) SetDeviceProperty(context.Context, uint32, byte) error {
func (p *Endpoint) SetDeviceProperty(context.Context, uint32, byte) error {
return nil
}
// GetSettings gets the endpoint settings
func (p *MIDIEndpoint) GetSettings() map[string]interface{} {
func (p *Endpoint) GetSettings() map[string]interface{} {
return p.settings
}
// GetInfo gets the endpoint information
func (p *MIDIEndpoint) GetInfo() EndpointInfo {
func (p *Endpoint) GetInfo() hardware.EndpointInfo {
return p.info
}
// WaitStop wait about the endpoint to close
func (p *MIDIEndpoint) WaitStop() error {
func (p *Endpoint) WaitStop() error {
log.Info().Str("file", "MIDIEndpoint").Str("s/n", p.info.SerialNumber).Msg("waiting for MIDI endpoint to close...")
p.wg.Wait()
log.Info().Str("file", "MIDIEndpoint").Str("s/n", p.info.SerialNumber).Msg("MIDI endpoint closed!")

View File

@@ -1,7 +1,8 @@
package hardware
package genericmidi
import (
"context"
"dmxconnect/hardware"
"fmt"
"regexp"
"strconv"
@@ -13,56 +14,56 @@ import (
"gitlab.com/gomidi/rtmididrv"
)
// MIDIProvider represents how the protocol is defined
type MIDIProvider struct {
// Provider represents how the protocol is defined
type Provider struct {
wg sync.WaitGroup
mu sync.Mutex
detected map[string]*MIDIEndpoint // Detected endpoints
detected map[string]*Endpoint // Detected endpoints
scanEvery time.Duration // Scans endpoints periodically
onArrival func(context.Context, Endpoint) // When a endpoint arrives
onRemoval func(context.Context, Endpoint) // When a endpoint goes away
onArrival func(context.Context, hardware.Endpoint) // When a endpoint arrives
onRemoval func(context.Context, hardware.Endpoint) // When a endpoint goes away
}
// NewMIDIProvider creates a new MIDI provider
func NewMIDIProvider(scanEvery time.Duration) *MIDIProvider {
// NewProvider creates a new MIDI provider
func NewProvider(scanEvery time.Duration) *Provider {
log.Trace().Str("file", "MIDIProvider").Msg("MIDI provider created")
return &MIDIProvider{
return &Provider{
scanEvery: scanEvery,
detected: make(map[string]*MIDIEndpoint),
detected: make(map[string]*Endpoint),
}
}
// OnArrival is the callback function when a new endpoint arrives
func (f *MIDIProvider) OnArrival(cb func(context.Context, Endpoint)) {
func (f *Provider) OnArrival(cb func(context.Context, hardware.Endpoint)) {
f.onArrival = cb
}
// OnRemoval i the callback when a endpoint goes away
func (f *MIDIProvider) OnRemoval(cb func(context.Context, Endpoint)) {
func (f *Provider) OnRemoval(cb func(context.Context, hardware.Endpoint)) {
f.onRemoval = cb
}
// Initialize initializes the MIDI driver
func (f *MIDIProvider) Initialize() error {
func (f *Provider) Initialize() error {
log.Trace().Str("file", "MIDIProvider").Msg("MIDI provider initialized")
return nil
}
// Create creates a new endpoint, based on the endpoint information (manually created)
func (f *MIDIProvider) Create(ctx context.Context, endpointInfo EndpointInfo) (EndpointInfo, error) {
return EndpointInfo{}, nil
func (f *Provider) Create(ctx context.Context, endpointInfo hardware.EndpointInfo) (hardware.EndpointInfo, error) {
return hardware.EndpointInfo{}, nil
}
// Remove removes an existing endpoint (manually created)
func (f *MIDIProvider) Remove(ctx context.Context, endpoint Endpoint) error {
func (f *Provider) Remove(ctx context.Context, endpoint hardware.Endpoint) error {
return nil
}
// Start starts the provider and search for endpoints
func (f *MIDIProvider) Start(ctx context.Context) error {
func (f *Provider) Start(ctx context.Context) error {
f.wg.Add(1)
go func() {
ticker := time.NewTicker(f.scanEvery)
@@ -86,7 +87,7 @@ func (f *MIDIProvider) Start(ctx context.Context) error {
}
// WaitStop stops the provider
func (f *MIDIProvider) WaitStop() error {
func (f *Provider) WaitStop() error {
log.Trace().Str("file", "MIDIProvider").Msg("stopping the MIDI provider...")
// Wait for goroutines to stop
@@ -97,7 +98,7 @@ func (f *MIDIProvider) WaitStop() error {
}
// GetName returns the name of the driver
func (f *MIDIProvider) GetName() string {
func (f *Provider) GetName() string {
return "MIDI"
}
@@ -123,8 +124,8 @@ func splitStringAndNumber(input string) (string, int, error) {
}
// scanEndpoints scans the MIDI endpoints
func (f *MIDIProvider) scanEndpoints(ctx context.Context) error {
currentMap := make(map[string]*MIDIEndpoint)
func (f *Provider) scanEndpoints(ctx context.Context) error {
currentMap := make(map[string]*Endpoint)
drv, err := rtmididrv.New()
if err != nil {
@@ -148,8 +149,8 @@ func (f *MIDIProvider) scanEndpoints(ctx context.Context) error {
sn := strings.ReplaceAll(strings.ToLower(baseName), " ", "_")
if _, ok := currentMap[sn]; !ok {
currentMap[sn] = &MIDIEndpoint{
info: EndpointInfo{
currentMap[sn] = &Endpoint{
info: hardware.EndpointInfo{
Name: baseName,
SerialNumber: sn,
ProtocolName: "MIDI",
@@ -177,8 +178,8 @@ func (f *MIDIProvider) scanEndpoints(ctx context.Context) error {
sn := strings.ReplaceAll(strings.ToLower(baseName), " ", "_")
if _, ok := currentMap[sn]; !ok {
currentMap[sn] = &MIDIEndpoint{
info: EndpointInfo{
currentMap[sn] = &Endpoint{
info: hardware.EndpointInfo{
Name: baseName,
SerialNumber: sn,
ProtocolName: "MIDI",
@@ -196,7 +197,7 @@ func (f *MIDIProvider) scanEndpoints(ctx context.Context) error {
for sn, discovery := range currentMap {
if _, known := f.detected[sn]; !known {
endpoint := NewMIDIEndpoint(discovery.info, discovery.inputPorts, discovery.outputsPorts)
endpoint := NewEndpoint(discovery.info, discovery.inputPorts, discovery.outputsPorts)
f.detected[sn] = endpoint

View File

@@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"sync"
"time"
"github.com/rs/zerolog/log"
"github.com/wailsapp/wails/v2/pkg/runtime"
@@ -165,12 +164,6 @@ func (h *Manager) SetEndpointSettings(ctx context.Context, endpointSN string, se
// Start starts to find new endpoint events
func (h *Manager) Start(ctx context.Context) error {
// Register all the providers to use as hardware scanners
h.RegisterProvider(NewFTDIProvider(3 * time.Second))
h.RegisterProvider(NewOS2LProvider())
h.RegisterProvider(NewMIDIProvider(3 * time.Second))
for providerName, provider := range h.providers {
// Initialize the provider

View File

@@ -1,7 +1,8 @@
package hardware
package os2l
import (
"context"
"dmxconnect/hardware"
"encoding/json"
"fmt"
"net"
@@ -13,8 +14,8 @@ import (
"github.com/wailsapp/wails/v2/pkg/runtime"
)
// OS2LMessage represents an OS2L message
type OS2LMessage struct {
// Message represents an OS2L message
type Message struct {
Event string `json:"evt"`
Name string `json:"name"`
State string `json:"state"`
@@ -22,22 +23,22 @@ type OS2LMessage struct {
Param float64 `json:"param"`
}
// OS2LEndpoint contains the data of an OS2L endpoint
type OS2LEndpoint struct {
// Endpoint contains the data of an OS2L endpoint
type Endpoint struct {
wg sync.WaitGroup
info EndpointInfo // The basic info for this endpoint
serverIP string // OS2L server IP
serverPort int // OS2L server port
listener net.Listener // Net listener (TCP)
listenerCancel context.CancelFunc // Call this function to cancel the endpoint activation
info hardware.EndpointInfo // The basic info for this endpoint
serverIP string // OS2L server IP
serverPort int // OS2L server port
listener net.Listener // Net listener (TCP)
listenerCancel context.CancelFunc // Call this function to cancel the endpoint activation
eventCallback func(any) // This callback is called for returning events
}
// NewOS2LEndpoint creates a new OS2L endpoint
func NewOS2LEndpoint(endpointData EndpointInfo) (*OS2LEndpoint, error) {
endpoint := &OS2LEndpoint{
func NewOS2LEndpoint(endpointData hardware.EndpointInfo) (*Endpoint, error) {
endpoint := &Endpoint{
info: endpointData,
listener: nil,
eventCallback: nil,
@@ -47,13 +48,13 @@ func NewOS2LEndpoint(endpointData EndpointInfo) (*OS2LEndpoint, error) {
}
// SetEventCallback sets the callback for returning events
func (p *OS2LEndpoint) SetEventCallback(eventCallback func(any)) {
func (p *Endpoint) SetEventCallback(eventCallback func(any)) {
p.eventCallback = eventCallback
}
// Connect connects the OS2L endpoint
func (p *OS2LEndpoint) Connect(ctx context.Context) error {
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusConnecting)
func (p *Endpoint) Connect(ctx context.Context) error {
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusConnecting)
var err error
addr := net.TCPAddr{Port: p.serverPort, IP: net.ParseIP(p.serverIP)}
@@ -61,18 +62,18 @@ func (p *OS2LEndpoint) Connect(ctx context.Context) error {
log.Debug().Any("addr", addr).Msg("parametres de connexion à la connexion")
p.listener, err = net.ListenTCP("tcp", &addr)
if err != nil {
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusDisconnected)
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusDisconnected)
return fmt.Errorf("unable to set the OS2L TCP listener")
}
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusDeactivated)
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusDeactivated)
log.Info().Str("file", "OS2LEndpoint").Msg("OS2L endpoint connected")
return nil
}
// handleMessage handles an OS2L message
func (p *OS2LEndpoint) handleMessage(raw []byte) error {
message := OS2LMessage{}
func (p *Endpoint) handleMessage(raw []byte) error {
message := Message{}
err := json.Unmarshal(raw, &message)
if err != nil {
return fmt.Errorf("Unable to parse the OS2L message: %w", err)
@@ -86,7 +87,7 @@ func (p *OS2LEndpoint) handleMessage(raw []byte) error {
}
// loadSettings check and load the settings in the endpoint
func (p *OS2LEndpoint) loadSettings(settings map[string]any) error {
func (p *Endpoint) loadSettings(settings map[string]any) error {
// Check if the IP exists
serverIP, found := settings["os2lIp"]
if !found {
@@ -119,21 +120,21 @@ func (p *OS2LEndpoint) loadSettings(settings map[string]any) error {
}
// Disconnect disconnects the MIDI endpoint
func (p *OS2LEndpoint) Disconnect(ctx context.Context) error {
func (p *Endpoint) Disconnect(ctx context.Context) error {
// Close the TCP listener if not null
if p.listener != nil {
p.listener.Close()
}
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusDisconnected)
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusDisconnected)
log.Info().Str("file", "OS2LEndpoint").Msg("OS2L endpoint disconnected")
return nil
}
// Activate activates the OS2L endpoint
func (p *OS2LEndpoint) Activate(ctx context.Context) error {
func (p *Endpoint) Activate(ctx context.Context) error {
// Create a derived context to handle deactivation
var listenerCtx context.Context
listenerCtx, p.listenerCancel = context.WithCancel(ctx)
@@ -198,7 +199,7 @@ func (p *OS2LEndpoint) Activate(ctx context.Context) error {
}
}
}()
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusActivated)
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusActivated)
log.Info().Str("file", "OS2LEndpoint").Msg("OS2L endpoint activated")
@@ -206,7 +207,7 @@ func (p *OS2LEndpoint) Activate(ctx context.Context) error {
}
// Deactivate deactivates the OS2L endpoint
func (p *OS2LEndpoint) Deactivate(ctx context.Context) error {
func (p *Endpoint) Deactivate(ctx context.Context) error {
if p.listener == nil {
return fmt.Errorf("the listener isn't defined")
}
@@ -216,14 +217,14 @@ func (p *OS2LEndpoint) Deactivate(ctx context.Context) error {
p.listenerCancel()
}
runtime.EventsEmit(ctx, string(EndpointStatusUpdated), p.GetInfo(), EndpointStatusDeactivated)
runtime.EventsEmit(ctx, string(hardware.EndpointStatusUpdated), p.GetInfo(), hardware.EndpointStatusDeactivated)
log.Info().Str("file", "OS2LEndpoint").Msg("OS2L endpoint deactivated")
return nil
}
// SetSettings sets a specific setting for this endpoint
func (p *OS2LEndpoint) SetSettings(ctx context.Context, settings map[string]any) error {
func (p *Endpoint) SetSettings(ctx context.Context, settings map[string]any) error {
err := p.loadSettings(settings)
if err != nil {
return fmt.Errorf("unable to load settings: %w", err)
@@ -260,12 +261,12 @@ func (p *OS2LEndpoint) SetSettings(ctx context.Context, settings map[string]any)
}
// SetDeviceProperty - not implemented for this kind of endpoint
func (p *OS2LEndpoint) SetDeviceProperty(context.Context, uint32, byte) error {
func (p *Endpoint) SetDeviceProperty(context.Context, uint32, byte) error {
return nil
}
// GetSettings gets the endpoint settings
func (p *OS2LEndpoint) GetSettings() map[string]any {
func (p *Endpoint) GetSettings() map[string]any {
return map[string]any{
"os2lIp": p.serverIP,
"os2lPort": p.serverPort,
@@ -273,12 +274,12 @@ func (p *OS2LEndpoint) GetSettings() map[string]any {
}
// GetInfo gets the endpoint information
func (p *OS2LEndpoint) GetInfo() EndpointInfo {
func (p *Endpoint) GetInfo() hardware.EndpointInfo {
return p.info
}
// WaitStop stops the endpoint
func (p *OS2LEndpoint) WaitStop() error {
func (p *Endpoint) WaitStop() error {
log.Info().Str("file", "OS2LEndpoint").Str("s/n", p.info.SerialNumber).Msg("waiting for OS2L endpoint to close...")
p.wg.Wait()
log.Info().Str("file", "OS2LEndpoint").Str("s/n", p.info.SerialNumber).Msg("OS2L endpoint closed!")

View File

@@ -1,7 +1,8 @@
package hardware
package os2l
import (
"context"
"dmxconnect/hardware"
"fmt"
"math/rand"
"strings"
@@ -11,43 +12,43 @@ import (
"github.com/wailsapp/wails/v2/pkg/runtime"
)
// OS2LProvider represents how the protocol is defined
type OS2LProvider struct {
// Provider represents how the protocol is defined
type Provider struct {
wg sync.WaitGroup
mu sync.Mutex
detected map[string]*OS2LEndpoint // The list of saved endpoints
detected map[string]*Endpoint // The list of saved endpoints
onArrival func(context.Context, Endpoint) // When a endpoint arrives
onRemoval func(context.Context, Endpoint) // When a endpoint goes away
onArrival func(context.Context, hardware.Endpoint) // When a endpoint arrives
onRemoval func(context.Context, hardware.Endpoint) // When a endpoint goes away
}
// NewOS2LProvider creates a new OS2L provider
func NewOS2LProvider() *OS2LProvider {
// NewProvider creates a new OS2L provider
func NewProvider() *Provider {
log.Trace().Str("file", "OS2LProvider").Msg("OS2L provider created")
return &OS2LProvider{
detected: make(map[string]*OS2LEndpoint),
return &Provider{
detected: make(map[string]*Endpoint),
}
}
// Initialize initializes the provider
func (f *OS2LProvider) Initialize() error {
func (f *Provider) Initialize() error {
log.Trace().Str("file", "OS2LProvider").Msg("OS2L provider initialized")
return nil
}
// OnArrival is the callback function when a new endpoint arrives
func (f *OS2LProvider) OnArrival(cb func(context.Context, Endpoint)) {
func (f *Provider) OnArrival(cb func(context.Context, hardware.Endpoint)) {
f.onArrival = cb
}
// OnRemoval if the callback when a endpoint goes away
func (f *OS2LProvider) OnRemoval(cb func(context.Context, Endpoint)) {
func (f *Provider) OnRemoval(cb func(context.Context, hardware.Endpoint)) {
f.onRemoval = cb
}
// Create creates a new endpoint, based on the endpoint information (manually created)
func (f *OS2LProvider) Create(ctx context.Context, endpointInfo EndpointInfo) (EndpointInfo, error) {
func (f *Provider) Create(ctx context.Context, endpointInfo hardware.EndpointInfo) (hardware.EndpointInfo, error) {
// If the SerialNumber is empty, generate another one
if endpointInfo.SerialNumber == "" {
endpointInfo.SerialNumber = strings.ToUpper(fmt.Sprintf("%08x", rand.Intn(1<<32)))
@@ -56,12 +57,12 @@ func (f *OS2LProvider) Create(ctx context.Context, endpointInfo EndpointInfo) (E
// Create a new OS2L endpoint
endpoint, err := NewOS2LEndpoint(endpointInfo)
if err != nil {
return EndpointInfo{}, fmt.Errorf("unable to create the OS2L endpoint: %w", err)
return hardware.EndpointInfo{}, fmt.Errorf("unable to create the OS2L endpoint: %w", err)
}
// Set the event callback
endpoint.SetEventCallback(func(event any) {
runtime.EventsEmit(ctx, string(EndpointEventEmitted), endpointInfo.SerialNumber, event)
runtime.EventsEmit(ctx, string(hardware.EndpointEventEmitted), endpointInfo.SerialNumber, event)
})
f.detected[endpointInfo.SerialNumber] = endpoint
@@ -73,7 +74,7 @@ func (f *OS2LProvider) Create(ctx context.Context, endpointInfo EndpointInfo) (E
}
// Remove removes an existing endpoint (manually created)
func (f *OS2LProvider) Remove(ctx context.Context, endpoint Endpoint) error {
func (f *Provider) Remove(ctx context.Context, endpoint hardware.Endpoint) error {
if f.onRemoval != nil {
f.onRemoval(ctx, endpoint)
}
@@ -82,18 +83,18 @@ func (f *OS2LProvider) Remove(ctx context.Context, endpoint Endpoint) error {
}
// GetName returns the name of the driver
func (f *OS2LProvider) GetName() string {
func (f *Provider) GetName() string {
return "OS2L"
}
// Start starts the provider
func (f *OS2LProvider) Start(ctx context.Context) error {
func (f *Provider) Start(ctx context.Context) error {
// No endpoints to scan here
return nil
}
// WaitStop stops the provider
func (f *OS2LProvider) WaitStop() error {
func (f *Provider) WaitStop() error {
log.Trace().Str("file", "OS2LProvider").Msg("stopping the OS2L provider...")
// Waiting internal tasks