// package i2c wraps the [i2c package] to interact with the i2c // with devices on the bus // // [i2c package]: https://pkg.go.dev/periph.io/x/conn/v3/i2c#pkg-overview package i2c import ( "FRMS/internal/pkg/logging" "bytes" "fmt" _ "log" "os/exec" "strconv" "strings" ) // GetConnected returns a map of each device address and its current // connection status. func GetConnected(b int) (map[int]bool, error) { bus := strconv.Itoa(b) devices := make(map[int]bool) // only keys cmd := exec.Command("i2cdetect", "-y", "-r", bus) var out bytes.Buffer var errs bytes.Buffer cmd.Stderr = &errs cmd.Stdout = &out if err := cmd.Run(); err != nil { logging.Debug( logging.DError, "I2C scan error %v", errs.String(), ) return devices, err } // parsing the command output outString := out.String() split := strings.SplitAfter(outString, ":") // 1st entry is reserved and ending is always \n##: split = split[1:] // create empty slice for all the devices for i, v := range split { lastDevice := strings.Index(v, "\n") trimmed := v[:lastDevice] trimmed = strings.Trim(trimmed, " ") count := strings.Split(trimmed, " ") for j, d := range count { // the first row has to be offset by 3 but after its just i*16 + j offset := j if i == 0 { offset += 3 } addr := i*16 + offset if !strings.Contains(d, "--") && !strings.Contains(d, "UU") { devices[addr] = true } } } return devices, nil } // SendCmd sends an arbitrary command string to the device at addr on i2c bus b. // Command will be converted from a string to bytes before // attempting to be sent. func SendCmd(b, addr int, command string) (string, error) { var cmd *exec.Cmd bus := strconv.Itoa(b) // default to an empty read operation := "r20" frmt_cmd := "" if command != "" { // command, do write operation = fmt.Sprintf("w%d", len(command)) // write // formatting cmd for _, char := range command { // loop over string frmt_cmd += fmt.Sprintf("0x%x", char) } cmd = exec.Command("i2ctransfer", "-y", bus, fmt.Sprintf("%s@0x%x", operation, addr), frmt_cmd) } else { // reading cmd = exec.Command("i2ctransfer", "-y", bus, fmt.Sprintf("%s@0x%x", operation, addr)) } // execute command var out bytes.Buffer var errs bytes.Buffer cmd.Stderr = &errs cmd.Stdout = &out if err := cmd.Run(); err != nil { logging.Debug(logging.DError, "I2C command error %v", err) return "", err } return out.String(), nil }