You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

139 lines
3.7 KiB
Go

3 years ago
package I2C
// file has general wrappers to interact with i2c-tools
3 years ago
import (
"fmt"
_ "log"
"encoding/hex"
3 years ago
"os/exec"
3 years ago
"bytes"
"strings"
"sync"
"strconv"
"FRMS/internal/pkg/logging"
3 years ago
)
type I2CBus struct {
int
sync.Mutex
3 years ago
}
3 years ago
func NewBus(bus int) *I2CBus {
b := &I2CBus{}
b.int = bus
return b
3 years ago
}
func (b *I2CBus) Scan() map[int]bool {
3 years ago
/*
Returns all the connected devices
3 years ago
*/
b.Lock()
defer b.Unlock()
bus := strconv.Itoa(b.int)
cmd := exec.Command("i2cdetect", "-y", "-r", bus)
3 years ago
var out bytes.Buffer
var errs bytes.Buffer
cmd.Stderr = &errs
3 years ago
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
logging.Debug(logging.DError, "I2C error performing scan. %v", errs.String())
3 years ago
}
3 years ago
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)
}