source: thomson/elec/CrO2/software/device.cpp@ 53c4be3

main
Last change on this file since 53c4be3 was 53c4be3, checked in by Adrien Destugues <pulkomandy@…>, 12 years ago
  • Support for ZX spectrup TAP files.

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

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