├── 3d
├── beagle_bone_gateway_magnet_plate.SLDPRT
├── beagle_bone_gateway_magnet_plate.STL
├── beagle_bone_gateway_magnet_plate.zcode
├── beagle_bone_gateway_magnet_plate.zproj
├── beagle_bone_gateway_magnet_plate_v2.STL
├── beagle_bone_gateway_magnet_plate_v2.zcode
├── beagle_bone_gateway_magnet_plate_v2.zproj
├── beagle_bone_gateway_magnet_plate_v3.STL
├── beagle_bone_gateway_magnet_plate_v3.zcode
├── beagle_bone_gateway_magnet_plate_v3.zproj
├── beagle_bone_gateway_magnet_plate_v3_6up.zcode
└── beagle_bone_gateway_magnet_plate_v3_6up.zproj
├── README.md
├── gap_rev3.png
├── gateway
└── tunnel
│ ├── debug.h
│ ├── tunnel-client.c
│ └── tunnel-server.c
├── hardware
└── eagle
│ ├── .gitignore
│ ├── bbb-cc2520.lbr
│ └── bbb-cc2520
│ ├── .gitignore
│ ├── rev_a
│ ├── bbb-cc2520_7-25-14_gerber_sunstone.zip
│ ├── bbb-cc2520_7-28-14_gerber_OSHPark.zip
│ ├── bbb-cc2520_a.brd
│ ├── bbb-cc2520_a.pro
│ ├── bbb-cc2520_a.sch
│ └── bbb-cc2520_a_bom.xlsx
│ ├── rev_b
│ ├── Zigbeag_b_10-06-14_gerber_sunstone.zip
│ ├── bbb-cc2520_b.brd
│ ├── bbb-cc2520_b.sch
│ ├── bbb-cc2520_b_bom.csv
│ └── bbb-cc2520_b_bom.xlsx
│ ├── rev_c
│ ├── BoardStackup.txt
│ ├── bbb-cc2520.brd
│ ├── bbb-cc2520.info
│ ├── bbb-cc2520.pdf
│ ├── bbb-cc2520.sch
│ ├── bbb-cc2520_bom.csv
│ ├── bbb-cc2520_bom.xlsx
│ ├── bbb-cc2520_c_2014-11-20.zip
│ ├── bbb-cc2520_c_to_assembler_2014-11-20.zip
│ ├── bbb-cc2520_c_to_fab_2014-11-20.zip
│ ├── bbb-cc2520_pcb.png
│ └── gap_c_panel_2014-11-20.zip
│ └── rev_d
│ ├── BoardStackup.txt
│ ├── bbb-cc2520.brd
│ ├── bbb-cc2520.info
│ ├── bbb-cc2520.pdf
│ ├── bbb-cc2520.sch
│ ├── bbb-cc2520_bom.csv
│ ├── bbb-cc2520_bom.xlsx
│ ├── bbb-cc2520_d_2015-04-03.zip
│ ├── bbb-cc2520_d_to_assembler_2015-04-03.zip
│ ├── bbb-cc2520_d_to_fab_2015-04-03.zip
│ └── bbb-cc2520_pcb.png
├── linux
├── README.md
├── recvRawEth.c
├── recv_raw_802154.c
└── recv_raw_802154.py
├── overlay
└── BB-GAP-00A0.dts
└── software
├── .gitignore
├── driver
├── Makefile
├── README.md
├── gapspi
│ ├── Makefile
│ ├── debug.h
│ ├── gapspi.c
│ └── gapspi.h
└── nrf51822
│ ├── Makefile
│ ├── bcp.h
│ ├── debug.h
│ ├── ioctl.h
│ ├── nrf51822.c
│ ├── nrf51822.h
│ └── tests
│ └── get_adv.c
├── nrf51822
├── .gitignore
├── Makefile
├── README.md
├── bcp.h
├── bcp_spi_slave.c
├── bcp_spi_slave.h
├── boards.h
├── device_manager_cnfg.h
├── gap.h
├── interrupt_event_queue.c
├── interrupt_event_queue.h
├── led.c
├── led.h
├── main.c
└── pstorage_platform.h
└── utility
└── eepromflasher.c
/3d/beagle_bone_gateway_magnet_plate.SLDPRT:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/3d/beagle_bone_gateway_magnet_plate.SLDPRT
--------------------------------------------------------------------------------
/3d/beagle_bone_gateway_magnet_plate.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/3d/beagle_bone_gateway_magnet_plate.STL
--------------------------------------------------------------------------------
/3d/beagle_bone_gateway_magnet_plate.zcode:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/3d/beagle_bone_gateway_magnet_plate.zcode
--------------------------------------------------------------------------------
/3d/beagle_bone_gateway_magnet_plate.zproj:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/3d/beagle_bone_gateway_magnet_plate.zproj
--------------------------------------------------------------------------------
/3d/beagle_bone_gateway_magnet_plate_v2.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/3d/beagle_bone_gateway_magnet_plate_v2.STL
--------------------------------------------------------------------------------
/3d/beagle_bone_gateway_magnet_plate_v2.zcode:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/3d/beagle_bone_gateway_magnet_plate_v2.zcode
--------------------------------------------------------------------------------
/3d/beagle_bone_gateway_magnet_plate_v2.zproj:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/3d/beagle_bone_gateway_magnet_plate_v2.zproj
--------------------------------------------------------------------------------
/3d/beagle_bone_gateway_magnet_plate_v3.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/3d/beagle_bone_gateway_magnet_plate_v3.STL
--------------------------------------------------------------------------------
/3d/beagle_bone_gateway_magnet_plate_v3.zcode:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/3d/beagle_bone_gateway_magnet_plate_v3.zcode
--------------------------------------------------------------------------------
/3d/beagle_bone_gateway_magnet_plate_v3.zproj:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/3d/beagle_bone_gateway_magnet_plate_v3.zproj
--------------------------------------------------------------------------------
/3d/beagle_bone_gateway_magnet_plate_v3_6up.zcode:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/3d/beagle_bone_gateway_magnet_plate_v3_6up.zcode
--------------------------------------------------------------------------------
/3d/beagle_bone_gateway_magnet_plate_v3_6up.zproj:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/3d/beagle_bone_gateway_magnet_plate_v3_6up.zproj
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | GAP: Generic Access Point
2 | =========================
3 |
4 |

5 |
6 |
7 | GAP is the WiFi router for low-power and embedded Internet of Things devices.
8 | While WiFi routers provide ubiquitous Internet access for laptops and
9 | smartphones, GAP provides Internet access for low-power sensors and wearable
10 | devices. It supports both 802.15.4 and Bluetooth Low Energy.
11 |
12 | GAP is implemented as a cape for the
13 | [BeagleBone Black](http://beagleboard.org/black). It uses two TI CC2520 radios
14 | and a Nordic nRF51822 radio to provide connectivity. Each radio has a linux
15 | kernel module to allow userspace access to the radios.
16 |
17 | Hardware
18 | --------
19 |
20 | The GAP cape features a SPI interface to two CC2520
21 | radios, one of which is amplified with a CC2591, and one nRF51822 radio.
22 | It also includes four LEDs.
23 |
24 |
25 | Software
26 | --------
27 |
28 | The CC2520 radios are
29 | [supported natively](https://github.com/torvalds/linux/blob/master/drivers/net/ieee802154/cc2520.c)
30 | in newer versions of the Linux kernel (>=4.1).
31 |
32 | The nRF51822 BLE radio is a work-in-progress. It can be used as a standalone
33 | BLE radio (see [this repo](https://github.com/lab11/nrf5x-base) for a starting
34 | point), but does not have great integration with the BBB at this point.
35 |
36 |
37 |
38 | Setting Up GAP
39 | --------------
40 |
41 | To setup a BBB to work with GAP, follow these instructions:
42 |
43 | 1. Start with a recent build of Debian for the BBB. We suggest starting
44 | with pretty new version of Debian, like that can be found
45 | [here](http://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Jessie_Snapshot_console).
46 |
47 | 2. Once that is setup, ssh to the BBB and update the kernel to the newest
48 | version. This will not only make sure you're running the latest code,
49 | but also ensure all of the kernel modules will be present.
50 |
51 | sudo apt-get update
52 | sudo apt-get install vim git lsb-release
53 | sudo /opt/scripts/tools/update_kernel.sh --beta --bone-channel
54 |
55 | Luckily [Robert C Nelson](https://github.com/RobertCNelson/)
56 | has made this really easy with a convenient script.
57 |
58 | 3. Now we have to setup the device tree overlay to let Linux know that
59 | the the radios exist. The GAP overlay and others are setup in a repository also
60 | maintained by RCN.
61 |
62 | git clone https://github.com/lab11/bb.org-overlays
63 | cd bb.org-overlays
64 | ./dtc-overlay.sh
65 | ./install.sh
66 |
67 | That puts the compiled overlay in the correct place, now we need to tell
68 | the BBB to use it at boot.
69 |
70 | vim /boot/uEnv.txt
71 | # Edit that line that looks like this to include the reference to GAP
72 | cape_enable=bone_capemgr.enable_partno=BB-GAP
73 |
74 | 4. Reboot to apply this.
75 |
76 | sudo reboot
77 |
78 |
79 |
80 | Sniffing 15.4 Packets
81 | ---------------------
82 |
83 | To make sure everything is working, it is pretty easy to get Linux to
84 | print out the packets the radio is receiving.
85 |
86 | 1. Install the `wpan-tools` to configure all of the 15.4 devices.
87 |
88 | sudo apt-get install pkg-config libnl-3-dev libnl-genl-3-dev
89 | wget http://wpan.cakelab.org/releases/wpan-tools-0.5.tar.gz
90 | tar xf wpan-tools-0.5.tar.gz
91 | cd wpan-tools-0.5
92 | ./configure
93 | make
94 | sudo make install
95 |
96 | 1. Install `tcpdump` to view the packets.
97 |
98 | sudo apt-get install tcpdump
99 |
100 | 2. Configure the network devices. Be sure to set the channel and PANID
101 | to match what is transmitting the 15.4 packets.
102 |
103 | iwpan phy phy0 set channel 0 11
104 | iwpan dev wpan0 del
105 | iwpan phy phy0 interface add wpan0 type node c0:98:e5:00:00:00:00:01
106 | iwpan dev wpan0 set pan_id 0x0022
107 | /sbin/ifconfig wpan0 up
108 |
109 | 3. Use `tcpdump` to view them.
110 |
111 | sudo tcpdump -i wpan0 -vvv
112 |
113 | OR, use a simple c program to read from the raw socket.
114 |
115 | cd linux
116 | gcc recv_raw_802154.c -o raw
117 | sudo ./raw
118 |
119 | OR, use a very similar python script:
120 |
121 | cd linux
122 | sudo python recv_raw_802154.py
123 |
124 |
125 |
126 | RPL Border Router
127 | ----------------
128 |
129 | GAP can be setup as a border router running a 6LoWPAN based mesh network
130 | with RPL as a routing layer. It uses [unstrung](https://github.com/mcr/unstrung)
131 | to provide the RPL implementation. The rest is supported by the Linux kernel.
132 |
133 | To set this up:
134 |
135 | 1. Setup the radios and network interfaces:
136 |
137 | sudo iwpan phy phy1 set channel 0 23
138 | sleep 15
139 | sudo iwpan dev wpan1 del
140 | sleep 15
141 | sudo iwpan phy phy1 interface add wpan1 type node c0:98:e5:00:00:00:00:01
142 | sleep 15
143 | sudo iwpan dev wpan1 set pan_id 0x0022
144 | sleep 15
145 | sudo ip link add link wpan1 name lowpan1 type lowpan
146 | sleep 15
147 | sudo ifconfig lowpan1 up
148 | sleep 15
149 | sudo ifconfig wpan1 up
150 |
151 | Note: I've found that putting a sleep between those commands makes everything run smoothly.
152 | Calling them too quickly seems to break things (at least in the past, it's possible
153 | that newer commits have solved this issue).
154 |
155 | 2. Get unstrung.
156 |
157 | git clone https://github.com/mcr/unstrung.git
158 | cd unstrung
159 | make
160 |
161 | There may be commits that need to be applied to make this
162 | work. Look at unstrung pull requests to see if there are
163 | outstanding patches that are required.
164 |
165 | 3. Run unstrung.
166 |
167 | /home/debian/unstrung/programs/sunshine/sunshine --verbose --dagid 0x11112222333344445555666677778888 -i lowpan1 -W 10000 --stderr -R 1 --prefix 2607:f018:800:201:c298:e588:4400:1/64 -m
168 |
169 | 4. You should be able to ping a node:
170 |
171 | sudo ping6 2607:f018:800:201:c298:e522:2200:bb -s 16
172 |
173 |
174 |
228 |
229 |
351 |
--------------------------------------------------------------------------------
/gap_rev3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/gap_rev3.png
--------------------------------------------------------------------------------
/gateway/tunnel/debug.h:
--------------------------------------------------------------------------------
1 | #ifndef __DEBUG_H__
2 | #define __DEBUG_H__
3 |
4 |
5 | #define DBG(...)\
6 | do {\
7 | flockfile(stdout);\
8 | printf("%s:%d:\t", __FILE__, __LINE__);\
9 | printf(__VA_ARGS__);\
10 | funlockfile(stdout);\
11 | } while (0)
12 |
13 | #define ERROR(...)\
14 | do {\
15 | flockfile(stderr);\
16 | fprintf(stderr, "%s:%d\t", __FILE__, __LINE__);\
17 | fprintf(stderr, __VA_ARGS__);\
18 | funlockfile(stderr);\
19 | } while (0)
20 |
21 | #endif
22 |
--------------------------------------------------------------------------------
/gateway/tunnel/tunnel-client.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | // #include "ini/ini.h"
18 | // #include "jsmn/jsmn.h"
19 |
20 | /* Connects to a server over TCP in order to create an IPv4 over v4 tunnel.
21 | *
22 | * @author Brad Campbell
23 | */
24 |
25 | // typedef struct {
26 | // const char* remotehost;
27 | // uint16_t remoteport;
28 | // } config_ini_t;
29 |
30 | #define MAC_ADDR_FILE "/sys/class/net/eth0/address"
31 |
32 | #define TUNNEL_SERVER_HOST "141.212.11.200"
33 | #define TUNNEL_SERVER_PORT 32100
34 |
35 | // Holds the parsed values from the config.ini file
36 | // config_ini_t cfg = {NULL, 0};
37 |
38 | // // Holding arrays for client specific information
39 | // char json_id[] = "{\"Id\":\"00:11:22:33:44:55\"}";
40 | // char prefix[48] = {'\0'};
41 | // char macbuf[128];
42 |
43 | char cmd_lladdr_buf[4096];
44 |
45 | // Sockets for two of our tunnel endpoints
46 | int tcp_socket = -1;
47 | int tun_file = -1;
48 |
49 |
50 | // Runs a command on the local system using the kernel command interpreter.
51 | int ssystem(const char *fmt, ...) {
52 | char cmd[128];
53 | va_list ap;
54 | va_start(ap, fmt);
55 | vsnprintf(cmd, sizeof(cmd), fmt, ap);
56 | va_end(ap);
57 | return system(cmd);
58 | }
59 |
60 | // Makes the given file descriptor non-blocking.
61 | // Returns 0 on success, -1 on failure.
62 | int make_nonblocking (int fd) {
63 | int flags, ret;
64 |
65 | flags = fcntl(fd, F_GETFL, 0);
66 | if (flags == -1) {
67 | return -1;
68 | }
69 | // Set the nonblocking flag.
70 | flags |= O_NONBLOCK;
71 | ret = fcntl(fd, F_SETFL, flags);
72 | if (ret == -1) {
73 | return -1;
74 | }
75 |
76 | return 0;
77 | }
78 |
79 | // // Functions parses the config.ini for the options we care about
80 | // static int config_handler(void* user, const char* section, const char* name,
81 | // const char* value) {
82 | // config_ini_t* cfg = (config_ini_t*) user;
83 |
84 | // #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
85 |
86 | // if (MATCH("client", "remotehost")) {
87 | // cfg->remotehost = strdup(value);
88 | // } else if (MATCH("client", "remoteport")) {
89 | // cfg->remoteport = atoi(value);
90 | // }
91 | // return 1;
92 | // }
93 |
94 | // Creates a TCP connection to the IPv6 tunnel server.
95 | // This function can fail if the client has no Internet (and therefore can't
96 | // resolve DNS). If the client has Internet but the server is down, this
97 | // function will spin until the server comes back.
98 | int connect_tcp () {
99 | int ret;
100 | struct addrinfo hints;
101 | struct addrinfo *strmSvr;
102 | char port_str[6];
103 |
104 | printf("Attempting to connect to %s:%d\n", TUNNEL_SERVER_HOST, TUNNEL_SERVER_PORT);
105 |
106 | // Close tcp_socket just in case. Likely this won't be valid, but if
107 | // we need to reconnect make sure this socket is closed.
108 | close(tcp_socket);
109 |
110 | // Tell getaddrinfo() that we only want a TCP connection
111 | memset(&hints, 0, sizeof(struct addrinfo));
112 | hints.ai_socktype = SOCK_STREAM;
113 |
114 | // Convert port number to a string
115 | snprintf(port_str, 6, "%d", TUNNEL_SERVER_PORT);
116 |
117 | // Resolve the HOST to an IP address
118 | ret = getaddrinfo(TUNNEL_SERVER_HOST, port_str, &hints, &strmSvr);
119 | if (ret < 0) {
120 | fprintf(stderr, "Could not resolve the host/port address: %s:%s\n",
121 | TUNNEL_SERVER_HOST, port_str);
122 | fprintf(stderr, "%s", gai_strerror(ret));
123 | return -1;
124 | }
125 |
126 | // Create a TCP connection
127 | tcp_socket = socket(strmSvr->ai_family,
128 | strmSvr->ai_socktype,
129 | strmSvr->ai_protocol);
130 | if (tcp_socket < 0) {
131 | fprintf(stderr, "Could not create a socket.\n");
132 | fprintf(stderr, "%s\n", strerror(errno));
133 | return -1;
134 | }
135 |
136 | // Loop until we establish a connection.
137 | // This is where reconnects happen if the server goes down
138 | while (1) {
139 | // Connect to the socket
140 | ret = connect(tcp_socket, strmSvr->ai_addr, strmSvr->ai_addrlen);
141 | if (ret < 0) {
142 | // Unable to connect
143 | sleep(2);
144 | } else {
145 | break;
146 | }
147 | }
148 |
149 | //make_nonblocking(tcp_socket);
150 |
151 | freeaddrinfo(strmSvr);
152 |
153 | printf("Connected to server.\n");
154 |
155 | return 0;
156 | }
157 |
158 | // // Communicate with the IPv6 tunnel server to get a prefix to use for wsn
159 | // int get_prefix () {
160 | // int ret;
161 | // ssize_t sent_len, read_len;
162 | // uint8_t buf[4096];
163 |
164 | // jsmn_parser p;
165 | // jsmntok_t tok[10];
166 |
167 | // int i;
168 |
169 | // // Copy the mac address into the json blob
170 | // memcpy(json_id+7, macbuf, 17);
171 |
172 | // // Transmit the ID to the server
173 | // sent_len = send(tcp_socket, json_id, strlen(json_id), 0);
174 | // if (sent_len == -1) {
175 | // fprintf(stderr, "Error sending MAC address via TCP\n");
176 | // return -1;
177 | // }
178 |
179 | // // Read the prefix response
180 | // read_len = recv(tcp_socket, buf, 4095, 0);
181 | // if (read_len < 0) {
182 | // fprintf(stderr, "Did not receive a prefix\n");
183 | // fprintf(stderr, "%s\n", strerror(errno));
184 | // return -1;
185 | // }
186 | // // Parse the JSON response
187 | // jsmn_init(&p);
188 | // buf[read_len] = '\0';
189 | // ret = jsmn_parse(&p, (char*) buf, tok, 10);
190 | // if (ret != JSMN_SUCCESS) {
191 | // fprintf(stderr, "Could not parse prefix value\n");
192 | // return -1;
193 | // }
194 |
195 | // #define TOKEN_STRING(js, t, s) \
196 | // (strncmp(js+(t).start, s, (t).end - (t).start) == 0 \
197 | // && strlen(s) == (t).end - (t).start)
198 |
199 | // for (i=0; i<9; i++) {
200 | // if (TOKEN_STRING((char*) buf, tok[i], "Prefix")) {
201 | // memcpy(prefix, buf+tok[i+1].start, tok[i+1].end-tok[i+1].start);
202 | // break;
203 | // }
204 | // }
205 |
206 | // if (prefix[0] == '\0') {
207 | // fprintf(stderr, "Could not decipher the prefix\n");
208 | // return -1;
209 | // }
210 |
211 | // printf("Got prefix %s\n", prefix);
212 |
213 | // return 0;
214 | // }
215 |
216 | // Simple function that calls the functions needed to reconnect
217 | void reconnect () {
218 |
219 | // Sit an spin until this works
220 | while (1) {
221 | if (connect_tcp() < 0) {
222 | goto loop;
223 | }
224 | // if (get_prefix() < 0) {
225 | // goto loop;
226 | // }
227 | break;
228 | loop:
229 | sleep(2);
230 | }
231 |
232 | // Now that we are connected, assign an address so that the tunnel server
233 | // knows our link local address.
234 | printf("%s", cmd_lladdr_buf);
235 | ssystem(cmd_lladdr_buf);
236 | }
237 |
238 | int main () {
239 |
240 | // Used to setup the tunnel
241 | struct ifreq ifr;
242 | uint8_t cmdbuf[4096];
243 |
244 | int macfile;
245 | char macbuf[128];
246 |
247 | // Used for the select
248 | fd_set rfds;
249 | uint8_t nfds = 0;
250 |
251 | ssize_t read_len;
252 | ssize_t sent_len;
253 | uint8_t buf[4096];
254 |
255 | int ret;
256 | int i;
257 |
258 | // Parse the config file
259 | // ret = ini_parse("ipv6tunnel-client.ini", config_handler, &cfg);
260 | // if (ret < 0) {
261 | // fprintf(stderr, "Could not open ipv6tunnel-client.ini\n");
262 | // fprintf(stderr, "The configuration file is required.\n");
263 | // return -1;
264 | // }
265 | // if (cfg.remotehost == NULL || cfg.remoteport == 0) {
266 | // fprintf(stderr, "Missing remotehost or remoteport in config.ini\n");
267 | // return -1;
268 | // }
269 |
270 | // Create the TUN interface
271 | tun_file = open("/dev/net/tun", O_RDWR);
272 | if (tun_file < 0) {
273 | // error
274 | fprintf(stderr, "Could not create a tun interface. errno: %i\n", errno);
275 | fprintf(stderr, "%s\n", strerror(errno));
276 | return -1;
277 | }
278 |
279 | // Clear the ifr struct
280 | memset(&ifr, 0, sizeof(ifr));
281 |
282 | // Select a TUN device
283 | ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
284 |
285 | // Name the TUN device
286 | strncpy(ifr.ifr_name, "ipv6-umich", IFNAMSIZ);
287 |
288 | // Setup the interface
289 | ret = ioctl(tun_file, TUNSETIFF, (void *) &ifr);
290 | if (ret < 0) {
291 | fprintf(stderr, "ioctl could not set up tun interface\n");
292 | close(tun_file);
293 | return -1;
294 | }
295 |
296 | // Make the tun interface file descriptor non blocking
297 | make_nonblocking(tun_file);
298 |
299 | // Configure the tun device
300 | snprintf((char*) cmdbuf, 4096, "ifconfig %s up", ifr.ifr_name);
301 | ssystem((char*) cmdbuf);
302 |
303 | snprintf((char*) cmdbuf, 4906,
304 | "ip -6 route add default via fe80::1 dev %s", ifr.ifr_name);
305 | ssystem((char*) cmdbuf);
306 |
307 | // Get our MAC address
308 | macfile = open(MAC_ADDR_FILE, O_RDONLY);
309 | if (macfile < 0) {
310 | fprintf(stderr, "Could not open file to get MAC address.\n");
311 | fprintf(stderr, "Have no way to get unique ID.\n");
312 | return -1;
313 | }
314 |
315 | read_len = read(macfile, macbuf, 128);
316 | if (read_len < 0) {
317 | fprintf(stderr, "Could not read MAC address file.\n");
318 | return -1;
319 | }
320 | close(macfile);
321 |
322 | // Create a command for setting a link-local address
323 | macbuf[14] = macbuf[15];
324 | macbuf[15] = macbuf[16];
325 | macbuf[16] = '\0';
326 | snprintf(cmd_lladdr_buf, 4096, "ifconfig %s add fe80::c298:e5ff:fe%s/64", ifr.ifr_name, macbuf+9);
327 |
328 | // Create the connection to the IPv6 tunnel server
329 | reconnect();
330 |
331 | // Now that everything is setup, block on the two reads and shuttle some
332 | // data.
333 |
334 | while (1) {
335 | // Clear the struct and set all fd that aren't 1
336 | FD_ZERO(&rfds);
337 | // Reset these each time in case tcp_socket changes after a reconnect
338 | FD_SET(tcp_socket, &rfds);
339 | nfds = tcp_socket + 1;
340 | FD_SET(tun_file, &rfds);
341 | if (tun_file + 1 > nfds) {
342 | nfds = tun_file + 1;
343 | }
344 |
345 | // This blocks
346 | ret = select(nfds, &rfds, NULL, NULL, NULL);
347 |
348 | if (ret < 0) {
349 | if (errno == EINTR) {
350 | // suppress
351 | } else {
352 | // error
353 | fprintf(stderr, "select return error: %i\n", ret);
354 | }
355 |
356 | } else if (ret == 0) {
357 | fprintf(stderr, "select return 0.\n");
358 |
359 | } else {
360 | if (FD_ISSET(tcp_socket, &rfds)) {
361 | // read from tcp
362 |
363 | read_len = recv(tcp_socket, buf, 4096, 0);
364 | if (read_len == 0) {
365 | reconnect();
366 | } else if (read_len < 0) {
367 | switch (errno) {
368 | case EAGAIN:
369 | // errant wakeup, just loop
370 | break;
371 | default:
372 | reconnect();
373 | }
374 | } else {
375 | ret = write(tun_file, buf, read_len);
376 | }
377 | }
378 |
379 | if (FD_ISSET(tun_file, &rfds)) {
380 | // read from tun
381 | read_len = read(tun_file, buf, 4906);
382 | if (read_len < 0) {
383 | switch (errno) {
384 | case EAGAIN:
385 | // errant wakeup, just loop
386 | break;
387 | default:
388 | fprintf(stderr, "Error occurred reading TUN\n");
389 | return -1;
390 | }
391 | } else {
392 | sent_len = send(tcp_socket, buf, read_len, 0);
393 | if (sent_len < 0) {
394 | reconnect();
395 | }
396 | }
397 | }
398 | }
399 | }
400 |
401 | return 0;
402 | }
403 |
--------------------------------------------------------------------------------
/gateway/tunnel/tunnel-server.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | // #include
12 | // #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 | #include "debug.h"
24 |
25 | #define TUNNEL_SERVER_LISTEN_PORT 32100
26 | #define MAXEVENTS 64
27 |
28 | struct ifreq6 {
29 | struct in6_addr addr;
30 | uint32_t prefix_len;
31 | unsigned int ifindex;
32 | };
33 |
34 | // // The prefix that all of the /60s come from
35 | // #define SLASH_48 "2001:db8:543:0::0"
36 | // // The global IP addresses for each client
37 | // #define SLASH_64 "2607:f017:999:1::0"
38 |
39 | // Data structure to hold all routing information for each connected client
40 | struct socket_prefix {
41 | struct in6_addr addr_pd; // The /60 (or whatever) that was assigned to this client. pd == prefix delegation
42 | uint32_t plen_pd; // 0 if not set, 60 (or the actual prefix) if set
43 | struct in6_addr addr_ll; // The link local assigned to this client
44 | uint32_t plen_ll; // 0 if not set, 128 if valid
45 | };
46 |
47 |
48 | struct ipv6hdr {
49 | #if defined(__LITTLE_ENDIAN_BITFIELD)
50 | __u8 priority:4,
51 | version:4;
52 | #elif defined(__BIG_ENDIAN_BITFIELD)
53 | __u8 version:4,
54 | priority:4;
55 | #else
56 | #error "Please fix "
57 | #endif
58 | uint8_t flow_lbl[3];
59 |
60 | uint16_t payload_len;
61 | uint8_t nexthdr;
62 | uint8_t hop_limit;
63 |
64 | struct in6_addr saddr;
65 | struct in6_addr daddr;
66 | };
67 |
68 |
69 | // Makes the given file descriptor non-blocking.
70 | // Returns 0 on success, -1 on failure.
71 | int make_nonblocking (int fd) {
72 | int flags, ret;
73 |
74 | flags = fcntl(fd, F_GETFL, 0);
75 | if (flags == -1) {
76 | return -1;
77 | }
78 | // Set the nonblocking flag.
79 | flags |= O_NONBLOCK;
80 | ret = fcntl(fd, F_SETFL, flags);
81 | if (ret == -1) {
82 | return -1;
83 | }
84 |
85 | return 0;
86 | }
87 |
88 |
89 | static int create_and_bind () {
90 | struct addrinfo hints;
91 | struct addrinfo *result;
92 | struct addrinfo *rp;
93 | int s;
94 | int sfd;
95 |
96 | memset(&hints, 0, sizeof(struct addrinfo));
97 | hints.ai_family = AF_INET;
98 | hints.ai_socktype = SOCK_STREAM; // tcp
99 | hints.ai_flags = AI_PASSIVE;
100 |
101 | s = getaddrinfo(NULL, "32100", &hints, &result);
102 | if (s != 0) {
103 | ERROR("Could not getaddrinfo.\n");
104 | return -1;
105 | }
106 |
107 | for (rp = result; rp != NULL; rp = rp->ai_next) {
108 | sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
109 | if (sfd == -1) {
110 | continue;
111 | }
112 |
113 | s = bind(sfd, rp->ai_addr, rp->ai_addrlen);
114 | if (s == 0) {
115 | // We managed to bind successfully!
116 | break;
117 | }
118 |
119 | close(sfd);
120 | }
121 |
122 | if (rp == NULL) {
123 | ERROR("Could not bind\n");
124 | return -1;
125 | }
126 |
127 | freeaddrinfo(result);
128 |
129 | return sfd;
130 | }
131 |
132 | void print_in6addr (struct in6_addr* a) {
133 | char str[INET6_ADDRSTRLEN];
134 | const char* ptr;
135 | ptr = inet_ntop(AF_INET6, a->s6_addr, str, INET6_ADDRSTRLEN);
136 | if (ptr == NULL) {
137 | perror("inet ntop");
138 | }
139 | printf("%s\n", str);
140 | // printf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
141 | // a->s6_addr[0],a->s6_addr[1], a->s6_addr[2], a->s6_addr[3], a->s6_addr[4],
142 | // a->s6_addr[5], a->s6_addr[6], a->s6_addr[7],
143 | // a->s6_addr[8],a->s6_addr[9], a->s6_addr[10], a->s6_addr[11], a->s6_addr[12],
144 | // a->s6_addr[13], a->s6_addr[14], a->s6_addr[15]);
145 | }
146 |
147 | static int parse_prefixes (struct socket_prefix* prefixes) {
148 |
149 | FILE* prefix_file;
150 | int read_len;
151 | int err;
152 |
153 | prefix_file = fopen("/etc/dibbler/client_assignments", "r");
154 | if (!prefix_file) {
155 | ERROR("Could not open file with prefixes.\n");
156 | ERROR("Does it exist?.\n");
157 | exit(1);
158 | }
159 |
160 |
161 | // Each line is:
162 | // fe80::1:2:3:4 2607:4::/60
163 | while (1) {
164 | char line[512];
165 | char* ptr;
166 | char* ptr2;
167 | int passes = 0;
168 | struct in6_addr local;
169 | struct in6_addr block;
170 | int match = 0;
171 |
172 |
173 | fgets(line, 512, prefix_file);
174 |
175 | if (feof(prefix_file)) {
176 | break;
177 | }
178 |
179 |
180 | ptr = line;
181 | while (1) {
182 | if (*ptr == '\0') {
183 | break;
184 | }
185 | if (passes == 0) {
186 | if (*ptr == ' ') {
187 | *ptr = '\0';
188 | ptr2 = ptr+1;
189 | err = inet_pton(AF_INET6, line, &local);
190 | if (err == 0) {
191 | printf("could not convert %s\n", line);
192 | }
193 | passes++;
194 | }
195 | } else {
196 | if (*ptr == '\n') {
197 | *ptr = '\0';
198 | *(ptr-1) = '0';
199 | *(ptr-2) = '0';
200 | *(ptr-3) = '0';
201 | err = inet_pton(AF_INET6, ptr2, &block);
202 | if (err == 0) {
203 | printf("could not convert %s\n", ptr2);
204 | }
205 | match = 1;
206 | break;
207 | }
208 | }
209 | ptr++;
210 | }
211 |
212 | if (match) {
213 |
214 | printf("Got local and block\n");
215 | print_in6addr(&local);
216 | print_in6addr(&block);
217 |
218 | // Got link local and the block.
219 | // Now match the link-local address and add the block.
220 | int j;
221 | for (j=0; j<512; j++) {
222 | struct socket_prefix* prefix = &prefixes[j];
223 | if (prefix->plen_ll != 0) {
224 | // Allow pd to be updated in case it changes
225 | printf("trying %i\n", j);
226 |
227 | // This could be the prefix match
228 | if (memcmp(prefix->addr_ll.s6_addr, local.s6_addr, 16) == 0) {
229 | // Found match!
230 | memcpy(prefix->addr_pd.s6_addr, block.s6_addr, 16);
231 | prefix->plen_pd = 62;
232 | printf("set %i as %02x\n", j, prefix->addr_pd.s6_addr[15]);
233 | print_in6addr(&prefix->addr_pd);
234 | break;
235 | }
236 | }
237 | }
238 | }
239 |
240 | }
241 |
242 | // read_len = read(macfile, macbuf, 128);
243 | // if (read_len < 0) {
244 | // fprintf(stderr, "Could not read MAC address file.\n");
245 | // return -1;
246 | // }
247 | close(prefix_file);
248 | }
249 |
250 |
251 | int main (int argc, char** argv) {
252 | struct ifreq ifr;
253 | struct ifreq6 ifr6;
254 | int err;
255 | char cmdbuf[4096];
256 | int sockfd;
257 | int tun_file;
258 |
259 | int sfd;
260 | int efd;
261 | struct epoll_event event;
262 | struct epoll_event *events;
263 |
264 | FILE* prefix_file;
265 | int num_valid_prefixes = 0;
266 | struct socket_prefix prefixes[512];
267 |
268 | struct in6_addr prefix_slash_52;
269 | struct in6_addr prefix_slash_64;
270 |
271 | if (argc != 3) {
272 | ERROR("usage: %s 52 full address> 64 full address>\n", argv[0]);
273 | exit(1);
274 | }
275 |
276 |
277 | // INIT
278 | memset(prefixes, 0, sizeof(prefixes));
279 | inet_pton(AF_INET6, argv[1], &prefix_slash_52);
280 | inet_pton(AF_INET6, argv[2], &prefix_slash_64);
281 |
282 |
283 |
284 |
285 | // Need to open a TUN device to get packets from linux and to send packets
286 | // to the kernel to be routed
287 | tun_file = open("/dev/net/tun", O_RDWR);
288 | if (tun_file < 0) {
289 | // error
290 | ERROR("Could not create a tun interface. errno: %i\n", errno);
291 | ERROR("%s\n", strerror(errno));
292 | exit(1);
293 | }
294 |
295 | // Clear the ifr struct
296 | memset(&ifr, 0, sizeof(ifr));
297 |
298 | // Set the TUN name
299 | strncpy(ifr.ifr_name, "ipv6-tun", IFNAMSIZ);
300 |
301 | // Select a TUN device
302 | ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
303 |
304 | // Make up a HW address
305 |
306 |
307 | // Setup the interface
308 | err = ioctl(tun_file, TUNSETIFF, (void *) &ifr);
309 | if (err < 0) {
310 | ERROR("ioctl could not set up tun interface\n");
311 | close(tun_file);
312 | exit(1);
313 | }
314 |
315 | // Make it persistent
316 | err = ioctl(tun_file, TUNSETPERSIST, 1);
317 | if (err < 0) {
318 | ERROR("Could not make persistent\n");
319 | exit(1);
320 | }
321 |
322 | // Make nonblocking in case select() gives us trouble
323 | make_nonblocking(tun_file);
324 |
325 | // Save the name of the tun interface
326 | // strncpy(tun_name, ifr.ifr_name, MAX_TUN_NAME_LEN);
327 |
328 | // Get a socket to perform the ioctls on
329 | sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
330 |
331 | // Set the interface to be up
332 | // ifconfig tun0 up
333 | err = ioctl(sockfd, SIOCGIFFLAGS, &ifr);
334 | if (err < 0) {
335 | ERROR("ioctl could not get flags.\n");
336 | close(tun_file);
337 | exit(1);
338 | }
339 | ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
340 | err = ioctl(sockfd, SIOCSIFFLAGS, &ifr);
341 | if (err < 0) {
342 | ERROR("ioctl could not bring up the TUN network interface.\n");
343 | perror("tup up");
344 | ERROR("errno: %i\n", errno);
345 | close(tun_file);
346 | exit(1);
347 | }
348 |
349 | // Set the MTU of the interface
350 | // ifconfig tun0 mtu 1280
351 | ifr.ifr_mtu = 1280;
352 | err = ioctl(sockfd, SIOCSIFMTU, &ifr);
353 | if (err < 0) {
354 | ERROR("ioctl could not set the MTU of the TUN network interface.\n");
355 | close(tun_file);
356 | exit(1);
357 | }
358 |
359 | // Get the ifr_index
360 | err = ioctl(sockfd, SIOCGIFINDEX, &ifr);
361 | if (err < 0) {
362 | ERROR("ioctl could not get ifindex.\n");
363 | close(tun_file);
364 | exit(1);
365 | }
366 |
367 | // Set a fake HW address
368 | // ifr.ifr_hwaddr.sa_data[0] = 0xc0;
369 | // ifr.ifr_hwaddr.sa_data[1] = 0x98;
370 | // ifr.ifr_hwaddr.sa_data[2] = 0xe5;
371 | // ifr.ifr_hwaddr.sa_data[3] = 0xaa;
372 | // ifr.ifr_hwaddr.sa_data[4] = 0x11;
373 | // ifr.ifr_hwaddr.sa_data[5] = 0xbb;
374 | // err = ioctl(sockfd, SIOCSIFHWADDR, &ifr);
375 | // if (err < 0) {
376 | // ERROR("Could not set hardware address.\n");
377 | // perror("SIOCSIFHWADDR");
378 | // close(tun_file);
379 | // exit(1);
380 | // }
381 |
382 | // Set a dummy link-local address on the interface
383 | //ifconfig tun0 inet6 add fe80::212:aaaa:bbbb:ffff/64
384 | inet_pton(AF_INET6, "fe80::c298:e5ff:feaa:11bb", &ifr6.addr);
385 | ifr6.prefix_len = 64;
386 | ifr6.ifindex = ifr.ifr_ifindex;
387 | err = ioctl(sockfd, SIOCSIFADDR, &ifr6);
388 | if (err < 0) {
389 | ERROR("ioctl could not set link-local address TUN network interface.\n");
390 | ERROR("perhaps it was already set\n");
391 | // close(tun_file);
392 | // exit(1);
393 | }
394 |
395 | close(sockfd);
396 |
397 |
398 |
399 |
400 | // SETUP TCP KEEP-ALIVES SO THAT WE KNOW WHEN A CLIENT DISCONNECTS SOONER
401 |
402 | int kafd;
403 | kafd = open("/proc/sys/net/ipv4/tcp_keepalive_time", O_WRONLY);
404 | if (kafd < 0) {
405 | ERROR("Could not open keepalive time\n");
406 | exit(1);
407 | }
408 | err = write(kafd, "60", 2);
409 | if (err == -1) {
410 | ERROR("Could not write keepalive time\n");
411 | perror("keepalive_time");
412 | exit(1);
413 | }
414 | close(kafd);
415 |
416 | kafd = open("/proc/sys/net/ipv4/tcp_keepalive_intvl", O_WRONLY);
417 | if (kafd < 0) {
418 | ERROR("Could not open keepalive interval\n");
419 | exit(1);
420 | }
421 | err = write(kafd, "20", 2);
422 | if (err == -1) {
423 | ERROR("Could not write keepalive interval\n");
424 | perror("keepalive_intvl");
425 | exit(1);
426 | }
427 | close(kafd);
428 |
429 | kafd = open("/proc/sys/net/ipv4/tcp_keepalive_probes", O_WRONLY);
430 | if (kafd < 0) {
431 | ERROR("Could not open keepalive probes\n");
432 | exit(1);
433 | }
434 | err = write(kafd, "3", 1);
435 | if (err == -1) {
436 | ERROR("Could not write keepalive probes\n");
437 | perror("keepalive_probes");
438 | exit(1);
439 | }
440 | close(kafd);
441 |
442 |
443 |
444 |
445 |
446 | // ACCEPT TCP CONNECTIONS FOR TUNNEL CLIENTS
447 |
448 | // Create a socket
449 | sfd = create_and_bind();
450 | if (sfd == -1) {
451 | ERROR("Could not create a socket\n");
452 | exit(1);
453 | }
454 |
455 | err = make_nonblocking(sfd);
456 | if (err == -1) {
457 | ERROR("Could not make socket nonblocking\n");
458 | exit(1);
459 | }
460 |
461 | err = listen(sfd, SOMAXCONN);
462 | if (err == -1) {
463 | ERROR("Could not listen on socket.\n");
464 | perror("listen");
465 | exit(1);
466 | }
467 |
468 | efd = epoll_create1(0);
469 | if (efd == -1) {
470 | perror("epoll_create");
471 | exit(1);
472 | }
473 |
474 | // Add the TCP socket to epoll
475 | event.data.fd = sfd;
476 | event.events = EPOLLIN | EPOLLET;
477 | err = epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &event);
478 | if (err == -1) {
479 | perror("epoll_ctl - TCP");
480 | exit(1);
481 | }
482 |
483 | // Add the TUN device to epoll
484 | event.data.fd = tun_file;
485 | event.events = EPOLLIN | EPOLLET;
486 | err = epoll_ctl(efd, EPOLL_CTL_ADD, tun_file, &event);
487 | if (err == -1) {
488 | perror("epoll_ctl - TUN");
489 | exit(1);
490 | }
491 |
492 | // Buffer where events are returned
493 | events = calloc(MAXEVENTS, sizeof(event));
494 |
495 |
496 |
497 |
498 | // The event loop
499 | while (1) {
500 | int n, i;
501 |
502 | // Wait for something to happen on one of the file descriptors
503 | // we are waiting on
504 | n = epoll_wait(efd, events, MAXEVENTS, -1);
505 |
506 | // Iterate all of the active events
507 | for (i = 0; i < n; i++) {
508 |
509 | // Check that everything is kosher
510 | if ((events[i].events & EPOLLERR) ||
511 | (events[i].events & EPOLLHUP) ||
512 | (!(events[i].events & EPOLLIN))) {
513 | // An error has occured on this fd, or the socket is not
514 | // ready for reading (why were we notified then?)
515 | ERROR("epoll error\n");
516 | continue;
517 |
518 | // Check if this is a new connection on the TCP listening socket
519 | } else if (events[i].data.fd == sfd) {
520 | while (1) {
521 | struct sockaddr in_addr;
522 | socklen_t in_len;
523 | int infd;
524 | char hbuf[NI_MAXHOST];
525 | char sbuf[NI_MAXSERV];
526 |
527 | in_len = sizeof(in_addr);
528 | infd = accept(sfd, &in_addr, &in_len);
529 | if (infd == -1) {
530 | if ((errno == EAGAIN) ||
531 | (errno == EWOULDBLOCK)) {
532 | // We have processed all incoming connections.
533 | break;
534 | } else {
535 | perror("accept");
536 | break;
537 | }
538 | }
539 |
540 | err = getnameinfo(&in_addr,
541 | in_len,
542 | hbuf,
543 | sizeof(hbuf),
544 | sbuf,
545 | sizeof(sbuf),
546 | NI_NUMERICHOST | NI_NUMERICSERV);
547 | if (err == 0) {
548 | DBG("Accepted connection on descriptor %d "
549 | "(host=%s, port=%s)\n", infd, hbuf, sbuf);
550 | }
551 |
552 | // Make the incoming socket non-blocking and add it to the
553 | // list of fds to monitor.
554 | err = make_nonblocking(infd);
555 | if (err == -1) {
556 | ERROR("Could not make nonblocking\n");
557 | exit(1);
558 | }
559 |
560 | event.data.fd = infd;
561 | event.events = EPOLLIN | EPOLLET;
562 | err = epoll_ctl(efd, EPOLL_CTL_ADD, infd, &event);
563 | if (err == -1) {
564 | perror ("epoll_ctl");
565 | exit(1);
566 | }
567 | }
568 |
569 | continue;
570 |
571 | // Check if we got data on the tun device
572 | // } else if (events[i].data.fd == tun_file) {
573 |
574 | // }
575 |
576 | } else {
577 | // Some socket has data ready. Read it all and handle it.
578 |
579 | int done = 0;
580 |
581 | // Loop until we have all of the data
582 | while (1) {
583 | ssize_t count;
584 | char buf[4096];
585 |
586 | count = read(events[i].data.fd, buf, sizeof(buf));
587 | if (count == -1){
588 | // If errno == EAGAIN, that means we have read all
589 | // data. So go back to the main loop.
590 | if (errno != EAGAIN) {
591 | perror ("read");
592 | done = 1;
593 | }
594 | break;
595 | } else if (count == 0) {
596 | // End of file. The remote has closed the
597 | // connection.
598 | done = 1;
599 | break;
600 | }
601 |
602 | if (events[i].data.fd == tun_file) {
603 | // Got a packet from the TUN device. Now we have to figure out
604 | // which TCP socket to send it to.
605 | printf("GOT DATA FROM TUN\n");
606 |
607 | struct ipv6hdr *iph = (struct ipv6hdr*) buf;
608 |
609 | if (iph->version == 6) {
610 |
611 | // Check to see if the packet is in the /52 that this tunnel
612 | // is responsible for
613 | if (memcmp(iph->daddr.s6_addr, prefix_slash_52.s6_addr, 6) == 0 &&
614 | ((iph->daddr.s6_addr[6] & 0xf0) == (prefix_slash_52.s6_addr[6] & 0xf0))) {
615 | printf("This dest in /52\n");
616 |
617 | // This is in the /52
618 | // Need to find a match for this destination
619 | int j;
620 | int match = 0;
621 | for (j=0; j<512; j++) {
622 | if (prefixes[j].plen_pd != 0 &&
623 | memcmp(iph->daddr.s6_addr, prefixes[j].addr_pd.s6_addr, 7) == 0 &&
624 | ((iph->daddr.s6_addr[7] & 0xfc) == (prefixes[j].addr_pd.s6_addr[7] & 0xfc))) {
625 | // Found match
626 | printf("Found destination with matching /62.\n");
627 | err = write(j, buf, count);
628 | match = 1;
629 | break;
630 | }
631 | }
632 |
633 | if (!match) {
634 | printf("Could not find match originally. Reading assignments\n");
635 | parse_prefixes(prefixes);
636 |
637 | // Check for matches again
638 | for (j=0; j<512; j++) {
639 | if (prefixes[j].plen_pd != 0 &&
640 | memcmp(iph->daddr.s6_addr, prefixes[j].addr_pd.s6_addr, 7) == 0 &&
641 | ((iph->daddr.s6_addr[7] & 0xfc) == (prefixes[j].addr_pd.s6_addr[7] & 0xfc))) {
642 | // Found match
643 | printf("Found destination with matching /62 after loading prefixes.\n");
644 | err = write(j, buf, count);
645 | break;
646 | }
647 | }
648 | }
649 |
650 | // Check to see if destination is in /64 or ll
651 | } else if (memcmp(iph->daddr.s6_addr, prefix_slash_64.s6_addr, 8) == 0 ||
652 | (iph->daddr.s6_addr[0] == 0xfe &&
653 | iph->daddr.s6_addr[1] == 0x80)) {
654 | printf("This dest in /64 or link local\n");
655 |
656 | // Need to find a match for this destination
657 | int j=0;
658 | for (j=0; j<512; j++) {
659 | if (prefixes[j].plen_ll != 0) {
660 | printf("checking tcp %i\n", j);
661 | printf("%02x%02x%02x%02x%02x%02x%02x%02x\n", iph->daddr.s6_addr[8],
662 | iph->daddr.s6_addr[9], iph->daddr.s6_addr[10], iph->daddr.s6_addr[11], iph->daddr.s6_addr[12],
663 | iph->daddr.s6_addr[13], iph->daddr.s6_addr[14], iph->daddr.s6_addr[15]);
664 | printf("%02x%02x%02x%02x%02x%02x%02x%02x\n", prefixes[j].addr_ll.s6_addr[8],
665 | prefixes[j].addr_ll.s6_addr[9], prefixes[j].addr_ll.s6_addr[10], prefixes[j].addr_ll.s6_addr[11], prefixes[j].addr_ll.s6_addr[12],
666 | prefixes[j].addr_ll.s6_addr[13], prefixes[j].addr_ll.s6_addr[14], prefixes[j].addr_ll.s6_addr[15]);
667 | }
668 | if (prefixes[j].plen_ll != 0 &&
669 | memcmp(iph->daddr.s6_addr+8, prefixes[j].addr_ll.s6_addr+8, 8) == 0) {
670 | // Found match
671 | printf("Found TCP destination for packet.\n");
672 | err = write(j, buf, count);
673 | break;
674 | }
675 | }
676 |
677 |
678 | } else {
679 | printf("some other packet, can't forward\n");
680 | }
681 | }
682 |
683 | } else {
684 | // Got this from one of the TCP connections
685 |
686 | if (events[i].data.fd < 512) {
687 | // Not outside the bounds
688 | struct socket_prefix* prefix = &prefixes[events[i].data.fd];
689 |
690 | // Check to see if we know the link local address of this client.
691 | if (prefix->plen_ll == 0) {
692 | // We do not know the link local address of this node. That is
693 | // bad, because we will not know how to route to it when we get
694 | // packets for it.
695 |
696 | // Inspect the packet to determine the IPv6 source address
697 | struct ipv6hdr *iph = (struct ipv6hdr*) buf;
698 |
699 | if (iph->version == 6) {
700 | // OK good, got IPv6 packet
701 |
702 | if (iph->saddr.s6_addr[0] == 0xfe &&
703 | iph->saddr.s6_addr[1] == 0x80) {
704 | // This came from link-local address. Great.
705 | // Save this
706 | memcpy(&prefix->addr_ll, &iph->saddr, sizeof(struct in6_addr));
707 | prefix->plen_ll = 128;
708 | }
709 | }
710 | }
711 | }
712 |
713 |
714 | //6 00 00000 0024 00 01 fe800000000000000000000099990001 ff0200000000000000000000000000163a000502000001008f00d66e0000000104000000ff020000000000000000000000000002
715 |
716 |
717 |
718 |
719 | int arghhh;
720 | for (arghhh = 0; arghhh < count; ++arghhh)
721 | {
722 | // code
723 | printf("%02x", buf[arghhh]);
724 | }
725 | printf("\n");
726 |
727 |
728 | // }
729 |
730 |
731 |
732 | // Now dump it to the TUN device
733 | err = write(tun_file, buf, count);
734 |
735 | printf("wrote to tun\n");
736 |
737 | }
738 |
739 |
740 | /* Write the buffer to standard output */
741 | // err = write(1, buf, count);
742 | // if (err == -1) {
743 | // perror ("write");
744 | // abort ();
745 | // }
746 | }
747 |
748 | if (done) {
749 | printf("CLOSED\n");
750 | printf(" descriptor %d\n", events[i].data.fd);
751 | printf(" ");
752 | print_in6addr(&prefixes[events[i].data.fd].addr_ll);
753 | printf(" ");
754 | print_in6addr(&prefixes[events[i].data.fd].addr_pd);
755 |
756 | // Closing the descriptor will make epoll remove it
757 | // from the set of descriptors which are monitored.
758 | close (events[i].data.fd);
759 | prefixes[events[i].data.fd].plen_ll = 0;
760 | prefixes[events[i].data.fd].plen_pd = 0;
761 | }
762 | }
763 | }
764 | }
765 |
766 | free (events);
767 |
768 | close (sfd);
769 | close (tun_file);
770 |
771 | return EXIT_SUCCESS;
772 | }
773 |
774 |
775 |
776 | // Register the file descriptor with the IO manager that will call select()
777 | // call IO.registerFileDescriptor(tun_file);
778 |
779 | // while (1);
780 | // }
781 |
782 | // Runs a command on the local system using
783 | // the kernel command interpreter.
784 | // int ssystem(const char *fmt, ...) {
785 | // char cmd[128];
786 | // va_list ap;
787 | // va_start(ap, fmt);
788 | // vsnprintf(cmd, sizeof(cmd), fmt, ap);
789 | // va_end(ap);
790 | // DBG("%s\n", cmd);
791 | // return system(cmd);
792 | // }
793 |
--------------------------------------------------------------------------------
/hardware/eagle/.gitignore:
--------------------------------------------------------------------------------
1 | *.b#*
2 | *.s#*
3 | *.l#*
4 |
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/.gitignore:
--------------------------------------------------------------------------------
1 | *bak
2 | *bck
3 | *.l#*
4 | *.s#*
5 | *.b#*
6 | *.top
7 | *.bot
8 | *.L1
9 | *.L2
10 | *.L3
11 | *.L4
12 | *.bsp
13 | *.tsp
14 | *.bps
15 | *.bsk
16 | *.drd
17 | *.dri
18 | *.dru
19 | *.gpi
20 | *.oln
21 | *.slk
22 | *.smb
23 | *.smt
24 | *.tps
25 | *.centroid
26 | *.svg
27 | *.mil
28 | *.crop
29 | *.hs
30 | .~lock.*.xlsx#
31 | _autosave-*.kicad_pcb
32 | kicad.pretty
33 | $*.sch
34 |
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_a/bbb-cc2520_7-25-14_gerber_sunstone.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_a/bbb-cc2520_7-25-14_gerber_sunstone.zip
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_a/bbb-cc2520_7-28-14_gerber_OSHPark.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_a/bbb-cc2520_7-28-14_gerber_OSHPark.zip
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_a/bbb-cc2520_a.pro:
--------------------------------------------------------------------------------
1 | EAGLE AutoRouter Statistics:
2 |
3 | Job : F:/Documents/Work-Lab11/beaglebone-cc2520/hardware/eagle/bbb-cc2520/rev_a/bbb-cc2520_a.brd
4 |
5 | Start at : 14:34:08 (7/2/2014)
6 | End at : 14:34:11 (7/2/2014)
7 | Elapsed time : 00:00:03
8 |
9 | Signals : 30 RoutingGrid: 8 mil Layers: 2
10 | Connections : 73 predefined: 55 ( 94 Vias )
11 |
12 | Router memory : 395872
13 |
14 | Passname : Busses Route Optimize1 Optimize2 Optimize3 Optimize4
15 |
16 | Time per pass : 00:00:00 00:00:01 00:00:00 00:00:01 00:00:01 00:00:00
17 | Number of Ripups : 0 0 0 0 0 0
18 | max. Level : 0 0 0 0 0 0
19 | max. Total : 0 0 0 0 0 0
20 |
21 | Routed : 3 18 18 18 18 18
22 | Vias : 0 34 19 10 9 9
23 | Resolution : 79.5 % 100.0 % 100.0 % 100.0 % 100.0 % 100.0 %
24 |
25 | Final : 98.6% finished. Polygons may have fallen apart.
26 |
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_a/bbb-cc2520_a_bom.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_a/bbb-cc2520_a_bom.xlsx
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_b/Zigbeag_b_10-06-14_gerber_sunstone.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_b/Zigbeag_b_10-06-14_gerber_sunstone.zip
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_b/bbb-cc2520_b_bom.csv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_b/bbb-cc2520_b_bom.csv
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_b/bbb-cc2520_b_bom.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_b/bbb-cc2520_b_bom.xlsx
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_c/BoardStackup.txt:
--------------------------------------------------------------------------------
1 | PCB NAME : ZIGBEAG
2 | REVISION: C
3 | DATE: 2014-11-20
4 |
5 | PCB DESCRIPTION:4 LAYER PCB 1.6 MM
6 | Copper 1 35 um
7 | Dielectric 1-2 0.175 mm (e.g. 1x Prepreg 7628 AT05 47% Resin)
8 | Copper 2 18 um
9 | Dielectric 2-3 1.14 mm (6x 7628M 43% Resin)
10 | Copper 3 18 um
11 | Dielectric 3-4 0.175 mm (e.g. 1x Prepreg 7628 AT05 47% Resin)
12 | Copper 4 35 um
13 | DE104iML or equivalent substrate (Resin contents around 45%, which gives Er=4.42@2.4GHz, TanD=0.016)
14 | Dimensions in mil (0.001 inch)
15 | DOUBLE SIDE SOLDER MASK,
16 | TOP SIDE SILKSCREEN,
17 | 8 MIL MIN TRACE WIDTH AND 5 MIL MIN ISOLATION.
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_c/bbb-cc2520.info:
--------------------------------------------------------------------------------
1 | title: Zigbeag
2 | rev: B
3 | author: Neal Jackson
4 |
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_c/bbb-cc2520.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_c/bbb-cc2520.pdf
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_c/bbb-cc2520_bom.csv:
--------------------------------------------------------------------------------
1 | Qty,Value,Device,Package,Parts,Description,DIGIKEY,SAMTEC,MAJOR LEAGUE
2 | 3,MOLEX_WM5544-ND,MOLEX_WM5544-ND,MOLEX_WM5544-ND,"ANT1, ANT2, ANT3",Through-hole SMA Antenna,WM5544-ND,,
3 | 1,2450BM15A0002,2450BM15A0002,2450BM,B1,BALUN JTI MATCHED ZIGBEE,712-1536-1-ND,,
4 | 1,BAL-NRF01D3,BAL-NRF01D3,BAL-NRF01D3,B2,"50 ohm nominal input / conjugate match balun to nRF51422-QFAA,",497-13637-1-ND,,
5 | 1,0.8pF,CAPACITOR,0402_CAP,C1,0402 Capacitor,490-6269-1-ND,,
6 | 1,1pF,C-EUC0402,C0402,C2,"Capacitor, 1p, 0402, NP0, +/-0.1pF 50V",490-6206-1-ND,,
7 | 1,2.7pF,C-EUC0402,C0402,C3,"Capacitor, 2p7, 0402, NP0, +-0.25pF, 50V",490-5934-1-ND,,
8 | 1,3pF,C-EUC0402,C0402,C4,"Capacitor, 3p, 0402, NP0, +-0.25pF, 50V",490-5872-1-ND,,
9 | 1,3.9pF,C-EUC0402,C0402,C5,"Capacitor, 3p9, 0402, NP0, +-0.25pF, 50V",490-1272-1-ND,,
10 | 1,6.8pF,C-EUC0402,C0402,C6,"Capacitor, 6p8, 0402, NP0, +-0.25pF 50V",490-5949-1-ND,,
11 | 2,12pF,CAPACITOR,0402_CAP,"C7, C8",0402 Capacitor,490-6197-1-ND,,
12 | 1,15pF,C-EUC0402,C0402,C9,"Capacitor, 15p, 0402, NP0, 5%, 50V",490-5888-1-ND,,
13 | 4,27pF,C-EUC0402,C0402,"C10, C11, C12, C13","Capacitor, 27p, 0402, NP0, 5%, 50V",490-5869-1-ND,,
14 | 3,1nF,C-EUC0402,C0402,"C14, C15, C16","Capacitor, 1n, 0402, NP0, 5%, 50V",490-3244-1-ND,,
15 | 2,1nF,CAPACITOR,0402_CAP,"C17, C18",0402 Capacitor,490-1303-1-ND,,
16 | 1,2.2nF,CAPACITOR,0402_CAP,C19,0402 Capacitor,490-5419-1-ND,,
17 | 1,47nF,CAPACITOR,0402_CAP,C20,0402 Capacitor,445-1264-1-ND,,
18 | 9,100nF,C-EUC0402,C0402,"C21, C22, C23, C24, C25, C26, C27, C28, C29","Capacitor, 100n, 0402, X5R, 10%, 10V",490-1318-1-ND,,
19 | 1,0.1uF,CAPACITOR,0402_CAP,C30,0402 Capacitor,445-4952-1-ND,,
20 | 1,1uF,CAPACITOR,0402_CAP,C31,0402 Capacitor,1276-1513-1-ND,,
21 | 2,1uF,C-EUC0603,C0603,"C32, C33","Capacitor, 1u0, 0402, X5R, 10%, 6.3V",490-1550-1-ND,,
22 | 1,2.2uF,C-EUC0402,C0402,C34,"Capacitor, 2u2, 0402, X5R, 20%, 4V",490-4518-1-ND,,
23 | 1,4.7uF,CAPACITOR,0402_CAP,C35,0402 Capacitor,445-5947-1-ND,,
24 | 1,GREEN,LED0603,LED-0603,D1,LEDs,160-1834-1-ND,,
25 | 1,RED,LED0603,LED-0603,D2,LEDs,160-1835-1-ND,,
26 | 1,BLUE,LED0603,LED-0603,D3,LEDs,160-1837-1-ND,,
27 | 1,YELLOW,LED0603,LED-0603,D4,LEDs,160-1831-1-ND,,
28 | 1,JUMPER-PTH-2-NO,JUMPER-PTH-2-NO,PTH-JUMPER-2-NO_NO_SILK,J2,,3M9447-ND,,
29 | 4,1nH,INDUCTOR0402,C0402,"L1, L2, L3, L4","Inductor, 1n0, 0402, Monolithic type, +/-0.3 nH",490-2610-1-ND,,
30 | 1,1.1nH,INDUCTOR0402,C0402,L5,"Inductor, 1n1, 0402, Monolithic type, +/-0.3 nH",490-6567-1-ND,,
31 | 1,1.5nH,INDUCTOR0402,C0402,L6,"Inductor, 1n5, 0402, wire-wound type, +/-0.1 nH",490-6782-1-ND,,
32 | 1,2nH,INDUCTOR0402,C0402,L7,"Inductor, 2n0, 0402, +/-0.3 nH",490-6569-1-ND,,
33 | 1,5.1nH,INDUCTOR0402,C0402,L8,"Inductor, 5n1, 0402, +/-0.3 nH",490-6573-1-ND,,
34 | 1,15nH,INDUCTOR0402,0402_CAP,L9,,587-1521-1-ND,,
35 | 1,10uH,INDUCTOR0603,0603_CAP,L10,,490-4025-1-ND,,
36 | 1,1k Ohm,INDUCTOR0402,C0402,L11,"EMI filter bead, 0402 1Kohms GHz Band Gen Use",490-3999-1-ND,,
37 | 2,1k Ohm,INDUCTOR0603,L0603,"L12, L13","EMI filter bead, 0603 1Kohms GHz Band Gen Use",490-1015-1-ND,,
38 | 2,BBB_HEADERS,BBB_HEADERS,BBB_HEADERS,"P8, P9",2x23 Pin Header,,SSW-123-03-T-D,SSHQ-123-D-08-G-LF
39 | 3,470 ohm,R-US_R0402,R0402,"R1, R2, R3, R4","RESISTOR, American symbol",RHM470CDCT-ND,,
40 | 2,1k 1%,R-US_R0402,R0402,"R5, R6","RESISTOR, American symbol",RHM1.00KCDCT-ND,,
41 | 1,4.3k,R-US_R0402,R0402,R7,"RESISTOR, American symbol",1276-4078-1-ND,,
42 | 3,4.75k,R-US_R0402,R0402,"R8, R9, R10","RESISTOR, American symbol",1276-4083-1-ND,,
43 | 2,5.6k 5%,R-US_R0402,R0402,"R11, R12","RESISTOR, American symbol",RHM5.6KCGCT-ND,,
44 | 1,10k 1%,R-US_R0402,R0402,"R13, R14, R15, R16","RESISTOR, American symbol",RHM10.0KCDCT-ND,,
45 | 1,12k,RESISTOR,0603-RES,R17,Resistor,RHM12.0KCDCT-ND,,
46 | 2,56k 1%,R-US_R0402,R0402,"R18, R19","RESISTOR, American symbol",P56.0KLCT-ND,,
47 | 1,330k 1%,R-US_R0402,R0402,R20,"RESISTOR, American symbol",RHM330KCFCT-ND,,
48 | 2,1M 1%,R-US_R0402,R0402,"R21, R22","RESISTOR, American symbol",RHM1.00MCDCT-ND,,
49 | 3,TEST_POINT_0.040IN,TEST_POINT_0.040IN,TESTPOINT_0.040IN,"TP0, TP1, TP2",0.040in Test Point,5001K-ND,,
50 | 2,CC2520,CC2520,S-PVQFN-N28,"U1, U2",2.4 GHZ IEEE 802.15.4/ZIGBEE® RF TRANSCEIVER,296-22996-1-ND,,
51 | 1,CAT24C256WI-GT3,CAT24C256WI-GT3,SOIC-8,U3,256kb Serial CMOS EEPROM,CAT24C256WI-GT3OSCT-ND,,
52 | 1,CC2591,CC2591,PVQFN-16,U4,2.4GHz Range Extender,296-23603-1-ND,,
53 | 1,CD4051B-53B,CD4051B-53B,TSSOP16,U5,IC MUX/DEMUX 8x1 16TSSOP,296-11993-1-ND,,
54 | 1,NRF51822QF,NRF51822QF,QFN-48-6MM,U6,Multiprotocol Bluetooth® 4.0 low energy/2.4 GHz RF SoC,1490-1031-1-ND,,
55 | 2,NX2520SA,NX2520SA,NX2520SA,"X1, X2",CRYSTAL 32MHZ 10PF SMD,644-1065-1-ND,,
56 | 1,16MHz,TXC-8Y,TXC-8Y,X3,2mmx1.6mm SMD Crystal,887-2003-1-ND,,
57 |
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_c/bbb-cc2520_bom.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_c/bbb-cc2520_bom.xlsx
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_c/bbb-cc2520_c_2014-11-20.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_c/bbb-cc2520_c_2014-11-20.zip
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_c/bbb-cc2520_c_to_assembler_2014-11-20.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_c/bbb-cc2520_c_to_assembler_2014-11-20.zip
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_c/bbb-cc2520_c_to_fab_2014-11-20.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_c/bbb-cc2520_c_to_fab_2014-11-20.zip
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_c/bbb-cc2520_pcb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_c/bbb-cc2520_pcb.png
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_c/gap_c_panel_2014-11-20.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_c/gap_c_panel_2014-11-20.zip
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_d/BoardStackup.txt:
--------------------------------------------------------------------------------
1 | PCB NAME : GAP
2 | REVISION: D
3 | DATE: 2015-04-03
4 |
5 | PCB DESCRIPTION:4 LAYER PCB 1.6 MM
6 | Copper 1 35 um
7 | Dielectric 1-2 0.175 mm (e.g. 1x Prepreg 7628 AT05 47% Resin)
8 | Copper 2 18 um
9 | Dielectric 2-3 1.14 mm (6x 7628M 43% Resin)
10 | Copper 3 18 um
11 | Dielectric 3-4 0.175 mm (e.g. 1x Prepreg 7628 AT05 47% Resin)
12 | Copper 4 35 um
13 | DE104iML or equivalent substrate (Resin contents around 45%, which gives Er=4.42@2.4GHz, TanD=0.016)
14 | Dimensions in mil (0.001 inch)
15 | DOUBLE SIDE SOLDER MASK,
16 | TOP SIDE SILKSCREEN,
17 | 8 MIL MIN TRACE WIDTH AND 5 MIL MIN ISOLATION.
18 |
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_d/bbb-cc2520.info:
--------------------------------------------------------------------------------
1 | title: GAP
2 | rev: D
3 | author: Neal Jackson
4 |
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_d/bbb-cc2520.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_d/bbb-cc2520.pdf
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_d/bbb-cc2520_bom.csv:
--------------------------------------------------------------------------------
1 | Qty,Value,Device,Package,Parts,Description,DIGIKEY,SAMTEC,MAJOR LEAGUE
2 | 3,MOLEX_WM5544-ND,MOLEX_WM5544-ND,MOLEX_WM5544-ND,"ANT1, ANT2, ANT3",Through-hole SMA Antenna,WM5544-ND,,
3 | 1,2450BM15A0002,2450BM15A0002,2450BM,B1,BALUN JTI MATCHED ZIGBEE,712-1536-1-ND,,
4 | 1,BAL-NRF01D3,BAL-NRF01D3,BAL-NRF01D3,B2,"50 ohm nominal input / conjugate match balun to nRF51422-QFAA,",497-13637-1-ND,,
5 | 1,0.8pF,CAPACITOR,0402_CAP,C1,0402 Capacitor,490-6269-1-ND,,
6 | 1,1pF,C-EUC0402,C0402,C2,"Capacitor, 1p, 0402, NP0, +/-0.1pF 50V",490-6206-1-ND,,
7 | 1,2.7pF,C-EUC0402,C0402,C3,"Capacitor, 2p7, 0402, NP0, +-0.25pF, 50V",490-5934-1-ND,,
8 | 1,3pF,C-EUC0402,C0402,C4,"Capacitor, 3p, 0402, NP0, +-0.25pF, 50V",490-5872-1-ND,,
9 | 1,3.9pF,C-EUC0402,C0402,C5,"Capacitor, 3p9, 0402, NP0, +-0.25pF, 50V",490-1272-1-ND,,
10 | 1,6.8pF,C-EUC0402,C0402,C6,"Capacitor, 6p8, 0402, NP0, +-0.25pF 50V",490-5949-1-ND,,
11 | 2,12pF,CAPACITOR,0402_CAP,"C7, C8",0402 Capacitor,490-6197-1-ND,,
12 | 1,15pF,C-EUC0402,C0402,C9,"Capacitor, 15p, 0402, NP0, 5%, 50V",490-5888-1-ND,,
13 | 4,27pF,C-EUC0402,C0402,"C10, C11, C12, C13","Capacitor, 27p, 0402, NP0, 5%, 50V",490-5869-1-ND,,
14 | 3,1nF,C-EUC0402,C0402,"C14, C15, C16","Capacitor, 1n, 0402, NP0, 5%, 50V",490-3244-1-ND,,
15 | 2,1nF,CAPACITOR,0402_CAP,"C17, C18",0402 Capacitor,490-1303-1-ND,,
16 | 1,2.2nF,CAPACITOR,0402_CAP,C19,0402 Capacitor,490-5419-1-ND,,
17 | 1,47nF,CAPACITOR,0402_CAP,C20,0402 Capacitor,445-1264-1-ND,,
18 | 9,100nF,C-EUC0402,C0402,"C21, C22, C23, C24, C25, C26, C27, C28, C29","Capacitor, 100n, 0402, X5R, 10%, 10V",490-1318-1-ND,,
19 | 1,0.1uF,CAPACITOR,0402_CAP,C30,0402 Capacitor,445-4952-1-ND,,
20 | 1,1uF,CAPACITOR,0402_CAP,C31,0402 Capacitor,1276-1513-1-ND,,
21 | 2,1uF,C-EUC0603,C0603,"C32, C33","Capacitor, 1u0, 0603, X5R, 10%, 6.3V",490-1550-1-ND,,
22 | 1,2.2uF,C-EUC0402,C0402,C34,"Capacitor, 2u2, 0402, X5R, 20%, 4V",490-4518-1-ND,,
23 | 1,4.7uF,CAPACITOR,0402_CAP,C35,0402 Capacitor,445-5947-1-ND,,
24 | 1,GREEN,LED0603,LED-0603,D1,LEDs,160-1834-1-ND,,
25 | 1,RED,LED0603,LED-0603,D2,LEDs,160-1835-1-ND,,
26 | 1,BLUE,LED0603,LED-0603,D3,LEDs,160-1837-1-ND,,
27 | 1,YELLOW,LED0603,LED-0603,D4,LEDs,160-1831-1-ND,,
28 | 1,JUMPER-PTH-2-NO,JUMPER-PTH-2-NO,PTH-JUMPER-2-NO_NO_SILK,J2,,3M9447-ND,,
29 | 4,1nH,INDUCTOR0402,C0402,"L1, L2, L3, L4","Inductor, 1n0, 0402, Monolithic type, +/-0.3 nH",490-2610-1-ND,,
30 | 1,1.1nH,INDUCTOR0402,C0402,L5,"Inductor, 1n1, 0402, Monolithic type, +/-0.3 nH",490-6567-1-ND,,
31 | 1,1.5nH,INDUCTOR0402,C0402,L6,"Inductor, 1n5, 0402, wire-wound type, +/-0.1 nH",490-6782-1-ND,,
32 | 1,2nH,INDUCTOR0402,C0402,L7,"Inductor, 2n0, 0402, +/-0.3 nH",490-6569-1-ND,,
33 | 1,5.1nH,INDUCTOR0402,C0402,L8,"Inductor, 5n1, 0402, +/-0.3 nH",490-6573-1-ND,,
34 | 1,15nH,INDUCTOR0402,0402_CAP,L9,,587-1521-1-ND,,
35 | 1,10uH,INDUCTOR0603,0603_CAP,L10,,490-4025-1-ND,,
36 | 1,1k Ohm,INDUCTOR0402,C0402,L11,"EMI filter bead, 0402 1Kohms GHz Band Gen Use",490-3999-1-ND,,
37 | 2,1k Ohm,INDUCTOR0603,L0603,"L12, L13","EMI filter bead, 0603 1Kohms GHz Band Gen Use",490-1015-1-ND,,
38 | 2,BBB_HEADERS,BBB_HEADERS,BBB_HEADERS,"P8, P9",2x23 Pin Header,,SSQ-123-03-T-D,SSHQ-123-D-08-G-LF
39 | 4,470 ohm,R-US_R0402,R0402,"R1, R2, R3, R4","RESISTOR, American symbol",RHM470CDCT-ND,,
40 | 2,1k 1%,R-US_R0402,R0402,"R5, R6","RESISTOR, American symbol",RHM1.00KCDCT-ND,,
41 | 1,4.3k,R-US_R0402,R0402,R7,"RESISTOR, American symbol",1276-4078-1-ND,,
42 | 3,4.75k,R-US_R0402,R0402,"R8, R9, R10","RESISTOR, American symbol",1276-4083-1-ND,,
43 | 2,5.6k 5%,R-US_R0402,R0402,"R11, R12","RESISTOR, American symbol",RHM5.6KCECT-ND,,
44 | 4,10k 1%,R-US_R0402,R0402,"R13, R14, R15, R16","RESISTOR, American symbol",RHM10.0KCDCT-ND,,
45 | 1,12k,RESISTOR,0603-RES,R17,Resistor,RHM12.0KCDCT-ND,,
46 | 2,56k 1%,R-US_R0402,R0402,"R18, R19","RESISTOR, American symbol",P56.0KLCT-ND,,
47 | 1,330k 1%,R-US_R0402,R0402,R20,"RESISTOR, American symbol",RHM330KCFCT-ND,,
48 | 2,1M 1%,R-US_R0402,R0402,"R21, R22","RESISTOR, American symbol",RHM1.00MCDCT-ND,,
49 | 3,TEST_POINT_0.040IN,TEST_POINT_0.040IN,TESTPOINT_0.040IN,"TP0, TP1, TP2",0.040in Test Point,5001K-ND,,
50 | 2,CC2520,CC2520,S-PVQFN-N28,"U1, U2",2.4 GHZ IEEE 802.15.4/ZIGBEE® RF TRANSCEIVER,296-22996-1-ND,,
51 | 1,CAT24C256WI-GT3,CAT24C256WI-GT3,SOIC-8,U3,256kb Serial CMOS EEPROM,CAT24C256WI-GT3OSCT-ND,,
52 | 1,CC2591,CC2591,PVQFN-16,U4,2.4GHz Range Extender,296-23603-1-ND,,
53 | 1,CD4051B-53B,CD4051B-53B,TSSOP16,U5,IC MUX/DEMUX 8x1 16TSSOP,296-11993-1-ND,,
54 | 1,NRF51822QF,NRF51822QF,QFN-48-6MM,U6,Multiprotocol Bluetooth® 4.0 low energy/2.4 GHz RF SoC 32kB/256kB,1490-1042-1-ND,,
55 | 2,NX2520SA,NX2520SA,NX2520SA,"X1, X2",CRYSTAL 32MHZ 10PF SMD,644-1065-1-ND,,
56 | 1,16MHz,TXC-8Y,TXC-8Y,X3,2mmx1.6mm SMD Crystal,887-2003-1-ND,,
57 |
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_d/bbb-cc2520_bom.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_d/bbb-cc2520_bom.xlsx
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_d/bbb-cc2520_d_2015-04-03.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_d/bbb-cc2520_d_2015-04-03.zip
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_d/bbb-cc2520_d_to_assembler_2015-04-03.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_d/bbb-cc2520_d_to_assembler_2015-04-03.zip
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_d/bbb-cc2520_d_to_fab_2015-04-03.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_d/bbb-cc2520_d_to_fab_2015-04-03.zip
--------------------------------------------------------------------------------
/hardware/eagle/bbb-cc2520/rev_d/bbb-cc2520_pcb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lab11/gap/16f6ea092f23031f5845668e326291c85097b509/hardware/eagle/bbb-cc2520/rev_d/bbb-cc2520_pcb.png
--------------------------------------------------------------------------------
/linux/README.md:
--------------------------------------------------------------------------------
1 | BBB + GAP + Linux
2 | ======================
3 |
4 | This provides some instructions for using GAP with Linux.
5 |
6 | Setup from new BBB Install
7 | --------------------------
8 |
9 | After flashing the BBB, ssh to it and:
10 | ```
11 | # lockout root
12 | edit /etc/ssh/sshd_config
13 |
14 | # change password
15 | passwd
16 |
17 | # packages
18 | sudo apt-get update
19 | sudo apt-get install vim git lsb-release
20 |
21 | # update kernel
22 | sudo /opt/scripts/tools/update_kernel.sh --beta --bone-channel
23 |
24 | # Add overlays
25 | git clone https://github.com/lab11/bb.org-overlays
26 | cd bb.org-overlays
27 | ./dtc-overlay.sh
28 | ./install.sh
29 |
30 | # Make GAP load on boot
31 | edit /boot/uEnv.txt
32 | cape_enable=bone_capemgr.enable_partno=BB-GAP
33 |
34 | # Reboot
35 | sudo reboot
36 |
37 | # Verify
38 | /sbin/ifconfig -a
39 |
40 | # Get WPAN tools
41 | sudo apt-get install pkg-config libnl-3-dev libnl-genl-3-dev
42 | wget http://wpan.cakelab.org/releases/wpan-tools-0.5.tar.gz
43 | tar xf wpan-tools-0.5.tar.gz
44 | cd wpan-tools-0.5
45 | ./configure
46 | make
47 | sudo make install
48 |
49 | ```
50 |
51 |
52 | Sniff broadcast packets
53 | -----------------------
54 |
55 | ```
56 | sudo apt-get install tcpdump
57 |
58 | iwpan phy phy0 set channel 0 11
59 | iwpan dev wpan0 del
60 | iwpan phy phy0 interface add wpan0 type node c0:98:e5:00:00:00:00:01
61 | iwpan dev wpan0 set pan_id 0x0022
62 | /sbin/ifconfig wpan0 up
63 |
64 | sudo tcpdump -i wpan0 -vvv
65 | ```
66 |
67 |
68 |
69 |
70 | Configuring CC2520 with 6LoWPAN
71 | ------------------
72 |
73 | Once the hardware and software packages are setup, the next step is the art
74 | of using the in-flux tools to get things configured.
75 |
76 | 1. Set the channel on the physical device.
77 |
78 | iwpan phy phy0 set channel 0 11
79 |
80 | 1. Create the wpan device. If it exists, delete it first. We need to set the
81 | address.
82 |
83 | iwpan dev wpan0 del
84 | iwpan phy phy0 interface add wpan0 type node c0:98:e5:00:00:00:00:01
85 |
86 | 2. Configure the wpan device with a PAN id.
87 |
88 | iwpan dev wpan0 set pan_id 0x0022
89 |
90 | 3. Add a lowpan device.
91 |
92 | ip link add link wpan0 name lowpan0 type lowpan
93 |
94 | 4. Bring things up.
95 |
96 | ifconfig lowpan0 up
97 | ifconfig wpan0 up
98 |
99 | 5. Ping!
100 |
101 | ping6 fe80::%lowpan0
102 |
103 |
104 |
--------------------------------------------------------------------------------
/linux/recvRawEth.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This program is free software: you can redistribute it and/or modify
3 | * it under the terms of the GNU General Public License as published by
4 | * the Free Software Foundation, either version 3 of the License, or
5 | * (at your option) any later version.
6 | */
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | #define DEST_MAC0 0x00
21 | #define DEST_MAC1 0x00
22 | #define DEST_MAC2 0x00
23 | #define DEST_MAC3 0x00
24 | #define DEST_MAC4 0x00
25 | #define DEST_MAC5 0x00
26 |
27 | //#define ETHER_TYPE 0x0800
28 | #define ETHER_TYPE 0x0
29 |
30 | #define DEFAULT_IF "eth0"
31 | #define BUF_SIZ 1024
32 |
33 | int main(int argc, char *argv[])
34 | {
35 | char sender[INET6_ADDRSTRLEN];
36 | int sockfd, ret, i;
37 | int sockopt;
38 | ssize_t numbytes;
39 | struct ifreq ifopts; /* set promiscuous mode */
40 | struct ifreq if_ip; /* get ip addr */
41 | struct sockaddr_storage their_addr;
42 | uint8_t buf[BUF_SIZ];
43 | char ifName[IFNAMSIZ];
44 |
45 | /* Get interface name */
46 | if (argc > 1)
47 | strcpy(ifName, argv[1]);
48 | else
49 | strcpy(ifName, DEFAULT_IF);
50 |
51 |
52 | printf("Interface: %s\n", ifName);
53 |
54 | /* Header structures */
55 | struct ether_header *eh = (struct ether_header *) buf;
56 | struct iphdr *iph = (struct iphdr *) (buf + sizeof(struct ether_header));
57 | struct udphdr *udph = (struct udphdr *) (buf + sizeof(struct iphdr) + sizeof(struct ether_header));
58 |
59 | memset(&if_ip, 0, sizeof(struct ifreq));
60 |
61 | /* Open PF_PACKET socket, listening for EtherType ETHER_TYPE */
62 | //if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE))) == -1) {
63 | //if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
64 | if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IEEE802154))) == -1) {
65 | //if ((sockfd = socket(PF_IEEE802154, SOCK_DGRAM, 0)) == -1) {
66 | // if ((sockfd = socket(PF_IEEE802154, SOCK_RAW, 0)) == -1) {
67 | perror("listener: socket");
68 | return -1;
69 | }
70 |
71 | /* Set interface to promiscuous mode - do we need to do this every time? */
72 | strncpy(ifopts.ifr_name, ifName, IFNAMSIZ-1);
73 | ioctl(sockfd, SIOCGIFFLAGS, &ifopts);
74 | ifopts.ifr_flags |= IFF_PROMISC;
75 | ioctl(sockfd, SIOCSIFFLAGS, &ifopts);
76 | /* Allow the socket to be reused - incase connection is closed prematurely */
77 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof sockopt) == -1) {
78 | perror("setsockopt");
79 | close(sockfd);
80 | exit(EXIT_FAILURE);
81 | }
82 | /* Bind to device */
83 | if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, IFNAMSIZ-1) == -1) {
84 | perror("SO_BINDTODEVICE");
85 | close(sockfd);
86 | exit(EXIT_FAILURE);
87 | }
88 |
89 | repeat: printf("listener: Waiting to recvfrom...\n");
90 | numbytes = recvfrom(sockfd, buf, BUF_SIZ, 0, NULL, NULL);
91 | printf("listener: got packet %lu bytes\n", numbytes);
92 | {
93 | int i;
94 | int d = 0;
95 | for (i=0;i1 && buf[i-2] == 0xe5 && buf[i-1] == 0x98 && buf[i] == 0xc0) {
99 | d = 1;
100 | //printf("***");
101 | }
102 | //printf("FOUND ONE");
103 | }
104 |
105 | printf("\n");
106 | if (d) {
107 | //return 0;
108 | }
109 | }
110 |
111 | {
112 | int i;
113 | printf("addr: ");
114 | for (i=14;i>6;i--){
115 | printf("%02x", buf[i]);
116 | }
117 | printf("\n");
118 | }
119 |
120 | {
121 | int i;
122 | printf("destination: ");
123 | for (i=18;i<=33;i++){
124 | printf("%02x", buf[i]);
125 | }
126 | printf("\n");
127 | }
128 |
129 | {
130 | int i;
131 | printf("transport: %02x\n", buf[34]);
132 | }
133 |
134 |
135 |
136 |
137 |
138 | /*
139 | // Check the packet is for me
140 | if (eh->ether_dhost[0] == DEST_MAC0 &&
141 | eh->ether_dhost[1] == DEST_MAC1 &&
142 | eh->ether_dhost[2] == DEST_MAC2 &&
143 | eh->ether_dhost[3] == DEST_MAC3 &&
144 | eh->ether_dhost[4] == DEST_MAC4 &&
145 | eh->ether_dhost[5] == DEST_MAC5) {
146 | printf("Correct destination MAC address\n");
147 | } else {
148 | printf("Wrong destination MAC: %x:%x:%x:%x:%x:%x\n",
149 | eh->ether_dhost[0],
150 | eh->ether_dhost[1],
151 | eh->ether_dhost[2],
152 | eh->ether_dhost[3],
153 | eh->ether_dhost[4],
154 | eh->ether_dhost[5]);
155 | ret = -1;
156 | goto done;
157 | }
158 |
159 | // Get source IP
160 | ((struct sockaddr_in *)&their_addr)->sin_addr.s_addr = iph->saddr;
161 | inet_ntop(AF_INET, &((struct sockaddr_in*)&their_addr)->sin_addr, sender, sizeof sender);
162 |
163 | // Look up my device IP addr if possible
164 | strncpy(if_ip.ifr_name, ifName, IFNAMSIZ-1);
165 | if (ioctl(sockfd, SIOCGIFADDR, &if_ip) >= 0) { if we can't check then don'
166 | printf("Source IP: %s\n My IP: %s\n", sender,
167 |
168 | inet_ntoa(((struct sockaddr_in *)&if_ip.ifr_addr)->sin_addr));
169 | if (strcmp(sender, inet_ntoa(((struct sockaddr_in *)&if_ip.ifr_addr)->sin_addr)) == 0) {
170 | printf("but I sent it :(\n");
171 | ret = -1;
172 | goto done;
173 | }
174 | }
175 |
176 | ret = ntohs(udph->len) - sizeof(struct udphdr);
177 |
178 | printf("\tData:");
179 | for (i=0; i
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | #define DEFAULT_IF "wpan0"
14 | #define BUF_SIZ 1024
15 |
16 | int main(int argc, char *argv[]) {
17 | char sender[INET6_ADDRSTRLEN];
18 | int sockfd, i;
19 | int sockopt;
20 | ssize_t numbytes;
21 | struct ifreq ifopts; /* set promiscuous mode */
22 | uint8_t buf[BUF_SIZ];
23 | char ifName[IFNAMSIZ];
24 |
25 | // Get interface name
26 | if (argc > 1) {
27 | strcpy(ifName, argv[1]);
28 | } else {
29 | strcpy(ifName, DEFAULT_IF);
30 | }
31 |
32 | // Open PF_PACKET socket, listening for EtherType ETH_P_IEEE802154
33 | if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IEEE802154))) == -1) {
34 | perror("listener: socket");
35 | return -1;
36 | }
37 |
38 | // Set interface to promiscuous mode - do we need to do this every time?
39 | strncpy(ifopts.ifr_name, ifName, IFNAMSIZ-1);
40 | ioctl(sockfd, SIOCGIFFLAGS, &ifopts);
41 | ifopts.ifr_flags |= IFF_PROMISC;
42 | ioctl(sockfd, SIOCSIFFLAGS, &ifopts);
43 | // Allow the socket to be reused - incase connection is closed prematurely
44 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof sockopt) == -1) {
45 | perror("setsockopt");
46 | close(sockfd);
47 | exit(EXIT_FAILURE);
48 | }
49 | // Bind to device
50 | if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, IFNAMSIZ-1) == -1) {
51 | perror("SO_BINDTODEVICE");
52 | close(sockfd);
53 | exit(EXIT_FAILURE);
54 | }
55 |
56 | // Wait for data
57 | while (1) {
58 | printf("listener: Waiting to recvfrom...\n");
59 | numbytes = recvfrom(sockfd, buf, BUF_SIZ, 0, NULL, NULL);
60 | printf("listener: got packet %lu bytes\n", numbytes);
61 |
62 | // Print packet bytes
63 | for (i=0; i;
76 | __overlay__ {
77 | gap_cc2520_0_pins: pinmux_gap_cc2520_0_pins {
78 | pinctrl-single,pins = <
79 | 0x048 0x2F /* ehrpwm1a.gpio1_18, INPUT | MODE7 */
80 | 0x044 0x2F /* gpio1_17.gpio1_17, INPUT | MODE7 */
81 | 0x1a4 0x2F /* gpio3_19.gpio3_19, INPUT | MODE7 */
82 | 0x078 0x17 /* gpio1_28.gpio1_28, OUTPUT_PULLUP | MODE7 */
83 | 0x040 0x2F /* gpio1_16.gpio1_16, INPUT | MODE7 */
84 | 0x08c 0x17 /* gpio2_1.gpio2_1, OUTPUT_PULLUP | MODE7 */
85 | >;
86 | };
87 |
88 | gap_cc2520_1_pins: pinmux_gap_cc2520_1_pins {
89 | pinctrl-single,pins = <
90 | 0x03c 0x2F /* P8.15 gpio1_15.gpio1_15, INPUT | MODE7 */
91 | 0x024 0x2F /* P8.13 ehrpwm2b.gpio0_23, INPUT | MODE7 */
92 | 0x038 0x2F /* P8.16 gpio1_14.gpio1_14, INPUT | MODE7 */
93 | 0x07c 0x17 /* P8.26 gpio1_29.gpio1_29, OUTPUT_PULLUP | MODE7 */
94 | 0x028 0x2F /* P8.14 gpio0_26.gpio0_26, INPUT | MODE7 */
95 | 0x09c 0x17 /* P8.09 gpio2_5.gpio2_5, OUTPUT_PULLUP | MODE7 */
96 | >;
97 | };
98 |
99 | /*gap_leds_pins: pinmux_gap_leds_pins {
100 | pinctrl-single,pins = <
101 | 0x020 0x17 /* ehrpwm2a.gpio0_22, OUTPUT_PULLUP | MODE7 *
102 | 0x02c 0x17 /* gpio0_27.gpio0_27, OUTPUT_PULLUP | MODE7 *
103 | >;
104 | };
105 |
106 | gap_spi0_pins: pinmux_gap_spi0_pins {
107 | pinctrl-single,pins = <
108 | 0x15c 0x10 /* i2c1_scl.spi0_cs0, OUTPUT_PULLUP | MODE0 *
109 | 0x158 0x10 /* i2c1_sda.spi0_d1, OUTPUT_PULLUP | MODE0 *
110 | 0x154 0x30 /* uart2_txd.spi0_d0, INPUT_PULLUP | MODE0 *
111 | 0x150 0x30 /* uart2_rxd.spi0_sclk, INPUT_PULLUP | MODE0 *
112 | >;
113 | };*/
114 |
115 | gap_spi1_pins: pinmux_gap_spi1_pins {
116 | pinctrl-single,pins = <
117 | 0x190 0x33 /* mcasp0_aclkx.spi1_sclk, INPUT_PULLUP | MODE3 */
118 | 0x194 0x33 /* mcasp0_fsx.spi1_d0, INPUT_PULLUP | MODE3 */
119 | 0x198 0x13 /* mcasp0_axr0.spi1_d1, OUTPUT_PULLUP | MODE3 */
120 | 0x19c 0x13 /* mcasp0_ahclkr.spi1_cs0, OUTPUT_PULLUP | MODE3 */
121 | 0x164 0x12 /* ecap0_in_pwm0_out.spi1_cs1, OUTPUT_PULLUP | MODE2 */
122 | >;
123 | };
124 | /*bb_gap_nrf51822_pins: pinmux_bb_gap_nrf51822_pins {
125 | pinctrl-single,pins = <
126 | 0x074 0x17 /* P9.11 uart4_rxd.gpio0_30, OUTPUT_PULLUP | MODE 7 *
127 | 0x04c 0x2F /* P9.16 ehrpwm1b.gpio1_19, INPUT | MODE7 *
128 | >;
129 | };
130 | bb_gap_uart1_pins: pinmux_bb_gap_uart1_pins {
131 | pinctrl-single,pins = <
132 | 0x184 0x20 /* P9.24 uart1_txd.uart1_txd, OUTPUT | MODE0 *
133 | 0x180 0x20 /* P9.26 uart1_rxd.uart1_rxd, INPUT | MODE0 *
134 | >;
135 | };*/
136 | };
137 | };
138 |
139 |
140 |
141 |
142 | /*fragment@1 {
143 | target = <&spi0>;
144 | __overlay__ {
145 | status = "okay";
146 |
147 | pinctrl-names = "default";
148 | pinctrl-0 = <&gap_spi0_pins>;
149 | };
150 | };*/
151 |
152 |
153 | fragment@1 {
154 | target = <&spi1>;
155 | __overlay__ {
156 |
157 | #address-cells = <1>;
158 | #size-cells = <0>;
159 |
160 | status = "okay";
161 |
162 | pinctrl-names = "default";
163 | pinctrl-0 = <&gap_spi1_pins>;
164 |
165 | gapcca@0 {
166 | compatible = "ti,cc2520";
167 |
168 | reg = <0>;
169 | spi-max-frequency = <4000000>;
170 | pinctrl-names = "default";
171 | pinctrl-0 = <&gap_cc2520_0_pins>;
172 | fifo-gpio = <&gpio3 19 0>;
173 | fifop-gpio = <&gpio1 17 0>;
174 | sfd-gpio = <&gpio1 18 0>;
175 | cca-gpio = <&gpio1 16 0>;
176 | vreg-gpio = <&gpio2 1 1>;
177 | reset-gpio = <&gpio1 28 0>;
178 | };
179 |
180 | gapccb@1 {
181 | compatible = "ti,cc2520";
182 |
183 | reg = <1>;
184 | spi-max-frequency = <4000000>;
185 | amplified;
186 | pinctrl-names = "default";
187 | pinctrl-0 = <&gap_cc2520_1_pins>;
188 | fifo-gpio = <&gpio1 14 0>;
189 | fifop-gpio = <&gpio0 23 0>;
190 | sfd-gpio = <&gpio1 15 0>;
191 | cca-gpio = <&gpio0 26 0>;
192 | vreg-gpio = <&gpio2 5 1>;
193 | reset-gpio = <&gpio1 29 0>;
194 | };
195 | };
196 | };
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 | /*fragment@3 {
207 | target = <&ocp>;
208 | __overlay__ {
209 |
210 | gap-nrf51822@0 {
211 | compatible = "lab11,nrf51822";
212 | pinctrl-names = "default";
213 | pinctrl-0 = <&bb_gap_nrf51822_pins>;
214 |
215 | num-radios = <1>;
216 |
217 | interrupt0-gpio = <&gpio2 19 0>;
218 | rst0-gpio = <&gpio1 30 0>;
219 | radio0-csmux = <2>;
220 |
221 | status = "okay";
222 | };
223 | };
224 | };*/
225 |
226 | /*fragment@4 {
227 | target = <&uart2>;
228 | __overlay__ {
229 |
230 | gap-nrf51822@1 {
231 | pinctrl-names = "default";
232 | pinctrl-0 = <&bb_gap_uart1_pins>;
233 | status = "okay";
234 | };
235 | };
236 | };*/
237 | /*fragment@5 {
238 | target = <&leds>;
239 | __overlay__ {
240 |
241 | pinctrl-1 = <&gap_leds_pins>;
242 |
243 | led@6 {
244 | label = "gap:green:usr4";
245 | gpios = <&gpio0 22 1>;
246 | linux,default-trigger = "none";
247 | default-state = "off";
248 | };
249 | led@7 {
250 | label = "gap:red:usr5";
251 | gpios = <&gpio0 27 1>;
252 | linux,default-trigger = "none";
253 | default-state = "off";
254 | };
255 | };
256 | };*/
257 | };
258 |
--------------------------------------------------------------------------------
/software/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | *.o.cmd
3 | Module.symvers
4 | *.ko.cmd
5 | *.ko
6 | *.mod.c
7 | *.order
8 | .tmp_versions
9 |
10 |
--------------------------------------------------------------------------------
/software/driver/Makefile:
--------------------------------------------------------------------------------
1 | #ARCH=arm
2 | #CROSS_COMPILE=arm-linux-gnueabi-
3 |
4 | obj-y := nrf51822/ gapspi/
5 |
6 | # Set this is your linux kernel checkout if cross-compiling.
7 | #KDIR := /lib/modules/$(shell uname -r)/build
8 | KDIR := ~/git/bb-kernel/KERNEL
9 | PWD := $(shell pwd)
10 |
11 | default:
12 | $(MAKE) -C $(KDIR) M=$(PWD) modules
13 |
14 | clean:
15 | $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean
16 |
17 | .PHONY: clean default
18 |
--------------------------------------------------------------------------------
/software/driver/README.md:
--------------------------------------------------------------------------------
1 | Custom Kernel Modules for GAP
2 | =============================
3 |
4 | These modules are a little out of date, but at one time supported the
5 | radios on GAP.
6 |
7 | gapspi.ko
8 | ---------
9 |
10 | This module uses SPI0 and the onboard demux to switch the SPI bus and
11 | single chip select to multiple peripherals.
12 |
13 |
14 | nrf51822.ko
15 | -----------
16 |
17 | This provides a SPI connection to the nRF51822.
18 |
19 |
--------------------------------------------------------------------------------
/software/driver/gapspi/Makefile:
--------------------------------------------------------------------------------
1 | obj-m += gapspi.o
2 |
--------------------------------------------------------------------------------
/software/driver/gapspi/debug.h:
--------------------------------------------------------------------------------
1 | #ifndef DEBUG_H
2 | #define DEBUG_H
3 |
4 | // Define different levels of debug printing
5 |
6 | // print nothing
7 | #define DEBUG_PRINT_OFF 0
8 | // print only when something goes wrong
9 | #define DEBUG_PRINT_ERR 1
10 | // print occasional messages about interesting things
11 | #define DEBUG_PRINT_INFO 2
12 | // print a good amount of debugging output
13 | #define DEBUG_PRINT_DBG 3
14 |
15 |
16 | // Define the printk macros.
17 | #define ERR(tag, ...) do {if (debug_print >= DEBUG_PRINT_ERR) { printk(tag "[gapspi] " __VA_ARGS__); }} while (0)
18 | #define INFO(tag, ...) do {if (debug_print >= DEBUG_PRINT_INFO) { printk(tag "[gapspi] " __VA_ARGS__); }} while (0)
19 | #define DBG(tag, ...) do {if (debug_print >= DEBUG_PRINT_DBG) { printk(tag "[gapspi] " __VA_ARGS__); }} while (0)
20 |
21 | #endif
--------------------------------------------------------------------------------
/software/driver/gapspi/gapspi.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | #include "debug.h"
19 |
20 | #define DRIVER_AUTHOR "Neal Jackson "
21 | #define DRIVER_DESC "A driver for the GAP Beaglebone Black \"Zigbeag\" cape SPI control."
22 | #define DRIVER_VERSION "0.1"
23 |
24 | static void gapspi_cs_mux(int id);
25 |
26 | const char gapspi_name[] = "gapspi";
27 |
28 | // Device and Pin config
29 | int num_demux_ctrl_pins;
30 | int demux_ctrl_pins[3];
31 |
32 | // Defines the level of debug output
33 | uint8_t debug_print = DEBUG_PRINT_ERR;
34 |
35 | struct spi_device* gapspi_spi_device;
36 |
37 | // Use this function to set the DEMUX
38 | static void gapspi_cs_mux(int id)
39 | {
40 | int i;
41 | for (i = 0; i < num_demux_ctrl_pins; ++i) {
42 | if (id & (1<state = (void*) dev_id;
55 | return spi_async(gapspi_spi_device, message);
56 | }
57 |
58 | int gap_spi_sync(struct spi_message * message, int dev_id)
59 | {
60 | message->state = (void*) dev_id;
61 | return spi_sync(gapspi_spi_device, message);
62 | }
63 |
64 | EXPORT_SYMBOL(gap_spi_async);
65 | EXPORT_SYMBOL(gap_spi_sync);
66 |
67 | /////////////////////
68 | // SPI
69 | /////////////////////
70 |
71 | // Intercept the "transfer message" function to allow for
72 | // setting the CS MUX before the message goes out.
73 | int (*real_transfer_one_message)(struct spi_master *master,
74 | struct spi_message *mesg);
75 |
76 | int our_transfer_one_message (struct spi_master *master,
77 | struct spi_message *mesg) {
78 | int cs_device_id;
79 |
80 | // Sse the stored value in mesg to set the mux
81 | cs_device_id = (int) (mesg->state);
82 | gapspi_cs_mux(cs_device_id);
83 |
84 | return real_transfer_one_message(master, mesg);
85 | }
86 |
87 | static int gapspi_spi_probe(struct spi_device *spi_device)
88 | {
89 | struct device_node *np = spi_device->dev.of_node;
90 | const __be32 *prop;
91 | int i;
92 | int err;
93 |
94 | INFO(KERN_INFO, "Inserting SPI protocol driver.\n");
95 |
96 | //
97 | // Setup GPIO SPI mux pins
98 | //
99 | // Get the parameters for the driver from the device tree
100 | prop = of_get_property(np, "num-csmux-pins", NULL);
101 | if (!prop) {
102 | ERR(KERN_ALERT, "Got NULL for the number of CS pins.\n");
103 | return -EINVAL;
104 | }
105 | num_demux_ctrl_pins = be32_to_cpup(prop);
106 | INFO(KERN_INFO, "Number of DEMUX ctrl pins %i\n", num_demux_ctrl_pins);
107 |
108 | for (i=0; idev, demux_ctrl_pins[i], GPIOF_OUT_INIT_LOW, "buf");
119 | if (err) return -EINVAL;
120 | }
121 |
122 | // Splice in our transfer one message function so that we can
123 | // set the mux before the packet is transfered.
124 | real_transfer_one_message = spi_device->master->transfer_one_message;
125 | spi_device->master->transfer_one_message = our_transfer_one_message;
126 |
127 | gapspi_spi_device = spi_device;
128 |
129 | return 0;
130 | }
131 |
132 | static int gapspi_spi_remove(struct spi_device *spi_device)
133 | {
134 | INFO(KERN_INFO, "Removing SPI protocol driver.");
135 |
136 | spi_device->master->transfer_one_message = real_transfer_one_message;
137 |
138 | gapspi_spi_device = NULL;
139 | return 0;
140 | }
141 |
142 | static const struct spi_device_id gapspi_ids[] = {
143 | {"gapspi", },
144 | {},
145 | };
146 | MODULE_DEVICE_TABLE(spi, gapspi_ids);
147 |
148 | static const struct of_device_id gapspi_of_ids[] = {
149 | {.compatible = "lab11,gapspi", },
150 | {},
151 | };
152 | MODULE_DEVICE_TABLE(of, gapspi_of_ids);
153 |
154 | // Configure SPI
155 | static struct spi_driver gapspi_spi_driver = {
156 | .driver = {
157 | .name = gapspi_name,
158 | .owner = THIS_MODULE,
159 | .bus = &spi_bus_type,
160 | .of_match_table = of_match_ptr(gapspi_of_ids),
161 | },
162 | .probe = gapspi_spi_probe,
163 | .remove = gapspi_spi_remove,
164 | .id_table = gapspi_ids,
165 | };
166 |
167 | module_spi_driver(gapspi_spi_driver);
168 |
169 | MODULE_LICENSE("GPL");
170 | MODULE_AUTHOR(DRIVER_AUTHOR);
171 | MODULE_DESCRIPTION(DRIVER_DESC);
172 |
--------------------------------------------------------------------------------
/software/driver/gapspi/gapspi.h:
--------------------------------------------------------------------------------
1 | #ifndef _GAPSPI_H_
2 | #define _GAPSPI_H_
3 |
4 | extern int gap_spi_async(struct spi_message * message, int dev_id);
5 | extern int gap_spi_sync(struct spi_message * message, int dev_id);
6 |
7 | #endif
--------------------------------------------------------------------------------
/software/driver/nrf51822/Makefile:
--------------------------------------------------------------------------------
1 | obj-m += nrf51822.o
2 |
--------------------------------------------------------------------------------
/software/driver/nrf51822/bcp.h:
--------------------------------------------------------------------------------
1 | #ifndef _BCP_H_
2 | #define _BCP_H_
3 |
4 | // Commands that are issued to the nRF51822
5 | #define BCP_COMMAND_READ_IRQ 1 // Read whatever caused the interrupt we received.
6 | #define BCP_COMMAND_SNIFF_ADVERTISEMENTS 2 // Tell the nRF51822 to send us all received advertisements.
7 | #define BCP_COMMAND_SNIFF_ADVERTISEMENTS_STOP 3 // Stop sending advertisements packets.
8 |
9 |
10 |
11 | #endif
--------------------------------------------------------------------------------
/software/driver/nrf51822/debug.h:
--------------------------------------------------------------------------------
1 | #ifndef DEBUG_H
2 | #define DEBUG_H
3 |
4 | // Define different levels of debug printing
5 |
6 | // print nothing
7 | #define DEBUG_PRINT_OFF 0
8 | // print only when something goes wrong
9 | #define DEBUG_PRINT_ERR 1
10 | // print occasional messages about interesting things
11 | #define DEBUG_PRINT_INFO 2
12 | // print a good amount of debugging output
13 | #define DEBUG_PRINT_DBG 3
14 |
15 |
16 | // Define the printk macros.
17 | #define ERR(tag, ...) do {if (config.debug_print >= DEBUG_PRINT_ERR) { printk(tag "[nrf51822] " __VA_ARGS__); }} while (0)
18 | #define INFO(tag, ...) do {if (config.debug_print >= DEBUG_PRINT_INFO) { printk(tag "[nrf51822] " __VA_ARGS__); }} while (0)
19 | #define DBG(tag, ...) do {if (config.debug_print >= DEBUG_PRINT_DBG) { printk(tag "[nrf51822] " __VA_ARGS__); }} while (0)
20 |
21 | #endif
22 |
--------------------------------------------------------------------------------
/software/driver/nrf51822/ioctl.h:
--------------------------------------------------------------------------------
1 | #ifndef _IOCTL_H_
2 | #define _IOCTL_H_
3 |
4 | #include
5 | #include
6 | #define BASE 0xCD
7 |
8 | #ifndef __KERNEL__
9 | #include
10 | #include
11 | typedef uint8_t u8;
12 | typedef uint16_t u16;
13 | typedef uint32_t u32;
14 | typedef uint64_t u64;
15 | #endif
16 |
17 | struct nrf51822_set_debug_verbosity_data {
18 | u8 debug_level;
19 | };
20 |
21 | struct nrf51822_simple_command {
22 | u8 command;
23 | };
24 |
25 | //#define CC2520_IO_RADIO_INIT _IO(BASE, 0)
26 | #define NRF51822_IOCTL_SET_DEBUG_VERBOSITY _IOW(BASE, 0, struct nrf51822_set_debug_verbosity_data)
27 | #define NRF51822_IOCTL_SIMPLE_COMMAND _IOW(BASE, 1, struct nrf51822_simple_command)
28 |
29 |
30 | static int nrf51822_ioctl_set_debug_verbosity(struct nrf51822_set_debug_verbosity_data *data);
31 | static int nrf51822_ioctl_simple_command(struct nrf51822_simple_command *data, struct nrf51822_dev *dev);
32 |
33 | static long nrf51822_ioctl(struct file *file,
34 | unsigned int ioctl_num,
35 | unsigned long ioctl_param);
36 |
37 | #endif
--------------------------------------------------------------------------------
/software/driver/nrf51822/nrf51822.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | #include "../gapspi/gapspi.h"
20 |
21 | #include "nrf51822.h"
22 | #include "bcp.h"
23 | #include "ioctl.h"
24 | #include "debug.h"
25 |
26 | #define DRIVER_AUTHOR "Brad Campbell "
27 | #define DRIVER_DESC "A driver for the nRF51822 BLE chip over SPI."
28 | #define DRIVER_VERSION "0.2"
29 |
30 | const char nrf51822_name[] = "nRF51822";
31 | struct nrf51822_config config;
32 |
33 | // Not implemented currently
34 | static ssize_t nrf51822_write(struct file *filp,
35 | const char *in_buf,
36 | size_t len,
37 | loff_t * off)
38 | {
39 | return -EFAULT;
40 | }
41 |
42 | // Called by the read() command from user space
43 | static ssize_t nrf51822_read(struct file *filp,
44 | char __user *buf,
45 | size_t count,
46 | loff_t *offp)
47 | {
48 | int result;
49 | int user_len;
50 | struct nrf51822_dev *dev = filp->private_data;
51 |
52 | // Wait for data to be ready to send to the user.
53 | wait_event_interruptible(dev->to_user_queue, (dev->buf_to_user_len > 0));
54 |
55 | // Copy the result from the nRF51822 to the user
56 | result = copy_to_user(buf, dev->buf_to_user, dev->buf_to_user_len);
57 | if (result) {
58 | return -EFAULT;
59 | }
60 |
61 | user_len = dev->buf_to_user_len;
62 |
63 | // Reset the buffer length so the user_queue wait doesn't trigger
64 | dev->buf_to_user_len = 0;
65 |
66 | return user_len;
67 | }
68 |
69 | static long nrf51822_ioctl(struct file *file,
70 | unsigned int ioctl_num,
71 | unsigned long ioctl_param)
72 | {
73 | int result;
74 | struct nrf51822_dev *dev = file->private_data;
75 |
76 | switch (ioctl_num) {
77 | case NRF51822_IOCTL_SET_DEBUG_VERBOSITY:
78 | result = nrf51822_ioctl_set_debug_verbosity((struct nrf51822_set_debug_verbosity_data*) ioctl_param);
79 | break;
80 | case NRF51822_IOCTL_SIMPLE_COMMAND:
81 | result = nrf51822_ioctl_simple_command((struct nrf51822_simple_command*) ioctl_param, dev);
82 | break;
83 | default:
84 | result = -ENOTTY;
85 | }
86 |
87 | return result;
88 | }
89 |
90 | static unsigned int nrf51822_poll (struct file *file, poll_table *wait)
91 | {
92 | unsigned int mask = 0;
93 | struct nrf51822_dev *dev = file->private_data;
94 |
95 | poll_wait(file, &dev->to_user_queue, wait);
96 |
97 | // always writable
98 | mask |= POLLOUT | POLLWRNORM;
99 |
100 | if (dev->buf_to_user_len > 0) {
101 | // readable
102 | mask |= POLLIN | POLLRDNORM;
103 | }
104 |
105 | return mask;
106 | }
107 |
108 | static int nrf51822_open(struct inode *inode, struct file *filp)
109 | {
110 | struct nrf51822_dev *dev;
111 | dev = container_of(inode->i_cdev, struct nrf51822_dev, cdev);
112 | filp->private_data = dev;
113 | DBG(KERN_INFO, "opening radio%d.\n", dev->id);
114 |
115 | return 0;
116 | }
117 |
118 | struct file_operations fops = {
119 | .read = nrf51822_read,
120 | .write = nrf51822_write,
121 | .unlocked_ioctl = nrf51822_ioctl,
122 | .open = nrf51822_open,
123 | .release = NULL,
124 | .poll = nrf51822_poll
125 | };
126 |
127 | ///////////////////
128 | // IOCTL Handlers
129 | ///////////////////
130 |
131 | // Change the print verbosity
132 | static int nrf51822_ioctl_set_debug_verbosity(struct nrf51822_set_debug_verbosity_data *data)
133 | {
134 | int result;
135 | struct nrf51822_set_debug_verbosity_data ldata;
136 |
137 | result = copy_from_user(&ldata, data, sizeof(struct nrf51822_set_debug_verbosity_data));
138 |
139 | if (result) {
140 | ERR(KERN_ALERT, "an error occurred setting print messages\n");
141 | return 0;
142 | }
143 |
144 | INFO(KERN_INFO, "setting debug message print: %i", ldata.debug_level);
145 |
146 | config.debug_print = ldata.debug_level;
147 |
148 | return 0;
149 | }
150 |
151 | // Issue a command to the nRF51822. These are 1 byte commands.
152 | static int nrf51822_ioctl_simple_command(struct nrf51822_simple_command *data, struct nrf51822_dev *dev)
153 | {
154 | int result;
155 | struct nrf51822_simple_command ldata;
156 |
157 | result = copy_from_user(&ldata, data, sizeof(struct nrf51822_simple_command));
158 |
159 | if (result) {
160 | ERR(KERN_ALERT, "an error occurred a command\n");
161 | return 0;
162 | }
163 |
164 | INFO(KERN_INFO, "issuing command: %i", ldata.command);
165 |
166 | return nrf51822_issue_simple_command(ldata.command, dev);
167 | }
168 |
169 |
170 | /////////////////////
171 | // Application logic
172 | /////////////////////
173 |
174 | // Manually check if the interrupt line is high.
175 | static void nrf51822_check_irq (struct nrf51822_dev *dev) {
176 | // Check if we need to read the IRQ again
177 | if (gpio_get_value(dev->pin_interrupt) == 1) {
178 | // Interrupt is still high.
179 | // Read again.
180 |
181 | // Put this delay here so the nRF51822 has time to set the SPI buffer
182 | // again.
183 | usleep_range(25, 50);
184 |
185 | nrf51822_read_irq(dev);
186 | }
187 | }
188 |
189 |
190 | // The result of the interrupt is in spi_buffer
191 | static void nrf51822_read_irq_done (void *arg) {
192 | struct nrf51822_dev *dev = arg;
193 | int len;
194 |
195 | DBG(KERN_INFO, "Got IRQ data from nrf51822\n");
196 |
197 | // There is an issue where the nRF51822 needs 7.1us between CS and CLK.
198 | // We violate that currently, so the first byte may be invalid (0x00).
199 | // If the second byte was zero as well, that denotes an error.
200 | if (dev->spi_data_buffer[0] == 0 && dev->spi_data_buffer[1] == 0) {
201 | // This was an invalid transfer. Some error occurred.
202 |
203 | ERR(KERN_INFO, "First two bytes zero. Ignoring response from nRF51822:%i\n", dev->id);
204 |
205 | spin_lock_irqsave(&dev->spi_spin_lock, dev->spi_spin_lock_flags);
206 | dev->spi_pending = false;
207 | spin_unlock_irqrestore(&dev->spi_spin_lock, dev->spi_spin_lock_flags);
208 |
209 | nrf51822_check_irq(dev);
210 |
211 | return;
212 |
213 | } else if (dev->spi_data_buffer[0] == 0) {
214 | // The first byte was an error. Skip it and use the second byte
215 | // as the length.
216 | len = dev->spi_data_buffer[1]+1;
217 |
218 | // Move the packet from the SPI buffer to the thing that can be read()
219 | memcpy(dev->buf_to_user, dev->spi_data_buffer, len);
220 | dev->buf_to_user_len = len;
221 |
222 | } else {
223 | // The first byte was the length
224 | len = dev->spi_data_buffer[0]+1;
225 |
226 | // Move the packet from the SPI buffer to the thing that can be read()
227 | memcpy(dev->buf_to_user, dev->spi_data_buffer, len);
228 | dev->buf_to_user_len = len;
229 | }
230 |
231 | // Release the lock on the SPI buffer
232 | spin_lock_irqsave(&dev->spi_spin_lock, dev->spi_spin_lock_flags);
233 | dev->spi_pending = false;
234 | spin_unlock_irqrestore(&dev->spi_spin_lock, dev->spi_spin_lock_flags);
235 |
236 | // Notify the read() call that there is data for it.
237 | wake_up(&dev->to_user_queue);
238 |
239 | nrf51822_check_irq(dev);
240 | }
241 |
242 | // Set up the SPI transfer to query the nRF51822 about why it interrupted
243 | // us.
244 | static void nrf51822_read_irq(struct nrf51822_dev *dev) {
245 |
246 | // Check if we can get a lock on the SPI rx/tx buffer. If not, ignore
247 | // this interrupt.
248 | spin_lock_irqsave(&dev->spi_spin_lock, dev->spi_spin_lock_flags);
249 | if (dev->spi_pending) {
250 | // Something else is using the SPI. Just skip this interrupt.
251 | spin_unlock_irqrestore(&dev->spi_spin_lock, dev->spi_spin_lock_flags);
252 | return;
253 | } else {
254 | // Claim the SPI buffer.
255 | dev->spi_pending = true;
256 | spin_unlock_irqrestore(&dev->spi_spin_lock, dev->spi_spin_lock_flags);
257 | }
258 |
259 | DBG(KERN_INFO, "setup SPI transfer to investigate interrupt\n");
260 |
261 | // Clear the transfer buffers
262 | memset(dev->spi_tsfers, 0, sizeof(dev->spi_tsfers));
263 |
264 | // Setup SPI transfers.
265 | // The first byte is the command byte. Because we just want interrupt
266 | // data we send the READ_IRQ command. The next bytes are the response
267 | // from the nRF51822. In the future we will be able to read the correct
268 | // number of bytes from the based on the first response byte from the slave
269 | // (the length byte). Right now just read the maximum length.
270 | dev->spi_tsfers[0].tx_buf = dev->spi_command_buffer;
271 | dev->spi_tsfers[0].rx_buf = dev->spi_data_buffer;
272 | dev->spi_tsfers[0].len = 40;
273 | dev->spi_tsfers[0].cs_change = 1;
274 |
275 | dev->spi_command_buffer[0] = BCP_COMMAND_READ_IRQ;
276 |
277 | spi_message_init(&dev->spi_msg);
278 | dev->spi_msg.complete = nrf51822_read_irq_done;
279 | dev->spi_msg.context = dev;
280 | spi_message_add_tail(&dev->spi_tsfers[0], &dev->spi_msg);
281 |
282 | gap_spi_async(&dev->spi_msg, dev->chipselect_demux_index);
283 | }
284 |
285 |
286 | //
287 | // Interrupts
288 | //
289 |
290 | static irqreturn_t nrf51822_interrupt_handler(int irq, void *data)
291 | {
292 | struct nrf51822_dev *dev = data;
293 | INFO(KERN_INFO, "got interrupt from nRF51822:%i\n", dev->id);
294 |
295 | nrf51822_read_irq(dev);
296 |
297 | return IRQ_HANDLED;
298 | }
299 |
300 | // Called after a command byte has been sent to the nRF51822.
301 | // Check if the nRF51822 sent us data.
302 | void nrf51822_issue_simple_command_done(void *arg) {
303 | struct nrf51822_dev *dev = arg;
304 | bool received_valid_data = false;
305 |
306 | if (dev->spi_data_buffer[0] == 0 && dev->spi_data_buffer[1] == 0) {
307 | // No data to be transfered to the host.
308 |
309 | } else {
310 | int len;
311 |
312 | received_valid_data = true;
313 |
314 | if (dev->spi_data_buffer[0] == 0) {
315 | // The first byte was an error. Skip it and use the second byte
316 | // as the length.
317 | len = dev->spi_data_buffer[1]+1;
318 |
319 | // Move the packet from the SPI buffer to the thing that can be read()
320 | memcpy(dev->buf_to_user, dev->spi_data_buffer, len);
321 | dev->buf_to_user_len = len;
322 |
323 | } else {
324 | // The first byte was the length
325 | len = dev->spi_data_buffer[0]+1;
326 |
327 | // Move the packet from the SPI buffer to the thing that can be read()
328 | memcpy(dev->buf_to_user, dev->spi_data_buffer, len);
329 | dev->buf_to_user_len = len;
330 | }
331 | }
332 |
333 |
334 | spin_lock_irqsave(&dev->spi_spin_lock, dev->spi_spin_lock_flags);
335 | dev->spi_pending = false;
336 | spin_unlock_irqrestore(&dev->spi_spin_lock, dev->spi_spin_lock_flags);
337 |
338 | if (received_valid_data) {
339 | // Notify the read() call that there is data for it.
340 | wake_up(&dev->to_user_queue);
341 | }
342 |
343 | DBG(KERN_INFO, "Finished writing the command.\n");
344 |
345 | nrf51822_check_irq(dev);
346 | }
347 |
348 | // Send command to the nRF51822
349 | int nrf51822_issue_simple_command(uint8_t command, struct nrf51822_dev *dev) {
350 |
351 | // Check if the SPI driver is in use
352 | spin_lock_irqsave(&dev->spi_spin_lock, dev->spi_spin_lock_flags);
353 | if (dev->spi_pending) {
354 | // Something else is using the SPI. Return that we can't issue the
355 | // command right now.
356 | spin_unlock_irqrestore(&dev->spi_spin_lock, dev->spi_spin_lock_flags);
357 | return -EINTR;
358 | } else {
359 | // Claim the SPI buffer.
360 | dev->spi_pending = true;
361 | spin_unlock_irqrestore(&dev->spi_spin_lock, dev->spi_spin_lock_flags);
362 | }
363 |
364 | DBG(KERN_INFO, "Issuing command %i on radio %i\n", command, dev->id);
365 |
366 | // Clear the transfer buffers
367 | memset(dev->spi_tsfers, 0, sizeof(dev->spi_tsfers));
368 |
369 | // Actually issue the command.
370 | // Also be prepared to receive data
371 | dev->spi_tsfers[0].tx_buf = dev->spi_command_buffer;
372 | dev->spi_tsfers[0].rx_buf = dev->spi_data_buffer;
373 | dev->spi_tsfers[0].len = 40;
374 | dev->spi_tsfers[0].cs_change = 1;
375 |
376 | dev->spi_command_buffer[0] = command;
377 |
378 | spi_message_init(&dev->spi_msg);
379 | dev->spi_msg.complete = nrf51822_issue_simple_command_done;
380 | dev->spi_msg.context = dev;
381 | spi_message_add_tail(&dev->spi_tsfers[0], &dev->spi_msg);
382 |
383 | gap_spi_async(&dev->spi_msg, dev->chipselect_demux_index);
384 |
385 | return 0;
386 | }
387 |
388 |
389 | /////////////////
390 | // init/free
391 | ///////////////////
392 |
393 | static int nrf51822_probe(struct platform_device *pltf)
394 | {
395 | struct device_node *np = pltf->dev.of_node;
396 | int result;
397 | const __be32 *prop;
398 | struct nrf51822_dev *dev;
399 | int i;
400 | int err;
401 |
402 | memset(&config, 0, sizeof(struct nrf51822_config));
403 | config.debug_print = DEBUG_PRINT_DBG;
404 |
405 | INFO(KERN_INFO, "Loading kernel module !!! v%s\n", DRIVER_VERSION);
406 |
407 | // Make sure that gapspi.ko is loaded first
408 | request_module("gapspi");
409 |
410 | // Get the parameters for the driver from the device tree
411 | prop = of_get_property(np, "num-radios", NULL);
412 | if (!prop) {
413 | ERR(KERN_ALERT, "Got NULL for the number of radios.\n");
414 | goto error0;
415 | }
416 | config.num_radios = be32_to_cpup(prop);
417 | INFO(KERN_INFO, "Number of nRF51822 radios %i\n", config.num_radios);
418 |
419 | // Instantiate the correct number of radios
420 | config.radios = (struct nrf51822_dev*) kmalloc(config.num_radios * sizeof(struct nrf51822_dev), GFP_KERNEL);
421 | if (config.radios == NULL) {
422 | ERR(KERN_INFO, "Could not allocate nrf51822 devices\n");
423 | goto error0;
424 | }
425 | memset(config.radios, 0, config.num_radios * sizeof(struct nrf51822_dev));
426 |
427 |
428 | for (i=0; ipin_interrupt = of_get_named_gpio(np, buf, 0);
436 |
437 | if (!gpio_is_valid(dev->pin_interrupt)) {
438 | ERR(KERN_ALERT, "interrupt gpio%i is not valid\n", i);
439 | goto error1;
440 | }
441 | err = devm_gpio_request_one(&pltf->dev, dev->pin_interrupt, GPIOF_IN, "interrupt");
442 | if (err) goto error1;
443 |
444 | // Enable the interrupt
445 | result = devm_request_irq(&pltf->dev,
446 | gpio_to_irq(dev->pin_interrupt),
447 | nrf51822_interrupt_handler,
448 | IRQF_TRIGGER_RISING,
449 | "nrf51822_interrupt",
450 | dev);
451 | if (result) goto error1;
452 |
453 | // Get other properties
454 | snprintf(buf, 64, "radio%i-csmux", i);
455 | prop = of_get_property(np, buf, NULL);
456 | if (!prop) {
457 | ERR(KERN_ALERT, "Got NULL for the csmux index.\n");
458 | goto error1;
459 | }
460 | dev->chipselect_demux_index = be32_to_cpup(prop);
461 | INFO(KERN_INFO, "Got index %i for the mux\n", dev->chipselect_demux_index);
462 |
463 | dev->id = i;
464 | dev->spi_pending = false;
465 | init_waitqueue_head(&dev->to_user_queue);
466 | spin_lock_init(&dev->spi_spin_lock);
467 |
468 | INFO(KERN_INFO, "GPIO CONFIG radio:%i\n", i);
469 | INFO(KERN_INFO, " INTERRUPT: %i\n", dev->pin_interrupt);
470 | INFO(KERN_INFO, "SETTINGS radio:%i\n", i);
471 | INFO(KERN_INFO, " DEMUX: %i\n", dev->chipselect_demux_index);
472 | }
473 |
474 | // Allocate a major number for this device
475 | err = alloc_chrdev_region(&config.chr_dev, 0, config.num_radios, nrf51822_name);
476 | if (err < 0) {
477 | ERR(KERN_INFO, "Could not allocate a major number\n");
478 | goto error1;
479 | }
480 | config.major = MAJOR(config.chr_dev);
481 |
482 | // Create device class
483 | config.cl = class_create(THIS_MODULE, nrf51822_name);
484 | if (config.cl == NULL) {
485 | ERR(KERN_INFO, "Could not create device class\n");
486 | goto error2;
487 | }
488 |
489 | for (i=0; idevno = MKDEV(config.major, dev->id);
493 |
494 | // Register the character device
495 | cdev_init(&dev->cdev, &fops);
496 | dev->cdev.owner = THIS_MODULE;
497 | dev->cdev.ops = &fops;
498 | result = cdev_add(&dev->cdev, dev->devno, 1);
499 | if (result < 0) {
500 | ERR(KERN_INFO, "Unable to register char dev\n");
501 | goto error3;
502 | }
503 | INFO(KERN_INFO, "Char interface registered on %d\n", config.major);
504 |
505 | de = device_create(config.cl, NULL, dev->devno, NULL, "nrf51822_%d", dev->id);
506 | if (de == NULL) {
507 | ERR(KERN_INFO, "Could not create device %i\n", dev->id);
508 | goto error3;
509 | }
510 | }
511 |
512 | return 0;
513 |
514 | error3:
515 | class_destroy(config.cl);
516 | error2:
517 | unregister_chrdev_region(config.chr_dev, config.num_radios);
518 | error1:
519 | kfree(config.radios);
520 | error0:
521 | return -1;
522 | }
523 |
524 | static int nrf51822_remove(struct platform_device *pltf)
525 | {
526 | int i;
527 |
528 | for (i=0; icdev);
531 | unregister_chrdev(dev->devno, nrf51822_name);
532 | device_destroy(config.cl, dev->devno);
533 | }
534 |
535 | class_destroy(config.cl);
536 |
537 | INFO(KERN_INFO, "Removed character device\n");
538 |
539 | return 0;
540 | }
541 |
542 | static const struct of_device_id nrf51822_of_ids[] = {
543 | {.compatible = "lab11,nrf51822", },
544 | {},
545 | };
546 | MODULE_DEVICE_TABLE(of, nrf51822_of_ids);
547 |
548 | static struct platform_driver nrf51822_driver = {
549 | .driver = {
550 | .name = "gap-nrf51822",
551 | .owner = THIS_MODULE,
552 | .of_match_table = of_match_ptr(nrf51822_of_ids),
553 | },
554 | .probe = nrf51822_probe,
555 | .remove = nrf51822_remove,
556 | };
557 |
558 | module_platform_driver(nrf51822_driver);
559 |
560 | MODULE_LICENSE("GPL");
561 | MODULE_AUTHOR(DRIVER_AUTHOR);
562 | MODULE_DESCRIPTION(DRIVER_DESC);
563 |
--------------------------------------------------------------------------------
/software/driver/nrf51822/nrf51822.h:
--------------------------------------------------------------------------------
1 | #ifndef _nrf51822_H_
2 | #define _nrf51822_H_
3 |
4 | #define SPI_BUF_LEN 128
5 | #define CHAR_DEVICE_BUFFER_LEN 256
6 |
7 | struct nrf51822_dev {
8 | int id;
9 |
10 | unsigned int chipselect_demux_index;
11 |
12 | int pin_interrupt;
13 |
14 | struct cdev cdev;
15 | int devno;
16 |
17 | wait_queue_head_t to_user_queue;
18 |
19 | u8 spi_command_buffer[SPI_BUF_LEN];
20 | u8 spi_data_buffer[SPI_BUF_LEN];
21 |
22 | struct spi_transfer spi_tsfers[4];
23 | struct spi_message spi_msg;
24 |
25 | spinlock_t spi_spin_lock;
26 | unsigned long spi_spin_lock_flags;
27 | bool spi_pending;
28 |
29 | u8 buf_to_nrf51822[CHAR_DEVICE_BUFFER_LEN];
30 | u8 buf_to_user[CHAR_DEVICE_BUFFER_LEN];
31 | size_t buf_to_nrf51822_len;
32 | size_t buf_to_user_len;
33 | };
34 |
35 | struct nrf51822_config {
36 | dev_t chr_dev;
37 | unsigned int major;
38 | struct class* cl;
39 |
40 | u8 num_radios; // Number of radios on board.
41 |
42 | struct nrf51822_dev *radios;
43 |
44 | int debug_print;
45 | };
46 |
47 | int nrf51822_issue_simple_command(uint8_t command, struct nrf51822_dev *dev);
48 | static void nrf51822_read_irq(struct nrf51822_dev *dev);
49 |
50 | #endif
--------------------------------------------------------------------------------
/software/driver/nrf51822/tests/get_adv.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include "../ioctl.h"
6 | #include "../bcp.h"
7 | #include
8 |
9 | int main(char ** argv, int argc)
10 | {
11 |
12 | int result = 0;
13 | printf("Testing nrf51822 driver...\n");
14 | int file_desc;
15 | file_desc = open("/dev/nrf51822_0", O_RDWR);
16 |
17 | printf("Setting nRF51822 to send advertisements.\n");
18 | struct nrf51822_simple_command sc;
19 | sc.command = BCP_COMMAND_SNIFF_ADVERTISEMENTS;
20 | ioctl(file_desc, NRF51822_IOCTL_SIMPLE_COMMAND, &sc);
21 |
22 | int i = 0;
23 |
24 | char buf[256];
25 | char pbuf[1024];
26 | char *buf_ptr = NULL;
27 |
28 | while (true) {
29 | result = read(file_desc, buf, 127);
30 |
31 | for (i = 0; i < result; i++) {
32 | printf("%02x", buf[i]);
33 | }
34 | printf(" ");
35 | for (i = 0; i < result; i++) {
36 | if (buf[i] > 31 && buf[i] < 127) {
37 | printf("%c", buf[i]);
38 | } else {
39 | printf(".", buf[i]);
40 | }
41 | }
42 | printf("\n");
43 |
44 | }
45 |
46 | close(file_desc);
47 | }
48 |
--------------------------------------------------------------------------------
/software/nrf51822/.gitignore:
--------------------------------------------------------------------------------
1 | _build
2 | *.jlink
3 |
--------------------------------------------------------------------------------
/software/nrf51822/Makefile:
--------------------------------------------------------------------------------
1 | PROJECT_NAME = $(shell basename "$(realpath ./)")
2 |
3 | APPLICATION_SRCS = $(notdir $(wildcard ./*.c))
4 | #APPLICATION_SRCS += system_nrf51.c
5 | APPLICATION_SRCS += softdevice_handler.c
6 | APPLICATION_SRCS += ble_advdata.c
7 | APPLICATION_SRCS += ble_conn_params.c
8 | APPLICATION_SRCS += app_timer.c
9 | APPLICATION_SRCS += ble_srv_common.c
10 | APPLICATION_SRCS += ble_db_discovery.c
11 | APPLICATION_SRCS += device_manager_central.c
12 | APPLICATION_SRCS += pstorage.c
13 | APPLICATION_SRCS += nrf_delay.c
14 | APPLICATION_SRCS += spi_slave.c
15 |
16 | DEVICE = NRF51
17 |
18 | ifndef TARGET
19 | TARGET = GAP
20 | endif
21 |
22 | TARGET_UPPER = $(shell echo $(TARGET) | tr a-z A-Z)
23 | BOARD = BOARD_$(TARGET_UPPER)
24 |
25 | USE_SOFTDEVICE = s120
26 |
27 | SDK_PATH ?= $(HOME)/nrf51822_sdk/nrf51822/
28 | TEMPLATE_PATH ?= $(HOME)/git/nrf51-pure-gcc-setup/template/
29 |
30 | LIBRARY_PATHS += ./
31 |
32 | CFLAGS = -Os
33 | GDB_PORT_NUMBER = 2331
34 |
35 | include $(TEMPLATE_PATH)Makefile
36 |
--------------------------------------------------------------------------------
/software/nrf51822/README.md:
--------------------------------------------------------------------------------
1 | Setting Up The nRF51822
2 | =======================
3 |
4 | This guide explains how to get going with running code on nRF51822 based
5 | platforms.
6 |
7 | Setup
8 | =====
9 |
10 | 1. Get the makefiles. This is an external set of makefiles for the nRF51822.
11 | Apparently they are better than the ones that ship with Nordic's SDK. They
12 | are also on github and can be modified as needed.
13 |
14 | git clone https://github.com/hlnd/nrf51-pure-gcc-setup.git
15 |
16 | 1. Make sure you have the [arm-none-eabi-gcc](https://launchpad.net/gcc-arm-embedded)
17 | toolchain. You just need the binaries for your platform.
18 |
19 | 1. Get the nRF51822 SDK and S120 soft device from the
20 | [downloads page](https://www.nordicsemi.com/eng/Products/Bluetooth-Smart-Bluetooth-low-energy/nRF51822?resource=20339).
21 | You want the "nRF51 SDK Zip File" and the "S120 nRF51822 SoftDevice (Production ready)".
22 | You do need to buy a nRF51822 evm kit to get access to these, because companies
23 | are the worst.
24 |
25 | 1. Get the [Segger flashing tools](http://www.segger.com/jlink-software.html)
26 | for your platform.
27 |
28 |
29 |
30 | Install an Application
31 | ======================
32 |
33 | 1. Make sure the path to the SDK is set correctly in the application
34 | makefile (or override it in your environment).
35 |
36 | 1. Make sure the path to the gcc Makefiles is set correctly in the application
37 | makefile (or override it in your environment).
38 |
39 | 1. Just once you need to load the soft device onto the nRF51822. In the application
40 | directory:
41 |
42 | sudo make flash-softdevice SOFTDEVICE=/path/to/softdevice/s120_nrf51822_X.X.X_softdevice.hex
43 |
44 | 1. Now compile and load the application code.
45 |
46 | sudo make flash
47 |
48 |
49 |
--------------------------------------------------------------------------------
/software/nrf51822/bcp.h:
--------------------------------------------------------------------------------
1 | #ifndef BCP_H__
2 | #define BCP_H__
3 |
4 | // BCP: Bluetooth low energy Co-Processor
5 | #define BCP_COMMAND_LEN 1
6 |
7 |
8 | // commands
9 | #define BCP_CMD_READ_IRQ 1 // read what caused us to interrupt the host
10 | #define BCP_CMD_SNIFF_ADVERTISEMENTS 2 // notify host on all advertisements
11 |
12 |
13 | // response types
14 | #define BCP_RSP_ADVERTISEMENT 1 // send the raw advertisement content
15 |
16 |
17 | // Send all received advertisements to the host
18 | void bcp_sniff_advertisements ();
19 |
20 | void bcp_interrupt_host ();
21 | void bcp_interupt_host_clear ();
22 |
23 |
24 | #endif
--------------------------------------------------------------------------------
/software/nrf51822/bcp_spi_slave.c:
--------------------------------------------------------------------------------
1 |
2 | #include "app_error.h"
3 | #include "spi_slave.h"
4 |
5 | #include "boards.h"
6 | #include "led.h"
7 |
8 | #include "bcp.h"
9 | #include "bcp_spi_slave.h"
10 | #include "interrupt_event_queue.h"
11 |
12 | uint8_t spi_tx_buf[SPI_BUF_LEN] = {0};
13 | uint8_t spi_rx_buf[SPI_BUF_LEN] = {0};
14 |
15 | // Keep track of whether we have put data into the SPI buffer or not.
16 | bool buffer_full = false;
17 |
18 | // This function is called to put data in the SPI buffer when data is added
19 | // to the queue.
20 | void spi_slave_notify() {
21 | uint32_t err_code;
22 |
23 | if (!buffer_full) {
24 | // Check if we need to repopulate the SPI buffer with the next
25 | // thing from the queue
26 | uint8_t data_len;
27 | uint8_t len;
28 | uint8_t response_type;
29 |
30 | data_len = interrupt_event_queue_get(&response_type, spi_tx_buf+2);
31 |
32 | if (data_len > 0) {
33 | buffer_full = true;
34 |
35 | len = data_len + 1; // for the response type byte
36 |
37 | // Create the response SPI buffer.
38 | spi_tx_buf[0] = len;
39 | spi_tx_buf[1] = response_type;
40 |
41 | // Send the TX buffer to the SPI module
42 | err_code = spi_slave_buffers_set(spi_tx_buf,
43 | spi_rx_buf,
44 | SPI_BUF_LEN,
45 | SPI_BUF_LEN);
46 |
47 | APP_ERROR_CHECK(err_code);
48 |
49 | // Set the interrupt line high
50 | bcp_interrupt_host();
51 | }
52 | }
53 | }
54 |
55 |
56 | // Callback after a SPI transaction completes (CS goes back high).
57 | static void spi_slave_event_handle(spi_slave_evt_t event) {
58 | uint32_t err_code;
59 |
60 | // Check the event type. There are only two events, and only one is useful.
61 | if (event.evt_type == SPI_SLAVE_XFER_DONE) {
62 |
63 |
64 |
65 |
66 | // The first byte is the command byte
67 | switch (spi_rx_buf[0]) {
68 |
69 | case BCP_CMD_READ_IRQ:
70 | led_on(LED_0);
71 | // This message was only to read data. Success.
72 | break;
73 |
74 | case BCP_CMD_SNIFF_ADVERTISEMENTS:
75 | // Instructs us to send all advertisements to the host
76 | bcp_sniff_advertisements();
77 | break;
78 |
79 | default:
80 | break;
81 | }
82 |
83 |
84 | {
85 | // Check if we need to repopulate the SPI buffer with the next
86 | // thing from the queue
87 | uint8_t data_len;
88 | uint8_t len;
89 | uint8_t response_type;
90 |
91 | data_len = interrupt_event_queue_get(&response_type, spi_tx_buf+2);
92 |
93 | if (data_len > 0) {
94 |
95 | len = data_len + 1; // for the response type byte
96 |
97 | // Create the response SPI buffer.
98 | spi_tx_buf[0] = len;
99 | spi_tx_buf[1] = response_type;
100 |
101 | // Send the TX buffer to the SPI module
102 | err_code = spi_slave_buffers_set(spi_tx_buf,
103 | spi_rx_buf,
104 | SPI_BUF_LEN,
105 | SPI_BUF_LEN);
106 |
107 | nrf_gpio_pin_toggle(3);
108 | APP_ERROR_CHECK(err_code);
109 |
110 | // Set the interrupt line high
111 | bcp_interrupt_host();
112 | buffer_full = true;
113 |
114 | } else {
115 |
116 | // Still need to set the RX buffer as the reception
117 | // destination
118 | err_code = spi_slave_buffers_set(spi_tx_buf,
119 | spi_rx_buf,
120 | SPI_BUF_LEN,
121 | SPI_BUF_LEN);
122 |
123 | buffer_full = false;
124 | bcp_interupt_host_clear();
125 | }
126 | }
127 |
128 | }
129 |
130 | }
131 |
132 |
133 | uint32_t spi_slave_example_init(void)
134 | {
135 | uint32_t err_code;
136 | spi_slave_config_t spi_slave_config;
137 |
138 | // This callback fires after the master has de-asserted chip select
139 | err_code = spi_slave_evt_handler_register(spi_slave_event_handle);
140 | APP_ERROR_CHECK(err_code);
141 |
142 | // Setup the pins from the board's .h file
143 | spi_slave_config.pin_miso = SPIS_MISO_PIN;
144 | spi_slave_config.pin_mosi = SPIS_MOSI_PIN;
145 | spi_slave_config.pin_sck = SPIS_SCK_PIN;
146 | spi_slave_config.pin_csn = SPIS_CSN_PIN;
147 | spi_slave_config.mode = SPI_MODE_0;
148 | spi_slave_config.bit_order = SPIM_MSB_FIRST;
149 | spi_slave_config.def_tx_character = 0x00;
150 | spi_slave_config.orc_tx_character = 0x55;
151 |
152 | err_code = spi_slave_init(&spi_slave_config);
153 | APP_ERROR_CHECK(err_code);
154 |
155 | // Set buffers.
156 | err_code = spi_slave_buffers_set(spi_tx_buf,
157 | spi_rx_buf,
158 | SPI_BUF_LEN,
159 | SPI_BUF_LEN);
160 | APP_ERROR_CHECK(err_code);
161 |
162 | return NRF_SUCCESS;
163 | }
164 |
165 |
--------------------------------------------------------------------------------
/software/nrf51822/bcp_spi_slave.h:
--------------------------------------------------------------------------------
1 | #ifndef BCP_SPI_SLAVE_H__
2 | #define BCP_SPI_SLAVE_H__
3 |
4 | // State machine for the SPI Slave driver.
5 | typedef enum {
6 | SPI_SLAVE_STATE_WAIT_FOR_COMMAND,
7 | SPI_SLAVE_STATE_RUN_COMMAND
8 | } spi_slave_state_e;
9 |
10 |
11 | #define SPI_BUF_LEN 64
12 |
13 | void spi_slave_notify();
14 | uint32_t spi_slave_example_init(void);
15 |
16 | #endif
--------------------------------------------------------------------------------
/software/nrf51822/boards.h:
--------------------------------------------------------------------------------
1 | #ifndef BOARDS_H
2 | #define BOARDS_H
3 |
4 | #if defined(BOARD_GAP)
5 | #include "gap.h"
6 | #else
7 | #error "Board is not defined"
8 | #endif
9 |
10 | #endif
11 |
--------------------------------------------------------------------------------
/software/nrf51822/device_manager_cnfg.h:
--------------------------------------------------------------------------------
1 | /* Copyright (C) 2013 Nordic Semiconductor. All Rights Reserved.
2 | *
3 | * The information contained herein is property of Nordic Semiconductor ASA.
4 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
5 | *
6 | * Licensees are granted free, non-transferable use of the information. NO
7 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
8 | * the file.
9 | *
10 | */
11 |
12 | /**
13 | * @file device_manager_cnfg.h
14 | *
15 | * @cond
16 | * @defgroup device_manager_cnfg Device Manager Configuration
17 | * @ingroup device_manager
18 | * @{
19 | *
20 | * @brief Defines application specific configuration for Device Manager.
21 | *
22 | * @details All configurations that are specific to application have been defined
23 | * here. Application should configuration that best suits its requirements.
24 | */
25 |
26 | #ifndef DEVICE_MANAGER_CNFG_H__
27 | #define DEVICE_MANAGER_CNFG_H__
28 |
29 | /**
30 | * @defgroup device_manager_inst Device Manager Instances
31 | * @{
32 | */
33 | /**
34 | * @brief Maximum applications that Device Manager can support.
35 | *
36 | * @details Maximum application that the Device Manager can support.
37 | * Currently only one application can be supported.
38 | * Minimum value : 1
39 | * Maximum value : 1
40 | * Dependencies : None.
41 | */
42 | #define DEVICE_MANAGER_MAX_APPLICATIONS 1
43 |
44 | /**
45 | * @brief Maximum connections that Device Manager should simultaneously manage.
46 | *
47 | * @details Maximum connections that Device Manager should simultaneously manage.
48 | * Minimum value : 1
49 | * Maximum value : Maximum links supported by SoftDevice.
50 | * Dependencies : None.
51 | */
52 | #define DEVICE_MANAGER_MAX_CONNECTIONS 1
53 |
54 |
55 | /**
56 | * @brief Maximum bonds that Device Manager should manage.
57 | *
58 | * @details Maximum bonds that Device Manager should manage.
59 | * Minimum value : 1
60 | * Maximum value : 254.
61 | * Dependencies : None.
62 | * @note In case of GAP Peripheral role, the Device Manager will accept bonding procedure
63 | * requests from peers even if this limit is reached, but bonding information will not
64 | * be stored. In such cases, application will be notified with DM_DEVICE_CONTEXT_FULL
65 | * as event result at the completion of the security procedure.
66 | */
67 | #define DEVICE_MANAGER_MAX_BONDS 7
68 |
69 |
70 | /**
71 | * @brief Maximum Characteristic Client Descriptors used for GATT Server.
72 | *
73 | * @details Maximum Characteristic Client Descriptors used for GATT Server.
74 | * Minimum value : 1
75 | * Maximum value : 254.
76 | * Dependencies : None.
77 | */
78 | #define DM_GATT_CCCD_COUNT 1
79 |
80 |
81 | /**
82 | * @brief Size of application context.
83 | *
84 | * @details Size of application context that Device Manager should manage for each bonded device.
85 | * Size had to be a multiple of word size.
86 | * Minimum value : 4.
87 | * Maximum value : 256.
88 | * Dependencies : Needed only if Application Context saving is used by the application.
89 | * @note If set to zero, its an indication that application context is not required to be managed
90 | * by the module.
91 | */
92 | #define DEVICE_MANAGER_APP_CONTEXT_SIZE 20
93 |
94 | /** @} */
95 | /** @} */
96 | /** @endcond */
97 | #endif // DEVICE_MANAGER_CNFG_H__
98 |
99 |
--------------------------------------------------------------------------------
/software/nrf51822/gap.h:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
2 | *
3 | * The information contained herein is property of Nordic Semiconductor ASA.
4 | * Terms and conditions of usage are described in detail in NORDIC
5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
6 | *
7 | * Licensees are granted free, non-transferable use of the information. NO
8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
9 | * the file.
10 | *
11 | */
12 | #ifndef PCA10001_H
13 | #define PCA10001_H
14 |
15 | #include "nrf_gpio.h"
16 |
17 | #define DEVICE_NAME "gap"
18 |
19 |
20 | #define LED_START 13
21 | #define LED_0 13
22 | #define LED_1 13
23 | #define LED_STOP 13
24 |
25 | //#define BUTTON_START 16
26 | //#define BUTTON_0 16
27 | //#define BUTTON_1 17
28 | //#define BUTTON_STOP 17
29 | //#define BUTTON_PULL NRF_GPIO_PIN_PULLUP
30 |
31 | // This pin is mapped to the FTDI chip to all the device to enter the
32 | // bootloader mode.
33 | #define BOOTLOADER_CTRL_PIN 3
34 | #define BOOTLOADER_CTRL_PULL NRF_GPIO_PIN_PULLUP
35 |
36 |
37 | #define RX_PIN_NUMBER 28
38 | #define TX_PIN_NUMBER 29
39 | #define CTS_PIN_NUMBER 0
40 | #define RTS_PIN_NUMBER 0
41 | #define HWFC false
42 |
43 | #define SPIS_MISO_PIN 9 // SPI MISO signal.
44 | #define SPIS_CSN_PIN 11 // 6 // SPI CSN signal.
45 | #define SPIS_MOSI_PIN 8 // SPI MOSI signal.
46 | #define SPIS_SCK_PIN 10 // SPI SCK signal.
47 |
48 | #define SPIM0_SCK_PIN 9u /**< SPI clock GPIO pin number. */
49 | #define SPIM0_MOSI_PIN 11u /**< SPI Master Out Slave In GPIO pin number. */
50 | #define SPIM0_MISO_PIN 10u /**< SPI Master In Slave Out GPIO pin number. */
51 | #define SPIM0_SS_PIN 1u /**< SPI Slave Select GPIO pin number. */
52 |
53 | //#define SPIM1_SCK_PIN 16u /**< SPI clock GPIO pin number. */
54 | //#define SPIM1_MOSI_PIN 18u /**< SPI Master Out Slave In GPIO pin number. */
55 | //#define SPIM1_MISO_PIN 17u /**< SPI Master In Slave Out GPIO pin number. */
56 | //#define SPIM1_SS_PIN 19u /**< SPI Slave Select GPIO pin number. */
57 |
58 | // serialization APPLICATION board
59 |
60 | // UART
61 | // this configuration works with the SPI wires setup
62 | #define SER_APP_RX_PIN 20 // UART RX pin number.
63 | #define SER_APP_TX_PIN 22 // UART TX pin number.
64 | #define SER_APP_CTS_PIN 23 // UART Clear To Send pin number.
65 | #define SER_APP_RTS_PIN 21 // UART Request To Send pin number.
66 |
67 | // SPI
68 | #if 0
69 | #define SER_APP_SPIM0_SCK_PIN 20 // SPI clock GPIO pin number.
70 | #define SER_APP_SPIM0_MOSI_PIN 17 // SPI Master Out Slave In GPIO pin number
71 | #define SER_APP_SPIM0_MISO_PIN 16 // SPI Master In Slave Out GPIO pin number
72 | #define SER_APP_SPIM0_SS_PIN 21 // SPI Slave Select GPIO pin number
73 | #define SER_APP_SPIM0_RDY_PIN 19 // SPI READY GPIO pin number
74 | #define SER_APP_SPIM0_REQ_PIN 18 // SPI REQUEST GPIO pin number
75 | #else
76 | #define SER_APP_SPIM0_SCK_PIN 23 // SPI clock GPIO pin number.
77 | #define SER_APP_SPIM0_MOSI_PIN 20 // SPI Master Out Slave In GPIO pin number
78 | #define SER_APP_SPIM0_MISO_PIN 22 // SPI Master In Slave Out GPIO pin number
79 | #define SER_APP_SPIM0_SS_PIN 21 // SPI Slave Select GPIO pin number
80 | #define SER_APP_SPIM0_RDY_PIN 25 // SPI READY GPIO pin number
81 | #define SER_APP_SPIM0_REQ_PIN 24 // SPI REQUEST GPIO pin number
82 | #endif
83 |
84 | // serialization CONNECTIVITY board
85 |
86 | // UART
87 | #if 0
88 | #define SER_CON_RX_PIN 22 // UART RX pin number.
89 | #define SER_CON_TX_PIN 20 // UART TX pin number.
90 | #define SER_CON_CTS_PIN 21 // UART Clear To Send pin number. Not used if HWFC is set to false.
91 | #define SER_CON_RTS_PIN 23 // UART Request To Send pin number. Not used if HWFC is set to false.
92 | #else
93 | // this configuration works with the SPI wires setup
94 | #define SER_CON_RX_PIN 20 // UART RX pin number.
95 | #define SER_CON_TX_PIN 22 // UART TX pin number.
96 | #define SER_CON_CTS_PIN 21 // UART Clear To Send pin number. Not used if HWFC is set to false.
97 | #define SER_CON_RTS_PIN 23 // UART Request To Send pin number. Not used if HWFC is set to false.
98 | #endif
99 |
100 | //SPI
101 | #if 0
102 | #define SER_CON_SPIS_SCK_PIN 20 // SPI SCK signal.
103 | #define SER_CON_SPIS_MISO_PIN 16 // SPI MISO signal.
104 | #define SER_CON_SPIS_MOSI_PIN 17 // SPI MOSI signal.
105 | #define SER_CON_SPIS_CSN_PIN 21 // SPI CSN signal.
106 | #define SER_CON_SPIS_RDY_PIN 19 // SPI READY GPIO pin number.
107 | #define SER_CON_SPIS_REQ_PIN 18 // SPI REQUEST GPIO pin number.
108 | #else
109 | #define SER_CON_SPIS_SCK_PIN 23 // SPI SCK signal.
110 | #define SER_CON_SPIS_MOSI_PIN 22 // SPI MOSI signal.
111 | #define SER_CON_SPIS_MISO_PIN 20 // SPI MISO signal.
112 | #define SER_CON_SPIS_CSN_PIN 21 // SPI CSN signal.
113 | #define SER_CON_SPIS_RDY_PIN 25 // SPI READY GPIO pin number.
114 | #define SER_CON_SPIS_REQ_PIN 24 // SPI REQUEST GPIO pin number.
115 | #endif
116 |
117 | #define SER_CONN_ASSERT_LED_PIN LED_0
118 |
119 | #endif
120 |
--------------------------------------------------------------------------------
/software/nrf51822/interrupt_event_queue.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "nrf_error.h"
6 |
7 | #include "interrupt_event_queue.h"
8 | #include "bcp_spi_slave.h"
9 |
10 | interrupt_event_queue_item_t queue[INTERRUPT_EVENT_QUEUE_LEN];
11 | uint8_t queue_head = 0;
12 | uint8_t queue_tail = 0;
13 | uint8_t items_in_queue = 0;
14 |
15 |
16 | uint32_t interrupt_event_queue_add (uint8_t interrupt_event,
17 | uint8_t len,
18 | uint8_t* data) {
19 | interrupt_event_queue_item_t* queue_entry;
20 |
21 | if (items_in_queue == INTERRUPT_EVENT_QUEUE_LEN) {
22 | return NRF_ERROR_NO_MEM;
23 | }
24 |
25 | queue_entry = queue + queue_head;
26 |
27 | // Copy into the queue
28 | memcpy(queue_entry->buffer, data, fmin(len, 64));
29 | queue_entry->len = len;
30 | queue_entry->interrupt_event = interrupt_event;
31 |
32 | // Update counters
33 | items_in_queue++;
34 | queue_head = (queue_head + 1) % INTERRUPT_EVENT_QUEUE_LEN;
35 |
36 | // Notify the SPI layer that it should read from the queue to populate
37 | // the SPI buffer ahead of time.
38 | spi_slave_notify();
39 |
40 | return NRF_SUCCESS;
41 | }
42 |
43 | uint16_t interrupt_event_queue_get (uint8_t* interrupt_event, uint8_t* data) {
44 | uint8_t len;
45 |
46 | if (items_in_queue == 0) {
47 | return 0;
48 | }
49 |
50 | // Copy to the arguments
51 | *interrupt_event = queue[queue_tail].interrupt_event;
52 | memcpy(data, queue[queue_tail].buffer, fmin(queue[queue_tail].len, 64));
53 | len = queue[queue_tail].len;
54 |
55 | // Update queue state
56 | items_in_queue--;
57 | queue_tail = (queue_tail + 1) % INTERRUPT_EVENT_QUEUE_LEN;
58 |
59 | return len;
60 | }
61 |
--------------------------------------------------------------------------------
/software/nrf51822/interrupt_event_queue.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 |
4 | #define INTERRUPT_EVENT_QUEUE_LEN 4
5 |
6 |
7 | typedef struct {
8 | uint8_t buffer[64];
9 | uint8_t len;
10 | uint8_t interrupt_event;
11 | } interrupt_event_queue_item_t;
12 |
13 |
14 | uint32_t interrupt_event_queue_add (uint8_t interrupt_event,
15 | uint8_t len,
16 | uint8_t* data);
17 |
18 | uint16_t interrupt_event_queue_get (uint8_t* interrupt_event, uint8_t* data);
19 |
--------------------------------------------------------------------------------
/software/nrf51822/led.c:
--------------------------------------------------------------------------------
1 | // LED Library
2 |
3 | // Assumes active low LEDs
4 |
5 | #include
6 | #include "nrf_gpio.h"
7 |
8 |
9 | void led_init (uint32_t pin_number) {
10 | nrf_gpio_cfg_output(pin_number);
11 | nrf_gpio_pin_set(pin_number);
12 | }
13 |
14 | void led_on (uint32_t pin_number) {
15 | nrf_gpio_pin_clear(pin_number);
16 | }
17 |
18 | void led_off (uint32_t pin_number) {
19 | nrf_gpio_pin_set(pin_number);
20 | }
21 |
22 | void led_toggle (uint32_t pin_number) {
23 | nrf_gpio_pin_toggle(pin_number);
24 | }
25 |
--------------------------------------------------------------------------------
/software/nrf51822/led.h:
--------------------------------------------------------------------------------
1 | // LED Library
2 |
3 | // Assumes active low LEDs
4 |
5 | #include
6 | #include "nrf_gpio.h"
7 |
8 | void led_init (uint32_t pin_number);
9 | void led_on (uint32_t pin_number);
10 | void led_off (uint32_t pin_number);
11 | void led_toggle (uint32_t pin_number);
12 |
--------------------------------------------------------------------------------
/software/nrf51822/main.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Bluetooth low energy Co-Processor
4 |
5 | This app makes the nRF51822 into a BLE SPI slave peripheral.
6 |
7 | See bcp.h for the list of valid commands the SPI master can issue.
8 |
9 | */
10 |
11 | #include
12 | #include
13 | #include
14 | #include "nordic_common.h"
15 | #include "nrf_sdm.h"
16 | #include "ble.h"
17 | #include "ble_db_discovery.h"
18 | #include "softdevice_handler.h"
19 | #include "app_util.h"
20 | #include "app_error.h"
21 | #include "ble_advdata_parser.h"
22 | #include "boards.h"
23 | #include "nrf_gpio.h"
24 | #include "pstorage.h"
25 | #include "device_manager.h"
26 | #include "app_trace.h"
27 | #include "ble_hrs_c.h"
28 | #include "ble_bas_c.h"
29 | #include "app_util.h"
30 |
31 | #include "led.h"
32 |
33 | #include "bcp.h"
34 | #include "interrupt_event_queue.h"
35 | #include "bcp_spi_slave.h"
36 |
37 |
38 | #define LED_GOT_ADV_PACKET LED_0 /**< Is on when application has asserted. */
39 |
40 | #define INTERRUPT_PIN 7
41 | #define ADV_PIN 4
42 |
43 | #define APPL_LOG app_trace_log /**< Debug logger macro that will be used in this file to do logging of debug information over UART. */
44 |
45 | #define SEC_PARAM_BOND 1 /**< Perform bonding. */
46 | #define SEC_PARAM_MITM 1 /**< Man In The Middle protection not required. */
47 | #define SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_NONE /**< No I/O capabilities. */
48 | #define SEC_PARAM_OOB 0 /**< Out Of Band data not available. */
49 | #define SEC_PARAM_MIN_KEY_SIZE 7 /**< Minimum encryption key size. */
50 | #define SEC_PARAM_MAX_KEY_SIZE 16 /**< Maximum encryption key size. */
51 |
52 | #define SCAN_INTERVAL 0x00A0 /**< Determines scan interval in units of 0.625 millisecond. */
53 | #define SCAN_WINDOW 0x0050 /**< Determines scan window in units of 0.625 millisecond. */
54 |
55 | #define MIN_CONNECTION_INTERVAL MSEC_TO_UNITS(7.5, UNIT_1_25_MS) /**< Determines maximum connection interval in millisecond. */
56 | #define MAX_CONNECTION_INTERVAL MSEC_TO_UNITS(30, UNIT_1_25_MS) /**< Determines maximum connection interval in millisecond. */
57 | #define SLAVE_LATENCY 0 /**< Determines slave latency in counts of connection events. */
58 | #define SUPERVISION_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) /**< Determines supervision time-out in units of 10 millisecond. */
59 |
60 | #define TARGET_UUID 0x180D /**< Target device name that application is looking for. */
61 | #define MAX_PEER_COUNT DEVICE_MANAGER_MAX_CONNECTIONS /**< Maximum number of peer's application intends to manage. */
62 | #define UUID16_SIZE 2 /**< Size of 16 bit UUID */
63 |
64 | /**@breif Macro to unpack 16bit unsigned UUID from octet stream. */
65 | #define UUID16_EXTRACT(DST,SRC) \
66 | do \
67 | { \
68 | (*(DST)) = (SRC)[1]; \
69 | (*(DST)) <<= 8; \
70 | (*(DST)) |= (SRC)[0]; \
71 | } while(0)
72 |
73 | /**@brief Variable length data encapsulation in terms of length and pointer to data */
74 | typedef struct
75 | {
76 | uint8_t * p_data; /**< Pointer to data. */
77 | uint16_t data_len; /**< Length of data. */
78 | }data_t;
79 |
80 | typedef enum
81 | {
82 | BLE_NO_SCAN, /**< No advertising running. */
83 | BLE_WHITELIST_SCAN, /**< Advertising with whitelist. */
84 | BLE_FAST_SCAN, /**< Fast advertising running. */
85 | } ble_advertising_mode_t;
86 |
87 | static ble_db_discovery_t m_ble_db_discovery; /**< Structure used to identify the DB Discovery module. */
88 | static ble_hrs_c_t m_ble_hrs_c; /**< Structure used to identify the heart rate client module. */
89 | static ble_bas_c_t m_ble_bas_c; /**< Structure used to identify the Battery Service client module. */
90 | static ble_gap_scan_params_t m_scan_param; /**< Scan parameters requested for scanning and connection. */
91 | static dm_application_instance_t m_dm_app_id; /**< Application identifier. */
92 | static dm_handle_t m_dm_device_handle; /**< Device Identifier identifier. */
93 | static uint8_t m_peer_count = 0; /**< Number of peer's connected. */
94 | static uint8_t m_scan_mode; /**< Scan mode used by application. */
95 |
96 | static bool m_memory_access_in_progress = false; /**< Flag to keep track of ongoing operations on persistent memory. */
97 |
98 | /**
99 | * @brief Connection parameters requested for connection.
100 | */
101 | static const ble_gap_conn_params_t m_connection_param =
102 | {
103 | (uint16_t)MIN_CONNECTION_INTERVAL, // Minimum connection
104 | (uint16_t)MAX_CONNECTION_INTERVAL, // Maximum connection
105 | 0, // Slave latency
106 | (uint16_t)SUPERVISION_TIMEOUT // Supervision time-out
107 | };
108 |
109 | static void scan_start(void);
110 |
111 | #define APPL_LOG app_trace_log /**< Debug logger macro that will be used in this file to do logging of debug information over UART. */
112 |
113 | // WARNING: The following macro MUST be un-defined (by commenting out the definition) if the user
114 | // does not have a nRF6350 Display unit. If this is not done, the application will not work.
115 | //#define APPL_LCD_PRINT_ENABLE /**< In case you do not have a functional display unit, disable this flag and observe trace on UART. */
116 |
117 | #ifdef APPL_LCD_PRINT_ENABLE
118 |
119 | #define APPL_LCD_CLEAR nrf6350_lcd_clear /**< Macro to clear the LCD display.*/
120 | #define APPL_LCD_WRITE nrf6350_lcd_write_string /**< Macro to write a string to the LCD display.*/
121 |
122 | #else // APPL_LCD_PRINT_ENABLE
123 |
124 | #define APPL_LCD_WRITE(...) true /**< Macro to clear the LCD display defined to do nothing when @ref APPL_LCD_PRINT_ENABLE is not defined.*/
125 | #define APPL_LCD_CLEAR(...) true /**< Macro to write a string to the LCD display defined to do nothing when @ref APPL_LCD_PRINT_ENABLE is not defined.*/
126 |
127 | #endif // APPL_LCD_PRINT_ENABLE
128 |
129 |
130 |
131 |
132 | bool bcp_irq_advertisements = false;
133 | //bool bcp_irq_advertisements = true;
134 |
135 |
136 |
137 |
138 |
139 |
140 | /**@brief Function for error handling, which is called when an error has occurred.
141 | *
142 | * @warning This handler is an example only and does not fit a final product. You need to analyze
143 | * how your product is supposed to react in case of error.
144 | *
145 | * @param[in] error_code Error code supplied to the handler.
146 | * @param[in] line_num Line number where the handler is called.
147 | * @param[in] p_file_name Pointer to the file name.
148 | */
149 | void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name)
150 | {
151 | // APPL_LOG("[APPL]: ASSERT: %s, %d, error 0x%08x\r\n", p_file_name, line_num, error_code);
152 | // nrf_gpio_pin_set(ASSERT_LED_PIN_NO);
153 |
154 | // This call can be used for debug purposes during development of an application.
155 | // @note CAUTION: Activating this code will write the stack to flash on an error.
156 | // This function should NOT be used in a final product.
157 | // It is intended STRICTLY for development/debugging purposes.
158 | // The flash write will happen EVEN if the radio is active, thus interrupting
159 | // any communication.
160 | // Use with care. Un-comment the line below to use.
161 | // ble_debug_assert_handler(error_code, line_num, p_file_name);
162 |
163 | // On assert, the system can only recover with a reset.
164 | NVIC_SystemReset();
165 | }
166 |
167 |
168 | /**@brief Function for asserts in the SoftDevice.
169 | *
170 | * @details This function will be called in case of an assert in the SoftDevice.
171 | *
172 | * @warning This handler is an example only and does not fit a final product. You need to analyze
173 | * how your product is supposed to react in case of Assert.
174 | * @warning On assert from the SoftDevice, the system can only recover on reset.
175 | *
176 | * @param[in] line_num Line number of the failing ASSERT call.
177 | * @param[in] p_file_name File name of the failing ASSERT call.
178 | */
179 | void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
180 | {
181 | app_error_handler(0xDEADBEEF, line_num, p_file_name);
182 | }
183 |
184 |
185 |
186 | // Send all received advertisements to the host
187 | void bcp_sniff_advertisements () {
188 | led_on(LED_0);
189 | bcp_irq_advertisements = true;
190 | }
191 |
192 |
193 |
194 | void bcp_interrupt_host () {
195 | nrf_gpio_pin_set(INTERRUPT_PIN);
196 | }
197 |
198 | void bcp_interupt_host_clear () {
199 | nrf_gpio_pin_clear(INTERRUPT_PIN);
200 | }
201 |
202 |
203 |
204 |
205 | /**@brief Callback handling device manager events.
206 | *
207 | * @details This function is called to notify the application of device manager events.
208 | *
209 | * @param[in] p_handle Device Manager Handle. For link related events, this parameter
210 | * identifies the peer.
211 | * @param[in] p_event Pointer to the device manager event.
212 | * @param[in] event_status Status of the event.
213 | */
214 | static api_result_t device_manager_event_handler(const dm_handle_t * p_handle,
215 | const dm_event_t * p_event,
216 | const api_result_t event_result)
217 | {
218 | // bool lcd_write_status;
219 | // uint32_t err_code;
220 |
221 | // switch(p_event->event_id)
222 | // {
223 | // case DM_EVT_CONNECTION:
224 | // {
225 | // APPL_LOG("[APPL]: >> DM_EVT_CONNECTION\r\n");
226 | // #ifdef ENABLE_DEBUG_LOG_SUPPORT
227 | // ble_gap_addr_t * peer_addr;
228 | // peer_addr = &p_event->event_param.p_gap_param->params.connected.peer_addr;
229 | // #endif // ENABLE_DEBUG_LOG_SUPPORT
230 | // APPL_LOG("[APPL]:[%02X %02X %02X %02X %02X %02X]: Connection Established\r\n",
231 | // peer_addr->addr[0], peer_addr->addr[1], peer_addr->addr[2],
232 | // peer_addr->addr[3], peer_addr->addr[4], peer_addr->addr[5]);
233 |
234 | // nrf_gpio_pin_set(CONNECTED_LED_PIN_NO);
235 | // lcd_write_status = APPL_LCD_WRITE("Connected", 9, LCD_UPPER_LINE, 0);
236 | // if (!lcd_write_status)
237 | // {
238 | // APPL_LOG("[APPL]: LCD Write failed!\r\n");
239 | // }
240 | // m_dm_device_handle = (*p_handle);
241 |
242 | // // Discover peer's services.
243 | // err_code = ble_db_discovery_start(&m_ble_db_discovery,
244 | // p_event->event_param.p_gap_param->conn_handle);
245 | // APP_ERROR_CHECK(err_code);
246 |
247 | // m_peer_count++;
248 | // if (m_peer_count < MAX_PEER_COUNT)
249 | // {
250 | // scan_start();
251 | // }
252 | // APPL_LOG("[APPL]: << DM_EVT_CONNECTION\r\n");
253 | // break;
254 | // }
255 |
256 | // case DM_EVT_DISCONNECTION:
257 | // {
258 | // APPL_LOG("[APPL]: >> DM_EVT_DISCONNECTION\r\n");
259 | // memset(&m_ble_db_discovery, 0 , sizeof (m_ble_db_discovery));
260 | // lcd_write_status = APPL_LCD_CLEAR();
261 | // if (!lcd_write_status)
262 | // {
263 | // APPL_LOG("[APPL]: LCD Clear failed!\r\n");
264 | // }
265 |
266 | // lcd_write_status = APPL_LCD_WRITE("Disconnected", 12, LCD_UPPER_LINE, 0);
267 | // if (!lcd_write_status)
268 | // {
269 | // APPL_LOG("[APPL]:[4]: LCD Write failed!\r\n");
270 | // }
271 |
272 | // nrf_gpio_pin_clear(CONNECTED_LED_PIN_NO);
273 | // if (m_peer_count == MAX_PEER_COUNT)
274 | // {
275 | // scan_start();
276 | // }
277 | // m_peer_count--;
278 | // APPL_LOG("[APPL]: << DM_EVT_DISCONNECTION\r\n");
279 | // break;
280 | // }
281 |
282 | // case DM_EVT_SECURITY_SETUP:
283 | // {
284 | // APPL_LOG("[APPL]:[0x%02X] >> DM_EVT_SECURITY_SETUP\r\n", p_handle->connection_id);
285 | // // Slave securtiy request received from peer, if from a non bonded device,
286 | // // initiate security setup, else, wait for encryption to complete.
287 | // err_code = dm_security_setup_req(&m_dm_device_handle);
288 | // APP_ERROR_CHECK(err_code);
289 | // APPL_LOG("[APPL]:[0x%02X] << DM_EVT_SECURITY_SETUP\r\n", p_handle->connection_id);
290 | // break;
291 | // }
292 | // case DM_EVT_SECURITY_SETUP_COMPLETE:
293 | // {
294 | // APPL_LOG("[APPL]: >> DM_EVT_SECURITY_SETUP_COMPLETE\r\n");
295 | // // Heart rate service discovered. Enable notification of Heart Rate Measurement.
296 | // err_code = ble_hrs_c_hrm_notif_enable(&m_ble_hrs_c);
297 | // APP_ERROR_CHECK(err_code);
298 | // APPL_LOG("[APPL]: << DM_EVT_SECURITY_SETUP_COMPLETE\r\n");
299 | // break;
300 | // }
301 |
302 | // case DM_EVT_LINK_SECURED:
303 | // APPL_LOG("[APPL]: >> DM_LINK_SECURED_IND\r\n");
304 | // APPL_LOG("[APPL]: << DM_LINK_SECURED_IND\r\n");
305 | // break;
306 |
307 | // case DM_EVT_DEVICE_CONTEXT_LOADED:
308 | // APPL_LOG("[APPL]: >> DM_EVT_LINK_SECURED\r\n");
309 | // APP_ERROR_CHECK(event_result);
310 | // APPL_LOG("[APPL]: << DM_EVT_DEVICE_CONTEXT_LOADED\r\n");
311 | // break;
312 |
313 | // case DM_EVT_DEVICE_CONTEXT_STORED:
314 | // APPL_LOG("[APPL]: >> DM_EVT_DEVICE_CONTEXT_STORED\r\n");
315 | // APP_ERROR_CHECK(event_result);
316 | // APPL_LOG("[APPL]: << DM_EVT_DEVICE_CONTEXT_STORED\r\n");
317 | // break;
318 |
319 | // case DM_EVT_DEVICE_CONTEXT_DELETED:
320 | // APPL_LOG("[APPL]: >> DM_EVT_DEVICE_CONTEXT_DELETED\r\n");
321 | // APP_ERROR_CHECK(event_result);
322 | // APPL_LOG("[APPL]: << DM_EVT_DEVICE_CONTEXT_DELETED\r\n");
323 | // break;
324 |
325 | // default:
326 | // break;
327 | // }
328 |
329 | return NRF_SUCCESS;
330 | }
331 |
332 |
333 | /**
334 | * @brief Parses advertisement data, providing length and location of the field in case
335 | * matching data is found.
336 | *
337 | * @param[in] Type of data to be looked for in advertisement data.
338 | * @param[in] Advertisement report length and pointer to report.
339 | * @param[out] If data type requested is found in the data report, type data length and
340 | * pointer to data will be populated here.
341 | *
342 | * @retval NRF_SUCCESS if the data type is found in the report.
343 | * @retval NRF_ERROR_NOT_FOUND if the data type could not be found.
344 | */
345 | static uint32_t adv_report_parse(uint8_t type, data_t * p_advdata, data_t * p_typedata)
346 | {
347 | uint32_t index = 0;
348 | uint8_t * p_data;
349 |
350 | p_data = p_advdata->p_data;
351 |
352 | while (index < p_advdata->data_len)
353 | {
354 | uint8_t field_length = p_data[index];
355 | uint8_t field_type = p_data[index+1];
356 |
357 | if (field_type == type)
358 | {
359 | p_typedata->p_data = &p_data[index+2];
360 | p_typedata->data_len = field_length-1;
361 | return NRF_SUCCESS;
362 | }
363 | index += field_length+1;
364 | }
365 | return NRF_ERROR_NOT_FOUND;
366 | }
367 |
368 |
369 | /**@brief Function for handling the Application's BLE Stack events.
370 | *
371 | * @param[in] p_ble_evt Bluetooth stack event.
372 | */
373 | static void on_ble_evt(ble_evt_t * p_ble_evt)
374 | {
375 | uint32_t err_code;
376 | const ble_gap_evt_t * p_gap_evt = &p_ble_evt->evt.gap_evt;
377 |
378 | switch (p_ble_evt->header.evt_id)
379 | {
380 | case BLE_GAP_EVT_ADV_REPORT:
381 | {
382 |
383 | //led_off(LED_GOT_ADV_PACKET);
384 |
385 |
386 | nrf_gpio_pin_toggle(ADV_PIN);
387 |
388 |
389 | if (bcp_irq_advertisements) {
390 | interrupt_event_queue_add(BCP_RSP_ADVERTISEMENT,
391 | p_gap_evt->params.adv_report.dlen+8,
392 | (uint8_t*)&p_gap_evt->params.adv_report);
393 |
394 | //nrf_gpio_pin_toggle(INTERRUPT_PIN);
395 | }
396 |
397 |
398 | // data_t adv_data;
399 | // data_t type_data;
400 |
401 | // // Initialize advertisement report for parsing.
402 | // adv_data.p_data = (uint8_t *)p_gap_evt->params.adv_report.data;
403 | // adv_data.data_len = p_gap_evt->params.adv_report.dlen;
404 |
405 | // err_code = adv_report_parse(BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE,
406 | // &adv_data,
407 | // &type_data);
408 | // if (err_code != NRF_SUCCESS)
409 | // {
410 | // // Compare short local name in case complete name does not match.
411 | // err_code = adv_report_parse(BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE,
412 | // &adv_data,
413 | // &type_data);
414 | // }
415 |
416 | // // Verify if short or complete name matches target.
417 | // if (err_code == NRF_SUCCESS)
418 | // {
419 | // uint16_t extracted_uuid;
420 |
421 | // // UUIDs found, look for matching UUID
422 | // for (uint32_t u_index = 0; u_index < (type_data.data_len/UUID16_SIZE); u_index++)
423 | // {
424 | // UUID16_EXTRACT(&extracted_uuid,&type_data.p_data[u_index * UUID16_SIZE]);
425 |
426 | // APPL_LOG("\t[APPL]: %x\r\n",extracted_uuid);
427 |
428 | // if(extracted_uuid == TARGET_UUID)
429 | // {
430 | // // Stop scanning.
431 | // err_code = sd_ble_gap_scan_stop();
432 | // if (err_code != NRF_SUCCESS)
433 | // {
434 | // APPL_LOG("[APPL]: Scan stop failed, reason %d\r\n", err_code);
435 | // }
436 | // nrf_gpio_pin_clear(SCAN_LED_PIN_NO);
437 |
438 | // m_scan_param.selective = 0;
439 |
440 | // // Initiate connection.
441 | // err_code = sd_ble_gap_connect(&p_gap_evt->params.adv_report.\
442 | // peer_addr,
443 | // &m_scan_param,
444 | // &m_connection_param);
445 |
446 | // if (err_code != NRF_SUCCESS)
447 | // {
448 | // APPL_LOG("[APPL]: Connection Request Failed, reason %d\r\n", err_code);
449 | // }
450 | // break;
451 | // }
452 | // }
453 | // }
454 | break;
455 | }
456 | case BLE_GAP_EVT_TIMEOUT:
457 | // if(p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN)
458 | // {
459 | // APPL_LOG("[APPL]: Scan timed out.\r\n");
460 | // if (m_scan_mode == BLE_WHITELIST_SCAN)
461 | // {
462 | // m_scan_mode = BLE_FAST_SCAN;
463 |
464 | // // Start non selective scanning.
465 | // scan_start();
466 | // }
467 | // }
468 | // else if (p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN)
469 | // {
470 | // APPL_LOG("[APPL]: Connection Request timed out.\r\n");
471 | // }
472 | break;
473 | case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
474 | // // Accepting parameters requested by peer.
475 | // err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle,
476 | // &p_gap_evt->params.conn_param_update_request.conn_params);
477 | // APP_ERROR_CHECK(err_code);
478 | break;
479 | default:
480 | break;
481 | }
482 | }
483 |
484 | /**@brief Function for handling the Application's system events.
485 | *
486 | * @param[in] sys_evt system event.
487 | */
488 | static void on_sys_evt(uint32_t sys_evt)
489 | {
490 | switch(sys_evt)
491 | {
492 | case NRF_EVT_FLASH_OPERATION_SUCCESS:
493 | case NRF_EVT_FLASH_OPERATION_ERROR:
494 | if (m_memory_access_in_progress)
495 | {
496 | m_memory_access_in_progress = false;
497 | scan_start();
498 | }
499 | break;
500 | default:
501 | // No implementation needed.
502 | break;
503 | }
504 | }
505 |
506 |
507 | /**@brief Function for dispatching a BLE stack event to all modules with a BLE stack event handler.
508 | *
509 | * @details This function is called from the scheduler in the main loop after a BLE stack event has
510 | * been received.
511 | *
512 | * @param[in] p_ble_evt Bluetooth stack event.
513 | */
514 | static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
515 | {
516 | // dm_ble_evt_handler(p_ble_evt);
517 | // ble_db_discovery_on_ble_evt(&m_ble_db_discovery, p_ble_evt);
518 | // ble_hrs_c_on_ble_evt(&m_ble_hrs_c, p_ble_evt);
519 | // ble_bas_c_on_ble_evt(&m_ble_bas_c, p_ble_evt);
520 | on_ble_evt(p_ble_evt);
521 | }
522 |
523 |
524 | /**@brief Function for dispatching a system event to interested modules.
525 | *
526 | * @details This function is called from the System event interrupt handler after a system
527 | * event has been received.
528 | *
529 | * @param[in] sys_evt System stack event.
530 | */
531 | static void sys_evt_dispatch(uint32_t sys_evt)
532 | {
533 | pstorage_sys_event_handler(sys_evt);
534 | on_sys_evt(sys_evt);
535 | }
536 |
537 |
538 | /**@brief Function for initializing the BLE stack.
539 | *
540 | * @details Initializes the SoftDevice and the BLE event interrupt.
541 | */
542 | static void ble_stack_init(void)
543 | {
544 | uint32_t err_code;
545 |
546 | // Initialize the SoftDevice handler module.
547 | //SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, false);
548 |
549 |
550 | SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_RC_250_PPM_8000MS_CALIBRATION, false);
551 | //led_on(LED_GOT_ADV_PACKET);
552 |
553 | // Register with the SoftDevice handler module for BLE events.
554 | err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
555 | APP_ERROR_CHECK(err_code);
556 |
557 | // Register with the SoftDevice handler module for System events.
558 | err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);
559 | APP_ERROR_CHECK(err_code);
560 | }
561 |
562 |
563 | /**@brief Function for initializing the Device Manager.
564 | *
565 | * @details Device manager is initialized here.
566 | */
567 | static void device_manager_init(void)
568 | {
569 | dm_application_param_t param;
570 | dm_init_param_t init_param;
571 |
572 | uint32_t err_code;
573 |
574 | err_code = pstorage_init();
575 | APP_ERROR_CHECK(err_code);
576 |
577 | // Clear all bonded devices if user requests to.
578 | init_param.clear_persistent_data = false;
579 | //((nrf_gpio_pin_read(BOND_DELETE_ALL_BUTTON_ID) == 0)? true: false);
580 |
581 | err_code = dm_init(&init_param);
582 | APP_ERROR_CHECK(err_code);
583 |
584 | memset(¶m.sec_param, 0, sizeof (ble_gap_sec_params_t));
585 |
586 | // Event handler to be registered with the module.
587 | param.evt_handler = device_manager_event_handler;
588 |
589 | // Service or protocol context for device manager to load, store and apply on behalf of application.
590 | // Here set to client as application is a GATT client.
591 | param.service_type = DM_PROTOCOL_CNTXT_GATT_CLI_ID;
592 |
593 | // Secuirty parameters to be used for security procedures.
594 | param.sec_param.bond = SEC_PARAM_BOND;
595 | param.sec_param.mitm = SEC_PARAM_MITM;
596 | param.sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES;
597 | param.sec_param.oob = SEC_PARAM_OOB;
598 | param.sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
599 | param.sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
600 | param.sec_param.kdist_periph.enc = 1;
601 | param.sec_param.kdist_periph.id = 1;
602 |
603 | err_code = dm_register(&m_dm_app_id,¶m);
604 | APP_ERROR_CHECK(err_code);
605 | }
606 |
607 |
608 |
609 |
610 |
611 |
612 | /** @brief Function for the Power manager.
613 | */
614 | static void power_manage(void)
615 | {
616 | uint32_t err_code = sd_app_evt_wait();
617 | APP_ERROR_CHECK(err_code);
618 | }
619 |
620 |
621 | // /**@brief Heart Rate Collector Handler.
622 | // */
623 | // static void hrs_c_evt_handler(ble_hrs_c_t * p_hrs_c, ble_hrs_c_evt_t * p_hrs_c_evt)
624 | // {
625 | // bool success;
626 | // uint32_t err_code;
627 |
628 | // switch (p_hrs_c_evt->evt_type)
629 | // {
630 | // case BLE_HRS_C_EVT_DISCOVERY_COMPLETE:
631 | // // Initiate bonding.
632 | // err_code = dm_security_setup_req(&m_dm_device_handle);
633 | // APP_ERROR_CHECK(err_code);
634 |
635 | // // Heart rate service discovered. Enable notification of Heart Rate Measurement.
636 | // err_code = ble_hrs_c_hrm_notif_enable(p_hrs_c);
637 | // APP_ERROR_CHECK(err_code);
638 |
639 | // success = APPL_LCD_WRITE("Heart Rate", 10, LCD_UPPER_LINE, 0);
640 | // APP_ERROR_CHECK_BOOL(success);
641 | // break;
642 |
643 | // case BLE_HRS_C_EVT_HRM_NOTIFICATION:
644 | // {
645 | // APPL_LOG("[APPL]: HR Measurement received %d \r\n", p_hrs_c_evt->params.hrm.hr_value);
646 |
647 | // char hr_as_string[LCD_LLEN];
648 |
649 | // sprintf(hr_as_string, "Heart Rate %d", p_hrs_c_evt->params.hrm.hr_value);
650 |
651 | // success = APPL_LCD_WRITE(hr_as_string, strlen(hr_as_string), LCD_UPPER_LINE, 0);
652 | // APP_ERROR_CHECK_BOOL(success);
653 | // break;
654 | // }
655 | // default:
656 | // break;
657 | // }
658 | // }
659 |
660 |
661 | // /**@brief Battery levelCollector Handler.
662 | // */
663 | // static void bas_c_evt_handler(ble_bas_c_t * p_bas_c, ble_bas_c_evt_t * p_bas_c_evt)
664 | // {
665 | // bool success;
666 | // uint32_t err_code;
667 |
668 | // switch (p_bas_c_evt->evt_type)
669 | // {
670 | // case BLE_BAS_C_EVT_DISCOVERY_COMPLETE:
671 | // // Batttery service discovered. Enable notification of Battery Level.
672 | // APPL_LOG("[APPL]: Battery Service discovered. \r\n");
673 |
674 | // APPL_LOG("[APPL]: Reading battery level. \r\n");
675 |
676 | // err_code = ble_bas_c_bl_read(p_bas_c);
677 | // APP_ERROR_CHECK(err_code);
678 |
679 |
680 | // APPL_LOG("[APPL]: Enabling Battery Level Notification. \r\n");
681 | // err_code = ble_bas_c_bl_notif_enable(p_bas_c);
682 | // APP_ERROR_CHECK(err_code);
683 |
684 | // break;
685 |
686 | // case BLE_BAS_C_EVT_BATT_NOTIFICATION:
687 | // {
688 | // APPL_LOG("[APPL]: Battery Level received %d %%\r\n", p_bas_c_evt->params.battery_level);
689 |
690 | // char bl_as_string[LCD_LLEN];
691 |
692 | // sprintf(bl_as_string, "Battery %d %%", p_bas_c_evt->params.battery_level);
693 |
694 | // success = APPL_LCD_WRITE(bl_as_string, strlen(bl_as_string), LCD_LOWER_LINE, 0);
695 | // APP_ERROR_CHECK_BOOL(success);
696 | // break;
697 | // }
698 |
699 | // case BLE_BAS_C_EVT_BATT_READ_RESP:
700 | // {
701 | // APPL_LOG("[APPL]: Battery Level Read as %d %%\r\n", p_bas_c_evt->params.battery_level);
702 |
703 | // char bl_as_string[LCD_LLEN];
704 |
705 | // sprintf(bl_as_string, "Battery %d %%", p_bas_c_evt->params.battery_level);
706 |
707 | // success = APPL_LCD_WRITE(bl_as_string, strlen(bl_as_string), LCD_LOWER_LINE, 0);
708 | // APP_ERROR_CHECK_BOOL(success);
709 | // break;
710 | // }
711 | // default:
712 | // break;
713 | // }
714 | // }
715 |
716 |
717 | // /**
718 | // * @brief Heart rate collector initialization.
719 | // */
720 | // static void hrs_c_init(void)
721 | // {
722 | // ble_hrs_c_init_t hrs_c_init_obj;
723 |
724 | // hrs_c_init_obj.evt_handler = hrs_c_evt_handler;
725 |
726 | // uint32_t err_code = ble_hrs_c_init(&m_ble_hrs_c, &hrs_c_init_obj);
727 | // APP_ERROR_CHECK(err_code);
728 | // }
729 |
730 |
731 | // /**
732 | // * @brief Battery level collector initialization.
733 | // */
734 | // static void bas_c_init(void)
735 | // {
736 | // ble_bas_c_init_t bas_c_init_obj;
737 |
738 | // bas_c_init_obj.evt_handler = bas_c_evt_handler;
739 |
740 | // uint32_t err_code = ble_bas_c_init(&m_ble_bas_c, &bas_c_init_obj);
741 | // APP_ERROR_CHECK(err_code);
742 | // }
743 |
744 |
745 | /**
746 | * @brief Database discovery collector initialization.
747 | */
748 | static void db_discovery_init(void)
749 | {
750 | uint32_t err_code = ble_db_discovery_init();
751 | APP_ERROR_CHECK(err_code);
752 | }
753 |
754 |
755 |
756 | /**@breif Function to start scanning.
757 | */
758 | static void scan_start(void)
759 | {
760 | ble_gap_whitelist_t whitelist;
761 | ble_gap_addr_t * p_whitelist_addr[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
762 | ble_gap_irk_t * p_whitelist_irk[BLE_GAP_WHITELIST_IRK_MAX_COUNT];
763 | uint32_t err_code;
764 | uint32_t count;
765 |
766 | // Verify if there is any flash access pending, if yes delay starting scanning until
767 | // it's complete.
768 | err_code = pstorage_access_status_get(&count);
769 | APP_ERROR_CHECK(err_code);
770 |
771 | if (count != 0)
772 | {
773 | m_memory_access_in_progress = true;
774 | return;
775 | }
776 |
777 | // // Initialize whitelist parameters.
778 | // whitelist.addr_count = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
779 | // whitelist.irk_count = 0;
780 | // whitelist.pp_addrs = p_whitelist_addr;
781 | // whitelist.pp_irks = p_whitelist_irk;
782 |
783 | // // Request creating of whitelist.
784 | // err_code = dm_whitelist_create(&m_dm_app_id,&whitelist);
785 | // APP_ERROR_CHECK(err_code);
786 |
787 | // if (((whitelist.addr_count == 0) && (whitelist.irk_count == 0)) ||
788 | // (m_scan_mode != BLE_WHITELIST_SCAN))
789 | // {
790 | // No devices in whitelist, hence non selective performed.
791 | m_scan_param.active = 0; // Active scanning set.
792 | m_scan_param.selective = 0; // Selective scanning not set.
793 | m_scan_param.interval = SCAN_INTERVAL;// Scan interval.
794 | m_scan_param.window = SCAN_WINDOW; // Scan window.
795 | m_scan_param.p_whitelist = NULL; // No whitelist provided.
796 | m_scan_param.timeout = 0x0000; // No timeout.
797 | // }
798 | // else
799 | // {
800 | // // Selective scanning based on whitelist first.
801 | // m_scan_param.active = 0; // Active scanning set.
802 | // m_scan_param.selective = 1; // Selective scanning not set.
803 | // m_scan_param.interval = SCAN_INTERVAL;// Scan interval.
804 | // m_scan_param.window = SCAN_WINDOW; // Scan window.
805 | // m_scan_param.p_whitelist = &whitelist; // Provide whitelist.
806 | // m_scan_param.timeout = 0x001E; // 30 seconds timeout.
807 |
808 | // // Set whitelist scanning state.
809 | // m_scan_mode = BLE_WHITELIST_SCAN;
810 | // }
811 |
812 | err_code = sd_ble_gap_scan_start(&m_scan_param);
813 | APP_ERROR_CHECK(err_code);
814 |
815 | // bool lcd_write_status = APPL_LCD_WRITE("Scanning", 8, LCD_UPPER_LINE, 0);
816 | // if (!lcd_write_status)
817 | // {
818 | // APPL_LOG("[APPL]: LCD Write failed!\r\n");
819 | // }
820 |
821 | // nrf_gpio_pin_set(SCAN_LED_PIN_NO);
822 | }
823 |
824 | int main(void)
825 | {
826 | // Initialization of various modules.
827 | // app_trace_init();
828 | led_init(LED_GOT_ADV_PACKET);
829 |
830 | nrf_gpio_cfg_output(INTERRUPT_PIN);
831 | nrf_gpio_pin_clear(INTERRUPT_PIN);
832 |
833 |
834 |
835 | nrf_gpio_cfg_output(ADV_PIN);
836 | nrf_gpio_pin_clear(ADV_PIN);
837 |
838 | nrf_gpio_cfg_output(3);
839 | nrf_gpio_pin_clear(3);
840 |
841 | led_on(LED_GOT_ADV_PACKET);
842 |
843 |
844 | ble_stack_init();
845 |
846 | spi_slave_example_init();
847 |
848 |
849 | device_manager_init();
850 | db_discovery_init();
851 |
852 |
853 | // hrs_c_init();
854 | // bas_c_init();
855 |
856 | // Start scanning for peripherals and initiate connection
857 | // with devices that advertise Heart Rate UUID.
858 | scan_start();
859 |
860 |
861 | led_off(LED_GOT_ADV_PACKET);
862 |
863 | for (;;)
864 | {
865 | power_manage();
866 | }
867 | }
868 |
869 |
870 |
--------------------------------------------------------------------------------
/software/nrf51822/pstorage_platform.h:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
2 | *
3 | * The information contained herein is property of Nordic Semiconductor ASA.
4 | * Terms and conditions of usage are described in detail in NORDIC
5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
6 | *
7 | * Licensees are granted free, non-transferable use of the information. NO
8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
9 | * the file.
10 | *
11 | */
12 |
13 | /** @cond To make doxygen skip this file */
14 |
15 | /** @file
16 | * This header contains defines with respect persistent storage that are specific to
17 | * persistent storage implementation and application use case.
18 | */
19 | #ifndef PSTORAGE_PL_H__
20 | #define PSTORAGE_PL_H__
21 |
22 | #include
23 |
24 | #define PSTORAGE_FLASH_PAGE_SIZE ((uint16_t)NRF_FICR->CODEPAGESIZE) /**< Size of one flash page. */
25 | #define PSTORAGE_FLASH_EMPTY_MASK 0xFFFFFFFF /**< Bit mask that defines an empty address in flash. */
26 |
27 | #define PSTORAGE_FLASH_PAGE_END \
28 | ((NRF_UICR->BOOTLOADERADDR != PSTORAGE_FLASH_EMPTY_MASK) \
29 | ? (NRF_UICR->BOOTLOADERADDR / PSTORAGE_FLASH_PAGE_SIZE) \
30 | : NRF_FICR->CODESIZE)
31 |
32 |
33 | #define PSTORAGE_MAX_APPLICATIONS 1 /**< Maximum number of applications that can be registered with the module, configurable based on system requirements. */
34 | #define PSTORAGE_MIN_BLOCK_SIZE 0x0010 /**< Minimum size of block that can be registered with the module. Should be configured based on system requirements, recommendation is not have this value to be at least size of word. */
35 |
36 | #define PSTORAGE_DATA_START_ADDR ((PSTORAGE_FLASH_PAGE_END - PSTORAGE_MAX_APPLICATIONS - 1) \
37 | * PSTORAGE_FLASH_PAGE_SIZE) /**< Start address for persistent data, configurable according to system requirements. */
38 | #define PSTORAGE_DATA_END_ADDR ((PSTORAGE_FLASH_PAGE_END - 1) * PSTORAGE_FLASH_PAGE_SIZE) /**< End address for persistent data, configurable according to system requirements. */
39 | #define PSTORAGE_SWAP_ADDR PSTORAGE_DATA_END_ADDR /**< Top-most page is used as swap area for clear and update. */
40 |
41 | #define PSTORAGE_MAX_BLOCK_SIZE PSTORAGE_FLASH_PAGE_SIZE /**< Maximum size of block that can be registered with the module. Should be configured based on system requirements. And should be greater than or equal to the minimum size. */
42 | #define PSTORAGE_CMD_QUEUE_SIZE 10 /**< Maximum number of flash access commands that can be maintained by the module for all applications. Configurable. */
43 |
44 |
45 | /** Abstracts persistently memory block identifier. */
46 | typedef uint32_t pstorage_block_t;
47 |
48 | typedef struct
49 | {
50 | uint32_t module_id; /**< Module ID.*/
51 | pstorage_block_t block_id; /**< Block ID.*/
52 | } pstorage_handle_t;
53 |
54 | typedef uint16_t pstorage_size_t; /** Size of length and offset fields. */
55 |
56 | /**@brief Handles Flash Access Result Events. To be called in the system event dispatcher of the application. */
57 | void pstorage_sys_event_handler (uint32_t sys_evt);
58 |
59 | #endif // PSTORAGE_PL_H__
60 |
61 | /** @} */
62 | /** @endcond */
63 |
--------------------------------------------------------------------------------
/software/utility/eepromflasher.c:
--------------------------------------------------------------------------------
1 | // MODIFIED BY Lab11, Neal Jackson
2 | // Copyright (C) 2012 - Cabin Programs, Ken Keller
3 | //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of
5 | // this software and associated documentation files (the "Software"), to deal in
6 | // the Software without restriction, including without limitation the rights to
7 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8 | // of the Software, and to permit persons to whom the Software is furnished to do
9 | // so, subject to the following conditions:
10 | //
11 | // The above copyright notice and this permission notice shall be included in all
12 | // copies or substantial portions of the Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | // SOFTWARE.
21 | //
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | #ifndef FALSE
30 | #define FALSE (0)
31 | #define TRUE (!(FALSE))
32 | #endif
33 |
34 | #define sizeEEPROM 244
35 | unsigned char eeprom[sizeEEPROM+100]; // Give a little extra for no good reason
36 |
37 |
38 |
39 | int eepromIndex[2][46] = {
40 | { -1, -1, 140, 142, 132, 134, 170, 176, 172, 174, 146, 144, 118, 120,
41 | 150, 148, 122, 168, 116, 166, 164, 138, 136, 130, 128, 162, 202, 206,
42 | 204, 208, 102, 104, 100, 200, 98, 198, 194, 196, 190, 192, 186, 188,
43 | 182, 184, 178, 180 },
44 | { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 124, 160, 126, 156, 152, 158,
45 | 94, 92, 106, 108, 90, 88, 154, 112, 220, 110, 216, 214, 210, 212, 218,
46 | -1, 230, -1, 234, 232, 226, 228, 222, 224, 114, 96, -1, -1, -1, -1 }
47 | };
48 |
49 | int main(int argc, char* argv[])
50 | {
51 | int currentnum, strnum;
52 | const int numPin = 23;
53 | char keypressed;
54 | char buffer[100];
55 | int index;
56 |
57 | printf("\n\n---GAP EEPROM MAKER---\n\nThis is a program to make the EEPROM data file for the GAP BeagleBone Cape.\n");
58 | printf("\nThis program produces an output file named: data.eeprom\n");
59 | printf("The data file follows EEPROM Format Revision 'A0'\n");
60 | printf("This data file can be put in the BeagleBone EEPROM by this command on a BeagleBone:\n");
61 | printf(" > cat data.eeprom > /sys/bus/i2c/devices/1-005x/eeprom\n");
62 | printf(" Where: 5x is 54, 55, 56, 57 depending on Cape addressing.\n");
63 | printf(" The default for the Zigbeag is 57.\n");
64 | printf("\n+++ No warranties or support is implied\n\n");
65 |
66 | for(index=0; index32) strnum=32;
79 | for(index=0; index4) strnum=4;
85 | for(index=0; index16) strnum=16;
91 | for(index=0; index16) strnum=16;
97 | for(index=0; index12) strnum=12;
104 | for(index=0; index>8;
110 | eeprom[237]=currentnum & 0xff;
111 |
112 | //MAX Current (mA) on VDD_5V Used by Cape (Range 0 to 1000mA):
113 | currentnum = 0;
114 | eeprom[238]=currentnum>>8;
115 | eeprom[239]=currentnum & 0xff;
116 |
117 | //MAX Current (mA) on SYS_5V Used by Cape (Range 0 to 250mA):
118 | currentnum = 0;
119 | eeprom[240]=currentnum>>8;
120 | eeprom[241]=currentnum & 0xff;
121 |
122 | //Current (mA) Supplied on VDD_5V by Cape (Range 0 to 65535mA):
123 | currentnum = 0;
124 | eeprom[242]=currentnum>>8;
125 | eeprom[243]=currentnum & 0xff;
126 |
127 |
128 | //Number of Pins Used by Cape (Range 0 to 74):
129 | eeprom[75]=numPin;
130 |
131 | int connector[23] = {9,9,9,9,9,9,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8};
132 | int pin[23] = {14,23,27,12,15,11,16,24,26,17,18,21,22,15,13,16,26,14,11,12,19,17,18};
133 | unsigned char upper[23] = {0xa0,0xa0,0xa0,0xc0,0xa0,0xa0,0xa0,0xa0,0xc0,0xa0,0xc0,0xa0,0xc0,0xa0,0xc0,0xc0,0xa0,0xa0,0xc0,0xc0,0xc0,0xc0,0xc0};
134 | unsigned char lower[23] = {0x2f,0x2f,0x2f,0x17,0x2f,0x2f,0x2f,0x2f,0x17,0x2f,0x17,0x2f,0x20,0x20,0x10,0x10,0x30,0x17,0x17,0x17,0x17,0x17};
135 | int i;
136 | for(i=0; i < numPin; ++i){
137 | eeprom[eepromIndex[connector[i]-8][pin[i]-1]] = upper[i];
138 | eeprom[eepromIndex[connector[i]-8][pin[i]-1]+1] = lower[i];
139 | }
140 |
141 | // write data to file
142 | printf("\nCreating output file... ./data.eeprom\n\n");
143 | char *file = "data.eeprom";
144 | FILE *p = NULL;
145 | p = fopen(file, "w");
146 | if (p== NULL) {
147 | printf("Error in opening a file..", file);
148 | return(1);
149 | }
150 | fwrite(eeprom, sizeEEPROM, 1, p);
151 | fclose(p);
152 |
153 | return 0;
154 | }
155 |
156 |
--------------------------------------------------------------------------------