osd-contiki/tools/sensinode/nano_programmer/programmer.c

440 lines
9.7 KiB
C

/*
NanoStack: MCU software and PC tools for IP-based wireless sensor networking.
Copyright (C) 2006-2007 Sensinode Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Address:
Sensinode Ltd.
Teknologiantie 6
90570 Oulu, Finland
E-mail:
info@sensinode.com
*/
#include <unistd.h>
#include <getopt.h>
#include <strings.h>
#include "port.h"
#include "programmer.h"
#include <stdio.h>
extern int cdi_programmer(conf_opts_t *conf, char *filename);
void usage(char *prg_name)
{
printf("\nUsage: %s [-d device]\n", prg_name);
printf("General options:\n");
printf(" -V/--version Get programmer version\n");
printf(" -1/--d100 Use D100 board (default D200)\n");
printf("Operating modes:\n");
printf(" -b/--bios to get programmer BIOS version\n");
printf(" -P/--program [ihex file] Do a complete programming sequence (write and verify)\n");
printf(" -v/--verify [ihex file] Verify against ihex file\n");
printf(" -r/--read [ihex file] Read program code into ihex file\n");
printf(" -m/--mac Read device MAC address\n");
printf(" -Q/--write-mac [MAC address] Write device MAC address\n");
printf(" -e/--erase Erase flash (erases MAC address!)\n");
printf("Programming options:\n");
printf(" -l/--linear Force linear model for extended addresses (not SDCC file)\n");
printf(" -s/--sdcc Force SDCC model for extended addresses (SDCC file)\n");
printf("Defaults:\n");
#ifndef PLATFORM_WINDOWS
printf("device /dev/ttyUSB0\n");
#else
printf("device 0\n");
#endif
}
conf_opts_t conf_opts;
static int option_index = 0;
int do_exit = 0;
#define OPTIONS_STRING "d:ec1lsmVbP:v:r:Q:"
/* long option list */
static struct option long_options[] =
{
{"device", 1, NULL, 'd'},
{"psoc", 0, NULL, 'p'},
{"d100", 0, NULL, '1'},
{"erase", 0, NULL, 'e'},
{"mac", 0, NULL, 'm'},
{"linear", 0, NULL, 'l'},
{"sdcc", 0, NULL, 's'},
{"cdi", 0, NULL, 'c'},
{"version", 0, NULL, 'V'},
{"bios", 0, NULL, 'b'},
{"program", 1, NULL, 'P'},
{"verify", 1, NULL, 'v'},
{"read", 1, NULL, 'r'},
{"write-mac", 1, NULL, 'Q'},
{0, 0, 0, 0}
};
int parse_opts(int count, char* param[])
{
int opt;
int error=0;
conf_opts.target_type = CDI;
while ((opt = getopt_long(count, param, OPTIONS_STRING,
long_options, &option_index)) != -1)
{
switch(opt)
{
case 'V':
conf_opts.target_type = VERSION;
break;
case '1':
conf_opts.prg_type = 1;
break;
case 'c':
conf_opts.target_type = CDI;
break;
case 'd':
#ifdef PLATFORM_WINDOWS
if (sscanf(optarg, "%d", &conf_opts.device) != 1)
{
printf("Device ID must be a positive integer.\n");
conf_opts.action = ' ';
}
#else
printf("device:%s\n", optarg);
strcpy(conf_opts.device, optarg);
#endif
break;
case 'P':
printf("Programming mode.\n");
conf_opts.action = 'P';
strcpy(conf_opts.ihex_file, optarg);
break;
case 's':
if (conf_opts.page_mode == PAGE_UNDEFINED)
{
conf_opts.page_mode = PAGE_SDCC;
}
else
{
printf("Only one paging option allowed.\n");
error = -1;
}
break;
case 'l':
if (conf_opts.page_mode == PAGE_UNDEFINED)
{
conf_opts.page_mode = PAGE_LINEAR;
}
else
{
printf("Only one paging option allowed.\n");
error = -1;
}
break;
case 'e':
printf("Erase.\n");
conf_opts.action = 'e';
break;
case 'm':
printf("Get MAC.\n");
conf_opts.action = 'm';
break;
case 'b':
printf("Get BIOS version\n");
conf_opts.action = 'b';
break;
case 'Q':
printf("Write MAC.\n");
conf_opts.action = 'Q';
if (sscanf(optarg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&conf_opts.write_mac[0], &conf_opts.write_mac[1],
&conf_opts.write_mac[2], &conf_opts.write_mac[3],
&conf_opts.write_mac[4], &conf_opts.write_mac[5],
&conf_opts.write_mac[6], &conf_opts.write_mac[7]) != 8)
{
printf("Invalid MAC.\n");
conf_opts.action = ' ';
}
break;
case 'v':
printf("Verify by comparing to ihex file:%s\n", optarg);
conf_opts.action = 'v';
strcpy(conf_opts.ihex_file, optarg);
break;
case 'r':
printf("Read program to ihex file:%s\n", optarg);
conf_opts.action = 'r';
strcpy(conf_opts.ihex_file, optarg);
break;
case '?':
printf("Duh\n");
error = -1;
break;
}
}
if (!error && (conf_opts.target_type == CDI) )
{
#ifdef PLATFORM_WINDOWS
printf("Setup: Device %d.\n", conf_opts.device);
#else
printf("Setup: Device %s.\n", conf_opts.device);
#endif
}
return error;
}
/*
int port_write_8byte_echo(port_t *port, char *string)
{
int length = 0;
int total_len;
int i, j;
struct pollfd pfds;
unsigned int nfds = 1;
int rval = 0;
int wrbytes = 2;
unsigned char byte8[wrbytes];
pfds.fd = (int)(port->handle);
pfds.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
total_len = strlen(string);
while(total_len > length)
{
if(total_len - length >= wrbytes)
{
i=0;
port_write(port, (unsigned char *)&string[length], wrbytes);
if((rval = poll(&pfds, nfds, 100)) == 0)
{
printf("Timed out...\n");
return(-1);
}
else
{
while(i<wrbytes)
{
i += port_read(port, &byte8[i], wrbytes);
}
if(i != wrbytes || memcmp(byte8, &string[length], wrbytes) != 0)
{
printf("Got wrong length (%d) or wrong bytes back.\n", i);
for(j=0;j<wrbytes;j++)
{
printf("%.2x <-> %.2x\n", string[length+j], byte8[j]);
}
return(-1);
}
else
{
printf("8Bwok - ");
fflush(stdout);
length += wrbytes;
}
}
}
else
{
i=0;
port_write(port, (unsigned char *)&string[length], total_len - length);
if((rval = poll(&pfds, nfds, 100)) == 0)
{
printf("Timed out...\n");
return(-1);
}
else
{
while(i<(total_len-length))
{
i = port_read(port, &byte8[i], total_len - length);
}
if(i != total_len - length || memcmp(byte8, &string[length], total_len - length) != 0)
{
printf("Got wrong length or wrong bytes back.\n");
for(j=0;j<total_len - length;j++)
{
printf("%.2x <-> %.2x\n", string[length+j], byte8[j]);
}
return(-1);
}
else
{
printf("<8Bwok - \n");
fflush(stdout);
length += (total_len - length);
}
}
}
usleep(5000);
}
return(length);
}
*/
#ifdef PLATFORM_WINDOWS
int programmer_init(int device, port_t **port)
#else
int programmer_init(char *device, port_t **port)
#endif
{
int error = port_open(port, device);
uint8_t buffer[8];
buffer[0] = 0;
if (error >= 0)
{
if (conf_opts.prg_type == 1)
{
int retry = 0;
port_set_params(*port, 9600, 0);
// Activate programming...
port_dtr_clear(*port);
port_rts_clear(*port);
sleep(1);
printf("Select D100.\n");
port_rts_set(*port);
sleep(1);
buffer[0] = '\r';
while (retry++ < 3)
{
int length;
port_write_echo(*port, "q\r");
length = port_readline(*port, buffer, sizeof(buffer), 800);
if (length)
{
if (*buffer == '!')
{
printf("D100 found.\n");
return 0;
}
}
}
printf("No programmer found.\n");
return -1;
}
else
{
port_set_params(*port, 57600, 0);
// Activate programming...
port_dtr_clear(*port);
port_rts_clear(*port);
usleep(300000);
printf("Select D200.\n");
port_rts_set(*port);
usleep(200000);
port_set_params(*port, 57600, 1);
port_write(*port, (uint8_t *)"\r", 1);
usleep(100000);
if ((port_get(*port, buffer, 500) >= 1) && (buffer[0] == '!'))
{
printf("D200 found.\n");
return 0;
}
printf("No programmer found.\n");
return -1;
}
}
return error;
}
void programmer_close(port_t *port)
{
if (port)
{
port_rts_clear(port);
port_dtr_set(port);
sleep(1);
port_close(port);
printf("Port closed.\n");
}
}
int main(int argc, char *argv[])
{
int error = 0;
conf_opts.target_type = 0;
conf_opts.action = 0;
conf_opts.prg_type = 2;
#ifndef PLATFORM_WINDOWS
strncpy(conf_opts.device, "/dev/ttyUSB0", 12);
/* Install a new handler for SIGIO.
*
* According to man 7 signal this signal is by default ignored by most systems.
* It seems that pre FC7 this was true for Fedoras also. We have noticed that at least
* on some FC7 installations the default action has changed. We avoid abnormal program
* exits by defining the SIGIO as SIG_IGN (ignore). - mjs
*/
if(signal(SIGIO, SIG_IGN) == SIG_ERR)
{
printf("%s error: failed to install SIGIO handler. Exit.\n", argv[0]);
exit(EXIT_FAILURE);
}
#else
conf_opts.device = 0;
#endif
conf_opts.page_mode = PAGE_UNDEFINED;
if ( (argc <= 1) || (error = parse_opts(argc, argv)) )
{
usage(argv[0]);
if (error < 0) return error;
else return 0;
}
if(conf_opts.target_type == CDI)
{ /*CDI*/
error = cdi_programmer(&conf_opts, conf_opts.ihex_file);
}
else
{
printf("\nSensinode Nano series programmer "PROGRAMMER_VERSION "\n");
}
return error;
}