bluetooth/adapter_sd.go
Ayke van Laethem e453c4d3f9
Add Linux support
Very much experimental, no BLE service support yet and BLE LocalName in
advertisement packet doesn't seem to work. So rather useless at the
moment.
2019-11-09 17:55:19 +01:00

166 lines
4.3 KiB
Go

// +build softdevice,s132v6
package bluetooth
/*
// Define SoftDevice functions as regular function declarations (not inline
// static functions).
#define SVCALL_AS_NORMAL_FUNCTION
#include "s132_nrf52_6.1.1/s132_nrf52_6.1.1_API/include/nrf_sdm.h"
#include "s132_nrf52_6.1.1/s132_nrf52_6.1.1_API/include/ble.h"
#include "s132_nrf52_6.1.1/s132_nrf52_6.1.1_API/include/ble_gap.h"
void assertHandler(void);
*/
import "C"
import (
"device/arm"
"device/nrf"
"errors"
"unsafe"
)
var (
ErrNotDefaultAdapter = errors.New("bluetooth: not the default adapter")
)
//export assertHandler
func assertHandler() {
println("SoftDevice assert")
}
var clockConfig C.nrf_clock_lf_cfg_t = C.nrf_clock_lf_cfg_t{
source: C.NRF_CLOCK_LF_SRC_SYNTH,
rc_ctiv: 0,
rc_temp_ctiv: 0,
accuracy: 0,
}
var (
secModeOpen C.ble_gap_conn_sec_mode_t // No security is needed (aka open link).
defaultDeviceName = [6]byte{'T', 'i', 'n', 'y', 'G', 'o'}
)
// Globally allocated buffer for incoming SoftDevice events.
var eventBuf struct {
C.ble_evt_t
buf [23]byte
}
func init() {
secModeOpen.set_bitfield_sm(1)
secModeOpen.set_bitfield_lv(1)
}
// Adapter is a dummy adapter: it represents the connection to the (only)
// SoftDevice on the chip.
type Adapter struct {
isDefault bool
handler func(Event)
charWriteHandlers []charWriteHandler
}
// defaultAdapter is an adapter to the default Bluetooth stack on a given
// target.
var defaultAdapter = Adapter{isDefault: true}
// DefaultAdapter returns the default adapter on the current system. On Nordic
// chips, it will return the SoftDevice interface.
func DefaultAdapter() (*Adapter, error) {
return &defaultAdapter, nil
}
// Enable configures the BLE stack. It must be called before any
// Bluetooth-related calls (unless otherwise indicated).
func (a *Adapter) Enable() error {
if !a.isDefault {
return ErrNotDefaultAdapter
}
// Enable the IRQ that handles all events.
arm.EnableIRQ(nrf.IRQ_SWI2)
arm.SetPriority(nrf.IRQ_SWI2, 192)
errCode := C.sd_softdevice_enable(&clockConfig, C.nrf_fault_handler_t(C.assertHandler))
if errCode != 0 {
return Error(errCode)
}
appRAMBase := uint32(0x200039c0)
errCode = C.sd_ble_enable(&appRAMBase)
if errCode != 0 {
return Error(errCode)
}
errCode = C.sd_ble_gap_device_name_set(&secModeOpen, &defaultDeviceName[0], uint16(len(defaultDeviceName)))
if errCode != 0 {
return Error(errCode)
}
var gapConnParams C.ble_gap_conn_params_t
gapConnParams.min_conn_interval = C.BLE_GAP_CP_MIN_CONN_INTVL_MIN
gapConnParams.max_conn_interval = C.BLE_GAP_CP_MIN_CONN_INTVL_MAX
gapConnParams.slave_latency = 0
gapConnParams.conn_sup_timeout = C.BLE_GAP_CP_CONN_SUP_TIMEOUT_NONE
errCode = C.sd_ble_gap_ppcp_set(&gapConnParams)
if errCode != 0 {
return Error(errCode)
}
return nil
}
func handleEvent() {
handler := defaultAdapter.handler
if handler == nil {
return
}
id := eventBuf.header.evt_id
switch {
case id >= C.BLE_GAP_EVT_BASE && id <= C.BLE_GAP_EVT_LAST:
gapEvent := GAPEvent{
Connection: Connection(eventBuf.evt.unionfield_gap_evt().conn_handle),
}
switch id {
case C.BLE_GAP_EVT_CONNECTED:
handler(&ConnectEvent{GAPEvent: gapEvent})
case C.BLE_GAP_EVT_DISCONNECTED:
handler(&DisconnectEvent{GAPEvent: gapEvent})
}
case id >= C.BLE_GATTS_EVT_BASE && id <= C.BLE_GATTS_EVT_LAST:
gattsEvent := eventBuf.evt.unionfield_gatts_evt()
switch id {
case C.BLE_GATTS_EVT_WRITE:
writeEvent := gattsEvent.params.unionfield_write()
len := writeEvent.len - writeEvent.offset
data := (*[255]byte)(unsafe.Pointer(&writeEvent.data[0]))[:len:len]
handler := defaultAdapter.getCharWriteHandler(writeEvent.handle)
if handler != nil {
handler.callback(Connection(gattsEvent.conn_handle), int(writeEvent.offset), data)
}
}
}
}
//go:export SWI2_EGU2_IRQHandler
func handleInterrupt() {
for {
eventBufLen := uint16(unsafe.Sizeof(eventBuf))
errCode := C.sd_ble_evt_get((*uint8)(unsafe.Pointer(&eventBuf)), &eventBufLen)
if errCode != 0 {
// Possible error conditions:
// * NRF_ERROR_NOT_FOUND: no events left, break
// * NRF_ERROR_DATA_SIZE: retry with a bigger data buffer
// (currently not handled, TODO)
// * NRF_ERROR_INVALID_ADDR: pointer is not aligned, should
// not happen.
// In all cases, it's best to simply stop now.
break
}
handleEvent()
}
}