package I2C // file has general wrappers to interact with i2c-tools import ( "fmt" _ "log" "encoding/hex" "os/exec" "bytes" "strings" "sync" "strconv" "FRMS/internal/pkg/logging" ) type I2CBus struct { int sync.Mutex } func NewBus(bus int) *I2CBus { b := &I2CBus{} b.int = bus return b } func (b *I2CBus) Scan() map[int]bool { /* Returns all the connected devices */ b.Lock() defer b.Unlock() bus := strconv.Itoa(b.int) 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 error performing scan. %v", errs.String()) } outString := out.String() // could split by \n too split := strings.SplitAfter(outString,":") // 1st entry is garbage headers and ending is always \n##: split = split[1:] // create empty slice for all the devices //var devices []i2cdev devices := map[int]bool{} //maps device addresses to active bool for i,v := range split { lst := strings.Index(v,"\n") trimmed := v[:lst] trimmed = strings.Trim(trimmed," ") // trimmed now holds just possible sensor addresses 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 := 0 if i == 0 { offset = 3 } addr := i*16 + j + offset if strings.Contains(d,"--") || strings.Contains(d,"UU") { // address is unconnected or reserved //devices = append(devices, I2Cdev{Addr:addr,Active:false}) devices[addr] = false } else { //devices = append(devices, I2Cdev{Addr:addr,Active:true,LastSeen:now}) devices[addr] = true } } } return devices } func (b *I2CBus) GetStatus(addr int) bool { b.Lock() defer b.Unlock() bus := strconv.Itoa(b.int) a := strconv.Itoa(addr) cmd := exec.Command("i2cdetect","-y","-r",bus,a,a) 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 error getting status! %v", errs.String()) } outString := out.String() split := strings.SplitAfter(outString,":") split = split[1:] // remove garbage header val := int(addr/16) // if addr = 90 90/16 = int(5.6) = 5 will be in 5th row dev := split[val] lst := strings.Index(dev,"\n") dev = dev[:lst] trimmed := strings.Trim(dev," \n") if strings.Contains(trimmed,"--") { return false } else { return true } } func (b *I2CBus) GetData(addr int) string { b.Lock() defer b.Unlock() bus := strconv.Itoa(b.int) a := strconv.FormatInt(int64(addr),16) cmd := exec.Command("i2ctransfer","-y",bus,fmt.Sprintf("r40@0x%s",a)) 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 error getting data! %v", errs.String()) } outString := out.String() split := strings.SplitAfter(outString," ") //getting chars 0x12 0x2f etc var final string for _,v := range split { trimmed := strings.TrimLeft(v, "0x ") // trimming extra bs in front of num trimmed = strings.TrimRight(trimmed," \n") // trimming back if trimmed != "ff" { final += trimmed } } ret, err := hex.DecodeString(final) if err != nil { panic(err) } return string(ret) }