1 /**
2     @file LimeUtil.cpp
3     @author Lime Microsystems
4     @brief Command line test app
5 */
6 
7 #include <VersionInfo.h>
8 #include <SystemResources.h>
9 #include <ConnectionRegistry.h>
10 #include <IConnection.h>
11 #include <iostream>
12 #include <cstdlib>
13 #include <ciso646>
14 #include <getopt.h>
15 #include <fstream>
16 #include "Logger.h"
17 #include "LMS64CProtocol.h"
18 #include "lms7_device.h"
19 #include "device_constants.h"
20 
21 using namespace lime;
22 
23 int deviceTestTiming(const std::string &argStr);
24 int deviceCalSweep(
25     const std::string &argStr,
26     const double start,
27     const double stop,
28     const double step,
29     const double bw,
30     const std::string &dir,
31     const std::string &chans);
32 
33 /***********************************************************************
34  * print help
35  **********************************************************************/
printHelp(void)36 static int printHelp(void)
37 {
38     std::cout << "Usage LimeUtil [options]" << std::endl;
39     std::cout << "  Options summary:" << std::endl;
40     std::cout << "    --help \t\t\t\t Print this help message" << std::endl;
41     std::cout << "    --info \t\t\t\t Print module information" << std::endl;
42     std::cout << "    --find[=\"module=foo,serial=bar\"] \t Discover available devices" << std::endl;
43     std::cout << "    --make[=\"module=foo,serial=bar\"] \t Create a device instance" << std::endl;
44     std::cout << "    --force \t\t\t\t Force operaton" << std::endl;
45     std::cout << std::endl;
46     std::cout << "  Advanced options:" << std::endl;
47     std::cout << "    --args[=\"module=foo,serial=bar\"] \t Arguments for the options below" << std::endl;
48     std::cout << "    --update          \t\t\t Automatic firmware sync + flash" << std::endl;
49     std::cout << "    --fpga=\"filename\" \t\t\t Program FPGA gateware to flash" << std::endl;
50     std::cout << "    --fw=\"filename\"   \t\t\t Program FX3  firmware to flash" << std::endl;
51     std::cout << "    --timing          \t\t\t Time interfaces and operations" << std::endl;
52     std::cout << std::endl;
53     std::cout << "  Calibrations sweep:" << std::endl;
54     std::cout << "    --cal[=\"module=foo,serial=bar\"]  \t Calibrate device, optional device args..." << std::endl;
55     std::cout << "    --start[=freqStart]                \t Frequency start for the sweep(Hz)" << std::endl;
56     std::cout << "    --stop[=freqStop]                  \t Frequency stop for the sweep(Hz)" << std::endl;
57     std::cout << "    --step[=freqStep, default=1MHz]    \t Frequency step for the sweep(Hz)" << std::endl;
58     std::cout << "    --bw[=bandwidth, default=30MHz]    \t Desired calibration bandwidth(Hz)" << std::endl;
59     std::cout << "    --dir[=direction, default=BOTH]    \t Calibration direction, RX, TX, BOTH" << std::endl;
60     std::cout << "    --chans[=channels, default=ALL]    \t Calibration channels, 0, 1, ALL" << std::endl;
61     std::cout << std::endl;
62     return EXIT_SUCCESS;
63 }
64 
65 /***********************************************************************
66  * print info
67  **********************************************************************/
printInfo(void)68 static int printInfo(void)
69 {
70     std::cout << "######################################################" << std::endl;
71     std::cout << "## LimeSuite information summary" << std::endl;
72     std::cout << "######################################################" << std::endl;
73     std::cout << std::endl;
74 
75     std::cout << "Version information:" << std::endl;
76     std::cout << "  Library version:\tv" << lime::GetLibraryVersion() << std::endl;
77     std::cout << "  Build timestamp:\t" << lime::GetBuildTimestamp() << std::endl;
78     std::cout << "  Interface version:\tv" << lime::GetAPIVersion() << std::endl;
79     std::cout << "  Binary interface:\t" << lime::GetABIVersion() << std::endl;
80     std::cout << std::endl;
81 
82     std::cout << "System resources:" << std::endl;
83     std::cout << "  Installation root:\t" << lime::getLimeSuiteRoot() << std::endl;
84     std::cout << "  User home directory:\t" << lime::getHomeDirectory() << std::endl;
85     std::cout << "  App data directory:\t" << lime::getAppDataDirectory() << std::endl;
86     std::cout << "  Config directory:\t" << lime::getConfigDirectory() << std::endl;
87     std::cout << "  Image search paths:" << std::endl;
88     for (const auto &name : lime::listImageSearchPaths()) std::cout << "     - " << name << std::endl;
89     std::cout << std::endl;
90 
91     std::cout << "Supported connections:" << std::endl;
92     for (const auto &name : ConnectionRegistry::moduleNames()) std::cout << "   * " << name << std::endl;
93     std::cout << std::endl;
94     return EXIT_SUCCESS;
95 }
96 
97 /***********************************************************************
98  * find devices
99  **********************************************************************/
findDevices(void)100 static int findDevices(void)
101 {
102     std::string argStr;
103     if (optarg != NULL) argStr = "none," + std::string(optarg);
104     ConnectionHandle hint(argStr);
105 
106     auto handles = ConnectionRegistry::findConnections(hint);
107     for (const auto &handle : handles)
108     {
109         std::cout << "  * [" << handle.serialize() << "]" << std::endl;
110     }
111 
112     std::cout << std::endl;
113     return EXIT_SUCCESS;
114 }
115 
116 /***********************************************************************
117  * make a device
118  **********************************************************************/
makeDevice(void)119 static int makeDevice(void)
120 {
121     std::string argStr = "none,";
122     if (optarg != NULL) argStr += optarg;
123     ConnectionHandle handle(argStr);
124 
125     std::cout << "Make device " << argStr.substr(5) << std::endl;
126     auto conn = ConnectionRegistry::makeConnection(handle);
127     if (conn == nullptr)
128     {
129         std::cout << "No available device!" << std::endl;
130         return EXIT_FAILURE;
131     }
132     if (not conn->IsOpen())
133     {
134         std::cout << "Connection not open!" << std::endl;
135         ConnectionRegistry::freeConnection(conn);
136         return EXIT_FAILURE;
137     }
138 
139     auto info = conn->GetDeviceInfo();
140     std::cout << "  Device name: " << info.deviceName << std::endl;
141     std::cout << "  Expansion name: " << info.expansionName << std::endl;
142     std::cout << "  Firmware version: " << info.firmwareVersion << std::endl;
143     std::cout << "  Hardware version: " << info.hardwareVersion << std::endl;
144     std::cout << "  Protocol version: " << info.protocolVersion << std::endl;
145     std::cout << "  Gateware version: " << info.gatewareVersion << std::endl;
146     std::cout << "  Gateware revision: " << info.gatewareRevision << std::endl;
147     std::cout << "  Gateware target: " << info.gatewareTargetBoard << std::endl;
148     std::cout << "  Serial number: " << std::hex << "0x" << info.boardSerialNumber << std::dec << std::endl;
149 
150     std::cout << "  Free connection... " << std::flush;
151     ConnectionRegistry::freeConnection(conn);
152     std::cout << "OK" << std::endl;
153     std::cout << std::endl;
154     return EXIT_SUCCESS;
155 }
156 
157 /***********************************************************************
158  * Program update (sync images and flash support)
159  **********************************************************************/
programUpdate(const bool force,const std::string & argStr)160 static int programUpdate(const bool force, const std::string &argStr)
161 {
162     auto handles = ConnectionRegistry::findConnections(argStr);
163     if(handles.size() == 0)
164     {
165         std::cout << "No devices found" << std::endl;
166         return EXIT_FAILURE;
167     }
168     std::cout << "Connected to [" << handles[0].ToString() << "]" << std::endl;
169     auto conn = ConnectionRegistry::makeConnection(handles[0]);
170 
171     auto progCallback = [](int bsent, int btotal, const char* progressMsg)
172     {
173         printf("[%3i%%] %5i/%5i Bytes %s\r", int(100.0*bsent/btotal+0.5), bsent, btotal, progressMsg);
174         fflush(stdout);
175         return 0;
176     };
177 
178     auto status = conn->ProgramUpdate(true/*yes download*/, force, progCallback);
179 
180     std::cout << std::endl;
181     if(status == 0)
182     {
183         std::cout << "Programming update complete!" << std::endl;
184     }
185     else
186     {
187         std::cout << "Programming update failed!" << std::endl;
188     }
189 
190     ConnectionRegistry::freeConnection(conn);
191     return (status==0)?EXIT_SUCCESS:EXIT_FAILURE;
192 }
193 
194 /***********************************************************************
195  * Program gateware
196  **********************************************************************/
programGateware(const std::string & argStr)197 static int programGateware(const std::string &argStr)
198 {
199     //load file
200     std::ifstream file;
201     file.open(optarg, std::ios::in | std::ios::binary);
202     if(not file.good())
203     {
204         std::cout << "File not found: " << optarg << std::endl;
205         return EXIT_FAILURE;
206     }
207 
208     std::streampos fileSize;
209     file.seekg(0, std::ios::end);
210     fileSize = file.tellg();
211     file.seekg(0, std::ios::beg);
212     std::vector<char> progData(fileSize, 0);
213     file.read(progData.data(), fileSize);
214 
215     auto handles = ConnectionRegistry::findConnections(argStr);
216     if(handles.size() == 0)
217     {
218         std::cout << "No devices found" << std::endl;
219         return EXIT_FAILURE;
220     }
221     std::cout << "Connected to [" << handles[0].ToString() << "]" << std::endl;
222     auto device = LMS7_Device::CreateDevice(handles[0]);
223 
224     auto progCallback = [](int bsent, int btotal, const char* progressMsg)
225     {
226         printf("[%3i%%] %5i/%5i Bytes %s\r", int(100.0*bsent/btotal+0.5), bsent, btotal, progressMsg);
227         fflush(stdout);
228         return 0;
229     };
230 
231     auto status = device->Program(program_mode::fpgaFlash, progData.data(), progData.size(), progCallback);
232     std::cout << std::endl;
233     if(status != 0)
234         std::cout << "Programming failed!" << std::endl;
235     delete device;
236     return (status==0)?EXIT_SUCCESS:EXIT_FAILURE;
237 }
238 
239 /***********************************************************************
240  * Program gateware
241  **********************************************************************/
programFirmware(const std::string & argStr)242 static int programFirmware(const std::string &argStr)
243 {
244     //load file
245     std::ifstream file;
246     file.open(optarg, std::ios::in | std::ios::binary);
247     if(not file.good())
248     {
249         std::cout << "File not found: " << optarg << std::endl;
250         return EXIT_FAILURE;
251     }
252 
253     std::streampos fileSize;
254     file.seekg(0, std::ios::end);
255     fileSize = file.tellg();
256     file.seekg(0, std::ios::beg);
257     std::vector<char> progData(fileSize, 0);
258     file.read(progData.data(), fileSize);
259 
260     auto handles = ConnectionRegistry::findConnections(argStr);
261     if(handles.size() == 0)
262     {
263         std::cout << "No devices found" << std::endl;
264         return EXIT_FAILURE;
265     }
266     std::cout << "Connected to [" << handles[0].ToString() << "]" << std::endl;
267     auto device = LMS7_Device::CreateDevice(handles[0]);
268 
269     auto progCallback = [](int bsent, int btotal, const char* progressMsg)
270     {
271         printf("[%3i%%] %5i/%5i Bytes %s\r", int(100.0*bsent/btotal+0.5), bsent, btotal, progressMsg);
272         fflush(stdout);
273         return 0;
274     };
275 
276     auto status = device->Program(program_mode::fx3Flash, progData.data(), progData.size(), progCallback);
277     std::cout << std::endl;
278     if(status != 0)
279         std::cout << "Programming failed!" << std::endl;
280     delete device;
281     return (status==0)?EXIT_SUCCESS:EXIT_FAILURE;
282 }
283 
284 /***********************************************************************
285  * main entry point
286  **********************************************************************/
main(int argc,char * argv[])287 int main(int argc, char *argv[])
288 {
289     static struct option long_options[] = {
290         {"help", no_argument, 0, 'h'},
291         {"info", optional_argument, 0, 'i'},
292         {"find", optional_argument, 0, 'f'},
293         {"make", optional_argument, 0, 'm'},
294         {"force",      no_argument, 0, 'F'},
295         {"args", optional_argument, 0, 'a'},
296         {"update",     no_argument, 0, 'u'},
297         {"fpga", required_argument, 0, 'g'},
298         {"fw",   required_argument, 0, 'w'},
299         {"timing",     no_argument, 0, 't'},
300         {"cal",     optional_argument, 0, 'l'},
301         {"start",   required_argument, 0, 's'},
302         {"stop",    required_argument, 0, 'p'},
303         {"step",    required_argument, 0, 'e'},
304         {"bw",      required_argument, 0, 'b'},
305         {"dir",     required_argument, 0, 'd'},
306         {"chans",   required_argument, 0, 'c'},
307         {0, 0, 0,  0}
308     };
309 
310     std::string argStr, dir("BOTH"), chans("ALL");
311     double start(0.0), stop(0.0), step(1e6), bw(30e6);
312     bool testTiming(false), calSweep(false), update(false), force(false);
313     int long_index = 0;
314     int option = 0;
315     while ((option = getopt_long_only(argc, argv, "", long_options, &long_index)) != -1)
316     {
317         switch (option)
318         {
319         case 'h': return printHelp();
320         case 'i': return printInfo();
321         case 'f': return findDevices();
322         case 'm': return makeDevice();
323         case 'a':
324             if (optarg != NULL) argStr = "none," + std::string(optarg);
325             break;
326         case 'u': update = true; break;
327         case 'g': return programGateware(argStr);
328         case 'w': return programFirmware(argStr);
329         case 't': testTiming = true; break;
330         case 'l':
331             calSweep = true;
332             if (optarg != NULL) argStr = "none," + std::string(optarg);
333             break;
334         case 's': if (optarg != NULL) start = std::stod(optarg); break;
335         case 'p': if (optarg != NULL) stop = std::stod(optarg); break;
336         case 'e': if (optarg != NULL) step = std::stod(optarg); break;
337         case 'b': if (optarg != NULL) bw = std::stod(optarg); break;
338         case 'd': if (optarg != NULL) dir = optarg; break;
339         case 'c': if (optarg != NULL) chans = optarg; break;
340         case 'F': force = true; break;
341         }
342     }
343 
344     if (testTiming) return deviceTestTiming(argStr);
345     if (calSweep) return deviceCalSweep(argStr, start, stop, step, bw, dir, chans);
346     if (update) return programUpdate(force, argStr);
347 
348     //unknown or unspecified options, do help...
349     return printHelp();
350 }
351