8000 all: Add bluetooth module for BLE. · andrewleech/micropython@fc910a8 · GitHub
[go: up one dir, main page]

Skip to content

Commit fc910a8

Browse files
aykevldpgeorge
authored andcommitted
all: Add bluetooth module for BLE.
Rebased to master with the help of Mirko Vogt.
1 parent fa5c0b8 commit fc910a8

File tree

17 files changed

+1011
-53
lines changed

17 files changed

+1011
-53
lines changed

extmod/modbluetooth.c

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2018 Ayke van Laethem
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include "py/obj.h"
28+
#include "py/runtime.h"
29+
#include "extmod/modbluetooth.h"
30+
31+
#if MICROPY_PY_BLUETOOTH
32+
33+
STATIC const mp_obj_type_t bluetooth_type;
34+
35+
typedef struct _mp_obj_bluetooth_t {
36+
mp_obj_base_t base;
37+
} mp_obj_bluetooth_t;
38+
39+
40+
// instantiated Bluetooth object
41+
STATIC const mp_obj_bluetooth_t bluetooth_obj = {
42+
{ &bluetooth_type },
43+
};
44+
45+
// Easier (hopefully tail-called) error handling.
46+
STATIC mp_obj_t bluetooth_handle_errno(int errno_) {
47+
if (errno_ != 0) {
48+
mp_raise_OSError(errno_);
49+
}
50+
return mp_const_none;
51+
}
52+
53+
STATIC mp_obj_t bluetooth_make_new() {
54+
return MP_OBJ_FROM_PTR(&bluetooth_obj);
55+
}
56+
57+
STATIC mp_obj_t bluetooth_active(size_t n_args, const mp_obj_t *args) {
58+
if (n_args == 2) { // boolean enable/disable argument supplied
59+
if (mp_obj_is_true(args[1])) {
60+
int errno_ = mp_bt_enable();
61+
if (errno_ != 0) {
62+
mp_raise_OSError(errno_);
63+
}
64+
} else {
65+
mp_bt_disable();
66+
}
67+
}
68+
return mp_obj_new_bool(mp_bt_is_enabled());
69+
}
70+
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_active_obj, 1, 2, bluetooth_active);
71+
72+
STATIC mp_obj_t bluetooth_advertise(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
73+
enum { ARG_interval, ARG_name, ARG_connectable };
74+
static const mp_arg_t allowed_args[] = {
75+
{ MP_QSTR_interval, MP_ARG_INT, {.u_int = 100} },
76+
{ MP_QSTR_name, MP_ARG_OBJ, {.u_obj = mp_const_none } },
77+
{ MP_QSTR_connectable, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_true } },
78+
};
79+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
80+
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
81+
82+
mp_int_t interval = args[ARG_interval].u_int;
83+
if (interval == 0) {
84+
mp_bt_advertise_stop();
85+
return mp_const_none;
86+
}
87+
interval = interval * 8 / 5; // convert from 1ms to 0.625ms units
88+
if (interval < 0x20 || interval > 0x4000) {
89+
mp_raise_ValueError("interval out of range");
90+
}
91+
92+
mp_bt_adv_type_t adv_type = MP_BT_ADV_TYPE_ADV_IND; // connectable=True
93+
if (!mp_obj_is_true(args[ARG_connectable].u_obj)) {
94+
adv_type = MP_BT_ADV_TYPE_ADV_NONCONN_IND; // connectable=False
95+
}
96+
97+
size_t name_len;
98+
const char *name = NULL;
99+
if (args[ARG_name].u_obj != mp_const_none) {
100+
name = mp_obj_str_get_data(args[ARG_name].u_obj, &name_len);
101+
}
102+
103+
uint8_t adv_data[31];
104+
size_t adv_data_len = 0;
105+
106+
if (name != NULL) {
107+
adv_data[adv_data_len++] = 2; // 1 byte type + 1 byte flags data
108+
adv_data[adv_data_len++] = MP_BLE_GAP_AD_TYPE_FLAG;
109+
adv_data[adv_data_len++] = MP_BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
110+
111+
if (name_len + 3 > sizeof(adv_data) - adv_data_len) {
112+
mp_raise_ValueError("advertisement packet overflow");
113+
}
114+
adv_data[adv_data_len++] = name_len + 1;
115+
adv_data[adv_data_len++] = MP_BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME;
116+
for (size_t i=0; i<name_len; i++) {
117+
adv_data[adv_data_len++] = name[i];
118+
}
119+
}
120+
121+
int errno_ = mp_bt_advertise_start(adv_type, interval, adv_data_len ? adv_data : NULL, adv_data_len, NULL, 0);
122+
return bluetooth_handle_errno(errno_);
123+
}
124+
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bluetooth_advertise_obj, 1, bluetooth_advertise);
125+
126+
STATIC const mp_rom_map_elem_t bluetooth_locals_dict_table[] = {
127+
{ MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&bluetooth_active_obj) },
128+
{ MP_ROM_QSTR(MP_QSTR_advertise), MP_ROM_PTR(&bluetooth_advertise_obj) },
129+
};
130+
STATIC MP_DEFINE_CONST_DICT(bluetooth_locals_dict, bluetooth_locals_dict_table);
131+
132+
STATIC const mp_obj_type_t bluetooth_type = {
133+
{ &mp_type_type },
134+
.name = MP_QSTR_Bluetooth,
135+
.make_new = bluetooth_make_new,
136+
.locals_dict = (void*)&bluetooth_locals_dict,
137+
};
138+
139+
STATIC const mp_rom_map_elem_t mp_module_bluetooth_globals_table[] = {
140+
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bluetooth) },
141+
{ MP_ROM_QSTR(MP_QSTR_Bluetooth), MP_ROM_PTR(&bluetooth_type) },
142+
};
143+
STATIC MP_DEFINE_CONST_DICT(mp_module_bluetooth_globals, mp_module_bluetooth_globals_table);
144+
145+
const mp_obj_module_t mp_module_bluetooth = {
146+
.base = { &mp_type_module },
147+
.globals = (mp_obj_dict_t*)&mp_module_bluetooth_globals,
148+
};
149+
150+
#endif //MICROPY_PY_BLUETOOTH

extmod/modbluetooth.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2018 Ayke van Laethem
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#pragma once
28+
29+
#include <stdbool.h>
30+
#include "bluetooth/bluetooth.h"
31+
32+
// Enables the Bluetooth stack. Returns errno on failure.
33+
int mp_bt_enable(void);
34+
35+
// Disables the Bluetooth stack. Is a no-op when not enabled.
36+
void mp_bt_disable(void);
37+
38+
// Returns true when the Bluetooth stack is enabled.
39+
bool mp_bt_is_enabled(void);
40+
41+
// Start advertisement. Will re-start advertisement when already enabled.
42+
// Returns errno on failure.
43+
int mp_bt_advertise_start(mp_bt_adv_type_t type, uint16_t interval, uint8_t *adv_data, size_t adv_data_len, uint8_t *sr_data, size_t sr_data_len);
44+
45+
// Stop advertisement. No-op when already stopped.
46+
void mp_bt_advertise_stop(void);
47+
48+
// Data types of advertisement packet.
49+
#define MP_BLE_GAP_AD_TYPE_FLAG (0x01)
50+
#define MP_BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME (0x09)
51+
52+
// Flags element of advertisement packet.
53+
#define MP_BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE (0x02) // discoverable for everyone
54+
#define MP_BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED (0x04) // BLE only - no classic BT supported
55+
#define MP_BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE (MP_BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE | MP_BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED)

0 commit comments

Comments
 (0)
0