BlitzMax Modules

BlitzMax Forums/BlitzMax Programming/BlitzMax Modules

How can i create my own BlitzMax Module! My idea is to create a usb mod from libusb! Is that possible and easy or not?

Hi,
Creating your own module shouldn't be so hard,
I've never done it myself, but I found this tutorial:
http://www.blitzbasic.com/Community/posts.php?topic=42290

Hope that helps, Good luck! :)

I will take a look to it. But i think it is a hard work!

Doesn't look too difficult.

If one were to do it properly of course, you might do libusb (for linux/OS X support) and libusb-win32 (for windows) wrapped up in the same module. Then you cover all the bases.

If you do go ahead, please include half-decent documentation and examples. The whole idea of having a wrapped library is that you don't want to have to go and look at the original library documentation to get an idea what such-and-such function is meant to do.
And if you can hide pointers and structs from the user, more the better.
If I have to use library pointers, via a module, directly in my app then I may as well have not bothered using the module at all and simply talked to the library instead.

Just some thoughts ;-)

Hi Brucey,

Is it this that you meen:

http://search.cpan.org/~gwadej/Device-USB-0.21/lib/Device/USB.pm

Again @ Brucey:

I found this:

www.math.ias.edu/doc/libusb-devel-0.1.8/manual.ps

Reward MainframeOSX

My idea is to create a usb mod from libusb!

I would be interested in having such a module too! Although I'm too busy at the moment to help, sorry!

Is this the right way:

Module pub.libusb
ModuleInfo "Version: 1.00"
ModuleInfo "Modserver: Not yet implemented"
ModuleInfo "Author: Sven Schwiecker(MacOS part)"
ModuleInfo "License: Public Domain"
ModuleInfo "Contact: Sven.Schweicker@..."
ModuleInfo "Homepage: www.SvenSchwiecker.de"


Import "usb.c"
Import "linux.c"
Import "darwin.c"
Import "error.c"


Extern "C"

Function usb_descriptor_header (bLength:Int Ptr,bDescriptorType:Int Ptr)
Function usb_string_descriptor (bLength:Int Ptr,bDescriptorType:Int Ptr,wData:Int Ptr)
Function usb_hid_descriptor (bLength:Int Ptr,bDescriptorType:Int Ptr,bcdHDI:Int Ptr,bCountryCode:Int Ptr,bNumDescriptors:Int Ptr)

EndExtern

After Build Modules no errors is shown.
Is this good?

Try using the functions and see what happens.

usb_descriptor_header etc, aren't functions. They are C-structs.

This function "usb_init()" initializes the library, which, according to the docs, you call *first*.

"usb_find_busses()" looks like it returns a count of busses... and "usb_find_devices()" looks to return a count of devices... etc.

Since it's LGPL, you may wish to rather link to a DLL/.so/.dylib, rather than compile in or statically link to the library - unless your code is in-house or GPL'd.

struct usb_descriptor_header {
	u_int8_t  bLength;
	u_int8_t  bDescriptorType;
};

If you have, say, a pointer to this struct, you could retrieve the "length" field with something like :
length = Byte Ptr(headerPtr)[0]
.. and for the descriptor type :
descType = Byte Ptr(headerPtr)[1]
, since they both appear to be byte-size values.

Things like :
	struct usb_interface *interface;

inside another struct, is a pointer to a struct of "usb_interface", which itself might contain pointers to other structs.

The two ways you might go about accessing all this information is either via the Ptr access like I've mentioned above, or by writing glue c/cpp code which makes your BlitzMax code easier to manage.

Hi,

My first test of the libusb module

Strict

Module Pub.libusb

ModuleInfo "Version: 1.00"
ModuleInfo "Modserver: Not yet implemented"
ModuleInfo "Author: Sven Schwiecker(MacOS part)"
ModuleInfo "License: Public Domain"
ModuleInfo "Contact: Sven.Schwiecker@..."
ModuleInfo "Homepage: www.SvenSchwiecker.de"

?MacOS
Import "darwin.c"
Import "error.c"
Import "usb.c"
Import "descriptors.c"


Extern "C"
Function usb_init()
Function usb_find_busses()
Function usb_find_devices()
EndExtern

Testprogramm:

'usbtest

usb_init()
Print x
x=usb_find_busses()
Print x
x=usb_find_devices()
Print x

and it works. Now it comes the next part.

I suggest you use your own namespace, rather than Pub.

Also, you might find it easier to define the return values of the functions...
Function usb_find_busses:Int()


If you use SuperStrict, it will force you to define things like this, which in the long run should help maintainability, since you only have to look at the function definition to see what it returns, if anything.

I change the namespace as soon as possible, at this time it is only for testings.
The problem that i had is, i have import "linux.c" and this is a problem under MacOS X.
But thanks for the help @Brucey, i hope i can make more then this.
It is my first time to make a module!

Need a little bit more help:


SuperStrict

Module Pub.libusb

ModuleInfo "Version:	 1.00"
ModuleInfo "Modserver:	 Not yet implemented"
ModuleInfo "Author:	 Sven Schwiecker(MacOS part)"
ModuleInfo "License:	 Public Domain"
ModuleInfo "Contact:	 Sven.Schwiecker@..."
ModuleInfo "Homepage:	 www.SvenSchwiecker.de"

?MacOS
Import "darwin.c"
Import "usb.c"
Import "descriptors.c"
Import "error.c"

Extern "C"
Function usb_init()
Function usb_find_busses:Int()
Function usb_find_devices:Int()
Function usb_device:Int()
EndExtern

All the function work in my Testprogram. The function usb_device:int() returns this: 2080899750 is this the adress of the last usb_device?
How can i get a list of all USB-Busses and USB-Devices from
this c-source (i'm working under MacOS X):
/*
 * Main API entry point
 *
 * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@...;
 *
 * This library is covered by the LGPL, read LICENSE for details.
 */

#include <stdlib.h>	/* getenv */
#include <stdio.h>	/* stderr */
#include <string.h>	/* strcmp */
#include <errno.h>

#include "usbi.h"

int usb_debug = 0;
struct usb_bus *usb_busses = NULL;

int usb_find_busses(void)
{
  struct usb_bus *busses, *bus;
  int ret, changes = 0;

  ret = usb_os_find_busses(&busses);
  if (ret < 0)
    return ret;

  /*
   * Now walk through all of the busses we know about and compare against
   * this new list. Any duplicates will be removed from the new list.
   * If we don't find it in the new list, the bus was removed. Any
   * busses still in the new list, are new to us.
   */
  bus = usb_busses;
  while (bus) {
    int found = 0;
    struct usb_bus *nbus, *tbus = bus->next;

    nbus = busses;
    while (nbus) {
      struct usb_bus *tnbus = nbus->next;

      if (!strcmp(bus->dirname, nbus->dirname)) {
        /* Remove it from the new busses list */
        LIST_DEL(busses, nbus);

        usb_free_bus(nbus);
        found = 1;
        break;
      }

      nbus = tnbus;
    }

    if (!found) {
      /* The bus was removed from the system */
      LIST_DEL(usb_busses, bus);
      usb_free_bus(bus);
      changes++;
    }

    bus = tbus;
  }

  /*
   * Anything on the *busses list is new. So add them to usb_busses and
   * process them like the new bus it is.
   */
  bus = busses;
  while (bus) {
    struct usb_bus *tbus = bus->next;

    /*
     * Remove it from the temporary list first and add it to the real
     * usb_busses list.
     */
    LIST_DEL(busses, bus);

    LIST_ADD(usb_busses, bus);

    changes++;

    bus = tbus;
  }

  return changes;
}

int usb_find_devices(void)
{
  struct usb_bus *bus;
  int ret, changes = 0;

  for (bus = usb_busses; bus; bus = bus->next) {
    struct usb_device *devices, *dev;

    /* Find all of the devices and put them into a temporary list */
    ret = usb_os_find_devices(bus, &devices);
    if (ret < 0)
      return ret;

    /*
     * Now walk through all of the devices we know about and compare
     * against this new list. Any duplicates will be removed from the new
     * list. If we don't find it in the new list, the device was removed.
     * Any devices still in the new list, are new to us.
     */
    dev = bus->devices;
    while (dev) {
      int found = 0;
      struct usb_device *ndev, *tdev = dev->next;

      ndev = devices;
      while (ndev) {
        struct usb_device *tndev = ndev->next;

        if (!strcmp(dev->filename, ndev->filename)) {
          /* Remove it from the new devices list */
          LIST_DEL(devices, ndev);

          usb_free_dev(ndev);
          found = 1;
          break;
        }

        ndev = tndev;
      }

      if (!found) {
        /* The device was removed from the system */
        LIST_DEL(bus->devices, dev);
        usb_free_dev(dev);
        changes++;
      }

      dev = tdev;
    }

    /*
     * Anything on the *devices list is new. So add them to bus->devices and
     * process them like the new device it is.
     */
    dev = devices;
    while (dev) {
      struct usb_device *tdev = dev->next;

      /*
       * Remove it from the temporary list first and add it to the real
       * bus->devices list.
       */
      LIST_DEL(devices, dev);

      LIST_ADD(bus->devices, dev);

      /*
       * Some ports fetch the descriptors on scanning (like Linux) so we don't
       * need to fetch them again.
       */
      if (!dev->config) {
        usb_dev_handle *udev;

        udev = usb_open(dev);
        if (udev) {
          usb_fetch_and_parse_descriptors(udev);

          usb_close(udev);
        }
      }

      changes++;

      dev = tdev;
    }

    usb_os_determine_children(bus);
  }

  return changes;
}

void usb_set_debug(int level)
{
  if (usb_debug || level)
    fprintf(stderr, "usb_set_debug: Setting debugging level to %d (%s)\n",
	level, level ? "on" : "off");

  usb_debug = level;
}

void usb_init(void)
{
  if (getenv("USB_DEBUG"))
    usb_set_debug(atoi(getenv("USB_DEBUG")));

  usb_os_init();
}

usb_dev_handle *usb_open(struct usb_device *dev)
{
  usb_dev_handle *udev;

  udev = malloc(sizeof(*udev));
  if (!udev)
    return NULL;

  udev->fd = -1;
  udev->device = dev;
  udev->bus = dev->bus;
  udev->config = udev->interface = udev->altsetting = -1;

  if (usb_os_open(udev) < 0) {
    free(udev);
    return NULL;
  }

  return udev;
}

int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf,
	size_t buflen)
{
  /*
   * We can't use usb_get_descriptor() because it's lacking the index
   * parameter. This will be fixed in libusb 1.0
   */
  return usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
			(USB_DT_STRING << 8) + index, langid, buf, buflen, 1000);
}

int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen)
{
  char tbuf[255];	/* Some devices choke on size > 255 */
  int ret, langid, si, di;

  /*
   * Asking for the zero'th index is special - it returns a string
   * descriptor that contains all the language IDs supported by the
   * device. Typically there aren't many - often only one. The
   * language IDs are 16 bit numbers, and they start at the third byte
   * in the descriptor. See USB 2.0 specification, section 9.6.7, for
   * more information on this. */
  ret = usb_get_string(dev, 0, 0, tbuf, sizeof(tbuf));
  if (ret < 0)
    return ret;

  if (ret < 4)
    return -EIO;

  langid = tbuf[2] | (tbuf[3] << 8);

  ret = usb_get_string(dev, index, langid, tbuf, sizeof(tbuf));
  if (ret < 0)
    return ret;

  if (tbuf[1] != USB_DT_STRING)
    return -EIO;

  if (tbuf[0] > ret)
    return -EFBIG;

  for (di = 0, si = 2; si < tbuf[0]; si += 2) {
    if (di >= (buflen - 1))
      break;

    if (tbuf[si + 1])	/* high byte */
      buf[di++] = '?';
    else
      buf[di++] = tbuf[si];
  }

  buf[di] = 0;

  return di;
}

int usb_close(usb_dev_handle *dev)
{
  int ret;

  ret = usb_os_close(dev);
  free(dev);

  return ret;
}

struct usb_device *usb_device(usb_dev_handle *dev)
{
  return dev->device;
}

void usb_free_dev(struct usb_device *dev)
{
  usb_destroy_configuration(dev);
  free(dev->children);
  free(dev);
}

struct usb_bus *usb_get_busses(void)
{
  return usb_busses;
}

void usb_free_bus(struct usb_bus *bus)
{
  free(bus);
}



You will find using {codebox}{/codebox} (replace curly brackets with square) for your code, takes up much less room, and keeps the formatting.

Is this better?

Much.

Have a look at testlibusb.c in the tests dir of libusb.
It shows how to access all the information.

Specifically :
  usb_init();

  usb_find_busses();
  usb_find_devices();

  for (bus = usb_busses; bus; bus = bus->next) {
    if (bus->root_dev && !verbose)
      print_device(bus->root_dev, 0);
    else {
      struct usb_device *dev;

      for (dev = bus->devices; dev; dev = dev->next)
        print_device(dev, 0);
    }
  }

"usb_busses" is a static variable, which you won't be able to access directly from BlitzMax. You'll need to add some C/C++ wrapping. The struct that it points to is a linked-list of buses, each of which has information on the devices that are connected to it.

:o)

Hi Brucey,

Can you make a little example?