vector<byte> *OOIEEPROMProtocol::readEEPROMSlot(const Bus &bus, int slot)
        throw (ProtocolException) {

    ByteVector *bv = NULL;
    Data *result = NULL;

    ReadEEPROMSlotExchange xchange(slot);

    TransferHelper *helper = bus.getHelper(xchange.getHints());
    if(NULL == helper) {
        string error("Failed to find a helper to bridge given protocol and bus.");
        throw ProtocolBusMismatchException(error);
    }

    result = xchange.transfer(helper);
    if(NULL == result) {
        string error("Expected Transfer::transfer to produce a non-null result "
                "containing raw EEPROM data.  Without this data, it is not possible to "
                "generate a valid EEPROM slot value.");
        throw ProtocolException(error);
    }

    bv = static_cast<ByteVector *>(result);

    // strip off leading two bytes (echoed request)
    vector<byte> raw = bv->getByteVector();
    vector<byte> *retval = new vector<byte>(raw.size() - 2);
    memcpy(&((*retval)[0]), &(raw[2]), retval->size());

    delete result; /* a.k.a. bv */

    return retval;
}
vector<float> *OOIIrradCalProtocol::readIrradCal(const Bus &bus)
        throw (ProtocolException) {
    TransferHelper *helper;
    OOIReadIrradCalExchange readCalExchange(this->numberOfPixels);

    helper = bus.getHelper(readCalExchange.getHints());
    if (NULL == helper) {
        string error("Failed to find a helper to bridge given protocol and bus.");
        throw ProtocolBusMismatchException(error);
    }

    /* This transfer() may cause a ProtocolException to be thrown. */
    Data *result = readCalExchange.transfer(helper);
    if (NULL == result) {
        string error("Expected Transfer::transfer to produce a non-null result "
            "containing calibration data.  Without this data, it is not possible to "
            "generate a calibration array.");
        throw ProtocolException(error);
    }

    /* FIXME: this cast is known to be safe for now, but this needs
     * to do some sort of check to make sure the cast is valid.
     */
    ByteVector *bv = static_cast<ByteVector *>(result);
    vector<byte> raw = bv->getByteVector();
    vector<float> *retval = new vector<float>;

    for(unsigned int i = 0; i < raw.size(); i += 4) {
        float value;
        unsigned int *fptr = (unsigned int *)&value;
        /* The convention here is MSB first */
        *fptr =   ((raw[i] & 0x00FF) << 24)
                | ((raw[i + 1] & 0x00FF) << 16)
                | ((raw[i + 2] & 0x00FF) << 8)
                | ((raw[i + 3] & 0x00FF));
        retval->push_back(value);
    }
    delete result;

    return retval;
}
unsigned int FPGARegisterProtocol::readRegister(const Bus &bus, byte address)
        throw (ProtocolException) {

    unsigned int retval = 0;

    FPGARegisterReadExchange exchange(address);

    TransferHelper *helper = bus.getHelper(exchange.getHints());
    if(NULL == helper) {
        string error("Failed to find a helper to bridge given protocol and bus.");
        throw ProtocolBusMismatchException(error);
    }

    Data* result = exchange.transfer(helper);
    if(NULL == result) {
        string error("Expected non-NULL result from FPGARegisterReadExchange");
        throw ProtocolException(error);
    }

    ByteVector *bv = dynamic_cast<ByteVector *>(result);
    if(NULL == bv) {
        throw ProtocolException(string("Expected ByteVector from FPGARegisterReadExchange"));
    }

    vector<byte> byteVec = bv->getByteVector();
    if(3 != byteVec.size()) {
        throw ProtocolException(string("Expected 3 bytes from FPGARegisterReadExchange"));
    }

    // Response is 3 bytes (address echo, LSB, MSB)
    // TODO: this will need to be updated when we have devices with 32-bit registers
    retval = (unsigned int) (byteVec[1] | ((unsigned int) byteVec[2] << 8));

    delete result;

    return retval;
}
Data *OOIReadIrradCalExchange::transfer(TransferHelper *helper)
        throw (ProtocolException) {
    Data *xfer;
    ByteVector *output = new ByteVector();
    vector<Transfer *>::iterator iter = this->transfers.begin();
    /* Number of calibration bytes that will be read */
    int bytesLeft = this->numberOfPixels * sizeof(float);

    /* Iterate over all stored transfers and delegate to the helper to
     * move the data.
     */
    for(iter = this->transfers.begin(); iter != this->transfers.end(); iter++) {
        /* Note that this may throw a ProtocolException which will not be caught here. */
        /* Either send request for data, or obtain data.
         * xfer will be NULL if request being issued.
         * data is returned as ByteVector type object if data being returned.
         */
        xfer = (*iter)->transfer(helper);

        if(NULL != xfer) {
            /* transfer block of 60 bytes from xfer to output */
            for(    unsigned int i = 0;
                    i < ((ByteVector*)xfer)->getByteVector().size()
                        && bytesLeft > 0;
                    i++, bytesLeft--) {
                /* FIXME: can this be done more efficiently using a memcpy()? */
                output->getByteVector().push_back(
                    ((ByteVector*)xfer)->getByteVector()[i]);
            }
            delete xfer; /* clear for next iteration */
        }
    }

    /* return concatenated data as ByteVector */
    return output;
}