Announcement

Collapse
No announcement yet.

FB in Linux: can somebody help?

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • FB in Linux: can somebody help?

    Hey guys!

    I have been trying to make FB v3 work under Linux but I cannot really get it to do what the specs say it should do. I have written some code using libusb (actually, not all of it is mine, I borrowed some from another post here, thanks) but I cannot make the outputs behave the way they are supposed to. I can turn output 0 on but it will never time out. If I try to turn any other output on before I toggle output zero, nothing happens. In all, the board behaves erratically.

    What is needed to initialize FB? Is there a special string, control transfer, anything I should send before I start sending and receiving the 64 byte messages? libusb is happy and the outputs do turn on and off (after I toggle output 0) so I guess it is a matter of the correct message exchange. My FB is v3 and the firmware is v 5.2 (according to bytes 62/63 of the received data). Please check out the code below.

    (I have not tried MDX under Windows yet, 'cause,... I have no Windows at the moment and cannot really afford to wait for a 300Mb download).

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <libusb.h>

    libusb_device *fusionBrain;
    libusb_device_handle *fusionBrainHandle;
    libusb_device **devs;
    libusb_context *context;
    unsigned char data_recv[64];
    unsigned char data_sent[64];
    unsigned char EP_OUT;
    unsigned char EP_IN;

    int setsingleio(int ionum, int active)
    {
    int actualReceived, actualSent;
    int toggle = 1;
    int enough = 0;
    int i, j;

    if ((ionum < 0) || (ionum > 11))
    {
    return -1;
    }

    for (i=0;i<64;i++)
    {
    data_sent[i]=0;
    }

    data_sent[61] = 0xff;

    while (enough < 5)
    {
    toggle = 1 - toggle; //flip the flop
    if (active)
    {
    data_sent[ionum] = 0b00000101|(toggle<<1);
    }
    else
    {
    data_sent[ionum] = 0b00000000|(toggle<<1);
    }

    printf("Bit: %i, Toggle: %i\n", data_sent[ionum], toggle <<1);

    libusb_bulk_transfer(fusionBrainHandle,EP_OUT,data _sent,64,&actualSent,500);
    libusb_bulk_transfer(fusionBrainHandle,EP_IN,data_ recv,64,&actualReceived,500);

    for(i = 0; i< 8; i++){
    for(j = 1; j<=8; j++){
    printf("%3i ", data_sent[i*8+j-1]);
    }
    printf("\n");
    }
    printf("********* RECEIVED ************\n");
    for(i = 0; i< 8; i++){
    for(j = 1; j<=8; j++){
    printf("%3i ", data_recv[i*8+j-1]);
    }
    printf("\n");
    }
    usleep(300000);
    enough++;
    }
    return 0;
    }


    int main(int argc, char **argv){
    int input, active;
    int i=0;

    libusb_init(&context);
    libusb_set_debug(context,3);
    EP_OUT = 0x01;
    EP_IN = 0x81;

    libusb_device *dev;
    libusb_get_device_list(NULL,&devs);

    while ((dev = devs[i++]) != NULL)
    {
    struct libusb_device_descriptor desc;
    libusb_get_device_descriptor(dev,&desc);
    if ((desc.idVendor == 0x04d8) && (desc.idProduct == 0x000C))
    {
    printf("Found fusion brain v4\n");
    fusionBrain = dev;
    }
    }

    printf("Trying to open...\n");
    if (libusb_open(fusionBrain,&fusionBrainHandle))
    {
    printf("ERROR\n");
    }
    printf("Opened... trying to claim...\n");
    libusb_claim_interface(fusionBrainHandle,0);



    if ( argc <2 ){
    input = 0;
    active = 1;
    } else {
    input = atoi(argv[1]);
    active = atoi(argv[2]);
    }

    if (setsingleio(input,active))
    {
    printf("Error on set\n");
    }

    }

  • #2
    timers dont work in current firmware.

    nick should be along to help with your other issues

    Comment


    • #3
      No special code has to be done. You just send a byte, read a byte. Send a byte, read a byte. That's it.

      Here is the code from MDX: http://www.fusioncontrolcentre.com/M...cationClass.cs

      Also there is already a Linux something around here that should work.
      Fusion Brain Version 6 Released!
      1.9in x 2.9in -- 47mm x 73mm
      30 Digital Outputs -- Directly drive a relay
      15 Analogue Inputs -- Read sensors like temperature, light, distance, acceleration, and more
      Buy now in the MP3Car.com Store

      Comment


      • #4
        2k1Toaster: yeah some of the code he has was copied/pasted from my program :P

        nousb: Everything looks fine, I've noticed with the FB sometimes I have to send the request several times to get it to actually work, which is why my program has a loop which checks to see if the output was successfully set, and if not it keeps trying until it actually gets set. Perhaps try a similar thing?
        "stop with the REINSTALLS, what do you think we got some lame-o installer!!!" - mitchjs
        RevFE
        My Shop

        Comment


        • #5
          That should not be the case. Are your endpoints configured as mine are in the source?

          Are you keeping the keep alive bit toggling?
          Fusion Brain Version 6 Released!
          1.9in x 2.9in -- 47mm x 73mm
          30 Digital Outputs -- Directly drive a relay
          15 Analogue Inputs -- Read sensors like temperature, light, distance, acceleration, and more
          Buy now in the MP3Car.com Store

          Comment


          • #6
            Originally posted by 2k1Toaster View Post
            That should not be the case. Are your endpoints configured as mine are in the source?

            Are you keeping the keep alive bit toggling?
            Ah, it seems I had forgotten about the keep-alive, I'll have to write that in.

            nousb: I should be able to test your code out either tomorrow or Saturday with my V4, I'll let you know how it works for me.
            "stop with the REINSTALLS, what do you think we got some lame-o installer!!!" - mitchjs
            RevFE
            My Shop

            Comment


            • #7
              Originally posted by 2k1Toaster View Post
              That should not be the case. Are your endpoints configured as mine are in the source?

              Are you keeping the keep alive bit toggling?
              2k1toaster: yes, everything seems to be the same; I do flip the keep-alive (and it shows in the output) every 300 ms.

              malcom2073: Yes, I did borrow some of your code, thank you, I apologize for not acknowledging you in the original post, I was a bit frustrated and could not find where it came from right away. In any case:

              1) according to the spec I read, you cannot check the status of the outputs as those bytes are simply not used (at least in v3) so I cannot really rely on your trick. In reality, I noticed that if I managed to set an output on, it DOES change in the received bytes as well.

              2) I got the endpoints from the lsusb -v output. they are both listed as interrupt EP but bulk trasfers work equally well (I did try interrupt transfers as well, nothing changed).

              3) I did notice that when I send byte 61 set to 0xff only once, the chip wakes up (well, I can see it returned as 0xff that is) for 500 ms and then the byte is reset to 0x00 so I have to constantly send it in a loop. This is not what the spec is saying.

              4) The most frustrating problem is that I cannot change ANY outputs before I turn output 0 on and off at lest once. I tried loops that lasted for minutes, so it is not a problem of not waiting enough. After out 0 is changed once, I can set and turn off any other output.

              5) In malcom2073's original code you use the same array data_recv to both output and read the input in a loop. I separated the arrays into two, so I do not have to worry about data being overwritten (such as byte 61). I thought this was the problem but that did not fix anything.

              6) finally, is it true that that time-out timers are not functioning in this firmware?

              7) Does the Windows code use the dll supplied by Microchip? And if yes, does this have anything to do with it? I do not think so since I can obviously communicate with the device, it just does not react as expected.

              Can someone actually test my code on a v3 FB? I would appreciate a confirmation of my observations. To compile, just use malcolm's original post, if it does not work, I can help with the compilation part (I had to change a few things in the command line, as well)

              Thanks for all your help, guys.

              Alex

              Comment


              • #8
                Well I can say that these anomalies are having to do with either your code or the linux version of the drivers. Using MDX under windows, no outputs need to turn on for any other output to work.

                And we use Microsoft's WinUSB driver. Microchip's driver was extremely buggy and slow when we started so we moved away from it. Microchip actually abandoned their driver as well and they now advocate using Microsoft WinUSB.
                Fusion Brain Version 6 Released!
                1.9in x 2.9in -- 47mm x 73mm
                30 Digital Outputs -- Directly drive a relay
                15 Analogue Inputs -- Read sensors like temperature, light, distance, acceleration, and more
                Buy now in the MP3Car.com Store

                Comment


                • #9
                  Originally posted by nousb View Post
                  malcom2073: Yes, I did borrow some of your code, thank you, I apologize for not acknowledging you in the original post, I was a bit frustrated and could not find where it came from right away.
                  No problem, I'm just glad someone found it helpful.

                  Originally posted by nousb View Post
                  3) I did notice that when I send byte 61 set to 0xff only once, the chip wakes up (well, I can see it returned as 0xff that is) for 500 ms and then the byte is reset to 0x00 so I have to constantly send it in a loop. This is not what the spec is saying.
                  Could this possibly be the keepalive? Perhaps flipping it on and off every other transmission is what 2k1toaster is talking about.
                  "stop with the REINSTALLS, what do you think we got some lame-o installer!!!" - mitchjs
                  RevFE
                  My Shop

                  Comment


                  • #10
                    For V4 boards:






                    Code:
                    *******************************
                    * FUSION BRAIN V4 BYTE STREAM *
                    *                             *
                    * Deterministic Difference:   *
                    *     PID Suffix: E           *
                    *                             *
                    *******************************
                    
                    
                    **** ID CODE ****
                    Version 3a: VID_04D8&PID_000A
                    Version 3b: VID_04D8&PID_000B
                    Version 3c: VID_04D8&PID_000C
                    Version 3d: VID_04D8&PID_000D
                    Version 4:  VID_04D8&PID_000E
                    
                    
                    **** STREAM ****
                    
                    Bytes
                      [00-31] Digital Outputs 00 through 15
                      [32-57] Analogue Inputs 00 through 12
                      [57-59] Not Used Now, Maybe in future
                      [60]    Number of Streams to Receive
                      [61]    Initialize/Watchdog byte
                      [62]    Hardware Version
                      [63]    Firmware Version
                    
                    Bits 0bMxxxxxxL | M = MSB and L = LSB
                      Digital Outputs
                        2 bytes per output
                        [PPPPPPPS][TTTTTTMM]
                          P = Value of PWM
                            ([7bit Value + 1]/128)% duty cycle
                            Details of full period to be determined later
                          S = 1bit state
                            0 = Off
                            1 = on
                          T = 6bits of Timer to shutoff --> [Evaluated Units in Seconds]
                            If 6'bTTTTTT is 0, then shut off immediately on disconnect
                            If 6'bTTTTTT is between 1 and 10 inclusive, then wait [6'bTTTTTT] seconds after disconnect
                            If 6'bTTTTTT is 11, then wait 30 seconds after disconnect
                            If 6'bTTTTTT is 12, then wait 60 seconds after disconnect
                            If 6'bTTTTTT is 13, then wait 90 seconds after disconnect
                            If 6'bTTTTTT is greater than 14, then wait ([6'bTTTTTT] * 10) seconds after disconnect
                          M = 2bit Output Mode
                            2'b00: Normal Full-Off or Full-On Operation Mode
                            2'b01: Pulse Width Modulation Operation Mode
                            2'b10: Yet to be determined
                            2'b11:  Yet to be determined
                      Analogue Inputs
                        2 bytes per input
                        [index][index + 1] = [000000Mx][xxxxxxxL] | M = MSB and L = LSB
                      Number of Streams to Receive
                        1 byte
                        [NNNNNNNN] | N = Number of streams to receive
                          If [8'bNNNNNNNN] is 0 (default) then receive 1 byte and send 1 byte
                          If [8'bNNNNNNNN] is greater than 0 then receive 1 byte and send 1 byte [8'bNNNNNNNN] times
                            Each of these "extra" byte streams received may not coorespond with the details of this byte stream outline
                            Each of the "extra" byte streams sent back to the PC may not coorespond with the details of this byte stream
                      Initialize/Watchdog Byte
                        1 byte
                        [000000IF] | F = Flipping Bit and I = Initialize Bit
                          F = Instead of flipping a bit in every digital output, flip 1 bit constantly
                          I = Needs I high to turn anything on, just like default behaviour of byte[61] now
                      Hardware Version
                        [MMMMLLLL]
                          M = Major Version. Currently Version 4, so MMMM = 0100
                          L = Minor Version. Currently Version 0, so LLLL = 0000 
                      Firmware Version
                        1 byte
                        [????????]
                          Unknown
                    Fusion Brain Version 6 Released!
                    1.9in x 2.9in -- 47mm x 73mm
                    30 Digital Outputs -- Directly drive a relay
                    15 Analogue Inputs -- Read sensors like temperature, light, distance, acceleration, and more
                    Buy now in the MP3Car.com Store

                    Comment


                    • #11
                      nick, he's using a v3, check the OP

                      Comment


                      • #12
                        Originally posted by malcom2073 View Post
                        No problem, I'm just glad someone found it helpful.


                        Could this possibly be the keepalive? Perhaps flipping it on and off every other transmission is what 2k1toaster is talking about.
                        I do flip the keepalive every transaction (that is what toggle = 1 - toggle; line is for), does not help. Somewhere in the forums I remember seeing that every OUT transfer should send byte 61 set to 0xff, so that is fine, I just do not remember seeing it in the spec.
                        As far as the Linux driver goes, I really do not see how that can be a problem: I see that the chip gets the messages (after all something does happen and libusb drives numerous other devices, like my scanner, no problem). According to the USB spec it is really not even a device driver, per se, but the host controller that is responsible for all the transfers, libusb is really just a `fake driver'. Can someone please explain what WinUSB does? Is it Microchip specific, or just a generic implementation of OHCI? Thanks.

                        Alex

                        Comment


                        • #13
                          As far as I can tell, WinUSB seems to be a (Microsoft created) user-space implementation of USB support in windows. Not entirely dissimilar from libusb in Linux.
                          "stop with the REINSTALLS, what do you think we got some lame-o installer!!!" - mitchjs
                          RevFE
                          My Shop

                          Comment


                          • #14
                            For some V3 firmware 61 does go to 0xFF all the time and is used for initialization. Also V3 specifies that every communication, every DO must toggle a keep alive bit.

                            Code:
                                                        switch (_version)
                                                        {
                                                            case MainMDX.BrainVersion.Version_03:
                                                                byte_address = MainMDX.AllDigitalOutputs[digitalOutputIndexArray[i]].Port;
                                                                if (flip) { val += 2; }
                                                                if (beOn) { val += 1; }
                                                                communicationArray[byte_address] = (byte)val;
                                                                break;
                                                            case MainMDX.BrainVersion.Version_04:
                                                                byte_address = (MainMDX.AllDigitalOutputs[digitalOutputIndexArray[i]].Port * 2);
                                                                if (beOn) { val += 1; }
                                                                val_2 += ((MainMDX.AllDigitalOutputs[digitalOutputIndexArray[i]].TimerValue % 64) * 4);
                                                                val_2 += (int)MainMDX.AllDigitalOutputs[digitalOutputIndexArray[i]].Mode;
                                                                val += (MainMDX.AllDigitalOutputs[digitalOutputIndexArray[i]].PWM_Value * 2);
                                                                communicationArray[byte_address] = (byte)val;
                                                                communicationArray[byte_address + 1] = (byte)val_2;
                                                                break;
                                                            default:
                                                                continue;
                                                        }
                            It is very hard to follow your code because it is all scrunched with no spacing. I dont get what you are doing with variable "enough". Also I dont get your reasoning behind setting all outputs to off, in the byte stream and it looks like you are only turning 1 IO back to whatever state you tell it. You need to loop all DO's regardless of if it is changing state or not. If you send a DO a 0x00, it will turn off. I dont see where you are setting all 12 outputs each transfer.


                            WinUSB is the generic USB driver for Vista and XP distributed by Microsoft. Microchip had its own driver when I started coding this program. It was an archaic buggy and slow driver. Over the past few months they have abandoned that driver, and now tell people to use Microsoft WinUSB drivers.

                            The drivers are not drivers in the sense of one device one driver. But they are drivers. It talks directly to the USB chipset and the programmers talk to it, the meaning of a driver. It is very generic driver and Microsoft's hope is for every device to use that single driver if it can. That way you install the driver once, and all your devices work without needing more new 3rd party drivers.
                            Fusion Brain Version 6 Released!
                            1.9in x 2.9in -- 47mm x 73mm
                            30 Digital Outputs -- Directly drive a relay
                            15 Analogue Inputs -- Read sensors like temperature, light, distance, acceleration, and more
                            Buy now in the MP3Car.com Store

                            Comment


                            • #15
                              Originally posted by 2k1Toaster View Post
                              For some V3 firmware 61 does go to 0xFF all the time and is used for initialization. Also V3 specifies that every communication, every DO must toggle a keep alive bit.


                              It is very hard to follow your code because it is all scrunched with no spacing. I dont get what you are doing with variable "enough". Also I dont get your reasoning behind setting all outputs to off, in the byte stream and it looks like you are only turning 1 IO back to whatever state you tell it. You need to loop all DO's regardless of if it is changing state or not. If you send a DO a 0x00, it will turn off. I dont see where you are setting all 12 outputs each transfer.
                              Ok, here is the code with spacing (I hope it works, I have not figured out the markup yet). The program itself is supposed to be used as `prog m b' where m is the number of the output to set, and b is either 1 or 0. So yes, it zeroes all the bytes first, then sets the one I want to , say `on', and the makes a bulk transfer (it also sets byte 61 to 0xff). `enough' was introduced to test the timers and also see how many transfers it takes to get byte 61 back as 0xff. After that all 64 bytes are transferred (and read back) `enough' times (pun intended) I really need the program to exit and the output to stay on until I run it again and turn it off. The most frustrating part is it all almost works .... after I switch input 0 on and off.

                              Edit: One more thing. What I said above means that after the board turns on, `prog 5 1' does nothing, even when I replace `while (enough<5)' to `while (1)' (i.e. loop forever trying to set DO 5 to 1) BUT `prog 0 1' has the desired effect instantly AND after that `prog 5 1' works as well! More weirdness: in the scenario above, if I wait, say 10 min, DO 5 turns itself off and if I run `prog 5 1' again, I cannot set it on (it just flickers while the program is running). Now `prog 0 1' ... you guessed it, makes everything peachy again ... for the next ten minutes.

                              Code:
                              #include <stdio.h>
                              #include <stdlib.h>
                              #include <string.h>
                              #include <libusb.h>
                              
                              #define EP_OUT 0x01
                              #define EP_IN 0x81
                              
                              
                              libusb_device *fusionBrain;
                              libusb_device_handle *fusionBrainHandle;
                              libusb_device **devs;
                              libusb_context *context;
                              unsigned char data_recv[64];
                              unsigned char data_sent[64];
                              
                              int setsingleio(int ionum, int active)
                              {
                                int actualReceived, actualSent;
                                int toggle = 1;
                                int enough = 0;
                                int i, j;
                              
                                if ((ionum < 0) || (ionum > 11))
                                  {
                                    return -1;
                                  }
                              
                                for (i=0;i<64;i++)
                                  {
                                    data_sent[i]=0;
                                  }
                                
                                data_sent[61] = 0xff;
                                
                                while (enough < 5)
                                  {
                                    toggle = 1 - toggle; //flip the flop
                              
                                    if (active)
                              	{
                              	  data_sent[ionum] = 0b00111101|(toggle<<1);
                              	}
                                    else
                              	{
                              	  data_sent[ionum] = 0b00000000|(toggle<<1);
                              	}
                                    
                                    printf("Bit: %i, Toggle: %i\n", data_sent[ionum], toggle <<1);
                                    
                                    libusb_interrupt_transfer(fusionBrainHandle,EP_OUT,data_sent,64,&actualSent,500);
                                    libusb_interrupt_transfer(fusionBrainHandle,EP_IN,data_recv,64,&actualReceived,500);
                                    
                                    //part below only for debugging, no USB transfers 
                              
                                    for(i = 0; i< 8; i++){
                              	for(j = 1; j<=8; j++){
                              	  printf("%3i ", data_sent[i*8+j-1]);
                              	}
                              	printf("\n");
                                    }
                                    printf("********* RECEIVED ************\n");
                                    for(i = 0; i< 8; i++){
                              	for(j = 1; j<=8; j++){
                              	  printf("%3i ", data_recv[i*8+j-1]);
                              	}
                              	printf("\n");
                                    }
                              
                                    // sleep .3 sec and do it again ... 
                              
                                    usleep(300000);
                                    enough++;
                                  }
                                return 0;
                              }
                              
                              
                              int main(int argc, char **argv){
                                int input, active;
                                int i=0;
                                
                                libusb_init(&context);
                                libusb_set_debug(context,3);
                                
                                libusb_device *dev;
                                libusb_get_device_list(NULL,&devs);
                              
                                while ((dev = devs[i++]) != NULL)
                                  {
                                    struct libusb_device_descriptor desc;
                                    libusb_get_device_descriptor(dev,&desc);
                                    if ((desc.idVendor == 0x04d8) && (desc.idProduct == 0x000C))
                              	{
                              	  printf("Found fusion brain v3\n");
                              	  fusionBrain = dev;
                              	}
                                  }
                                
                                printf("Trying to open...\n");
                                if (libusb_open(fusionBrain,&fusionBrainHandle))
                                  {
                                    printf("ERROR\n");
                                  }
                                printf("Opened... trying to claim...\n");
                                libusb_claim_interface(fusionBrainHandle,0);
                                
                                
                                
                                if ( argc < 2 ){
                                  input = 0; 
                                  active = 1;
                                } else {
                                  input = atoi(argv[1]);
                                  active = atoi(argv[2]);
                                }
                                
                                if (setsingleio(input,active))
                                  {
                                    printf("Error on set\n");
                                  }
                              
                              }

                              Comment

                              Working...
                              X