⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 蓝牙点对点通信程序
💻 C
字号:
/*
  SPP master
*/

#include <cm_rfcomm.h>
#include <message.h>
#include <panic.h>
#include <pio.h>
#include <ps.h>
#include <sched.h>
#include <stream.h>
#include <timer.h>
#include <vm.h>

/* Don't enable this on chip; the application will stop running */
/* #define DEBUG_PRINT_ENABLED */
#include <print.h>

#include <stdlib.h>
#include <string.h>

#include "spp_master_service_record.h" /* Autogenerated from spp_master.sdp */

#include "../spp_common/config.h"
#include "../spp_common/invalid.h"
#include "../spp_common/lights.h"
#include "../spp_common/store.h"
#include "../spp_common/transport.h"

/* The UID of the SerialPort profile */

#define SERIAL_PORT 0x1101

/* The pin key. You probably want to change this */

static const uint16 THE_PIN[8] = { 'N', 'o', 'P', 'i', 'n', 'S', 'e', 't' };

/* Program state */

static enum { starting, inquiring, pairing, connecting, active } state = starting;
static uint16 have_paired = 0;

/* Report current state of play */

#ifdef DEBUG_PRINT_ENABLED
static void status(const char *s)
{
    PRINT(("State %d, far addr %lx %x %x, event %s\n", state, far_addr.lap, far_addr.nap, far_addr.uap, s));
}
#else
#define status(s) (void) 0
#endif

/* Send requests to the connection manager */

static void cm_init_req(void)
{
    /* Send first message to connection manager before starting scheduler */
    MAKE_MSG(CM_INIT_REQ);
    MessagePut(CM, msg);
}

static void cm_open_req(void)
{
    MAKE_MSG(CM_OPEN_REQ);
    msg->sizeServiceRecord = sizeof(spp_master_service_record);
    msg->serviceRecord = PanicNull(malloc(sizeof(spp_master_service_record)));
    memcpy(msg->serviceRecord, spp_master_service_record, sizeof(spp_master_service_record));
    msg->classOfDevice = 0;
    MessagePut(CM, msg);
}

static void cm_write_cod(void)
{
    MAKE_MSG(CM_WRITE_COD_REQ); 
    msg->class_of_device = CLASS_OF_DEVICE;
    MessagePut(CM, msg);
}

static void cm_connect_as_master_req(void)
{
    MAKE_MSG(CM_CONNECT_AS_MASTER_REQ);
    config_use(&msg->use);
    config_park(&msg->park);
    config_sniff(&msg->sniff);
    /* Look for a serial port at the far end */
    msg->bd_addr       = far_addr;
    msg->target        = SERIAL_PORT;
    msg->timeout       = D_SEC(60);
    msg->max_framesize = MAX_FRAMESIZE;
    MessagePut(CM, msg);
}

static void cm_cancel_req(void)
{
    MAKE_MSG(CM_CANCEL_REQ);
    MessagePut(CM, msg);
}

static void cm_disconnect_req(void)
{
    MAKE_MSG(CM_DISCONNECT_REQ);
    msg->link_type = RfcommConnection;
    msg->addr      = far_addr;
    MessagePut(CM, msg);
}

static void cm_inquiry_req(void)
{
    MAKE_MSG(CM_INQUIRY_REQ);
    msg->max_responses   = 8;
    msg->inq_timeout     = D_SEC(60);
    msg->class_of_device = CLASS_OF_DEVICE;
    msg->remote_name_request_enabled = 0;
    MessagePut(CM, msg);
}

static void cm_pair_req(void)
{
    MAKE_MSG(CM_PAIR_REQ);
    msg->role           = CmMaster;
    msg->timeout        = D_SEC(10);
    msg->authentication = 1;
    msg->bd_addr        = far_addr;
    MessagePut(CM, msg);
}

static void cm_add_sm_device_req(const uint8 *link_key)
{
    MAKE_MSG(CM_ADD_SM_DEVICE_REQ);
    msg->addr = far_addr;
    memcpy(msg->link_key, link_key, SIZE_LINK_KEY);
    msg->trust = 1;
    MessagePut(CM, msg);
}

static void cm_pin_code_res(const BD_ADDR_T *addr)
{
    MAKE_MSG(CM_PIN_CODE_RES);
    bool accept = !know_far_addr() || (far_addr.nap == addr->nap && far_addr.lap == addr->lap && far_addr.uap == addr->uap);
    msg->addr = *addr;
    msg->pin_length = accept ? sizeof(THE_PIN) < 8 ? sizeof(THE_PIN) : 8 : 0;
    memcpy(msg->pin, THE_PIN, msg->pin_length);
    MessagePut(CM, msg);
}

static void cm_link_key_res(const BD_ADDR_T *other)
{
    MAKE_MSG(CM_LINK_KEY_RES);
    msg->accept = far_addr.lap == other->lap
        && far_addr.nap == other->nap
        && far_addr.uap == other->uap
        && read_link_key(msg->key_val);
    msg->addr = *other;
    if(!msg->accept) memset(msg->key_val, 0, SIZE_LINK_KEY);
    MessagePut(CM, msg);
}

/* Keep a list of addresses we've tried before without success */

enum { FAILED_SIZE = 8 };
static BD_ADDR_T failed_addr[FAILED_SIZE];

static uint16 tried_and_failed(const BD_ADDR_T *addr)
{
    static uint16 failed_next;
    uint16 i;
    for(i = 0; i < FAILED_SIZE; ++i)
        if(failed_addr[i].lap == addr->lap
           && failed_addr[i].nap == addr->nap
           && failed_addr[i].uap == addr->uap)
            return 1;
    failed_addr[failed_next] = *addr;
    ++failed_next;
    if(failed_next == FAILED_SIZE) failed_next = 0;
    return 0;
}

/* Handle incoming messages from the connection manager */

static void forward(void)
{
    if(!know_far_addr())
    {
        /* If we don't know who we're meant to be talking to, start looking. */
        status("Inquiring");
        cm_inquiry_req();
        state = inquiring;
        lights_inquiring();
    }
    else if(!have_paired)
    {
        /* If we know who is at the far end, but we're not paired, do that now. */
        status("Pairing");
        cm_pair_req();
        state = pairing;
        lights_pairing();
    }
    else
    {
        /* If we get here, we know who's at the far end and we've paired with them. Connect. */
        status("Connecting");
        cm_connect_as_master_req();
        state = connecting;
        lights_connecting();
    }
}

DECLARE_TASK(1)
{
    MessageType type ;
    void * msg = MessageGet(1,&type) ;
    if (msg)
    {
        switch (type) 
        {
        case CM_INIT_CFM:
            status("init_cfm");
            cm_open_req();
            break;

        case CM_OPEN_CFM:
            status("open_cfm");
            cm_write_cod();
            forward();
            break;

        case CM_SERVICE_REGISTER_CFM:
            /* Don't care */
            break;

        case CM_CONNECT_CFM:
        {
            CM_CONNECT_CFM_T *prim = (CM_CONNECT_CFM_T *) msg;
            connect_status_t result = prim->status;
            if(result == CmConnectComplete)
            {
                Source rfcomm_source = prim->source;
                Sink rfcomm_sink = prim->sink;
                status("connect_cfm complete");

                PanicFalse(TransportConnect(rfcomm_source, rfcomm_sink));

                state = active;
                lights_connected();
            }
            else
            {
                status("connect_cfm failure");
                forward();
            }
        }
        break;

        case CM_CONNECT_STATUS_IND:
            /* Disconnected. Start again. */
            status("connect_status_ind");
            forward();
            break;

        case CM_INQUIRY_RESULT_IND:
        {
            CM_INQUIRY_RESULT_IND_T *prim = (CM_INQUIRY_RESULT_IND_T *) msg;
            status("inquiry_result_ind");
            if(!tried_and_failed(&prim->inq_result.bd_addr))
            {
                far_addr = prim->inq_result.bd_addr;
                cm_cancel_req();
                /* Will issue next request after INQUIRY_COMPLETE_CFM */
            }
        }
        break;

        case CM_INQUIRY_COMPLETE_CFM:
        {
            status("inquiry_complete_cfm");
            forward();
        }
        break;

        case CM_PAIR_CFM:
        {
            CM_PAIR_CFM_T *prim = (CM_PAIR_CFM_T *) msg;
            status("pair_cfm");
            switch(prim->status)
            {
            case CmPairingNotFinished:
                /* We get the link key here */
                write_link_key(prim->link_key);
                break;
            case CmPairingComplete:
                /* But pairing isn't complete until this message arrives */
                write_far_addr();
                have_paired = 1;
                forward();
                break;
            case CmPairingTimeout:
            case CmPairingCancelled:
            case CmPairingFail:
                /* Didn't work */
                have_paired = 0;
                clear_far_addr();
                forward();
                break;
            }
        }  
        break;

        case CM_PIN_CODE_REQ:
            status("cm_pin_code_req");
            cm_pin_code_res(&((CM_PIN_CODE_REQ_T *) msg)->addr);
            break;

        case CM_LINK_KEY_REQ:
            status("cm_link_key_req");
            cm_link_key_res(&((CM_LINK_KEY_REQ_T *) msg)->addr);
            break;

        case CM_CONTROL_IND:
            TransportModemStatusControl((CM_CONTROL_IND_T *)msg);
            break;

        case CM_ERROR_IND:
        {
            cm_error_t error = ((CM_ERROR_IND_T *) msg)->error;
            if(error >= CmWarnLocalSniffNotEnabled || error == CmErrorCancelWhenIdle)
            {
                /* Ignore warnings */
                break;
            }
            PRINT(("Error %d\n", error));
        }
        /*lint -fallthrough and panic */
        default:
            /* Unexpected message */
            PRINT(("Type %d\n", type));
            status("Panic");
            Panic();
            break;
        }
        MessageDestroy(msg);
    }
}

static void appPioEvent(uint16 pressed)
{
    if(BUTTON_DOWN(pressed))
    {
        have_paired = 0;
        clear_far_addr();
        clear_link_key();
        memset(failed_addr, 0, sizeof(failed_addr));

        status("button pressed");

        switch(state)
        {
        case starting:
            break;
        case pairing:
        case connecting:
        case inquiring:
            cm_cancel_req();
            break;
        case active:
            cm_disconnect_req();
            break;
        }
        state = starting;
    }
    invalid_update(pressed);
}

static const uint16 INPUT = BUTTON | INVALID;

const SchedPioEntry applicationPioEntry = { &INPUT, appPioEvent };

int main(void)
{
    /* Refuse to run unless the transport has been successfully initialised */
    if(TransportInit())
    {
        /* Tell scheduler we are using our pio entry */
        SchedPioEntryChanged();
        
        /* Enable the LEDs as outputs, other lines as inputs */
        PioSetDir(LED_CONNECT|LED_POWER|BUTTON|INVALID, LED_CONNECT|LED_POWER);

#ifdef CSR_APPLICATION_HARDWARE
        PioSet(BUTTON|INVALID, ~0);  /* Enable VERY weak pull-ups */
        PioSet(LED_CONNECT | LED_POWER, LED_CONNECT); /* only power on initially */
#else
        PioSet(LED_CONNECT, 0);
#endif
        invalid_update(PioGet());
        read_far_addr();
        if(know_far_addr())
        {
            uint8 link_key[SIZE_LINK_KEY];
            if(read_link_key(link_key))
            {
                cm_add_sm_device_req(link_key);
                have_paired = 1;
            }
        }
        status("Init");
        TimerInit();
        cm_init_req();
        Sched();
    }
    return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -