1 /*
2 * Copyright 2012 Jared Boone <jared@sharebrained.com>
3 * Copyright 2013 Benjamin Vernoux <titanmkd@gmail.com>
4 * Copyright 2013 Michael Ossmann <mike@ossmann.com>
5 *
6 * This file is part of HackRF.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; see the file COPYING. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 #include <hackrf.h>
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <getopt.h>
30 #include <sys/types.h>
31
32 #ifndef bool
33 typedef int bool;
34 #define true 1
35 #define false 0
36 #endif
37
38 #ifdef _MSC_VER
39 #ifdef _WIN64
40 typedef int64_t ssize_t;
41 #else
42 typedef int32_t ssize_t;
43 #endif
44 #endif
45
46 /* 8 Mbit flash */
47 #define MAX_LENGTH 0x100000
48
49 static struct option long_options[] = {
50 { "address", required_argument, 0, 'a' },
51 { "length", required_argument, 0, 'l' },
52 { "read", required_argument, 0, 'r' },
53 { "write", required_argument, 0, 'w' },
54 { "verbose", no_argument, 0, 'v' },
55 { 0, 0, 0, 0 },
56 };
57
parse_u32(char * s,uint32_t * const value)58 int parse_u32(char* s, uint32_t* const value)
59 {
60 char* s_end;
61 uint_fast8_t base = 10;
62 uint32_t u32_value;
63
64 if (strlen(s) > 2) {
65 if (s[0] == '0') {
66 if ((s[1] == 'x') || (s[1] == 'X')) {
67 base = 16;
68 s += 2;
69 } else if ((s[1] == 'b') || (s[1] == 'B')) {
70 base = 2;
71 s += 2;
72 }
73 }
74 }
75
76 s_end = s;
77 u32_value = strtoul(s, &s_end, base);
78 if ((s != s_end) && (*s_end == 0)) {
79 *value = u32_value;
80 return HACKRF_SUCCESS;
81 } else {
82 return HACKRF_ERROR_INVALID_PARAM;
83 }
84 }
85
usage()86 static void usage()
87 {
88 printf("Usage:\n");
89 printf("\t-a, --address <n>: starting address (default: 0)\n");
90 printf("\t-l, --length <n>: number of bytes to read (default: %d)\n", MAX_LENGTH);
91 printf("\t-r <filename>: Read data into file.\n");
92 printf("\t-w <filename>: Write data from file.\n");
93 printf("\t-d <serialnumber>: Serial number of device, if multiple devices\n");
94 printf("\t-v: Verbose output.\n");
95 }
96
main(int argc,char ** argv)97 int main(int argc, char** argv)
98 {
99 int opt;
100 uint32_t address = 0;
101 uint32_t length = MAX_LENGTH;
102 uint32_t tmp_length;
103 uint16_t xfer_len = 0;
104 const char* path = NULL;
105 const char* serial_number = NULL;
106 hackrf_device* device = NULL;
107 int result = HACKRF_SUCCESS;
108 int option_index = 0;
109 static uint8_t data[MAX_LENGTH];
110 uint8_t* pdata = &data[0];
111 FILE* fd = NULL;
112 bool read = false;
113 bool write = false;
114 bool verbose = false;
115
116 while ((opt = getopt_long(argc, argv, "a:l:r:w:d:v", long_options,
117 &option_index)) != EOF) {
118 switch (opt) {
119 case 'a':
120 result = parse_u32(optarg, &address);
121 break;
122
123 case 'l':
124 result = parse_u32(optarg, &length);
125 break;
126
127 case 'r':
128 read = true;
129 path = optarg;
130 break;
131
132 case 'w':
133 write = true;
134 path = optarg;
135 break;
136
137 case 'd':
138 serial_number = optarg;
139 break;
140
141 case 'v':
142 verbose = true;
143 break;
144
145 default:
146 fprintf(stderr, "opt error: %d\n", opt);
147 usage();
148 return EXIT_FAILURE;
149 }
150
151 if (result != HACKRF_SUCCESS) {
152 fprintf(stderr, "argument error: %s (%d)\n",
153 hackrf_error_name(result), result);
154 usage();
155 return EXIT_FAILURE;
156 }
157 }
158
159 if (write == read) {
160 if (write == true) {
161 fprintf(stderr, "Read and write options are mutually exclusive.\n");
162 } else {
163 fprintf(stderr, "Specify either read or write option.\n");
164 }
165 usage();
166 return EXIT_FAILURE;
167 }
168
169 if (path == NULL) {
170 fprintf(stderr, "Specify a path to a file.\n");
171 usage();
172 return EXIT_FAILURE;
173 }
174
175 if( write )
176 {
177 fd = fopen(path, "rb");
178 if(fd == NULL)
179 {
180 printf("Error to open file %s\n", path);
181 return EXIT_FAILURE;
182 }
183 /* Get size of the file */
184 fseek(fd, 0, SEEK_END); /* Not really portable but work on major OS Linux/Win32 */
185 length = ftell(fd);
186 /* Move to start */
187 rewind(fd);
188 printf("File size %d bytes.\n", length);
189 }
190
191 if (length == 0) {
192 fprintf(stderr, "Requested transfer of zero bytes.\n");
193 if(fd != NULL)
194 fclose(fd);
195 usage();
196 return EXIT_FAILURE;
197 }
198
199 if ((length > MAX_LENGTH) || (address > MAX_LENGTH)
200 || ((address + length) > MAX_LENGTH)) {
201 fprintf(stderr, "Request exceeds size of flash memory.\n");
202 if(fd != NULL)
203 fclose(fd);
204 usage();
205 return EXIT_FAILURE;
206 }
207
208 if (read) {
209 fd = fopen(path, "wb");
210 if(fd == NULL)
211 {
212 printf("Error to open file %s\n", path);
213 return EXIT_FAILURE;
214 }
215 }
216
217 if (fd == NULL) {
218 fprintf(stderr, "Failed to open file: %s\n", path);
219 return EXIT_FAILURE;
220 }
221
222 result = hackrf_init();
223 if (result != HACKRF_SUCCESS) {
224 fprintf(stderr, "hackrf_init() failed: %s (%d)\n",
225 hackrf_error_name(result), result);
226 return EXIT_FAILURE;
227 }
228
229 result = hackrf_open_by_serial(serial_number, &device);
230 if (result != HACKRF_SUCCESS) {
231 fprintf(stderr, "hackrf_open() failed: %s (%d)\n",
232 hackrf_error_name(result), result);
233 return EXIT_FAILURE;
234 }
235
236 if (read)
237 {
238 ssize_t bytes_written;
239 tmp_length = length;
240 while (tmp_length)
241 {
242 xfer_len = (tmp_length > 256) ? 256 : tmp_length;
243 if( verbose ) printf("Reading %d bytes from 0x%06x.\n", xfer_len, address);
244 result = hackrf_spiflash_read(device, address, xfer_len, pdata);
245 if (result != HACKRF_SUCCESS) {
246 fprintf(stderr, "hackrf_spiflash_read() failed: %s (%d)\n",
247 hackrf_error_name(result), result);
248 fclose(fd);
249 fd = NULL;
250 return EXIT_FAILURE;
251 }
252 address += xfer_len;
253 pdata += xfer_len;
254 tmp_length -= xfer_len;
255 }
256 bytes_written = fwrite(data, 1, length, fd);
257 if (bytes_written != length) {
258 fprintf(stderr, "Failed write to file (wrote %d bytes).\n",
259 (int)bytes_written);
260 fclose(fd);
261 fd = NULL;
262 return EXIT_FAILURE;
263 }
264 } else {
265 ssize_t bytes_read = fread(data, 1, length, fd);
266 if (bytes_read != length) {
267 fprintf(stderr, "Failed read file (read %d bytes).\n",
268 (int)bytes_read);
269 fclose(fd);
270 fd = NULL;
271 return EXIT_FAILURE;
272 }
273 printf("Erasing SPI flash.\n");
274 result = hackrf_spiflash_erase(device);
275 if (result != HACKRF_SUCCESS) {
276 fprintf(stderr, "hackrf_spiflash_erase() failed: %s (%d)\n",
277 hackrf_error_name(result), result);
278 fclose(fd);
279 fd = NULL;
280 return EXIT_FAILURE;
281 }
282 if( !verbose ) printf("Writing %d bytes at 0x%06x.\n", length, address);
283 while (length) {
284 xfer_len = (length > 256) ? 256 : length;
285 if( verbose ) printf("Writing %d bytes at 0x%06x.\n", xfer_len, address);
286 result = hackrf_spiflash_write(device, address, xfer_len, pdata);
287 if (result != HACKRF_SUCCESS) {
288 fprintf(stderr, "hackrf_spiflash_write() failed: %s (%d)\n",
289 hackrf_error_name(result), result);
290 fclose(fd);
291 fd = NULL;
292 return EXIT_FAILURE;
293 }
294 address += xfer_len;
295 pdata += xfer_len;
296 length -= xfer_len;
297 }
298 }
299
300 result = hackrf_close(device);
301 if (result != HACKRF_SUCCESS) {
302 fprintf(stderr, "hackrf_close() failed: %s (%d)\n",
303 hackrf_error_name(result), result);
304 fclose(fd);
305 fd = NULL;
306 return EXIT_FAILURE;
307 }
308
309 hackrf_exit();
310
311 if (fd != NULL) {
312 fclose(fd);
313 }
314
315 return EXIT_SUCCESS;
316 }
317