fp@1388: /*****************************************************************************
fp@1388:  *
fp@1388:  *  $Id$
fp@1388:  *
fp@1388:  *  Copyright (C) 2006-2009  Florian Pose, Ingenieurgemeinschaft IgH
fp@1388:  *
fp@1388:  *  This file is part of the IgH EtherCAT Master.
fp@1388:  *
fp@1388:  *  The IgH EtherCAT Master is free software; you can redistribute it and/or
fp@1388:  *  modify it under the terms of the GNU General Public License version 2, as
fp@1388:  *  published by the Free Software Foundation.
fp@1388:  *
fp@1388:  *  The IgH EtherCAT Master is distributed in the hope that it will be useful,
fp@1388:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
fp@1388:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
fp@1388:  *  Public License for more details.
fp@1388:  *
fp@1388:  *  You should have received a copy of the GNU General Public License along
fp@1388:  *  with the IgH EtherCAT Master; if not, write to the Free Software
fp@1388:  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
fp@1388:  *
fp@1388:  *  ---
fp@1388:  *
fp@1388:  *  The license mentioned above concerns the source code only. Using the
fp@1388:  *  EtherCAT technology and brand is only permitted in compliance with the
fp@1388:  *  industrial property and similar rights of Beckhoff Automation GmbH.
fp@1388:  *
fp@1388:  ****************************************************************************/
fp@1388: 
fp@1388: #include <iostream>
fp@1388: #include <iomanip>
fp@1388: #include <fstream>
fp@1388: using namespace std;
fp@1388: 
fp@1388: #include "CommandRegWrite.h"
fp@1388: #include "sii_crc.h"
fp@1826: #include "MasterDevice.h"
fp@1388: 
fp@1388: /*****************************************************************************/
fp@1388: 
fp@1388: CommandRegWrite::CommandRegWrite():
fp@1835:     Command("reg_write", "Write data to a slave's registers.")
fp@1388: {
fp@1388: }
fp@1388: 
fp@1388: /*****************************************************************************/
fp@1388: 
fp@1968: string CommandRegWrite::helpString(const string &binaryBaseName) const
fp@1388: {
fp@1388:     stringstream str;
fp@1388: 
fp@1968:     str << binaryBaseName << " " << getName()
fp@1968:         << " [OPTIONS] <OFFSET> <DATA>" << endl
fp@1388:         << endl 
fp@1388:         << getBriefDescription() << endl
fp@1388:         << endl
fp@1388:         << "This command requires a single slave to be selected." << endl
fp@1804:         << endl
fp@1388:         << "Arguments:" << endl
fp@1389:         << "  OFFSET  is the register address to write to." << endl
fp@1389:         << "  DATA    depends on whether a datatype was specified" << endl
fp@1804:         << "          with the --type option: If not, DATA must be" << endl
fp@1804:         << "          either a path to a file with data to write," << endl
fp@1804:         << "          or '-', which means, that data are read from" << endl
fp@1804:         << "          stdin. If a datatype was specified, VALUE is" << endl
fp@1804:         << "          interpreted respective to the given type." << endl
fp@1388:         << endl
fp@1868:         << typeInfo()
fp@1804:         << endl
fp@1388:         << "Command-specific options:" << endl
fp@1388:         << "  --alias    -a <alias>" << endl
fp@1388:         << "  --position -p <pos>    Slave selection. See the help of" << endl
fp@1388:         << "                         the 'slaves' command." << endl
fp@1389:         << "  --type     -t <type>   Data type (see above)." << endl
fp@1388:         << endl
fp@1388:         << numericInfo();
fp@1388: 
fp@1388:     return str.str();
fp@1388: }
fp@1388: 
fp@1388: /****************************************************************************/
fp@1388: 
fp@1826: void CommandRegWrite::execute(const StringVector &args)
fp@1388: {
fp@1388:     stringstream strOffset, err;
fp@1388:     ec_ioctl_slave_reg_t data;
fp@1388:     ifstream file;
fp@1388:     SlaveList slaves;
fp@1388: 
fp@1388:     if (args.size() != 2) {
fp@1388:         err << "'" << getName() << "' takes exactly two arguments!";
fp@1388:         throwInvalidUsageException(err);
fp@1388:     }
fp@1388:     
fp@1388:     strOffset << args[0];
fp@1388:     strOffset
fp@1388:         >> resetiosflags(ios::basefield) // guess base from prefix
fp@1388:         >> data.offset;
fp@1388:     if (strOffset.fail()) {
fp@1388:         err << "Invalid offset '" << args[0] << "'!";
fp@1388:         throwInvalidUsageException(err);
fp@1388:     }
fp@1826:   
fp@1804:     if (getDataType().empty()) {
fp@1804:         if (args[1] == "-") {
fp@1804:             loadRegData(&data, cin);
fp@1804:         } else {
fp@1804:             file.open(args[1].c_str(), ifstream::in | ifstream::binary);
fp@1804:             if (file.fail()) {
fp@1804:                 err << "Failed to open '" << args[1] << "'!";
fp@1804:                 throwCommandException(err);
fp@1804:             }
fp@1804:             loadRegData(&data, file);
fp@1804:             file.close();
fp@1804:         }
fp@1804:     } else {
fp@1804:         stringstream strValue;
fp@1804:         const DataType *dataType = findDataType(getDataType());
fp@1389: 
fp@1389:         if (!dataType) {
fp@1389:             err << "Invalid data type '" << getDataType() << "'!";
fp@1389:             throwInvalidUsageException(err);
fp@1388:         }
fp@1389: 
fp@1804:         if (dataType->byteSize) {
fp@1804:             data.length = dataType->byteSize;
fp@1835:         } else {
fp@1835:             data.length = 1024; // FIXME
fp@1835:         }
fp@1835: 
fp@1835:         data.data = new uint8_t[data.length];
fp@1804: 
fp@1804:         try {
fp@1835:             data.length = interpretAsType(
fp@1835:                     dataType, args[1], data.data, data.length);
fp@1835:         } catch (SizeException &e) {
fp@1835:             delete [] data.data;
fp@1835:             throwCommandException(e.what());
fp@1804:         } catch (ios::failure &e) {
fp@1804:             delete [] data.data;
fp@1804:             err << "Invalid value argument '" << args[1]
fp@1804:                 << "' for type '" << dataType->name << "'!";
fp@1804:             throwInvalidUsageException(err);
fp@1804:         }
fp@1804:     }
fp@1388: 
fp@1388:     if ((uint32_t) data.offset + data.length > 0xffff) {
fp@1388:         err << "Offset and length exceeding 64k!";
fp@1388:         delete [] data.data;
fp@1388:         throwInvalidUsageException(err);
fp@1388:     }
fp@1388: 
fp@1870:     MasterDevice m(getSingleMasterIndex());
fp@1388:     try {
fp@1388:         m.open(MasterDevice::ReadWrite);
fp@1388:     } catch (MasterDeviceException &e) {
fp@1388:         delete [] data.data;
fp@1388:         throw e;
fp@1388:     }
fp@1388: 
fp@1388:     slaves = selectedSlaves(m);
fp@1388:     if (slaves.size() != 1) {
fp@1388:         delete [] data.data;
fp@1388:         throwSingleSlaveRequired(slaves.size());
fp@1388:     }
fp@1388:     data.slave_position = slaves.front().position;
fp@1388: 
fp@1388:     // send data to master
fp@1388:     try {
fp@1388:         m.writeReg(&data);
fp@1388:     } catch (MasterDeviceException &e) {
fp@1388:         delete [] data.data;
fp@1388:         throw e;
fp@1388:     }
fp@1388: 
fp@1388:     if (getVerbosity() == Verbose) {
fp@1388:         cerr << "Register writing finished." << endl;
fp@1388:     }
fp@1388: 
fp@1388:     delete [] data.data;
fp@1388: }
fp@1388: 
fp@1388: /*****************************************************************************/
fp@1388: 
fp@1388: void CommandRegWrite::loadRegData(
fp@1388:         ec_ioctl_slave_reg_t *data,
fp@1388:         const istream &in
fp@1388:         )
fp@1388: {
fp@1388:     stringstream err;
fp@1388:     ostringstream tmp;
fp@1388: 
fp@1388:     tmp << in.rdbuf();
fp@1388:     string const &contents = tmp.str();
fp@1388: 
fp@1388:     if (getVerbosity() == Verbose) {
fp@1388:         cerr << "Read " << contents.size() << " bytes of data." << endl;
fp@1388:     }
fp@1388: 
fp@1388:     if (contents.size() > 0xffff) {
fp@1388:         err << "Invalid data size " << contents.size() << "!";
fp@1388:         throwInvalidUsageException(err);
fp@1388:     }
fp@1388:     data->length = contents.size();
fp@1388: 
fp@1388:     // allocate buffer and read file into buffer
fp@1388:     data->data = new uint8_t[data->length];
fp@1388:     contents.copy((char *) data->data, contents.size());
fp@1388: }
fp@1388: 
fp@1388: /*****************************************************************************/