1 /*
2 * File: loader.cpp
3 *
4 * Copyright (c) 2011 Eric J. Holmes, Orion Telescopes & Binoculars
5 *
6 */
7
8 #ifdef HAVE_CONFIG_H
9 # include "config.h"
10 #endif
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <libusb.h>
16 #if !defined(_MSC_VER)
17 # include <unistd.h>
18 #endif
19
20 #include "openssag.h"
21 #include "openssag_priv.h"
22 #include "firmware.h"
23
24 #define CPUCS_ADDRESS 0xe600
25
26 /* USB commands to control device */
27 enum USB_REQUEST {
28 USB_RQ_LOAD_FIRMWARE = 0xa0,
29 USB_RQ_WRITE_SMALL_EEPROM = 0xa2
30 };
31
32 using namespace OpenSSAG;
33
34 /* Bootloader data */
35 static unsigned char bootloader[] = { SSAG_BOOTLOADER };
36 /* Firmware data */
37 static unsigned char firmware[] = { SSAG_FIRMWARE };
38 /* EEPROM data (shouldn't be needed) */
39 static unsigned char eeprom[] = { SSAG_EEPROM };
40
Loader()41 Loader::Loader()
42 :
43 handle(NULL)
44 {
45 }
46
~Loader()47 Loader::~Loader()
48 {
49 Disconnect();
50 }
51
Connect(int loader_vid,int loader_pid)52 bool Loader::Connect(int loader_vid, int loader_pid)
53 {
54 if (usb_open_device(&this->handle, loader_vid, loader_pid, NULL))
55 return true;
56
57 return false;
58 }
59
Disconnect()60 void Loader::Disconnect()
61 {
62 if (this->handle) {
63 libusb_close(this->handle);
64 this->handle = NULL;
65 }
66 }
67
EnterResetMode()68 void Loader::EnterResetMode()
69 {
70 char data = 0x01;
71 //usb_control_msg(this->handle, 0x40, USB_RQ_LOAD_FIRMWARE, 0x7f92, 0, &data, 1, 5000);
72 int r = libusb_control_transfer(
73 this->handle,
74 0x40 & 0xff,
75 USB_RQ_LOAD_FIRMWARE & 0xff,
76 0x7f92 & 0xffff,
77 0 & 0xffff,
78 (unsigned char*)&data,
79 1,
80 5000);
81
82 if (r < 0)
83 {
84 DBG("Loader::EnterResetMode: error sending command (1)");
85 }
86
87
88 //usb_control_msg(this->handle, 0x40, USB_RQ_LOAD_FIRMWARE, CPUCS_ADDRESS, 0, &data, 1, 5000);
89 r = libusb_control_transfer(
90 this->handle,
91 0x40 & 0xff,
92 USB_RQ_LOAD_FIRMWARE & 0xff,
93 CPUCS_ADDRESS & 0xffff,
94 0 & 0xffff,
95 (unsigned char*)&data,
96 1,
97 5000);
98
99 if (r < 0)
100 {
101 DBG("Loader::EnterResetMode: error sending command (2)");
102 }
103 }
104
ExitResetMode()105 void Loader::ExitResetMode()
106 {
107 char data = 0x00;
108 //usb_control_msg(this->handle, 0x40, USB_RQ_LOAD_FIRMWARE, 0x7f92, 0, &data, 1, 5000);
109 int r = libusb_control_transfer(
110 this->handle,
111 0x40 & 0xff,
112 USB_RQ_LOAD_FIRMWARE & 0xff,
113 0x7f92 & 0xffff,
114 0 & 0xffff,
115 (unsigned char*)&data,
116 1,
117 5000);
118
119 if (r < 0)
120 {
121 DBG("Loader::ExitResetMode: error sending command (1)");
122 }
123
124
125 //usb_control_msg(this->handle, 0x40, USB_RQ_LOAD_FIRMWARE, CPUCS_ADDRESS, 0, &data, 1, 5000);
126 r = libusb_control_transfer(
127 this->handle,
128 0x40 & 0xff,
129 USB_RQ_LOAD_FIRMWARE & 0xff,
130 CPUCS_ADDRESS & 0xffff,
131 0 & 0xffff,
132 (unsigned char*)&data,
133 1,
134 5000);
135
136 if (r < 0)
137 {
138 DBG("Loader::ExitResetMode: error sending command (2)");
139 }
140
141 }
142
Upload(unsigned char * data)143 bool Loader::Upload(unsigned char *data)
144 {
145 for (;;) {
146
147 /*
148 unsigned char byte_count = *data;
149 if (byte_count == 0)
150 break;
151 unsigned short address = *(unsigned int *)(data+1);
152 int received = 0;
153 if ((received = usb_control_msg(this->handle, 0x40, USB_RQ_LOAD_FIRMWARE, address, 0, (char *)(data+3), byte_count, 5000)) != byte_count) {
154 DBG("ERROR: Tried to send %d bytes of data but device reported back with %d\n", byte_count, received);
155 return false;
156 }
157 data += byte_count + 3;
158 */
159
160
161 unsigned char byte_count = *data;
162 if (byte_count == 0)
163 break;
164 unsigned short address = *(unsigned int *)(data+1);
165 int received = 0;
166
167 //usb_control_msg(this->handle, 0x40, USB_RQ_LOAD_FIRMWARE, address, 0, (char *)(data+3), byte_count, 5000))
168 received = libusb_control_transfer(
169 this->handle,
170 0x40 & 0xff,
171 USB_RQ_LOAD_FIRMWARE & 0xff,
172 address & 0xffff,
173 0 & 0xffff,
174 (unsigned char*)(data+3),
175 byte_count,
176 5000);
177
178
179 //if ((received = usb_control_msg(this->handle, 0x40, USB_RQ_LOAD_FIRMWARE, address, 0, (char *)(data+3), byte_count, 5000)) != byte_count) {
180
181 if (received != byte_count) {
182
183 DBG("ERROR: Tried to send %d bytes of data but device reported back with %d\n", byte_count, received);
184 return false;
185 }
186 data += byte_count + 3;
187
188
189
190 }
191 return true;
192 }
193
LoadFirmware()194 bool Loader::LoadFirmware()
195 {
196 /* Load bootloader */
197 this->EnterResetMode();
198 this->EnterResetMode();
199 DBG("Loading bootloader...");
200 if (!this->Upload(bootloader))
201 return false;
202 DBG("done\n");
203 this->ExitResetMode(); /* Transfer execution to the reset vector */
204
205 sleep(1); /* Wait for renumeration */
206
207 /* Load firmware */
208 this->EnterResetMode();
209 DBG("Loading firmware...");
210 if (!this->Upload(firmware))
211 return false;
212 DBG("done\n");
213 this->EnterResetMode(); /* Make sure the CPU is in reset */
214 this->ExitResetMode(); /* Transfer execution to the reset vector */
215
216 return true;
217 }
218
LoadEEPROM()219 bool Loader::LoadEEPROM()
220 {
221 size_t length = *eeprom;
222 char *data = (char *)(eeprom+3);
223 //usb_control_msg(this->handle, 0x40, USB_RQ_WRITE_SMALL_EEPROM, 0x00, 0xBEEF, data, length, 5000);
224 int received = libusb_control_transfer(
225 this->handle,
226 0x40 & 0xff,
227 USB_RQ_WRITE_SMALL_EEPROM & 0xff,
228 0x00 & 0xffff,
229 0xBEEF & 0xffff,
230 (unsigned char*)(data),
231 length,
232 5000);
233 if(received != length)
234 {
235 DBG("ERROR: during the loading of the EEPROM");
236 }
237 return true;
238 }
239