Get Input Values Direct Command

Discussion specific to NXT-G, NXC, NBC, RobotC, Lejos, and more.
Post Reply
lizard381
Posts: 44
Joined: 16 Nov 2010, 19:57

Get Input Values Direct Command

Post by lizard381 »

Hi,

I'm having trouble using the GETINPUTVALUES Direct Command. I'm not sure how to access the sensor data that is supposedly written to the responseBufferPtr. When I go through the code and do some error checking, I see that the sendDirectCommand function returns the correct value of 16, so there should be 16 bytes of data written, but when I try to print the data I get garbage. Am I doing something wrong? sendDirectCommand takes in ViPBuf responseBufferPtr as one of its arguments, and from what I've gathered, ViPBuf is the same as ViByte*, so I declared responseBufferPtr as ViByte responseBufferPtr[bufferSize]. At first I thought that perhaps I wasn't formatting the ViBytes properly, and ViByte seems to be the same as unsigned char, but I think that this isn't the problem...

Any help/experience with getting sensor data using the direct command interface would be great!

Cheers,
Kami
I haven't grown past my playing with Legos stage and I don't think I want to :)
Blog: http://nuhlikklebickle.blogspot.com
Kami
lizard381
Posts: 44
Joined: 16 Nov 2010, 19:57

Re: Get Input Values Direct Command

Post by lizard381 »

Hi,

I haven't gotten a reply so I thought I'd send another desperate plea!

In Lego's fantom SDK, they have:

Code: Select all

//! Sends the specified direct command to this NXT.
         /*!
            For more information on direct commands, refer to the LEGO MINDSTORMS NXT Direct
               commands document.
            The command is not sent if the specified status is fatal.
            The command buffer must be non-NULL and the command buffer size in bytes must be
               non-zero.
            If require response is set to true, the response buffer must be non-NULL and the
               response buffer size in bytes must be non-zero.
            If require response is set to false, the response buffer must be NULL and the
               response buffer size in bytes must be zero.
            Both of the buffer size parameters must be small enough to fit in one packet for
               whichever bus the NXT is connected over (USB or Bluetooth).  This means the
               maximum length for a direct command over USB is 63 bytes; over Bluetooth, 65,533
               bytes.
            If any of these requirements are violated, VI_ERROR_USER_BUF will be returned.

            \param requireResponse Boolean flag indicating if a response is required.
            \param commandBufferPtr Buffer containing the direct command to send to the NXT.
            \param commandBufferSizeInBytes Number of bytes in the command buffer.
            \param responseBufferPtr Buffer that will be populated with the response to the direct
               command.
            \param responseBufferSizeInBytes Capacity of the response buffer in bytes.
            \param status Status chaining object.
            \return Number of bytes written to the response buffer.
         */
         virtual ViUInt32 sendDirectCommand( ViBoolean requireResponse, const ViByte commandBufferPtr[],
               ViUInt32 commandBufferSizeInBytes, ViPBuf responseBufferPtr,
               ViUInt32 responseBufferSizeInBytes, tStatus& status ) = 0;
In their Direct Command Documentation, they have a couple of sensor related commands, one of which is SETINPUTMODE, and another is GETINPUTVALUES. I think you're supposed to use these two together to get sensor values by setting requireResponse to true and declaring ViByte responseBufferPtr[63], since ViPBuf is really just ViByte*. I've done all of this, but when I try to say for instance access responseBufferPtr[0], I get garbage, and when I initialize everything to 0 using memset, then I get 0, so it seems like sendDirectCommand isn't writing anything to responseBufferPtr, but sendDirectCommand returns 16, so supposedly 16 bytes have been written to the response buffer.

My question is, am I doing anything stupid, and does anyone have experience using sendDirectCommand and reading the response buffer?

Thanks!

Kami
I haven't grown past my playing with Legos stage and I don't think I want to :)
Blog: http://nuhlikklebickle.blogspot.com
Kami
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: Get Input Values Direct Command

Post by afanofosc »

In Pascal I use code like this:

Code: Select all

    dcResponse : array [0..63] of byte;


function TFantomSpirit.dcBuffer: PByte;
begin
  Result := @dcResponse[0]; // the address of the first element in the 64 byte long dcResponse array
end;


function TFantomSpirit.GetReplyByte(index: integer): Byte;
const
  DCReplyOffset = 2;
begin
  Result := dcResponse[index + DCReplyOffset];
end;

function TFantomSpirit.GetReplyWord(index: integer): Word;
begin
  Result := Word(BytesToCardinal(GetReplyByte(index), GetReplyByte(index+1)));
end;

function TFantomSpirit.GetNXTInputValues(const aPort: byte; var valid,
  calibrated: boolean; var stype, smode: byte; var raw, normalized: word;
  var scaled, calvalue: smallint): boolean;
var
  cmd : TNINxtCmd;
  status : integer;
begin
  Result := IsOpen;
  if not Result then Exit;
  cmd := TNINxtCmd.Create;
  try
    status := kStatusNoError;
    cmd.SetVal(kNXT_DirectCmd, kNXT_DCGetInputValues, aPort);
    iNXT_sendDirectCommandEnhanced(fNXTHandle, 1, cmd.BytePtr, cmd.Len, dcBuffer, 15, status);
    Result := status >= kStatusNoError;
    if not Result then
      Exit;
//    port       := GetReplyByte(0);
    valid      := GetReplyByte(1) <> 0;
    calibrated := GetReplyByte(2) <> 0;
    stype      := GetReplyByte(3);
    smode      := GetReplyByte(4);
    raw        := GetReplyWord(5);
    normalized := GetReplyWord(7);
    scaled     := SmallInt(GetReplyWord(9));
    calvalue   := SmallInt(GetReplyWord(11));
  finally
    cmd.Free;
  end;
end;

function TFantomSpirit.SetNXTInputMode(const aPort, stype, smode: byte): boolean;
var
  cmd : TNINxtCmd;
  status : integer;
begin
  Result := IsOpen;
  if not Result then Exit;
  cmd := TNINxtCmd.Create;
  try
    status := kStatusNoError;
    cmd.SetVal(kNXT_DirectCmdNoReply, kNXT_DCSetInputMode, aPort, stype, smode);
    iNXT_sendDirectCommandEnhanced(fNXTHandle, 0, cmd.BytePtr, cmd.Len, nil, 0, status);
    Result := status >= kStatusNoError;
  finally
    cmd.Free;
  end;
end;
John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
ricardocrl
Posts: 117
Joined: 27 Dec 2010, 19:27

Re: Get Input Values Direct Command

Post by ricardocrl »

Hi Kami,

I've done something with the C++ API like you are doing, not using that direct command, but two others.

If you are not getting any value in the response, make sure you send the correct direct command. In the structure of the direct command you have to start with the command number byte, and not with the command type, like it is suggested in the "LEGO MINDSTORMS NXT Direct Commands" document. The very first byte, the command type, is written by the method sendDirrectCommand() you call.
So, you should send: { 0x07, INPUT_PORT }. Don't forget of course to set the response flag to true. Your buffer size seems to be correct and the data type is fine, ViByte blabla[].

In the response you may not get the byte 0x02. The first you will get is (again) the byte 1, from the Direct Command document, the command number: 0x07. Check your responseBufferPtr[1] which will contain the Status Byte. If something goes wrong, you will not get 0, which means success.

Good luck! ;)
lizard381
Posts: 44
Joined: 16 Nov 2010, 19:57

Re: Get Input Values Direct Command

Post by lizard381 »

John, I didn't realise that you used Pascal, so your NeXT Tools don't use Lego's C++ API?

ricardocrl, the direct command I send is correct, I have checked all that you mentioned. I've already been able to use the direct command for SETOUTPUTSTATE, it's just getting a response that seems to elude me. I checked responseBufferPtr[1], its still not returning 0x07. The array remains in its initial state. I actually just found a post in the nxt++ forums with the same exact complaint. I'm now looking at the read and write commands and wondering if using a combination of those can replace using sendDirectCommand.

If anyone has experience with this, please let me know! Anything would be helpful.

Kami
I haven't grown past my playing with Legos stage and I don't think I want to :)
Blog: http://nuhlikklebickle.blogspot.com
Kami
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: Get Input Values Direct Command

Post by afanofosc »

Since I am using Pascal (Delphi) I use the C version of the Fantom API. You may want to consider using it as I know that it works correctly. My code above can be easily ported to C but if you have any questions about it just ask. I have written a send direct command function using read and write. Here it is:

Code: Select all


procedure iNXT_sendDirectCommandEnhanced(nxtHandle : FantomHandle; requireResponse : byte;
  inputBufferPtr : Pbyte; inputBufferSize : Cardinal; outputBufferPtr : PByte;
  outputBufferSize : Cardinal; var status : integer; bEnhanced : boolean = false);
var
  BufOut, BufIn : PByte;
  dstatus : integer;
begin
  // is this an enhanced direct command?
  if requireResponse = 127 then
  begin
    if status < kStatusNoError then Exit;
    BufOut := nil;
    GetMem(BufOut, inputBufferSize+1);
    try
      BufOut^ := kNXT_DirectCmd;
      if not Boolean(requireResponse) then
        BufOut^ := BufOut^ or kNXT_NoResponseMask;
      inc(BufOut);
      Move(inputBufferPtr^, BufOut^, inputBufferSize);
      dec(BufOut);
      iNXT_write(nxtHandle, BufOut, inputBufferSize+1, status);
      if Boolean(requireResponse) and (status >= kStatusNoError) then
      begin
        BufIn := nil;
        GetMem(BufIn, outputBufferSize+1);
        try
          iNXT_read(nxtHandle, BufIn, outputBufferSize+1, status);
          if Boolean(requireResponse) and (status >= kStatusNoError) then
          begin
            inc(BufIn);
            Move(BufIn^, outputBufferPtr^, outputBufferSize);
            dec(BufIn);
          end;
        finally
          FreeMem(BufIn);
        end;
      end
      else
      begin
        // no response required or error occurred on write
        // drain our channel of any leftover data
        BufIn := nil;
        GetMem(BufIn, 1);
        try
          dstatus := kStatusNoError;
          while dstatus = kStatusNoError do
            iNXT_read(nxtHandle, BufIn, 1, dstatus);
        finally
          FreeMem(BufIn);
        end;
      end;
    finally
      FreeMem(BufOut);
    end;
  end
  else
    iNXT_sendDirectCommand(nxtHandle, requireResponse, inputBufferPtr,
      inputBufferSize, outputBufferPtr, outputBufferSize, status);
end;
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
lizard381
Posts: 44
Joined: 16 Nov 2010, 19:57

Re: Get Input Values Direct Command

Post by lizard381 »

Thank you so much! I finally understand, I got it working similarly to how you have it implemented.

I have a related question, what Sensor Type and Sensor Mode do you use for the color sensor to get the light to turn on? I thought it would be LIGHT_ACTIVE and PCTFULLSCALEMODE, but I just get a return value of 100 when I set it like that.

Kami
I haven't grown past my playing with Legos stage and I don't think I want to :)
Blog: http://nuhlikklebickle.blogspot.com
Kami
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: Get Input Values Direct Command

Post by afanofosc »

The color sensor uses the types and modes shown in the NBC code snippet from NXTDefs.h below. I've also included a snippet from NBCCommon.h.

Code: Select all

#define __SetSensorColorFull(_port) \
  setin IN_TYPE_COLORFULL, _port, TypeField \
  setin IN_MODE_RAW, _port, InputModeField \
  __ResetSensor(_port)

#define __SetSensorColorRed(_port) \
  setin IN_TYPE_COLORRED, _port, TypeField \
  setin IN_MODE_PCTFULLSCALE, _port, InputModeField \
  __ResetSensor(_port)

#define __SetSensorColorGreen(_port) \
  setin IN_TYPE_COLORGREEN, _port, TypeField \
  setin IN_MODE_PCTFULLSCALE, _port, InputModeField \
  __ResetSensor(_port)

#define __SetSensorColorBlue(_port) \
  setin IN_TYPE_COLORBLUE, _port, TypeField \
  setin IN_MODE_PCTFULLSCALE, _port, InputModeField \
  __ResetSensor(_port)

#define __SetSensorColorNone(_port) \
  setin IN_TYPE_COLORNONE, _port, TypeField \
  setin IN_MODE_PCTFULLSCALE, _port, InputModeField \
  __ResetSensor(_port)

Code: Select all

#define IN_TYPE_COLORFULL      0x0D /*!< NXT 2.0 color sensor in full color mode */
#define IN_TYPE_COLORRED       0x0E /*!< NXT 2.0 color sensor with red light */
#define IN_TYPE_COLORGREEN     0x0F /*!< NXT 2.0 color sensor with green light */
#define IN_TYPE_COLORBLUE      0x10 /*!< NXT 2.0 color sensor with blue light */
#define IN_TYPE_COLORNONE      0x11 /*!< NXT 2.0 color sensor with no light */
#define IN_TYPE_COLOREXIT      0x12 /*!< NXT 2.0 color sensor internal state */
John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
lizard381
Posts: 44
Joined: 16 Nov 2010, 19:57

Re: Get Input Values Direct Command

Post by lizard381 »

Thank you so much, that was exactly what I was looking for!

Did Lego release this information? I was looking for it but I don't see any updates for new sensors in the documentation.

Also, do they have new codes for some of the other sensors that seem to be HiTechnic sensors that they now sell on their site?

Cheers,
Kami
I haven't grown past my playing with Legos stage and I don't think I want to :)
Blog: http://nuhlikklebickle.blogspot.com
Kami
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: Get Input Values Direct Command

Post by afanofosc »

The source code for the 1.2x firmwares which LEGO has released contains the new types for the NXT 2.0 color sensor. The NXT-G block for the color sensor generates code that I decompiled using BricxCC so that I could see how the sensor was configured and how its values were read. That, along with the firmware source code, told me everything I needed to know to add NBC/NXC API constants and functions.

HiTechnic devices are often I2C aka lowspeed sensors. You will need to use the lowspeed direct commands to complete an I2C transaction in order to read values from these kind of devices, including the LEGO Ultrasonic sensor, the LEGO Temperature sensor, and the LEGO E-Meter sensor. Many of the mindsensors.com devices are also I2C devices. Both companies post sample programs that demonstrate how to read values from their devices. A small number of HiTechnic and mindsensors.com devices are analog sensors but they use types and modes of other LEGO analog sensors. You will need to refer to the respective websites for docs or sample code that shows how to use them. Or you could look in the NXTDefs.h header file to see how I have implemented NBC/NXC API functions for them.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
Post Reply

Who is online

Users browsing this forum: No registered users and 16 guests