Contiki 2.5
bbmc.c
1 /*
2  * Copyright (c) 2010, Mariano Alvira <mar@devl.org> and other contributors
3  * to the MC1322x project (http://mc1322x.devl.org)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the Institute nor the names of its contributors
15  * may be used to endorse or promote products derived from this software
16  * without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * This file is part of libmc1322x: see http://mc1322x.devl.org
31  * for details.
32  *
33  *
34  */
35 
36 /* control reset and VREF2 lines */
37 
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdint.h>
41 #include <getopt.h>
42 #include <ftdi.h>
43 
44 #define DEBUG 0
45 
46 #define low(x) (1 << x)
47 #define high(x) (1 << (x + 8))
48 
49 #define REDBEE_ECONOTAG_RESET high(2)
50 #define REDBEE_ECONOTAG_VREF2L high(7)
51 #define REDBEE_ECONOTAG_VREF2H high(6)
52 #define REDBEE_ECONOTAG_INTERFACE INTERFACE_A
53 
54 #define REDBEE_USB_RESET high(2)
55 #define REDBEE_USB_VREF2L low(5)
56 #define REDBEE_USB_VREF2H low(6)
57 #define REDBEE_USB_INTERFACE INTERFACE_B
58 
59 #define BOARD REDBEE_USB
60 
61 #define STR(x) #x
62 #define STR2(x) STR(x)
63 #define CAT(x,y) x##y
64 #define CAT2(x, y, z) x##y##z
65 
66 #define dir(x) ( CAT(x,_RESET) | CAT(x,_VREF2L) | CAT(x,_VREF2H))
67 #define interface(x) ( CAT(x,_INTERFACE) )
68 #define reset_release(x) ( CAT(x,_RESET) )
69 #define reset_set(x) ( 0 )
70 #define vref2_normal(x) ( CAT(x,_VREF2H) )
71 #define vref2_erase(x) ( CAT(x,_VREF2L) )
72 
73 /* fgets input buffer length: for prompts and such */
74 #define BUF_LEN 32
75 
76 struct layout {
77  char *name;
78  char *desc;
79  enum ftdi_interface interface;
80  uint16_t dir;
81  uint16_t reset_release;
82  uint16_t reset_set;
83  uint16_t vref2_normal;
84  uint16_t vref2_erase;
85 };
86 
87 int print_and_prompt( struct ftdi_device_list *devlist );
88 int bb_mpsee(struct ftdi_context *ftdic, uint16_t dir, uint16_t val);
89 void reset(struct ftdi_context *ftdic, const struct layout * l);
90 void erase(struct ftdi_context *ftdic, const struct layout * l);
91 void usage(void);
92 
93 #define std_layout(x) \
94  .interface = interface(x), \
95  .dir = dir(x), \
96  .reset_release = reset_release(x), \
97  .reset_set = reset_set(x), \
98  .vref2_normal = vref2_normal(x), \
99  .vref2_erase = vref2_erase(x),
100 
101 static struct layout layouts[] =
102 {
103  { .name = "redbee-econotag",
104  .desc = "Redbee Econotag",
105  std_layout(REDBEE_ECONOTAG)
106  },
107  { .name = "redbee-usb",
108  .desc = "Redbee USB stick",
109  std_layout(REDBEE_USB)
110  },
111  { .name = NULL, /* end of table */ },
112 };
113 
114 struct command {
115  char *name;
116  char *desc;
117  void (*cmd)(struct ftdi_context *ftdic, const struct layout * l);
118 };
119 
120 static const struct command commands[] =
121 {
122  {
123  .name = "reset",
124  .desc = "Toggles reset pin",
125  .cmd = reset,
126  },
127  {
128  .name = "erase",
129  .desc = "Sets VREF2 erase mode; toggles reset; waits 2 sec.; sets normal; toggles reset again",
130  .cmd = erase,
131  },
132  { .name = NULL, /* end of table */ },
133 };
134 
135 struct layout * find_layout(char * str)
136 {
137  uint32_t i = 0;
138 
139  while(layouts[i].name != NULL) {
140  if(strcmp(layouts[i].name, str) == 0) { return &layouts[i]; }
141  i++;
142  }
143 
144  return NULL;
145 }
146 
147 static uint32_t vendid = 0x0403; uint32_t prodid = 0x6010;
148 
149 int main(int argc, char **argv)
150 {
151  struct ftdi_context ftdic;
152  struct ftdi_device_list *devlist;
153  int dev_index = -1; int num_devs;
154  char layout_str[BUF_LEN];
155  struct layout layout;
156  struct layout *l = NULL;
157  int i, ret;
158 
159  /* overrides for layout parameters */
160  int interface = -1;
161  int dir = -1;
162  int reset_release = -1;
163  int reset_set = -1;
164  int vref2_normal = -1;
165  int vref2_erase = -1;
166 
167  layout.name = NULL;
168 
169  while (1) {
170  int c;
171  int option_index = 0;
172  static struct option long_options[] = {
173  {"layout", required_argument, 0, 'l'},
174  {"index", required_argument, 0, 'i'},
175  {"vendor", required_argument, 0, 'v'},
176  {"product", required_argument, 0, 'p'},
177  {"dir", required_argument, 0, 0 },
178  {"reset_release", required_argument, 0, 0 },
179  {"reset_set", required_argument, 0, 0 },
180  {"vref2_normal", required_argument, 0, 0 },
181  {"vref2_erase", required_argument, 0, 0 },
182  {"interface", required_argument, 0, 0 },
183  {"help", no_argument, 0, '?'},
184  {0, 0, 0, 0}
185  };
186 
187  c = getopt_long (argc, argv, "i:l:v:p:",
188  long_options, &option_index);
189  if (c == -1)
190  break;
191 
192  switch (c) {
193  /* process long opts */
194  case 0:
195  if(strcmp(long_options[option_index].name, "interface") == 0) {
196  sscanf(optarg, "%i", &interface);
197  }
198  if(strcmp(long_options[option_index].name, "dir") == 0) {
199  sscanf(optarg, "%i", &dir);
200  }
201  if (strcmp(long_options[option_index].name, "reset_release") == 0) {
202  sscanf(optarg, "%i", &reset_release);
203  }
204  if (strcmp(long_options[option_index].name, "reset_set") == 0) {
205  sscanf(optarg, "%i", &reset_set);
206  }
207  if (strcmp(long_options[option_index].name, "vref2_normal") == 0) {
208  sscanf(optarg, "%i", &vref2_normal);
209  }
210  if (strcmp(long_options[option_index].name, "vref2_erase") == 0) {
211  sscanf(optarg, "%i", &vref2_erase);
212  }
213  break;
214 
215  case 'l':
216  strncpy(layout_str, optarg, BUF_LEN);
217  break;
218  case 'i':
219  dev_index = atoi(optarg);
220  break;
221  case 'v':
222  sscanf(optarg, "%i", &vendid);
223  break;
224  case 'p':
225  sscanf(optarg, "%i", &prodid);
226  break;
227  default:
228  usage();
229  break;
230  }
231  }
232 
233  if( !(l = find_layout(layout_str)) &&
234  !((interface >= 0) &&
235  (dir >= 0) &&
236  (reset_release >= 0) &&
237  (reset_set >= 0) &&
238  (vref2_normal >= 0) &&
239  (vref2_erase >= 0))
240  ) {
241 
242  printf("*** You must specify a layout or a complete set of overrides\n");
243  return EXIT_FAILURE;
244  }
245 
246  if(l) {
247  memcpy(&layout, l, sizeof(struct layout));
248  }
249 
250 #define override(x) if(x > 0) { layout.x = x; }
251  override(interface);
252  override(dir);
253  override(reset_release); override(reset_set);
254  override(vref2_normal); override(vref2_erase);
255 
256  if ((num_devs = ftdi_usb_find_all(&ftdic, &devlist, vendid, prodid)) < 0)
257  {
258  fprintf(stderr, "ftdi_usb_find_all failed: %d (%s)\n",
259  num_devs,
260  ftdi_get_error_string(&ftdic));
261  return EXIT_FAILURE;
262  }
263 
264  if (ftdi_init(&ftdic) < 0)
265  {
266  fprintf(stderr, "ftdi_init failed\n");
267  return EXIT_FAILURE;
268  }
269 
270  if (ftdi_set_interface(&ftdic, layout.interface) < 0) {
271  fprintf(stderr, "couldn't set interface %d\n", layout.interface);
272  return EXIT_FAILURE;
273  }
274 
275  printf("Found %d devices with vendor id 0x%04x product id 0x%04x\n",
276  num_devs, vendid, prodid);
277 
278  if(num_devs == 0) { return EXIT_SUCCESS; }
279 
280  if(num_devs == 1) { dev_index = 0; }
281  while( (dev_index < 0) || (dev_index >= num_devs)){
282  dev_index = print_and_prompt(devlist);
283  }
284 
285  if(layout.name != NULL) {
286  printf("Opening device %d interface %d using layout %s\n",
287  dev_index, layout.interface, layout.name);
288  } else {
289  printf("Opening device %d interface %d without a layout.\n",
290  dev_index, layout.interface);
291  }
292 
293  if( (ret = ftdi_usb_open_desc_index(
294  &ftdic,
295  vendid,
296  prodid,
297  NULL,
298  NULL,
299  dev_index)) < 0) {
300  fprintf(stderr, "couldn't open dev_index %d\n", dev_index);
301  return EXIT_FAILURE;
302  }
303 
304 
305  for(i = 0; commands[i].name != NULL; i++) {
306  if( (argv[optind] != NULL) &&
307  (strcmp(commands[i].name, argv[optind]) == 0)) { break; }
308  }
309  if(commands[i].name != NULL) {
310  commands[i].cmd(&ftdic, &layout);
311  } else {
312  printf("invalid command\n");
313 
314  ftdi_list_free(&devlist);
315  ftdi_deinit(&ftdic);
316 
317  return EXIT_FAILURE;
318  }
319 
320  printf("done.\n");
321 
322  ftdi_list_free(&devlist);
323  ftdi_deinit(&ftdic);
324 
325  return EXIT_SUCCESS;
326 }
327 
328 void usage(void)
329 {
330  int i;
331  printf( "Usage: bbmc [options|overrides] -l|--layout layout command \n");
332  printf( "Commands:\n");
333  for(i = 0; commands[i].name != NULL; i++) {
334  printf( " %s: %s\n", commands[i].name, commands[i].desc);
335  }
336  printf("\n");
337  printf( "Required options:\n");
338  printf( " -l|--layout\t specifiy which board layout to use\n");
339  printf( " \t layout is not necessary with a full\n");
340  printf( " \t set of overrides\n");
341  printf( "\nLayout overrides:\n");
342  printf( " --interface\t\t FTDI interface to use\n");
343  printf( " --dir\t\t direction (1 is output)\n");
344  printf( " --reset_release\t reset release command\n");
345  printf( " --reset_set\t\t reset set command\n");
346  printf( " --vref2_normal\t vref2 normal\n");
347  printf( " --vref2_erase\t vref2 erase\n");
348  printf("\n");
349  printf( "Layouts:\n");
350  for(i = 0; layouts[i].name != NULL; i++) {
351  printf( "\t%s: %s\n", layouts[i].name, layouts[i].desc);
352  printf("\n");
353  printf( "\t\tinterface: \t0x%04x\n", layouts[i].interface);
354  printf( "\t\tdir: \t\t0x%04x\n", layouts[i].dir);
355  printf( "\t\treset release: \t0x%04x\n", layouts[i].reset_release);
356  printf( "\t\treset hold: \t0x%04x\n", layouts[i].reset_set);
357  printf( "\t\tvref2 normal: \t0x%04x\n", layouts[i].vref2_normal);
358  printf( "\t\tvref2 erase: \t0x%04x\n", layouts[i].vref2_erase);
359  printf("\n");
360  }
361  printf("\n");
362  printf( "Options:\n");
363  printf( " -i|--index specifiy which device to use (default 0)\n");
364  printf( " -v|--vendor set vendor id (default 0x0403)\n");
365  printf( " -p|--product set vendor id (default 0x6010)\n");
366 }
367 
368 int print_and_prompt( struct ftdi_device_list *devlist )
369 {
370  int i, ret;
371  struct ftdi_context ftdic;
372  struct ftdi_device_list *curdev;
373  char manufacturer[128], description[128], serial[128];
374  char input[BUF_LEN]; char *s;
375  int sel = -1;
376 
377  printf("\n");
378 
379  i = 0;
380  for (curdev = devlist; curdev != NULL; i++)
381  {
382  printf(" [%d] ", i);
383  if (0 > (ret = ftdi_usb_get_strings(&ftdic,
384  curdev->dev,
385  manufacturer, 128,
386  description, 128,
387  serial, 128)))
388  {
389  fprintf(stderr, "ftdi_usb_get_strings failed: %d (%s)\n",
390  ret, ftdi_get_error_string(&ftdic));
391  return EXIT_FAILURE;
392  }
393  printf("Manufacturer: %s, Description: %s, Serial %s\n",
394  manufacturer, description, serial);
395  curdev = curdev->next;
396  }
397 
398  printf("\nUse which device? ");
399 
400  s = fgets(input, BUF_LEN, stdin);
401  if (s != NULL) {
402  size_t last = strlen (input) - 1;
403  if (input[last] == '\n') input[last] = '\0';
404  }
405 
406  sscanf(s, "%i",&sel);
407 
408  return sel;
409 }
410 
411 void reset(struct ftdi_context *ftdic, const struct layout * l)
412 {
413 
414  /* using MPSSE since it give access to high GPIO*/
415  /* set as inputs for now */
416  ftdi_set_bitmode(ftdic, 0 , BITMODE_MPSSE);
417 
418  printf("toggle reset\n");
419 
420  bb_mpsee(ftdic, l->dir, (l->reset_release | l->vref2_normal));
421  bb_mpsee(ftdic, l->dir, (l->reset_set | l->vref2_normal));
422  bb_mpsee(ftdic, l->dir, (l->reset_release | l->vref2_normal));
423 
424  return;
425 
426 }
427 
428 
429 void erase(struct ftdi_context *ftdic, const struct layout * l)
430 {
431  printf("setting VREF2 erase\n");
432 
433  /* using MPSSE since it give access to high GPIO*/
434  /* set as inputs for now */
435  ftdi_set_bitmode(ftdic, 0 , BITMODE_MPSSE);
436 
437  bb_mpsee(ftdic, l->dir, (l->reset_release | l->vref2_normal));
438  bb_mpsee(ftdic, l->dir, (l->reset_release | l->vref2_erase));
439 
440  printf("toggle reset\n");
441 
442  bb_mpsee(ftdic, l->dir, (l->reset_set | l->vref2_erase));
443  bb_mpsee(ftdic, l->dir, (l->reset_release | l->vref2_erase));
444 
445  printf("waiting for erase\n");
446 
447  sleep(2);
448 
449  printf("setting VREF2 normal\n");
450 
451  bb_mpsee(ftdic, l->dir, (l->reset_release | l->vref2_normal));
452 
453  reset(ftdic, l);
454 
455  return;
456 
457 }
458 
459 
460 int bb_mpsee(struct ftdi_context *ftdic, uint16_t dir, uint16_t val)
461 {
462  uint8_t buf[3];
463  int ret;
464 
465  /* command "set data bits low byte" */
466  buf[0] = 0x80;
467  buf[1] = (val & 0xff);
468  buf[2] = dir & 0xff;
469 #if DEBUG
470  fprintf(stderr,"write %x %x %x\n",buf[0],buf[1],buf[2]);
471 #endif
472 
473  if ((ret = (ftdi_write_data(ftdic, buf, 3))) < 0)
474  {
475  perror("ft2232_write error");
476  fprintf(stderr, "ft2232_write command %x\n", buf[0]);
477  return EXIT_FAILURE;
478  }
479 
480 
481  /* command "set data bits high byte" */
482  buf[0] = 0x82;
483  buf[1] = (val >> 8);
484  buf[2] = dir >> 8;
485 #if DEBUG
486  fprintf(stderr,"write %x %x %x\n",buf[0],buf[1],buf[2]);
487 #endif
488 
489  if ((ret = (ftdi_write_data(ftdic, buf, 3))) < 0)
490  {
491  perror("ft2232_write error");
492  fprintf(stderr, "ft2232_write command %x\n", buf[0]);
493  return EXIT_FAILURE;
494  }
495 
496  return 0;
497 
498 }