source: thomson/elec/CrO2/software/device.cpp@ 192e299

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

Cleanup.

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

  • Property mode set to 100644
File size: 4.2 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#include "k5.h"
11
12bool Device::initOnce = false;
13Device* Device::instance = NULL;
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
27// Gets the device instance. Throws an error message if something bad happens.
28Device& Device::getDevice() throw(const char*)
29{
30 if (instance == NULL)
31 instance = new Device();
32
33 return *instance;
34}
35
36
37/* USB device lookup by VID and PID, then Vendor and Product strings, as we use
38 * V-USB shared ID. */
39static int usbGetStringAscii(usb_dev_handle *dev, int index, int langid,
40 char *buf, int buflen)
41{
42char buffer[256];
43int rval, i;
44
45 if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
46 (USB_DT_STRING << 8) + index, langid, buffer, sizeof(buffer), 1000)) < 0)
47 return rval;
48 if(buffer[1] != USB_DT_STRING)
49 return 0;
50 if((unsigned char)buffer[0] < rval)
51 rval = (unsigned char)buffer[0];
52 rval /= 2;
53 /* lossy conversion to ISO Latin1 */
54 for(i=1;i<rval;i++){
55 if(i > buflen) /* destination buffer overflow */
56 break;
57 buf[i-1] = buffer[2 * i];
58 if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */
59 buf[i-1] = '?';
60 }
61 buf[i-1] = 0;
62 return i-1;
63}
64
65Device::Device() throw(const char*)
66{
67 handle = NULL;
68
69 if (!initOnce)
70 {
71 initOnce = true;
72 usb_init();
73 }
74
75 usb_find_busses();
76 usb_find_devices();
77
78 for(struct usb_bus* bus=usb_get_busses(); bus; bus=bus->next)
79 {
80 for(struct usb_device* dev=bus->devices; dev; dev=dev->next)
81 {
82 if(dev->descriptor.idVendor != vid || dev->descriptor.idProduct != pid)
83 continue;
84
85 // Found device with correct VID and PID. Now try to match the
86 // vendor and product strings
87 char string[256];
88 int len;
89 handle = usb_open(dev);
90 /* we need to open the device in order to query strings */
91 if(!handle){
92 continue;
93 }
94 /* now check whether the names match: */
95 len = usbGetStringAscii(handle, dev->descriptor.iManufacturer,
96 0x0409, string, sizeof(string));
97 if(len >= 0)
98 {
99 if(strcmp(string, vendor) == 0){
100 len = usbGetStringAscii(handle, dev->descriptor.iProduct,
101 0x0409, string, sizeof(string));
102 if(len >= 0){
103 if(strcmp(string, product) == 0)
104 break;
105 }
106 }
107 }
108 usb_close(handle);
109 handle = NULL;
110 }
111 if(handle)
112 break;
113 }
114
115 // At this point, either we have found a device and handle is pointing to it,
116 // or we failed and handle is NULL.
117 if (!handle)
118 throw "Device not found. Is the USB cable plugged correctly?";
119}
120
121
122Device::~Device()
123{
124 usb_close(handle);
125}
126
127
128int Device::read(uint8_t* buffer, size_t max)
129{
130 return usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
131 PSCMD_GET, 0,0, (char*)buffer, max, 5000);
132
133}
134
135
136int Device::write(uint8_t* buffer, size_t size, int blktype)
137{
138 int rqtype = (size == 0) ? USB_ENDPOINT_IN:USB_ENDPOINT_OUT;
139 return usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | rqtype,
140 PSCMD_PUT, blktype,0 /*checksum*/, (char*)buffer, size, 5000);
141
142}
143
144
145void Device::write(K5& file)
146{
147 for (int k = 0; k < file.getBlockCount(); k++)
148 {
149 // wait for motor on
150 while (getStatus() & 8)
151 Sleep(1000);
152
153 K5::Block block = file.getBlock(k);
154
155 int nBytes = write(block.data, block.length - 1, block.type);
156 // TODO error handling
157
158 // TODO wait for correct time (read status from usb OR compute from size+type)
159 Sleep(1400);
160 }
161}
162
163uint8_t Device::getStatus()
164{
165 uint8_t status;
166 usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
167 PSCMD_STATUS, 0,0, (char*)&status, 1, 5000);
168 // TODO handle errors (return value)
169 return status;
170}
Note: See TracBrowser for help on using the repository browser.