NXT access via USB on OSX

Discussion specific to NXT-G, NXC, NBC, RobotC, Lejos, and more.
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: NXT access via USB on OSX

Post by afanofosc »

Code from my FantomSpirit.pas file may be useful in getting your calls to the Fantom API's sendDirectCommand function working when you require a response. Here are a few snippets:

Code: Select all

      cmd.SetVal(kNXT_DirectCmd, kNXT_DCGetBatteryLevel);
      iNXT_sendDirectCommandEnhanced(fNXTHandle, 1, cmd.BytePtr, cmd.Len, dcBuffer, 4, status);

    cmd.MakeCmdWithFilename(kNXT_DirectCmd, kNXT_DCStartProgram, tmp);
    iNXT_sendDirectCommandEnhanced(fNXTHandle, 1, cmd.BytePtr, cmd.Len, dcBuffer, 2, status);

    cmd.SetVal(kNXT_DirectCmd, kNXT_DCStopProgram);
    iNXT_sendDirectCommandEnhanced(fNXTHandle, 1, cmd.BytePtr, cmd.Len, dcBuffer, 2, status);

    cmd.SetVal(kNXT_DirectCmd, kNXT_DCGetOutputState, aPort);
    iNXT_sendDirectCommandEnhanced(fNXTHandle, 1, cmd.BytePtr, cmd.Len, dcBuffer, 24, status);

    cmd.SetVal(kNXT_DirectCmd, kNXT_DCGetInputValues, aPort);
    iNXT_sendDirectCommandEnhanced(fNXTHandle, 1, cmd.BytePtr, cmd.Len, dcBuffer, 15, status);

    cmd.SetVal(b, kNXT_DCKeepAlive);
    iNXT_sendDirectCommandEnhanced(fNXTHandle, 1, cmd.BytePtr, cmd.Len, dcBuffer, 6, status)

    cmd.SetVal(kNXT_DirectCmd, kNXT_DCLSGetStatus, aPort);
    iNXT_sendDirectCommandEnhanced(fNXTHandle, 1, cmd.BytePtr, cmd.Len, dcBuffer, 3, status);

    cmd.SetVal(kNXT_DirectCmd, kNXT_DCLSRead, aPort);
    iNXT_sendDirectCommandEnhanced(fNXTHandle, 1, cmd.BytePtr, cmd.Len, dcBuffer, 19, status);

    cmd.SetVal(kNXT_DirectCmd, kNXT_DCGetCurrentProgramName);
    iNXT_sendDirectCommandEnhanced(fNXTHandle, 1, cmd.BytePtr, cmd.Len, dcBuffer, 22, status);

    cmd.SetVal(kNXT_DirectCmd, kNXT_DCGetButtonState, idx, Ord(reset));
    iNXT_sendDirectCommandEnhanced(fNXTHandle, 1, cmd.BytePtr, cmd.Len, dcBuffer, 3, status);

    cmd.SetVal(kNXT_DirectCmd, kNXT_DCMessageRead, remote, local, Ord(remove));
    iNXT_sendDirectCommandEnhanced(fNXTHandle, 1, cmd.BytePtr, cmd.Len, dcBuffer, 63, status);

    cmd.SetVal(kNXT_DirectCmd, kNXT_DCGetVMState);
    iNXT_sendDirectCommandEnhanced(fNXTHandle, 1, cmd.BytePtr, cmd.Len, dcBuffer, 6, status, True);

    cmd.SetVal(kNXT_DirectCmd, kNXT_DCSetVMState, state);
    iNXT_sendDirectCommandEnhanced(fNXTHandle, 1, cmd.BytePtr, cmd.Len, dcBuffer, 6, status, True);

    cmd.SetVal(kNXT_DirectCmd, kNXT_DCGetProperty, kNXT_Property_Debugging);
    iNXT_sendDirectCommandEnhanced(fNXTHandle, 1, cmd.BytePtr, cmd.Len, dcBuffer, 6, status, True);

const
  NXT_CMD_RESPONSE_LENGTH : array[0..$ff] of byte = (
   3, // DCStartProgram (x00)
   3, // DCStopProgram (x01)
   3, // DCPlaySoundFile (x02)
   3, // DCPlayTone (x03)
   3, // DCSetOutputState (x04)
   3, // DCSetInputMode (x05)
  25, // DCGetOutputState (x06)
  16, // DCGetInputValues (x07)
   3, // DCResetInputScaledValue (x08)
   3, // DCMessageWrite (x09)
   3, // DCResetMotorPosition (x0a)
   5, // DCGetBatteryLevel (x0b)
   3, // DCStopSoundPlayback (x0c)
   7, // DCKeepAlive (x0d)
   4, // DCLSGetStatus (x0e)
   3, // DCLSWrite (x0f)
  20, // DCLSRead (x10)
  23, // DCGetCurrentProgramName (x11)
   0, // DCGetButtonState (not implemented) (x12)
  64, // DCMessageRead (x13)
   0, // DCRESERVED1 (x14)
   0, // DCRESERVED2 (x15)
   0, // DCRESERVED3 (x16)
   0, // DCRESERVED4 (x17)
   0, // DCRESERVED5 (x18)
  64, // DCDatalogRead (1.28+) (x19)
   3, // DCDatalogSetTimes (1.28+) (x1a)
   4, // DCBTGetContactCount (1.28+) (x1b)
  21, // DCBTGetContactName (1.28+) (x1c)
   4, // DCBTGetConnCount (1.28+) (x1d)
  21, // DCBTGetConnName (1.28+) (x1e)
   3, // DCSetProperty(1.28+) (x1f)
   7, // DCGetProperty (1.28+) (x20)
   3, // DCUpdateResetCount (1.28+) (x21)
   7, // RC_SET_VM_STATE (enhanced only) (x22)
   7, // RC_GET_VM_STATE (enhanced only) (x23)
  15, // RC_SET_BREAKPOINTS (enhanced only) (x24)
  15, // RC_GET_BREAKPOINTS (enhanced only) (x25)
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // (x26-x2f)
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // (x30-x3f)
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // (x40-x4f)
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // (x50-x5f)
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // (x60-x6f)
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // (x70-x7f)
   8, //   OPENREAD        = 0x80,
   4, //   OPENWRITE       = 0x81,
  64, //   READ            = 0x82, (actually is a variable length response)
   6, //   WRITE           = 0x83,
   4, //   CLOSE           = 0x84,
  23, //   DELETE          = 0x85,
  28, //   FINDFIRST       = 0x86,
  28, //   FINDNEXT        = 0x87,
   7, //   VERSIONS        = 0x88,
   4, //   OPENWRITELINEAR = 0x89,
   7, //   OPENREADLINEAR  = 0x8A, (not actually implemented)
   4, //   OPENWRITEDATA   = 0x8B,
   8, //   OPENAPPENDDATA  = 0x8C,
   4, //   CROPDATAFILE    = 0x8D,    /* New cmd for datalogging */
   0, //   XXXXXXXXXXXXXX  = 0x8E,
   0, //   XXXXXXXXXXXXXX  = 0x8F,
  34, //   FINDFIRSTMODULE = 0x90,
  34, //   FINDNEXTMODULE  = 0x91,
   4, //   CLOSEMODHANDLE  = 0x92,
   0, //   XXXXXXXXXXXXXX  = 0x93,
  64, //   IOMAPREAD       = 0x94, (actually is a variable length response)
   9, //   IOMAPWRITE      = 0x95,
   0, //   XXXXXXXXXXXXXX  = 0x96,
   7, //   BOOTCMD         = 0x97,  (can only be executed via USB)
   3, //   SETBRICKNAME    = 0x98,
   0, //   XXXXXXXXXXXXXX  = 0x99,
  10, //   BTGETADR        = 0x9A,
  33, //   DEVICEINFO      = 0x9B,
   0, //   XXXXXXXXXXXXXX  = 0x9C,
   0, //   XXXXXXXXXXXXXX  = 0x9D,
   0, //   XXXXXXXXXXXXXX  = 0x9E,
   0, //   XXXXXXXXXXXXXX  = 0x9F,
   3, //   DELETEUSERFLASH = 0xA0,
   5, //   POLLCMDLEN      = 0xA1,
  64, //   POLLCMD         = 0xA2,
  44, //   RENAMEFILE      = 0xA3,
   3, //   BTFACTORYRESET  = 0xA4,
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // (xA5-xAF)
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // (xB0-xBf)
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // (xC0-xCf)
   0, //   RESIZEDATAFILE  = 0xD0,
   0, //   SEEKFROMSTART   = 0xD1,
   0, //   SEEKFROMCURRENT = 0xD2,
   0, //   SEEKFROMEND     = 0xD3
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // (xD4-xDF)
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // (xE0-xEF)
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  // (xF0-xFF)
);
The length you pass into the sendDirectCommand function has to be 1 less than the expected response length. So for example, you expect 64 bytes from MessageRead but you have to pass in 63 or it will not work.

Also see my implementation of iNXT_sendSystemCommand and iNXT_sendDirectCommandEx in FantomSpirit.pas. These both work with USB and Bluetooth and for commands that do not require a response and those that do require a response. There is no reason this code would not work correctly if written equivalently in C/C++ or any other programming language.

The cmd.BytePtr, cmd.Len code in the above snippets simply drops the first byte of the cmd object's buffer (since it is the DC or SC byte) and decrements the length by one. So a buffer that contains 2 bytes such as kNXT_DirectCmd, kNXT_DCGetBatteryLevel will be sent as just one byte (kNXT_DCGetBatteryLevel) with a length of 1. Internally it appends the direct command byte ORed with the require response flag and it increments the length by one. Again, see how I do this exact thing using iNXT_read and iNXT_write in my working implementation of iNXT_sendSystemCommand and iNXT_sendDirectCommandEx in FantomSpirit.pas.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
linusa
Posts: 228
Joined: 16 Oct 2010, 11:44
Location: Aachen, Germany
Contact:

Re: NXT access via USB on OSX

Post by linusa »

To add our version of "iNXT_sendDirectCommand" (we're only using it for USB, but it works with retrieving answers, too): http://www.mindstorms.rwth-aachen.de/tr ... ket.m#L261

Code: Select all

[whatever command reply status] = calllib('fantom', 'nFANTOM100_iNXT_sendDirectCommand', h.Handle(), NeedReply, packet(2:end)', length(packet), reply, length(reply), 0);
After executing the call, reply contains the byte array with the answer payload, and status the statusbyte (see Mindstorms BDK). Command should just be the command/packet type byte of the request.

I think the MATLAB wrapper does some internal handling of how the reply-buffer retrieved, i.e. the mechanism parses the C-Header-File, realizes what the (possible) output arguments are, and creates this functions signature...

As you can see from the source code file, we need to pre-allocate the reply-buffer with the correct length of the expected reply.
RWTH - Mindstorms NXT Toolbox for MATLAB
state of the art in nxt remote control programming
http://www.mindstorms.rwth-aachen.de
MotorControl now also in Python, .net, and Mathematica
lizard381
Posts: 44
Joined: 16 Nov 2010, 19:57

Re: NXT access via USB on OSX

Post by lizard381 »

afanofosc wrote:The length you pass into the sendDirectCommand function has to be 1 less than the expected response length. So for example, you expect 64 bytes from MessageRead but you have to pass in 63 or it will not work.

Also see my implementation of iNXT_sendSystemCommand and iNXT_sendDirectCommandEx in FantomSpirit.pas. These both work with USB and Bluetooth and for commands that do not require a response and those that do require a response. There is no reason this code would not work correctly if written equivalently in C/C++ or any other programming language.

The cmd.BytePtr, cmd.Len code in the above snippets simply drops the first byte of the cmd object's buffer (since it is the DC or SC byte) and decrements the length by one. So a buffer that contains 2 bytes such as kNXT_DirectCmd, kNXT_DCGetBatteryLevel will be sent as just one byte (kNXT_DCGetBatteryLevel) with a length of 1. Internally it appends the direct command byte ORed with the require response flag and it increments the length by one. Again, see how I do this exact thing using iNXT_read and iNXT_write in my working implementation of iNXT_sendSystemCommand and iNXT_sendDirectCommandEx in FantomSpirit.pas.

John Hansen
Yea so your implementation of sendDirectCommand when you require a response essentially calls write and read. I've done that, and it works over USB the first time I poll a specific sensor, then it doesn't work after that, I get a VISA error that I haven't been able to get rid of, I mentioned this in another thread I think (https://sourceforge.net/apps/phpbb/mind ... t=10#p6907). Over Bluetooth this implementation doesn't work (the write/read work around) and I can't figure out why, just using the fantom command sendDirectCommand when I don't require a response works fine.
linusa wrote:To add our version of "iNXT_sendDirectCommand" (we're only using it for USB, but it works with retrieving answers, too): http://www.mindstorms.rwth-aachen.de/tr ... ket.m#L261

Code: Select all

[whatever command reply status] = calllib('fantom', 'nFANTOM100_iNXT_sendDirectCommand', h.Handle(), NeedReply, packet(2:end)', length(packet), reply, length(reply), 0);
After executing the call, reply contains the byte array with the answer payload, and status the statusbyte (see Mindstorms BDK). Command should just be the command/packet type byte of the request.

I think the MATLAB wrapper does some internal handling of how the reply-buffer retrieved, i.e. the mechanism parses the C-Header-File, realizes what the (possible) output arguments are, and creates this functions signature...

As you can see from the source code file, we need to pre-allocate the reply-buffer with the correct length of the expected reply.
I know I have to pre-allocate the memory needed for the reply buffer, if you look at the posts in this older thread (https://sourceforge.net/apps/phpbb/mind ... ?f=3&t=487), you can see where I explained that the function would return that it's written 16 bytes, but nothing would be in the responseBuffer. I'm not sure if you have suggestions on ways to get around this, it would be great if I could.

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: NXT access via USB on OSX

Post by afanofosc »

Kami,

I am curious what your theory is to explain why my code works correctly over both USB and Bluetooth but your code does not? The only theory I can come up with that makes any sense is that you are doing something different code-wise than I am - perhaps sending the wrong lengths, as I explained. The wrong length guarantees a failure. If you are using the C Fantom API (hopefully you are not using the C++ API which I have heard is somewhat buggy) then it should be trivially easy to port my Pascal code to C/C++ and do exactly what I am doing. If you do that then your code would have to work as well as mine does.

If you like, you can send me your code and I will see if I can get it working for you.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
lizard381
Posts: 44
Joined: 16 Nov 2010, 19:57

Re: NXT access via USB on OSX

Post by lizard381 »

afanofosc wrote:Kami,

I am curious what your theory is to explain why my code works correctly over both USB and Bluetooth but your code does not? The only theory I can come up with that makes any sense is that you are doing something different code-wise than I am - perhaps sending the wrong lengths, as I explained. The wrong length guarantees a failure. If you are using the C Fantom API (hopefully you are not using the C++ API which I have heard is somewhat buggy) then it should be trivially easy to port my Pascal code to C/C++ and do exactly what I am doing. If you do that then your code would have to work as well as mine does.

If you like, you can send me your code and I will see if I can get it working for you.

John Hansen
This differentiation between the C API and the C++ API is confusing me a bit, when I downloaded the fantom sdk, it came with a single set of header files...is there somewhere else where you can get another set?

I've tried fiddling around with the length, but to no avail, it's still returning 0 bytes when I try to read from the sensors over bluetooth.

Unfortunately I'm not able to send you my code.

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
tcwan
Posts: 186
Joined: 30 Sep 2010, 07:39

Re: NXT access via USB on OSX

Post by tcwan »

lizard381 wrote: This differentiation between the C API and the C++ API is confusing me a bit, when I downloaded the fantom sdk, it came with a single set of header files...is there somewhere else where you can get another set?

I've tried fiddling around with the length, but to no avail, it's still returning 0 bytes when I try to read from the sensors over bluetooth.

Unfortunately I'm not able to send you my code.

Kami
There are 'extern C' API functions defined in the same include files. John Hansen was referring to using the C API instead of the C++ API.
Sorry, I haven't tried to solve the Bluetooth read() problem, too busy with other issues since USB works for now....
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest