Files
dmxconnect/hardware/FTDIDriver.go

152 lines
4.8 KiB
Go
Raw Normal View History

2024-12-15 13:45:46 +01:00
package hardware
import (
"bufio"
"context"
_ "embed"
"fmt"
"os"
"os/exec"
goRuntime "runtime"
"strconv"
"strings"
"time"
2024-12-29 13:09:46 +01:00
"github.com/rs/zerolog/log"
2024-12-15 13:45:46 +01:00
)
const (
scanDelay = 4 * time.Second // Waiting delay before scanning the FTDI devices
)
2024-12-23 17:22:37 +01:00
// FTDIDriver represents how the protocol is defined
type FTDIDriver struct {
2024-12-15 13:45:46 +01:00
peripherals map[string]Peripheral
}
2024-12-23 17:22:37 +01:00
// NewFTDIDriver creates a new FTDI finder
func NewFTDIDriver() *FTDIDriver {
2024-12-29 13:09:46 +01:00
log.Trace().Str("file", "FTDIDriver").Msg("FTDI driver created")
2024-12-23 17:22:37 +01:00
return &FTDIDriver{
2024-12-15 13:45:46 +01:00
peripherals: make(map[string]Peripheral),
}
}
2024-12-23 17:22:37 +01:00
// Initialize initializes the FTDI driver
func (d *FTDIDriver) Initialize() error {
2024-12-15 13:45:46 +01:00
if goRuntime.GOOS != "windows" {
2024-12-29 13:09:46 +01:00
log.Error().Str("file", "FTDIDriver").Str("platform", goRuntime.GOOS).Msg("FTDI driver not compatible with your platform")
2024-12-23 17:22:37 +01:00
return fmt.Errorf("<!> The FTDI driver is not compatible with your platform yet (%s)", goRuntime.GOOS)
2024-12-15 13:45:46 +01:00
}
2024-12-29 13:09:46 +01:00
log.Trace().Str("file", "FTDIDriver").Msg("FTDI driver initialized")
2024-12-15 13:45:46 +01:00
return nil
}
2024-12-23 17:22:37 +01:00
// GetName returns the name of the driver
func (d *FTDIDriver) GetName() string {
2024-12-20 17:18:57 +01:00
return "FTDI"
}
// GetPeripheral gets the peripheral that correspond to the specified ID
2024-12-23 17:22:37 +01:00
func (d *FTDIDriver) GetPeripheral(peripheralID string) (Peripheral, bool) {
2024-12-20 17:18:57 +01:00
// Return the specified peripheral
2024-12-23 17:22:37 +01:00
peripheral := d.peripherals[peripheralID]
2024-12-20 17:18:57 +01:00
if peripheral == nil {
2024-12-29 13:09:46 +01:00
log.Error().Str("file", "FTDIDriver").Str("peripheralID", peripheralID).Msg("unable to get this peripheral from the FTDI driver")
2024-12-20 17:18:57 +01:00
return nil, false
}
2024-12-29 13:09:46 +01:00
log.Debug().Str("file", "FTDIDriver").Str("peripheralID", peripheralID).Msg("peripheral found by the FTDI driver")
2024-12-20 17:18:57 +01:00
return peripheral, true
2024-12-15 13:45:46 +01:00
}
//go:embed third-party/ftdi/detectFTDI.exe
var findFTDI []byte
// Scan scans the FTDI peripherals
2024-12-23 17:22:37 +01:00
func (d *FTDIDriver) Scan(ctx context.Context) error {
2024-12-29 13:09:46 +01:00
log.Trace().Str("file", "FTDIDriver").Msg("FTDI scan triggered")
2024-12-15 13:45:46 +01:00
time.Sleep(scanDelay)
// Create a temporary file
tempFile, err := os.CreateTemp("", "findFTDI*.exe")
if err != nil {
return err
}
defer os.Remove(tempFile.Name())
2024-12-29 13:09:46 +01:00
log.Trace().Str("file", "FTDIDriver").Msg("has created the FIND executable temp")
2024-12-15 13:45:46 +01:00
// Write the embedded executable to the temp file
if _, err := tempFile.Write(findFTDI); err != nil {
return err
}
tempFile.Close()
2024-12-29 13:09:46 +01:00
log.Trace().Str("file", "FTDIDriver").Msg("has written the FIND executable")
2024-12-15 13:45:46 +01:00
ftdiPeripherals := make(map[string]Peripheral)
finder := exec.Command(tempFile.Name())
2024-12-29 13:09:46 +01:00
log.Trace().Str("file", "FTDIDriver").Msg("has executed the FIND executable")
2024-12-15 13:45:46 +01:00
stdout, err := finder.StdoutPipe()
if err != nil {
2024-12-29 13:09:46 +01:00
return fmt.Errorf("unable to create the stdout pipe: %s", err)
2024-12-15 13:45:46 +01:00
}
stderr, err := finder.StderrPipe()
if err != nil {
2024-12-29 13:09:46 +01:00
return fmt.Errorf("unable to create the stderr pipe: %s", err)
2024-12-15 13:45:46 +01:00
}
err = finder.Start()
if err != nil {
2024-12-29 13:09:46 +01:00
return fmt.Errorf("unable to find FTDI devices: %s", err)
2024-12-15 13:45:46 +01:00
}
scannerErr := bufio.NewScanner(stderr)
for scannerErr.Scan() {
2024-12-29 13:09:46 +01:00
return fmt.Errorf("unable to find FTDI devices: %s", scannerErr.Text())
2024-12-15 13:45:46 +01:00
}
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
2024-12-29 13:09:46 +01:00
peripheralString := scanner.Text()
2024-12-15 13:45:46 +01:00
// The program output is like '0:1:2' where 0 is the location, 1 is the S/N and 2 is the name
2024-12-29 13:09:46 +01:00
peripheralInfo := strings.Split(peripheralString, ":")
2024-12-15 13:45:46 +01:00
2024-12-29 13:09:46 +01:00
log.Debug().Str("file", "FTDIDriver").Str("peripheralName", peripheralInfo[2]).Str("peripheralSN", peripheralInfo[1]).Msg("new FTDI peripheral detected")
2024-12-15 13:45:46 +01:00
// Convert the location to an integer
2024-12-29 13:09:46 +01:00
location, err := strconv.Atoi(peripheralInfo[0])
2024-12-15 13:45:46 +01:00
if err != nil {
2024-12-29 13:09:46 +01:00
log.Warn().Str("file", "FTDIDriver").Str("peripheralName", peripheralInfo[2]).Msg("no location provided for this FTDI peripheral")
2024-12-15 13:45:46 +01:00
location = -1
}
// Add the peripheral to the temporary list
2024-12-29 13:09:46 +01:00
peripheral, err := NewFTDIPeripheral(peripheralInfo[2], peripheralInfo[1], location)
2024-12-15 13:45:46 +01:00
if err != nil {
return fmt.Errorf("Unable to create the FTDI peripheral: %v", err)
}
2024-12-29 13:09:46 +01:00
ftdiPeripherals[peripheralInfo[1]] = peripheral
log.Trace().Str("file", "FTDIDriver").Str("peripheralName", peripheralInfo[2]).Msg("successfully added the FTDI peripheral to the driver")
2024-12-15 13:45:46 +01:00
}
// Compare with the current peripherals to detect arrivals/removals
2024-12-23 17:22:37 +01:00
removedList, addedList := comparePeripherals(d.peripherals, ftdiPeripherals)
2024-12-15 13:45:46 +01:00
// Emit the events
emitPeripheralsEvents(ctx, removedList, PeripheralRemoval)
2024-12-29 13:09:46 +01:00
log.Info().Str("file", "FTDIDriver").Msg("FTDI remove list emitted to the front")
2024-12-15 13:45:46 +01:00
emitPeripheralsEvents(ctx, addedList, PeripheralArrival)
2024-12-29 13:09:46 +01:00
log.Info().Str("file", "FTDIDriver").Msg("FTDI add list emitted to the front")
2024-12-15 13:45:46 +01:00
// Store the new peripherals list
2024-12-23 17:22:37 +01:00
d.peripherals = ftdiPeripherals
return nil
}
// CreatePeripheral is not implemented here
func (d *FTDIDriver) CreatePeripheral(context.Context) (Peripheral, error) {
return nil, nil
}
// RemovePeripheral is not implemented here
func (d *FTDIDriver) RemovePeripheral(serialNumber string) error {
2024-12-15 13:45:46 +01:00
return nil
}