<commit_before>/**
@file	Streaming.cpp
@brief	Soapy SDR + IConnection streaming interfaces.
@author Lime Microsystems (www.limemicro.com)
*/

#include "SoapyLMS7.h"
#include <IConnection.h>
#include <SoapySDR/Formats.hpp>
#include <SoapySDR/Time.hpp>
#include "ErrorReporting.h"

using namespace lime;

/*******************************************************************
 * Stream data structure
 ******************************************************************/
struct IConnectionStream
{
    std::vector<size_t> streamID;
    int direction;
};

/*******************************************************************
 * Stream information
 ******************************************************************/
std::vector<std::string> SoapyLMS7::getStreamFormats(const int direction, const size_t channel) const
{
    std::vector<std::string> formats;
    formats.push_back(SOAPY_SDR_CF32);
    formats.push_back(SOAPY_SDR_CS12);
    formats.push_back(SOAPY_SDR_CS16);
    return formats;
}

std::string SoapyLMS7::getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const
{
    fullScale = 2048;
    return SOAPY_SDR_CS16;
}

SoapySDR::ArgInfoList SoapyLMS7::getStreamArgsInfo(const int direction, const size_t channel) const
{
    SoapySDR::ArgInfoList argInfos;

    //buffer length
    {
        SoapySDR::ArgInfo info;
        info.key = "bufferLength";
        info.name = "Buffer Length";
        info.description = "The buffer transfer size over the link.";
        info.units = "samples";
        info.type = SoapySDR::ArgInfo::INT;
        argInfos.push_back(info);
    }

    //link format
    {
        SoapySDR::ArgInfo info;
        info.key = "linkFormat";
        info.name = "Link Format";
        info.description = "The format of the samples over the link.";
        info.type = SoapySDR::ArgInfo::STRING;
        info.options.push_back(SOAPY_SDR_CS16);
        info.options.push_back(SOAPY_SDR_CS12);
        info.optionNames.push_back("Complex int16");
        info.optionNames.push_back("Complex int12");
        argInfos.push_back(info);
    }

    return argInfos;
}

/*******************************************************************
 * Stream config
 ******************************************************************/
SoapySDR::Stream *SoapyLMS7::setupStream(
    const int direction,
    const std::string &format,
    const std::vector<size_t> &channels,
    const SoapySDR::Kwargs &args)
{
    std::unique_lock<std::recursive_mutex> lock(_accessMutex);

    //store result into opaque stream object
    auto stream = new IConnectionStream;
    stream->direction = direction;

    StreamConfig config;
    config.isTx = (direction == SOAPY_SDR_TX);

    //default to channel 0, if none were specified
    const std::vector<size_t> &channelIDs = channels.empty() ? std::vector<size_t>{0} : channels;

    for(size_t i=0; i<channelIDs.size(); ++i)
    {
        config.channelID = channelIDs[i];
        if (format == SOAPY_SDR_CF32) config.format = StreamConfig::STREAM_COMPLEX_FLOAT32;
        else if (format == SOAPY_SDR_CS16) config.format = StreamConfig::STREAM_12_BIT_IN_16;
        else if (format == SOAPY_SDR_CS12) config.format = StreamConfig::STREAM_12_BIT_COMPRESSED;
        else throw std::runtime_error("SoapyLMS7::setupStream(format="+format+") unsupported format");

        //optional buffer length if specified
        if (args.count("bufferLength") != 0)
        {
            config.bufferLength = std::stoul(args.at("bufferLength"));
        }

        //create the stream
        size_t streamID(~0);
        const int status = _conn->SetupStream(streamID, config);
        if (status != 0)
            throw std::runtime_error("SoapyLMS7::setupStream() failed: " + std::string(GetLastErrorMessage()));
        stream->streamID.push_back(streamID);
    }
    return (SoapySDR::Stream *)stream;
}

void SoapyLMS7::closeStream(SoapySDR::Stream *stream)
{
    std::unique_lock<std::recursive_mutex> lock(_accessMutex);
    auto icstream = (IConnectionStream *)stream;
    auto streamID = icstream->streamID;

    for(auto i : streamID)
        _conn->CloseStream(i);
}

size_t SoapyLMS7::getStreamMTU(SoapySDR::Stream *stream) const
{
    auto icstream = (IConnectionStream *)stream;
    auto streamID = icstream->streamID;
    for(auto i : streamID)
    {
        return _conn->GetStreamSize(i);
    }
    return 0;
}

int SoapyLMS7::activateStream(
    SoapySDR::Stream *stream,
    const int flags,
    const long long timeNs,
    const size_t numElems)
{
    auto icstream = (IConnectionStream *)stream;
    auto streamID = icstream->streamID;

    if (_conn->GetHardwareTimestampRate() == 0.0)
        throw std::runtime_error("SoapyLMS7::activateStream() - the sample rate has not been configured!");

    StreamMetadata metadata;
    metadata.timestamp = SoapySDR::timeNsToTicks(timeNs, _conn->GetHardwareTimestampRate());
    metadata.hasTimestamp = (flags & SOAPY_SDR_HAS_TIME) != 0;
    metadata.endOfBurst = (flags & SOAPY_SDR_END_BURST) != 0;
    for(auto i : streamID)
    {
        int status = _conn->ControlStream(i, true);
        if(status != 0)
            return SOAPY_SDR_STREAM_ERROR;
    }
    return 0;
}

int SoapyLMS7::deactivateStream(
    SoapySDR::Stream *stream,
    const int flags,
    const long long timeNs)
{
    auto icstream = (IConnectionStream *)stream;
    auto streamID = icstream->streamID;

    StreamMetadata metadata;
    metadata.timestamp = SoapySDR::timeNsToTicks(timeNs, _conn->GetHardwareTimestampRate());
    metadata.hasTimestamp = (flags & SOAPY_SDR_HAS_TIME) != 0;
    metadata.endOfBurst = (flags & SOAPY_SDR_END_BURST) != 0;
    for(auto i : streamID)
    {
        int status = _conn->ControlStream(i, false);
        if(status != 0)
            return SOAPY_SDR_STREAM_ERROR;
    }
    return 0;
}

/*******************************************************************
 * Stream API
 ******************************************************************/
int SoapyLMS7::readStream(
    SoapySDR::Stream *stream,
    void * const *buffs,
    const size_t numElems,
    int &flags,
    long long &timeNs,
    const long timeoutUs)
{
    auto icstream = (IConnectionStream *)stream;
    auto streamID = icstream->streamID;

    StreamMetadata metadata;
    int status = 0;
    int bufIndex = 0;
    for(auto i : streamID)
    {
        status = _conn->ReadStream(i, buffs[bufIndex++], numElems, timeoutUs/1000, metadata);
        if(status == 0) return SOAPY_SDR_TIMEOUT;
        if(status < 0) return SOAPY_SDR_STREAM_ERROR;
    }
    //output metadata
    flags = 0;
    if (metadata.endOfBurst) flags |= SOAPY_SDR_END_BURST;
    if (metadata.hasTimestamp) flags |= SOAPY_SDR_HAS_TIME;
    timeNs = SoapySDR::ticksToTimeNs(metadata.timestamp, _conn->GetHardwareTimestampRate());
    //return num read or error code
    return (status >= 0) ? status : SOAPY_SDR_STREAM_ERROR;
}

int SoapyLMS7::writeStream(
    SoapySDR::Stream *stream,
    const void * const *buffs,
    const size_t numElems,
    int &flags,
    const long long timeNs,
    const long timeoutUs)
{
    auto icstream = (IConnectionStream *)stream;
    auto streamID = icstream->streamID;

    //input metadata
    StreamMetadata metadata;
    metadata.timestamp = SoapySDR::timeNsToTicks(timeNs, _conn->GetHardwareTimestampRate());
    metadata.hasTimestamp = (flags & SOAPY_SDR_HAS_TIME) != 0;
    metadata.endOfBurst = (flags & SOAPY_SDR_END_BURST) != 0;

    int ret = 0;
    int bufIndex = 0;
    for(auto i : streamID)
    {
        ret = _conn->WriteStream(i, buffs[bufIndex++], numElems, timeoutUs/1000, metadata);
        if(ret == 0) return SOAPY_SDR_TIMEOUT;
        if(ret < 0) return SOAPY_SDR_STREAM_ERROR;
    }

    //return num written or error code
    return (ret > 0)? ret : SOAPY_SDR_STREAM_ERROR;
}

int SoapyLMS7::readStreamStatus(
    SoapySDR::Stream *stream,
    size_t &chanMask,
    int &flags,
    long long &timeNs,
    const long timeoutUs)
{
    auto icstream = (IConnectionStream *)stream;
    auto streamID = icstream->streamID;

    StreamMetadata metadata;
    for(auto i : streamID)
    {
        int ret = _conn->ReadStreamStatus(i, timeoutUs/1000, metadata);
        if (ret != 0)
            return SOAPY_SDR_TIMEOUT;
    }

    //output metadata
    flags = 0;
    if (metadata.endOfBurst) flags |= SOAPY_SDR_END_BURST;
    if (metadata.hasTimestamp) flags |= SOAPY_SDR_HAS_TIME;
    timeNs = SoapySDR::ticksToTimeNs(metadata.timestamp, _conn->GetHardwareTimestampRate());

    if (metadata.lateTimestamp) return SOAPY_SDR_TIME_ERROR;
    if (metadata.packetDropped) return SOAPY_SDR_OVERFLOW;
    return 0;
}
<commit_msg>readStreamStatus - handle not implemented case<commit_after>/**
@file	Streaming.cpp
@brief	Soapy SDR + IConnection streaming interfaces.
@author Lime Microsystems (www.limemicro.com)
*/

#include "SoapyLMS7.h"
#include <IConnection.h>
#include <SoapySDR/Formats.hpp>
#include <SoapySDR/Time.hpp>
#include "ErrorReporting.h"

using namespace lime;

/*******************************************************************
 * Stream data structure
 ******************************************************************/
struct IConnectionStream
{
    std::vector<size_t> streamID;
    int direction;
};

/*******************************************************************
 * Stream information
 ******************************************************************/
std::vector<std::string> SoapyLMS7::getStreamFormats(const int direction, const size_t channel) const
{
    std::vector<std::string> formats;
    formats.push_back(SOAPY_SDR_CF32);
    formats.push_back(SOAPY_SDR_CS12);
    formats.push_back(SOAPY_SDR_CS16);
    return formats;
}

std::string SoapyLMS7::getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const
{
    fullScale = 2048;
    return SOAPY_SDR_CS16;
}

SoapySDR::ArgInfoList SoapyLMS7::getStreamArgsInfo(const int direction, const size_t channel) const
{
    SoapySDR::ArgInfoList argInfos;

    //buffer length
    {
        SoapySDR::ArgInfo info;
        info.key = "bufferLength";
        info.name = "Buffer Length";
        info.description = "The buffer transfer size over the link.";
        info.units = "samples";
        info.type = SoapySDR::ArgInfo::INT;
        argInfos.push_back(info);
    }

    //link format
    {
        SoapySDR::ArgInfo info;
        info.key = "linkFormat";
        info.name = "Link Format";
        info.description = "The format of the samples over the link.";
        info.type = SoapySDR::ArgInfo::STRING;
        info.options.push_back(SOAPY_SDR_CS16);
        info.options.push_back(SOAPY_SDR_CS12);
        info.optionNames.push_back("Complex int16");
        info.optionNames.push_back("Complex int12");
        argInfos.push_back(info);
    }

    return argInfos;
}

/*******************************************************************
 * Stream config
 ******************************************************************/
SoapySDR::Stream *SoapyLMS7::setupStream(
    const int direction,
    const std::string &format,
    const std::vector<size_t> &channels,
    const SoapySDR::Kwargs &args)
{
    std::unique_lock<std::recursive_mutex> lock(_accessMutex);

    //store result into opaque stream object
    auto stream = new IConnectionStream;
    stream->direction = direction;

    StreamConfig config;
    config.isTx = (direction == SOAPY_SDR_TX);

    //default to channel 0, if none were specified
    const std::vector<size_t> &channelIDs = channels.empty() ? std::vector<size_t>{0} : channels;

    for(size_t i=0; i<channelIDs.size(); ++i)
    {
        config.channelID = channelIDs[i];
        if (format == SOAPY_SDR_CF32) config.format = StreamConfig::STREAM_COMPLEX_FLOAT32;
        else if (format == SOAPY_SDR_CS16) config.format = StreamConfig::STREAM_12_BIT_IN_16;
        else if (format == SOAPY_SDR_CS12) config.format = StreamConfig::STREAM_12_BIT_COMPRESSED;
        else throw std::runtime_error("SoapyLMS7::setupStream(format="+format+") unsupported format");

        //optional buffer length if specified
        if (args.count("bufferLength") != 0)
        {
            config.bufferLength = std::stoul(args.at("bufferLength"));
        }

        //create the stream
        size_t streamID(~0);
        const int status = _conn->SetupStream(streamID, config);
        if (status != 0)
            throw std::runtime_error("SoapyLMS7::setupStream() failed: " + std::string(GetLastErrorMessage()));
        stream->streamID.push_back(streamID);
    }
    return (SoapySDR::Stream *)stream;
}

void SoapyLMS7::closeStream(SoapySDR::Stream *stream)
{
    std::unique_lock<std::recursive_mutex> lock(_accessMutex);
    auto icstream = (IConnectionStream *)stream;
    auto streamID = icstream->streamID;

    for(auto i : streamID)
        _conn->CloseStream(i);
}

size_t SoapyLMS7::getStreamMTU(SoapySDR::Stream *stream) const
{
    auto icstream = (IConnectionStream *)stream;
    auto streamID = icstream->streamID;
    for(auto i : streamID)
    {
        return _conn->GetStreamSize(i);
    }
    return 0;
}

int SoapyLMS7::activateStream(
    SoapySDR::Stream *stream,
    const int flags,
    const long long timeNs,
    const size_t numElems)
{
    auto icstream = (IConnectionStream *)stream;
    auto streamID = icstream->streamID;

    if (_conn->GetHardwareTimestampRate() == 0.0)
        throw std::runtime_error("SoapyLMS7::activateStream() - the sample rate has not been configured!");

    StreamMetadata metadata;
    metadata.timestamp = SoapySDR::timeNsToTicks(timeNs, _conn->GetHardwareTimestampRate());
    metadata.hasTimestamp = (flags & SOAPY_SDR_HAS_TIME) != 0;
    metadata.endOfBurst = (flags & SOAPY_SDR_END_BURST) != 0;
    for(auto i : streamID)
    {
        int status = _conn->ControlStream(i, true);
        if(status != 0)
            return SOAPY_SDR_STREAM_ERROR;
    }
    return 0;
}

int SoapyLMS7::deactivateStream(
    SoapySDR::Stream *stream,
    const int flags,
    const long long timeNs)
{
    auto icstream = (IConnectionStream *)stream;
    auto streamID = icstream->streamID;

    StreamMetadata metadata;
    metadata.timestamp = SoapySDR::timeNsToTicks(timeNs, _conn->GetHardwareTimestampRate());
    metadata.hasTimestamp = (flags & SOAPY_SDR_HAS_TIME) != 0;
    metadata.endOfBurst = (flags & SOAPY_SDR_END_BURST) != 0;
    for(auto i : streamID)
    {
        int status = _conn->ControlStream(i, false);
        if(status != 0)
            return SOAPY_SDR_STREAM_ERROR;
    }
    return 0;
}

/*******************************************************************
 * Stream API
 ******************************************************************/
int SoapyLMS7::readStream(
    SoapySDR::Stream *stream,
    void * const *buffs,
    const size_t numElems,
    int &flags,
    long long &timeNs,
    const long timeoutUs)
{
    auto icstream = (IConnectionStream *)stream;
    auto streamID = icstream->streamID;

    StreamMetadata metadata;
    int status = 0;
    int bufIndex = 0;
    for(auto i : streamID)
    {
        status = _conn->ReadStream(i, buffs[bufIndex++], numElems, timeoutUs/1000, metadata);
        if(status == 0) return SOAPY_SDR_TIMEOUT;
        if(status < 0) return SOAPY_SDR_STREAM_ERROR;
    }
    //output metadata
    flags = 0;
    if (metadata.endOfBurst) flags |= SOAPY_SDR_END_BURST;
    if (metadata.hasTimestamp) flags |= SOAPY_SDR_HAS_TIME;
    timeNs = SoapySDR::ticksToTimeNs(metadata.timestamp, _conn->GetHardwareTimestampRate());
    //return num read or error code
    return (status >= 0) ? status : SOAPY_SDR_STREAM_ERROR;
}

int SoapyLMS7::writeStream(
    SoapySDR::Stream *stream,
    const void * const *buffs,
    const size_t numElems,
    int &flags,
    const long long timeNs,
    const long timeoutUs)
{
    auto icstream = (IConnectionStream *)stream;
    auto streamID = icstream->streamID;

    //input metadata
    StreamMetadata metadata;
    metadata.timestamp = SoapySDR::timeNsToTicks(timeNs, _conn->GetHardwareTimestampRate());
    metadata.hasTimestamp = (flags & SOAPY_SDR_HAS_TIME) != 0;
    metadata.endOfBurst = (flags & SOAPY_SDR_END_BURST) != 0;

    int ret = 0;
    int bufIndex = 0;
    for(auto i : streamID)
    {
        ret = _conn->WriteStream(i, buffs[bufIndex++], numElems, timeoutUs/1000, metadata);
        if(ret == 0) return SOAPY_SDR_TIMEOUT;
        if(ret < 0) return SOAPY_SDR_STREAM_ERROR;
    }

    //return num written or error code
    return (ret > 0)? ret : SOAPY_SDR_STREAM_ERROR;
}

int SoapyLMS7::readStreamStatus(
    SoapySDR::Stream *stream,
    size_t &chanMask,
    int &flags,
    long long &timeNs,
    const long timeoutUs)
{
    auto icstream = (IConnectionStream *)stream;
    auto streamID = icstream->streamID;

    StreamMetadata metadata;
    for(auto i : streamID)
    {
        int ret = _conn->ReadStreamStatus(i, timeoutUs/1000, metadata);
        if (ret != 0)
        {
            //handle the default not implemented case and return not supported
            if (GetLastError() == EPERM) return SOAPY_SDR_NOT_SUPPORTED;
            return SOAPY_SDR_TIMEOUT;
        }
    }

    //output metadata
    flags = 0;
    if (metadata.endOfBurst) flags |= SOAPY_SDR_END_BURST;
    if (metadata.hasTimestamp) flags |= SOAPY_SDR_HAS_TIME;
    timeNs = SoapySDR::ticksToTimeNs(metadata.timestamp, _conn->GetHardwareTimestampRate());

    if (metadata.lateTimestamp) return SOAPY_SDR_TIME_ERROR;
    if (metadata.packetDropped) return SOAPY_SDR_OVERFLOW;
    return 0;
}
<|endoftext|>


<commit_before>//
//  CassandraScene.cpp
//  show
//
//  Created by Chris Mullany on 05/09/2015.
//
//

#include "CassandraScene.h"
using namespace ofxCv;
using namespace cv;

#define DIR_CASSANDRA "recordings/cassandra/"
#define DIR_MAIN "recordings/main/"

#define CASSANDRA_DURATION 120 // Cassandra recording lasts for 2 minutes
#define MAIN_DURATION 300 // main recording lasts for 5 minutes

CassandraScene::CassandraScene() {
    name = "Cassandra";
}

void CassandraScene::setup() {
    // subscenes
    subsceneStart = 77;
    subsceneEnd = 82;
    timer.setup("fonts/Arial Black.ttf", 140);
    timer.colour.set(255);
    SceneBase::setup();
}

void CassandraScene::update() {
    if (isWindow()) {
        if (mode == RECORD_CASSANDRA) {
            auto image = vision->ipcamCassandra.grabber->getFrame();
            if (image->isAllocated() && image->height > 1) {
                stringstream stream;
                stream << DIR_CASSANDRA << setw(10) << setfill('0') << cassandraFileCount << ".jpg";
                string filename = stream.str();
                image->saveImage(filename, OF_IMAGE_QUALITY_HIGH);
                //fileCount++;
                cassandraFileCount++;
            }
        }
        else if (mode == RECORD_MAIN) {
            auto image = vision->ipcam.grabber->getFrame();
            if (image->isAllocated() && image->height > 1) {
                stringstream stream;
                stream << DIR_MAIN << setw(10) << setfill('0') << mainFileCount << ".jpg";
                string filename = stream.str();
                image->saveImage(filename, OF_IMAGE_QUALITY_HIGH);
                //filecount++;
                mainFileCount++;
            }
        }
        timer.update();
    }
    SceneBase::update();
}

void CassandraScene::draw() {
    if (isWindow()) {
        vision->isEnabled = true;
        if (mode == PLAYBACK) {
            playbackTime += ofGetLastFrameTime();

            // draw the image sequences next to each other
            // if only main is drawing, set the scale to fill the screen
            ofTexture& main = sequenceMain.getTextureForTime(playbackTime);
            float scale = ofGetWidth() / main.getWidth();
            float x = 0;
            float y = (ofGetHeight()/2) - (main.getHeight()*scale*0.5);
            // draw cassandra if it's still playing
            if (playbackTime < timerCassandra) {
                ofTexture& cassandra = sequenceCassandra.getTextureForTime(playbackTime);
                scale = (ofGetWidth()/2) / cassandra.getWidth();
                x = cassandra.getWidth()*scale;
                y = (ofGetHeight()/2) - (main.getHeight()*scale*0.5);
                cassandra.draw(0, y, cassandra.getWidth()*scale, cassandra.getHeight()*scale);
            }
            main.draw(x, y, main.getWidth()*scale, main.getHeight()*scale);

            if (sequenceMain.getCurrentFrame() >= sequenceMain.getTotalFrames() - 1 || (playbackTime > timerMain && sequenceMain.getCurrentFrame() < 20)) {
                // sequence is over
                mode == IDLE;
            }

        }

        if (subsceneI == 80) {
            windowTimer += ofGetLastFrameTime();
            int secondsLeft = timerMain - windowTimer;
            if (secondsLeft > 0) {
                int mins = floor(secondsLeft / 60);
                string secs = ofToString( (secondsLeft % 60) );
                if (secs.length() == 1) secs = "0" + secs;
                timer.messageString = ofToString(mins) + ":" + secs;
                timer.maxWidth = ofGetWidth() * 0.9;
                int stringH = timer.getHeight();
                timer.draw(ofGetWidth()/2, ofGetHeight()*.45 - stringH/2);
            }
        }

        if (isDebugMode) {
            if (mode == RECORD_CASSANDRA) {
                auto image = vision->ipcamCassandra.grabber->getFrame();
                image->draw(0, 0);
                ofSetColor(200,0,0);
                ofCircle(ofGetWidth()/2, ofGetHeight()/2, 20);
                ofSetColor(255);
            }
            else if (mode == RECORD_MAIN) {
                vision->ipcam.grabber->getFrame()->draw(0, 0);
                ofSetColor(200,0,0);
                ofCircle(ofGetWidth()/2, ofGetHeight()/2, 20);
                ofSetColor(255);
            }
            else if (mode == PLAYBACK) {
                ofDrawBitmapStringHighlight("playback time: " + ofToString(playbackTime), 10, ofGetHeight()/2);
                ofDrawBitmapStringHighlight("cassandra: " + ofToString(sequenceCassandra.getCurrentFrame()) + "/" + ofToString(sequenceCassandra.getTotalFrames()), 10, ofGetHeight()/2 + 20);
                ofDrawBitmapStringHighlight("main: " + ofToString(sequenceMain.getCurrentFrame()) + "/" + ofToString(sequenceMain.getTotalFrames()), 10, ofGetHeight()/2 + 40);
            }
        }
    }
    SceneBase::draw();
}

//////////////////////////////////////////////////////////////////////////////////
// public
//////////////////////////////////////////////////////////////////////////////////
void CassandraScene::play(int i){
    switch (i) {
        case 77:
            // title, timed
            if (isSlave()) {
                led->show("5. SOMEONE");
            }
            if (isMaster()) {
                countdown->start(timerIntro.get());
                osc->sendSoundCue(soundCueIntro);
            }
            if (isWindow()) setMode(IDLE);
            break;

        case 78:
            // audience name, manual cue
            if (isSlave()) {
                led->show(audience.get());
            }
            if (isMaster()) {
                osc->sendLightingCue(lxCueIntro);
                osc->sendSoundCue(soundCueName);
            }
            if (isWindow()) setMode(IDLE);
            break;

        case 79:
            // welcome, all windows record cassandra room, timed
            if (isSlave()) {
                led->hide();
                led->show("5. " + ofToUpper(audience.get()) + " KNOWS");
                //led->playQueue();
            }
            if (isWindow()) {
                timer.hide();
                setMode(RECORD_CASSANDRA);
            }
            if (isMaster()) {
                countdown->start(timerCassandra.get());
                osc->sendSoundCue(75);
            }
            break;

        case 80:
            // welcome, all windows stop recording cassandra, start recording main room, timed
            if (isSlave()) {
                led->hide();
                //led->queue(LedDisplay::Params(welcome.get(), 1, 5, 1, true)); old replaced with line below
                //led->playQueue();
                //led->show("5. SOMEONE KNOWS");
                led->hide();

            }
            if (isWindow()) {
                windowTimer = 0;
                timer.show("", 1, -1, 1);
                setMode(RECORD_MAIN);
            }
            if (isMaster()) {
                countdown->start(timerMain.get());
                osc->sendSoundCue(soundCueTimePassing);
            }
            break;

        case 81:
            // all windows stop recording main room, playback both videos split screen, timed
            if (isWindow()) {
                timer.hide();
                setMode(PLAYBACK);
            }
            if (isSlave()) {
                led->hide();
                led->queue(LedDisplay::Params("5. SOMEONE KNOWS NOTHING", 0, 1, 5, false, 0));
                led->playQueue();
                //led->show("5. SOMEONE KNOWS NOTHING");
            }
            if (isMaster()) {
                countdown->start(timerMain.get());
                osc->sendSoundCue(soundCuePlayback);
                osc->sendLightingCue(lxCuePlayback);
            }
            break;
        case 82:
            // rabbit angry, etc, timed
            if (isSlave()) {
                led->hide();
                led->queue(LedDisplay::Params(rabbitDisappointed.get(), 0, 2, 0, false));
                led->queue(LedDisplay::Params(rabbitBoss.get(), 0, 1, 0, false, timerOutro.get()));
                led->queue(LedDisplay::Params(boss.get(), 0, 1, 0));
                led->queue(LedDisplay::Params(boss.get(), 0, 1, 0));
                led->queue(LedDisplay::Params(boss.get(), 0, 1, 0));
                led->queue(LedDisplay::Params(boss.get(), 0, 1, 0));
                led->playQueue();
            }
            if (isMaster()) {
                countdown->start(7);
                osc->sendSoundCue(80);
                osc->sendLightingCue(lxCueOutro);
            }
            if (isWindow()) setMode(IDLE);
            break;
        default:
            break;
    }
    SceneBase::play(i);
}

void CassandraScene::stop(){
    // stop/unload/clear things
    SceneBase::stop();
}

void CassandraScene::setupGui() {
    guiName = "Cassandra";
    panel.setup(guiName, "settings/cassandra.xml");

    titleGroup.setName("Titles");
    titleGroup.add(title.set("title1", "5. ALL THINK FIB LENS"));
    titleGroup.add(audience.set("title2", "Clare"));
    titleGroup.add(welcome.set("title3", "Welcome"));
    titleGroup.add(rabbitDisappointed.set("title4", "He is disappointed"));
    titleGroup.add(rabbitBoss.set("title5", "He is pleased"));
    titleGroup.add(boss.set("title6", "He is boss"));

    timerGroup.setName("Timers");
    timerGroup.add(timerIntro.set("intro", 5, 1, 10));
    timerGroup.add(timerCassandra.set("cassandra", 2*60, 1, 10*60));
    timerGroup.add(timerMain.set("main", 5*60, 1, 10*60));
    timerGroup.add(timerOutro.set("outro", 5, 1, 10));
    panel.add(titleGroup);
    panel.add(timerGroup);

    // LX cues
    lxCueGroup.setName("LX Cues");
    lxCueGroup.add(lxCueIntro.set("intro", 34, 0, 100));
    lxCueGroup.add(lxCuePlayback.set("playback", 35, 0, 100));
    lxCueGroup.add(lxCueOutro.set("outro", 0, 0, 100));
    panel.add(lxCueGroup);

    // Sound cues
    soundCueGroup.setName("Sound Cues");
    soundCueGroup.add(soundCueIntro.set("intro", 0, 0, 100));
    soundCueGroup.add(soundCueName.set("name", 0, 0, 100));
    soundCueGroup.add(soundCueCassandra.set("cassandra", 0, 0, 100));
    soundCueGroup.add(soundCueTimePassing.set("time passing", 0, 0, 100));
    soundCueGroup.add(soundCuePlayback.set("playback", 0, 0, 100));
    soundCueGroup.add(soundCueOutro.set("outro", 0, 0, 100));
    panel.add(soundCueGroup);

    panel.loadFromFile("settings/cassandra.xml");
}
//////////////////////////////////////////////////////////////////////////////////
// protected
//////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////
// private
//////////////////////////////////////////////////////////////////////////////////

void CassandraScene::setMode(Mode mode) {
    this->mode = mode;
    if (mode == PLAYBACK) {
        indexCassandra = 0;
        indexMain = 0;
        playbackTime = 0;
        sequenceCassandra.setExtension("jpg");
        sequenceCassandra.loadSequence(DIR_CASSANDRA);
        sequenceCassandra.setFrameRate(cassandraFileCount/CASSANDRA_DURATION);
        sequenceMain.setExtension("jpg");
        sequenceMain.loadSequence(DIR_MAIN);
        sequenceMain.setFrameRate(mainFileCount/MAIN_DURATION);
    }
    else {
        sequenceCassandra.unloadSequence();
        sequenceMain.unloadSequence();
    }
    if (mode == RECORD_CASSANDRA) {
        prepareRecordingDir(DIR_CASSANDRA);
        vision->setToIPCamCassandra();
    }
    else if (mode == RECORD_MAIN) {
        prepareRecordingDir(DIR_MAIN);
        vision->setToIPCamMain();
    }
}

void CassandraScene::prepareRecordingDir(string path) {
    // remove existing recordings
    if (ofDirectory::doesDirectoryExist(path)) {
        ofDirectory::removeDirectory(path, true);
    }
    ofDirectory::createDirectory(path);
    if(path == DIR_CASSANDRA) cassandraFileCount = 0;
    else mainFileCount = 0;
}
//////////////////////////////////////////////////////////////////////////////////
// custom event handlers
//////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////
// oF event handlers
//////////////////////////////////////////////////////////////////////////////////

<commit_msg>Changed cassandra display issue<commit_after>//
//  CassandraScene.cpp
//  show
//
//  Created by Chris Mullany on 05/09/2015.
//
//

#include "CassandraScene.h"
using namespace ofxCv;
using namespace cv;

#define DIR_CASSANDRA "recordings/cassandra/"
#define DIR_MAIN "recordings/main/"

#define CASSANDRA_DURATION 120 // Cassandra recording lasts for 2 minutes
#define MAIN_DURATION 300 // main recording lasts for 5 minutes

CassandraScene::CassandraScene() {
    name = "Cassandra";
}

void CassandraScene::setup() {
    // subscenes
    subsceneStart = 77;
    subsceneEnd = 82;
    timer.setup("fonts/Arial Black.ttf", 140);
    timer.colour.set(255);
    SceneBase::setup();
}

void CassandraScene::update() {
    if (isWindow()) {
        if (mode == RECORD_CASSANDRA) {
            auto image = vision->ipcamCassandra.grabber->getFrame();
            if (image->isAllocated() && image->height > 1) {
                stringstream stream;
                stream << DIR_CASSANDRA << setw(10) << setfill('0') << cassandraFileCount << ".jpg";
                string filename = stream.str();
                image->saveImage(filename, OF_IMAGE_QUALITY_HIGH);
                //fileCount++;
                cassandraFileCount++;
            }
        }
        else if (mode == RECORD_MAIN) {
            auto image = vision->ipcam.grabber->getFrame();
            if (image->isAllocated() && image->height > 1) {
                stringstream stream;
                stream << DIR_MAIN << setw(10) << setfill('0') << mainFileCount << ".jpg";
                string filename = stream.str();
                image->saveImage(filename, OF_IMAGE_QUALITY_HIGH);
                //filecount++;
                mainFileCount++;
            }
        }
        timer.update();
    }
    SceneBase::update();
}

void CassandraScene::draw() {
    if (isWindow()) {
        vision->isEnabled = true;
        if (mode == PLAYBACK) {
            playbackTime += ofGetLastFrameTime();

            // draw the image sequences next to each other
            // if only main is drawing, set the scale to fill the screen
            ofTexture& main = sequenceMain.getTextureForTime(playbackTime);
            float scale = ofGetWidth() / main.getWidth();
            float x = 0;
            float y = (ofGetHeight()/2) - (main.getHeight()*scale*0.5);
            // draw cassandra if it's still playing
            if (playbackTime < timerCassandra) {
                ofTexture& cassandra = sequenceCassandra.getTextureForTime(playbackTime);
                scale = (ofGetWidth()/2) / cassandra.getWidth();
                x = cassandra.getWidth()*scale;
                y = (ofGetHeight()/2) - (main.getHeight()*scale*0.5);
                cassandra.draw(0, y, cassandra.getWidth()*scale, cassandra.getHeight()*scale);
            }
            main.draw(x, y, main.getWidth()*scale, main.getHeight()*scale);

            if (sequenceMain.getCurrentFrame() >= sequenceMain.getTotalFrames() - 1 || (playbackTime > timerMain && sequenceMain.getCurrentFrame() < 20)) {
                // sequence is over
                mode == IDLE;
            }

        }

        if (subsceneI == 80) {
            windowTimer += ofGetLastFrameTime();
            int secondsLeft = timerMain - windowTimer;
            if (secondsLeft > 0) {
                int mins = floor(secondsLeft / 60);
                string secs = ofToString( (secondsLeft % 60) );
                if (secs.length() == 1) secs = "0" + secs;
                timer.messageString = ofToString(mins) + ":" + secs;
                timer.maxWidth = ofGetWidth() * 0.9;
                int stringH = timer.getHeight();
                timer.draw(ofGetWidth()/2, ofGetHeight()*.45 - stringH/2);
            }
        }

        if (isDebugMode) {
            if (mode == RECORD_CASSANDRA) {
                auto image = vision->ipcamCassandra.grabber->getFrame();
                image->draw(0, 0);
                ofSetColor(200,0,0);
                ofCircle(ofGetWidth()/2, ofGetHeight()/2, 20);
                ofSetColor(255);
            }
            else if (mode == RECORD_MAIN) {
                vision->ipcam.grabber->getFrame()->draw(0, 0);
                ofSetColor(200,0,0);
                ofCircle(ofGetWidth()/2, ofGetHeight()/2, 20);
                ofSetColor(255);
            }
            else if (mode == PLAYBACK) {
                ofDrawBitmapStringHighlight("playback time: " + ofToString(playbackTime), 10, ofGetHeight()/2);
                ofDrawBitmapStringHighlight("cassandra: " + ofToString(sequenceCassandra.getCurrentFrame()) + "/" + ofToString(sequenceCassandra.getTotalFrames()), 10, ofGetHeight()/2 + 20);
                ofDrawBitmapStringHighlight("main: " + ofToString(sequenceMain.getCurrentFrame()) + "/" + ofToString(sequenceMain.getTotalFrames()), 10, ofGetHeight()/2 + 40);
            }
        }
    }
    SceneBase::draw();
}

//////////////////////////////////////////////////////////////////////////////////
// public
//////////////////////////////////////////////////////////////////////////////////
void CassandraScene::play(int i){
    switch (i) {
        case 77:
            // title, timed
            if (isSlave()) {
                led->show("5. SOMEONE");
            }
            if (isMaster()) {
                countdown->start(timerIntro.get());
                osc->sendSoundCue(soundCueIntro);
            }
            if (isWindow()) setMode(IDLE);
            break;

        case 78:
            // audience name, manual cue
            if (isSlave()) {
                led->show(audience.get());
            }
            if (isMaster()) {
                osc->sendLightingCue(lxCueIntro);
                osc->sendSoundCue(soundCueName);
            }
            if (isWindow()) setMode(IDLE);
            break;

        case 79:
            // welcome, all windows record cassandra room, timed
            if (isSlave()) {
                led->hide();
                led->show("5. " + ofToUpper(audience.get()) + " KNOWS");
                //led->playQueue();
            }
            if (isWindow()) {
                timer.hide();
                setMode(RECORD_CASSANDRA);
            }
            if (isMaster()) {
                countdown->start(timerCassandra.get());
                osc->sendSoundCue(75);
            }
            break;

        case 80:
            // welcome, all windows stop recording cassandra, start recording main room, timed
            if (isSlave()) {
                led->hide();
                //led->queue(LedDisplay::Params(welcome.get(), 1, 5, 1, true)); old replaced with line below
                //led->playQueue();
                //led->show("5. SOMEONE KNOWS");
            }
            if (isWindow()) {
                windowTimer = 0;
                timer.show("", 1, -1, 1);
                setMode(RECORD_MAIN);
            }
            if (isMaster()) {
                countdown->start(timerMain.get());
                osc->sendSoundCue(soundCueTimePassing);
            }
            break;

        case 81:
            // all windows stop recording main room, playback both videos split screen, timed
            if (isWindow()) {
                timer.hide();
                setMode(PLAYBACK);
            }
            if (isSlave()) {
                led->hide();
                led->queue(LedDisplay::Params("5. SOMEONE KNOWS NOTHING", 0, 1, 5, false, 0));
                led->playQueue();
                //led->show("5. SOMEONE KNOWS NOTHING");
            }
            if (isMaster()) {
                countdown->start(timerMain.get());
                osc->sendSoundCue(soundCuePlayback);
                osc->sendLightingCue(lxCuePlayback);
            }
            break;
        case 82:
            // rabbit angry, etc, timed
            if (isSlave()) {
                led->hide();
                led->queue(LedDisplay::Params(rabbitDisappointed.get(), 0, 2, 0, false));
                led->queue(LedDisplay::Params(rabbitBoss.get(), 0, 1, 0, false, timerOutro.get()));
                led->queue(LedDisplay::Params(boss.get(), 0, 1, 0));
                led->queue(LedDisplay::Params(boss.get(), 0, 1, 0));
                led->queue(LedDisplay::Params(boss.get(), 0, 1, 0));
                led->queue(LedDisplay::Params(boss.get(), 0, 1, 0));
                led->playQueue();
            }
            if (isMaster()) {
                countdown->start(7);
                osc->sendSoundCue(80);
                osc->sendLightingCue(lxCueOutro);
            }
            if (isWindow()) setMode(IDLE);
            break;
        default:
            break;
    }
    SceneBase::play(i);
}

void CassandraScene::stop(){
    // stop/unload/clear things
    SceneBase::stop();
}

void CassandraScene::setupGui() {
    guiName = "Cassandra";
    panel.setup(guiName, "settings/cassandra.xml");

    titleGroup.setName("Titles");
    titleGroup.add(title.set("title1", "5. ALL THINK FIB LENS"));
    titleGroup.add(audience.set("title2", "Clare"));
    titleGroup.add(welcome.set("title3", "Welcome"));
    titleGroup.add(rabbitDisappointed.set("title4", "He is disappointed"));
    titleGroup.add(rabbitBoss.set("title5", "He is pleased"));
    titleGroup.add(boss.set("title6", "He is boss"));

    timerGroup.setName("Timers");
    timerGroup.add(timerIntro.set("intro", 5, 1, 10));
    timerGroup.add(timerCassandra.set("cassandra", 2*60, 1, 10*60));
    timerGroup.add(timerMain.set("main", 5*60, 1, 10*60));
    timerGroup.add(timerOutro.set("outro", 5, 1, 10));
    panel.add(titleGroup);
    panel.add(timerGroup);

    // LX cues
    lxCueGroup.setName("LX Cues");
    lxCueGroup.add(lxCueIntro.set("intro", 34, 0, 100));
    lxCueGroup.add(lxCuePlayback.set("playback", 35, 0, 100));
    lxCueGroup.add(lxCueOutro.set("outro", 0, 0, 100));
    panel.add(lxCueGroup);

    // Sound cues
    soundCueGroup.setName("Sound Cues");
    soundCueGroup.add(soundCueIntro.set("intro", 0, 0, 100));
    soundCueGroup.add(soundCueName.set("name", 0, 0, 100));
    soundCueGroup.add(soundCueCassandra.set("cassandra", 0, 0, 100));
    soundCueGroup.add(soundCueTimePassing.set("time passing", 0, 0, 100));
    soundCueGroup.add(soundCuePlayback.set("playback", 0, 0, 100));
    soundCueGroup.add(soundCueOutro.set("outro", 0, 0, 100));
    panel.add(soundCueGroup);

    panel.loadFromFile("settings/cassandra.xml");
}
//////////////////////////////////////////////////////////////////////////////////
// protected
//////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////
// private
//////////////////////////////////////////////////////////////////////////////////

void CassandraScene::setMode(Mode mode) {
    this->mode = mode;
    if (mode == PLAYBACK) {
        indexCassandra = 0;
        indexMain = 0;
        playbackTime = 0;
        sequenceCassandra.setExtension("jpg");
        sequenceCassandra.loadSequence(DIR_CASSANDRA);
        sequenceCassandra.setFrameRate(cassandraFileCount/CASSANDRA_DURATION);
        sequenceMain.setExtension("jpg");
        sequenceMain.loadSequence(DIR_MAIN);
        sequenceMain.setFrameRate(mainFileCount/MAIN_DURATION);
    }
    else {
        sequenceCassandra.unloadSequence();
        sequenceMain.unloadSequence();
    }
    if (mode == RECORD_CASSANDRA) {
        prepareRecordingDir(DIR_CASSANDRA);
        vision->setToIPCamCassandra();
    }
    else if (mode == RECORD_MAIN) {
        prepareRecordingDir(DIR_MAIN);
        vision->setToIPCamMain();
    }
}

void CassandraScene::prepareRecordingDir(string path) {
    // remove existing recordings
    if (ofDirectory::doesDirectoryExist(path)) {
        ofDirectory::removeDirectory(path, true);
    }
    ofDirectory::createDirectory(path);
    if(path == DIR_CASSANDRA) cassandraFileCount = 0;
    else mainFileCount = 0;
}
//////////////////////////////////////////////////////////////////////////////////
// custom event handlers
//////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////
// oF event handlers
//////////////////////////////////////////////////////////////////////////////////

<|endoftext|>


<commit_before>// Copyright 2012 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <fstream>
#include <vector>
#include <set>
#include <string>
#include <cstring>
#include <cmath>
#include <exception>
#include <H5Cpp.h>
#ifdef HAVE_PSRDADA
#include <dada_hdu.h>
#endif
#include <ascii_header.h>

#include <Observation.hpp>
#include <utils.hpp>

#ifndef READ_DATA_HPP
#define READ_DATA_HPP

namespace AstroData {

// Exception: the PSRDADA ring buffer does not work
class RingBufferError : public std::exception {
public:
  explicit RingBufferError(std::string message);
  ~RingBufferError() throw ();

  const char * what() const throw ();
private:
  std::string message;
};

// Zapped channels (excluded from computation)
void readZappedChannels(Observation & observation, const std::string & inputFileName, std::vector< uint8_t > & zappedChannels);
// Integration steps
void readIntegrationSteps(const Observation & observation, const std::string  & inputFileName, std::set< unsigned int > & integrationSteps);
// SIGPROC data
template< typename T > void readSIGPROC(const Observation & observation, const unsigned int padding, const uint8_t inputBits, const unsigned int bytesToSkip, const std::string & inputFilename, std::vector< std::vector< T > * > & data, const unsigned int firstBatch = 0);
// LOFAR data
template< typename T > void readLOFAR(std::string headerFilename, std::string rawFilename, Observation & observation, const unsigned int padding, std::vector< std::vector< T > * > & data, unsigned int nrBatches = 0, unsigned int firstBatch = 0);
#ifdef HAVE_PSRDADA
// PSRDADA buffer
void readPSRDADAHeader(Observation & observation, dada_hdu_t & ringBuffer) throw(RingBufferError);
template< typename T > inline void readPSRDADA(dada_hdu_t & ringBuffer, std::vector< T > * data) throw(RingBufferError);
#endif

// Implementations

template< typename T > void readSIGPROC(const Observation & observation, const unsigned int padding, const uint8_t inputBits, const unsigned int bytesToSkip, const std::string & inputFilename, std::vector< std::vector< T > * > & data, const unsigned int firstBatch) {
  std::ifstream inputFile;
  const unsigned int BUFFER_DIM = sizeof(T);
  char * buffer = new char [BUFFER_DIM];

  inputFile.open(inputFilename.c_str(), std::ios::binary);
  inputFile.sync_with_stdio(false);
  inputFile.seekg(bytesToSkip, std::ios::beg);
  for ( unsigned int batch = 0; batch < observation.getNrBatches(); batch++ ) {
    if ( inputBits >= 8 ) {
      data.at(batch) = new std::vector< T >(observation.getNrChannels() * observation.getNrSamplesPerPaddedBatch(padding / sizeof(T)));
      for ( unsigned int sample = 0; sample < observation.getNrSamplesPerBatch(); sample++ ) {
        for ( unsigned int channel = observation.getNrChannels(); channel > 0; channel-- ) {
          inputFile.read(buffer, BUFFER_DIM);
          data.at(batch)->at((static_cast< uint64_t >(channel - 1) * observation.getNrSamplesPerPaddedBatch(padding / sizeof(T))) + sample) = *(reinterpret_cast< T * >(buffer));
        }
      }
    } else {
      uint64_t bytesToRead = static_cast< uint64_t >(observation.getNrSamplesPerBatch() * (observation.getNrChannels() / (8.0 / inputBits)));

      data.at(batch) = new std::vector< T >(observation.getNrChannels() * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T)));
      for ( uint64_t byte = 0; byte < bytesToRead; byte++ ) {
        unsigned int channel = (observation.getNrChannels() - 1) - ((byte * (8 / inputBits)) % observation.getNrChannels());
        unsigned int sample = (byte * (8 / inputBits)) / observation.getNrChannels();
        unsigned int sampleByte = sample / (8 / inputBits);
        uint8_t sampleFirstBit = (sample % (8 / inputBits)) * inputBits;

        inputFile.read(buffer, BUFFER_DIM);
        for ( unsigned int item = 0; item < 8 / inputBits; item++ ) {
          uint8_t channelFirstBit = item * inputBits;
          uint8_t sampleBuffer = 0;

          if ( item > channel ) {
            // All channels read, the remaining elements are from the next sample
            unsigned int channelOffset = 0;
            channel = (observation.getNrChannels() - 1);
            sample += 1;
            sampleByte = sample / (8 / inputBits);
            sampleFirstBit = (sample % (8 / inputBits)) * inputBits;

            while ( item < (8 / inputBits) ) {
              channelFirstBit = item * inputBits;
              sampleBuffer = data.at(batch)->at((static_cast< uint64_t >(channel - channelOffset) * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T))) + sampleByte);
              for ( uint8_t bit = 0; bit < inputBits; bit++ ) {
                isa::utils::setBit(sampleBuffer, isa::utils::getBit(*buffer, channelFirstBit + bit), sampleFirstBit + bit);
              }
              data.at(batch)->at((static_cast< uint64_t >(channel - channelOffset) * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T))) + sampleByte) = sampleBuffer;
              item++;
              channelOffset++;
            }

            break;
          }
          sampleBuffer = data.at(batch)->at((static_cast< uint64_t >(channel - item) * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T))) + sampleByte);
          for ( uint8_t bit = 0; bit < inputBits; bit++ ) {
            isa::utils::setBit(sampleBuffer, isa::utils::getBit(*buffer, channelFirstBit + bit), sampleFirstBit + bit);
          }
          data.at(batch)->at((static_cast< uint64_t >(channel - item) * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T))) + sampleByte) = sampleBuffer;
        }
      }
    }
  }
  inputFile.close();

  delete [] buffer;
}

template< typename T > void readLOFAR(std::string headerFilename, std::string rawFilename, Observation & observation, const unsigned int padding, std::vector< std::vector< T > * > & data, unsigned int nrBatches, unsigned int firstBatch) {
  unsigned int nrSubbands, nrChannels;
  float minFreq, channelBandwidth;
  // Read the HDF5 file with the metadata
  H5::H5File headerFile = H5::H5File(headerFilename, H5F_ACC_RDONLY);
  H5::FloatType typeDouble = H5::FloatType(H5::PredType::NATIVE_DOUBLE);
  double valueDouble = 0.0;
  H5::IntType typeUInt = H5::IntType(H5::PredType::NATIVE_UINT);
  unsigned int valueUInt = 0;

  H5::Group currentNode = headerFile.openGroup("/");
  currentNode.openAttribute("OBSERVATION_FREQUENCY_MIN").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  minFreq = valueDouble;
  currentNode = currentNode.openGroup(currentNode.getObjnameByIdx(0));
  currentNode.openAttribute("TOTAL_INTEGRATION_TIME").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  double totalIntegrationTime = valueDouble;
  currentNode.openAttribute("NOF_BEAMS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  observation.setNrBeams(valueUInt);
  currentNode = currentNode.openGroup(currentNode.getObjnameByIdx(0));
  currentNode.openAttribute("NOF_SAMPLES").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  unsigned int totalSamples = valueUInt;
  currentNode.openAttribute("NOF_STATIONS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  observation.setNrStations(valueUInt);
  currentNode.openAttribute("CHANNELS_PER_SUBBAND").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  nrChannels = valueUInt;
  currentNode.openAttribute("CHANNEL_WIDTH").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  channelBandwidth = valueDouble / 1000000;
  H5::DataSet currentData = currentNode.openDataSet("STOKES_0");
  currentData.openAttribute("NOF_SUBBANDS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  nrSubbands = valueUInt;
  headerFile.close();

  observation.setNrSamplesPerBatch(static_cast< unsigned int >(totalSamples / totalIntegrationTime));
  if ( nrBatches == 0 ) {
    observation.setNrBatches(static_cast< unsigned int >(totalIntegrationTime));
  } else {
    if ( static_cast< unsigned int >(totalIntegrationTime) >= (firstBatch + nrBatches) ) {
      observation.setNrBatches(nrBatches);
    } else {
      observation.setNrBatches(static_cast< unsigned int >(totalIntegrationTime) - firstBatch);
    }
  }
  observation.setFrequencyRange(1, nrSubbands * nrChannels, minFreq, channelBandwidth);

  // Read the raw file with the actual data
  std::ifstream rawFile;
  rawFile.open(rawFilename.c_str(), std::ios::binary);
  rawFile.sync_with_stdio(false);
  if ( firstBatch > 0 ) {
    rawFile.seekg(firstBatch * observation.getNrSamplesPerBatch() * nrSubbands * nrChannels, std::ios::beg);
  }
  data.resize(observation.getNrBatches());

  char * word = new char [4];
  for ( unsigned int batch = 0; batch < observation.getNrBatches(); batch++ ) {
    data.at(batch) = new std::vector< T >(observation.getNrChannels() * observation.getNrSamplesPerPaddedBatch(padding / sizeof(T)));
    for ( unsigned int sample = 0; sample < observation.getNrSamplesPerBatch(); sample++ ) {
      for ( unsigned int subband = 0; subband < nrSubbands; subband++ ) {
        for ( unsigned int channel = 0; channel < nrChannels; channel++ ) {
          unsigned int globalChannel = (subband * nrChannels) + channel;

          rawFile.read(word, 4);
          isa::utils::bigEndianToLittleEndian(word);
          data.at(batch)->at((globalChannel * observation.getNrSamplesPerPaddedBatch(padding / sizeof(T))) + sample) = *(reinterpret_cast< T * >(word));
        }
      }
    }
  }
  rawFile.close();
  delete [] word;
}

#ifdef HAVE_PSRDADA
template< typename T > inline void readPSRDADA(dada_hdu_t & ringBuffer, std::vector< T > * data) throw(RingBufferError) {
  char * buffer = 0;
  uint64_t bufferBytes = 0;

  buffer = ipcbuf_get_next_read(reinterpret_cast< ipcbuf_t * >(ringBuffer.data_block), &bufferBytes);
  if ( (buffer == 0) || (bufferBytes == 0) ) {
    throw RingBufferError("Impossible to read the PSRDADA buffer.");
  }
  std::memcpy(reinterpret_cast< void * >(data->data()), reinterpret_cast< const void * >(buffer), data->size() * sizeof(T));
  if ( ipcbuf_mark_cleared(reinterpret_cast< ipcbuf_t * >(ringBuffer.data_block)) < 0 ) {
    throw RingBufferError("Impossible to mark the PSRDADA buffer as cleared.");
  }
}
#endif
} // AstroData

#endif // READ_DATA_HPP

<commit_msg>BUGFIX: make psrdada header file optional<commit_after>// Copyright 2012 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <fstream>
#include <vector>
#include <set>
#include <string>
#include <cstring>
#include <cmath>
#include <exception>
#include <H5Cpp.h>
#ifdef HAVE_PSRDADA
#include <dada_hdu.h>
#include <ascii_header.h>
#endif

#include <Observation.hpp>
#include <utils.hpp>

#ifndef READ_DATA_HPP
#define READ_DATA_HPP

namespace AstroData {

// Exception: the PSRDADA ring buffer does not work
class RingBufferError : public std::exception {
public:
  explicit RingBufferError(std::string message);
  ~RingBufferError() throw ();

  const char * what() const throw ();
private:
  std::string message;
};

// Zapped channels (excluded from computation)
void readZappedChannels(Observation & observation, const std::string & inputFileName, std::vector< uint8_t > & zappedChannels);
// Integration steps
void readIntegrationSteps(const Observation & observation, const std::string  & inputFileName, std::set< unsigned int > & integrationSteps);
// SIGPROC data
template< typename T > void readSIGPROC(const Observation & observation, const unsigned int padding, const uint8_t inputBits, const unsigned int bytesToSkip, const std::string & inputFilename, std::vector< std::vector< T > * > & data, const unsigned int firstBatch = 0);
// LOFAR data
template< typename T > void readLOFAR(std::string headerFilename, std::string rawFilename, Observation & observation, const unsigned int padding, std::vector< std::vector< T > * > & data, unsigned int nrBatches = 0, unsigned int firstBatch = 0);
#ifdef HAVE_PSRDADA
// PSRDADA buffer
void readPSRDADAHeader(Observation & observation, dada_hdu_t & ringBuffer) throw(RingBufferError);
template< typename T > inline void readPSRDADA(dada_hdu_t & ringBuffer, std::vector< T > * data) throw(RingBufferError);
#endif

// Implementations

template< typename T > void readSIGPROC(const Observation & observation, const unsigned int padding, const uint8_t inputBits, const unsigned int bytesToSkip, const std::string & inputFilename, std::vector< std::vector< T > * > & data, const unsigned int firstBatch) {
  std::ifstream inputFile;
  const unsigned int BUFFER_DIM = sizeof(T);
  char * buffer = new char [BUFFER_DIM];

  inputFile.open(inputFilename.c_str(), std::ios::binary);
  inputFile.sync_with_stdio(false);
  inputFile.seekg(bytesToSkip, std::ios::beg);
  for ( unsigned int batch = 0; batch < observation.getNrBatches(); batch++ ) {
    if ( inputBits >= 8 ) {
      data.at(batch) = new std::vector< T >(observation.getNrChannels() * observation.getNrSamplesPerPaddedBatch(padding / sizeof(T)));
      for ( unsigned int sample = 0; sample < observation.getNrSamplesPerBatch(); sample++ ) {
        for ( unsigned int channel = observation.getNrChannels(); channel > 0; channel-- ) {
          inputFile.read(buffer, BUFFER_DIM);
          data.at(batch)->at((static_cast< uint64_t >(channel - 1) * observation.getNrSamplesPerPaddedBatch(padding / sizeof(T))) + sample) = *(reinterpret_cast< T * >(buffer));
        }
      }
    } else {
      uint64_t bytesToRead = static_cast< uint64_t >(observation.getNrSamplesPerBatch() * (observation.getNrChannels() / (8.0 / inputBits)));

      data.at(batch) = new std::vector< T >(observation.getNrChannels() * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T)));
      for ( uint64_t byte = 0; byte < bytesToRead; byte++ ) {
        unsigned int channel = (observation.getNrChannels() - 1) - ((byte * (8 / inputBits)) % observation.getNrChannels());
        unsigned int sample = (byte * (8 / inputBits)) / observation.getNrChannels();
        unsigned int sampleByte = sample / (8 / inputBits);
        uint8_t sampleFirstBit = (sample % (8 / inputBits)) * inputBits;

        inputFile.read(buffer, BUFFER_DIM);
        for ( unsigned int item = 0; item < 8 / inputBits; item++ ) {
          uint8_t channelFirstBit = item * inputBits;
          uint8_t sampleBuffer = 0;

          if ( item > channel ) {
            // All channels read, the remaining elements are from the next sample
            unsigned int channelOffset = 0;
            channel = (observation.getNrChannels() - 1);
            sample += 1;
            sampleByte = sample / (8 / inputBits);
            sampleFirstBit = (sample % (8 / inputBits)) * inputBits;

            while ( item < (8 / inputBits) ) {
              channelFirstBit = item * inputBits;
              sampleBuffer = data.at(batch)->at((static_cast< uint64_t >(channel - channelOffset) * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T))) + sampleByte);
              for ( uint8_t bit = 0; bit < inputBits; bit++ ) {
                isa::utils::setBit(sampleBuffer, isa::utils::getBit(*buffer, channelFirstBit + bit), sampleFirstBit + bit);
              }
              data.at(batch)->at((static_cast< uint64_t >(channel - channelOffset) * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T))) + sampleByte) = sampleBuffer;
              item++;
              channelOffset++;
            }

            break;
          }
          sampleBuffer = data.at(batch)->at((static_cast< uint64_t >(channel - item) * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T))) + sampleByte);
          for ( uint8_t bit = 0; bit < inputBits; bit++ ) {
            isa::utils::setBit(sampleBuffer, isa::utils::getBit(*buffer, channelFirstBit + bit), sampleFirstBit + bit);
          }
          data.at(batch)->at((static_cast< uint64_t >(channel - item) * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T))) + sampleByte) = sampleBuffer;
        }
      }
    }
  }
  inputFile.close();

  delete [] buffer;
}

template< typename T > void readLOFAR(std::string headerFilename, std::string rawFilename, Observation & observation, const unsigned int padding, std::vector< std::vector< T > * > & data, unsigned int nrBatches, unsigned int firstBatch) {
  unsigned int nrSubbands, nrChannels;
  float minFreq, channelBandwidth;
  // Read the HDF5 file with the metadata
  H5::H5File headerFile = H5::H5File(headerFilename, H5F_ACC_RDONLY);
  H5::FloatType typeDouble = H5::FloatType(H5::PredType::NATIVE_DOUBLE);
  double valueDouble = 0.0;
  H5::IntType typeUInt = H5::IntType(H5::PredType::NATIVE_UINT);
  unsigned int valueUInt = 0;

  H5::Group currentNode = headerFile.openGroup("/");
  currentNode.openAttribute("OBSERVATION_FREQUENCY_MIN").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  minFreq = valueDouble;
  currentNode = currentNode.openGroup(currentNode.getObjnameByIdx(0));
  currentNode.openAttribute("TOTAL_INTEGRATION_TIME").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  double totalIntegrationTime = valueDouble;
  currentNode.openAttribute("NOF_BEAMS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  observation.setNrBeams(valueUInt);
  currentNode = currentNode.openGroup(currentNode.getObjnameByIdx(0));
  currentNode.openAttribute("NOF_SAMPLES").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  unsigned int totalSamples = valueUInt;
  currentNode.openAttribute("NOF_STATIONS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  observation.setNrStations(valueUInt);
  currentNode.openAttribute("CHANNELS_PER_SUBBAND").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  nrChannels = valueUInt;
  currentNode.openAttribute("CHANNEL_WIDTH").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  channelBandwidth = valueDouble / 1000000;
  H5::DataSet currentData = currentNode.openDataSet("STOKES_0");
  currentData.openAttribute("NOF_SUBBANDS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  nrSubbands = valueUInt;
  headerFile.close();

  observation.setNrSamplesPerBatch(static_cast< unsigned int >(totalSamples / totalIntegrationTime));
  if ( nrBatches == 0 ) {
    observation.setNrBatches(static_cast< unsigned int >(totalIntegrationTime));
  } else {
    if ( static_cast< unsigned int >(totalIntegrationTime) >= (firstBatch + nrBatches) ) {
      observation.setNrBatches(nrBatches);
    } else {
      observation.setNrBatches(static_cast< unsigned int >(totalIntegrationTime) - firstBatch);
    }
  }
  observation.setFrequencyRange(1, nrSubbands * nrChannels, minFreq, channelBandwidth);

  // Read the raw file with the actual data
  std::ifstream rawFile;
  rawFile.open(rawFilename.c_str(), std::ios::binary);
  rawFile.sync_with_stdio(false);
  if ( firstBatch > 0 ) {
    rawFile.seekg(firstBatch * observation.getNrSamplesPerBatch() * nrSubbands * nrChannels, std::ios::beg);
  }
  data.resize(observation.getNrBatches());

  char * word = new char [4];
  for ( unsigned int batch = 0; batch < observation.getNrBatches(); batch++ ) {
    data.at(batch) = new std::vector< T >(observation.getNrChannels() * observation.getNrSamplesPerPaddedBatch(padding / sizeof(T)));
    for ( unsigned int sample = 0; sample < observation.getNrSamplesPerBatch(); sample++ ) {
      for ( unsigned int subband = 0; subband < nrSubbands; subband++ ) {
        for ( unsigned int channel = 0; channel < nrChannels; channel++ ) {
          unsigned int globalChannel = (subband * nrChannels) + channel;

          rawFile.read(word, 4);
          isa::utils::bigEndianToLittleEndian(word);
          data.at(batch)->at((globalChannel * observation.getNrSamplesPerPaddedBatch(padding / sizeof(T))) + sample) = *(reinterpret_cast< T * >(word));
        }
      }
    }
  }
  rawFile.close();
  delete [] word;
}

#ifdef HAVE_PSRDADA
template< typename T > inline void readPSRDADA(dada_hdu_t & ringBuffer, std::vector< T > * data) throw(RingBufferError) {
  char * buffer = 0;
  uint64_t bufferBytes = 0;

  buffer = ipcbuf_get_next_read(reinterpret_cast< ipcbuf_t * >(ringBuffer.data_block), &bufferBytes);
  if ( (buffer == 0) || (bufferBytes == 0) ) {
    throw RingBufferError("Impossible to read the PSRDADA buffer.");
  }
  std::memcpy(reinterpret_cast< void * >(data->data()), reinterpret_cast< const void * >(buffer), data->size() * sizeof(T));
  if ( ipcbuf_mark_cleared(reinterpret_cast< ipcbuf_t * >(ringBuffer.data_block)) < 0 ) {
    throw RingBufferError("Impossible to mark the PSRDADA buffer as cleared.");
  }
}
#endif
} // AstroData

#endif // READ_DATA_HPP

<|endoftext|>


<commit_before>#ifdef _WIN32
#include <string>
#include <vector>
#include <windows.h>
#include "winargs.h"
#include "winglob.h"

static bool is_unc(const std::wstring &argw) {
	if (argw.length() > 4) {
		return argw[0] == '\\' && argw[1] == '\\' && argw[2] == '?' && argw[3] == '\\';
	}
	return false;
}

// Translate a path into components, i.e. { "C:", "Users", "Me", "Doc*", "*.foo" }
static std::vector<std::wstring> split_components(const std::wstring &argw) {
	std::vector<std::wstring> components;
	if (is_unc(argw)) {
		// This tells us specifically not to perform wildcard expansion.
		components.push_back(argw);
		return components;
	}

	size_t pos = 0;
	while (pos != argw.npos) {
		size_t next = argw.find_first_of(L"/\\", pos);
		if (next == pos) {
			if (pos != 0) {
				// Ignore doubled up slashes, i.e. C:\\Users\\\\Me.
				++pos;
				continue;
			}
			next = argw.find_first_of(L"/\\", pos + 1);
		}

		if (next == argw.npos) {
			components.push_back(argw.substr(pos));
		} else {
			components.push_back(argw.substr(pos, next - pos));
		}
		pos = next;
	}

	return components;
}

static std::wstring find_base_context(std::vector<std::wstring> &components) {
	if (components[0].length() == 2 && components[0][1] == ':') {
		// Is the first thing a drive letter?
		std::wstring context = components[0] + L"\\";
		components.erase(components.begin());
		return context;
	} else if (components[0].length() == 0) {
		components.erase(components.begin());
		return L"\\";
	} else if (components.size() == 1 && is_unc(components[0])) {
		// UNC path, use it as a context directly to avoid any wildcard parsing.
		std::wstring context = components[0];
		components.clear();
		return context;
	}

	return L"";
}

// Expand the wildcard component against each context folder in input, and return the full list.
static std::vector<std::wstring> next_contexts(const std::vector<std::wstring> &input, std::wstring component) {
	std::vector<std::wstring> output;

	// Special case for . or .. as the component.
	if (component == L"." || component == L"..") {
		for (const std::wstring &context : input) {
			std::wstring base = context.empty() ? L"" : (context + L"\\");
			output.push_back(base + component);
		}
		return output;
	}

	for (const std::wstring &context : input) {
		std::wstring base = context.empty() ? L"" : (context + L"\\");
		std::wstring search = base + component;

		WIN32_FIND_DATA data;
		HANDLE finder = FindFirstFile(search.c_str(), &data);
		if (finder == INVALID_HANDLE_VALUE) {
			output.push_back(search);
			continue;
		}
		do {
			std::wstring filename(data.cFileName, wcsnlen(data.cFileName, MAX_PATH));
			if (filename == L"." || filename == L"..") {
				continue;
			}

			output.push_back(base + filename);
		} while (FindNextFile(finder, &data) != 0);
		FindClose(finder);
	}

	return output;
}

void winargs_get_wildcard(const char *arg, std::vector<std::string> &files) {
	std::wstring argw;
	str_to_utf16z(arg, argw);
	if (argw.empty()) {
		return;
	}
	argw.resize(argw.size() - 1);

	// We need to process each component, one at a time.
	std::vector<std::wstring> components = split_components(argw);
	std::vector<std::wstring> contexts;
	contexts.push_back(find_base_context(components));

	for (const std::wstring &component : components) {
		contexts = next_contexts(contexts, component);
	}

	// Now we have all the expanded files, so convert to utf8.
	for (const std::wstring &wfilename : contexts) {
		std::string filename;
		str_to_utf8z(wfilename.c_str(), filename);
		// Now truncate off the null - we don't need it here.
		if (!filename.empty()) {
			filename.resize(filename.size() - 1);
		}
		files.push_back(filename);
	}
}
#endif
<commit_msg>Always use Unicode file finding funcs.<commit_after>#ifdef _WIN32
#include <string>
#include <vector>
#include <windows.h>
#include "winargs.h"
#include "winglob.h"

static bool is_unc(const std::wstring &argw) {
	if (argw.length() > 4) {
		return argw[0] == '\\' && argw[1] == '\\' && argw[2] == '?' && argw[3] == '\\';
	}
	return false;
}

// Translate a path into components, i.e. { "C:", "Users", "Me", "Doc*", "*.foo" }
static std::vector<std::wstring> split_components(const std::wstring &argw) {
	std::vector<std::wstring> components;
	if (is_unc(argw)) {
		// This tells us specifically not to perform wildcard expansion.
		components.push_back(argw);
		return components;
	}

	size_t pos = 0;
	while (pos != argw.npos) {
		size_t next = argw.find_first_of(L"/\\", pos);
		if (next == pos) {
			if (pos != 0) {
				// Ignore doubled up slashes, i.e. C:\\Users\\\\Me.
				++pos;
				continue;
			}
			next = argw.find_first_of(L"/\\", pos + 1);
		}

		if (next == argw.npos) {
			components.push_back(argw.substr(pos));
		} else {
			components.push_back(argw.substr(pos, next - pos));
		}
		pos = next;
	}

	return components;
}

static std::wstring find_base_context(std::vector<std::wstring> &components) {
	if (components[0].length() == 2 && components[0][1] == ':') {
		// Is the first thing a drive letter?
		std::wstring context = components[0] + L"\\";
		components.erase(components.begin());
		return context;
	} else if (components[0].length() == 0) {
		components.erase(components.begin());
		return L"\\";
	} else if (components.size() == 1 && is_unc(components[0])) {
		// UNC path, use it as a context directly to avoid any wildcard parsing.
		std::wstring context = components[0];
		components.clear();
		return context;
	}

	return L"";
}

// Expand the wildcard component against each context folder in input, and return the full list.
static std::vector<std::wstring> next_contexts(const std::vector<std::wstring> &input, std::wstring component) {
	std::vector<std::wstring> output;

	// Special case for . or .. as the component.
	if (component == L"." || component == L"..") {
		for (const std::wstring &context : input) {
			std::wstring base = context.empty() ? L"" : (context + L"\\");
			output.push_back(base + component);
		}
		return output;
	}

	for (const std::wstring &context : input) {
		std::wstring base = context.empty() ? L"" : (context + L"\\");
		std::wstring search = base + component;

		WIN32_FIND_DATAW data;
		HANDLE finder = FindFirstFileW(search.c_str(), &data);
		if (finder == INVALID_HANDLE_VALUE) {
			output.push_back(search);
			continue;
		}
		do {
			std::wstring filename(data.cFileName, wcsnlen(data.cFileName, MAX_PATH));
			if (filename == L"." || filename == L"..") {
				continue;
			}

			output.push_back(base + filename);
		} while (FindNextFileW(finder, &data) != 0);
		FindClose(finder);
	}

	return output;
}

void winargs_get_wildcard(const char *arg, std::vector<std::string> &files) {
	std::wstring argw;
	str_to_utf16z(arg, argw);
	if (argw.empty()) {
		return;
	}
	argw.resize(argw.size() - 1);

	// We need to process each component, one at a time.
	std::vector<std::wstring> components = split_components(argw);
	std::vector<std::wstring> contexts;
	contexts.push_back(find_base_context(components));

	for (const std::wstring &component : components) {
		contexts = next_contexts(contexts, component);
	}

	// Now we have all the expanded files, so convert to utf8.
	for (const std::wstring &wfilename : contexts) {
		std::string filename;
		str_to_utf8z(wfilename.c_str(), filename);
		// Now truncate off the null - we don't need it here.
		if (!filename.empty()) {
			filename.resize(filename.size() - 1);
		}
		files.push_back(filename);
	}
}
#endif
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtLocation module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
** This file is part of the Ovi services plugin for the Maps and
** Navigation API.  The use of these services, whether by use of the
** plugin or by other means, is governed by the terms and conditions
** described by the file OVI_SERVICES_TERMS_AND_CONDITIONS.txt in
** this package, located in the directory containing the Ovi services
** plugin source code.
**
****************************************************************************/

#include "qgeomappingmanagerengine_nokia.h"
#include "qgeomapreply_nokia.h"

#include <qgeotilespec.h>

#include <QNetworkAccessManager>
#include <QNetworkDiskCache>
#include <QNetworkProxy>
#include <QSize>
#include <QDir>
#include <QUrl>
#ifdef USE_CHINA_NETWORK_REGISTRATION
#include <QtSystemInfo/QNetworkInfo>
#endif

#define LARGE_TILE_DIMENSION 256

#define DISK_CACHE_MAX_SIZE 50*1024*1024  //50MB

#if defined(Q_OS_WINCE_WM) || defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)
#undef DISK_CACHE_ENABLED
#else
#define DISK_CACHE_ENABLED 1
#endif

#undef DISK_CACHE_ENABLED

QT_BEGIN_NAMESPACE

const char* MAPTILES_HOST = "1-4.maptile.lbs.ovi.com";
const char* MAPTILES_HOST_CN = "a-k.maptile.maps.svc.nokia.com.cn";

QGeoMappingManagerEngineNokia::QGeoMappingManagerEngineNokia(const QMap<QString, QVariant> &parameters, QGeoServiceProvider::Error *error, QString *errorString)
        : QGeoMappingManagerEngine(parameters),
        m_cache(0),
        m_token(QGeoServiceProviderFactoryNokia::defaultToken),
        m_referer(QGeoServiceProviderFactoryNokia::defaultReferer),
        m_firstSubdomain(QChar::Null),
        m_maxSubdomains(0)
{
    Q_UNUSED(error)
    Q_UNUSED(errorString)

    setHost(MAPTILES_HOST);
    setMinimumZoomLevel(0.0);
    setMaximumZoomLevel(20.0);

#ifdef USE_CHINA_NETWORK_REGISTRATION
    m_networkInfo = 0;
#endif
}

QGeoMappingManagerEngineNokia::~QGeoMappingManagerEngineNokia() {}

void QGeoMappingManagerEngineNokia::init()
{
    setTileSize(256);

    QList<QGeoMapType> types;
    types << QGeoMapType(QGeoMapType::StreetMap,tr("Street Map"),tr("Nokia Street Map"), false, 1);
    types << QGeoMapType(QGeoMapType::SatelliteMapDay,tr("Satellite Map(day)"),tr("Nokia Satellite Map (day)"), false, 2);
    types << QGeoMapType(QGeoMapType::TerrainMap,tr("Terrain Map"),tr("Nokia Terrain Map"), false, 3);
    types << QGeoMapType(QGeoMapType::HybridMap,tr("Hybrid Map"),tr("Nokia Hybrid Map"), false, 4);
    types << QGeoMapType(QGeoMapType::TransitMap,tr("Transit Map"),tr("Nokia Transit Map"), false, 5);
    types << QGeoMapType(QGeoMapType::GrayStreetMap,tr("Gray Street Map"),tr("Nokia Gray Street Map"), false, 6);
    types << QGeoMapType(QGeoMapType::StreetMap,tr("Mobile Street Map"),tr("Nokia Mobile Street Map"), true, 7);
    types << QGeoMapType(QGeoMapType::TerrainMap,tr("Mobile Terrain Map"),tr("Nokia Mobile Terrain Map"), true, 8);
    types << QGeoMapType(QGeoMapType::HybridMap,tr("Mobile Hybrid Map"),tr("Nokia Mobile Hybrid Map"), true, 9);
    types << QGeoMapType(QGeoMapType::TransitMap,tr("Mobile Transit Map"),tr("Nokia Mobile Transit Map"), true, 10);
    types << QGeoMapType(QGeoMapType::GrayStreetMap,tr("Mobile Gray Street Map"),tr("Nokia Mobile Gray Street Map"), true, 11);
    setSupportedMapTypes(types);

//    QList<QGraphicsGeoMap::ConnectivityMode> modes;
//    modes << QGraphicsGeoMap::OnlineMode;
//    setSupportedConnectivityModes(modes);

    m_networkManager = new QNetworkAccessManager(this);

    QMap<QString, QVariant> parameters = this->parameters();

    if (parameters.contains("mapping.proxy")) {
        QString proxy = parameters.value("mapping.proxy").toString();
        if (!proxy.isEmpty()) {
            QUrl proxyUrl(proxy);
            if (proxyUrl.isValid()) {
                m_networkManager->setProxy(QNetworkProxy(QNetworkProxy::HttpProxy,
                    proxyUrl.host(),
                    proxyUrl.port(8080),
                    proxyUrl.userName(),
                    proxyUrl.password()));
            }
        }
    }

    if (parameters.contains("mapping.host")) {
        QString host = parameters.value("mapping.host").toString();
        if (!host.isEmpty())
            setHost(host);
    }

    if (parameters.contains("mapping.referer")) {
        m_referer = parameters.value("mapping.referer").toString();
    }

    if (parameters.contains("mapping.app_id")) {
        m_applicationId = parameters.value("mapping.app_id").toString();
    }
    else if (parameters.contains("app_id")) {
        m_applicationId = parameters.value("app_id").toString();
    }

    if (parameters.contains("mapping.token")) {
        m_token = parameters.value("mapping.token").toString();
    }
    else if (parameters.contains("token")) {
        m_token = parameters.value("token").toString();
    }
#ifdef DISK_CACHE_ENABLED
    QString cacheDir;
    if (parameters.contains("mapping.cache.directory"))
        cacheDir = parameters.value("mapping.cache.directory").toString();

    if (cacheDir.isEmpty()) {
        cacheDir = QDir::temp().path()+"/maptiles";
    }
    if (!cacheDir.isEmpty()) {
        m_cache = new QNetworkDiskCache(this);
        QDir dir;
        dir.mkpath(cacheDir);
        dir.setPath(cacheDir);

        m_cache->setCacheDirectory(dir.path());

        if (parameters.contains("mapping.cache.size")) {
            bool ok = false;
            qint64 cacheSize = parameters.value("mapping.cache.size").toString().toLongLong(&ok);
            if (ok)
                m_cache->setMaximumCacheSize(cacheSize);
        }

        if (m_cache->maximumCacheSize() > DISK_CACHE_MAX_SIZE)
            m_cache->setMaximumCacheSize(DISK_CACHE_MAX_SIZE);

        m_networkManager->setCache(m_cache);
    }
#endif

#ifdef USE_CHINA_NETWORK_REGISTRATION
    m_networkInfo = new QNetworkInfo(this);
    connect(m_networkInfo, SIGNAL(currentMobileCountryCodeChanged(int, const QString&)),
            SLOT(currentMobileCountryCodeChanged(int, const QString&)));
    currentMobileCountryCodeChanged(0, m_networkInfo->currentMobileCountryCode(0));
#endif

    if (!isValidParameter(m_applicationId) || !isValidParameter(m_referer)) {
        qWarning() << "Qt Location requires usage of app_id and token parameters obtained from:";
        qWarning() << "https://api.forum.nokia.com/ovi-api/ui/registration";
    }

    // Temporary testing aid for setting China maptile server
    QFile file("/.enable_china_maptile_server");
    if (file.exists()) {
        qDebug() << "CHINA MAPTILE SERVER SET FOR TESTING PURPOSES.";
        setHost(MAPTILES_HOST_CN);
    }

    QGeoMappingManagerEngine::init();
}

QGeoTiledMapReply* QGeoMappingManagerEngineNokia::getTileImage(const QGeoTileSpec &spec)
{
    // TODO add error detection for if request.connectivityMode() != QGraphicsGeoMap::OnlineMode
    QString rawRequest = getRequestString(spec);

    QNetworkRequest netRequest((QUrl(rawRequest))); // The extra pair of parens disambiguates this from a function declaration
    netRequest.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);

#ifdef DISK_CACHE_ENABLED
    netRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
#endif

    QNetworkReply* netReply = m_networkManager->get(netRequest);

    QGeoTiledMapReply* mapReply = new QGeoMapReplyNokia(netReply, spec);

    // TODO goes badly on linux
    //qDebug() << "request: " << QString::number(reinterpret_cast<int>(mapReply), 16) << " " << request.row() << "," << request.column();
    // this one might work better. It follows defined behaviour, unlike reinterpret_cast
    //qDebug("request: %p %i,%i @ %i", mapReply, request.row(), request.column(), request.zoomLevel());
    return mapReply;
}

QString QGeoMappingManagerEngineNokia::getRequestString(const QGeoTileSpec &spec) const
{
    const char subdomain = m_maxSubdomains ? m_firstSubdomain.toAscii() +
                                             (spec.x() + spec.y()) % m_maxSubdomains : 0;
    static const QString http("http://");
    static const QString path("/maptiler/v2/maptile/newest/");
    static const QChar dot('.');
    static const QChar slash('/');

    QString requestString = http;
    if (subdomain != 0) {
        requestString += subdomain;
        requestString += dot;
    }
    requestString += m_host;
    requestString += path;

    requestString += mapIdToStr(spec.mapId());
    requestString += slash;
    requestString += QString::number(spec.zoom());
    requestString += slash;
    requestString += QString::number(spec.x());
    requestString += slash;
    requestString += QString::number(spec.y());
    requestString += slash;
    requestString += sizeToStr(tileSize());
    static const QString slashpng("/png8");
    requestString += slashpng;

    if (!m_token.isEmpty()) {
        requestString += "?token=";
        requestString += m_token;

        if (!m_referer.isEmpty()) {
            requestString += "&referer=";
            requestString += m_referer;
        }
    } else if (!m_referer.isEmpty()) {
        requestString += "?referer=";
        requestString += m_referer;
    }
    if (!m_applicationId.isEmpty()) {
        requestString += "&app_id=";
        requestString += m_applicationId;
    }
    return requestString;
}

QString QGeoMappingManagerEngineNokia::sizeToStr(int size)
{
    static const QString s256("256");
    static const QString s128("128");
    if (size >= LARGE_TILE_DIMENSION)
        return s256;
    else
        return s128;
}

QString QGeoMappingManagerEngineNokia::mapIdToStr(int mapId)
{
    typedef std::map<int, QString> MapTypeRegistry;
    static MapTypeRegistry registeredTypes;
    if (registeredTypes.empty()) {
        registeredTypes[0] = "normal.day";
        registeredTypes[1] = "normal.day";
        registeredTypes[2] = "satellite.day";
        registeredTypes[3] = "terrain.day";
        registeredTypes[4] = "hybrid.day";
        registeredTypes[5] = "normal.day.transit";
        registeredTypes[6] = "normal.day.grey";
        registeredTypes[7] = "normal.day.mobile";
        registeredTypes[8] = "terrain.day.mobile";
        registeredTypes[9] = "hybrid.day.mobile";
        registeredTypes[10] = "normal.day.transit.mobile";
        registeredTypes[11] = "normal.day.grey.mobile";
    }

    MapTypeRegistry::const_iterator it = registeredTypes.find(mapId);
    if (it != registeredTypes.end()) {
        return it->second;
    }

    qWarning() << "Unknown mapId: " << mapId;
    return "normal.day";
}

const QString & QGeoMappingManagerEngineNokia::referer() const
{
    return m_referer;
}

const QString & QGeoMappingManagerEngineNokia::token() const
{
    return m_token;
}

const QString & QGeoMappingManagerEngineNokia::host() const
{
    return m_host;
}

const QString & QGeoMappingManagerEngineNokia::applicationId() const
{
    return m_applicationId;
}
QChar QGeoMappingManagerEngineNokia::firstSubdomain() const
{
    return m_firstSubdomain;
}

unsigned char QGeoMappingManagerEngineNokia::maxSubdomains() const
{
    return m_maxSubdomains;
}

void QGeoMappingManagerEngineNokia::setHost(const QString &host)
{
    if (host.length() > 4 && host.at(1) == QChar('-') && host.at(3) == QChar('.')) {
        QString realHost = host.right(host.length() - 4);
        m_firstSubdomain = host.at(0);
        m_maxSubdomains = host.at(2).toAscii() - host.at(0).toAscii() + 1;
        m_host = realHost;
    } else {
        m_host = host;
        m_firstSubdomain = QChar::Null;
        m_maxSubdomains = 0;
    }
}

#ifdef USE_CHINA_NETWORK_REGISTRATION
void QGeoMappingManagerEngineNokia::currentMobileCountryCodeChanged(int interface, const QString & mcc)
{
    Q_UNUSED(interface)
    if (mcc == "460" || mcc == "461" || mcc == "454" || mcc == "455") {
        setHost(MAPTILES_HOST_CN);
    }
}
#endif

bool QGeoMappingManagerEngineNokia::isValidParameter(const QString &param)
{
    if (param.isEmpty())
        return false;

    if (param.length() > 512)
        return false;

    foreach (QChar c, param) {
        if (!c.isLetterOrNumber() || c.toAscii() != '%' || c.toAscii() != '-' ||
                c.toAscii() != '+' || c.toAscii() != '_') {
            return false;
        }
    }

    return true;
}

QT_END_NAMESPACE
<commit_msg>Fix warning message for app_id and token.<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtLocation module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
** This file is part of the Ovi services plugin for the Maps and
** Navigation API.  The use of these services, whether by use of the
** plugin or by other means, is governed by the terms and conditions
** described by the file OVI_SERVICES_TERMS_AND_CONDITIONS.txt in
** this package, located in the directory containing the Ovi services
** plugin source code.
**
****************************************************************************/

#include "qgeomappingmanagerengine_nokia.h"
#include "qgeomapreply_nokia.h"

#include <qgeotilespec.h>

#include <QNetworkAccessManager>
#include <QNetworkDiskCache>
#include <QNetworkProxy>
#include <QSize>
#include <QDir>
#include <QUrl>
#ifdef USE_CHINA_NETWORK_REGISTRATION
#include <QtSystemInfo/QNetworkInfo>
#endif

#define LARGE_TILE_DIMENSION 256

#define DISK_CACHE_MAX_SIZE 50*1024*1024  //50MB

#if defined(Q_OS_WINCE_WM) || defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)
#undef DISK_CACHE_ENABLED
#else
#define DISK_CACHE_ENABLED 1
#endif

#undef DISK_CACHE_ENABLED

QT_BEGIN_NAMESPACE

const char* MAPTILES_HOST = "1-4.maptile.lbs.ovi.com";
const char* MAPTILES_HOST_CN = "a-k.maptile.maps.svc.nokia.com.cn";

QGeoMappingManagerEngineNokia::QGeoMappingManagerEngineNokia(const QMap<QString, QVariant> &parameters, QGeoServiceProvider::Error *error, QString *errorString)
        : QGeoMappingManagerEngine(parameters),
        m_cache(0),
        m_token(QGeoServiceProviderFactoryNokia::defaultToken),
        m_referer(QGeoServiceProviderFactoryNokia::defaultReferer),
        m_firstSubdomain(QChar::Null),
        m_maxSubdomains(0)
{
    Q_UNUSED(error)
    Q_UNUSED(errorString)

    setHost(MAPTILES_HOST);
    setMinimumZoomLevel(0.0);
    setMaximumZoomLevel(20.0);

#ifdef USE_CHINA_NETWORK_REGISTRATION
    m_networkInfo = 0;
#endif
}

QGeoMappingManagerEngineNokia::~QGeoMappingManagerEngineNokia() {}

void QGeoMappingManagerEngineNokia::init()
{
    setTileSize(256);

    QList<QGeoMapType> types;
    types << QGeoMapType(QGeoMapType::StreetMap,tr("Street Map"),tr("Nokia Street Map"), false, 1);
    types << QGeoMapType(QGeoMapType::SatelliteMapDay,tr("Satellite Map(day)"),tr("Nokia Satellite Map (day)"), false, 2);
    types << QGeoMapType(QGeoMapType::TerrainMap,tr("Terrain Map"),tr("Nokia Terrain Map"), false, 3);
    types << QGeoMapType(QGeoMapType::HybridMap,tr("Hybrid Map"),tr("Nokia Hybrid Map"), false, 4);
    types << QGeoMapType(QGeoMapType::TransitMap,tr("Transit Map"),tr("Nokia Transit Map"), false, 5);
    types << QGeoMapType(QGeoMapType::GrayStreetMap,tr("Gray Street Map"),tr("Nokia Gray Street Map"), false, 6);
    types << QGeoMapType(QGeoMapType::StreetMap,tr("Mobile Street Map"),tr("Nokia Mobile Street Map"), true, 7);
    types << QGeoMapType(QGeoMapType::TerrainMap,tr("Mobile Terrain Map"),tr("Nokia Mobile Terrain Map"), true, 8);
    types << QGeoMapType(QGeoMapType::HybridMap,tr("Mobile Hybrid Map"),tr("Nokia Mobile Hybrid Map"), true, 9);
    types << QGeoMapType(QGeoMapType::TransitMap,tr("Mobile Transit Map"),tr("Nokia Mobile Transit Map"), true, 10);
    types << QGeoMapType(QGeoMapType::GrayStreetMap,tr("Mobile Gray Street Map"),tr("Nokia Mobile Gray Street Map"), true, 11);
    setSupportedMapTypes(types);

//    QList<QGraphicsGeoMap::ConnectivityMode> modes;
//    modes << QGraphicsGeoMap::OnlineMode;
//    setSupportedConnectivityModes(modes);

    m_networkManager = new QNetworkAccessManager(this);

    QMap<QString, QVariant> parameters = this->parameters();

    if (parameters.contains("mapping.proxy")) {
        QString proxy = parameters.value("mapping.proxy").toString();
        if (!proxy.isEmpty()) {
            QUrl proxyUrl(proxy);
            if (proxyUrl.isValid()) {
                m_networkManager->setProxy(QNetworkProxy(QNetworkProxy::HttpProxy,
                    proxyUrl.host(),
                    proxyUrl.port(8080),
                    proxyUrl.userName(),
                    proxyUrl.password()));
            }
        }
    }

    if (parameters.contains("mapping.host")) {
        QString host = parameters.value("mapping.host").toString();
        if (!host.isEmpty())
            setHost(host);
    }

    if (parameters.contains("mapping.referer")) {
        m_referer = parameters.value("mapping.referer").toString();
    }

    if (parameters.contains("mapping.app_id")) {
        m_applicationId = parameters.value("mapping.app_id").toString();
    }
    else if (parameters.contains("app_id")) {
        m_applicationId = parameters.value("app_id").toString();
    }

    if (parameters.contains("mapping.token")) {
        m_token = parameters.value("mapping.token").toString();
    }
    else if (parameters.contains("token")) {
        m_token = parameters.value("token").toString();
    }
#ifdef DISK_CACHE_ENABLED
    QString cacheDir;
    if (parameters.contains("mapping.cache.directory"))
        cacheDir = parameters.value("mapping.cache.directory").toString();

    if (cacheDir.isEmpty()) {
        cacheDir = QDir::temp().path()+"/maptiles";
    }
    if (!cacheDir.isEmpty()) {
        m_cache = new QNetworkDiskCache(this);
        QDir dir;
        dir.mkpath(cacheDir);
        dir.setPath(cacheDir);

        m_cache->setCacheDirectory(dir.path());

        if (parameters.contains("mapping.cache.size")) {
            bool ok = false;
            qint64 cacheSize = parameters.value("mapping.cache.size").toString().toLongLong(&ok);
            if (ok)
                m_cache->setMaximumCacheSize(cacheSize);
        }

        if (m_cache->maximumCacheSize() > DISK_CACHE_MAX_SIZE)
            m_cache->setMaximumCacheSize(DISK_CACHE_MAX_SIZE);

        m_networkManager->setCache(m_cache);
    }
#endif

#ifdef USE_CHINA_NETWORK_REGISTRATION
    m_networkInfo = new QNetworkInfo(this);
    connect(m_networkInfo, SIGNAL(currentMobileCountryCodeChanged(int, const QString&)),
            SLOT(currentMobileCountryCodeChanged(int, const QString&)));
    currentMobileCountryCodeChanged(0, m_networkInfo->currentMobileCountryCode(0));
#endif

    if (!isValidParameter(m_applicationId) || !isValidParameter(m_token)) {
        qWarning() << "This plug in must have a valid \"app_id\" and \"token\".";
        qWarning() << "These may be obtained from:";
        qWarning() << "https://api.forum.nokia.com/ovi-api/ui/registration";
    }

    // Temporary testing aid for setting China maptile server
    QFile file("/.enable_china_maptile_server");
    if (file.exists()) {
        qDebug() << "CHINA MAPTILE SERVER SET FOR TESTING PURPOSES.";
        setHost(MAPTILES_HOST_CN);
    }

    QGeoMappingManagerEngine::init();
}

QGeoTiledMapReply* QGeoMappingManagerEngineNokia::getTileImage(const QGeoTileSpec &spec)
{
    // TODO add error detection for if request.connectivityMode() != QGraphicsGeoMap::OnlineMode
    QString rawRequest = getRequestString(spec);

    QNetworkRequest netRequest((QUrl(rawRequest))); // The extra pair of parens disambiguates this from a function declaration
    netRequest.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);

#ifdef DISK_CACHE_ENABLED
    netRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
#endif

    QNetworkReply* netReply = m_networkManager->get(netRequest);

    QGeoTiledMapReply* mapReply = new QGeoMapReplyNokia(netReply, spec);

    // TODO goes badly on linux
    //qDebug() << "request: " << QString::number(reinterpret_cast<int>(mapReply), 16) << " " << request.row() << "," << request.column();
    // this one might work better. It follows defined behaviour, unlike reinterpret_cast
    //qDebug("request: %p %i,%i @ %i", mapReply, request.row(), request.column(), request.zoomLevel());
    return mapReply;
}

QString QGeoMappingManagerEngineNokia::getRequestString(const QGeoTileSpec &spec) const
{
    const char subdomain = m_maxSubdomains ? m_firstSubdomain.toAscii() +
                                             (spec.x() + spec.y()) % m_maxSubdomains : 0;
    static const QString http("http://");
    static const QString path("/maptiler/v2/maptile/newest/");
    static const QChar dot('.');
    static const QChar slash('/');

    QString requestString = http;
    if (subdomain != 0) {
        requestString += subdomain;
        requestString += dot;
    }
    requestString += m_host;
    requestString += path;

    requestString += mapIdToStr(spec.mapId());
    requestString += slash;
    requestString += QString::number(spec.zoom());
    requestString += slash;
    requestString += QString::number(spec.x());
    requestString += slash;
    requestString += QString::number(spec.y());
    requestString += slash;
    requestString += sizeToStr(tileSize());
    static const QString slashpng("/png8");
    requestString += slashpng;

    if (!m_token.isEmpty()) {
        requestString += "?token=";
        requestString += m_token;

        if (!m_referer.isEmpty()) {
            requestString += "&referer=";
            requestString += m_referer;
        }
    } else if (!m_referer.isEmpty()) {
        requestString += "?referer=";
        requestString += m_referer;
    }
    if (!m_applicationId.isEmpty()) {
        requestString += "&app_id=";
        requestString += m_applicationId;
    }
    return requestString;
}

QString QGeoMappingManagerEngineNokia::sizeToStr(int size)
{
    static const QString s256("256");
    static const QString s128("128");
    if (size >= LARGE_TILE_DIMENSION)
        return s256;
    else
        return s128;
}

QString QGeoMappingManagerEngineNokia::mapIdToStr(int mapId)
{
    typedef std::map<int, QString> MapTypeRegistry;
    static MapTypeRegistry registeredTypes;
    if (registeredTypes.empty()) {
        registeredTypes[0] = "normal.day";
        registeredTypes[1] = "normal.day";
        registeredTypes[2] = "satellite.day";
        registeredTypes[3] = "terrain.day";
        registeredTypes[4] = "hybrid.day";
        registeredTypes[5] = "normal.day.transit";
        registeredTypes[6] = "normal.day.grey";
        registeredTypes[7] = "normal.day.mobile";
        registeredTypes[8] = "terrain.day.mobile";
        registeredTypes[9] = "hybrid.day.mobile";
        registeredTypes[10] = "normal.day.transit.mobile";
        registeredTypes[11] = "normal.day.grey.mobile";
    }

    MapTypeRegistry::const_iterator it = registeredTypes.find(mapId);
    if (it != registeredTypes.end()) {
        return it->second;
    }

    qWarning() << "Unknown mapId: " << mapId;
    return "normal.day";
}

const QString & QGeoMappingManagerEngineNokia::referer() const
{
    return m_referer;
}

const QString & QGeoMappingManagerEngineNokia::token() const
{
    return m_token;
}

const QString & QGeoMappingManagerEngineNokia::host() const
{
    return m_host;
}

const QString & QGeoMappingManagerEngineNokia::applicationId() const
{
    return m_applicationId;
}
QChar QGeoMappingManagerEngineNokia::firstSubdomain() const
{
    return m_firstSubdomain;
}

unsigned char QGeoMappingManagerEngineNokia::maxSubdomains() const
{
    return m_maxSubdomains;
}

void QGeoMappingManagerEngineNokia::setHost(const QString &host)
{
    if (host.length() > 4 && host.at(1) == QChar('-') && host.at(3) == QChar('.')) {
        QString realHost = host.right(host.length() - 4);
        m_firstSubdomain = host.at(0);
        m_maxSubdomains = host.at(2).toAscii() - host.at(0).toAscii() + 1;
        m_host = realHost;
    } else {
        m_host = host;
        m_firstSubdomain = QChar::Null;
        m_maxSubdomains = 0;
    }
}

#ifdef USE_CHINA_NETWORK_REGISTRATION
void QGeoMappingManagerEngineNokia::currentMobileCountryCodeChanged(int interface, const QString & mcc)
{
    Q_UNUSED(interface)
    if (mcc == "460" || mcc == "461" || mcc == "454" || mcc == "455") {
        setHost(MAPTILES_HOST_CN);
    }
}
#endif

bool QGeoMappingManagerEngineNokia::isValidParameter(const QString &param)
{
    if (param.isEmpty())
        return false;

    if (param.length() > 512)
        return false;

    foreach (QChar c, param) {
        if (!c.isLetterOrNumber() || c.toAscii() != '%' || c.toAscii() != '-' ||
                c.toAscii() != '+' || c.toAscii() != '_') {
            return false;
        }
    }

    return true;
}

QT_END_NAMESPACE
<|endoftext|>