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