This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to debug nRF52840 and nRF9160 designs on Thingy:91 board

Hi guys!

I am witnessing the things are evolving pretty fast around Thingy:91! What was up-to-date and actual yesterday is outdated today! That's why I would like to ask some fresh questions about some things...

  1. We were recently forced to move from 1.1.0 tag to master branch because we wanted to benefit from cloud_client example and connection with AWS IoT Cloud. In that master branch, we were unfortunately unable to debug our nRF9160/nRF52840 designs from Segger Embedded Studio, according to this thread. I see that there is a tag 1.2.0 available now. Is it possible to debug with SES from tag 1.2.0or from master?
  2. How can we keep nRF52840 as a nRF9160 controller/debugger and add some BLE functionality over that usb_uart_bridge? I can see some threads discussing about that(e.g. here) but I am unable to benefit from them because we are now in master branch and it's impossible to apply fixes and patches suggested for 1.1.0 tag. It is too bad that nRF52840 is used only as nRF9160 controller with so much troubles and efforts needed to add some basic BLE functionality.
  3. We need only to read advertisement messages from some Bluetooth beacons with known UUIDs. Can you reference me to some similar example?

Thanks in advance for your time and efforts!

Sincerely,

Bojan.

Parents Reply Children
  • Hello, .

    Thanks for pointing out this sample for me! I tried the sample and it behaves as expected on v1.2.0tag - I am able to debug nRF9160 code from LTE Monitor app.

    However, to the best of my understanding, BLE NUS Service offered in the sample can be implemented only in BLE peripheral devices. What we need is to act as a BLE central device, to scan the area looking for the BLE beacon with the fixed UUID, read data advertised by BLE beacon and transfer them to nRF9160. For that purpose, we would need BLE NUS Client implemented.

    Am I correct when thinking that we can not use connectivity_bridge sample for BLE central devices?

    IMHO, the easiest way to implement what we need is to keep default connection between nRF9160 and nRF52840 (made of &uart0 and &uart1), to use &uart0 for debugging and &uart1 for data transfer between nRF9160 and nRF52840. In addition to that default hardware connection, I would need BLE stack (called SoftDevice in SDK 16.0 environment) for BLE scanning and reading advertised packages. Moreover, that BLE-related task should co-exist with the usb_uart_bridge task in the code for nRF52840. I tried to simply merge usb_uart_bridge and central_uart samples similar way  did in his hci_uart_with_usb_uart_bridge project (here attached you have a main.c file). The code compiles successfully but I am unfortunately unable to see PCA20035 device from LTE Monitor app. I guess this is due to some bad settings. Do you have any idea what I am missing here? Is the approach I described above OK for you or you have some better suggestion for me?

    Thank  you very much for your time and efforts, guys!

    Sincerely,

    Bojan.

    /*
     * Copyright (c) 2019 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
     */
    
    #include <zephyr.h>
    #include <device.h>
    #include <drivers/uart.h>
    #include <nrfx.h>
    #include <string.h>
    #include <hal/nrf_power.h>
    #include <power/reboot.h>
    #include <usb/usb_device.h>
    
    /* Overriding weak function to set iSerial runtime. */
    u8_t *usb_update_sn_string_descriptor(void)
    {
    	static u8_t buf[] = "PCA20035_12PLACEHLDRS";
    
    	snprintk(&buf[9], 13, "%04X%08X",
    		(uint32_t)(NRF_FICR->DEVICEADDR[1] & 0x0000FFFF)|0x0000C000,
    		(uint32_t)NRF_FICR->DEVICEADDR[0]);
    
    	return (u8_t *)&buf;
    }
    
    #define POWER_THREAD_STACKSIZE		CONFIG_IDLE_STACK_SIZE
    #define POWER_THREAD_PRIORITY		K_LOWEST_APPLICATION_THREAD_PRIO
    
    /* Heap block space is always one of 2^(2n) for n from 3 to 7.
     * (see reference/kernel/memory/heap.html for more info)
     * Here, we target 64-byte blocks. Since we want to fit one struct uart_data
     * into each block, the block layout becomes:
     * 16 bytes: reserved by the Zephyr heap block descriptor (not in struct)
     *  4 bytes: reserved by the Zephyr FIFO (in struct)
     * 40 bytes: UART data buffer (in struct)
     *  4 bytes: length field (in struct, padded for alignment)
     */
    #define UART_BUF_SIZE 40
    
    static K_FIFO_DEFINE(usb_0_tx_fifo);
    static K_FIFO_DEFINE(usb_1_tx_fifo);
    static K_FIFO_DEFINE(uart_0_tx_fifo);
    static K_FIFO_DEFINE(uart_1_tx_fifo);
    
    struct uart_data {
    	void *fifo_reserved;
    	u8_t buffer[UART_BUF_SIZE];
    	u16_t len;
    };
    
    static struct serial_dev {
    	struct device *dev;
    	void *peer;
    	struct k_fifo *fifo;
    	struct k_sem sem;
    	struct uart_data *rx;
    } devs[4];
    
    /* Frees data for incoming transmission on device blocked by full heap. */
    static int oom_free(struct serial_dev *sd)
    {
    	struct serial_dev *peer_sd = (struct serial_dev *)sd->peer;
    	struct uart_data *buf;
    
    	/* First, try to free from FIFO of peer device (blocked stream) */
    	buf = k_fifo_get(peer_sd->fifo, K_NO_WAIT);
    	if (buf) {
    		k_free(buf);
    		return 0;
    	}
    
    	/* Then, try FIFO of the receiving device (reverse of blocked stream) */
    	buf = k_fifo_get(sd->fifo, K_NO_WAIT);
    	if (buf) {
    		k_free(buf);
    		return 0;
    	}
    
    	/* Finally, try all of them */
    	for (int i = 0; i < ARRAY_SIZE(devs); i++) {
    		buf = k_fifo_get(sd->fifo, K_NO_WAIT);
    		if (buf) {
    			k_free(buf);
    			return 0;
    		}
    	}
    
    	return -1; /* Was not able to free any heap memory */
    }
    
    static void uart_interrupt_handler(void *user_data)
    {
    	struct serial_dev *sd = user_data;
    	struct device *dev = sd->dev;
    	struct serial_dev *peer_sd = (struct serial_dev *)sd->peer;
    
    	uart_irq_update(dev);
    
    	while (uart_irq_rx_ready(dev)) {
    		int data_length;
    
    		while (!sd->rx) {
    			sd->rx = k_malloc(sizeof(*sd->rx));
    			if (sd->rx) {
    				sd->rx->len = 0;
    			} else {
    				int err = oom_free(sd);
    
    				if (err) {
    					printk("Could not free memory. Rebooting.\n");
    					sys_reboot(SYS_REBOOT_COLD);
    				}
    			}
    		}
    
    		data_length = uart_fifo_read(dev, &sd->rx->buffer[sd->rx->len],
    					   UART_BUF_SIZE - sd->rx->len);
    		sd->rx->len += data_length;
    
    		if (sd->rx->len > 0) {
    			if ((sd->rx->len == UART_BUF_SIZE) ||
    			   (sd->rx->buffer[sd->rx->len - 1] == '\n') ||
    			   (sd->rx->buffer[sd->rx->len - 1] == '\r') ||
    			   (sd->rx->buffer[sd->rx->len - 1] == '\0')) {
    				k_fifo_put(peer_sd->fifo, sd->rx);
    				k_sem_give(&peer_sd->sem);
    
    				sd->rx = NULL;
    			}
    		}
    	}
    
    	if (uart_irq_tx_ready(dev)) {
    		struct uart_data *buf = k_fifo_get(sd->fifo, K_NO_WAIT);
    		u16_t written = 0;
    
    		/* Nothing in the FIFO, nothing to send */
    		if (!buf) {
    			uart_irq_tx_disable(dev);
    			return;
    		}
    
    		while (buf->len > written) {
    			written += uart_fifo_fill(dev,
    						  &buf->buffer[written],
    						  buf->len - written);
    		}
    
    		while (!uart_irq_tx_complete(dev)) {
    			/* Wait for the last byte to get
    			 * shifted out of the module
    			 */
    		}
    
    		if (k_fifo_is_empty(sd->fifo)) {
    			uart_irq_tx_disable(dev);
    		}
    
    		k_free(buf);
    	}
    }
    
    void power_thread(void)
    {
    	while (1) {
    		if (!nrf_power_usbregstatus_vbusdet_get(NRF_POWER)) {
    			nrf_power_system_off(NRF_POWER);
    		}
    		k_sleep(100);
    	}
    }
    
    void main(void)
    {
    	int ret;
    	struct serial_dev *usb_0_sd = &devs[0];
    	struct serial_dev *usb_1_sd = &devs[1];
    	struct serial_dev *uart_0_sd = &devs[2];
    	struct serial_dev *uart_1_sd = &devs[3];
    	struct device *usb_0_dev, *usb_1_dev, *uart_0_dev, *uart_1_dev;
    
    	usb_0_dev = device_get_binding("CDC_ACM_0");
    	if (!usb_0_dev) {
    		printk("CDC ACM device not found\n");
    		return;
    	}
    
    	usb_1_dev = device_get_binding("CDC_ACM_1");
    	if (!usb_1_dev) {
    		printk("CDC ACM device not found\n");
    		return;
    	}
    
    	uart_0_dev = device_get_binding("UART_0");
    	if (!uart_0_dev) {
    		printk("UART 0 init failed\n");
    	}
    
    	uart_1_dev = device_get_binding("UART_1");
    	if (!uart_1_dev) {
    		printk("UART 1 init failed\n");
    	}
    
    	usb_0_sd->dev = usb_0_dev;
    	usb_0_sd->fifo = &usb_0_tx_fifo;
    	usb_0_sd->peer = uart_0_sd;
    
    	usb_1_sd->dev = usb_1_dev;
    	usb_1_sd->fifo = &usb_1_tx_fifo;
    	usb_1_sd->peer = uart_1_sd;
    
    	uart_0_sd->dev = uart_0_dev;
    	uart_0_sd->fifo = &uart_0_tx_fifo;
    	uart_0_sd->peer = usb_0_sd;
    
    	uart_1_sd->dev = uart_1_dev;
    	uart_1_sd->fifo = &uart_1_tx_fifo;
    	uart_1_sd->peer = usb_1_sd;
    
    	k_sem_init(&usb_0_sd->sem, 0, 1);
    	k_sem_init(&usb_1_sd->sem, 0, 1);
    	k_sem_init(&uart_0_sd->sem, 0, 1);
    	k_sem_init(&uart_1_sd->sem, 0, 1);
    
    	uart_irq_callback_user_data_set(usb_0_dev, uart_interrupt_handler,
    		usb_0_sd);
    	uart_irq_callback_user_data_set(usb_1_dev, uart_interrupt_handler,
    		usb_1_sd);
    	uart_irq_callback_user_data_set(uart_0_dev, uart_interrupt_handler,
    		uart_0_sd);
    	uart_irq_callback_user_data_set(uart_1_dev, uart_interrupt_handler,
    		uart_1_sd);
    
    	ret = usb_enable(NULL);
    	if (ret != 0) {
    		printk("Failed to enable USB\n");
    		return;
    	}
    
    	uart_irq_rx_enable(usb_0_dev);
    	uart_irq_rx_enable(usb_1_dev);
    	uart_irq_rx_enable(uart_0_dev);
    	uart_irq_rx_enable(uart_1_dev);
    
    	printk("USB <--> UART bridge is now initialized\n");
    
    	struct k_poll_event events[4] = {
    		K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
    						K_POLL_MODE_NOTIFY_ONLY,
    						&usb_0_sd->sem, 0),
    		K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
    						K_POLL_MODE_NOTIFY_ONLY,
    						&usb_1_sd->sem, 0),
    		K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
    						K_POLL_MODE_NOTIFY_ONLY,
    						&uart_0_sd->sem, 0),
    		K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
    						K_POLL_MODE_NOTIFY_ONLY,
    						&uart_1_sd->sem, 0),
    	};
    
    	while (1) {
    		ret = k_poll(events, ARRAY_SIZE(events), K_FOREVER);
    		if (ret != 0) {
    			continue;
    		}
    
    		if (events[0].state == K_POLL_TYPE_SEM_AVAILABLE) {
    			events[0].state = K_POLL_STATE_NOT_READY;
    			k_sem_take(&usb_0_sd->sem, K_NO_WAIT);
    			uart_irq_tx_enable(usb_0_dev);
    		} else if (events[1].state == K_POLL_TYPE_SEM_AVAILABLE) {
    			events[1].state = K_POLL_STATE_NOT_READY;
    			k_sem_take(&usb_1_sd->sem, K_NO_WAIT);
    			uart_irq_tx_enable(usb_1_dev);
    		} else if (events[2].state == K_POLL_TYPE_SEM_AVAILABLE) {
    			events[2].state = K_POLL_STATE_NOT_READY;
    			k_sem_take(&uart_0_sd->sem, K_NO_WAIT);
    			uart_irq_tx_enable(uart_0_dev);
    		} else if (events[3].state == K_POLL_TYPE_SEM_AVAILABLE) {
    			events[3].state = K_POLL_STATE_NOT_READY;
    			k_sem_take(&uart_1_sd->sem, K_NO_WAIT);
    			uart_irq_tx_enable(uart_1_dev);
    		}
    	}
    }
    
    K_THREAD_DEFINE(power_thread_id, POWER_THREAD_STACKSIZE, power_thread,
    		NULL, NULL, NULL, POWER_THREAD_PRIORITY, 0, K_NO_WAIT);
    
    
    
    
    #if 0
    
    /*
     * Copyright (c) 2018 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
     */
    
    /** @file
     *  @brief Nordic UART Service Client sample
     */
    
    #include <errno.h>
    #include <zephyr.h>
    #include <sys/byteorder.h>
    #include <sys/printk.h>
    
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/hci.h>
    #include <bluetooth/conn.h>
    #include <bluetooth/uuid.h>
    #include <bluetooth/gatt.h>
    
    #include <bluetooth/services/nus.h>
    #include <bluetooth/services/nus_c.h>
    #include <bluetooth/gatt_dm.h>
    #include <bluetooth/scan.h>
    
    #include <settings/settings.h>
    
    #include <drivers/uart.h>
    
    
    #include <stddef.h>
    #include <stdio.h>
    #include <string.h>
    
    #include <arch/cpu.h>
    #include <logging/log.h>
    #include <sys/util.h>
    #include <device.h>
    #include <init.h>
    #include <net/buf.h>
    #include <bluetooth/l2cap.h>
    #include <bluetooth/hci.h>
    #include <bluetooth/buf.h>
    #include <bluetooth/hci_raw.h>
    #include <nrfx.h>
    #include <hal/nrf_power.h>
    #include <power/reboot.h>
    
    
    /* UART payload buffer element size. */
    #define UART_BUF_SIZE 40
    
    #define KEY_PASSKEY_ACCEPT DK_BTN1_MSK
    #define KEY_PASSKEY_REJECT DK_BTN2_MSK
    
    #define NUS_WRITE_TIMEOUT 150
    
    static struct device *uart;
    static bool rx_disabled;
    
    K_SEM_DEFINE(nus_write_sem, 0, 1);
    
    struct uart_data_t {
    	void *fifo_reserved;
    	u8_t  data[UART_BUF_SIZE];
    	u16_t len;
    };
    
    static K_FIFO_DEFINE(fifo_uart_tx_data);
    static K_FIFO_DEFINE(fifo_uart_rx_data);
    
    static struct bt_conn *default_conn;
    static struct bt_gatt_nus_c gatt_nus_c;
    
    static void ble_data_sent(u8_t err, const u8_t *const data, u16_t len)
    {
    	struct uart_data_t *buf;
    
    	/* Retrieve buffer context. */
    	buf = CONTAINER_OF(data, struct uart_data_t, data);
    	k_free(buf);
    
    	if (rx_disabled) {
    		rx_disabled = false;
    		uart_irq_rx_enable(uart);
    	}
    
    	k_sem_give(&nus_write_sem);
    
    	if (err) {
    		printk("ATT error code: 0x%02X\n", err);
    	}
    }
    
    static u8_t ble_data_received(const u8_t *const data, u16_t len)
    {
    	for (u16_t pos = 0; pos != len;) {
    		struct uart_data_t *tx = k_malloc(sizeof(*tx));
    
    		if (!tx) {
    			printk("Not able to allocate UART send data buffer\n");
    			return BT_GATT_ITER_CONTINUE;
    		}
    
    		/* Keep the last byte of TX buffer for potential LF char. */
    		size_t tx_data_size = sizeof(tx->data) - 1;
    
    		if ((len - pos) > tx_data_size) {
    			tx->len = tx_data_size;
    		} else {
    			tx->len = (len - pos);
    		}
    
    		memcpy(tx->data, &data[pos], tx->len);
    
    		pos += tx->len;
    
    		/* Append the LF character when the CR character triggered
    		 * transmission from the peer.
    		 */
    		if ((pos == len) && (data[len - 1] == '\r')) {
    			tx->data[tx->len] = '\n';
    			tx->len++;
    		}
    
    		k_fifo_put(&fifo_uart_tx_data, tx);
    	}
    
    	/* Start the UART transfer by enabling the TX ready interrupt */
    	uart_irq_tx_enable(uart);
    
    	return BT_GATT_ITER_CONTINUE;
    }
    
    static void uart_cb(struct device *uart)
    {
    	static struct uart_data_t *rx;
    
    	uart_irq_update(uart);
    
    	if (uart_irq_rx_ready(uart)) {
    		int data_length;
    
    		if (!rx) {
    			rx = k_malloc(sizeof(*rx));
    			if (rx) {
    				rx->len = 0;
    			} else {
    				/* Disable UART interface, it will be
    				 * enable again after releasing the buffer.
    				 */
    				uart_irq_rx_disable(uart);
    				rx_disabled = true;
    
    				printk("Not able to allocate UART receive buffer\n");
    
    				return;
    			}
    		}
    
    		data_length = uart_fifo_read(uart, &rx->data[rx->len],
    					     UART_BUF_SIZE - rx->len);
    		rx->len += data_length;
    
    		if (rx->len > 0) {
    			/* Send buffer to Bluetooth unit if either buffer size
    			 * is reached or the char \n or \r is received, which
    			 * ever comes first
    			 */
    			if ((rx->len == UART_BUF_SIZE) ||
    			   (rx->data[rx->len - 1] == '\n') ||
    			   (rx->data[rx->len - 1] == '\r')) {
    				k_fifo_put(&fifo_uart_rx_data, rx);
    				rx = NULL;
    			}
    		}
    	}
    
    	if (uart_irq_tx_ready(uart)) {
    		struct uart_data_t *buf =
    			k_fifo_get(&fifo_uart_tx_data, K_NO_WAIT);
    		u16_t written = 0;
    
    		/* Nothing in the FIFO, nothing to send */
    		if (!buf) {
    			uart_irq_tx_disable(uart);
    			return;
    		}
    
    		while (buf->len > written) {
    			written += uart_fifo_fill(uart,
    						  &buf->data[written],
    						  buf->len - written);
    		}
    
    		while (!uart_irq_tx_complete(uart)) {
    			/* Wait for the last byte to get
    			 * shifted out of the module
    			 */
    		}
    
    		if (k_fifo_is_empty(&fifo_uart_tx_data)) {
    			uart_irq_tx_disable(uart);
    		}
    
    		k_free(buf);
    	}
    }
    
    static void discovery_complete(struct bt_gatt_dm *dm,
    			       void *context)
    {
    	struct bt_gatt_nus_c *nus_c = context;
    	printk("Service discovery completed\n");
    
    	bt_gatt_dm_data_print(dm);
    
    	bt_gatt_nus_c_handles_assign(dm, nus_c);
    	bt_gatt_nus_c_tx_notif_enable(nus_c);
    
    	bt_gatt_dm_data_release(dm);
    }
    
    static void discovery_service_not_found(struct bt_conn *conn,
    					void *context)
    {
    	printk("Service not found\n");
    }
    
    static void discovery_error(struct bt_conn *conn,
    			    int err,
    			    void *context)
    {
    	printk("Error while discovering GATT database: (%d)\n", err);
    }
    
    struct bt_gatt_dm_cb discovery_cb = {
    	.completed         = discovery_complete,
    	.service_not_found = discovery_service_not_found,
    	.error_found       = discovery_error,
    };
    
    static void gatt_discover(struct bt_conn *conn)
    {
    	int err;
    
    	if (conn != default_conn) {
    		return;
    	}
    
    	err = bt_gatt_dm_start(conn,
    			       BT_UUID_NUS_SERVICE,
    			       &discovery_cb,
    			       &gatt_nus_c);
    	if (err) {
    		printk("could not start the discovery procedure, error "
    			"code: %d\n", err);
    	}
    }
    
    static void connected(struct bt_conn *conn, u8_t conn_err)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    	int err;
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	if (conn_err) {
    		printk("Failed to connect to %s (%d)\n", addr, conn_err);
    		return;
    	}
    
    	printk("Connected: %s\n", addr);
    
    	err = bt_conn_set_security(conn, BT_SECURITY_L2);
    	if (err) {
    		printk("Failed to set security: %d\n", err);
    
    		gatt_discover(conn);
    	}
    
    	err = bt_scan_stop();
    	if ((!err) && (err != -EALREADY)) {
    		printk("Stop LE scan failed (err %d)\n", err);
    	}
    }
    
    static void disconnected(struct bt_conn *conn, u8_t reason)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    	int err;
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	printk("Disconnected: %s (reason %u)\n", addr, reason);
    
    	if (default_conn != conn) {
    		return;
    	}
    
    	bt_conn_unref(default_conn);
    	default_conn = NULL;
    
    	err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
    	if (err) {
    		printk("Scanning failed to start (err %d)\n", err);
    	}
    }
    
    static void security_changed(struct bt_conn *conn, bt_security_t level,
    			     enum bt_security_err err)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	if (!err) {
    		printk("Security changed: %s level %u\n", addr, level);
    	} else {
    		printk("Security failed: %s level %u err %d\n", addr, level,
    			err);
    	}
    
    	gatt_discover(conn);
    }
    
    static struct bt_conn_cb conn_callbacks = {
    	.connected = connected,
    	.disconnected = disconnected,
    	.security_changed = security_changed
    };
    
    static void scan_filter_match(struct bt_scan_device_info *device_info,
    			      struct bt_scan_filter_match *filter_match,
    			      bool connectable)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(device_info->addr, addr, sizeof(addr));
    
    	printk("Filters matched. Address: %s connectable: %d\n",
    		addr, connectable);
    }
    
    static void scan_connecting_error(struct bt_scan_device_info *device_info)
    {
    	printk("Connecting failed\n");
    }
    
    static void scan_connecting(struct bt_scan_device_info *device_info,
    			    struct bt_conn *conn)
    {
    	default_conn = bt_conn_ref(conn);
    }
    
    static int uart_init(void)
    {
    	uart = device_get_binding(DT_UART_0_NAME);
    	if (!uart) {
    		printk("UART binding failed\n");
    		return -ENXIO;
    	}
    
    	uart_irq_callback_set(uart, uart_cb);
    	uart_irq_rx_enable(uart);
    
    	printk("UART initialized\n");
    	return 0;
    }
    
    static int nus_client_init(void)
    {
    	int err;
    	struct bt_gatt_nus_c_init_param nus_c_init_obj = {
    		.cbs = {
    			.data_received = ble_data_received,
    			.data_sent = ble_data_sent,
    		}
    	};
    
    	err = bt_gatt_nus_c_init(&gatt_nus_c, &nus_c_init_obj);
    	if (err) {
    		printk("NUS Client initialization failed (err %d)\n", err);
    		return err;
    	}
    
    	printk("NUS Client module initialized\n");
    	return err;
    }
    
    BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL,
    		scan_connecting_error, scan_connecting);
    
    static int scan_init(void)
    {
    	int err;
    	struct bt_scan_init_param scan_init = {
    		.connect_if_match = 1,
    	};
    
    	bt_scan_init(&scan_init);
    	bt_scan_cb_register(&scan_cb);
    
    	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_UUID, BT_UUID_NUS_SERVICE);
    	if (err) {
    		printk("Scanning filters cannot be set (err %d)\n", err);
    		return err;
    	}
    
    	err = bt_scan_filter_enable(BT_SCAN_UUID_FILTER, false);
    	if (err) {
    		printk("Filters cannot be turned on (err %d)\n", err);
    		return err;
    	}
    
    	printk("Scan module initialized\n");
    	return err;
    }
    
    
    static void auth_cancel(struct bt_conn *conn)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	printk("Pairing cancelled: %s\n", addr);
    }
    
    
    static void pairing_confirm(struct bt_conn *conn)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	bt_conn_auth_pairing_confirm(conn);
    
    	printk("Pairing confirmed: %s\n", addr);
    }
    
    
    static void pairing_complete(struct bt_conn *conn, bool bonded)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	printk("Pairing completed: %s, bonded: %d\n", addr, bonded);
    }
    
    
    static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	printk("Pairing failed conn: %s, reason %d\n", addr, reason);
    }
    
    static struct bt_conn_auth_cb conn_auth_callbacks = {
    	.cancel = auth_cancel,
    	.pairing_confirm = pairing_confirm,
    	.pairing_complete = pairing_complete,
    	.pairing_failed = pairing_failed
    };
    
    //Start
    /* Overriding weak function to set iSerial runtime. */
    u8_t *usb_update_sn_string_descriptor(void)
    {
    	static u8_t buf[] = "PCA20035_12PLACEHLDRS";
    
    	snprintk(&buf[9], 13, "%04X%08X",
    		(uint32_t)(NRF_FICR->DEVICEADDR[1] & 0x0000FFFF)|0x0000C000,
    		(uint32_t)NRF_FICR->DEVICEADDR[0]);
    
    	return (u8_t *)&buf;
    }
    
    
    /* Heap block space is always one of 2^(2n) for n from 3 to 7.
     * (see reference/kernel/memory/heap.html for more info)
     * Here, we target 64-byte blocks. Since we want to fit one struct uart_data
     * into each block, the block layout becomes:
     * 16 bytes: reserved by the Zephyr heap block descriptor (not in struct)
     *  4 bytes: reserved by the Zephyr FIFO (in struct)
     * 40 bytes: UART data buffer (in struct)
     *  4 bytes: length field (in struct, padded for alignment)
     */
    #define UART_BUF_SIZE 40
    
    static K_FIFO_DEFINE(usb_0_tx_fifo);
    
    static K_FIFO_DEFINE(uart_0_tx_fifo);
    
    
    struct uart_data {
    	void *fifo_reserved;
    	u8_t buffer[UART_BUF_SIZE];
    	u16_t len;
    };
    
    static struct serial_dev {
    	struct device *dev;
    	void *peer;
    	struct k_fifo *fifo;
    	struct k_sem sem;
    	struct uart_data *rx;
    } devs[2];
    
    /* Frees data for incoming transmission on device blocked by full heap. */
    static int oom_free(struct serial_dev *sd)
    {
    	struct serial_dev *peer_sd = (struct serial_dev *)sd->peer;
    	struct uart_data *buf;
    
    	/* First, try to free from FIFO of peer device (blocked stream) */
    	buf = k_fifo_get(peer_sd->fifo, K_NO_WAIT);
    	if (buf) {
    		k_free(buf);
    		return 0;
    	}
    
    	/* Then, try FIFO of the receiving device (reverse of blocked stream) */
    	buf = k_fifo_get(sd->fifo, K_NO_WAIT);
    	if (buf) {
    		k_free(buf);
    		return 0;
    	}
    
    	/* Finally, try all of them */
    	for (int i = 0; i < ARRAY_SIZE(devs); i++) {
    		buf = k_fifo_get(sd->fifo, K_NO_WAIT);
    		if (buf) {
    			k_free(buf);
    			return 0;
    		}
    	}
    
    	return -1; /* Was not able to free any heap memory */
    }
    
    static void uart_interrupt_handler(void *user_data)
    {
    	struct serial_dev *sd = user_data;
    	struct device *dev = sd->dev;
    	struct serial_dev *peer_sd = (struct serial_dev *)sd->peer;
    
    	uart_irq_update(dev);
    
    	while (uart_irq_rx_ready(dev)) {
    		int data_length;
    
    		while (!sd->rx) {
    			sd->rx = k_malloc(sizeof(*sd->rx));
    			if (sd->rx) {
    				sd->rx->len = 0;
    			} else {
    				int err = oom_free(sd);
    
    				if (err) {
    					printk("Could not free memory. Rebooting.\n");
    					sys_reboot(SYS_REBOOT_COLD);
    				}
    			}
    		}
    
    		data_length = uart_fifo_read(dev, &sd->rx->buffer[sd->rx->len],
    					   UART_BUF_SIZE - sd->rx->len);
    		sd->rx->len += data_length;
    
    		if (sd->rx->len > 0) {
    			if ((sd->rx->len == UART_BUF_SIZE) ||
    			   (sd->rx->buffer[sd->rx->len - 1] == '\n') ||
    			   (sd->rx->buffer[sd->rx->len - 1] == '\r') ||
    			   (sd->rx->buffer[sd->rx->len - 1] == '\0')) {
    				k_fifo_put(peer_sd->fifo, sd->rx);
    				k_sem_give(&peer_sd->sem);
    
    				sd->rx = NULL;
    			}
    		}
    	}
    
    	if (uart_irq_tx_ready(dev)) {
    		struct uart_data *buf = k_fifo_get(sd->fifo, K_NO_WAIT);
    		u16_t written = 0;
    
    		/* Nothing in the FIFO, nothing to send */
    		if (!buf) {
    			uart_irq_tx_disable(dev);
    			return;
    		}
    
    		while (buf->len > written) {
    			written += uart_fifo_fill(dev,
    						  &buf->buffer[written],
    						  buf->len - written);
    		}
    
    		while (!uart_irq_tx_complete(dev)) {
    			/* Wait for the last byte to get
    			 * shifted out of the module
    			 */
    		}
    
    		if (k_fifo_is_empty(sd->fifo)) {
    			uart_irq_tx_disable(dev);
    		}
    
    		k_free(buf);
    	}
    }
    
    void usb_uart_thread(void)
    {
    	int ret;
    	struct serial_dev *usb_0_sd = &devs[0];
    
    	struct serial_dev *uart_0_sd = &devs[1];
    
    	struct device *usb_0_dev, *uart_0_dev;
    
    	usb_0_dev = device_get_binding("CDC_ACM_0");
    	if (!usb_0_dev) {
    		printk("CDC ACM device not found\n");
    		return;
    	}
    
    	uart_0_dev = device_get_binding("UART_0");
    	if (!uart_0_dev) {
    		printk("UART 0 init failed\n");
    	}
    
    	usb_0_sd->dev = usb_0_dev;
    	usb_0_sd->fifo = &usb_0_tx_fifo;
    	usb_0_sd->peer = uart_0_sd;
    
    	uart_0_sd->dev = uart_0_dev;
    	uart_0_sd->fifo = &uart_0_tx_fifo;
    	uart_0_sd->peer = usb_0_sd;
    
    
    	k_sem_init(&usb_0_sd->sem, 0, 1);
    
    	k_sem_init(&uart_0_sd->sem, 0, 1);
    
    
    	uart_irq_callback_user_data_set(usb_0_dev, uart_interrupt_handler,
    		usb_0_sd);
    
    	uart_irq_callback_user_data_set(uart_0_dev, uart_interrupt_handler,
    		uart_0_sd);
    
    
    	uart_irq_rx_enable(usb_0_dev);
    
    	uart_irq_rx_enable(uart_0_dev);
    
    
    	printk("USB <--> UART bridge is now initialized\n");
    
    	struct k_poll_event events[2] = {
    		K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
    						K_POLL_MODE_NOTIFY_ONLY,
    						&usb_0_sd->sem, 0),
    		K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
    						K_POLL_MODE_NOTIFY_ONLY,
    						&uart_0_sd->sem, 0),
    	};
    
    	while (1) {
    		ret = k_poll(events, ARRAY_SIZE(events), K_FOREVER);
    		if (ret != 0) {
    			continue;
    		}
    
    		if (events[0].state == K_POLL_TYPE_SEM_AVAILABLE) {
    			events[0].state = K_POLL_STATE_NOT_READY;
    			k_sem_take(&usb_0_sd->sem, K_NO_WAIT);
    			uart_irq_tx_enable(usb_0_dev);
    		}  else if (events[1].state == K_POLL_TYPE_SEM_AVAILABLE) {
    			events[1].state = K_POLL_STATE_NOT_READY;
    			k_sem_take(&uart_0_sd->sem, K_NO_WAIT);
    			uart_irq_tx_enable(uart_0_dev);
    		} 
    	}
    }
    
    
    //END
    
    
    void main(void)
    {
    	int err;
    
    	printk("Starting Bluetooth Central UART example\n");
    
    	err = bt_conn_auth_cb_register(&conn_auth_callbacks);
    	if (err) {
    		printk("Failed to register authorization callbacks.\n");
    		return;
    	}
    
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    	printk("Bluetooth initialized\n");
    
    	if (IS_ENABLED(CONFIG_SETTINGS)) {
    		settings_load();
    	}
    
    	bt_conn_cb_register(&conn_callbacks);
    
    	int (*module_init[])(void) = {uart_init, scan_init, nus_client_init};
    	for (size_t i = 0; i < ARRAY_SIZE(module_init); i++) {
    		err = (*module_init[i])();
    		if (err) {
    			return;
    		}
    	}
    
    	err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
    	if (err) {
    		printk("Scanning failed to start (err %d)\n", err);
    		return;
    	}
    	printk("Scanning successfully started\n");
    
    	for (;;) {
    		/* Wait indefinitely for data to be sent over Bluetooth */
    		struct uart_data_t *buf = k_fifo_get(&fifo_uart_rx_data,
    						     K_FOREVER);
    
    		err = bt_gatt_nus_c_send(&gatt_nus_c, buf->data, buf->len);
    		if (err) {
    			printk("Failed to send data over BLE connection"
    			       "(err %d)\n", err);
    		}
    
    		err = k_sem_take(&nus_write_sem, NUS_WRITE_TIMEOUT);
    		if (err) {
    			printk("NUS send timeout\n");
    		}
    	}
    }
    
    K_THREAD_DEFINE(usb_uart_thread_id, 16384, usb_uart_thread, NULL, NULL,
    	NULL, K_LOWEST_APPLICATION_THREAD_PRIO, 0, K_NO_WAIT);
    #endif

Related