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-28
Revision:
2:3a28bc9332b6
Parent:
1:5ed110051e39
Child:
3:2a87c102ddd3

File content as of revision 2:3a28bc9332b6:

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

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_Timeout=        201;
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)
{
    this->setDev_UART(baudrate, bit, parity, stop);

    // attach rxIrq. because, rx buf of serial equals to 16 Bytes.
    this->rn41.attach(this, &RN41::_readIrq, Serial::RxIrq);

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

int RN41::connect(string addr)
{
    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入れず
    if(!disconnect())
        return ERR_Disconnect;
    if(!enterCMD())
        return ERR_EnterCmdMode;       // CMD入れず

    sendCMD("C,"+ addr);
    bool2 find;
    find= chkReply("TRYING\r", 1000, "ERR\r");    // within waiting for Reply

    // TRYINGが返って来ない場合
    if(!find.b1)
        return ERR_Connect;

    // Trying to connect to remote Bluetooth dev.
    find= chkReply("CONNECT,", 10000, "CONNECT failed\r");    // wait 10s(max)

    if(find.b1)
        return OK;
    if(find.b2)
        return FAIL_Connect;

    return ERR_Timeout;
}

string RN41::read()
{
    _read();
    if(rxStrStored.empty() && rxStr.empty())
        return "";

    string tmp= rxStrStored+ rxStr;
    rxStr.erase();
    rxStrStored.erase();
    return tmp;
}

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

    if(rxStrStored.empty() && rxStr.empty())
        return "";

    int idx= rxStr.rfind('\r');
    if(idx != string::npos) {       // CR存在
        if(rxStr[++idx] == '\n')
            idx++;
        rxStrStored += rxStr.substr(0, idx);  // size
        rxStr= rxStr.substr(idx);             // idx
    }
    // rxStrはCRなし、rxStrStoredに調整済み

    string tmp= rxStrStored;
    rxStrStored.erase();
    return tmp;
}


int RN41::setDev_UART(int baud, int bit, int parity, int stop)
{
    rn41.baud(baud);

    // 力技
    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
    else
        return NG;

    // 9,600bps -> 1,200B/s -> 833us/B. 0.1文字×13回待ちする(安全率30%)。
//    usWait4readBuf= (int)( (float)800000 / (float)baud );
//    if(usWait4readBuf < 1)usWait4readBuf= 1;

    return OK;
}


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);
    if(chkReply("AOK\r", 1000).b1)
        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).b1)    // 500ms
        return true;

    sendCMD("\r", false);           // 既にCMDモード
    if(chkReply("?\r", 500).b1)
        return true;
        
    return false;
}

bool RN41::disconnect()
{
    if(!enterCMD())
        return false;       // CMD入れず
    sendCMD("K,");     // rtn KILL ? / ERR ?

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


RN41::bool2 RN41::chkReply(string cmp1, int timeout, string cmp2, bool wCR) // withCR
{
    // BT外側から文字列が到着しないと仮定。
    // 目的単語は、取り逃していないと仮定。

    if(rxStr[0] == '\n')
        rxStr= rxStr.substr(1);

    timer.start(true);      // for Timeout
    int idxCR;//, idx1, idx2;//, idxCut;
//    bool2 find;//1, find2;
    bool2 find, tmpFind;
    string tmpStr;


    find.b1= find.b2= false;    // rxStr全てを確認するために、trueのみ上書きしていく。
    while(true) {
        _read();
        // rxStrを確認する。

        idxCR= rxStr.find('\r');
        if(idxCR != string::npos) {     // CR found.
            // 通常通信、目的語(wCR)、目的語(woCR)+通常通信。の3パターンのみのはず。

            // tmpに切り取って確認する。
            idxCR++;
            if(rxStr[idxCR] == '\n')
                idxCR++;
            // rxStr[idxCR]は次の文字列のidx
            tmpStr= rxStr.substr(0, idxCR); // substr(idx, count)
            rxStr=  rxStr.substr(idxCR);

            tmpFind= chkReply_line(tmpStr, cmp1, cmp2);
            if(tmpFind.b1)
                find.b1= true;
            if(tmpFind.b2)
                find.b2= true;
            if(!(tmpFind.b1 || tmpFind.b2))     // 通常通信
                rxStrStored += tmpStr;
        } else {
            // CRなし
            tmpFind= chkReply_line(rxStr, cmp1, cmp2);
            // この時点で、tmpとfindの両方がTrueの場合、目的のリプが2回出てきた。おかしい。
            // とりあ、そのケースは無視。
            if(tmpFind.b1)
                find.b1= true;
            if(tmpFind.b2)
                find.b2= true;

            bool flagRtn= false;
            if(find.b1||find.b2)
                flagRtn= true;

            // Return準備
            if( wCR && (tmpFind.b1||tmpFind.b2))
                flagRtn= false;

            if(!wCR && (tmpFind.b1||tmpFind.b2)) {
                int idx1, idx2;
                idx1= rxStr.find(cmp1);
                if(!cmp2.empty())
                    idx2= rxStr.find(cmp2);
                else
                    idx2= string::npos;

                if(idx1 != string::npos)
                    idx1 += cmp1.size();
                else
                    idx1= 0;
                if(idx2 != string::npos)
                    idx2 += cmp2.size();
                else
                    idx2= 0;

                if(idx1 < idx2)
                    idx1= idx2;
                rxStr= rxStr.substr(idx1);
            }

            if(flagRtn)
                return find;
        }

        if(timer.read_ms(false, false, false) > timeout)
            return find;
        wait_ms(2);     // 1ms waiting.
    }   // end while
}

RN41::bool2 RN41::chkReply_line(string trg, string cmp1, string cmp2)   //, bool wCR) // withCR
{
    bool2 tmp;
    tmp.b1= tmp.b2= false;

    if(    trg.find(cmp1) != string::npos)
        tmp.b1= true;
    if(!cmp2.empty())
        if(trg.find(cmp2) != string::npos)
            tmp.b2= true;

    return tmp;
}


/*
int RN41::chkReply(string cmp1, int timeout, string cmp2)
{
//    _read();//    rxStrStored += rxStr;

    timer.start(true);
//    int cmp2Size= cmp2.size();
    int idxCR, idx;//1, idx2;//, idxCut;
    bool find1, find2;

    // RxStrのチェック必要じゃね?初期化とか
    while(true) {
        _read();
        idxCR= rxStr.find('\r');
        if(idxCR != string::npos) {     // CR found.
            // 最初のCRまでを確認。
            find1= find2= false;
            // idx1: 0< or npos, idx2: 0< or npos(notfined or size0)
            //idx1(~CR) -> idx2(~CR)
            idx= rxStr.find(cmp1);
            if((idx != string::npos) && (idx < idxCR))
                find1= true;

            if(!cmp2.empty()) { //(cmp2.size() != 0) {
                idx= rxStr.find(cmp2);
                if((idx != string::npos) && (idx < idxCR))
                    find2= true;
            }

            // CRまで切り取り。findならば削除。見つからなければ目的でない、通常通信とみなし、コピー。
            idxCR++;//idxCut= idxCR+ 1;
            if(rxStr[idxCR] == '\n')
                idxCR++;
            // 切り捨てはidxからの切り取りを上書き。コピーは文字数。
            if(!(find1 || find2))
                rxStrStored += rxStr.substr(0, idxCR);
            rxStr= rxStr.substr(idxCR);        // 切り取りは共通。

            if(find1 && find2)     // find1有、find2有
                return findCmp12;
            if(find1)
                return findCmp1;
            if(find2)
                return findCmp2;
            // CR内にCMP無い場合は、ループへ
        }   // (idxCR != string::npos)

        if(timer.read_ms(false, false, false) > timeout)
            return ERR_Timeout;
        wait_ms(2);     // 1ms waiting.
    }   // end for
}
bool RN41::chkReply_woCR(string cmp, int timeout)
{
//    _read();rxStrStored += rxStr;

    timer.start(true);
    int idx, idxCR;
    while(true) {
        _read();
        idx= rxStr.find(cmp);

        if(idx != string::npos) {
            idxCR= rxStr.find('\r');

            if(idxCR == string::npos)
                rxStr.erase();      // 目的の単語のみと判断する。使用済みなので消去。
            else {      // CR存在するので、目的単語の前後で意図が異なる。
                idxCR++;
                if(rxStr[idxCR] == '\n')
                    idxCR++;
                // CR後の最初の文字位置

                rxStr= rxStr.substr(idx);
            }
            return true;
        }

        if(timer.read_ms(false, false, false) > timeout)
            return false;
        wait_ms(2);
    }
}
*/


void RN41::_readIrq(void)
{
    if(rn41.readable())
        rxStr += (char)rn41.getc();
    return;
}
void RN41::_read()
{
    // Bufferを吸い尽くす
    while(rn41.readable())
        rxStr += (char)rn41.getc();

    return;         // Bufferになくなった
}
/*
void RN41::_read()
{
    // Bufferを吸い尽くす
    // bps(Baudrate)から一文字分待ち、それでも受信がなければBuf空と判断。
    int iter= 0;
    while(true) {
        if(rn41.readable()) {
            rxStr += (char)rn41.getc();
            iter= 0;    //reset
        } else {
            wait_us(usWait4readBuf);
            iter++;
            if(iter > 13)   // 安全率30%
                return;         // Bufferになくなった
        }
    } // end while
}
*/

// EOF