This post continues the BM78 series (Initializing Microchip’s BM78 module, …) with the different paring modes and an example implementation.
Pairing modes
So first lets look at the different pairing modes. There are four of them:
typedef enum {
BM78_PAIRING_PIN = 0x00,
BM78_PAIRING_JUST_WORK = 0x01,
BM78_PAIRING_PASSKEY = 0x02,
BM78_PAIRING_USER_CONFIRM = 0x03
} BM78_PairingMode_t;
PIN Pairing Mode
Is a very well know, simple, somewhat secure pairing mode with a static PIN. A pin needs to be between 4-5 digits which makes it not particularly save. But for simple applications where interaction is not possible this method can be used.
This mode can be setup using the following command: BM78_CMD_WRITE_PAIRING_MODE_SETTING (0x0B):

SINC|LENH|LENL|COM |STOR|MODE|CHKS
0xAA 0x00 0x03 0x0B 0x01 0x00 0xYY - will be stored in EEPROM
0xAA 0x00 0x03 0x0B 0x00 0x00 0xYY - will not be store in EEPROM
The PIN number can be changed using BM78_CMD_WRITE_PIN_CODE (0x51) command:
SINC|LENH|LENL|COM |STOR|DIG1|DIG2|DIG3|DIG4|CHKS
0xAA 0x00 0x06 0x51 0x01 0x31 0x32 0x33 0x34 0xYY - pin: 1234
SINC|LENH|LENL|COM |STOR|DIG1|DIG2|DIG3|DIG4|DIG5|DIG6|CHKS
0xAA 0x00 0x08 0x51 0x01 0x31 0x32 0x33 0x34 0x35 0x36 0xYY - pin: 123456
If both commands are executed successfully you BM78 can be now paired using the desired PIN. To put the module into pairing mode you need to put it into BM78_STATUS_STANDBY_MODE (0x03) using BM78_STANDBY_MODE_ENTER (0x01). Assuming you are in the BM78_STATUS_IDLE_MODE (0x09):
SINC|LENH|LENL|COM |MODE|CHKS
0xAA 0x00 0x02 0x1C 0x01 0xYY
If you have a device paired already and don’t want to allow other devices to pair themselves but be connectable to already paired devices you need to put the BM78 module into BM78_STATUS_STANDBY_MODE (0x03) using BM78_STANDBY_MODE_ENTER_ONLY_TRUSTED (0x02):
SINC|LENH|LENL|COM |MODE|CHKS
0xAA 0x00 0x02 0x1C 0x02 0xYY
Just Works Pairing Method
This is the most unsecure but simple pairing mode. Whenever the BM78 module is put into BM78_STATUS_STANDBY_MODE (0x03) using BM78_STANDBY_MODE_ENTER (0x01) other bluetooth devices can be paired with it without any pin, passkey or user interaction. Use this mode with caution.
Passkey Pairing Method
This is the most secure available pairing method. It displays a random passkey on the connecting device and requires the user to repeat that passkey. The BM78 uses the following command to do that:
BM78_CMD_PASSKEY_ENTRY_RES (0x40)
SINC|LENH|LENL|COM |ACT |KEY |CHKS
0xAA 0x00 0x02 0x40 0x01 0x31 0xYY - enter digit '1'
0xAA 0x00 0x02 0x40 0x02 0x00 0xYY - last digit erased
0xAA 0x00 0x02 0x40 0x03 0x00 0xYY - passkey cleared
0xAA 0x00 0x02 0x40 0x04 0x00 0xYY - entry completed
User Confirm Pairing Method

The user confirmation method is a very simple method relying of user’s feedback. It tries to make sure that at the time of the pairing the user has both devices under physical control. The pairing request will exchange a random passkey and display it on both devices. The user should check that the passkey matches on both devices and confirm or reject with a simple “yes” or “no” answer.

Implementation
The implementation can be found at https://github.com/kubovy/mclib/blob/master/components/bm78_pairing.c. Basically, the first two methods do not need any extra implementation. The last two, the passkey method and the user confirm method, have sample implementation realized in two function:
inline void BMP_bm78PairingEventHandler(BM78_Response_t response, uint8_t *data) {
uint8_t i;
switch (response.op_code) {
case BM78_EVENT_PASSKEY_ENTRY_REQ:
LCD_clear();
LCD_setString("New Pairing Request ", 0, true);
LCD_setString(" Code: ", 1, true);
LCD_setString("D) Delete Clear (B", 2, true);
LCD_setString("C) Confirm Abort (A", 3, true);
BMP_cancel();
BMP_passkeyCodeIndex = 0;
break;
case BM78_EVENT_PAIRING_COMPLETE:
LCD_clear();
switch(response.PairingComplete_0x61.result) {
case BM78_PAIRING_RESULT_COMPLETE:
LCD_setString(" New Device Paired ", 1, true);
break;
case BM78_PAIRING_RESULT_FAIL:
LCD_setString(" Pairing Failed! ", 1, true);
break;
case BM78_PAIRING_RESULT_TIMEOUT:
LCD_setString(" Pairing Timed Out! ", 1, true);
break;
default:
break;
}
BMP_cancel();
break;
case BM78_EVENT_PASSKEY_DISPLAY_YES_NO_REQ:
LCD_clear();
LCD_setString("New Pairing Request ", 0, true);
LCD_setString(" Code: ", 1, false);
for (i = 0; i < 6; i++) {
LCD_replaceChar(response.PasskeyDisplayYesNoReq_0x62.passkey[i],
10 + i, 1, false);
}
LCD_displayLine(1);
LCD_setString("C) Confirm Abort (A", 3, true);
BMP_cancel();
BMP_waitingForPasskeyConfirmation = true;
break;
case BM78_EVENT_DISCONNECTION_COMPLETE:
BMP_cancel();
break;
default:
break;
}
}
void BMP_processKey(uint8_t key) {
if (BMP_passkeyCodeIndex < 0xFF) { // Pairing Passkey
if (key >= '0' && key <= '9') { // Digit
BM78_execute(BM78_CMD_PASSKEY_ENTRY_RES, 2,
BM78_PAIRING_PASSKEY_DIGIT_ENTERED, key);
LCD_replaceChar(key, (BMP_passkeyCodeIndex++) + 10, 1, true);
} else if (key == 'B') { // Clear
BM78_execute(BM78_CMD_PASSKEY_ENTRY_RES, 2,
BM78_PAIRING_PASSKEY_CLEARED, 0x00);
LCD_replaceString(" ", 10, 1, true);
BMP_passkeyCodeIndex = 0;
} else if (key == 'C') { // Confirm
BM78_execute(BM78_CMD_PASSKEY_ENTRY_RES, 2,
BM78_PAIRING_PASSKEY_ENTRY_COMPLETED, 0x00);
LCD_clear();
BMP_passkeyCodeIndex = 0xFF;
} else if (key == 'D') { // Delete
BM78_execute(BM78_CMD_PASSKEY_ENTRY_RES, 2,
BM78_PAIRING_PASSKEY_DIGIT_ERASED, 0x00);
LCD_replaceChar(' ', (--BMP_passkeyCodeIndex) + 10, 1, true);
}
} else if (BMP_waitingForPasskeyConfirmation) {
switch(key) { // Pairing Confirmation
case 'C': // Confirm (YES)
LCD_clear();
LCD_setString(" Pairing Confirmed ", 1, true);
BM78_execute(BM78_CMD_USER_CONFIRM_RES, 1,
BM78_PAIRING_USER_CONFIRM_YES);
BMP_waitingForPasskeyConfirmation = false;
break;
case 'A': // Abort (NO)
LCD_clear();
LCD_setString(" Pairing Aborted ", 1, true);
BM78_execute(BM78_CMD_USER_CONFIRM_RES, 1,
BM78_PAIRING_USER_CONFIRM_NO);
BMP_waitingForPasskeyConfirmation = false;
break;
}
}
}
Conclusion
I never got the Passkey Pairing method working properly. I guess there is something wrong with my BM78 module. But anyway it requires the user to be actually able to enter the digits, which is not the case in most of my projects. If the device you are building has a display the User Confirm method is ok. In smaller devices without the option of user interaction one of, Just Works method or PIN method, needs to be used. I will use mostly the PIN method.
I would recommend to allow pairing by default when no devices are paired. After that the MCU should disable it. Manual enablement of pairing additional devices or complete memory clear will be then needed before pairing another or different device.