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