Setting up DI Wifi Sensor --Problems

Discussion specific to projects ideas and support.
markcrosbie
Posts: 34
Joined: 30 Sep 2010, 09:56
Location: Ireland
Contact:

Re: Setting up DI Wifi Sensor --Problems

Post by markcrosbie »

afanofosc wrote:I am not convinced that the problems you both are encountering are not user-error. For one thing, trying to execute listener.nxc when you don't understand what it is supposed to do or how it works is a recipe for disaster. For another thing, if the latest compiler and firmware work just fine to talk to an NXTBee at baud rates ranging from 1200 to 115200 then can you give me a reason for it not working with another RS485 device at 9600 baud?
Hi John,

I wouldn't be surprised if user error is to blame (I've been in this game long enough to know that!) but for the life of me I could not figure out what I was missing in the code I wrote. I would point out that just because the firmware talks to a NXTBee doesn't imply anything about it's ability to talk to a DiWifi sensor. Two different sensors, potentially two entirely different RS485 stacks in the microcontroller on the sensor itself.
I looked at Mark's code last night and it has many issues that could cause it to fail. I would never try to figure out what was going wrong without first getting rid of all his logging code - to rule that out as a problem causer - and simplify the test harness as much as possible. Xander's RobotC code leaves off all LF characters while Mark's code follows the DIWIFI docs by always ending a command with CRLF. Which one works? Which one is right?
If you can see that many issues that would cause it to fail then please let me know what they are so I can correct them and hence learn in the process. The debug code was added to generate verbose log files on the NXT that allowed me to trace what was going on in the program. It was the only way I could figure out what was going on and when. You can disable the logging by setting a boolean to false at the top of the listener.nxc file. By default a text file named listener.txt is generated on the NXT. The logging library is not rocket science and is explained here http://www.mastincrosbie.com/Marks_LEGO ... n_NXC.html

I even went so far as to write a DiWifi simulator program that ran on a second NXT (in NXC) and spoke to the primary NXT over RS485. As far as I could tell the code I wrote in listener.nxc behaved correctly when run with this "simulated" DiWifi sensor.

As for CRLF vs. LF: I tried both approaches with no reliable results from either in NXC.
Did Matt put the NXT into DATA_MODE_NXT or leave it in its default DATA_MODE_RAW configuration?
I tried both modes and saw that only DATA_MODE_RAW would work.

I spent the guts of a month every evening for hours on end trying to get NXC and the DiWifi to work reliably with each. I almost abandoned the whole project numerous times out of sheer frustration. I would love to get this to work reliably, so if you can assist in any way I would greatly appreciate it.

Regards,
Mark
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: Setting up DI Wifi Sensor --Problems

Post by afanofosc »

Mark,

I don't mean to criticize your code, which clearly worked or works or you would not have posted it. But both Matt and the OP suggest that "it blows up" or something like that. The OP says his NXT locks up and Matt says with any code he has tried he can't even get a response to +++. I am certain you got a lot farther than that and would be extremely surprised if you had significant trouble getting your code to work with the latest compiler and firmware versions.

My main concern with your code is that, as a rule, an unbreakable cardinal rule, you never ever ever call RS485Write without immediately afterward waiting for the firmware to finish sending your outbound data. In your case you sort of end up waiting because you wait to receive a response. But it is my strong opinion that you should not let your RS485 code go forward until you are done sending, just to make sure that you never accidentally wind up trying to send again before the first send has completed.

Additionally, I would recommend minimizing the number of places that you make copies of your command buffers. Implement an RS485WriteString function which takes a null terminated string and only inside that function do you strip off the trailing null before sending it on to the device.

Matt suggested that a probable cause for his failures was that the enhanced NBC/NXC firmware did not implement a proper 9600 baud rate, which surely would cause any device to fail at that baud rate and not just the DIWIFI device. You got it to work at 9600 baud so you know for certain that it could not be a firmware bug that might never get fixed.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
mattallen37
Posts: 1818
Joined: 02 Oct 2010, 02:19
Location: Michigan USA
Contact:

Re: Setting up DI Wifi Sensor --Problems

Post by mattallen37 »

John Hansen,

I tried just about everything I could think of. I know I didn't intentionally put the RS485 into DATA_MODE_NXT. The only way it wasn't DATA_MODE_RAW, is if one of the RS485 setup functions changed it. Anyhow, here is the RS485 initialization code:

Code: Select all

void nxtSetHSBaudRate(long baudrate){
  switch (baudrate){
    case 9600:
      SetHSSpeed(HS_BAUD_9600);
    break;
    case 19200:
      SetHSSpeed(HS_BAUD_19200);
    break;
    case 38400:
      SetHSSpeed(HS_BAUD_38400);
    break;
    case 57600:
      SetHSSpeed(HS_BAUD_57600);
    break;
    case 115200:
      SetHSSpeed(HS_BAUD_115200);
    break;
    case 230400:
      SetHSSpeed(HS_BAUD_230400);
    break;
    case 460800:
      SetHSSpeed(HS_BAUD_460800);
    break;
    case 921600:
      SetHSSpeed(HS_BAUD_921600);
    break;
  }
}

void nxtEnableHSPort(long baudrate = 0){
  SetSensorType(S4, SENSOR_TYPE_HIGHSPEED);
  SetHSFlags(HS_UPDATE);
  SetHSState(HS_INITIALISE);
  SetHSFlags(HS_UPDATE);
  if (baudrate) nxtSetHSBaudRate(baudrate);
  SetHSFlags(HS_UPDATE);
}

void nxtDisableHSPort(){
  SetSensorType(S4, SENSOR_TYPE_NONE);
  SetHSFlags(HS_UPDATE);
  SetSensorType(S4, SENSOR_TYPE_NONE);
}
So to initialize RS485, I would make a call like this: nxtEnableHSPort(baudrate); where baudrate would be e.g. 9600. Or, if I leave the baudrate parameter empty, then it wouldn't set the speed (I guess it would use whatever speed is default).

Mark,

What I did was take the ROBOTC files from DI for WPA Connect, modify them slightly, and convert them into NXC. I tried to convert them as literally as I could (with the mods), even keeping some function names. I had to write several functions that I couldn't find suitable replacements for in NXC.

The main program:

Code: Select all

////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Setup for Wifi Sensor, Associate with a WPA Network
//
//  This scrip will connect the DI Wifi sensor to a WPA network.
//
//  You must replace the values of SSID and WPA_PAK
//
////////////////////////////////////////////////////////////////////////////////////////////////////////

#define writeRawHS(X, Y) debugnxtWriteRawHS(X, Y)

//#define writeRawHS(X, Y) nxtWriteRawHS(X, Y)


// Declare the SSID and WPA_PSK we're connecting to
byte ssid[] = {'F','a','k','e',' ','N','e','t','w','o','r','k'};
byte wpa_psk[] = {'P','a','s','s','w','o','r','d'};

#include "My debug stream lib.nxc"
#include "My DI WIFI RS485.nxc"
#include "DIWIFI WPA Connect_h.nxc"

void wifi_startup(){

  config_wifi();            // This function sets up the wifi sensor for operation.  Basic housekeeping.
  wifi_auth_mode(0);        // Set the authentication mode.
                            // 0 is none or WPA // 1 is Open network // 2 is Shared with WEP
  setDHCP(1);               // Get us an IP number
  set_wpa_psk();            // Calculates your psk
  Wait(100);
  Receive(false);            // Housekeeping
  Receive(false);            // Housekeeping
  connect_to_ssid();         // Connects to the wifi network you've designated
  PlaySound(SOUND_DOUBLE_BEEP); // After connection, announce to the world you're connected.
  Receive(true);            // Housekeeping.
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                        Main Task
////////////////////////////////////////////////////////////////////////////////////////////////////////

task main()
{
  //bNxtLCDStatusDisplay = true; // Enable top status line display
  wifi_startup();             // This is where the work is done.
  PlaySound(SOUND_DOUBLE_BEEP);   // Make some noise when we're connected.
  PlayTone(500, 100);         // Make some noise when we're connected.
}
DIWIFI WPA Connect_h.nxc:

Code: Select all

byte BytesRead[8];
const byte newline[] = {0x0D};
typedef byte buff_t;
buff_t buffer[128];

long baudrates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600};

// This function sends the array out Port 4.

void debugnxtWriteRawHS(byte pData[], byte nLength)
{
  string tmpString;
  byte buff[35];
  memcpy(buff, pData, nLength);
  tmpString = FlattenVar(buff);
  writeDebugStream(tmpString);
  nxtWriteRawHS(pData, nLength);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
//      Clear Read Buffer
//      Run this to clear out the reading buffer.
//      Simply sends a carriage return, then clears the buffer out.
////////////////////////////////////////////////////////////////////////////////////////////////////////

void clear_read_buffer()
{
  byte nData[] = {13};
  nxtWriteRawHS(nData, 1);
  Wait(1000);                //100?
  while(HSInputBufferInPtr()){
    GetHSInputBuffer(0, 1, BytesRead);  //Read the buffer
    SetHSInputBufferInPtr(0);
  }
  GetHSInputBuffer(0, 1, BytesRead);
  SetHSInputBufferInPtr(0);
  Wait(10);                //100?
}

/////////////////////////////////////////////////////////
//Scan Baud Rate - Scans the baud rate, sets up the sensor.
/////////////////////////////////////////////////////////
long scanBaudRate() {
  byte Retried9600 = 0;
  string tmpString;
  byte attention[] = {'+','+','+',13};
  for (int i = 0; i < 8; i++) {
    Retry_9600:
    byte tmpbuff[8];// = {0, 0, 0, 0, 0, 0, 0, 0};
    nxtDisableHSPort();
    Wait(10);
    nxtEnableHSPort(baudrates[i]);
//    nxtSetHSBaudRate(baudrates[i]);
    clear_read_buffer();
    Wait(1000);
    writeDebugStreamLine("Trying %ld", baudrates[i]);
    nxtWriteRawHS(attention, 4); //nxtWriteRawHS(attention, sizeof(attention));
    nxtReadRawHS(tmpbuff, 7);  // make sure last ubyte is always NULL
    tmpString = FlattenVar (tmpbuff);
    writeDebugStreamLine(tmpString);
    if ((StringFind(tmpString, "ERR") > -1) ||
        (StringFind(tmpString, "OK") > -1) ||
        (StringFind(tmpString, "0") > -1) ||
        (StringFind(tmpString, "2") > -1)) {
      clear_read_buffer();
      writeDebugStreamLine("Success at %ld", baudrates[i]);
      writeDebugStreamLine("");
      return baudrates[i];
    }
    writeDebugStreamLine("Failed at %ld", baudrates[i]);
    if(i == 0 && Retried9600 == 0){Retried9600 = 1;goto Retry_9600;} //It seems to always pick up on it the second time, so try it again.
  }
  clear_read_buffer();
  return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
// Receive Bytes
// Reads whatever is in the buffer and prints to debug
////////////////////////////////////////////////////////////////////////////////////////////////////////

void Receive(bool wait=false)
{
  if (wait)
    while (HSInputBufferInPtr() == 0) Wait(5);
  long StartTick = CurrentTick();
  bool TimeOut = 0;
  while (HSInputBufferInPtr() > 0) {
    SetHSInputBufferInPtr(0);
    StartTick = CurrentTick();
    nxtReadRawHS(BytesRead, 1);
    writeDebugStream("%c", BytesRead[0]);
    until(HSInputBufferInPtr() > 0 || TimeOut){
      if(StartTick + 100 < CurrentTick())TimeOut = 1;
    }
  }
}

/*int appendToBuff(byte &buf, const long index, const ubyte &pData, const long nLength)
{
  if (index == 0) memset(buf, 0, sizeof(buf));

  memcpy(buf[index], pData, nLength);
  return index + nLength;
} */

//index = appendToBuff(  buffer,      index,     ssid_cmd, sizeof(ssid_cmd));
int appendToBuff(byte & buf[], long index, byte pData[], long nLength)
{
  if (index == 0){
    for (int i = 0; i < ArrayLen(buf); i++){
      buf[i] = 0;
    }
  }

  //memcpy(buf[index], pData, nLength);
  //ArraySubset(buf, pData, index, nLength);
  
  for(int i = 0; i < nLength; i++){
    buf[i + index] = pData[i];
  }
  
  return index + nLength;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
//      Echo All Input Off - Turns off the echo effect on the wifi.
//      Sending the serial command "ate0" which turns off the echo effect.
//      Sends one single byte at a time, pauses.
//      Drains receiver with a read each time.
////////////////////////////////////////////////////////////////////////////////////////////////////////

void echo_all_input_off()
{
  byte nData[] = {'a','t','e','0',13};
//  byte s_buf[1];
//  for(int i = 0; i < 5; i++){
//    s_buf[0] = nData[i];
//    writeRawHS(s_buf, 1);               // Send the command, byte by byte.
//    nxtReadRawHS(BytesRead, 8);         // Clear out the echo.
//    Wait(100);
//  }
  SetHSInputBufferInPtr(0);
  writeRawHS(nData, 5);
  nxtReadRawHS(BytesRead, 8);

  Receive(true);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
//      Software Flow Control On
//      Send string "at&k1" and carriage return.
//      Shouldn't need the wait or read now that we've got the echo off.
////////////////////////////////////////////////////////////////////////////////////////////////////////
void software_flow_control()
{
  writeDebugStreamLine("sfwr_flw_cntrl");
    byte nData[] = {'a','t','&','k','1',13};
    writeRawHS(nData[0], 6);            // Send the command, byte by byte.
    Wait(1000);

    Receive(true);
    // wait10Msec(100);
}

//////////////////////////////////////////////////////////////////
// Configure the verbose mode of the wifi sensor.
// n = 0, verbose disabled.
// n = 1, verbose enable.
//////////////////////////////////////////////////////////////////

void set_verbose(byte n)
{
  if(n) {n = 49;}                                  // Shouldn't be larger than 1 so set it back.
  else  {n = 48;}
  writeDebugStreamLine("set_verbose");
  byte nData[] = {'a','t','v',49,13};
//  nData[3] = n;
  writeRawHS(nData, 5);            // Send the command, byte by byte.
  Receive(true);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
//      Set the Infrastructure Mode.
//      Send string "AT+WM = n" and carriage return.
//      This sets the infrastructure mode as either infrastructure or ad-hoc network.
////////////////////////////////////////////////////////////////////////////////////////////////////////

void infrastructure_mode(int state)
{
  writeDebugStreamLine("wifi_infra_mode.");
  char state_n = state + 48;
  byte nData[] = {'a','t','+','w','m','=',0 ,13};
  nData [6] = state_n;
  writeRawHS(nData, 8);            // Send the command, byte by byte.
  Receive(true);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
//      Disassociate from any networks.
//      Send string "AT+WD" and carriage return.
//      This dissaciates from any networks we're currently connected to.
////////////////////////////////////////////////////////////////////////////////////////////////////////

void disass()
{
  writeDebugStream("discon_frm_networks");
  byte nData[] = {'a','t','+','w','d',13};
  writeRawHS(nData, sizeof(nData));            // Send the command, byte by byte.
  writeRawHS(newline, sizeof(newline));        // send new line
  Receive(true);
}

void set_network_config()
{
  byte wpa_psk_cmd[] = {'A','T','S','1','=','1','0','0','0'};
  int index = 0;

  index = appendToBuff(buffer, index, wpa_psk_cmd, sizeof(wpa_psk_cmd));
  index = appendToBuff(buffer, index, newline, sizeof(newline));

  writeRawHS(buffer[0], index);
  Receive(true);
}

// Keep Association Alive for 20 Minutes
void Keep_Alive() {
  int index = 0;
  byte Keep_Alive_cmd[] = {'A','T','+','P','S','P','O','L','L','I','N','T','R','L','=','1','2','0','0'};

  index = appendToBuff(buffer, index, Keep_Alive_cmd, sizeof(Keep_Alive_cmd));
  index = appendToBuff(buffer, index, newline, sizeof(newline));
  writeRawHS(buffer[0], index);
  Receive(true);
}


void max_transmit_power() {
  writeDebugStreamLine("Set Max Xmit Power");
  byte status_cmd[] = {'a','t','+','W','P','=', '7', 13};
  writeRawHS(status_cmd[0], sizeof(status_cmd));       // Send the command, byte by byte.
  Receive(true);
}


void config_wifi(){

  //It must be properly connected before continueing, so don't continue until it's communicating.
  while(scanBaudRate()==0){writeDebugStreamLine("Trying again");}           // This function scans the baud rate and sets up the server.  You can also call the "setupHighSpeedLink" function
                            // if you want a specific baud rate.  If the baud rate of the wifi sensor was a different rate, this will
                            // connect the sensor to the wifi server.
  // Configure the link for raw read and write. User program will have complete control over the link.
  // User program will be responsible for managing the half-duplex operation and must prevent collisions!

  clear_read_buffer();      // Clear out the buffer and test TX/RX.
  Wait(1000);
  writeDebugStreamLine("echo_all_input_off");
  echo_all_input_off();     // Turn off serial echo.
  software_flow_control();  // Turn on software flow control
  set_verbose(1);           // Turn on verbose responses.
  infrastructure_mode(0);   // Setup as infrastructure.  1 would be adhoc network.  0 is infrastructure.
  disass();                 // Disassociate from any networks we might be hooked to.
  set_network_config();
  Keep_Alive();             // Keep association with network alive.
  max_transmit_power();     // Max transmit power . . .  rock out and forget about the batteries.
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
//      WIFI:  Set Authentication Mode
//             Security of the wifi system we're connecting to.
//             Send string "at+wauth=<n>" and carriage return.
//              n = 0 --> No security mode
//              n = 1 --> Open security mode
//              n = 2 --> Shared with WEP
////////////////////////////////////////////////////////////////////////////////////////////////////////

void wifi_auth_mode(int state)
{
  writeDebugStreamLine("wifi_auth_mode");
  char state_n = state + 48;
  byte nData[] = {'a','t','+','w','a','u','t','h','=',48,13};
  nData[9] = state_n;
  writeRawHS(nData, 11);            // Send the command, byte by byte.
  Receive(true);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//      Dynamic Host Configuration Protocol
//      Sends the command AT+NDHCP=<n>
//      We're gong to turn it on or turn it off.  This will acquire an IP address automatically.
//
////////////////////////////////////////////////////////////////////////////////////////////////////////

void setDHCP(int n)
{
  writeDebugStreamLine("setDHCP");
  byte dhcp_cmd[] = {'a','t','+','N','D','H','C','P', '=', 49, 13};
  dhcp_cmd[9] = n + 48;
  writeRawHS(dhcp_cmd, 11);       // Send the command, byte by byte.
  Receive(true);
  Wait(1000);
}

void set_wpa_psk()
{
  byte wpa_psk_cmd[] = {'A','T','+','W','P','A','P','S','K','='};
  unsigned byte dummy[] = {','};
  int index = 0;
  writeDebugStreamLine("set_wpa_psk");
  Wait(250);
  
  writeDebugStreamLine(FlattenVar(wpa_psk_cmd));
  index = appendToBuff(buffer, index, wpa_psk_cmd, sizeof(wpa_psk_cmd));
  Wait(250);
  
  writeDebugStreamLine(FlattenVar(ssid));
  index = appendToBuff(buffer, index, ssid, sizeof(ssid));
  Wait(250);

  writeDebugStreamLine(FlattenVar(dummy));
  index = appendToBuff(buffer, index, dummy, sizeof(dummy));
  Wait(250);

  writeDebugStreamLine(FlattenVar(wpa_psk));
  index = appendToBuff(buffer, index, wpa_psk, sizeof(wpa_psk));
  Wait(250);

  writeDebugStreamLine(FlattenVar(newline));
  index = appendToBuff(buffer, index, newline, sizeof(newline));
  Wait(250);

  writeRawHS(buffer, index);
}


bool Receive_connect(bool wait=false)
{
  int i = 0;
  byte Bytes_Error[128];
  if (wait)
    while (HSInputBufferInPtr() == 0) Wait(5);

  while (HSInputBufferInPtr() > 0) {
    nxtReadRawHS(BytesRead, 1);
    writeDebugStream("%c", BytesRead[0]);
    Wait(2);
    Bytes_Error[i] = BytesRead[0];
    i++;
  }

  writeDebugStream("%c", Bytes_Error[0]);
  writeDebugStream("%c", Bytes_Error[1]);
  writeDebugStream("%c", Bytes_Error[2]);
  writeDebugStream("%c", Bytes_Error[3]);

  if(Bytes_Error[2] == 'E' && Bytes_Error[3] == 'R'){
    return false;
  }
  return true;
}

void set_ssid() {
  byte ssid_cmd[] = {'A','T','+','W','A','='};
  int index = 0;

  index = appendToBuff(buffer, index, ssid_cmd, sizeof(ssid_cmd));
  writeDebugStreamLine("1" + FlattenVar(buffer));
  index = appendToBuff(buffer, index, ssid, sizeof(ssid));
  writeDebugStreamLine("2" + FlattenVar(buffer));
  index = appendToBuff(buffer, index, newline, sizeof(newline));
  writeDebugStreamLine(FlattenVar(ssid_cmd));
  writeDebugStreamLine(FlattenVar(ssid));
  writeDebugStreamLine("3" + FlattenVar(buffer));
  writeRawHS(buffer, index);
}

// This repeatedly tries to connect until succesful.
void connect_to_ssid(){
  disass();
  bool quit = false;
  while(quit == false){
    set_ssid();
    quit = Receive_connect(true);
  }
}
My DI WIFI RS485.nxc:

Code: Select all

/*
*  Matthew Richardson
*  matthewrichardson37<at>gmail.com
*  http://mattallen37.wordpress.com/
*  November 2011
*
*  You may use this code as you wish, provided you give credit where it's due.
*
*  This is a library of functions for low level communication with the DIWIFI.
*/

void nxtWriteRawHS(byte pData[], byte nLength)
{
  string StringSendData = FlattenVar(pData);                  //Flatten it into a string
  SendRS485String(StringSendData);                            //Send the string
  until(HSOutputBufferOutPtr() == StrLen(StringSendData)+1);  //Wait until the string has been sent
}

int nxtReadRawHS (byte & tmpbuff[], byte nLength, long TimeOut = 1000){
  long OriginalTick = CurrentTick();

  until(HSInputBufferInPtr()>=1){
    if (OriginalTick + TimeOut < CurrentTick()){
      PlayTone(2500, 10);
      Wait(10);
      return -3;                                 //Didn't get anything
    }
  }
  
  OriginalTick = CurrentTick();
  until(HSInputBufferInPtr()>=nLength+1){
    if (OriginalTick + TimeOut < CurrentTick()){
      byte Nlength = HSInputBufferInPtr();
      GetHSInputBuffer(0, Nlength, tmpbuff);
      SetHSInputBufferInPtr(0);
      PlayTone(440, 100);
      Wait(100);
      return -2;                                     //Got something, but not full length
    }
  }
  GetHSInputBuffer(0, nLength, tmpbuff);
  SetHSInputBufferInPtr(0);
  return 1;                                      //It was full length, and good
}

/*
int nxtReadRawHS (byte & tmpbuff[], byte nLength, long TimeOut = 1000){
  long OriginalTick = CurrentTick();
  until(HSInputBufferInPtr()>=nLength+1){
    if (OriginalTick + TimeOut < CurrentTick()){
      return -2;
    }
  }
  GetHSInputBuffer(0, nLength, tmpbuff);
  SetHSInputBufferInPtr(0);
  return 1;
}
*/

void nxtSetHSBaudRate(long baudrate){
  switch (baudrate){
    case 9600:
      SetHSSpeed(HS_BAUD_9600);
    break;
    case 19200:
      SetHSSpeed(HS_BAUD_19200);
    break;
    case 38400:
      SetHSSpeed(HS_BAUD_38400);
    break;
    case 57600:
      SetHSSpeed(HS_BAUD_57600);
    break;
    case 115200:
      SetHSSpeed(HS_BAUD_115200);
    break;
    case 230400:
      SetHSSpeed(HS_BAUD_230400);
    break;
    case 460800:
      SetHSSpeed(HS_BAUD_460800);
    break;
    case 921600:
      SetHSSpeed(HS_BAUD_921600);
    break;
  }
}

void nxtDisableHSPort(){
  SetSensorType(S4, SENSOR_TYPE_NONE);
  SetHSFlags(HS_UPDATE);
  SetSensorType(S4, SENSOR_TYPE_NONE);
}

void nxtEnableHSPort(long baudrate = 0){
  SetSensorType(S4, SENSOR_TYPE_HIGHSPEED);
  SetHSFlags(HS_UPDATE);
  SetHSState(HS_INITIALISE);
  SetHSFlags(HS_UPDATE);
  if (baudrate) nxtSetHSBaudRate(baudrate);
  SetHSFlags(HS_UPDATE);
}
My debug stream lib.nxc:

Code: Select all

/*
*  Matthew Richardson
*  matthewrichardson37<at>gmail.com
*  http://mattallen37.wordpress.com/
*  November 20, 2011
*
*  You may use this code as you wish, provided you give credit where it's due.
*
*  This is a library of functions for creating a debug stream on the NXT LCD.
*/

int StringFind(string In_String, string F_String){                              // Input a string to look through, a string to look for, and return the position
  if (StrLen(In_String)<StrLen(F_String)) return -2;                            // The input string is shorter than the string I am looking for, so return -2
  for (int i = 0; i < StrLen(In_String); i++){                                  // repeat for the number of times the input string is long
    if (In_String[i]==F_String[0]){                                             // If the current char is the same as the first char in the string to look for
      for (int ii = 0; ii < StrLen(F_String); ii++){                            // Repeat for the number of times the find string is long
        if (In_String[i+ii]!=F_String[ii]) goto LookForFirstChar;               // If the chars don't match up, go back to looking for the first char again
      }
      return i;                                                                 // It found the matching string, so return the start char position 0 - n
    }
    LookForFirstChar:                                                           // Label to jump to to look again for the first char of the string to search for
  }
  return -1;                                                                    // It didn't find the string, so return -1
}

byte sizeof(byte buf[]){                                                        // Strictly for added compatibility with ROBOTC
  return ArrayLen(buf);
}

string LCD_LINE_ONE;
string LCD_LINE_TWO;
string LCD_LINE_THREE;
string LCD_LINE_FOUR;
string LCD_LINE_FIVE;
string LCD_LINE_SIX;
string LCD_LINE_SEVEN;
string LCD_LINE_EIGHT;

byte LCD_COL_POS = 1;

void GetNewLine(){                                                              // Get a new line by shifting everything up a line and clearing the necessary string and variable
  LCD_LINE_ONE   = LCD_LINE_TWO  ;
  LCD_LINE_TWO   = LCD_LINE_THREE;
  LCD_LINE_THREE = LCD_LINE_FOUR ;
  LCD_LINE_FOUR  = LCD_LINE_FIVE ;
  LCD_LINE_FIVE  = LCD_LINE_SIX  ;
  LCD_LINE_SIX   = LCD_LINE_SEVEN;
  LCD_LINE_SEVEN = LCD_LINE_EIGHT;
  LCD_LINE_EIGHT = "";
  LCD_COL_POS = 1;
}

void writeDebugTextAdv(string txt, bool NL){                                    // Post text to the LCD, and optionally get a new line first
  if (NL){                                                                      // If I requested to get a new line (start with an empty line)...
    GetNewLine();                                                               // ...Get a new line.
  }

  if (LCD_COL_POS - 1 + StrLen(txt) - 1 >= 16){                                 // If it won't all fit on the current line
    unsigned int cur_txt_char = 0;
    char txt_char[];                                                            // Create an array to hold the input text for easy manipulation
    const unsigned int txt_len = StrLen(txt);
    ArrayInit    (txt_char, 0, txt_len);                                        // Set the size to the length of the input text
    UnflattenVar (txt, txt_char);                                               // Put the input text string into the array
    char LCD_LINE_EIGHT_char[16];                                               // Create an array to hold the line I am building
    
    char LCD_LINE_EIGHT_char_temp[];                                            // Create an array to hold the existing charactors of the current line
    const unsigned int LCD_LINE_EIGHT_char_temp_len = StrLen(LCD_LINE_EIGHT);
    ArrayInit    (LCD_LINE_EIGHT_char_temp, 0, LCD_LINE_EIGHT_char_temp_len);   // Initialize the array with the right number of elements
    UnflattenVar (LCD_LINE_EIGHT          ,    LCD_LINE_EIGHT_char_temp);       // Put the previous text into array format
    for (int i = 0; i < LCD_LINE_EIGHT_char_temp_len; i++){                     // Repeat for the number of times it takes to copy all the previous chars into the new char array
      LCD_LINE_EIGHT_char[i] = LCD_LINE_EIGHT_char_temp[i];                     // In the properly lengthed array
    }

    for (int i = 0; i < (17-LCD_COL_POS); i++){                                 // repeat once for every char to add to the line
      LCD_LINE_EIGHT_char[i+LCD_COL_POS-1] = txt_char[i];
      cur_txt_char++;
    }
    LCD_LINE_EIGHT = FlattenVar(LCD_LINE_EIGHT_char);                           // The line is full, so go ahead and convert it into the string...
    GetNewLine();                                                               // ...and grab a new line...
    ArrayInit (LCD_LINE_EIGHT_char, 0, 16);                                     // ...and clear the values of the current line array to 0

    unsigned int NumberOfFullLines = (txt_len - cur_txt_char - 1) / 16;         // Determine how many full lines of chars there are left
    if(NumberOfFullLines){                                                      // If there are some (at least one)...
      repeat(NumberOfFullLines){                                                // Repeat for the number of full lines needing to be written
        unsigned int iiii = 0;
        repeat(16){                                                             // Repeat 16 times (once for each char).
          LCD_LINE_EIGHT_char[iiii] = txt_char[cur_txt_char];
          iiii++;
          cur_txt_char++;
        }
        LCD_LINE_EIGHT = FlattenVar(LCD_LINE_EIGHT_char);                       // The array is full, so write it to the string...
        GetNewLine();                                                           // ...and get a new line...
        ArrayInit (LCD_LINE_EIGHT_char, 0, 16);                                 // ...and set the array values back to 0
      }
    }
    byte ii=0;
    if(txt_len - cur_txt_char < 17){                                            // if there are less than 17 chars left (not more than a whole line) then continue
      repeat(txt_len - cur_txt_char){                                           // Repeat once for every char that needs to be on the last line
        LCD_LINE_EIGHT_char[ii] = txt_char[cur_txt_char];
        ii++;
        cur_txt_char++;
      }
    }
    else                                                                        // If there were 17 or more, then an error occured
    {
      PlayTone(500, 100);
      Wait(500);
    }
    ArrayInit    (LCD_LINE_EIGHT_char_temp, 0, ii);                             // Initialize the array with an element for each char in the last line
    byte iii=0;
    repeat(ii){                                                                 // Repeat once for every char that needs to be added to the last line
      LCD_LINE_EIGHT_char_temp[iii] = LCD_LINE_EIGHT_char[iii];
      iii++;
    }
    LCD_LINE_EIGHT = FlattenVar(LCD_LINE_EIGHT_char_temp);                      // Write the string to the values in the array
    LCD_COL_POS = ii;                                                           // Set the pointer to the proper place for furute use
  }
  else{                                                                         // Otherwise, if it will all fit on the current line...
    LCD_LINE_EIGHT += txt;                                                      // Just add to the current string
  }
  
  LCD_COL_POS = StrLen(LCD_LINE_EIGHT) + 1;                                     // Set the pointer for use later

  asm{
  	acquire __PointOutMutex                                                     // Clear the screen
  	mov __PointOutArgs.Location.X, 200
  	mov __PointOutArgs.Location.Y, 200
  	mov __PointOutArgs.Options, __constVal1
  	syscall 14, __PointOutArgs
  	release __PointOutMutex

  	acquire __TextOutMutex
  	
  	mov __TextOutArgs.Location.X, 0
    set __TextOutArgs.Options, 0

    mov __TextOutArgs.Location.Y, 56
  	mov __TextOutArgs.Text, LCD_LINE_ONE
  	syscall 13, __TextOutArgs                                                   // Display the first...

    mov __TextOutArgs.Location.Y, 48
  	mov __TextOutArgs.Text, LCD_LINE_TWO
  	syscall 13, __TextOutArgs                                                   // ...second...

  	mov __TextOutArgs.Location.Y, 40
  	mov __TextOutArgs.Text, LCD_LINE_THREE
  	syscall 13, __TextOutArgs                                                   // ...third...

  	mov __TextOutArgs.Location.Y, 32
  	mov __TextOutArgs.Text, LCD_LINE_FOUR
  	syscall 13, __TextOutArgs                                                   // ...fourth...

  	mov __TextOutArgs.Location.Y, 24
  	mov __TextOutArgs.Text, LCD_LINE_FIVE
  	syscall 13, __TextOutArgs                                                   // ...fifth...

  	mov __TextOutArgs.Location.Y, 16
  	mov __TextOutArgs.Text, LCD_LINE_SIX
  	syscall 13, __TextOutArgs                                                   // ...sixth...

  	mov __TextOutArgs.Location.Y, 8
  	mov __TextOutArgs.Text, LCD_LINE_SEVEN
  	syscall 13, __TextOutArgs                                                   // ...seventh...

  	mov __TextOutArgs.Location.Y, 0
  	mov __TextOutArgs.Text, LCD_LINE_EIGHT
  	syscall 13, __TextOutArgs                                                   // ...and eighth lines of text

    release __TextOutMutex
  }
}

void writeDebugText(string txt, bool NL){

  static int LCD_LINE = 1;
  static int LCD_COL  = 0;
  if(NL){
    LCD_LINE++;
    LCD_COL  = 0;
  }
  if(LCD_LINE>8){
    LCD_LINE = 1;
    LCD_COL  = 0;
    ClearScreen();
  }
  TextOut(LCD_COL * 6, LCD_LINE1 + 8 - (LCD_LINE*8), txt);
  LCD_COL+=StrLen(txt);
}

void writeDebugStream(string in_txt, float display_f = 0, bool NL = 0){
  string String_out;
  int Formatter_offset = StringFind(in_txt,"%");
  if (Formatter_offset > -1){   //If there is a formatter
    char in_txt_char[];
    const unsigned int in_txt_len = StrLen(in_txt);
    ArrayInit  (in_txt_char, 0, in_txt_len);
    UnflattenVar  (in_txt, in_txt_char);

    byte Formatter_Length = in_txt_len - Formatter_offset;

    char formatter_char[];

    ArraySubset(formatter_char, in_txt_char, Formatter_offset, Formatter_Length);

    char dis_txt_char[];
    const unsigned int dis_txt_len = in_txt_len - Formatter_Length;

    ArraySubset(dis_txt_char, in_txt_char, 0, dis_txt_len);

    string formatter = FlattenVar(formatter_char);
    if(StringFind(formatter,"f")!=-1){
      sprintf(String_out, formatter, display_f);
    }
    else{
      long display_i = display_f;
      sprintf(String_out, formatter, display_i);
    }

    String_out = FlattenVar(dis_txt_char) + String_out;
  }
  else{
    String_out = in_txt;
  }
  writeDebugTextAdv(String_out, NL);
}

void writeDebugStreamLine(string in_txt, float display = 0){
  writeDebugStream(in_txt, display, 1);
}
Please note that ATM I have no idea what comments apply, and due to some more pressing issues involving family, I am unable to access an NXT and my normal computer for probably another week or so (so no testing for me for a while).

So, at one point I said:
At this point in my testing, I think it might be that 9600 baud in NXC isn't truly 9600. Another theory of mine is that the FW throws on a header to all strings being sent over RS485. It would make sense to me how two NXTs do fine, but the DIWIFI gets jammed. Anyhow, both of those are just suspicions which I can't test without an NXT and an RS485 to TTL UART converter (plus a computer and terminal), of which I don't have access to right now.
Based on what little I know of how the RS485 part of the FW works, I am not ready to rule out either of those possibilities (Edit: I guess maybe the speed thing is a little impossible). What now seems just as likely though, is that the DIWIFI is echoing back everything, jamming the half-duplex RS485 stream (not allowing itself to see the command turning off echo). If somehow the timing of ROBOTC's RS485 is different, that could be why we are getting the results we are.

When I get home, I will test out this theory (turn off echo with ROBOTC, and then switch over to NXC). If it proves to be the problem, I can think of several possible HW fixes.
Matt
http://mattallen37.wordpress.com/

I'm all for gun control... that's why I use both hands when shooting ;)
mightor
Site Admin
Posts: 1079
Joined: 25 Sep 2010, 15:02
Location: Rotterdam, Netherlands
Contact:

Re: Setting up DI Wifi Sensor --Problems

Post by mightor »

Could you not use flow control to prevent the NXTBee from being so chatty? John from DI and I discussed that but I never tested it and I don't know if he did/

- Xander
| My Blog: I'd Rather Be Building Robots (http://botbench.com)
| RobotC 3rd Party Driver Suite: (http://rdpartyrobotcdr.sourceforge.net)
| Some people, when confronted with a problem, think, "I know, I'll use threads,"
| and then two they hav erpoblesms. (@nedbat)
markcrosbie
Posts: 34
Joined: 30 Sep 2010, 09:56
Location: Ireland
Contact:

Re: Setting up DI Wifi Sensor --Problems

Post by markcrosbie »

mightor wrote:Could you not use flow control to prevent the NXTBee from being so chatty? John from DI and I discussed that but I never tested it and I don't know if he did/

- Xander
Xander, I tried that using software-flow-control on the DiWifi but never got it to work reliably. I tried every combination of hw/sw flow-control I could think of :)

I think the next step is for me to take John's suggestion regarding waiting for RS485Write() to finish sending before proceeding in the code. I think I tried that at one point and it hung my code in an infinite loop, but I will give it another look...

Mark
mattallen37
Posts: 1818
Joined: 02 Oct 2010, 02:19
Location: Michigan USA
Contact:

Re: Setting up DI Wifi Sensor --Problems

Post by mattallen37 »

mightor wrote:Could you not use flow control to prevent the NXTBee from being so chatty? ...
If you mean DIWIFI, that's the idea. The problem might be that the NXC NXT isn't able to issue the command to not echo, without getting the RS485 line jammed. It could be that by chance the ROBOTC NXT's RS485 messages aren't usually colliding with the ones being sent back by the DIWIFI (which could be why it usually works with ROBOTC).
Matt
http://mattallen37.wordpress.com/

I'm all for gun control... that's why I use both hands when shooting ;)
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: Setting up DI Wifi Sensor --Problems

Post by afanofosc »

Well, my apologies to Matt for thinking he must have been doing something wrong when he couldn't get his NXT to talk to the DIWIFI device via NXC and the enhanced NBC/NXC firmware. I am running into what seems like exactly the same problem, i.e., no sign of any kind of echo or response from the DIWIFI device no matter how hard I try.

I don't think it is a half-duplex timing problem but I could be wrong. I still don't understand why Mark could get his NXC code to chat with the device, albeit with some flakiness, while I get stone cold silence. Is it possible that Matt and I have newer/older versions of the device that might explain the difference in behavior?

Mark, do you have some functional sample NXC code that lets you change the baud rate on the DIWIFI from 9600 to something else, such as the default NXT firmware baud rate?

My non-functional NXC code is attached. I think it is written "correctly" and should work but it does not. Mark, could you try working with my code to see if it works with your device? I should say, actually, that my diwifi.h file is not 100% complete and "correct". I haven't finished hooking up the functions that return a string type so that the code would work correctly, if I ever code convince the DIWIFI to say anything. Basically where I return msg these functions should instead return Receive(true);
DIWIFI-Connect_WEP.nxc
(3.04 KiB) Downloaded 393 times
diwifi.h
(25.53 KiB) Downloaded 411 times
John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
mattallen37
Posts: 1818
Joined: 02 Oct 2010, 02:19
Location: Michigan USA
Contact:

Re: Setting up DI Wifi Sensor --Problems

Post by mattallen37 »

John Hansen, no apology necessary. I deem it almost a requirement to "argue" over things while developing/debugging. It's not personal, and it helps everyone see it from different perspectives.

I'm not at home with my normal computer, so I don't have easy access to some of the documentation and other resources I would use to test/confirm things, so bare with me.

John from DI,

Tell me if this sounds right:
When you turn on the DIWIFI, it (for some reason) starts out in a mode where every serial command it receives (rx), it sends back (tx). We don't want that with the NXT, so one of the first things we do is issue a command to turn off that echo.

If that's the case (which it is IIRC), then so far the only thing I can think is that the echo is clogging the half-duplex line before much of the message gets through to the DIWIFI (much less the entire command).

To fix it, I suggest connecting a transistor between the tx line of the WIFI module, and the RS485 transceiver. The transistor could be controlled with pin one of the sensor port. Pin 1 is analog in, with a 10k pullup to bus voltage (about 4.7v). It can also be driven higher (to near battery voltage) to source up to around 20ma (IIRC) for higher-voltage sensors. I'm not sure what all would be required to control a transistor this way, but it should be possible.

Thinking about it a little more, maybe a comparator (with two voltage dividers) would be a good way to sense the state of pin 1. Take a look at this crude schematic:

Code: Select all

4.7v<-10k internal pullup
pin 1 ^ -> 56k
             -> 3.7v high, 1.6 low -> comparator +
           33k

4.7v  56k
        -> 2.35v -> comparator -
      56k
That way you have a logic high/low that you can use to control a transistor (to turn on/off the tx from the WIFI module). A couple things to think about, should you consider this type of HW change:
The NXT FW needs to let the user have control over the "9v" pin 1 option.
The LM339 comparator (one of the most common) isn't able to source current on it's output (you will need a pullup resistor to drive anything).
Whatever circuit you use to control the tx line will need to handle (potentially) high UART speeds when enabled.
The LM339 is a quad comparator, so you have three "extra" comparators that might work instead of an additional transistor to switch the tx line (to save part count).
Matt
http://mattallen37.wordpress.com/

I'm all for gun control... that's why I use both hands when shooting ;)
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: Setting up DI Wifi Sensor --Problems

Post by afanofosc »

I find it really hard to believe that Dick Swan has significantly changed the Comm module code that he originally got from LEGO that formed the core of his firmware. At one point it surely looked exactly like what the standard firmware has and unless he just decided to rewrite it for grins it probably is still very similar to the standard firmware. My understanding is he still has a pretty much the same modular structure with IOMaps and all that and likely still has a d_hispeed.r file that contains the code that initializes the RS485 receiver, transmits outbound data, and receives inbound data. There would be very little reason to fiddle around with that code except for things like adding support for changing the baud rate, etc... My version of d_hispeed.r, d_hispeed.c, and d_hispeed.h code is here:

http://mindboards.svn.sourceforge.net/s ... _hispeed.r
http://mindboards.svn.sourceforge.net/s ... _hispeed.c
http://mindboards.svn.sourceforge.net/s ... _hispeed.h

The standard NXT firmware's d_hispeed.r is attached (renamed with .txt extension).
d_hispeed.txt
(12.1 KiB) Downloaded 406 times
If Xander could persuade Dick to give us a diff or something along those lines it would be useful. Maybe Ralph Hempel could try talking to the DIWIFI device using pbLua and Gloomy Andy could have a go using leJOS and see if all together we can figure out what might be different enough to cause the enhanced firmware trouble getting any response from the DIWIFI device, though I am still struck by Mark Crosbie's apparent great success in chatting back and forth with it using the enhanced firmware and NXC, albeit with some flakiness.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
milluzaj
Posts: 31
Joined: 28 Sep 2010, 22:15

Re: Setting up DI Wifi Sensor --Problems

Post by milluzaj »

So I might have a few thoughts on this as I can talk just fine to the dWifi via NXT-G (blocks coming soon) and LabVIEW with the latest enhanced fw.

I actually had to send everything byte by byte to get it to work. (see the LV code posted to my blog) Before that I got nothing back, exactly as you describe. I didnt go digging through your code to see if you had tried this, but it worked for me... For the echo control, I first turned it off (it is on by default after each byte sent) and had to do write a byte and then read a byte and repeat that until I had sent the command.


Hopefully something in there helps.

EDIT: If you would like to try the LV code, shoot me an email or comment on my blog. I will send out a VI for LV 7.1. It is an unfinished VI, but does successfully connect to a network.
Last edited by milluzaj on 07 Jan 2012, 03:29, edited 1 time in total.
Blog: 08milluz.wordpress.com
LMS Shuttle: facebook.com/lmsshuttle
Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests