From: <iku...@ya...> - 2009-07-07 15:36:24
|
Check your monitor's documentation and the USB 2.0 spec for asynchronous transfers. Differences in how the monitor responds for supposedly-identical command sets are generally issues with the monitor or communication, not the command sets. If you look at the pyusb source code, it's pretty much a simple wrapper for libusb. That is, there's no real difference (except convenience in language choice) between programming a driver using pyusb and programming one using libusb. That being said, I'm not entirely sure that pyusb includes support for the asynchronous commands... and it was a fairly recent addition to libusb as well. There's an outside chance that there's a bug in the asynch code, but it's more likely there's a difference between the way the monitor handles asynchronous vs. synchronous input Also try isolating the particular sections of the code where the difference happens. The file you sent is long, has no comments, and has very few print statements. If you're debugging, add in lots more prints, preferably showing the hex code for the transfers sent to & from the monitor at each write / read command. Then compare those hex codes to each other for the sync and async versions - and compare both to the USB spec and the programmer's manual for the monitor. -Sarah --- On Mon, 7/6/09, Scott Sibley <sis...@gm...> wrote: From: Scott Sibley <sis...@gm...> Subject: [Pyusb-users] Hoping for suggestions - libusb-1.0 related To: pyu...@li... Date: Monday, July 6, 2009, 8:04 PM This isn't entirely pyusb related, but it could possibly affect the future of pyusb. I've been working on an LCD controller, with the goal of being able to control multiple, concurrent devices. I needed USB support for my newest LCD, so I began work on that using pyusb-0.1. However, it became clear pretty quickly that I needed an asynchronous solution, so I set out to work on this wielding ctypes and a fresh copy of libusb-1.0. I've run into some snags, overcoming most (Python's GIL was getting in the way for instance), but there's this one issue that just won't go away. See, the operations work fine synchronously following the steps below in sequence. We can view asynchronous I/O as a 5 step process: Allocation: allocate a libusb_transfer (This is self.transfer)Filling: populate the libusb_transfer instance with information about the transfer you wish to perform (libusb_fill_bulk_transfer)Submission: ask libusb to submit the transfer (libusb_submit_transfer)Completion handling: examine transfer results in the libusb_transfer structure (libusb_handle_events and libusb_handle_events_timeout)Deallocation: clean up resources (Not shown below)However, when performing these steps asynchronously only a portion of the LCD is filled with pixels. I've been through libusb's debug messages and usbmon's output, and between async and sync there are no differences, except when I look at the LCD for the results. I'm starting to believe that this is just not possible with Python+ctypes, which is why I said this could possibly affect pyusb. I am of course hoping for an answer to this, and having some experience in both Python and libusb I'm hoping maybe you would have one. I've attached some code if you feel up to looking into this. Also, I have a question opened at Stackoverflow here: http://stackoverflow.com/questions/1060305/usb-sync-vs-async-vs-semi-async-partially-answered-now -----Inline Attachment Follows----- ------------------------------------------------------------------------------ Enter the BlackBerry Developer Challenge This is your chance to win up to $100,000 in prizes! For a limited time, vendors submitting new applications to BlackBerry App World(TM) will have the opportunity to enter the BlackBerry Developer Challenge. See full prize details at: http://p.sf.net/sfu/blackberry -----Inline Attachment Follows----- _______________________________________________ Pyusb-users mailing list Pyu...@li... https://lists.sourceforge.net/lists/listinfo/pyusb-users |
From: Scott S. <sis...@gm...> - 2009-07-07 17:58:50
|
#include <errno.h> #include <pthread.h> #include <signal.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <libusb-1.0/libusb.h> #include "font_6x8.h" #define VENDOR_ID 0x04d8 #define PRODUCT_ID 0xc002 #define OUT_REPORT_LED_STATE 0x81 #define OUT_REPORT_LCD_BACKLIGHT 0x91 #define OUT_REPORT_LCD_CONTRAST 0x92 #define OUT_REPORT_CMD 0x94 #define OUT_REPORT_DATA 0x95 #define OUT_REPORT_CMD_DATA 0x96 #define SCREEN_H 64 #define SCREEN_W 256 typedef struct Command { void (*cb) (unsigned char *data, int size); unsigned char data[64]; int size; } Command; struct Command queue[1024]; int queueEnd = 0; int queueStart = 0; unsigned char locked = 0; static unsigned char pLG_framebuffer[256*64]; /* used to display white text on black background or inverse */ unsigned char inverted = 0; static struct libusb_device_handle *devh = NULL; static struct libusb_transfer *lcd_transfer = NULL; static int do_exit = 0; static pthread_t poll_thread; static pthread_t command_thread; static pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER; static pthread_mutex_t exit_cond_lock = PTHREAD_MUTEX_INITIALIZER; static void queue_push(void (*cb), unsigned char *data, int size) { int i; if (queueEnd >= 1024) return; queue[queueEnd].cb = cb; queue[queueEnd].size = size; for(i = 0; i < size; i++) { queue[queueEnd].data[i] = data[i]; } printf("Data0: %x, %x, %x\n", queue[queueEnd].data[0], queue[queueEnd].data[1], queue[queueEnd].data[2]); queueEnd++; } struct Command * queue_pop(void) { if( queueStart >= queueEnd ) return NULL; return &queue[queueStart++]; } static void request_exit(int code) { do_exit = code; pthread_cond_signal(&exit_cond); } static void *command_thread_main(void *arg) { struct Command *cmd; while (!do_exit) { if(locked) continue; locked = 1; cmd = queue_pop(); if(cmd != NULL) { cmd->cb(cmd->data, cmd->size); printf("Data1: %x, %x, %x, %d\n", cmd->data[0], cmd->data[1], cmd->data[2], cmd->size); } } return NULL; } static void *poll_thread_main(void *arg) { int r = 0; while ( !do_exit) { struct timeval tv = { 1, 0}; r = libusb_handle_events_timeout(NULL, &tv); if( r < 0 ) { request_exit(2); break; } } return NULL; } void cb_lcd(struct libusb_transfer *transfer) { if(transfer->status != LIBUSB_TRANSFER_COMPLETED) { fprintf(stderr, "transfer not completed!\n"); } printf("cb_lcd: length=%d, actual_length=%d\n", transfer->length, transfer->actual_length); locked = 0; } void drv_pLG_real_send(unsigned char *data, int size) { libusb_fill_interrupt_transfer(lcd_transfer, devh, LIBUSB_ENDPOINT_OUT + 1, data, size, cb_lcd, NULL, 0); libusb_submit_transfer(lcd_transfer); } void drv_pLG_send(unsigned char *data, int size) { queue_push(drv_pLG_real_send, data, size); } static void drv_pLG_update_img() { unsigned char cmd3[64] = { OUT_REPORT_CMD_DATA }; /* send command + data */ unsigned char cmd4[64] = { OUT_REPORT_DATA }; /* send data only */ int index, bit, x, y; unsigned char cs, line; unsigned char pixel; for (cs = 0; cs < 4; cs++) { unsigned char chipsel = (cs << 2); //chipselect for (line = 0; line < 8; line++) { cmd3[0] = OUT_REPORT_CMD_DATA; cmd3[1] = chipsel; cmd3[2] = 0x02; cmd3[3] = 0x00; cmd3[4] = 0x00; cmd3[5] = 0xb8 | line; cmd3[6] = 0x00; cmd3[7] = 0x00; cmd3[8] = 0x40; cmd3[9] = 0x00; cmd3[10] = 0x00; cmd3[11] = 32; cmd4[0] = OUT_REPORT_DATA; cmd4[1] = chipsel | 0x01; cmd4[2] = 0x00; cmd4[3] = 0x00; cmd4[4] = 32; for (index = 0; index < 32; index++) { pixel = 0x00; for (bit = 0; bit < 8; bit++) { x = cs * 64 + index; y = (line * 8 + bit + 0) % SCREEN_H; if (pLG_framebuffer[y * 256 + x] ^ inverted) pixel |= (1 << bit); } cmd3[12 + index] = pixel; } for (index = 32; index < 64; index++) { pixel = 0x00; for (bit = 0; bit < 8; bit++) { x = cs * 64 + index; y = (line * 8 + bit + 0) % SCREEN_H; if (pLG_framebuffer[y * 256 + x] ^ inverted) pixel |= (1 << bit); } cmd4[5 + (index - 32)] = pixel; } drv_pLG_send(cmd3, 44); drv_pLG_send(cmd4, 38); } } } void drv_pLG_clear(void) { unsigned char cmd[3] = { 0x93, 0x01, 0x00 }; /* init display */ unsigned char cmd2[9] = { OUT_REPORT_CMD }; /* init display */ unsigned char cmd3[64] = { OUT_REPORT_CMD_DATA }; /* clear screen */ unsigned char cmd4[64] = { OUT_REPORT_CMD_DATA }; /* clear screen */ int init, index; unsigned char cs, line; drv_pLG_send(cmd, 3); for (init = 0; init < 4; init++) { unsigned char cs = ((init << 2) & 0xFF); cmd2[0] = OUT_REPORT_CMD; cmd2[1] = cs; cmd2[2] = 0x02; cmd2[3] = 0x00; cmd2[4] = 0x64; cmd2[5] = 0x3F; cmd2[6] = 0x00; cmd2[7] = 0x64; cmd2[8] = 0xC0; drv_pLG_send(cmd2, 9); } for (cs = 0; cs < 4; cs++) { unsigned char chipsel = (cs << 2); //chipselect for (line = 0; line < 8; line++) { cmd3[0] = OUT_REPORT_CMD_DATA; cmd3[1] = chipsel; cmd3[2] = 0x02; cmd3[3] = 0x00; cmd3[4] = 0x00; cmd3[5] = 0xb8 | line; cmd3[6] = 0x00; cmd3[7] = 0x00; cmd3[8] = 0x40; cmd3[9] = 0x00; cmd3[10] = 0x00; cmd3[11] = 32; unsigned char temp = 0; for (index = 0; index < 32; index++) { cmd3[12 + index] = temp; } drv_pLG_send(cmd3, 64); cmd4[0] = OUT_REPORT_DATA; cmd4[1] = chipsel | 0x01; cmd4[2] = 0x00; cmd4[3] = 0x00; cmd4[4] = 32; for (index = 32; index < 64; index++) { temp = 0x00; cmd4[5 + (index - 32)] = temp; } drv_pLG_send(cmd4, 64); } } } static int find_device(void) { devh = libusb_open_device_with_vid_pid(NULL, VENDOR_ID, PRODUCT_ID); return devh ? 0 : -EIO; } static void sighandler(int signum) { request_exit(1); } static void fill_pixels(void) { int i, r, c, row, col; char *text = "picoLCDGraphics "; char ch; memset(pLG_framebuffer, 0, sizeof(pLG_framebuffer)); for( i = 0; i < 256/6*8; i++) { r = i / 42 * 8; c = i % 42 * 6; ch = text[i % strlen(text)]; for( row = 0; row < 8; row++ ) { for( col = 0; col < 6; col++ ) { if (Font_6x8[(int)ch][row] & (1 << (5-col)) ) pLG_framebuffer[(r + row) * 256 + c + col] = 1; } } } } int main(void) { struct sigaction sigact; int r = 1; r = libusb_init(NULL); if( r < 0) { fprintf(stderr, "failed to initialize libusb\n"); exit(1); } r = find_device(); if(r < 0) { fprintf(stderr, "Could not find device\n"); goto out; } r = libusb_claim_interface(devh, 0); if (r < 0) { fprintf(stderr, "usb_claim_interface error %d\n", r); goto out; } printf("claimed interface\n"); lcd_transfer = libusb_alloc_transfer(0); if(!lcd_transfer) { fprintf(stderr, "Unable to allocate transfer\n"); goto out; } drv_pLG_clear(); fill_pixels(); drv_pLG_update_img(); sigact.sa_handler = sighandler; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); sigaction(SIGQUIT, &sigact, NULL); r = pthread_create(&poll_thread, NULL, poll_thread_main, NULL); if (r) goto out_deinit; r = pthread_create(&command_thread, NULL, command_thread_main, NULL); if (r) goto out_deinit; while (!do_exit) { pthread_mutex_lock(&exit_cond_lock); pthread_cond_wait(&exit_cond, &exit_cond_lock); pthread_mutex_unlock(&exit_cond_lock); } pthread_join(poll_thread, NULL); pthread_join(command_thread, NULL); if (lcd_transfer) { r = libusb_cancel_transfer(lcd_transfer); if (r < 0) goto out_deinit; } while (lcd_transfer) if (libusb_handle_events(NULL) < 0) break; out_deinit: libusb_free_transfer(lcd_transfer); out_release: libusb_release_interface(devh, 0); out: libusb_close(devh); libusb_exit(NULL); return r >= 0 ? r : -r; } |