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-22
Revision:
1:5ed110051e39
Parent:
0:812e6b59aa54
Child:
2:3a28bc9332b6

File content as of revision 1:5ed110051e39:

#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);
    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);
    int status;

    status= chkReply("TRYING\r", 1000, "ERR\r");    // within waiting for Reply

    if(status == findCmp2)
        return ERR_Connect;
    else if(status == findCmp1) {
        // Trying to connect to remote Bluetooth dev.
        status= chkReply("CONNECT,", 10000, "CONNECT failed\r");    // wait 10s(max)
        if(status == findCmp1)
            return OK;
        else if(status == findCmp2)
            return FAIL_Connect;
        else if(status == ERR_Timeout)
            return ERR_Timeout;
    }
    return 1234;
}


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

    if(str4GetLine.size()==0 && rxStr.size()==0)
        return "";

    int idx= rxStr.rfind(cr);
    if(idx == string::npos)     // not find CR!
        return str4GetLine;     // ダメじゃね??

    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_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;

    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);
    int status;
    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
        return true;


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



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

    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_woCR("DISCONNECT", 5000))  // CR無いかも?
            return true;
        else
            return false;   // どういう状況か不明
    }
    return false;
}

int RN41::chkReply(string cmp1, int timeout, string cmp2)
{
    timer.start(true);

    int cmp2Size= cmp2.size();
    int idxCR, idx1, idx2;
    bool find1, find2;

    // RxStrのチェック必要じゃね?初期化とか
    int idxCut;
    while(true) {
        if(timer.read_ms(false, false, false) > timeout)
            return ERR_Timeout;
        read();
        idxCR= rxStr.find('\r');
        if(idxCR != string::npos) {     // CR found.

            find1= find2= false;
            // idx1: 0< or npos, idx2: 0< or npos(notfined or size0)
            //idx1(~CR) -> idx2(~CR)
            idx1= rxStr.find(cmp1);
            if((idx1 != string::npos) && (idx1 < idxCR))
                find1= true;

            if(cmp2Size != 0) {
                idx2= rxStr.find(cmp2);
                if((idx2 != string::npos) && (idx2 < idxCR))
                    find2= true;
            }

            // 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無い場合は、ループへ
        }   // (idxCR != string::npos)
        wait_ms(2);     // 1ms waiting.
    }   // end for
}


bool RN41::chkReply_woCR(string cmp, int timeout)
{
    timer.start(true);

    int idx;
    while(true) {
        if(timer.read_ms(false, false, false) > timeout)
            return false;

        read();
        idx= rxStr.find(cmp);
        
        if(idx != string::npos) {
            idx= rxStr.find('\r');
            // find CRLF
            if(idx == string::npos)
                rxStr= "";
            else {
                idx++;
                if(rxStr[idx] == '\n')
                    idx++;
                rxStr= rxStr.substr(idx);
            }
            return true;
        }
        wait_ms(2);
    }
}




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

    // Bufferを吸い尽くす
    while(true) {
        rxStr += (char)rn41.getc();
        if(!rn41.readable())
            return;         // Bufferになくなった
    } // end for
}

// EOF