LCDInfo.com
http://forum.lcdinfo.com/

Using Cairo to draw on the USBD480 display
http://forum.lcdinfo.com/viewtopic.php?f=19&t=2564
Page 1 of 1

Author:  Henri [ Fri Jan 02, 2009 17:40 ]
Post subject:  Using Cairo to draw on the USBD480 display

Here is an example of using the Cairo graphics library to draw simple shapes on the display.

http://www.cairographics.org/
http://www.cairographics.org/samples/

Code:
#include <cairo-win32.h>
#include "USBD480_lib.h"

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

DisplayInfo DisplayProperties;

int main(int argc, char* argv[])
{
   int width = 480;
   int height = 272;
   int i;

   int displays = USBD480_GetNumberOfDisplays();
   if(displays < 1)
   {
      printf("No displays found\n\r");
      return 0;
   }
   else
   {
      printf("%d display(s) found\n\r", displays);   
   }

   for(i=0; i<displays; i++)
   {
      int ret = USBD480_GetDisplayConfiguration(i, &DisplayProperties);
      
      if(ret == USBD480_OK)
         printf("Display: %s, %s, %d, %d, %d\n\r", DisplayProperties.Name,
               DisplayProperties.Username, DisplayProperties.Width, DisplayProperties.Height,
               DisplayProperties.Version);
      else
         printf("Unable to get display info\n\r");
   }

   int ret = USBD480_Open(&DisplayProperties,  0);
   if(ret == USBD480_OK)
   {      
      cairo_surface_t * surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
      cairo_t * cr = cairo_create (surface);

      /* Normalize our context to a (width, height) of (1.0, 1.0) by scaling by our window width and height. */
      //cairo_scale (cr, height, height);
      //cairo_scale (cr, 1, 1);

      /* draw the entire context white. */
      cairo_set_source_rgba (cr, 1, 1, 1, 1);
      cairo_paint(cr);
   
      /* who doesn't want all those nice line settings :) */
        //cairo_set_line_cap  (cr, CAIRO_LINE_CAP_ROUND);
        //cairo_set_line_width(cr, 0.1);
      cairo_set_line_width(cr, 1);

      cairo_set_source_rgba (cr, 0, 0, 1, 1);
        cairo_move_to(cr, 0, 0);
        //cairo_line_to(cr, 0.5, 0.5);
      cairo_line_to(cr, 100, 100);
        cairo_stroke (cr);

      static unsigned int count = 0;

      static double const trs[8][8] = {
        { 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 },
        { 1.0, 0.0,  0.15, 0.30, 0.5, 0.65, 0.8, 0.9 },
        { 0.9, 1.0,  0.0,  0.15, 0.3, 0.5, 0.65, 0.8 },
        { 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5, 0.65},
        { 0.65, 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5 },
        { 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15, 0.3 },
        { 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15 },
        { 0.15, 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0, }
      };

      cairo_translate(cr, width / 2, height /2);

      int i = 0;
      for (i = 0; i < 8; i++)
      {
         cairo_set_line_width(cr, 3);
         cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
         cairo_set_source_rgba(cr, 0, 0, 0, trs[count%8][i]);

         cairo_move_to(cr, 0.0, -10.0);
         cairo_line_to(cr, 0.0, -40.0);
         cairo_rotate(cr, M_PI/4);

         cairo_stroke(cr);
      }

      cairo_set_source_rgba (cr, 0, 0, 0, 1);

      cairo_identity_matrix(cr);
      cairo_translate(cr, 30, 30);
      cairo_move_to(cr, 0.0, 20.0);
      cairo_line_to(cr, 0.0, -20.0);
      cairo_stroke(cr);
      cairo_move_to(cr, 20.0, 0.0);
      cairo_line_to(cr, -20.0, 0.0);
      cairo_stroke(cr);

      cairo_identity_matrix(cr);
      cairo_translate(cr, 480-30, 30);
      cairo_move_to(cr, 0.0, 20.0);
      cairo_line_to(cr, 0.0, -20.0);
      cairo_stroke(cr);
      cairo_move_to(cr, 20.0, 0.0);
      cairo_line_to(cr, -20.0, 0.0);
      cairo_stroke(cr);

      cairo_identity_matrix(cr);
      cairo_translate(cr, 480-30, 272-30);
      cairo_move_to(cr, 0.0, 20.0);
      cairo_line_to(cr, 0.0, -20.0);
      cairo_stroke(cr);
      cairo_move_to(cr, 20.0, 0.0);
      cairo_line_to(cr, -20.0, 0.0);
      cairo_stroke(cr);

      cairo_identity_matrix(cr);
      cairo_translate(cr, 30, 272-30);
      cairo_move_to(cr, 0.0, 20.0);
      cairo_line_to(cr, 0.0, -20.0);
      cairo_stroke(cr);
      cairo_move_to(cr, 20.0, 0.0);
      cairo_line_to(cr, -20.0, 0.0);
      cairo_stroke(cr);


      // some text
      cairo_select_font_face(cr, "Georgia", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
      cairo_set_font_size (cr, 0.10);
      cairo_show_text (cr, "Hello world!");


      // now draw cairo surface to the display
      USBD480_DrawFullScreenBGRA32(&DisplayProperties, (uint32_t*)cairo_image_surface_get_data(surface));

      cairo_destroy (cr);
      cairo_surface_destroy (surface);

      USBD480_Close(&DisplayProperties);

   }
   else
   {
      printf("Unable to open display\n");
   }

   return 0;
}

Author:  Henri [ Fri Jan 02, 2009 17:47 ]
Post subject: 

Here is the same example modified to use direct Libusb commands for handling the display instead of the Windows DLL. This should be quite portable for different environments.

Code:
#include "usb.h"

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

#define USBD480_VID 0x16C0
#define USBD480_PID 0x08A6

#define USBD480_SET_ADDRESS  0xC0 // set sdram address
#define USBD480_SET_FRAME_START_ADDRESS 0xC4 // set frame start address

static struct usb_device *find_usbd480(void)
{
    struct usb_bus *usb_bus;
    struct usb_device *dev;
   
    usb_find_busses();
    usb_find_devices();
    for (usb_bus = usb_busses; usb_bus; usb_bus = usb_bus->next) {
        for (dev = usb_bus->devices; dev; dev = dev->next) {
            if ((dev->descriptor.idVendor == USBD480_VID) &&
                (dev->descriptor.idProduct == USBD480_PID))
                return dev;
        }
    }
    return NULL;
}


int main(int argc, char* argv[])
{
   struct usb_device *usbdev;
   usb_dev_handle *usb_handle = NULL;

   int result;
   unsigned int addr;
   unsigned int writesize;

   int width = 480;
   int height = 272;

   usb_init();
   usbdev = find_usbd480();
   
   if(usbdev)
   {
      usb_handle = usb_open(usbdev);
   
      if(usb_handle==NULL)
         printf("error: usb_open\n");
      
      if(usb_set_configuration(usb_handle, 1) < 0)
      {
         printf("error: setting config 1 failed\n");
         printf("%s\n", usb_strerror() );
         usb_close(usb_handle);
         return 0;
      }
      
      if(usb_claim_interface(usb_handle, 0) < 0)
      {
         printf("error: claiming interface 0 failed\n");
         printf("%s\n", usb_strerror() );
         usb_close(usb_handle);
         return 0;
      }

      cairo_surface_t * surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
      cairo_t * cr = cairo_create (surface);

      /* Normalize our context to a (width, height) of (1.0, 1.0) by scaling by our window width and height. */
      //cairo_scale (cr, height, height);
      //cairo_scale (cr, 1, 1);

      /* draw the entire context white. */
      cairo_set_source_rgba (cr, 1, 1, 1, 1);
      cairo_paint(cr);
   
      /* who doesn't want all those nice line settings :) */
        //cairo_set_line_cap  (cr, CAIRO_LINE_CAP_ROUND);
        //cairo_set_line_width(cr, 0.1);
      cairo_set_line_width(cr, 1);

      cairo_set_source_rgba (cr, 0, 0, 1, 1);
        cairo_move_to(cr, 0, 0);
        //cairo_line_to(cr, 0.5, 0.5);
      cairo_line_to(cr, 100, 100);
        cairo_stroke (cr);

      static unsigned int count = 0;

      static double const trs[8][8] = {
        { 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 },
        { 1.0, 0.0,  0.15, 0.30, 0.5, 0.65, 0.8, 0.9 },
        { 0.9, 1.0,  0.0,  0.15, 0.3, 0.5, 0.65, 0.8 },
        { 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5, 0.65},
        { 0.65, 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5 },
        { 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15, 0.3 },
        { 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15 },
        { 0.15, 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0, }
      };

      cairo_translate(cr, width / 2, height /2);

      int i = 0;
      for (i = 0; i < 8; i++)
      {
         cairo_set_line_width(cr, 3);
         cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
         cairo_set_source_rgba(cr, 0, 0, 0, trs[count%8][i]);

         cairo_move_to(cr, 0.0, -10.0);
         cairo_line_to(cr, 0.0, -40.0);
         cairo_rotate(cr, M_PI/4);

         cairo_stroke(cr);
      }

      cairo_set_source_rgba (cr, 0, 0, 0, 1);

      cairo_identity_matrix(cr);
      cairo_translate(cr, 30, 30);
      cairo_move_to(cr, 0.0, 20.0);
      cairo_line_to(cr, 0.0, -20.0);
      cairo_stroke(cr);
      cairo_move_to(cr, 20.0, 0.0);
      cairo_line_to(cr, -20.0, 0.0);
      cairo_stroke(cr);

      cairo_identity_matrix(cr);
      cairo_translate(cr, 480-30, 30);
      cairo_move_to(cr, 0.0, 20.0);
      cairo_line_to(cr, 0.0, -20.0);
      cairo_stroke(cr);
      cairo_move_to(cr, 20.0, 0.0);
      cairo_line_to(cr, -20.0, 0.0);
      cairo_stroke(cr);

      cairo_identity_matrix(cr);
      cairo_translate(cr, 480-30, 272-30);
      cairo_move_to(cr, 0.0, 20.0);
      cairo_line_to(cr, 0.0, -20.0);
      cairo_stroke(cr);
      cairo_move_to(cr, 20.0, 0.0);
      cairo_line_to(cr, -20.0, 0.0);
      cairo_stroke(cr);

      cairo_identity_matrix(cr);
      cairo_translate(cr, 30, 272-30);
      cairo_move_to(cr, 0.0, 20.0);
      cairo_line_to(cr, 0.0, -20.0);
      cairo_stroke(cr);
      cairo_move_to(cr, 20.0, 0.0);
      cairo_line_to(cr, -20.0, 0.0);
      cairo_stroke(cr);


      // some text
      cairo_select_font_face(cr, "Georgia", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
      cairo_set_font_size (cr, 0.10);
      cairo_show_text (cr, "Hello world!");


      // now draw cairo buffer to display
        unsigned char* surface_data;
      unsigned char rgb565_buf[262144];
      unsigned short *outbuf;
      int r2,g2,b2;

      outbuf = (unsigned short *)&rgb565_buf;
      surface_data = cairo_image_surface_get_data (surface);

      // conversion from 32 bit RGB to 16 bit RGB565
      for(int i=0; i<480*272; i++)
      {
            b2 = (*surface_data++ & 0xf8) >> 3;
            g2 = (*surface_data++ & 0xfc) << 3;
            r2 = (*surface_data++ & 0xf8) << 8;
            *surface_data++;

            *outbuf++ = r2 | g2 | b2;
      }

      writesize = 262144;
      addr = 0;

      result = usb_control_msg( usb_handle, 0x40, USBD480_SET_ADDRESS, addr, (addr>>16)&0xffff, NULL, 0, 500);

      if(result = usb_bulk_write( usb_handle, 0x02, (char*)rgb565_buf, writesize, 500) != writesize)
         printf("bulk_write error %d\n", result);


      cairo_destroy (cr);
      cairo_surface_destroy (surface);


      usb_release_interface(usb_handle, 0);
      usb_close(usb_handle);
   }
   else
   {
      printf("No USBD480 device found\n");
   }

   return 0;
}

Author:  Curtis Newton [ Mon Oct 11, 2010 9:39 ]
Post subject:  Re: Using Cairo to draw on the USBD480 display

Hi,

why is writesize = 262144 when (480*272*2)=261120?

Also, int find_usbd480, should the dev also be static:

static struct usb_device *find_usbd480(void)
{
struct usb_bus *usb_bus;
static struct usb_device *dev;
...

C.

Author:  Henri [ Thu Oct 14, 2010 19:13 ]
Post subject:  Re: Using Cairo to draw on the USBD480 display

Curtis Newton wrote:
why is writesize = 262144 when (480*272*2)=261120?

In this case looks like it has just been rounded up to full 256KB. There's really no reason for that and the more correct value would be the exact 261120. Sending that extra 1024 bytes shouldn't be an issue in most cases though.

Curtis Newton wrote:
Also, int find_usbd480, should the dev also be static:

static struct usb_device *find_usbd480(void)
{
struct usb_bus *usb_bus;
static struct usb_device *dev;
...

C.

I don't really see why the pointer would need to be static in this case. The old value is not needed if the function is executed again.

Author:  yo1dog [ Sun Mar 03, 2013 0:47 ]
Post subject:  Re: Using Cairo to draw on the USBD480 display

Henri wrote:
Curtis Newton wrote:
why is writesize = 262144 when (480*272*2)=261120?

In this case looks like it has just been rounded up to full 256KB. There's really no reason for that and the more correct value would be the exact 261120. Sending that extra 1024 bytes shouldn't be an issue in most cases though.

Actually Curtis is correct. Sending over the incorrect size can result in an error in the USB bulk write. Before seeing this post I was using 262144 and I would sporadically get:
Code:
bulk_write error. -14
USB error: error submitting URB: Bad address

It would also not draw the last 10 or so lines on the LCD. After I set it to the correct size I no longer get this error.

To reiterate: use 261120 NOT 262144.

Page 1 of 1 All times are UTC + 2 hours
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/