Announcement

Collapse
No announcement yet.

HQCT Driver.

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

  • HQCT Driver.

    Hello everyone.

    I decided not to release the HQCT driver this weekend because I want to add some more features (frequency seeking, etc...). The good news is the driver runs very well and my seeking algorithm will be very fast (compared to the HQCT Driver example).

    Now, developers -- I have a few options for getting data from the device to userspace.

    Option 1: A non blocking read() function. You can read from the device driver as you would with any other file. e.g:
    Code:
    fd = open("/dev/hqct0", O_RDWR); 
    read(fd, buf, 32);
    This function will return immediately with the current data. I.e: it will not wait for the radio to provide new data since the status is buffered. This is optimal for one-shot reads. Now, the problem is, if you put this in a loop to read from the device then you will get many unneeded reads. You will have to rely on a timer which may still cause unneeded reads or lost reports. Please tell me if you do not understand this.

    Option 2: A blocking read() function. This will behave like option 1, except that it will wait until new data is available. Therefore, you can safely place a read loop inside a thread to get new data as soon as it is available. The con is that if you want to just get the current data then you will have to wait until the radio sends the next report.

    Option 3: A hybrid approach. We can have a read() function that blocks. Then we can an ioctl() function that will return the current data without blocking. So, a non-blocking read would look like:
    Code:
    fd = open("/dev/hqct0", O_RDWR); 
    ioctl(fd, HQCTIOC_READ, buf);
    Option 4: Like option 3 except the read() is nonblocking and the ioctl() blocks.

    Option 5: Not really an option, but more of an enhancement to any of the above options. We can also have a proc file (/proc/hqct) which contains human-friendly data of all the attached radios. Oh yeah, the device driver supports multiple units attached.

    Of course, all of these details will be hidden behind a friendly C library eventually (no reason there couldn't be a Python,etc. library too). The benefit is, all the hardware details will be stored in the device driver so it is trival to write a user program to interface with the device

  • #2
    would a mixture of Option 3 and Option 5 be an option? or a Blocking read(); with an human readable /proc output?
    ---
    "Flying is easy, Just jump at the ground and miss"
    --Ford Perfect, HHGTTG

    Comment


    • #3
      Originally posted by Kusuriya
      would a mixture of Option 3 and Option 5 be an option? or a Blocking read(); with an human readable /proc output?
      Yes. I think this is what I will end up doing anyways. Option 3 and 5 are already implemented. read() is non-blocking while ioctl(HQCTIOC_READ) blocks. The proc file will come later. The ioctl calls are much more efficient than parsing proc output. Proc is naturally a bit slower, so I will probably only update it every 5 radio-updates or so. You can get the status of the driver and certain radio features with various ioctl calls too, but you need to read the whole report for anything else. There is no reason the C api couldn't parse the report and provide a ton of get_fubar() functions.

      Seeking support is finished. It moves between stations much faster than its Windows equivalent. The seeking functions are non-blocking so you can easily use them in non-threaded applications and not lock your program while the radio scans. If you want the seek function to block, it is as simple as:
      Code:
      ioctl(fd, HQCTIOC_SEEK_UP, 0); 
      ioctl(fd, HQCTIOC_READ, 0);
      The first function returns immediately but the read function will not return until the radio is finished seeking and new data is available. Note, you can use standard non-blocking read() while the radio is tuning.

      I still need to add some more calls and there is alot of user error checking that needs to be added before I release the first version. The proc file and RDS will come later.

      Comment


      • #4
        yah normally i just use proc to check if its there or to pull info off with like a TAIL file.. the proc file is just a good way to check if its up or not but its sounding pretty good heh
        ---
        "Flying is easy, Just jump at the ground and miss"
        --Ford Perfect, HHGTTG

        Comment


        • #5
          Originally posted by Kusuriya
          yah normally i just use proc to check if its there or to pull info off with like a TAIL file.. the proc file is just a good way to check if its up or not but its sounding pretty good heh
          Yes, I suspect you could also use inotify to signal when the proc file changes.

          Now, I found a problem in the seeking method which could cause systems to hardlock. I was using a semaphore from an interrupt handler. I am changing the system to use tasklets for this task. Unfortunately, I am also in the middle of moving, so it may be a couple days before I get anything usable out.

          Thanks for you patience! It will be worth the wait. This radio sounds soooo good.

          Comment


          • #6
            heh man making me want to build it before i get home XD
            ---
            "Flying is easy, Just jump at the ground and miss"
            --Ford Perfect, HHGTTG

            Comment


            • #7
              Ugh!!!! I have a version that works fine but it relies on a busy wait that runs in kernel mode, so basically the whole system is locked out for 30ms everytime you send a request to tune. I'm working with someone to resolve this issue. I don't feel comfortable releasing until this problem is solved.

              Comment


              • #8
                that does sound a little ugly.. but man take your time lol the more your hurry it the more bugs there are gonna be expecally if its gonna have its own wait timer or polling code that runs independantly of the kernels "heart beat"
                ---
                "Flying is easy, Just jump at the ground and miss"
                --Ford Perfect, HHGTTG

                Comment


                • #9
                  Originally posted by Kusuriya
                  that does sound a little ugly.. but man take your time lol the more your hurry it the more bugs there are gonna be expecally if its gonna have its own wait timer or polling code that runs independantly of the kernels "heart beat"
                  Good news, I just implemented a solution that does not use busy waiting. There is no polling or threads either, everything is driven from interrupts and user requests. I am driving back to my campus tommorow and will be staying there for a few days. I would probably have a version up tommorow otherwise. Fortunately, I can bring my test rig and get some work done there.

                  I decided to swap the read() and ioctl(HQCTIOC_READ) functions so that read() blocks. I did this because it is ideal to use the blocking read to block until the previous instruction has finished. read() is ideal for the blocking read because you can call it with a buffer of zero length while the ioctl call will assume you have allocated a buffer for it. I suppose one could call the ioctl read with a NULL address in order to block, but a blocking read() is easy to call from bash etc... Any comments? I'm still 50-50 with this decision.

                  So, with tuning out of the way, all that is left (for the first version) is making sure the common TEF set commands (Volume, Treble, Bass, etc..) can be set through ioctl and providing a method for serializing the TEF configuration back and forth.

                  Comment


                  • #10
                    thought read was a kernel blocked funtion by default anyway but sounds like a plan.. heh dont drive to fast tho dont want you to get in a car accident on your way to start your coding marathon. but man it sounds like you have something... have you had a chance to play "bug hunt" on it yet?
                    ---
                    "Flying is easy, Just jump at the ground and miss"
                    --Ford Perfect, HHGTTG

                    Comment


                    • #11
                      Originally posted by Kusuriya
                      thought read was a kernel blocked funtion by default anyway but sounds like a plan.. heh dont drive to fast tho dont want you to get in a car accident on your way to start your coding marathon. but man it sounds like you have something... have you had a chance to play "bug hunt" on it yet?
                      read() is by default because most of the drivers implement it that way. The OS doesn't actually do any of that work. Now, I have everything working fine but there is one place where things seem to mess up. For some reason the HQCT radio stops sending reports if it receives two reports too quickly. So, I need to rework the innards one more time... this time I need to make sure that two reports are never sent less than ~50ms apart. Even if the user places two requests within that time frame.

                      If you want to try out the current version then let me know. I just finished the user api and you can do pretty much anything (except RDS). Many more flags are configurable than with the Windows demo. Just don't try to send too many message close together or else you will have to cycle power on the radio. So, I'll post it if anyone actually wants it.

                      Comment


                      • #12
                        Humm.. I need some place to dump files.

                        Comment


                        • #14
                          OK. But in the meantime you can check out this zip file. The forums wouldn't let me upload a tarball.

                          I worked around the problem from above by simply placing a sleep at the end of the ioctl function. This causes ioctl to always block for at least 100ms, which in turn, doesn't allow you to send messages fast enough to overload the radio. This is just a fix until I redo the mechanics again.

                          So, it 'works', but it causes needless waiting and some lag. For example, if you send 20 tef commands at once, then you have to wait ~2seconds for them to all be processed. This should be good enough for people to start writing software with the API.

                          I am going to rework the innards and it will actually end up being a simplification. The user API will not change (except maybe for some additions). I plan to keep a queue of work needed to be done and have a kthread that loops on the queue and sends out the next packet every 100ms. Changing TEF settings (volume, bass, etc..) will still block until the command has executed, but it won't be a dumb wait like it is currently. Also, if the user sends multiple TEF settings then they will be collapsed into a single packet. For instance, if you set the volume to -10,-9,-8, and -7 within 100ms, then only the -7 will be sent.

                          Development notes I forgot to place in README:
                          Do not send TEF settings while seeking and do not seek while the module is initializing. These problems are easy to fix, but I'm going to wait for the new version.
                          You can use hqct_get_tef() to get the current TEF string. You should do this before your program closes and store the output to a file. This way your program can read the settings from file and use it as the 2nd parameter of hqct_init().

                          Files contained:
                          hqct.c - HQCT device driver
                          hqct.h - HQCT device driver header
                          hqctapi.c - The HQCT C API, check this file for documentation
                          hqctapi.h - The HQCT C API header, include this file in your programs
                          demo.c - Demonstation including initialization, blocking seek, and a few TEF settings.
                          Makefile - builds the driver, api, and demo
                          README - Read this, it will provides installation and development tips.

                          Attached Files

                          Comment


                          • #15
                            I see that the driver has been downloaded several times. Has anyone tried it out? I want to know what kinds of problems people are having with it (hopefully none). I'm also looking for suggestions. I'm not going to work on the new version until I get _some_ feedback for this one. Must... spend... more time.... on MP3 Player!

                            Comment

                            Working...
                            X