1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include "os/mynewt.h"
21 #include "bsp/bsp.h"
22 #include "hal/hal_gpio.h"
23 #include "host/ble_gap.h"
24 #include "bleprph.h"
25
26 #if MYNEWT_VAL(BLEPRPH_LE_PHY_SUPPORT)
27
28 static const int button_gpio[4] = MYNEWT_VAL(BLEPRPH_LE_PHY_BUTTON_GPIO);
29 static const int led_gpio[3] = MYNEWT_VAL(BLEPRPH_LE_PHY_LED_GPIO);
30
31 #define PHY_TO_PTR(_mask, _opts) (void *)(((_opts) << 16) | ((_mask)))
32 #define PTR_TO_PHY_MASK(_ptr) (uint8_t)(((int)_ptr) & 0x0ff)
33 #define PTR_TO_PHY_OPTS(_ptr) (uint8_t)(((int)_ptr) >> 16)
34
35 static struct os_event gpio_event;
36
37 static uint16_t conn_handle = CONN_HANDLE_INVALID;
38
39 static void
gpio_irq_handler(void * arg)40 gpio_irq_handler(void *arg)
41 {
42 gpio_event.ev_arg = arg;
43 os_eventq_put(os_eventq_dflt_get(), &gpio_event);
44 }
45
46 static void
gpio_event_handler(struct os_event * ev)47 gpio_event_handler(struct os_event *ev)
48 {
49 uint8_t phy_mask;
50 uint8_t phy_opts;
51 int sr;
52
53 OS_ENTER_CRITICAL(sr);
54 phy_mask = PTR_TO_PHY_MASK(ev->ev_arg);
55 phy_opts = PTR_TO_PHY_OPTS(ev->ev_arg);
56 OS_EXIT_CRITICAL(sr);
57
58 if (conn_handle != CONN_HANDLE_INVALID) {
59 ble_gap_set_prefered_le_phy(conn_handle, phy_mask, phy_mask, phy_opts);
60 }
61 }
62
63 static void
setup_button_gpio(int button,uint8_t phy_mask,uint8_t phy_opts)64 setup_button_gpio(int button, uint8_t phy_mask, uint8_t phy_opts)
65 {
66 if (button < 0) {
67 return;
68 }
69
70 hal_gpio_irq_init(button, gpio_irq_handler, PHY_TO_PTR(phy_mask, phy_opts),
71 HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP);
72 hal_gpio_irq_enable(button);
73 }
74
75 void
phy_init(void)76 phy_init(void)
77 {
78 gpio_event.ev_cb = gpio_event_handler;
79
80 /*
81 * XXX: we could make this configurable, but for now assume all pins are
82 * valid, buttons gpio pins are pulled-up and LEDs are active-low - this
83 * is valid for nRF52840 PDK.
84 */
85 setup_button_gpio(button_gpio[0], BLE_GAP_LE_PHY_1M_MASK,
86 BLE_GAP_LE_PHY_CODED_ANY);
87 setup_button_gpio(button_gpio[1], BLE_GAP_LE_PHY_2M_MASK,
88 BLE_GAP_LE_PHY_CODED_ANY);
89 setup_button_gpio(button_gpio[2], BLE_GAP_LE_PHY_CODED_MASK,
90 BLE_GAP_LE_PHY_CODED_S2);
91 setup_button_gpio(button_gpio[3], BLE_GAP_LE_PHY_CODED_MASK,
92 BLE_GAP_LE_PHY_CODED_S8);
93
94 hal_gpio_init_out(led_gpio[0], 1);
95 hal_gpio_init_out(led_gpio[1], 1);
96 hal_gpio_init_out(led_gpio[2], 1);
97 }
98
99 void
phy_conn_changed(uint16_t handle)100 phy_conn_changed(uint16_t handle)
101 {
102 uint8_t phy = 0;
103
104 conn_handle = handle;
105
106 if (handle != CONN_HANDLE_INVALID) {
107 /* XXX: assume symmetric phy for now */
108 ble_gap_read_le_phy(handle, &phy, &phy);
109 }
110
111 phy_update(phy);
112 }
113
114 void
phy_update(uint8_t phy)115 phy_update(uint8_t phy)
116 {
117 if (conn_handle == CONN_HANDLE_INVALID) {
118 hal_gpio_write(led_gpio[0], 1);
119 hal_gpio_write(led_gpio[1], 1);
120 hal_gpio_write(led_gpio[2], 1);
121 } else {
122 hal_gpio_write(led_gpio[0], !(phy == BLE_GAP_LE_PHY_1M));
123 hal_gpio_write(led_gpio[1], !(phy == BLE_GAP_LE_PHY_2M));
124 hal_gpio_write(led_gpio[2], !(phy == BLE_GAP_LE_PHY_CODED));
125 }
126 }
127
128 #endif
129