<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://devzone.nordicsemi.com/cfs-file/__key/system/syndication/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Trigger iOS Shutter via BLE on iOS 16</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/92798/trigger-ios-shutter-via-ble-on-ios-16</link><description>We would like the Fjorden Grip also to trigger the native iOS camera&amp;#39;s shutter button, via sending a “volume up” command—similar to selfie sticks, which however use classic Bluetooth instead of BLE. Our implementation worked flawlessly in iOS 15, but</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Tue, 01 Nov 2022 09:55:25 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/92798/trigger-ios-shutter-via-ble-on-ios-16" /><item><title>RE: Trigger iOS Shutter via BLE on iOS 16</title><link>https://devzone.nordicsemi.com/thread/393406?ContentTypeID=1</link><pubDate>Tue, 01 Nov 2022 09:55:25 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:1446a5cd-b8ef-4486-96a4-05481db56ffb</guid><dc:creator>florianbuerger</dc:creator><description>&lt;p&gt;Hey Sigurd, apologies for my delayed response. Thank you for your help, and adjusting the sample. We have a working version now for iOS 16. It doesn&amp;#39;t work anymore on iOS 15, but we decided to accept that and don&amp;#39;t invest any more time in it. The number of iOS 15 users for our app is quite low, and only will get lower over time. The important part was that iOS 16 works.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Trigger iOS Shutter via BLE on iOS 16</title><link>https://devzone.nordicsemi.com/thread/392588?ContentTypeID=1</link><pubDate>Wed, 26 Oct 2022 11:11:56 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:a3dcb70a-6c80-4fca-a1c3-3fea12ac2ab2</guid><dc:creator>Sigurd</dc:creator><description>&lt;p&gt;Hi,&lt;/p&gt;
[quote user="sigurdon"]Small update: I will get hold of a iPhone with iOS16 and try to reproduce&amp;nbsp;the issue here.[/quote]
&lt;p&gt;We have 1 sample in the nRF Connect SDK that implements HID Volume control:&amp;nbsp;&lt;a href="https://github.com/nrfconnect/sdk-nrf/tree/main/samples/bluetooth/peripheral_fast_pair"&gt;https://github.com/nrfconnect/sdk-nrf/tree/main/samples/bluetooth/peripheral_fast_pair&lt;/a&gt;&amp;nbsp;,&lt;/p&gt;
&lt;p&gt;&lt;span&gt;The HID report map looks like this:&amp;nbsp;&lt;/span&gt;&lt;a href="https://github.com/nrfconnect/sdk-nrf/blob/v2.1.0/samples/bluetooth/peripheral_fast_pair/src/hids_helper.c#L58"&gt;https://github.com/nrfconnect/sdk-nrf/blob/v2.1.0/samples/bluetooth/peripheral_fast_pair/src/hids_helper.c#L58&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I removed some of the fast-pairing stuff, and was left with this:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://devzone.nordicsemi.com/cfs-file/__key/communityserver-discussions-components-files/4/peripheral_5F00_hids_5F00_volume.zip"&gt;devzone.nordicsemi.com/.../peripheral_5F00_hids_5F00_volume.zip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Button 2 and 4 on a nRF52-DK can be used to control the volume.&lt;/p&gt;
&lt;p&gt;The sample was built using NCS v2.1.0, and tested on a iPhone with iOS 16.1, and the HID volume control worked fine.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Trigger iOS Shutter via BLE on iOS 16</title><link>https://devzone.nordicsemi.com/thread/392479?ContentTypeID=1</link><pubDate>Tue, 25 Oct 2022 20:16:59 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:1f7bc61e-bf53-46fd-a7fc-1fb8258314cc</guid><dc:creator>Sigurd</dc:creator><description>&lt;p&gt;Small update: I will get hold of a iPhone with iOS16 and try to reproduce&amp;nbsp;the issue here.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Trigger iOS Shutter via BLE on iOS 16</title><link>https://devzone.nordicsemi.com/thread/392058?ContentTypeID=1</link><pubDate>Mon, 24 Oct 2022 08:47:05 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:0df78911-f68e-4247-8fe2-10d2488067a2</guid><dc:creator>florianbuerger</dc:creator><description>&lt;p&gt;All the above testing was done with the 16.1 release candidate, which should be the same version as the public release today.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Trigger iOS Shutter via BLE on iOS 16</title><link>https://devzone.nordicsemi.com/thread/392038?ContentTypeID=1</link><pubDate>Mon, 24 Oct 2022 07:54:07 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:cc2ba662-3f0a-4352-8908-14912245dc1f</guid><dc:creator>Sigurd</dc:creator><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;iOS v16.1.0 is being released today. Could you check&amp;nbsp;if this is issue is fixed in v16.1.0?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Trigger iOS Shutter via BLE on iOS 16</title><link>https://devzone.nordicsemi.com/thread/391948?ContentTypeID=1</link><pubDate>Fri, 21 Oct 2022 15:15:48 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:e4fbc5c3-55b2-47d9-968f-5aec84a9fdfb</guid><dc:creator>florianbuerger</dc:creator><description>&lt;p&gt;That results in iOS 15 not working at all, iOS 16 receives a volume down command, but then never receives the release command.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Trigger iOS Shutter via BLE on iOS 16</title><link>https://devzone.nordicsemi.com/thread/391919?ContentTypeID=1</link><pubDate>Fri, 21 Oct 2022 13:39:51 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:1e3d70ee-f87b-484b-894c-57d9283b41e3</guid><dc:creator>Sigurd</dc:creator><description>&lt;p&gt;Hi,&lt;/p&gt;
[quote userid="120430" url="~/f/nordic-q-a/92798/trigger-ios-shutter-via-ble-on-ios-16/391915"] I&amp;#39;ve attached the updated HID report map.[/quote]
&lt;p&gt;Could you try to set&amp;nbsp;MEDIA_KEYS_ID to 0 ?&lt;/p&gt;
&lt;p&gt;More context for this suggestion can be found in this PR:&amp;nbsp;&lt;a id="" href="https://github.com/nrfconnect/sdk-nrf/pull/8772"&gt;https://github.com/nrfconnect/sdk-nrf/pull/8772&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Trigger iOS Shutter via BLE on iOS 16</title><link>https://devzone.nordicsemi.com/thread/391915?ContentTypeID=1</link><pubDate>Fri, 21 Oct 2022 13:33:35 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:109b0954-3788-47e6-9d82-a8b24fe5ef9d</guid><dc:creator>florianbuerger</dc:creator><description>&lt;p&gt;Okay, I can confirm that we adhere to the suggested intervals. Our accessory connects fine, and never gets disconnected by iOS.&lt;/p&gt;
&lt;p&gt;We experimented with the report descriptor, and found a version that works on iOS 16. But, the same version does not work on iOS 15. Instead of receiving a single volume down command, iOS 15 treats it as a continuous volume up command. It seems the key release event is never sent.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;I was unable to capture a sniffer trace, for some reason the Wireshark plugin didn&amp;#39;t work. I tried on macOS first, with no luck. I installed Windows 10 on an Intel MacBook, the plugin worked once, but then it stopped. We do have logs from running our firmware on the Nordic Dev Board. I&amp;#39;ve attached the updated HID report map.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;#include &amp;lt;hid.h&amp;gt;

#include &amp;lt;zephyr/types.h&amp;gt;
#include &amp;lt;stddef.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;errno.h&amp;gt;
#include &amp;lt;sys/byteorder.h&amp;gt;
#include &amp;lt;zephyr.h&amp;gt;

#include &amp;lt;bluetooth/bluetooth.h&amp;gt;
#include &amp;lt;bluetooth/hci.h&amp;gt;
#include &amp;lt;bluetooth/conn.h&amp;gt;
#include &amp;lt;bluetooth/uuid.h&amp;gt;
#include &amp;lt;bluetooth/gatt.h&amp;gt;

#include &amp;lt;logging/log.h&amp;gt;
LOG_MODULE_REGISTER(hid);

// BLE HID Descriptor Report ID
#define MEDIA_KEYS_ID 0x01

#define KEY_VOLUME_UP (0xe9)
#define KEY_VOLUME_DOWN (0xea)
#define KEY_RELEASE (0x00)

#define KEY_DELAY K_MSEC(20)

#define STACKSIZE 1024
#define PRIORITY 7

enum {
	HIDS_REMOTE_WAKE = BIT(0),
	HIDS_NORMALLY_CONNECTABLE = BIT(1),
};

struct hids_info {
	uint16_t version;
	uint8_t code;
	uint8_t flags;
} __packed;

struct hids_report {
	uint8_t id;
	uint8_t type;
} __packed;

static struct hids_info info = {
	.version = 0x0101,
	.code = 33,
	.flags = HIDS_NORMALLY_CONNECTABLE,
};

enum {
	HIDS_INPUT = 0x01,
	HIDS_OUTPUT = 0x02,
	HIDS_FEATURE = 0x03,
};

enum {
	HIDS_BOOT_PROTOCOL = 0x0,
	HIDS_REPORT_PROTOCOL = 0x1,
};

static struct hids_report input = {
	.id = 0x01,
	.type = HIDS_INPUT,
};

static uint8_t protocol = HIDS_REPORT_PROTOCOL;
static uint8_t send_input;
static uint8_t ctrl_point;

static uint8_t report_map[] = {
0x05, 0x0C,                     // Usage Page (Consumer)
        0x09, 0x01,                     // Usage (Consumer Control)
        0xA1, 0x01,                     // Collection (Application)
        0x85, MEDIA_KEYS_ID,            //     Report Id (1)
        0x15, 0x00,                     //     Logical minimum (0)
        0x25, 0x01,                     //     Logical maximum (1)
        0x75, 0x01,                     //     Report Size (1)
        0x95, 0x01,                     //     Report Count (1)

        0x09, KEY_VOLUME_DOWN,          //     Usage (Volume Down)
        0x81, 0x02,                     //     Input (Data,Value,Relative,Bit Field)
        0x09, KEY_VOLUME_UP,            //     Usage (Volume Up)
        0x81, 0x02,                     //     Input (Data,Value,Relative,Bit Field)

        0xC0                            // End Collection	
};


static ssize_t read_info(struct bt_conn *conn, const struct bt_gatt_attr *attr, 
	void *buf, uint16_t len, uint16_t offset)
{
	return bt_gatt_attr_read(conn, attr, buf, len, offset, attr-&amp;gt;user_data, sizeof(struct hids_info));
}

static ssize_t read_report_map(struct bt_conn *conn, const struct bt_gatt_attr *attr, 
	void *buf, uint16_t len, uint16_t offset)
{
	return bt_gatt_attr_read(conn, attr, buf, len, offset, report_map, sizeof(report_map));
}

static ssize_t read_report(struct bt_conn *conn, const struct bt_gatt_attr *attr, 
	void *buf, uint16_t len, uint16_t offset)
{
	return bt_gatt_attr_read(conn, attr, buf, len, offset, attr-&amp;gt;user_data, sizeof(struct hids_report));
}

static ssize_t read_protocol(struct bt_conn *conn, const struct bt_gatt_attr *attr, 
	void *buf, uint16_t len, uint16_t offset)
{
	return bt_gatt_attr_read(conn, attr, buf, len, offset, attr-&amp;gt;user_data, sizeof(protocol));
}

static void input_ccc_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
	send_input = (value == BT_GATT_CCC_NOTIFY) ? 1 : 0;
}

static ssize_t read_input_report(struct bt_conn *conn, 
	const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset)
{
	return bt_gatt_attr_read(conn, attr, buf, len, offset, NULL, 0);
}

static ssize_t write_ctrl_point(struct bt_conn *conn, 
	const struct bt_gatt_attr *attr, const void *buf, uint16_t len, 
	uint16_t offset, uint8_t flags)
{
	uint8_t *value = attr-&amp;gt;user_data;

	if (offset + len &amp;gt; sizeof(ctrl_point)) 
    {
		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
	}

	memcpy(value + offset, buf, len);

	return len;
}

/* HID Service Declaration */
BT_GATT_SERVICE_DEFINE(hid_service,
	BT_GATT_PRIMARY_SERVICE(BT_UUID_HIDS),
	BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_INFO, 
		BT_GATT_CHRC_READ, BT_GATT_PERM_READ, read_info, NULL, &amp;amp;info),
	BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT_MAP, 
		BT_GATT_CHRC_READ, BT_GATT_PERM_READ, read_report_map, NULL, NULL),
	BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, 
		BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT, 
		read_input_report, NULL, NULL),
	BT_GATT_CCC(input_ccc_changed, 
		BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT),
	BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, 
		BT_GATT_PERM_READ, read_report, NULL, &amp;amp;input),
    BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_PROTOCOL_MODE, 
		BT_GATT_CHRC_READ, BT_GATT_PERM_READ, read_protocol, NULL, &amp;amp;protocol),
	BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_CTRL_POINT, 
		BT_GATT_CHRC_WRITE_WITHOUT_RESP, BT_GATT_PERM_WRITE, NULL, 
		write_ctrl_point, &amp;amp;ctrl_point),
);

struct key_report 
{
	int reportId;
    int keycode;
};

K_MSGQ_DEFINE(key_report_queue, sizeof(struct key_report), 8, 4);

static void 
send_key(int reportId, int keycode)
{
	struct key_report report = { reportId, keycode };

	LOG_INF(&amp;quot;Sending key report to HID thread {%x, %x}&amp;quot;, report.reportId, report.keycode);
	
	int rc = k_msgq_put(&amp;amp;key_report_queue, &amp;amp;report, K_NO_WAIT);

	if (rc != 0)
	{
		LOG_ERR(&amp;quot;Failed to send key report&amp;quot;);
	}
}

void 
hid_thread_handler(void)
{
	struct key_report report = { 0 };

	for (;;)
	{
		k_sleep(KEY_DELAY);

		k_msgq_get(&amp;amp;key_report_queue, &amp;amp;report, K_FOREVER);

		LOG_INF(&amp;quot;[HID Thread] Received key report {%x, %x}&amp;quot;, report.reportId, report.keycode);

		uint8_t raw_cc_report[] = { report.reportId, report.keycode };
		LOG_HEXDUMP_INF(raw_cc_report, sizeof(raw_cc_report), &amp;quot;Hex dump&amp;quot;);
		bt_gatt_notify(NULL, hid_service.attrs + 5, raw_cc_report, sizeof(raw_cc_report));
	}
}

K_THREAD_DEFINE(hid_thread, STACKSIZE, hid_thread_handler, NULL, NULL, NULL, PRIORITY, 0, 0);

void
hid_send_press_event(void)
{
    LOG_INF(&amp;quot;Sending HID press event&amp;quot;);

	if (send_input == 0)
	{
		LOG_INF(&amp;quot;iOS is not listening for the events&amp;quot;);
		return;
	}

    send_key(MEDIA_KEYS_ID, KEY_VOLUME_DOWN);
}

void
hid_send_release_event(void)
{
	LOG_INF(&amp;quot;Sending HID release event&amp;quot;);

	if (send_input == 0)
	{
		LOG_INF(&amp;quot;iOS is not listening for the events&amp;quot;);
		return;
	}

    send_key(0, KEY_RELEASE);
}&lt;/pre&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Trigger iOS Shutter via BLE on iOS 16</title><link>https://devzone.nordicsemi.com/thread/390561?ContentTypeID=1</link><pubDate>Thu, 13 Oct 2022 07:46:36 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:811d2c18-86a0-4fe7-8486-850cf0b1f511</guid><dc:creator>Sigurd</dc:creator><description>&lt;p&gt;Ok, let me know once you know more. Should the&amp;nbsp;&lt;span&gt;connection parameters turn out to be inline with the guidelines, then the next step in debugging this would be to take&amp;nbsp;&lt;/span&gt;&lt;span style="font-family:inherit;"&gt;a&amp;nbsp;&lt;/span&gt;&lt;span style="font-family:inherit;"&gt;sniffer trace&lt;/span&gt;&lt;span style="font-family:inherit;"&gt;:&amp;nbsp;&lt;/span&gt;&lt;a id="" style="font-family:inherit;" href="https://www.nordicsemi.com/Products/Development-tools/nrf-sniffer-for-bluetooth-le"&gt;https://www.nordicsemi.com/Products/Development-tools/nrf-sniffer-for-bluetooth-le&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Trigger iOS Shutter via BLE on iOS 16</title><link>https://devzone.nordicsemi.com/thread/390560?ContentTypeID=1</link><pubDate>Thu, 13 Oct 2022 07:38:20 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:b67262af-9e15-42cb-b7e1-c317400a5da4</guid><dc:creator>florianbuerger</dc:creator><description>&lt;p&gt;Hey Sigurd, thanks for getting back to me. I&amp;rsquo;ll double-check with our engineer, but the device works flawlessly with using our app&amp;mdash;which then doesn&amp;rsquo;t rely on HID, we are using our services/characteristics. But there are no disconnects.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Trigger iOS Shutter via BLE on iOS 16</title><link>https://devzone.nordicsemi.com/thread/390473?ContentTypeID=1</link><pubDate>Wed, 12 Oct 2022 14:00:10 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:59b18451-7917-40fe-a504-80b4df595261</guid><dc:creator>Sigurd</dc:creator><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;Can you check and make&amp;nbsp;sure that all connection parameters match the requirements from the Apple accessory design guidelines?&lt;br /&gt;&lt;a id="" href="https://developer.apple.com/accessories/Accessory-Design-Guidelines.pdf"&gt;https://developer.apple.com/accessories/Accessory-Design-Guidelines.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img style="max-height:240px;max-width:320px;" src="https://devzone.nordicsemi.com/resized-image/__size/640x480/__key/communityserver-discussions-components-files/4/pastedimage1665582805585v1.png" alt=" " /&gt;&lt;/p&gt;
[quote userid="120430" url="~/f/nordic-q-a/92798/trigger-ios-shutter-via-ble-on-ios-16"]I wonder if&amp;nbsp;anyone&amp;nbsp;has encountered this issue, or understand what is happening?[/quote]
&lt;p&gt;We have seen reports that there have been some changes in iOS v16 on how these guidelines are being enforced. See e.g. this case:&amp;nbsp;&amp;nbsp;&lt;a href="https://devzone.nordicsemi.com/f/nordic-q-a/92003/getting-continuous-disconnects-with-ios-16/386457"&gt;RE: Getting continuous disconnects with iOS 16&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>