generated from thinkode/modelRepository
118 lines
2.9 KiB
Go
118 lines
2.9 KiB
Go
|
|
package hardware
|
||
|
|
|
||
|
|
import (
|
||
|
|
"bufio"
|
||
|
|
"context"
|
||
|
|
_ "embed"
|
||
|
|
"fmt"
|
||
|
|
"os"
|
||
|
|
"os/exec"
|
||
|
|
goRuntime "runtime"
|
||
|
|
"strconv"
|
||
|
|
"strings"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
const (
|
||
|
|
scanDelay = 4 * time.Second // Waiting delay before scanning the FTDI devices
|
||
|
|
)
|
||
|
|
|
||
|
|
// FTDIFinder represents how the protocol is defined
|
||
|
|
type FTDIFinder struct {
|
||
|
|
peripherals map[string]Peripheral
|
||
|
|
}
|
||
|
|
|
||
|
|
// NewFTDIFinder creates a new FTDI finder
|
||
|
|
func NewFTDIFinder() *FTDIFinder {
|
||
|
|
return &FTDIFinder{
|
||
|
|
peripherals: make(map[string]Peripheral),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Initialize initializes the FTDI finder
|
||
|
|
func (f *FTDIFinder) Initialize() error {
|
||
|
|
if goRuntime.GOOS != "windows" {
|
||
|
|
return fmt.Errorf("<!> The FTDI finder is not compatible with your platform yet (%s)", goRuntime.GOOS)
|
||
|
|
}
|
||
|
|
fmt.Println("FTDI finder initialized")
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetName returns the name of the finder
|
||
|
|
func (f *FTDIFinder) GetName() string {
|
||
|
|
return "FTDI Finder"
|
||
|
|
}
|
||
|
|
|
||
|
|
//go:embed third-party/ftdi/detectFTDI.exe
|
||
|
|
var findFTDI []byte
|
||
|
|
|
||
|
|
// Scan scans the FTDI peripherals
|
||
|
|
func (f *FTDIFinder) Scan(ctx context.Context) error {
|
||
|
|
time.Sleep(scanDelay)
|
||
|
|
|
||
|
|
// Create a temporary file
|
||
|
|
tempFile, err := os.CreateTemp("", "findFTDI*.exe")
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
defer os.Remove(tempFile.Name())
|
||
|
|
|
||
|
|
// Write the embedded executable to the temp file
|
||
|
|
if _, err := tempFile.Write(findFTDI); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
tempFile.Close()
|
||
|
|
|
||
|
|
ftdiPeripherals := make(map[string]Peripheral)
|
||
|
|
|
||
|
|
finder := exec.Command(tempFile.Name())
|
||
|
|
|
||
|
|
stdout, err := finder.StdoutPipe()
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("Unable to create the stdout pipe: %s", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
stderr, err := finder.StderrPipe()
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("Unable to create the stderr pipe: %s", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
err = finder.Start()
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("Unable to find FTDI devices: %s", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
scannerErr := bufio.NewScanner(stderr)
|
||
|
|
for scannerErr.Scan() {
|
||
|
|
return fmt.Errorf("Unable to find FTDI devices: %s", scannerErr.Text())
|
||
|
|
}
|
||
|
|
|
||
|
|
scanner := bufio.NewScanner(stdout)
|
||
|
|
for scanner.Scan() {
|
||
|
|
deviceString := scanner.Text()
|
||
|
|
// The program output is like '0:1:2' where 0 is the location, 1 is the S/N and 2 is the name
|
||
|
|
deviceInfo := strings.Split(deviceString, ":")
|
||
|
|
|
||
|
|
fmt.Println("FTDI device: " + deviceString)
|
||
|
|
// Convert the location to an integer
|
||
|
|
location, err := strconv.Atoi(deviceInfo[0])
|
||
|
|
if err != nil {
|
||
|
|
location = -1
|
||
|
|
}
|
||
|
|
// Add the peripheral to the temporary list
|
||
|
|
peripheral, err := NewFTDIPeripheral(deviceInfo[2], deviceInfo[1], location)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("Unable to create the FTDI peripheral: %v", err)
|
||
|
|
}
|
||
|
|
ftdiPeripherals[deviceInfo[1]] = peripheral
|
||
|
|
}
|
||
|
|
// Compare with the current peripherals to detect arrivals/removals
|
||
|
|
removedList, addedList := comparePeripherals(f.peripherals, ftdiPeripherals)
|
||
|
|
// Emit the events
|
||
|
|
emitPeripheralsEvents(ctx, removedList, PeripheralRemoval)
|
||
|
|
emitPeripheralsEvents(ctx, addedList, PeripheralArrival)
|
||
|
|
// Store the new peripherals list
|
||
|
|
f.peripherals = ftdiPeripherals
|
||
|
|
return nil
|
||
|
|
}
|