source: thomson/elec/CrO2/software/device.cpp@ 96bc8fa

main
Last change on this file since 96bc8fa was 96bc8fa, checked in by Adrien Destugues <pulkomandy@…>, 12 years ago

C++ refactoring : move USB communication to device class.

git-svn-id: svn://localhost/thomson@11 85ae3b6b-dc8f-4344-a89d-598714f2e4e5

  • Property mode set to 100644
File size: 4.0 KB
Line 
1/* CrO2 datassette emulator
2 * Copyright 2012, Adrien Destugues <pulkomandy@pulkomandy.ath.cx>
3 *
4 * Distributed under the terms of the MIT licence.
5 *
6 * Handles device communication through libusb
7 */
8
9#include "device.h"
10
11#include <iostream> // TODO remove
12
13bool Device::initOnce = false;
14
15const uint32_t Device::vid = 0x16C0;
16const uint32_t Device::pid = 0x05DC;
17const char* Device::vendor = "pulkomandy.ath.cx";
18const char* Device::product = "CrO2";
19
20/* These are the vendor specific commands implemented by our USB device */
21#define PSCMD_CONFIG 0
22#define PSCMD_GET 1
23#define PSCMD_PUT 2
24#define PSCMD_STATUS 3
25
26/* USB device lookup by VID and PID, then Vendor and Product strings, as we use V-USB shared ID. */
27static int usbGetStringAscii(usb_dev_handle *dev, int index, int langid, char *buf, int buflen)
28{
29char buffer[256];
30int rval, i;
31
32 if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, langid, buffer, sizeof(buffer), 1000)) < 0)
33 return rval;
34 if(buffer[1] != USB_DT_STRING)
35 return 0;
36 if((unsigned char)buffer[0] < rval)
37 rval = (unsigned char)buffer[0];
38 rval /= 2;
39 /* lossy conversion to ISO Latin1 */
40 for(i=1;i<rval;i++){
41 if(i > buflen) /* destination buffer overflow */
42 break;
43 buf[i-1] = buffer[2 * i];
44 if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */
45 buf[i-1] = '?';
46 }
47 buf[i-1] = 0;
48 return i-1;
49}
50
51Device::Device()
52{
53 handle = NULL;
54
55 if (!initOnce)
56 {
57 initOnce = true;
58 usb_init();
59 }
60
61 usb_find_busses();
62 usb_find_devices();
63
64 for(struct usb_bus* bus=usb_get_busses(); bus; bus=bus->next)
65 {
66 for(struct usb_device* dev=bus->devices; dev; dev=dev->next)
67 {
68 if(dev->descriptor.idVendor != vid || dev->descriptor.idProduct != pid)
69 continue;
70
71 // Found device with correct VID and PID. Now try to match the strings
72 char string[256];
73 int len;
74 handle = usb_open(dev); /* we need to open the device in order to query strings */
75 if(!handle){
76 std::cerr << "Warning: cannot open USB device: " << usb_strerror() << std::endl;
77 continue;
78 }
79 /* now check whether the names match: */
80 len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, 0x0409, string, sizeof(string));
81 if(len < 0)
82 {
83 std::cerr << "Warning: cannot query manufacturer for device: " << usb_strerror() << std::endl;
84 }
85 else
86 {
87 if(strcmp(string, vendor) == 0){
88 len = usbGetStringAscii(handle, dev->descriptor.iProduct, 0x0409, string, sizeof(string));
89 if(len < 0){
90 std::cerr << "Warning: cannot query product for device: " << usb_strerror() << std::endl;
91 }else{
92 if(strcmp(string, product) == 0)
93 break;
94 }
95 }
96 }
97 usb_close(handle);
98 handle = NULL;
99 }
100 if(handle)
101 break;
102 }
103
104 // At this point, either we have found a device and handle is pointing to it,
105 // or we failed and handle is NULL.
106 //
107 // TODO : use exceptions for error handling; instead of fprintf (not useable in GUI mode).
108 if (!handle)
109 std::cerr << "Could not find USB device \"" << product << "\" with vid=0x" << std::hex << vid << " pid=0x" << pid << std::endl;
110}
111
112
113Device::~Device()
114{
115 usb_close(handle);
116}
117
118
119int Device::read(uint8_t* buffer, size_t max)
120{
121 return usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, PSCMD_GET, 0,0, (char*)buffer, max, 5000);
122
123}
124
125
126int Device::write(uint8_t* buffer, size_t size, int blktype)
127{
128 int rqtype = (size == 0) ? USB_ENDPOINT_IN:USB_ENDPOINT_OUT;
129 return usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | rqtype, PSCMD_PUT, blktype,0 /*checksum*/, (char*)buffer, size, 5000);
130
131}
132
133uint8_t Device::getStatus()
134{
135 uint8_t status;
136 usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, PSCMD_STATUS, 0,0, (char*)&status, 1, 5000);
137 // TODO handle errors (return value)
138 return status;
139}
Note: See TracBrowser for help on using the repository browser.