/*
 * $RCSfile: mem.c,v $  $Revision: 1.7 $  $Name:  $
 * $Id: mem.c,v 1.7 2007/09/09 18:16:04 bpaauwe Exp $
 * $Author: bpaauwe $
 * $Date: 2007/09/09 18:16:04 $
 * ----------------------------------------------------------------------------
 *
 *  Copyright (c) Bob Paauwe (2006)
 *
 *  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.,
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * ----------------------------------------------------------------------------
 *
 *  Description:
 *    read/write PLC memory.
 *
 * ----------------------------------------------------------------------------
 */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <memory.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include "ilib.h"


#define VERSION "mem version 0.2.20a Copyright (C) 2006, Bob Paauwe"
#define BLKSIZE 256
#define SALAD_ADDR 0x0210   /* Start address in PLC for salad code */

void usage(char *prog)
{
	printf("%s\n\n", VERSION);
	printf("This program will read and write PLC memory locations.\n");
	printf("\n");
	printf("usage: %s\n", prog);
	printf("       [-r <address> <len>        read bytes from PLC.\n");
	printf("       [-w <address> <data>       write byte in PLC.\n");
}

int main (int argc, char **argv)
{
	ilib_t *iplc;
	unsigned char test[100];
	unsigned char buffer[65536];
	char device_id[10];
	unsigned int start_addr;
	int dump = 0;
	int wbyte = 0;
	int write_mem = 0;
	int i;
	unsigned char wp;

	memset(device_id, 0, 10);

	if (argc > 0) {
		for (i = 1; i < argc; i++) {
			if (argv[i][0] == '-') {
				switch (argv[i][1]) {
					case 'V':
						printf("%s\n", VERSION);

						printf("arg = %d\n", alpha_to_i(argv[++i]));
						return 0;
						break;
					case 'h':
						usage(argv[0]);
						return 0;
						break;
					case 'r': /* do memory dump */
						dump = 1;
						start_addr = alpha_to_i(argv[++i]);
						dump = atoi(argv[++i]);
						break;
					case 'w': /* Program PLC */
						start_addr = alpha_to_i(argv[++i]);
						wbyte = alpha_to_i(argv[++i]);
						write_mem = 1;
						break;
					default:
						usage(argv[0]);
						return 0;
						break;
				}
			}
		}
	}

	printf("%s\n", VERSION);
	/* if ((iplc = ilib_open(USE_IPLC, "/dev/usb/iplc0")) == NULL) { */
	if ((iplc = ilib_open(USE_HIDDEV, "/dev/hiddev0")) == NULL) {
		perror("download:");
		return -1;
		if ((iplc = ilib_open(USE_LIBHID, NULL)) == NULL) {
			if ((iplc = ilib_open(USE_LIBUSB, NULL)) == NULL) {
				printf("Failed to connect to PLC\n");
				return -1;
			}
		}
	}

	/* Send some test commands */
	if (ibios_get_version(iplc, &test[0], buffer) == 0) {
		printf("PLC ID: %s   Firmware version %02x\n", buffer, test[0]);
	} else {
		printf("Command failed\n");
	}

	if(dump) {
		printf("Reading %d bytes starting at 0x%04x\n", dump, start_addr);
		ibios_read_memory(iplc, start_addr, dump, buffer);
		for (i = 0; i < dump; i++) {
			if ((i % 16) == 0) {
				printf("\n0x%04x: ", (start_addr + i));
			}
			printf("%02x ", (buffer[i] & 0xff));
		}
		printf("\n");
	}

	if (write_mem) {
		/*
		 * Remove write protect from salad code area just in case
		 * that is where  we're writing.
		 */
		ibios_read_memory(iplc, 0x016b, 1, &wp);
		wp |= 0x08;
		ibios_write_memory(iplc, 0x016b, 1, &wp);

		buffer[0] = wbyte;
		ibios_write_memory(iplc, start_addr, 1, buffer);
		printf("Wrote 0x%02x at 0x%04x\n", buffer[0], start_addr);

		/* Turn write protect back on */
		wp &= ~0x08;
		ibios_write_memory(iplc, 0x016b, 1, &wp);

	}

	ilib_close(iplc);
	return 0;
}

