SparkFun Forums 

Where electronics enthusiasts find answers.

Have questions about a SparkFun product or board? This is the place to be.
By OldSchoolAirCool
#181983
Hello all,

I've recently been working with the BlueSMiRF HID as part of a prototype for a custom keyboard, and I've run into a problem entering command mode while the device is connected to a host over Bluetooth. The device particulars are as follows:

Firmware: v6.10 HID
Configuration is default, with the following exceptions:
Name: PrototypeKbd-XXXX (Where XXXX are the last 4 nibbles of the module's address.)
Operation Mode: Slave (0)
Bluetooth Profile: HID (6)
Config. Timeout: Local only, no timeout (253)

While disconnected, the device behaves predictably: command mode can be entered and exited, and all commands execute and respond per the User's Guide. However, once connected to a BT host, the command mode escape sequence ("$$$") passes directly through to the host as a series of keyboard events (per HID Translation Mode).

The only explanation I have left is that by allowing the host to initiate the connection, the dongle defaults to fast data mode, in which all traffic is passed to the host. Is this the case?

The below code segments are from my test application, the first of which configures the RN-42, and the second performs a connection status inquiry.
Code: Select all
int Bluetooth_RN42Config(void)
{
    int ret = 0;
    unsigned int resetRequired = 0;
    char terminalBuff[MAX_COMMAND_LENGTH] = {0x00};
    int i = 0;

    //Wait for the Bluetooth module to finish startup?  500ms.

    //Enter Configuration mode:
    BT_DMA_SEND_STRING_POLLED(ESC_START_COMMAND_MODE, 3);
    BT_DMA_RECEIVE_COMMAND_POLLED(terminalBuff);
    if(terminalBuff[0] == 'C' && terminalBuff[1] == 'M' && terminalBuff[2] == 'D')  //"CMD\r\n"
    {
        //In configuration mode - start device setup:
        //Check assigned name:
        BT_DMA_SEND_COMMAND_POLLED(COMMAND_GET_NAME);   
        BT_DMA_RECEIVE_COMMAND_POLLED(terminalBuff);
        if(terminalBuff[0] != 'P' || terminalBuff[1] != 'r' || terminalBuff[2] != 'o' ) //"PrototypeKbd-XXXX<CR>"
        {
            //Device has not been renamed yet - do so.
            BT_DMA_SEND_COMMAND_POLLED(COMMAND_SET_NAME);
            BT_DMA_RECEIVE_COMMAND_POLLED(terminalBuff);
            if(terminalBuff[0] != 'A' || terminalBuff[1] != 'O' || terminalBuff[2] != 'K')  //"AOK\r\n"
            {
                //ERROR - DEVICE RENAME FAILED
                //Find a way to recover?
                while(1){}
            }

            resetRequired = 1;
        }


        //Check operation mode = ??????:
        BT_DMA_SEND_COMMAND_POLLED(COMMAND_GET_OPMODE);
        BT_DMA_RECEIVE_COMMAND_POLLED(terminalBuff);
        /* Slave =      "Slav\r\n"  - 
         * Master =     "Mstr\r\n"  - NO COMMAND WHILE CONNECTED
         * Trigger =    "Trig\r\n"  -
         * AC Master =  "Auto\r\n"
         * AC DTR =     "DTR \r\n"  - DEFAULT MODE
         * AC Any =     "Any \r\n"
         * Pairing =    "Pair\r\n"
         */
        if(terminalBuff[0] != 'S' || terminalBuff[1] != 'l' || terminalBuff[2] != 'a' ) //"Slav\r\n"
        {
            //Device opmode has not been reassigned - do it.
            BT_DMA_SEND_COMMAND_POLLED(COMMAND_SET_OPMODESLAVE);
            BT_DMA_RECEIVE_COMMAND_POLLED(terminalBuff);
            if(terminalBuff[0] != 'A' || terminalBuff[1] != 'O' || terminalBuff[2] != 'K')  //"AOK\r\n"
            {
                //ERROR - DEVICE OPMODE CHANGE FAILED!
                //Find a way to recover?
                while(1){}
            }

            resetRequired = 1;
        }


        //Check Bluetooth profile = HID:
        BT_DMA_SEND_COMMAND_POLLED(COMMAND_GET_PROFILE);
        BT_DMA_RECEIVE_COMMAND_POLLED(terminalBuff);
        if(terminalBuff[0] != '6' || terminalBuff[1] != '\r' || terminalBuff[2] != '\n' )   //"6\r\n"
        {
            //Device profile has not been reassigned - do so.
            BT_DMA_SEND_COMMAND_POLLED(COMMAND_SET_PROFILEHID);
            BT_DMA_RECEIVE_COMMAND_POLLED(terminalBuff);
            if(terminalBuff[0] != 'A' || terminalBuff[1] != 'O' || terminalBuff[2] != 'K')  //"AOK\r\n"
            {
                //ERROR - DEVICE PROFILE CHANGE FAILED!
                //Find a way to recover?
                while(1){}
            }

            resetRequired = 1;
        }


        //Check module special configuration:
        BT_DMA_SEND_COMMAND_POLLED(COMMAND_GET_SPECIALCONFIG);
        BT_DMA_RECEIVE_COMMAND_POLLED(terminalBuff);
        if(terminalBuff[0] != '0' || terminalBuff[1] != '\r' || terminalBuff[2] != '\n' )   //"0\r\n"
        {
            //Device profile has not been reassigned - do so.
            BT_DMA_SEND_COMMAND_POLLED(COMMAND_SET_SPECIALCONFIGDEFAULT);
            BT_DMA_RECEIVE_COMMAND_POLLED(terminalBuff);
            if(terminalBuff[0] != 'A' || terminalBuff[1] != 'O' || terminalBuff[2] != 'K')  //"AOK\r\n"
            {
                //ERROR - DEVICE PROFILE CHANGE FAILED!
                //Find a way to recover?
                while(1){}
            }

            resetRequired = 1;
        }


        //Check config timeout timer:
        BT_DMA_SEND_COMMAND_POLLED(COMMAND_GET_CONFIGTIMER);
        BT_DMA_RECEIVE_COMMAND_POLLED(terminalBuff);
        if(terminalBuff[0] != '2' || terminalBuff[1] != '5' || terminalBuff[2] != '3' )     //"253\r\n"
        {
            //Device config timeout has not been changed - do so.
            BT_DMA_SEND_COMMAND_POLLED(COMMAND_SET_CONFIGTIMERLOCAL);
            BT_DMA_RECEIVE_COMMAND_POLLED(terminalBuff);
            if(terminalBuff[0] != 'A' || terminalBuff[1] != 'O' || terminalBuff[2] != 'K')  //"AOK\r\n"
            {
                //ERROR - DEVICE CONFIG TIMER CHANGE FAILED!
                //Find a way to recover?
                while(1){}
            }

            resetRequired = 1;
        }

    }
    else
    {
        //CANNOT ENTER CONFIGURATION MODE!!!
        while(1){}
    }

    //See if we need to reset the device, or if we can just exit command mode:
    if(resetRequired)
    {
        //Reset the device and wait for it to power cycle.
        BT_DMA_SEND_COMMAND_POLLED(COMMAND_REBOOT);
        BT_DMA_RECEIVE_COMMAND_POLLED(terminalBuff);    //"Reboot\r\n"

        //Wait for the module to reactivate:
        Bluetooth_delayForReset();
    }
    else
    {
        //Send the command mode exit sequence.
        BT_DMA_SEND_COMMAND_POLLED(ESC_END_COMMAND_MODE);
        BT_DMA_RECEIVE_COMMAND_POLLED(terminalBuff);
        if(terminalBuff[0] != 'E' || terminalBuff[1] != 'N' || terminalBuff[2] != 'D')  //"END\r\n"
        {
            //Command mode exit failed.  Spin for debug.
            while(1){}
        }
    }

    return ret;
}

Code: Select all
int Bluetooth_isConnected(void)
{
    unsigned int ret = 0;
    static char temp[8] = {0x00};

    BT_DMA_SEND_STRING_POLLED(ESC_START_COMMAND_MODE, 3);
    BT_DMA_RECEIVE_COMMAND_POLLED(temp);    //NOTE: Execution hangs here when attempting to enter command mode while connected (device does not reply).
    if(temp[0] == 'C' && temp[1] == 'M' && temp[2] == 'D')
    {
        BT_DMA_SEND_COMMAND_POLLED(COMMAND_GET_CONNECTIONSTAT);
        BT_DMA_RECEIVE_COMMAND_POLLED(temp);

        if(temp[0] == '1') //"1,0,0\r\n"
        {
            ret = 1;
        }
    }
    else
    {
        //Enter command mode failed!
        while(1){}
    }
    BT_DMA_SEND_COMMAND_POLLED(ESC_END_COMMAND_MODE);
    BT_DMA_RECEIVE_COMMAND_POLLED(temp);
    if(temp[0] != 'E' && temp[1] != 'N' && temp[2] != 'D')
    {
        //Exit command mode failed!
        //Debug trap:
        while(1){}
    }

    return ret;
}

Essentially how these blocks are implemented in the test app:
Code: Select all
void main(void)
{
//Device/Peripheral configuration...

    Bluetooth_RN42Config();

    while(1)
    {
        if(Bluetooth_isConnected())
        {
            //Do test application things!
        }
        else
        {
            //Wait for something to talk to...
        }
    }

}
Thanks for your help,
Sean.