Removed C++11 dependencies, and compile Windows binaries staically with mingw.
[SCSI2SD.git] / software / bootloaderhost / main.cc
1 //      Copyright (C) 2013 Michael McMaster <michael@codesrc.com>
2 //
3 //      This file is part of SCSI2SD.
4 //
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.
9 //
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.
14 //
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
18 #include "SCSI2SD_HID.hh"
19 #include "SCSI2SD_Bootloader.hh"
20 #include "Firmware.hh"
21
22 #if __cplusplus >= 201103L
23 #include <cstdint>
24 #include <memory>
25 using std::shared_ptr;
26 #else
27 #include <stdint.h>
28 #include <tr1/memory>
29 using std::tr1::shared_ptr;
30 #endif
31
32 #include <iomanip>
33 #include <iostream>
34 #include <sstream>
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39
40 using namespace SCSI2SD;
41
42 extern "C"
43 void ProgressUpdate(unsigned char arrayId, unsigned short rowNum)
44 {
45         //std::cerr <<
46                 //"Programmed flash array " << static_cast<int>(arrayId) <<
47                 //      ", row " << rowNum << std::endl;
48         std::cout << "." << std::flush;
49 }
50
51 static void usage()
52 {
53         std::cout << "Usage: bootloaderhost [-f] "
54                 "/path/to/firmware.cyacd\n" <<
55                 "\t-f\tForce, even if the firmware doesn't match the target board.\n\n" <<
56                 std::endl;
57 }
58
59
60 int main(int argc, char* argv[])
61 {
62         std::cout <<
63                 "PSoC 3/5LP USB HID Bootloader Host\n" <<
64                 "Copyright (C) 2013 Michael McMaster <michael@codesrc.com>\n" <<
65                 std::endl;
66
67         int force = 0;
68
69         opterr = 0;
70         int c;
71         while ((c = getopt(argc, argv, "v:p:f")) != -1)
72         {
73                 switch (c)
74                 {
75                 case 'f':
76                         force = 1;
77                         break;
78                 case '?':
79                         usage();
80                         exit(1);
81                 }
82         }
83
84         std::string filename;
85         if (optind < argc)
86         {
87                 filename = argv[optind];
88         }
89         else
90         {
91                 usage();
92                 exit(1);
93         }
94
95         // Enumerate and print the HID devices on the system
96         shared_ptr<Bootloader> bootloader(Bootloader::Open());
97         shared_ptr<HID> hid(HID::Open());
98
99         if (hid)
100         {
101                 try
102                 {
103                         hid->enterBootloader();
104                 }
105                 catch (std::exception& e)
106                 {
107                         std::cerr << e.what() << std::endl;
108                         hid.reset();
109                 }
110         }
111
112         if (!hid)
113         {
114                 std::cout <<
115                         "Waiting for device connection" << std::endl <<
116                         "Connect USB cable to the bus-powered device now, or otherwise "
117                                 "reset the device." << std::endl;
118         }
119
120
121         while (!bootloader)
122         {
123                 bootloader.reset(Bootloader::Open());
124
125                 if (!bootloader && !hid)
126                 {
127                         hid.reset(HID::Open());
128                         if (hid)
129                         {
130                                 try
131                                 {
132                                         hid->enterBootloader();
133                                 }
134                                 catch (std::exception& e)
135                                 {
136                                         std::cerr << e.what();
137                                 }
138                         }
139                 }
140
141                 if (!bootloader)
142                 {
143                         usleep(100000); // 100ms
144                 }
145         }
146
147         std::stringstream foundMsg;
148         foundMsg <<
149                 "Device Found\n" <<
150                 "  type:\t\t\t" << std::setw(4) << std::hex <<
151                         Bootloader::VENDOR_ID << " " <<
152                         Bootloader::PRODUCT_ID <<
153                         "\n" <<
154                 "  path:\t\t\t" << bootloader->getDevicePath() << "\n";
155         std::cout << foundMsg.str() << std::endl;
156
157         Bootloader::HWInfo hwInfo(bootloader->getHWInfo());
158         std::cout <<
159                 "  Board:\t\t" << hwInfo.desc << "\n" <<
160                 "  Revision:\t\t" << hwInfo.version << std::endl;
161
162         if (hid)
163         {
164                 std::cout <<
165                         "  Existing firmware:\t" <<
166                         hid->getFirmwareVersionStr() << std::endl;
167         }
168
169
170         if (!bootloader->isCorrectFirmware(filename) && !force)
171         {
172                 std::cerr <<
173                         "ERROR: Unexpected firmware file. Expected: \""
174                                 << hwInfo.firmwareName << "\"\n\n" <<
175                         "Using firmware design for a different board will destroy your " <<
176                         "hardware.\n" <<
177                         "If you still wish to proceed, try again with the \"-f\" flag.\n" <<
178                         std::endl;
179                 exit(1);
180         }
181
182         Firmware firmware(filename);
183
184         std::stringstream firmMsg;
185         firmMsg <<
186                 "  Firmware Silicon ID:\t" <<  std::hex << firmware.siliconId() <<
187                         "\n";
188         std::cout << firmMsg.str() << std::endl;
189
190         std::cout << "Starting firmware upload: " << filename << std::endl;
191
192         try
193         {
194                 bootloader->load(filename, &ProgressUpdate);
195                 std::cout << "Firmware upload complete." << std::endl;
196         }
197         catch (std::exception& e)
198         {
199                 std::cerr << "ERROR: Firmware update failed.\n" << e.what() << std::endl;
200                 exit(1);
201         }
202
203         return 0;
204 }
205