From 1bc13d74b244336233695851aefd08e7c108bd61 Mon Sep 17 00:00:00 2001 From: MaMe82 Date: Fri, 14 Sep 2018 15:31:53 +0200 Subject: [PATCH] Bluetooth: #21 started NAP implementation for systemd service --- ntest.go | 242 ++++++++++++++++++++ service/bluetooth.go | 509 +++++++++++++++++++++++++++++++++++++++++++ service/defaults.go | 3 + service/wifi.go | 2 +- 4 files changed, 755 insertions(+), 1 deletion(-) create mode 100644 service/bluetooth.go diff --git a/ntest.go b/ntest.go index 06ab7d0..946ae35 100644 --- a/ntest.go +++ b/ntest.go @@ -1 +1,243 @@ package main + +import ( + "errors" + "fmt" + "github.com/mame82/P4wnP1_go/service" + "io/ioutil" + "os" + "os/signal" + "regexp" + "strconv" + "syscall" +) + +/* +while $true; do cat /sys/kernel/debug/20980000.usb/regdump | grep HPRT0; sleep 1; done + +Host Port Control and Status register +===================================== +Reg value is dumpable via debugfs for DesignWare USB 2.0 host controller (dwc2) +The dump could be triggered via debugff by reading `/sys/kernel/debug/20980000.usb/regdump` which holds the value for the register in `HPRT0`. +The problem with the approach: The register dump has to be triggered by polling /sys/kernel/debug/20980000.usb/regdump and dumps ALL registers. +This seems to crash the UDC from time to time, in contrast to the comment of the kernel source (https://github.com/raspberrypi/linux/blob/rpi-4.14.y/drivers/usb/dwc2/debugfs.c#L402). + +HPRT --> Host Port Control and Status Register, details on data struct: +https://www.cl.cam.ac.uk/~atm26/ephemeral/rpi/dwc_otg/doc/html/unionhprt0__data.html#a964274b5d22e89ca4490f66dff3c763 + + +Meanings of struct fields: +https://www.intel.com/content/www/us/en/programmable/documentation/sfo1410144425160/sfo1410067646785/sfo1410069362932/sfo1410069623936/sfo1410069628257/sfo1410069409998.html + +01741 typedef union hprt0_data { +01743 uint32_t d32; +01745 struct { +01746 unsigned prtconnsts:1; +01747 unsigned prtconndet:1; +01748 unsigned prtena:1; +01749 unsigned prtenchng:1; + +01750 unsigned prtovrcurract:1; +01751 unsigned prtovrcurrchng:1; +01752 unsigned prtres:1; +01753 unsigned prtsusp:1; + +01754 unsigned prtrst:1; +01755 unsigned reserved9:1; +01756 unsigned prtlnsts:2; + +01757 unsigned prtpwr:1; +01758 unsigned prttstctl:4; +01759 unsigned prtspd:2; +01760 #define DWC_HPRT0_PRTSPD_HIGH_SPEED 0 +01761 #define DWC_HPRT0_PRTSPD_FULL_SPEED 1 +01762 #define DWC_HPRT0_PRTSPD_LOW_SPEED 2 +01763 unsigned reserved19_31:13; +01764 } b; +01765 } hprt0_data_t; + +Test results (polling /sys/kernel/debug/20980000.usb/regdump and parsing "HPRT0") +================================================================================= + +USB gadget running, but OTG adapter attached, NO device connected to the OTG adapter +--> prtlnsts = 0 (No data line on positive logic level) +--> prtpwr = 1 (the port is powered ... at least if there's no overcorrency) +--> prtconnsts = 0 (No device attached) + +USB gadget running, but OTG adapter attached, device connected to the OTG adapter +--> prtlnsts = 0,1 or 2 (changes) +--> prtpwr = 1 (the port is powered ... at least if there's no overcorrency) +--> prtconnsts = 1 (A device is attached) +--> prtspd = 1 or 2 (for non high speed devices) + +USB gadget running, no OTG adapter attached, but NOT connected to host as a peripheral +--> prtlnsts = 1 (Logic Level of D+ is 1, logic level of D- is 0) +--> prtpwr = 0 +--> prtconnsts = 0 (No device attached) + +USB gadget running, no OTG adapter attached, connected to host as a peripheral +--> prtlnsts = 0 (both, D+ and D-, are indicated as low) +--> prtpwr = 0 +--> prtconnsts = 0 (No device attached) +--> in fact the whole HPRT0 is set to 0x00000000 if connected to a host in device mode + + + +WARNING: Constant reading from the regdump file sometimes crashes UDC */ + +type USBConnectionState int + +const ( + USB_CONNECTION_STATE_UNKNOWN = 0 + USB_CONNECTION_STATE_PERIPHERAL_ATTACHED_TO_HOST = 1 + USB_CONNECTION_STATE_PERIPHERAL_NOT_ATTACHED_TO_HOST = 2 + USB_CONNECTION_STATE_OTG_NO_DEVICE_ATTACHED = 3 + USB_CONNECTION_STATE_OTG_DEVICE_ATTACHED = 4 +) + +func (cs USBConnectionState) String() string { + names := [...]string{ + "Unknown", + "Peripheral mode, connected to host", + "Peripheral mode, not connected to host", + "OTG mode, no device attached", + "OTG mode, some device(s) attached", + } + + if cs < USB_CONNECTION_STATE_UNKNOWN || cs > USB_CONNECTION_STATE_OTG_DEVICE_ATTACHED { + return names[0] + } + + return names[cs] +} + +// Host Port Control and Status Register +type HprtData struct { + RegVal uint32 + + PrtConnSts bool //0 + PrtConnDet bool //1 + PrtEnA bool //2 + PrtEnChng bool //3 + + PrtOvrCurrAct bool //4 + PrtOvrCurrChng bool //5 + PrtRes bool //6 + PrtSusp bool //7 + + PrtRst bool //8 + // Reserved9 bool //9 + PrtLnSts uint8 // 10 + 11 + + PrtPwr bool //12 + PrtTstCtl uint8 //13,14,15,16 + + PrtSpd uint8 //17,18 + + ConState USBConnectionState + // #define DWC_HPRT0_PRTSPD_HIGH_SPEED 0 + // #define DWC_HPRT0_PRTSPD_FULL_SPEED 1 + // #define DWC_HPRT0_PRTSPD_LOW_SPEED 2 + // unsigned reserved19_31:13; +} + +func (tgt *HprtData) FromUint32(src uint32) { + tgt.RegVal = src + + tgt.PrtConnSts = src&1 > 0 + tgt.PrtConnDet = src&(1<<1) > 0 + tgt.PrtEnA = src&(1<<2) > 0 + tgt.PrtEnChng = src&(1<<3) > 0 + + tgt.PrtOvrCurrAct = src&(1<<4) > 0 + tgt.PrtOvrCurrChng = src&(1<<5) > 0 + tgt.PrtRes = src&(1<<6) > 0 + tgt.PrtSusp = src&(1<<7) > 0 + + tgt.PrtRst = src&(1<<8) > 0 + tgt.PrtLnSts = uint8((src >> 10) & 0x3) + + tgt.PrtPwr = src&(1<<12) > 0 + tgt.PrtTstCtl = uint8((src >> 13) & 0xF) + tgt.PrtSpd = uint8((src >> 17) & 0x3) + + switch { + case tgt.PrtPwr && !tgt.PrtConnSts: + tgt.ConState = USB_CONNECTION_STATE_OTG_NO_DEVICE_ATTACHED + case tgt.PrtPwr && tgt.PrtConnSts: + tgt.ConState = USB_CONNECTION_STATE_OTG_DEVICE_ATTACHED + case tgt.RegVal == 0: + tgt.ConState = USB_CONNECTION_STATE_PERIPHERAL_ATTACHED_TO_HOST + case !tgt.PrtPwr && tgt.PrtLnSts > 0: + tgt.ConState = USB_CONNECTION_STATE_PERIPHERAL_NOT_ATTACHED_TO_HOST + default: + tgt.ConState = USB_CONNECTION_STATE_UNKNOWN + } +} + +func ReadState() (regval *HprtData, err error) { + cont, err := ioutil.ReadFile("/sys/kernel/debug/20980000.usb/regdump") // This read dumps all regs, including HPRT0 + if err != nil { + return regval, err + } + scont := string(cont) + + reHprt0 := regexp.MustCompile("(?m)HPRT0 = 0x([0-9]{8})") + strReg := "" + if rRes := reHprt0.FindStringSubmatch(scont); len(rRes) > 1 { + strReg = rRes[1] + } else { + return regval, errors.New("String for register HPRT0 couldn't be extracted from sysfs") + } + + regValInt, err := strconv.ParseUint(strReg, 16, 32) + if err != nil { + return regval, errors.New(fmt.Sprintf("Couldn't parse HPRT0 value '%s' to int32\n", strReg)) + } + + regval = &HprtData{} + regval.FromUint32(uint32(regValInt)) + + return regval, nil +} + +func main() { + + btsvc := service.NewBtService() + err := btsvc.StartNAP() + if err != nil { + panic(err) + } + + fmt.Println("Stop with SIGTERM or SIGINT") + sig := make(chan os.Signal) + signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) + si := <-sig + fmt.Printf("Signal (%v) received, ending P4wnP1_service ...\n", si) + + + btsvc.StopNAP() + + + /* + wsvc := service.NewWifiService() + res, err := wsvc.UpdateStateFromIw() + if err == nil { + fmt.Printf("Wifi state: %+v\n", res) + } else { + fmt.Println("Error retrieving WiFi state") + } + */ + + /* + for { + res, err := ReadState() + if err == nil { + fmt.Printf("%+v\n ", res) + } else { + fmt.Println(err) + } + time.Sleep(time.Second) + } +*/ +} diff --git a/service/bluetooth.go b/service/bluetooth.go new file mode 100644 index 0000000..06e402c --- /dev/null +++ b/service/bluetooth.go @@ -0,0 +1,509 @@ +package service + +import ( + "errors" + "fmt" + "github.com/mame82/P4wnP1_go/service/util" + "log" + "net" + "os/exec" + "regexp" + "strconv" + "strings" + "sync" +) + +const ( + bt_dev_name string = "hci0" + BT_MINIMUM_BLUEZ_VERSION_MAJOR = 5 + BT_MINIMUM_BLUEZ_VERSION_MINOR = 43 +) + +const ( + BT_AGENT_MODE_DISPLAY_YES_NO = BtAgentMode("DisplayYesNo") + BT_AGENT_MODE_DISPLAY_ONLY = BtAgentMode("DisplayOnly") + BT_AGENT_MODE_KEYBOARD_ONLY = BtAgentMode("KeyboardOnly") + BT_AGENT_MODE_NO_INPUT_NO_OUTPUT = BtAgentMode("NoInputNoOutput") +) + +type BtAgentMode string + +type BtService struct { + DevName string + BrName string + PathBtConf string + bridgeIfDeployed bool + + Agent *BtAgent + Adapter *BtAdapter +} + +type BtAdapter struct { + /* + --set + Where `property` is one of: + Name + Discoverable + DiscoverableTimeout + Pairable + PairableTimeout + Powered + + + root@raspberrypi:~# bt-adapter -i +[hci0] + Name: raspberrypi + Address: B8:27:EB:8E:44:43 + Alias: raspberrypi [rw] + Class: 0x0 + Discoverable: 0 [rw] + DiscoverableTimeout: 180 [rw] + Discovering: 0 + Pairable: 1 [rw] + PairableTimeout: 0 [rw] + Powered: 1 [rw] + UUIDs: [00001801-0000-1000-8000-00805f9b34fb, AVRemoteControl, PnPInformation, 00001800-0000-1000-8000-00805f9b34fb, AVRemoteControlTarget] + + */ + + *sync.Mutex + Address net.HardwareAddr + DeviceName string + Name string // Not changeable + Alias string + Discoverable bool + DiscoverableTimeout uint64 + Pairable bool + PairableTimeout uint64 + Powered bool +} + +var ( + reAdapterAddress = regexp.MustCompile("(?m)Address: ([0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2})") + reAdapterName = regexp.MustCompile("(?m)Name: (.*)\n") + reAdapterAlias = regexp.MustCompile("(?m)Alias: (.*) \\[") + reAdapterDiscoverable = regexp.MustCompile("(?m)Discoverable: ([01])") + reAdapterDiscoverableTimeout = regexp.MustCompile("(?m)DiscoverableTimeout: ([0-9]+)") + reAdapterPairable = regexp.MustCompile("(?m)Pairable: ([01])") + reAdapterPairableTimeout = regexp.MustCompile("(?m)PairableTimeout: ([0-9]+)") + reAdapterPowered = regexp.MustCompile("(?m)Powered: ([01])") + + eAdapterParseOutput = errors.New("Error parsing output of `bt-adapter -i`") + eAdapterSetAdapter = errors.New("Error setting adapter options with `bt-adapter -s`") +) + +func (bAd *BtAdapter) DeploySate() (err error) { + proc := exec.Command("/usr/bin/bt-adapter", "-s", "Alias", bAd.Alias, "-a", bAd.DeviceName) + if proc.Run() != nil { + return eAdapterSetAdapter + } + proc = exec.Command("/usr/bin/bt-adapter", "-s", "Discoverable", BoolToIntStr(bAd.Discoverable), "-a", bAd.DeviceName) + if proc.Run() != nil { + return eAdapterSetAdapter + } + proc = exec.Command("/usr/bin/bt-adapter", "-s", "DiscoverableTimeout", strconv.Itoa(int(bAd.DiscoverableTimeout)), "-a", bAd.DeviceName) + if proc.Run() != nil { + return eAdapterSetAdapter + } + proc = exec.Command("/usr/bin/bt-adapter", "-s", "Pairable", BoolToIntStr(bAd.Pairable), "-a", bAd.DeviceName) + if proc.Run() != nil { + return eAdapterSetAdapter + } + proc = exec.Command("/usr/bin/bt-adapter", "-s", "PairableTimeout", strconv.Itoa(int(bAd.PairableTimeout)), "-a", bAd.DeviceName) + if proc.Run() != nil { + return eAdapterSetAdapter + } + proc = exec.Command("/usr/bin/bt-adapter", "-s", "Powered", BoolToIntStr(bAd.Powered), "-a", bAd.DeviceName) + if proc.Run() != nil { + return eAdapterSetAdapter + } + bAd.updateMembers() + return +} + +// Updates members via `bt-adapter -i` +func (bAd *BtAdapter) updateMembers() (err error) { + proc := exec.Command("/usr/bin/bt-adapter", "-i", "-a", bAd.DeviceName) + res, err := proc.CombinedOutput() + if err != nil { + return errors.New(fmt.Sprintf("Error running `bt-adapter -i -a %s`: %s\niw output: %s", bAd.DeviceName, err, res)) + } + output := string(res) + + strAdapterAddress := "" + strAdapterName := "" + strAdapterAlias := "" + strAdapterDiscoverable := "" + strAdapterDiscoverableTimeout := "" + strAdapterPairable := "" + strAdapterPairableTimeout := "" + strAdapterPowered := "" + + if matches := reAdapterAddress.FindStringSubmatch(output); len(matches) > 1 { + strAdapterAddress = matches[1] + } else { + return eAdapterParseOutput + } + + if matches := reAdapterName.FindStringSubmatch(output); len(matches) > 1 { + strAdapterName = matches[1] + } else { + return eAdapterParseOutput + } + + if matches := reAdapterAlias.FindStringSubmatch(output); len(matches) > 1 { + strAdapterAlias = matches[1] + } else { + return eAdapterParseOutput + } + + if matches := reAdapterDiscoverable.FindStringSubmatch(output); len(matches) > 1 { + strAdapterDiscoverable = matches[1] + } else { + return eAdapterParseOutput + } + + if matches := reAdapterDiscoverableTimeout.FindStringSubmatch(output); len(matches) > 1 { + strAdapterDiscoverableTimeout = matches[1] + } else { + return eAdapterParseOutput + } + + if matches := reAdapterPairable.FindStringSubmatch(output); len(matches) > 1 { + strAdapterPairable = matches[1] + } else { + return eAdapterParseOutput + } + + if matches := reAdapterPairableTimeout.FindStringSubmatch(output); len(matches) > 1 { + strAdapterPairableTimeout = matches[1] + } else { + return eAdapterParseOutput + } + + if matches := reAdapterPowered.FindStringSubmatch(output); len(matches) > 1 { + strAdapterPowered = matches[1] + } else { + return eAdapterParseOutput + } + + /* + fmt.Println("strAdapterAddress", strAdapterAddress) + fmt.Println("strAdapterName", strAdapterName) + fmt.Println("strAdapterAlias", strAdapterAlias) + fmt.Println("strAdapterDiscoverable", strAdapterDiscoverable) + fmt.Println("strAdapterDiscoverableTimeout", strAdapterDiscoverableTimeout) + fmt.Println("strAdapterPairable", strAdapterPairable) + fmt.Println("strAdapterPairableTimeout", strAdapterPairableTimeout) + fmt.Println("strAdapterPowered", strAdapterPowered) + */ + + if bAd.Address, err = net.ParseMAC(strAdapterAddress); err != nil { + return err + } + if bAd.Discoverable, err = strconv.ParseBool(strAdapterDiscoverable); err != nil { + return err + } + if bAd.DiscoverableTimeout, err = strconv.ParseUint(strAdapterDiscoverableTimeout, 10, 64); err != nil { + return err + } + if bAd.Pairable, err = strconv.ParseBool(strAdapterPairable); err != nil { + return err + } + if bAd.PairableTimeout, err = strconv.ParseUint(strAdapterPairableTimeout, 10, 64); err != nil { + return err + } + if bAd.Powered, err = strconv.ParseBool(strAdapterPowered); err != nil { + return err + } + bAd.Name = strAdapterName + bAd.Alias = strAdapterAlias + + /* + log.Printf("adapter: %+v\n", bAd) + */ + + return +} + +func NewBtAdapter() (bAd *BtAdapter, err error) { + bAd = &BtAdapter{ + Mutex: &sync.Mutex{}, + } + err = bAd.updateMembers() + if err != nil { + return nil, err + } + return +} + +type BtAgent struct { + *exec.Cmd + *sync.Mutex //mutex for wpa-supplicant proc + mode BtAgentMode + pinFilePath string + logger *util.TeeLogger +} + +func (ba *BtAgent) Start(mode BtAgentMode) (err error) { + log.Printf("Starting bt-agent with mode '%s'...\n", ba.mode) + + ba.Lock() + defer ba.Unlock() + + ba.mode = mode + + //stop if already running + if ba.Cmd != nil { + // avoid deadlock + ba.Unlock() + ba.Stop() + ba.Lock() + } + + ba.Cmd = exec.Command("/usr/bin/bt-agent", "-c", string(ba.mode)) + ba.Cmd.Stdout = ba.logger.LogWriter + ba.Cmd.Stderr = ba.logger.LogWriter + err = ba.Cmd.Start() + if err != nil { + ba.Cmd.Wait() + return errors.New(fmt.Sprintf("Error starting bt-agent '%v'", err)) + } + log.Println("... bt-agent started") + return nil + +} + +func (ba *BtAgent) Stop() (err error) { + log.Println("Stopping bt-agent...") + ba.Lock() + defer ba.Unlock() + if ba.Cmd == nil { + log.Println("bt-agent already stopped") + } + if ba.Process == nil { + return errors.New("Couldn't access bt-agent process") + } + ba.Process.Kill() + ba.Process.Wait() + if ba.ProcessState == nil { + return errors.New("Couldn't access bt-agent process state") + } + if !ba.ProcessState.Exited() { + return errors.New("bt-agent didn't terminate after SIGKILL") + } + ba.Cmd = nil + return nil +} + +func NewBtAgent() (res *BtAgent) { + res = &BtAgent{ + Mutex: &sync.Mutex{}, + mode: BT_AGENT_MODE_NO_INPUT_NO_OUTPUT, + pinFilePath: "", + logger: util.NewTeeLogger(true), + } + res.logger.SetPrefix("bt-agent: ") + + return res +} + +func NewBtService() (res *BtService) { + res = &BtService{ + Agent: NewBtAgent(), + DevName: bt_dev_name, + BrName: BT_ETHERNET_BRIDGE_NAME, + PathBtConf: "", + } + if err := res.CheckExternalBinaries(); err != nil { + panic(err) + } + if err := CheckBluezVersion(); err != nil { + panic(err) + } + // ToDo Check if bluetooth service is loaded + if btAdp, errAd := NewBtAdapter(); errAd != nil { + panic(errAd) + } else { + res.Adapter = btAdp + } + + return +} + +func (bt *BtService) StartNAP() (err error) { + log.Println("Bluetooth: starting NAP...") + // assure bnep module is loaded + if err = CheckBnep(); err != nil { + return err + } + + // Create a bridge interface + if errBr := bt.EnableBridge(); errBr != nil { + log.Println("Bridge exists already") + } + + // start bt-agent with "No Input, No Output" capabilities + if err = bt.Agent.Start(BT_AGENT_MODE_NO_INPUT_NO_OUTPUT); err != nil { + return err + } + + fmt.Println("Reconfigure adapter to be discoverable and pairable") + bt.Adapter.Alias = "P4wnP1" + bt.Adapter.Discoverable = true + bt.Adapter.DiscoverableTimeout = 0 + bt.Adapter.Pairable = true + bt.Adapter.PairableTimeout = 0 + if err = bt.Adapter.DeploySate(); err != nil { + return err + } else { + log.Printf("... reconfiguration succeeded: %+v\n", bt.Adapter) + } + + return +} + +func (bt *BtService) StopNAP() (err error) { + log.Println("Bluetooth: stopping NAP...") + + //Stop bt-agent + bt.Agent.Stop() + + // Delete bridge interface + bt.DisableBridge() + + return +} + +func (bt *BtService) EnableBridge() (err error) { + log.Println("Creating bluetooth bridge interface", BT_ETHERNET_BRIDGE_NAME) + //Create the bridge + err = CreateBridge(bt.BrName) + if err != nil { + return err + } + + err = setInterfaceMac(BT_ETHERNET_BRIDGE_NAME, BT_ETHERNET_BRIDGE_MAC) + if err != nil { + return err + } + // SetBridgeSTP(BT_ETHERNET_BRIDGE_NAME, true) //enable spanning tree + SetBridgeForwardDelay(BT_ETHERNET_BRIDGE_NAME, 0) + if err != nil { + return err + } + + //enable the bridge + err = NetworkLinkUp(BT_ETHERNET_BRIDGE_NAME) + if err != nil { + return err + } + + bt.bridgeIfDeployed = true + return +} + +func (bt *BtService) DisableBridge() { + log.Println("Deleting bluetooth bridge interface", BT_ETHERNET_BRIDGE_NAME) + //we ignore error results and assume bridge is disable after this call (error could be created if bridge if wasn't existent, too) + DeleteBridge(BT_ETHERNET_BRIDGE_NAME) + bt.bridgeIfDeployed = false +} + +// assures bnep kernel module is loaded +func CheckBnep() error { + log.Printf("Checking for 'bnep' module...") + out, err := exec.Command("lsmod").Output() + if err != nil { + log.Fatal(err) + } + + if strings.Contains(string(out), "bnep") { + log.Printf("... bnep loaded") + return nil + } + + //if here, libcomposite isn't loaded ... try to load + log.Printf("Kernel module 'bnep' not loaded, trying to load ...") + err = exec.Command("modprobe", "bnep").Run() + if err == nil { + log.Printf("... bnep loaded") + } + + return err +} + +/* +ToDo: The binaries used (bluez-tools) should be replaced by custom functions interfacing with bluez D-Bus API, later on. +Example: https://github.com/muka/go-bluetooth + */ +func (bt BtService) CheckExternalBinaries() error { + bins := []string{"modprobe", "lsmod", "bt-adapter", "bt-agent", "bt-device", "bt-network", "bluetoothd"} + for _, bin := range bins { + if !binaryAvailable(bin) { + return errors.New(bin + " seems to be missing, please install it") + } + + } + return nil +} + +func GetBluezVersion() (major int, minor int, err error) { + eGeneral := errors.New("Couldn't retrieve bluez version") + proc := exec.Command("/usr/sbin/bluetoothd", "-v") + res, err := proc.CombinedOutput() + if err != nil { + err = errors.New(fmt.Sprintf("Error fetching Bluez version: '%s'\nbluetoothd output: %s", err, res)) + return + } + + matches := regexp.MustCompile("(?m)([0-9]+).([0-9]+)").FindStringSubmatch(string(res)) + if len(matches) != 3 { + err = eGeneral + return + } + + major, err = strconv.Atoi(matches[1]) + if err != nil { + err = eGeneral + return + } + minor, err = strconv.Atoi(matches[2]) + if err != nil { + err = eGeneral + return + } + + return +} + +func CheckBluezVersion() (err error) { + eGeneral := errors.New("Newer Bluez version needed") + major, minor, err := GetBluezVersion() + if err != nil { + return err + } + fmt.Printf("Bluez %d.%d found (minimum needed %d.%d)\n", major, minor, BT_MINIMUM_BLUEZ_VERSION_MAJOR, BT_MINIMUM_BLUEZ_VERSION_MINOR) + if major > BT_MINIMUM_BLUEZ_VERSION_MAJOR { + return nil + } + if major == BT_MINIMUM_BLUEZ_VERSION_MAJOR { + if minor >= BT_MINIMUM_BLUEZ_VERSION_MINOR { + return nil + } else { + return eGeneral + } + } + return eGeneral +} + +func BoolToInt(b bool) int { + if b { + return 1 + } + return 0 +} + +func BoolToIntStr(b bool) string { + return strconv.Itoa(BoolToInt(b)) +} diff --git a/service/defaults.go b/service/defaults.go index 979cfc9..7b9622c 100644 --- a/service/defaults.go +++ b/service/defaults.go @@ -11,6 +11,9 @@ const ( DEFAULT_RNDIS_DEV_ADDR = "42:63:65:56:34:12" USB_ETHERNET_BRIDGE_MAC = "24:22:26:12:14:16" USB_ETHERNET_BRIDGE_NAME = "usbeth" + BT_ETHERNET_BRIDGE_MAC = "44:22:26:12:14:16" + BT_ETHERNET_BRIDGE_NAME = "bteth" + ) func GetDefaultNetworkSettingsUSB() (*pb.EthernetInterfaceSettings) { diff --git a/service/wifi.go b/service/wifi.go index 5c13a4b..d22456e 100644 --- a/service/wifi.go +++ b/service/wifi.go @@ -798,7 +798,7 @@ func (wsvc WiFiService) UpdateStateFromIw() (err error) { if len(strSsid) > 0 { wsvc.State.Ssid = strSsid if wsvc.State.Mode == pb.WiFiStateMode_STA_NOT_CONNECTED { - wsvc.State.Mode = pb.WiFiStateMode_STA_CONNECTED // when a SSID is present, the wifi interface is conected to an AP + wsvc.State.Mode = pb.WiFiStateMode_STA_CONNECTED // when a SSID is present, the wifi interface is connected to an AP } }