Bluetooth "extras"

Discussion specific to NXT-G, NXC, NBC, RobotC, Lejos, and more.
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: Bluetooth "extras"

Post by HaWe »

probably another problem:
as I have 3 slaves, I only have 3 mailboxes for each slave on the master. I use them for 1 outbox and 2 inboxes for each slave (on the slaves vice versa):

Code: Select all

// master: connection channels and mailboxes to the slaves.

#define BT_CONN_1 1 // Slave 1
#define OUTBOX_1  1 // out: bool or cmd_string
#define INBOX_11  2 // sensors + variables
#define INBOX_12  3 // ack (requested)

#define BT_CONN_2 2 // Slave 2
#define OUTBOX_2  4 // out: bool or cmd_string
#define INBOX_21  5 // sensors + variables
#define INBOX_22  6 // ack (requested)

#define BT_CONN_3 3 // Slave 3
#define OUTBOX_3  7 // out: bool or cmd_string
#define INBOX_31  8 // sensors + variables
#define INBOX_32  9 // ack (requested) 
the slave receives a remoteBool (value_request) and a remoteString (Exec_command) in the same inbox.
the 2 different outboxes are used to return
1) the requested value and
2) an acknoldge byte.

Wouldn't cause the fact problems, that both a bool and a string come in at a slave via the same inbox and require different handlings?

Code: Select all

// send and receive tasks on each slave

    #define BT_CONN   0
    #define INBOX     1 // requests and exec_commands
    #define OUTBOX_1  2 // sensor + variable values to send back
    #define OUTBOX_2  3 // acknowledge to send back

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
task BTReceive() {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  string in;
  int ack, len;
  char bResult;

  while(true) {
    in= "  ";

    JHSReceiveRemoteString(BT_CONN, INBOX, true, in, bResult); // INBOX: incoming cmd string containing exec_cmd

       ack=checksum(in);
       JHSSendResponseNumber(BT_CONN, OUTBOX_2, ack);   //  check / acknowledge
       Wait(1);
       __cmd=in;
       start ExecCmd;

    Wait(1);
  }
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
task BTMBxWrite() {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  string sn, sv;
  string fmtstr, buf, out;
  int i, dec;
  char bResult;

  while(true)   {
     out="";
     JHSReceiveRemoteBool( BT_CONN, INBOX, true, bResult);  // INBOX: incoming request to send values back

     for(i=0; i<11; i++) {  // Sensorports: 0...3  plus virtual ports
        GetSensorValues(i);
        dec=SensorValueDecimals[i];
        sn=NumToStr(dec);                          // value decimals
        fmtstr=StrCat("%",NumToStr(dec),"d");
        sv=FormatNum(fmtstr,SensorCurrArr);
        out = StrCat(out, sn, sv);
     } //  for port i=...

     if (StrLen(out)>58) strncpy(out,out,58);     // 58 = max msg length
     JHSSendResponseString(BT_CONN, OUTBOX_1, out);
     //TextOut(0, 0, out);
     Wait(1);

  } // while(true)
}

mcsummation
Posts: 220
Joined: 23 Jan 2012, 17:07
Location: Round Rock, TX

Re: Bluetooth "extras"

Post by mcsummation »

1) I found a NumOut in the JHSReceiveRemoteStruct routine which was there for debug and I did not get it deleted before uploading it to the web. Please download a fresh copy of the library.

2) Why can the master not use the same mailbox number for all slaves? Since you specify the connection number on the SendRemote... call, the BT hardware knows which slave to send the message to.

3) With the enhancement that John made so that the ReceiveRemote... calls (on the master) can specify which connection number (and therefore which slave) you could use the same mailboxes there, also. I implemented that function in the JHSReceiveRemote... calls.
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: Bluetooth "extras"

Post by HaWe »

1) I found a NumOut in the JHSReceiveRemoteStruct routine which was there for debug and I did not get it deleted before uploading it to the web. Please download a fresh copy of the library.
ok, will do so!
2) Why can the master not use the same mailbox number for all slaves? Since you specify the connection number on the SendRemote... call, the BT hardware knows which slave to send the message to.
that's fine, I didn't realize this new feature with it's new facilities! Great! +1
3) With the enhancement that John made so that the ReceiveRemote... calls (on the master) can specify which connection number (and therefore which slave) you could use the same mailboxes there, also. I implemented that function in the JHSReceiveRemote... calls.
fine! Thanks for clarification! +1
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: Bluetooth "extras"

Post by HaWe »

now I re-programmed my own BT send/receive functions using your new commands,
but the BT connection is faulty and finally hangs-up at all .... :(
(e.g. the master can't send or receive any commands or values to/from any slave any more: master tries to send, but slave obviously doesn't receive)

Before that, the connection worked unreliably, but at least sometimes it did what I expected...

this is for the master:

Code: Select all

#include "BT_JHS_TOOLS_H.nxc"
#include "CHESS_AI_ENGINE_H.nxc"

#define debug

// master: connection channels and mailboxes to the slaves.

#define BT_CONN_1 1 // Slave 1
#define BT_CONN_2 2 // Slave 2
#define BT_CONN_3 3 // Slave 3

#define OUTBOX_1  1 // out: bool
#define INBOX_1   2 // in: sensors + variables

#define OUTBOX_2  3 // out: cm_string
#define INBOX_2   4 // back in: ack


char _NOS_;  // number of slaves


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
inline int checksum(string s) {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    int cs=0;
    for (int i=0;i<strlen(s);++i) cs+=s[i];
    return cs;
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void BTSend(char ID, string cmd) {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  int ack=0;
  int ch=checksum(cmd);

  while (ack!=ch)  {
    JHSSendRemoteString(ID, OUTBOX_2, cmd);
    JHSReceiveRemoteNumber(ID, INBOX_2, true, ack);
    Wait(50);
  }
}



//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
safecall void ParseBTResponseMsg(char ID, string str)  // slaveID=0...2
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{
    string rstr, vstr, sn;
    int i, n, len, v;
    char slot;

    len=strlen(str);   //
    slot=ID-1;

    for (i=0; i<11; ++i)    {
       sn=SubStr(str,0,1);                                                // dec
       n=StrToNum(sn);

       vstr=SubStr(str, 1, n);                      // n= length of value string
       v=StrToNum(vstr);
       RemoteValueArray[slot][i]=v;

       rstr=SubStr(str, 1+n, len);
       str=rstr;
       len=strlen(str);
    }
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
task ReceiveSlaveData()    // NOS = Number of Slaves
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{
   string _msg;
   char conn;

   while(true)   {
     if (_NOS_>=1) {
       conn=1;
       JHSSendRemoteBool(conn, OUTBOX_1, true);
       JHSReceiveRemoteString(conn, INBOX_1, true, _msg);
       ParseBTResponseMsg(conn, _msg) ;
       Wait(50);
     }

     if (_NOS_>=2) {
       conn=2;
       JHSSendRemoteBool(conn, OUTBOX_1, true);
       JHSReceiveRemoteString(conn, INBOX_1, true, _msg);
       ParseBTResponseMsg(conn, _msg) ;
       Wait(50);
     }

     if (_NOS_==3) {
       conn=3;
       JHSSendRemoteBool(conn, OUTBOX_1, true);
       JHSReceiveRemoteString(conn, INBOX_1, true, _msg);
       ParseBTResponseMsg(conn, _msg) ;
       Wait(50);
      }

     Wait(1);
   }
}
and this is for the slaves:

Code: Select all


#include "CHESS_AI_ENGINE_H.nxc"
#include "BT_JHS_TOOLS_H.nxc"

#define BT_CONN   0

#define INBOX_1   1 // in: bool
#define OUTBOX_1  2 // out: sensors + variables

#define INBOX_2   3 // in: cmd_string
#define OUTBOX_2  4 // out: ack


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
task BTReceive() {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  string in;
  int ack, len;
  char bResult;

  while(true) {
    in= "  ";

    JHSReceiveRemoteString(BT_CONN, INBOX_2, true, in, bResult); // cmd string
       ack=checksum(in);
       JHSSendResponseNumber(BT_CONN, OUTBOX_2, ack);   //  check / acknowledge
       Wait(1);
       __cmd=in;
       start ExecCmd;
    Wait(1);
  }
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
task BTMBxWrite() {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  string sn, sv;
  string fmtstr, buf, out;
  int i, dec;
  char bResult;

  while(true)   {
     out="";
     JHSReceiveRemoteBool( BT_CONN, INBOX_1, true, bResult);  // receive request

     for(i=0; i<11; i++) {  // Sensorports: 0...3  plus virtual ports
        GetSensorValues(i);
        dec=SensorValueDecimals[i];
        sn=NumToStr(dec);                          // value decimals
        fmtstr=StrCat("%",NumToStr(dec),"d");
        sv=FormatNum(fmtstr,SensorCurrArr);
        out = StrCat(out, sn, sv);
     } //  for port i=...

     if (StrLen(out)>58) strncpy(out,out,58);     // 58 = max msg length
     JHSSendResponseString(BT_CONN, OUTBOX_1, out);
     //TextOut(0, 0, out);
     Wait(1);

  } // while(true)
}
Last edited by HaWe on 01 Apr 2012, 17:59, edited 1 time in total.
mcsummation
Posts: 220
Joined: 23 Jan 2012, 17:07
Location: Round Rock, TX

Re: Bluetooth "extras"

Post by mcsummation »

This statement (in slave's BTReceive):

Code: Select all

JHSReceiveRemoteString(BT_CONN, INBOX_2, true, in, bResult); // cmd string
has a value of bResult which is not known. It should be either "true" for "wait until a message is received" or "false" for "do not wait for a message". The default is "true". I suspect that it is "zero", which would mean "do not wait for a message".
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: Bluetooth "extras"

Post by HaWe »

thank you!
Of Course, what I want is that it should wait for a message to come in; when there is no message, it wouldn't have to send a response acknowledge value,
and if there is no bool request, there is no need to send a string back.
During this waiting period of one task there should be enough scheduled time for the other task to wait and / or to receive values.

(BTW, that was my question I once had asked here: https://sourceforge.net/apps/phpbb/mind ... =10#p13520)

So I have to do it like this...? (I changed the task names a little to make it more clear what they are supposed to do)

Code: Select all

 //master

#define BT_CONN_1 1 // Slave 1
#define BT_CONN_2 2 // Slave 2
#define BT_CONN_3 3 // Slave 3

#define OUTBOX_1  1 // out: bool
#define INBOX_1   2 // in: sensors + variables

#define OUTBOX_2  3 // out: cmd_string
#define INBOX_2   4 // in: ack

inline void BTSend(char ID, string cmd) {
  int ack, ch;

  //ch=checksum(cmd);
  ch=0x99;
  ack=0;
  while (ack!=ch)  {
    JHSSendRemoteString(ID, OUTBOX_2, cmd);
    JHSReceiveRemoteNumber(ID, INBOX_2, true, ack);  // wait until acknowledge
    Wait(100);
  }
}


task ReceiveSlaveData()    // NOS = Number of Slaves
{
   string _msg;
   char conn;

   while(true)   {
     if (_NOS_>=1) {
       conn=1;
       JHSSendRemoteBool(conn, OUTBOX_1, true);  // send request BOOL
       JHSReceiveRemoteString(conn, INBOX_1, true, _msg);
       ParseBTResponseMsg(conn, _msg) ;
       Wait(50);
     }

     if (_NOS_>=2) {
       conn=2;
       JHSSendRemoteBool(conn, OUTBOX_1, true);
       JHSReceiveRemoteString(conn, INBOX_1, true, _msg);
       ParseBTResponseMsg(conn, _msg) ;
       Wait(50);
     }

     if (_NOS_==3) {
       conn=3;
       JHSSendRemoteBool(conn, OUTBOX_1, true);
       JHSReceiveRemoteString(conn, INBOX_1, true, _msg);
       ParseBTResponseMsg(conn, _msg) ;
       Wait(50);
      }

     Wait(1);
   }
}



Code: Select all

 // slaves 
#define BT_CONN   0

#define INBOX_1   1 // in: bool
#define OUTBOX_1  2 // out: sensors + variables

#define INBOX_2   3 // in: cmd_string
#define OUTBOX_2  4 // out: ack

task BTReceiveCmdStr() {
  string scmd;
  int ack=0x99, len;
  char bWait=true;

  while(true) {
    scmd= "  ";
    bWait=true;
    ack=0x99;
    JHSReceiveRemoteString(BT_CONN, INBOX_2, true, scmd, bWait); // wait: cmd string
       //ack=checksum(scmd);
       JHSSendResponseNumber(BT_CONN, OUTBOX_2, ack);   //  back: acknowledge
       Wait(1);
       __cmd=scmd;
       start ExecCmd;
    Wait(1);
  }
}


task BTSendValueStr() {
  string sn, sv;
  string fmtstr, buf, out;
  int i, dec;
  char bWait=true;

  while(true)   {
     out="";
     bWait=true;
     JHSReceiveRemoteBool( BT_CONN, INBOX_1, true, bWait);  // wait: receive request

     for(i=0; i<11; ++i) {  // Sensorports: 0...3  plus virtual ports
        GetSensorValues(i);
        dec=SensorValueDecimals[i];
        sn=NumToStr(dec);                           
        fmtstr=StrCat("%",NumToStr(dec),"d");
        sv=FormatNum(fmtstr,SensorCurrArr);
        out = StrCat(out, sn, sv);
     } //  for port i=...

     if (StrLen(out)>58) strncpy(out,out,58);     // 58 = max msg length
     JHSSendResponseString(BT_CONN, OUTBOX_1, out);
     //TextOut(0, 0, out);
     Wait(1);

  } // while(true)
}
I changed the code as written above, but the program is not able again yet to send command strings from the master to a slave like once before.
It still blocks totally and so it also can't receive any remote values (strings) from a slave



ps
would you mind adding a "version number" to your BT_Stuff.nxc ?
Attachments
chess_master_2slaves.zip
(28.06 KiB) Downloaded 298 times
mcsummation
Posts: 220
Joined: 23 Jan 2012, 17:07
Location: Round Rock, TX

Re: Bluetooth "extras"

Post by mcsummation »

I have spent some time looking at your code. It appears that the BT communication should be working properly. However, it is difficult for me to see that the data is being processed properly once it is received by the master. For instance, you receive data from the slaves into an array. But, there is no synchronization between the data coming back (and being parsed into the array) and any processing taking place on that data. Or, at least, I did not see any.

In the slave, because you send the "ack" immediately, it is possible for you to receive another command before you have completely processed the first one that came in. It would seem to me that ExecCmd should be inline and process the command before sending back the "ack".
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: Bluetooth "extras"

Post by HaWe »

thank you for your reply.
the sensor data string processing is done by the procedure

safecall void ParseBTResponseMsg(char ID, string str)

so I'll try it by

inline void ParseBTResponseMsg(char ID, string str)

I will report asap!

Do you think my mailbox setup is compatibel with your customized BT functions??
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: Bluetooth "extras"

Post by HaWe »

ok, I changed "safecall" into "inline" , but it also does not work.

The program hangs right from the start and does nothing at all.
This happens just when the BT connection seems to be established and actually a remote motor (slave1) should have been started.
mcsummation
Posts: 220
Joined: 23 Jan 2012, 17:07
Location: Round Rock, TX

Re: Bluetooth "extras"

Post by mcsummation »

It has been suggested (more than once) that the startup of multiple BT devices should be:
1) The master program starts, then hangs on a ReceiveRemoteBool for each slave;
2) As the slave(s) starts and completes its initialization, it sends a SendResponseBool so the master will know it is up and ready to receive commands.

The mailbox setup should be compatible with what I've done. My "enhancements" do nothing more than put John's suggestions into the functions/procedures to make it easier to code. That's all.
Post Reply

Who is online

Users browsing this forum: Semrush [Bot] and 4 guests