1 // Copyright (C) 2014 Michael McMaster <michael@codesrc.com>
3 // This file is part of SCSI2SD.
5 // SCSI2SD is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // SCSI2SD is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
17 #include "SCSI2SD_HID.hh"
19 #include "hidpacket.h"
21 // For compilers that support precompilation, includes "wx/wx.h".
22 #include <wx/wxprec.h>
34 #include <string.h> // memcpy
36 using namespace SCSI2SD;
38 HID::HID(hid_device_info* hidInfo) :
46 // hidInfo->interface_number not supported on mac, and interfaces
47 // are enumerated in a random order. :-(
48 // We rely on the watchdog value of the debug interface changing on each
49 // read to differentiate the interfaces.
52 while (hidInfo && !(myConfigHandle && myDebugHandle))
54 std::stringstream msg;
55 msg << "Error opening HID device " << hidInfo->path << std::endl;
57 if ((hidInfo->interface_number == CONFIG_INTERFACE) ||
58 (hidInfo->usage_page == 0xFF00))
60 myConfigHandle = hid_open_path(hidInfo->path);
61 if (!myConfigHandle) throw std::runtime_error(msg.str());
63 hidInfo = hidInfo->next;
65 else if ((hidInfo->interface_number == DEBUG_INTERFACE) ||
66 (hidInfo->usage_page == 0xFF01))
68 myDebugHandle = hid_open_path(hidInfo->path);
69 if (!myDebugHandle) throw std::runtime_error(msg.str());
71 hidInfo = hidInfo->next;
73 else if (hidInfo->interface_number == -1)
75 // hidInfo->interface_number not supported on mac, and
76 // interfaces are enumerated in a random order. :-(
77 // We rely on the watchdog value of the debug interface
78 // changing on each read to differentiate the interfaces.
79 // Not necessary since firmware 3.5.2 as the usage_page can
81 hid_device* dev = hid_open_path(hidInfo->path);
84 throw std::runtime_error(msg.str());
87 uint8_t buf[HID_PACKET_SIZE];
89 int configIntFound = 1;
90 for (int i = 0; i < 4; ++i)
92 buf[0] = 0; // report id
93 hid_read(dev, buf, HID_PACKET_SIZE);
94 if (watchVal == -1) watchVal = buf[25];
95 configIntFound = configIntFound && (buf[25] == watchVal);
100 myConfigHandle = dev;
110 catch (std::runtime_error& e)
122 hid_close(myConfigHandle);
123 myConfigHandle = NULL;
127 hid_close(myDebugHandle);
128 myDebugHandle = NULL;
131 hid_free_enumeration(myHidInfo);
143 hid_device_info* dev = hid_enumerate(VENDOR_ID, PRODUCT_ID);
155 HID::enterBootloader()
157 // Reboot commands added in firmware 3.5
160 throw std::runtime_error(
161 "Cannot enter SCSI2SD bootloader: debug interface not found");
163 else if (myFirmwareVersion == 0)
165 throw std::runtime_error(
166 "Cannot enter SCSI2SD bootloader: old firmware version running.\n"
167 "The SCSI2SD board cannot reset itself. Please disconnect and \n"
168 "reconnect the USB cable.\n");
172 uint8_t hidBuf[HID_PACKET_SIZE + 1] =
175 0x01 // Reboot command
179 int result = hid_write(myDebugHandle, hidBuf, sizeof(hidBuf));
182 const wchar_t* err = hid_error(myDebugHandle);
183 std::stringstream ss;
184 ss << "USB HID write failure: " << err;
185 throw std::runtime_error(ss.str());
191 HID::readFlashRow(int array, int row, std::vector<uint8_t>& out)
193 std::vector<uint8_t> cmd
196 static_cast<uint8_t>(array),
197 static_cast<uint8_t>(row)
199 sendHIDPacket(cmd, out);
203 HID::writeFlashRow(int array, int row, const std::vector<uint8_t>& in)
205 std::vector<uint8_t> cmd;
206 cmd.push_back(CONFIG_WRITEFLASH);
207 cmd.insert(cmd.end(), in.begin(), in.end());
208 cmd.push_back(static_cast<uint8_t>(array));
209 cmd.push_back(static_cast<uint8_t>(row));
210 std::vector<uint8_t> out;
211 sendHIDPacket(cmd, out);
212 if ((out.size() < 1) || (out[0] != CONFIG_STATUS_GOOD))
214 std::stringstream ss;
215 ss << "Error writing flash " << array << "/" << row;
216 throw std::runtime_error(ss.str());
221 HID::readHID(uint8_t* buffer, size_t len)
224 buffer[0] = 0; // report id
227 for (int retry = 0; retry < 3 && result < 0; ++retry)
229 result = hid_read(myConfigHandle, buffer, len);
234 const wchar_t* err = hid_error(myConfigHandle);
235 std::stringstream ss;
236 ss << "USB HID read failure: " << err;
237 throw std::runtime_error(ss.str());
244 uint8_t buf[HID_PACKET_SIZE];
245 buf[0] = 0; // report id
246 int result = hid_read(myDebugHandle, buf, HID_PACKET_SIZE);
250 const wchar_t* err = hid_error(myDebugHandle);
251 std::stringstream ss;
252 ss << "USB HID read failure: " << err;
253 throw std::runtime_error(ss.str());
255 myFirmwareVersion = (((uint16_t)buf[62]) << 8) | buf[63];
258 (((uint32_t)buf[58]) << 24) |
259 (((uint32_t)buf[59]) << 16) |
260 (((uint32_t)buf[60]) << 8) |
265 HID::getFirmwareVersionStr() const
267 if (myFirmwareVersion == 0)
269 return "Unknown (3.0 - 3.4)";
273 std::stringstream ver;
275 (myFirmwareVersion >> 8) <<
276 '.' << ((myFirmwareVersion & 0xF0) >> 4);
278 int rev = myFirmwareVersion & 0xF;
291 std::vector<uint8_t> cmd { CONFIG_PING };
292 std::vector<uint8_t> out;
295 sendHIDPacket(cmd, out);
297 catch (std::runtime_error& e)
302 return (out.size() >= 1) && (out[0] == CONFIG_STATUS_GOOD);
306 HID::sendHIDPacket(const std::vector<uint8_t>& cmd, std::vector<uint8_t>& out)
308 assert(cmd.size() <= HIDPACKET_MAX_LEN);
309 hidPacket_send(&cmd[0], cmd.size());
311 uint8_t hidBuf[HID_PACKET_SIZE];
312 const uint8_t* chunk = hidPacket_getHIDBytes(hidBuf);
315 uint8_t reportBuf[HID_PACKET_SIZE + 1] = { 0x00 }; // Report ID
316 memcpy(&reportBuf[1], chunk, HID_PACKET_SIZE);
318 for (int retry = 0; retry < 10 && result < 0; ++retry)
320 result = hid_write(myConfigHandle, reportBuf, sizeof(reportBuf));
321 if (result < 0) wxMilliSleep(8);
326 const wchar_t* err = hid_error(myConfigHandle);
327 std::stringstream ss;
328 ss << "USB HID write failure: " << err;
329 throw std::runtime_error(ss.str());
331 chunk = hidPacket_getHIDBytes(hidBuf);
334 const uint8_t* resp = NULL;
336 resp = hidPacket_getPacket(&respLen);
338 // We need to poll quick enough to not skip packets
339 // This depends on the USB HID device poll rate parameter.
340 // SCSI2SD uses a 32ms poll rate, so we check for new chunks at 4x
342 for (int retry = 0; retry < (HIDPACKET_MAX_LEN / 62) * 30 && !resp; ++retry)
344 readHID(hidBuf, sizeof(hidBuf));
345 hidPacket_recv(hidBuf, HID_PACKET_SIZE);
346 resp = hidPacket_getPacket(&respLen);
347 if (!resp) wxMilliSleep(8);
352 throw std::runtime_error("SCSI2SD config protocol error");