RN41/42 control lib. RN41/42 is bluetooth module with class 1 or 2.

Dependencies:   StrLib myTimer RingBuffer

Dependents:   Theremin

RN41.cpp

Committer:
AkinoriHashimoto
Date:
2015-10-20
Revision:
0:812e6b59aa54
Child:
1:5ed110051e39

File content as of revision 0:812e6b59aa54:

#include "RN41.h"
//#include "SerialBase.h"

//extern void sendHC05(string);



const int RN41::NG=                   0;
const int RN41::OK=                   1;

// PRIVATE
const int RN41::findCmp12=          100;
const int RN41::findCmp1=           101;
const int RN41::findCmp2=           102;

// PUBLIC
const int RN41::ERR_AddrUnder12=    210;
const int RN41::ERR_AddrOver12=     211;
const int RN41::ERR_Connect=        220;
const int RN41::FAIL_Connect=       221;
const int RN41::ERR_EnterCmdMode=   230;
const int RN41::ERR_Disconnect=     240;

const int RN41::ERR_NameSize=       310;

/*
const int RN41::None=                10;
const int RN41::Odd=                 11;
const int RN41::Even=                12;
*/



RN41::RN41(PinName TX, PinName RX, int baudrate, int bit, int parity, int stop, bool CRLN)
    : rn41(TX, RX)
{
    rn41.baud(baudrate);
    /*
        Parity _parity= SerialBase::None;      // enum
        if(parity == 'O')
            _parity= SerialBase::Odd;
        if(parity == 'E')
            _parity= SerialBase::Even;
        rn41.format(bit, _parity, stop);     // 8bit, NonParity, 1stopbit
    */

    // 力技
    if      (parity == SerialBase::Odd)
        rn41.format(bit, SerialBase::Odd,  stop);
    else if (parity == SerialBase::Even)
        rn41.format(bit, SerialBase::Even, stop);     // 8bit, NonParity, 1stopbit
    else// if (parity == SerialBase::None)
        rn41.format(bit, SerialBase::None, stop);     // 8bit, NonParity, 1stopbit

    CR= '\r';
    if(CRLN)
        CR= "\r\n";
}


int RN41::connect(string addr)
{
    timerLocal.reset();
    timerLocal.start();

    addr= toAlpanumeric(addr, true);
    int idx= addr.size();
    // ex. 0006:66:72:6e05\r ->000666726e05.
    if(idx < 12)
        return ERR_AddrUnder12;
    if(idx > 12)
        return ERR_AddrOver12;

    if(!enterCMD())
        return ERR_EnterCmdMode;       // CMD入れず
//    sendHC05("test 100");
    if(!disconnect())
        return ERR_Disconnect;
    if(!enterCMD())
        return ERR_EnterCmdMode;       // CMD入れず

    // BT addr check success;
    sendCMD("C,"+ addr);
    int status;

//    wait(1.0);read();sendHC05("--"+ rxStr+ "**");

    status= chkReply("TRYING\r", 1000, "ERR\r");
    if(status == findCmp2)
        return ERR_Connect;
    else if(status == findCmp1) {
        // Trying to connect to remote Bluetooth dev.

//        wait(7.0);        read();        sendHC05(rxStr);
        timerLocal.reset();
        timerLocal.start();
        status= chkReply("CONNECT,", 10000, "CONNECT failed\r");    // wait 10s

//        sendHC05("Time of Create-Connection: "+ I2A(timerLocal.read_ms())+ " ms.");

        if(status == findCmp1)
            return OK;
        else if(status == findCmp2)
            return FAIL_Connect;
    } else {
//        sendHC05("connect:"+ I2A(status));
    }
    return 1234;
}




string RN41::getLine()
{
    read();
    // CRまでを返す

//sendHC05("debug 10");
    if(str4GetLine.size()==0 && rxStr.size()==0)
        return "";

// trying->Connect待ちをTickerにすると、そこんとの除外処理が必須。
//    sendHC05("debug 20");

    // rxStr.size() > 0
    int idx= rxStr.rfind(CR);
//    sendHC05("rxStr: "+ rxStr);    sendHC05("idxCR: "+ I2A(idx));
    if(idx == string::npos)     // not find CR!
        return str4GetLine;     // ダメじゃね??

//    sendHC05("debug 30");
    // rxStr has CR.
    idx += CR.size();   // \rなら+1、\r\nは+2
    string rtn= str4GetLine;
    rtn += rxStr.substr(0, idx);   // 切り取り
    rxStr= rxStr.substr(idx);
//    sendHC05("debug 40");
    return rtn;
}



int RN41::setDev_Name(string str, bool usingAddr)
{
    int strSize= str.size();
    if((strSize==0) || (20<=strSize) || (usingAddr && 15<=strSize))
        return ERR_NameSize;

    // 特殊文字チェックは不要っぽい

    string cmd;
    if(usingAddr)
        cmd= "S-,";
    else
        cmd= "SN,";

    if(!enterCMD())
        return ERR_EnterCmdMode;       // CMD入れず


    sendCMD(cmd+ str);
    int status;
//    wait(1.0);read();sendHC05("--"+ rxStr+ "**");
    status= chkReply("AOK\r", 1000);
    if(status == findCmp1)
        return OK;

    return NG;
}


void RN41::sendCMD(string str, bool addCR)
{
    if(addCR)
        str += '\r';
    rn41.printf(str.c_str());
    return;
}
void RN41::sendLINE(string str, bool addCR)
{
    if(addCR)
        str += "\r\n";
    rn41.printf(str.c_str());
    return;
}



bool RN41::enterCMD()
{
    sendCMD("$$$", false);
    if(chkReply("CMD\r", 500) == findCmp1) {    // 500ms
//        sendHC05("returned CMD.");
        return true;
    }

    sendCMD("\r", false);           // 既にCMDモード
    if(chkReply("?\r", 500) == findCmp1) {
//        sendHC05("Already CmdMode.");
        return true;
    }
    return false;
}



bool RN41::disconnect()
{
    //    if(!enterCMD())        return false;       // CMD入れず

    sendCMD("K,");     // rtn KILL ? / ERR ?
    int status;
//    wait(6.0);    read();    sendHC05("in disconnect; \t"+ rxStr);

    status= chkReply("KILL\r", 500, "ERR\r");
    if(status == findCmp2) {    // 既に切断されている
        sendCMD("---");        // exit CMD mode.
        if(chkReply("END\r", 500) == findCmp1)
            return true;
        else// {            leds.ON(4);
            return false;   // どういう状況か不明
    } else if(status == findCmp1) {
//        if(chkReply("DISCONNECT", 2000) == findCmp1)
        if(chkReply_woCR("DISCONNECT", 5000))  // CR無いかも?
            return true;
        else //{            leds.ON(3);
            return false;   // どういう状況か不明
    }// else {        return false;    }
    return false;
}




int RN41::chkReply(string cmp1, int timeout, string cmp2)
{
    timerLocal.reset();
    timerLocal.start();

    int cmp2Size= cmp2.size();
    int idxCR, idx1, idx2;//= string::npos;
    bool find1, find2;
    for(;;) {
        if(timerLocal.read_ms() > timeout)
            return NG;

        read();
        idxCR= rxStr.find_first_of('\r');
        if(idxCR != string::npos) {     // CR found.
            idx1= idx2= string::npos;   // -1
            find1= find2= false;
            idx1= rxStr.find(cmp1);
            if(cmp2Size != 0)
                idx2= rxStr.find(cmp2);

            // idx1: 0< or npos, idx2: 0< or npos(notfined or size0)
            int idxCut;
            //idx1(~CR) -> idx2(~CR)
            if(idx1 != string::npos)
                if(idx1 < idxCR)
                    find1= true;
            if(idx2 != string::npos)
                if(idx2 < idxCR)
                    find2= true;

//sendHC05("++"+ rxStr+ "**");
//sendHC05("idx1:"+cmp1+":"+ I2A(idx1)+ "\tidx2:"+cmp2+":"+ I2A(idx2)+ "\tidxCR:"+ I2A(idxCR));

            // CRまで切り取り。findならば切り捨て、見つからなければコピー後切り捨て
            idxCut= idxCR+ 1;
            if(rxStr[idxCut] == '\n')
                idxCut++;
            // 切り捨てはidxからの切り取りを上書き。コピーは文字数なので、idxが-1まで。
            if(!(find1 || find2))
                str4GetLine= rxStr.substr(0, idxCut);
            rxStr= rxStr.substr(idxCut);        // 切り取りは共通。

            if(find1 && find2)     // find1有、find2有
                return findCmp12;
            if(find1)
                return findCmp1;
            if(find2)
                return findCmp2;
            // CR内にCMP無い場合は、ループへ
        }
    }   // end for
}


bool RN41::chkReply_woCR(string cmp, int timeout)
{
    timerLocal.reset();
    timerLocal.start();

    int idx;
    for(;;) {
        if(timerLocal.read_ms() > timeout) {
//            sendHC05("in chkReply; "+ rxStr);
            return false;
        }
        read();
        idx= rxStr.find(cmp);
        if(idx != string::npos) {
            // めんどいから消去する。
            idx= rxStr.find_first_of('\r');
            if(idx == string::npos)
                rxStr= "";
            else {
                idx++;
                if(rxStr[idx] == '\n')
                    idx++;
                rxStr= rxStr.substr(idx);
            }
//            rxStr= "";
            return true;
        }
    }
}




void RN41::read()
{
    if(!rn41.readable())
        return;

    // Bufferを吸い尽くす
//    char ch;
    for(;;) {
//        char ch= rn41.getc();    // 1文字取る
//        ch= rn41.getc();    // 1文字取る
//        rxStr += ch;            // 上書き前に退避
        rxStr += (char)rn41.getc();
        if(!rn41.readable())
            return; //break;    // Bufferになくなった
    } // end for
}