Using HID keyboard and the iOS soft-keyboard combined - ios

I've been using nRF52840, SDK 17.0.2, with the example code for HID over BLE keyboard.
When connecting to an iOS phone, the HID keyboard promotes the iOS soft-keyboard, so not input is enabled from the phone's user.
I would like to enable the iOS soft-keyboard while BLE connected with the nRF.
I am using the hid_init configuration and the eject-keyboard key sending, described in here:
Bluetooth LE HID Eject Key Code?
Another source for the above code:
https://github.com/Rallare/nrf51_ble_app_hids_kbd_consumercontrol/blob/master/main.c
However, sending the key will not enable the keyboard unless the phone is currently in a text field. If not in a text field, the key is ignored.
I've also tried sending the following sequence to enable the keyboard:
report key modifier release
*{0, 0x0B, 0x08, true} // Home
{0, 0x2C, 0x08, true} //spotlight
{0, 0x52, 0, true} // Up Arrow
{0, 0x04, 0x08, true} // Select All
{0, 0x2A, 0, true} // Backspace
{1, 0x01, 0, true} // eject
{0, 0x2C, 0x08, true} //spotlight*
But, this solution is not stable and mostly does not work.
I also use shortcuts and keyboard commands to lunch apps, in the project, but could not find something that might help with my issue.
This is the hid configuration I use:
*static void hids_init(void)
{
ret_code_t err_code;
ble_hids_init_t hids_init_obj;
ble_hids_inp_rep_init_t * p_input_report;
ble_hids_outp_rep_init_t * p_output_report;
ble_hids_feature_rep_init_t * p_feature_report;
uint8_t hid_info_flags;
static ble_hids_inp_rep_init_t input_report_array[2];
static ble_hids_outp_rep_init_t output_report_array[1];
static ble_hids_feature_rep_init_t feature_report_array[1];
static uint8_t report_map_data[] =
{
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report Id (1)
0x05, 0x07, // Usage Page (Key Codes)
0x19, 0xe0, // Usage Minimum (224)
0x29, 0xe7, // Usage Maximum (231)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data, Variable, Absolute)
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x01, // Input (Constant) reserved byte(1)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (Page# for LEDs)
0x19, 0x01, // Usage Minimum (1)
0x29, 0x05, // Usage Maximum (5)
0x91, 0x02, // Output (Data, Variable, Absolute), Led report
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x91, 0x01, // Output (Data, Variable, Absolute), Led report
padding
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x65, // Logical Maximum (101)
0x05, 0x07, // Usage Page (Key codes)
0x19, 0x00, // Usage Minimum (0)
0x29, 0x65, // Usage Maximum (101)
0x81, 0x00, // Input (Data, Array) Key array(6 bytes)
0x09, 0x05, // Usage (Vendor Defined)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8 bit)
0x95, 0x02, // Report Count (2)
0xB1, 0x02, // Feature (Data, Variable, Absolute)
0xC0, // End Collection (Application)
// Report ID 2: Advanced buttons
0x05, 0x0C, // Usage Page (Consumer)
0x09, 0x01, // Usage (Consumer Control)
0xA1, 0x01, // Collection (Application)
0x85, 0x02, // Report Id (2)
0x15, 0x00, // Logical minimum (0)
0x25, 0x01, // Logical maximum (1)
0x0A, 0xAE, 0x01, // Usage (AL Keyboard Layout)
0x75, 0x01, // Report Size (1)
0x95, 0x01, // Report Count (1)
0x81, 0x06, // Input (Data,Value,Relative,Bit Field)
0xC0 // End Collection
};
memset((void *)input_report_array, 0,
2*sizeof(ble_hids_inp_rep_init_t));
memset((void *)output_report_array, 0,
sizeof(ble_hids_outp_rep_init_t));
memset((void *)feature_report_array, 0,
sizeof(ble_hids_feature_rep_init_t));
// Initialize HID Service
p_input_report = &input_report_array[INPUT_REPORT_KEYS_INDEX];
p_input_report->max_len = INPUT_REPORT_KEYS_MAX_LEN;
p_input_report->rep_ref.report_id = INPUT_REP_REF_ID;
p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;
p_input_report->sec.cccd_wr = SEC_JUST_WORKS;
p_input_report->sec.wr = SEC_JUST_WORKS;
p_input_report->sec.rd = SEC_JUST_WORKS;
// Initialize HID Service
p_input_report = &input_report_array[INPUT_REPORT_TOGGLE_INDEX];
p_input_report->max_len = INPUT_REPORT_KEYS_MAX_LEN;
p_input_report->rep_ref.report_id = INPUT_REP_TOGGLE_ID;
p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;
p_input_report->sec.cccd_wr = SEC_JUST_WORKS;
p_input_report->sec.wr = SEC_JUST_WORKS;
p_input_report->sec.rd = SEC_JUST_WORKS;
p_output_report = &output_report_array[OUTPUT_REPORT_INDEX];
p_output_report->max_len = OUTPUT_REPORT_MAX_LEN;
p_output_report->rep_ref.report_id = OUTPUT_REP_REF_ID;
p_output_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_OUTPUT;
p_output_report->sec.wr = SEC_JUST_WORKS;
p_output_report->sec.rd = SEC_JUST_WORKS;
p_feature_report = &feature_report_array[FEATURE_REPORT_INDEX];
p_feature_report->max_len = FEATURE_REPORT_MAX_LEN;
p_feature_report->rep_ref.report_id = FEATURE_REP_REF_ID;
p_feature_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_FEATURE;
p_feature_report->sec.rd = SEC_JUST_WORKS;
p_feature_report->sec.wr = SEC_JUST_WORKS;
hid_info_flags = HID_INFO_FLAG_REMOTE_WAKE_MSK |
HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK;
memset(&hids_init_obj, 0, sizeof(hids_init_obj));
hids_init_obj.evt_handler = on_hids_evt;
hids_init_obj.error_handler = service_error_handler;
hids_init_obj.is_kb = true;
hids_init_obj.is_mouse = false;
hids_init_obj.inp_rep_count = 2;
hids_init_obj.p_inp_rep_array = input_report_array;
hids_init_obj.outp_rep_count = 1;
hids_init_obj.p_outp_rep_array = output_report_array;
hids_init_obj.feature_rep_count = 1;
hids_init_obj.p_feature_rep_array = feature_report_array;
hids_init_obj.rep_map.data_len = sizeof(report_map_data);
hids_init_obj.rep_map.p_data = report_map_data;
hids_init_obj.hid_information.bcd_hid =BASE_USB_HID_SPEC_VERSION;
hids_init_obj.hid_information.b_country_code = 0;
hids_init_obj.hid_information.flags = hid_info_flags;
hids_init_obj.included_services_count = 0;
hids_init_obj.p_included_services_array = NULL;
hids_init_obj.rep_map.rd_sec = SEC_JUST_WORKS;
hids_init_obj.hid_information.rd_sec = SEC_JUST_WORKS;
hids_init_obj.boot_kb_inp_rep_sec.cccd_wr = SEC_JUST_WORKS;
hids_init_obj.boot_kb_inp_rep_sec.rd = SEC_JUST_WORKS;
hids_init_obj.boot_kb_outp_rep_sec.rd = SEC_JUST_WORKS;
hids_init_obj.boot_kb_outp_rep_sec.wr = SEC_JUST_WORKS;
hids_init_obj.protocol_mode_rd_sec = SEC_JUST_WORKS;
hids_init_obj.protocol_mode_wr_sec = SEC_JUST_WORKS;
hids_init_obj.ctrl_point_wr_sec = SEC_JUST_WORKS;
err_code = ble_hids_init(&m_hids, &hids_init_obj);
APP_ERROR_CHECK(err_code);
}*
Tnx for any help given.

Related

How to read multiple sensor and send the data to ThingSpeak?

I have a problem with my code. When I test it without ThingSpeak library, my sensor values (especially for analogRead on fireLevel dan gasLevel) are there (not 0). But when I use ThingSpeak library for send the data, the fireLevel dan gasLevel show 0 for the values. Any solutions for my code, thanks
I'm still learning
The sensor that I used:
DHT11
KY-026
MQ-135
and for the NodeMCU I used ESP32 type
#include <WiFi.h>
#include "ThingSpeak.h"
#include <SPI.h>
#include <Wire.h>
#include <DHT.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
const char* ssid = "SECRET_SSID";
const char* password = "SECRET_PASSWORD";
WiFiClient client;
unsigned long channelNum = X;
const char* APIKey = "SECRET_KEY";
#define AIRQ_SENSOR 2 // ESP32 pin GIP2 connected to mq135 sensor
#define DHT_SENSOR_PIN 13 // ESP32 pin GIOP13 connected to DHT11 sensor
#define DHT_SENSOR_TYPE DHT11
#define FIRE_SENSOR_ANALOG 14 // ESP32 pin GIP14 connected to Fire sensor
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
DHT dht_sensor(DHT_SENSOR_PIN, DHT_SENSOR_TYPE);
float humi, tempC, gasLevel, fireLevel;
String quality = "";
const uint8_t bitmap19[] = {0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x40, 0x00, 0x7f, 0x60, 0x00, 0xff, 0xe0, 0x00, 0xff, 0xf0, 0x06, 0xff, 0xf0, 0x07, 0xff, 0xf8, 0x07, 0xff, 0xf8, 0x0f, 0xf7, 0xf8, 0x0f, 0xe7, 0xf8, 0x1f, 0xe3, 0xfc, 0x1f, 0xc1, 0xfc, 0x3f, 0x80, 0xfc, 0x3f, 0x80, 0xf8, 0x1f, 0x00, 0xf8, 0x1f, 0x00, 0xf0, 0x0f, 0x00, 0xe0, 0x07, 0x80, 0xc0, 0x01, 0x81, 0x00};
void setup() {
Serial.begin(9600);
dht_sensor.begin(); // initialize the DHT sensor
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3c)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
}
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(2);
display.setCursor(50, 0);
display.println("Air");
display.setTextSize(1);
display.setCursor(23, 20);
display.println("Quality Monitor");
display.display();
delay(1200);
display.clearDisplay();
WiFi.mode(WIFI_STA);
ThingSpeak.begin(client);
}
void fireSensor() {
fireLevel = analogRead(FIRE_SENSOR_ANALOG);
Serial.println("fire level: " + String(fireLevel));
if(fireLevel < 2000) {
display.drawBitmap(90, 35, bitmap19, 24, 24, 1);
}
else {
display.clearDisplay();
}
}
void temphSensor() {
// read humidity
humi = dht_sensor.readHumidity();
// read temperature in Celsius
tempC = dht_sensor.readTemperature();
// check whether the reading is successful or not
if ( isnan(tempC) || isnan(humi)) {
Serial.println("Failed to read from DHT sensor!");
} else {
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0, 35);
display.println("Tmp:");
display.setCursor(30, 35);
display.println(tempC);
display.setCursor(64, 35);
display.println("C");
display.setCursor(0, 50);
display.println("RH:");
display.setCursor(30, 50);
display.println(humi);
display.setCursor(64, 50);
display.println("%");
}
}
void airqSensor() {
gasLevel = analogRead(AIRQ_SENSOR);
Serial.println("gas Level: " + String(gasLevel));
if(gasLevel < 500) {
quality = "Good";
}
else if(gasLevel < 750) {
// avg 750
quality = "Moderate";
}
else if(gasLevel < 1500) {
// avg 1500
quality = "Unhealty";
}
else {
// 2000 >
quality = "Hazardous";
}
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(30, 5);
display.println("Air Quality");
display.setCursor(35, 20);
display.println(quality);
}
void writeThingSpeak() {
ThingSpeak.setField(1, tempC);
ThingSpeak.setField(2, humi);
ThingSpeak.setField(3, gasLevel);
ThingSpeak.setField(4, fireLevel);
int x = ThingSpeak.writeFields(channelNum, APIKey);
if(x == 200) {
Serial.println("Channel update successful.");
}
else {
Serial.println("Problem updating channel. HTTP error code " + String(x));
}
delay(15000);
}
void loop() {
display.clearDisplay();
if(WiFi.status() != WL_CONNECTED){
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
while(WiFi.status() != WL_CONNECTED){
WiFi.begin(ssid, password); // Connect to WPA/WPA2 network. Change this line if using open or WEP network
Serial.print(".");
delay(5000);
}
Serial.println("\nConnected.");
}
fireSensor();
airqSensor();
temphSensor();
display.display();
writeThingSpeak();
}
After further search I found a solution about my question. The problem is I used ADC2 for my sensor (ex: MQ-135 and KY-026) which is used to read an analog. In this case I put my sensor on GPIO2 and GPIO4, which is among the ADC2.
List of ADC2s are: GPIO pins 0, 2, 4, 12, 13, 14, 15, 25, 26 and 27.
So, instead use ADC2 that originally if you used a WiFi connection on your ESP32, just use ADC1.
List of ADC1s are: GPIO pins 32, 33, 34, 35, 36, 37, 38 and 39.
When I changed my AO pins for both of my sensors (MQ-135 and KY-026) to GPIO34 and 35 it worked!
reference: esp32 pinout reference

Toggle virtual keyboard with Bluetooth HID

I am developing a HID device on the NRF52810.
After testing the work of HID on IOS, I found out that the virtual keyboard disappears when the HID device is connected and it is impossible to return it to the iphone.
After reading the documentation for the HID, I did not find the right command.
I found a BLE keyboard that has this key to enable the virtual keyboard. After testing the keyboard, I found out the following things:
1) On windows, this button launches the context menu, key code 0x65
2) On android, this button launches the context menu
3) On ios, hides and opens the virtual keyboard
I tried to send this code (0x65) through my device. And as expected on windows and android opens a context menu. However, on ios it is not recognized. The keyboard does not appear, programs see the key as undefined.
Does anyone know what the problem is? What code do I need to send to IOS to open the virtual keyboard? Can there be a problem in the HID descriptor?
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report id(1)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (Page# for LEDs)
0x19, 0x01, // Usage Minimum (1)
0x29, 0x05, // Usage Maximum (5)
0x91, 0x02, // Output (Data, Variable, Absolute), Led report
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x91, 0x01, // Output (Data, Variable, Absolute), Led report padding
0x95, 0x04, // Report Count (5)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0xFF, // Logical Maximum (255)
0x05, 0x07, // Usage Page (Key codes)
0x19, 0x00, // Usage Minimum (0)
0x29, 0xFF, // Usage Maximum (255)
0x81, 0x00, // Input (Data, Array) Key array(6 bytes)
0xC0, // End Collection (Application)
0x05, 0x01, // Usage Page (Desktop),
0x09, 0x80, // Usage (Generic Desktop),
0xA1, 0x01, // Collection (Application),
0x85, 0x02, // Report id(2)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x09, 0x81, // Usage (System Power Down)
0x09, 0x82, // Usage (System Sleep)
0x09, 0x83, // Usage (System Wake Up)
0x09, 0x84, // Usage (System Context Menu)
0x09, 0x85, // Usage (System Main Menu)
0x09, 0x86, // Usage (System App Menu)
0x09, 0x87, // Usage (System Menu Help)
0x09, 0x88, // Usage (System Menu Exit)
0x81, 0x02, // Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit)
0xC0, // End Collection,
I realise this was asked 9 months ago, but I wanted to add the answer anyway since I was trying to do the same and figured it out recently. I managed it using the Consumer Control usage page, with the specific usage:
0x0A, 0xAE, 0x01, // Usage (AL Keyboard Layout)
For more information, see HID Usage Tables section 15.15.

UInt8 from Swift to Objective-C

I need a clarification. I'm following a tutorial on Hash sha256 in Swift and my app is in Objective-C. I have trouble translating this UInt8 in Objective-C. What is the equivalent in Objective-C?
let rsa2048Asn1Header:[UInt8] = [
0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00
]
I tried this but I'm not sure it's right I'd like to have confirmation
UInt8 rsa2048AsnlHeader[] = {
0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00};
Yes what you posted above would work if you're just looking to use a primitive array in Objective-C.
Another option would be to use NSArray, shown below:
NSArray<NSNumber *> *rsa2048AsnlHeader = #[
#0x30, #0x82, #0x01, #0x22, #0x30, #0x0d, #0x06, #0x09, #0x2a, #0x86, #0x48, #0x86,
#0xf7, #0x0d, #0x01, #0x01, #0x01, #0x05, #0x00, #0x03, #0x82, #0x01, #0x0f, #0x00
];
To get the equivalent UInt8 value from the NSNumber elements, use the unsignedCharValue property of the NSNumber class (which is equivalent to uint8Value in Swift). For example:
for (NSNumber *value in rsa2048AsnlHeader) {
UInt8 uint8Value = value.unsignedCharValue;
// ...
}
Source

convert c char to swift

I am trying to conver the following code to swift:
static unsigned char rsa2048Asn1Header[] = {
0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00
};
static unsigned char rsa4096Asn1Header[] = {
0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00
};
static unsigned char ecDsaSecp256r1Asn1Header[] = {
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
0x42, 0x00
};
static unsigned char *asn1HeaderBytes[3] = { rsa2048Asn1Header, rsa4096Asn1Header, ecDsaSecp256r1Asn1Header };
static unsigned int asn1HeaderSizes[3] = { sizeof(rsa2048Asn1Header), sizeof(rsa4096Asn1Header), sizeof(ecDsaSecp256r1Asn1Header) };
My swift code looks like this:
let rsa2048Asn1Header:[CUnsignedChar] = [0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00]
let rsa4096Asn1Header:[CUnsignedChar] = [0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00]
let ecDsaSecp256r1Asn1Header:[CUnsignedChar] = [0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00]
let asn1HeaderBytes:[[CUnsignedChar]] = [rsa2048Asn1Header, rsa4096Asn1Header, ecDsaSecp256r1Asn1Header]
let asn1HeaderSizes:[UInt] = [sizeof(rsa2048Asn1Header.dynamicType).toUInt, sizeof(rsa4096Asn1Header.dynamicType).toUInt, sizeof(ecDsaSecp256r1Asn1Header.dynamicType).toUInt]
However i failing at his badly, per example using rsa2048Asn1Header and converting it to NSData:
let data:NSData = NSData(bytes: rsa2048Asn1Header, length:strideofValue(rsa2048Asn1Header))
swift prints with length 8:
<30820122 300d0609>
objc for the following code:
[NSData dataWithBytes:rsa2048Asn1Header length:sizeof(rsa2048Asn1Header)];
prints
<30820122 300d0609 2a864886 f70d0101 01050003 82010f00> size: 24
looking at apple documentation, strideOfvalue should return the right size for each one of those [CUnsignedChar] but that doesnt seem to be the case, my question is shouldnt a [CUnsignedChar] have same size as usigned char [] in objc, if not what could i use to change?
also [[CUnsignedChar]] makes no sense whatsoever in my head, how would the code below convert to swift, should i convert those arrays to an NSString and extract the CString when required, if so what encoding should I use?
static unsigned char *asn1HeaderBytes[3] = { rsa2048Asn1Header, rsa4096Asn1Header, ecDsaSecp256r1Asn1Header };
I don't think strideofValue is the function you are looking for. I haven't heard of it before, but the documentation states:
Returns the least possible interval between distinct instances of T in memory. The result is always positive.
If this is returning 8, that means that the minimum distance between [CUnsignedChar]s in memory is 8 bytes.
To use NSData(data:length:) properly, the second parameter needs to be the size of the array. You can use the count property for this:
let data: NSData = NSData(bytes: rsa2048Asn1Header, length:rsa2048Asn1Header.count)
[[CUnsignedChar]] is an array of arrays (two-dimensional array) of CUnsignedChar.
Your headers are raw bytes, so technically no encoding is 'correct' to convert to NSString. The cryptographic headers you have don't appear to be strings, and contain unprintable characters.
You should not use strideofValue function. 'strideofValue' it's not a replacement for 'sizeof'. Just go for ".count" property.

Bluetooth LE HID Eject Key Code?

I am implementing a dongle based on the TI Bluetooth LE HID sample that needs to restore or disable keyboard functionality. When using an Apple keyboard with an iOS device, pressing the eject button will enable/disable the device, hiding/showing the keyboard.
Most references say there is no key code for the eject button, although one lists it as 161; this does not work when used from a Bluetooth LE device. What are the key codes sent to the device from the keyboard to accomplish this?
I am assuming, of course, that a Bluetooth LE device will send the same key codes as a Bluetooth device, and that Apple's implementation of the Bluetooth LE HID includes the functionality for hiding and restoring the keyboard. If one of these assumptions is incorrect, that would help, too.
I've successfully gotten this working with an Nordic Semiconductor's nRF51822 and S110, using the following report map:
static uint8_t report_map_data[] =
{
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report Id (1)
0x05, 0x07, // Usage Page (Key Codes)
0x19, 0xe0, // Usage Minimum (224)
0x29, 0xe7, // Usage Maximum (231)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data, Variable, Absolute)
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x01, // Input (Constant) reserved byte(1)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (Page# for LEDs)
0x19, 0x01, // Usage Minimum (1)
0x29, 0x05, // Usage Maximum (5)
0x91, 0x02, // Output (Data, Variable, Absolute), Led report
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x91, 0x01, // Output (Data, Variable, Absolute), Led report padding
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x65, // Logical Maximum (101)
0x05, 0x07, // Usage Page (Key codes)
0x19, 0x00, // Usage Minimum (0)
0x29, 0x65, // Usage Maximum (101)
0x81, 0x00, // Input (Data, Array) Key array(6 bytes)
0x09, 0x05, // Usage (Vendor Defined)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Count (2)
0x95, 0x02, // Report Size (8 bit)
0xB1, 0x02, // Feature (Data, Variable, Absolute)
0xC0, // End Collection (Application)
// Report ID 2: Advanced buttons
0x05, 0x0C, // Usage Page (Consumer)
0x09, 0x01, // Usage (Consumer Control)
0xA1, 0x01, // Collection (Application)
0x85, 0x02, // Report Id (2)
0x15, 0x00, // Logical minimum (0)
0x25, 0x01, // Logical maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x01, // Report Count (1)
0x0A, 0xAE, 0x01, // Usage (AL Keyboard Layout)
0x81, 0x06, // Input (Data,Value,Relative,Bit Field)
0xC0 // End Collection
};
Having this report map enables me to send a toggle with this:
static void toggle_send(void)
{
uint32_t err_code;
uint8_t release = 0;
uint8_t keyboard_toggle = 0x01;
// 1 designates the report index, not report ID.
err_code = ble_hids_inp_rep_send(&m_hids, 1, sizeof(keyboard_toggle), &keyboard_toggle);
APP_ERROR_CHECK(err_code);
err_code = ble_hids_inp_rep_send(&m_hids, 1, sizeof(release), &release);
APP_ERROR_CHECK(err_code);
}
I don't know the TI APIs in detail, but I hope this can be useful to refer to nevertheless. The above modifications should be easy to add to the ble_app_hids_keyboard in the regular nRF51 SDK, if you also have access to that chip.
this was worked for me:
static void hids_init(void)
{
ret_code_t err_code;
ble_hids_init_t hids_init_obj;
ble_hids_inp_rep_init_t * p_input_report;
ble_hids_outp_rep_init_t * p_output_report;
ble_hids_feature_rep_init_t * p_feature_report;
uint8_t hid_info_flags;
static ble_hids_inp_rep_init_t input_report_array[2];
static ble_hids_outp_rep_init_t output_report_array[1];
static ble_hids_feature_rep_init_t feature_report_array[1];
static uint8_t report_map_data[] =
{
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x85, 0x00, // Report Id (1)
0x05, 0x07, // Usage Page (Key Codes)
0x19, 0xe0, // Usage Minimum (224)
0x29, 0xe7, // Usage Maximum (231)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data, Variable, Absolute)
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x01, // Input (Constant) reserved byte(1)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (Page# for LEDs)
0x19, 0x01, // Usage Minimum (1)
0x29, 0x05, // Usage Maximum (5)
0x91, 0x02, // Output (Data, Variable, Absolute), Led report
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x91, 0x01, // Output (Data, Variable, Absolute), Led report padding
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x65, // Logical Maximum (101)
0x05, 0x07, // Usage Page (Key codes)
0x19, 0x00, // Usage Minimum (0)
0x29, 0x65, // Usage Maximum (101)
0x81, 0x00, // Input (Data, Array) Key array(6 bytes)
0x09, 0x05, // Usage (Vendor Defined)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Count (2)
0x95, 0x02, // Report Size (8 bit)
0xB1, 0x02, // Feature (Data, Variable, Absolute)
0xC0, // End Collection (Application)
// Report ID 2: Advanced buttons
0x05, 0x0C, // Usage Page (Consumer)
0x09, 0x01, // Usage (Consumer Control)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report Id (2)
0x15, 0x00, // Logical minimum (0)
0x25, 0x01, // Logical maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x01, // Report Count (1)
0x0A, 0xAE, 0x01, // Usage (AL Keyboard Layout)
0x81, 0x06, // Input (Data,Value,Relative,Bit Field)
0xC0 // End Collection
};
memset((void *)input_report_array, 0, sizeof(ble_hids_inp_rep_init_t));
memset((void *)output_report_array, 0, sizeof(ble_hids_outp_rep_init_t));
memset((void *)feature_report_array, 0, sizeof(ble_hids_feature_rep_init_t));
// Initialize HID Service
p_input_report = &input_report_array[INPUT_REPORT_KEYS_INDEX];
p_input_report->max_len = INPUT_REPORT_KEYS_MAX_LEN;
p_input_report->rep_ref.report_id = INPUT_REP_REF_ID;
p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;
p_input_report->sec.cccd_wr = SEC_JUST_WORKS;
p_input_report->sec.wr = SEC_JUST_WORKS;
p_input_report->sec.rd = SEC_JUST_WORKS;
// Initialize HID Service
p_input_report = &input_report_array[1];
p_input_report->max_len = INPUT_REPORT_KEYS_MAX_LEN;
p_input_report->rep_ref.report_id = 1;
p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;
p_input_report->sec.cccd_wr = SEC_JUST_WORKS;
p_input_report->sec.wr = SEC_JUST_WORKS;
p_input_report->sec.rd = SEC_JUST_WORKS;
p_input_report = &input_report_array[INPUT_REPORT_KEYS_INDEX];
p_output_report = &output_report_array[OUTPUT_REPORT_INDEX];
p_output_report->max_len = OUTPUT_REPORT_MAX_LEN;
p_output_report->rep_ref.report_id = OUTPUT_REP_REF_ID;
p_output_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_OUTPUT;
p_output_report->sec.wr = SEC_JUST_WORKS;
p_output_report->sec.rd = SEC_JUST_WORKS;
p_feature_report = &feature_report_array[FEATURE_REPORT_INDEX];
p_feature_report->max_len = FEATURE_REPORT_MAX_LEN;
p_feature_report->rep_ref.report_id = FEATURE_REP_REF_ID;
p_feature_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_FEATURE;
p_feature_report->sec.rd = SEC_JUST_WORKS;
p_feature_report->sec.wr = SEC_JUST_WORKS;
hid_info_flags = HID_INFO_FLAG_REMOTE_WAKE_MSK | HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK;
memset(&hids_init_obj, 0, sizeof(hids_init_obj));
hids_init_obj.evt_handler = on_hids_evt;
hids_init_obj.error_handler = service_error_handler;
hids_init_obj.is_kb = true;
hids_init_obj.is_mouse = false;
hids_init_obj.inp_rep_count = 2;
hids_init_obj.p_inp_rep_array = input_report_array;
hids_init_obj.outp_rep_count = 1;
hids_init_obj.p_outp_rep_array = output_report_array;
hids_init_obj.feature_rep_count = 1;
hids_init_obj.p_feature_rep_array = feature_report_array;
hids_init_obj.rep_map.data_len = sizeof(report_map_data);
hids_init_obj.rep_map.p_data = report_map_data;
hids_init_obj.hid_information.bcd_hid = BASE_USB_HID_SPEC_VERSION;
hids_init_obj.hid_information.b_country_code = 0;
hids_init_obj.hid_information.flags = hid_info_flags;
hids_init_obj.included_services_count = 0;
hids_init_obj.p_included_services_array = NULL;
hids_init_obj.rep_map.rd_sec = SEC_JUST_WORKS;
hids_init_obj.hid_information.rd_sec = SEC_JUST_WORKS;
hids_init_obj.boot_kb_inp_rep_sec.cccd_wr = SEC_JUST_WORKS;
hids_init_obj.boot_kb_inp_rep_sec.rd = SEC_JUST_WORKS;
hids_init_obj.boot_kb_outp_rep_sec.rd = SEC_JUST_WORKS;
hids_init_obj.boot_kb_outp_rep_sec.wr = SEC_JUST_WORKS;
hids_init_obj.protocol_mode_rd_sec = SEC_JUST_WORKS;
hids_init_obj.protocol_mode_wr_sec = SEC_JUST_WORKS;
hids_init_obj.ctrl_point_wr_sec = SEC_JUST_WORKS;
err_code = ble_hids_init(&m_hids, &hids_init_obj);
APP_ERROR_CHECK(err_code);
}

Resources