<commit_before>/* DEL1 - split mono source to two channels, delay right channel

      p0 = output start time
      p1 = input start time
      p2 = output duration
      p3 = amplitude multiplier
      p4 = right channel delay time
      p5 = right channel amplitude multiplier (relative to left channel)
      p6 = input channel [optional, default is 0]
      p7 = ring-down duration [optional, default is first delay time value]

   p3 (amplitude), p4 (delay time) and p5 (delay amplitude) can receive
	dynamic updates from a table or real-time control source.

   If an old-style gen table 1 is present, its values will be multiplied
   by the p3 amplitude multiplier, even if the latter is dynamic.

	The point of the ring-down duration parameter is to let you control
	how long the delay will sound after the input has stopped.  If the
	delay time is constant, DEL1 will figure out the correct ring-down
	duration for you.  If the delay time is dynamic, you must specify a
	ring-down duration if you want to ensure that your sound will not be
	cut off prematurely.

                                          rev. for v4.0 by JGG, 7/10/04
*/
#include <stdio.h>
#include <stdlib.h>
#include <ugens.h>
#include <Instrument.h>
#include "DEL1.h"
#include <rt.h>
#include <rtdefs.h>

#define MAXDELTIME 30.0		// seconds (176400 bytes per second at SR=44100

DEL1::DEL1() : Instrument()
{
	delay = NULL;
	in = NULL;
	branch = 0;
	warn_deltime = true;
}

DEL1::~DEL1()
{
	delete [] in;
	delete delay;
}

int DEL1::init(double p[], int n_args)
{
	float outskip = p[0];
	float inskip = p[1];
	float dur = p[2];
	float deltime = p[4];
	inchan = n_args > 6 ? (int) p[6] : 0;
	float ringdur = n_args > 7 ? p[7] : deltime;

	if (rtsetinput(inskip, this) == -1)
		return DONT_SCHEDULE;

	if (inchan >= inputChannels())
		return die("DEL1", "You asked for channel %d of a %d-channel file.",
													inchan, inputChannels());

	if (rtsetoutput(outskip, dur + ringdur, this) == -1)
		return DONT_SCHEDULE;
	insamps = (int) (dur * SR + 0.5);

	if (outputChannels() != 2)
		return die("DEL1", "Output must be stereo.");

	if (deltime > MAXDELTIME)
		return die("DEL1", "Maximum delay time (%g) exceeded.", MAXDELTIME);

	long maxdelsamps = (long) (MAXDELTIME * SR + 0.5);
	delay = new Odelayi(maxdelsamps);
	if (delay == NULL)
		return die("DEL1", "Can't allocate delay line memory.");

	amptable = floc(1);
	if (amptable) {
		int amplen = fsize(1);
		tableset(SR, dur, amplen, amptabs);
	}

	skip = (int) (SR / (float) resetval);

	return nSamps();
}

int DEL1::configure()
{
	in = new float [RTBUFSAMPS * inputChannels()];
	return in ? 0 : -1;
}

int DEL1::run()
{
	int samps = framesToRun() * inputChannels();

	if (currentFrame() < insamps)
		rtgetin(in, this, samps);

	for (int i = 0; i < samps; i += inputChannels())  {
		if (--branch <= 0) {
			double p[6];
			update(p, 6);
			amp = p[3];
			if (amptable)
				amp *= tablei(cursamp, amptable, amptabs);
			float deltime = p[4];
			if (deltime > MAXDELTIME) {
				if (warn_deltime) {
					warn("DEL1", "Maximum delay time (%g) exceeded!", MAXDELTIME);
					warn_deltime = false;
				}
				delsamps = MAXDELTIME * SR;
			}
			else
				delsamps = deltime * SR;
			delamp = p[5];
			branch = skip;
		}

		float sig;
		if (currentFrame() < insamps)
			sig = in[i + inchan];
		else
			sig = 0.0;

		float out[2];
		out[0] = sig * amp;
		out[1] = delay->getsamp(delsamps) * delamp;
		delay->putsamp(sig);

		rtaddout(out);
		increment();
	}
	return framesToRun();
}

Instrument *makeDEL1()
{
	DEL1 *inst;

	inst = new DEL1();
	inst->set_bus_config("DEL1");

	return inst;
}

void
rtprofile()
{
	RT_INTRO("DEL1",makeDEL1);
}

<commit_msg>Updated to use new delay class<commit_after>/* DEL1 - split mono source to two channels, delay right channel

      p0 = output start time
      p1 = input start time
      p2 = output duration
      p3 = amplitude multiplier
      p4 = right channel delay time
      p5 = right channel amplitude multiplier (relative to left channel)
      p6 = input channel [optional, default is 0]
      p7 = ring-down duration [optional, default is first delay time value]

   p3 (amplitude), p4 (delay time) and p5 (delay amplitude) can receive
	dynamic updates from a table or real-time control source.

   If an old-style gen table 1 is present, its values will be multiplied
   by the p3 amplitude multiplier, even if the latter is dynamic.

	The point of the ring-down duration parameter is to let you control
	how long the delay will sound after the input has stopped.  If the
	delay time is constant, DEL1 will figure out the correct ring-down
	duration for you.  If the delay time is dynamic, you must specify a
	ring-down duration if you want to ensure that your sound will not be
	cut off prematurely.

                                          rev. for v4.0 by JGG, 7/10/04
*/
#include <stdio.h>
#include <stdlib.h>
#include <ugens.h>
#include <Instrument.h>
#include "DEL1.h"
#include <rt.h>
#include <rtdefs.h>

#define MAXDELTIME 30.0		// seconds (176400 bytes per second at SR=44100

DEL1::DEL1() : Instrument()
{
	delay = NULL;
	in = NULL;
	branch = 0;
	warn_deltime = true;
}

DEL1::~DEL1()
{
	delete [] in;
	delete delay;
}

int DEL1::init(double p[], int n_args)
{
	float outskip = p[0];
	float inskip = p[1];
	float dur = p[2];
	float deltime = p[4];
	inchan = n_args > 6 ? (int) p[6] : 0;
	float ringdur = n_args > 7 ? p[7] : deltime;

	if (rtsetinput(inskip, this) == -1)
		return DONT_SCHEDULE;

	if (inchan >= inputChannels())
		return die("DEL1", "You asked for channel %d of a %d-channel file.",
													inchan, inputChannels());

	if (rtsetoutput(outskip, dur + ringdur, this) == -1)
		return DONT_SCHEDULE;
	insamps = (int) (dur * SR + 0.5);

	if (outputChannels() != 2)
		return die("DEL1", "Output must be stereo.");

	if (deltime <= 0.0)
		return die("DEL1", "Illegal delay time (%g).", deltime);

	long delsamps = (long) (deltime * SR + 0.5);
	delay = new Odelayi(delsamps);
	if (delay->length() == 0)
		return die("DEL1", "Can't allocate delay line memory.");

	amptable = floc(1);
	if (amptable) {
		int amplen = fsize(1);
		tableset(SR, dur, amplen, amptabs);
	}

	skip = (int) (SR / (float) resetval);

	return nSamps();
}

int DEL1::configure()
{
	in = new float [RTBUFSAMPS * inputChannels()];
	return in ? 0 : -1;
}

int DEL1::run()
{
	int samps = framesToRun() * inputChannels();

	if (currentFrame() < insamps)
		rtgetin(in, this, samps);

	for (int i = 0; i < samps; i += inputChannels())  {
		if (--branch <= 0) {
			double p[6];
			update(p, 6);
			amp = p[3];
			if (amptable)
				amp *= tablei(cursamp, amptable, amptabs);
			float deltime = p[4];
			delsamps = deltime * SR;
			delamp = p[5];
			branch = skip;
		}

		float sig;
		if (currentFrame() < insamps)
			sig = in[i + inchan];
		else
			sig = 0.0;

		float out[2];
		out[0] = sig * amp;
		out[1] = delay->getsamp(delsamps) * delamp;
		delay->putsamp(sig);

		rtaddout(out);
		increment();
	}
	return framesToRun();
}

Instrument *makeDEL1()
{
	DEL1 *inst;

	inst = new DEL1();
	inst->set_bus_config("DEL1");

	return inst;
}

void
rtprofile()
{
	RT_INTRO("DEL1",makeDEL1);
}

<|endoftext|>


<commit_before>#include "engine.hpp"
#include "timevault.hpp"

#include <algorithm>
#include <set>
#include <iomanip>

using namespace std;
using namespace bohrium::core;

namespace bohrium{
namespace engine {
namespace cpu {

typedef std::vector<bh_instruction> instr_iter;
typedef std::vector<bh_ir_kernel>::iterator krnl_iter;

const char Engine::TAG[] = "Engine";

Engine::Engine(
    const thread_binding binding,
    const size_t thread_limit,
    const size_t vcache_size,
    const bool preload,
    const bool jit_enabled,
    const bool jit_dumpsrc,
    const bool jit_fusion,
    const bool jit_contraction,
    const bool jit_offload,
    const string compiler_cmd,
    const string compiler_inc,
    const string compiler_lib,
    const string compiler_flg,
    const string compiler_ext,
    const string object_directory,
    const string template_directory,
    const string kernel_directory
    )
:   vcache_size_(vcache_size),
    preload_(preload),
    jit_enabled_(jit_enabled),
    jit_dumpsrc_(jit_dumpsrc),
    jit_fusion_(jit_fusion),
    jit_contraction_(jit_contraction),
    jit_offload_(jit_offload),
    storage_(object_directory, kernel_directory),
    plaid_(template_directory),
    compiler_(compiler_cmd, compiler_inc, compiler_lib, compiler_flg, compiler_ext),
    thread_control_(binding, thread_limit),
    accelerator_(0, jit_offload),
    exec_count(0)
{
    bh_vcache_init(vcache_size);    // Victim cache
    if (preload_) {                 // Object storage
        storage_.preload();
    }
    thread_control_.bind_threads(); // Thread control

    DEBUG(TAG, text());             // Print the engine configuration
}

Engine::~Engine()
{
    if (vcache_size_>0) {    // De-allocate the malloc-cache
        bh_vcache_clear();
        bh_vcache_delete();
    }
}

string Engine::text()
{
    stringstream ss;
    ss << "Engine {" << endl;
    ss << "  vcache_size = "        << this->vcache_size_ << endl;
    ss << "  preload = "            << this->preload_ << endl;
    ss << "  jit_enabled = "        << this->jit_enabled_ << endl;
    ss << "  jit_dumpsrc = "        << this->jit_dumpsrc_ << endl;
    ss << "  jit_fusion = "         << this->jit_fusion_ << endl;
    ss << "  jit_contraction = "    << this->jit_contraction_ << endl;
    ss << "  jit_offload = "        << this->jit_offload_ << endl;
    ss << "}" << endl;

    ss << thread_control_.text() << endl;
    ss << storage_.text() << endl;
    ss << compiler_.text() << endl;
    ss << plaid_.text() << endl;

    return ss.str();
}

bh_error Engine::execute_block(SymbolTable& symbol_table,
                            std::vector<tac_t>& program,
                            Block& block,
                            bh_ir_kernel& krnl
                            )
{
    bh_error res = BH_SUCCESS;

    bool consider_jit = jit_enabled_ and (block.narray_tacs() > 0);

    //
    // Turn temps into scalars aka array-contraction
    if (consider_jit and jit_contraction_) {
        for (bh_base* base: krnl.get_temps())
        {
            for(size_t operand_idx = 0;
                operand_idx < block.noperands();
                ++operand_idx) {
                if (block.operand(operand_idx).base == base) {
                    symbol_table.turn_contractable(block.local_to_global(operand_idx));
                }
            }
        }
    }

    block.update_iterspace();                       // Update iterspace

    if (!block.symbolize()) {                       // Update block-symbol
        fprintf(stderr, "Engine::execute(...) == Failed creating symbol.\n");
        return BH_ERROR;
    }

    DEBUG(TAG, "EXECUTING "<< block.symbol());

    //
    // JIT-compile the block if enabled
    //
    if (consider_jit && \
        (!storage_.symbol_ready(block.symbol()))) {
        DEBUG(TAG, "JITTING " << block.text());
        // Specialize and dump sourcecode to file
        string sourcecode = codegen::Kernel(plaid_, block).generate_source();
        bool compile_res;
        if (jit_dumpsrc_==1) {
            core::write_file(
                storage_.src_abspath(block.symbol()),
                sourcecode.c_str(),
                sourcecode.size()
            );
            // Send to compiler_
            compile_res = compiler_.compile(
                storage_.obj_abspath(block.symbol()),
                storage_.src_abspath(block.symbol())
            );
        } else {
            // Send to compiler
            compile_res = compiler_.compile(
                storage_.obj_abspath(block.symbol()),
                sourcecode.c_str(),
                sourcecode.size()
            );
        }
        if (!compile_res) {
            fprintf(stderr, "Engine::execute(...) == Compilation failed.\n");

            return BH_ERROR;
        }
        // Inform storage
        storage_.add_symbol(block.symbol(), storage_.obj_filename(block.symbol()));
    }

    //
    // Load the compiled code
    //
    if ((block.narray_tacs() > 0) && \
        (!storage_.symbol_ready(block.symbol())) && \
        (!storage_.load(block.symbol()))) {// Need but cannot load

        fprintf(stderr, "Engine::execute(...) == Failed loading object.\n");
        return BH_ERROR;
    }

    //
    // Allocate memory for output operand(s)
    //
    for(size_t i=0; i<block.ntacs(); ++i) {
        tac_t& tac = block.tac(i);
        operand_t& operand = symbol_table[tac.out];

        if (((tac.op & ARRAY_OPS)>0) and \
            ((operand.layout & (DYNALLOC_LAYOUT))>0)) {
            res = bh_vcache_malloc_base(operand.base);
            if (BH_SUCCESS != res) {
                fprintf(stderr, "Unhandled error returned by bh_vcache_malloc() "
                                "called from bh_ve_cpu_execute()\n");
                return res;
            }
            if (jit_offload_) {
                accelerator_.alloc(operand);
            }
        }
    }

    //
    // Execute block handling array operations.
    //
    if (block.narray_tacs() > 0) {
        TIMER_START
        iterspace_t& iterspace = block.iterspace();   // retrieve iterspace
        storage_.funcs[block.symbol()](block.operands(), &iterspace);
        TIMER_STOP(block.text_compact())
    }

    //
    // De-Allocate memory for operand(s)
    //
    for(size_t i=0; i<block.ntacs(); ++i) {
        tac_t& tac = block.tac(i);
        operand_t& operand = symbol_table[tac.out];

        switch(tac.oper) {
            case FREE:
                if (jit_offload_) {
                    accelerator_.free(operand);
                }
                res = bh_vcache_free_base(operand.base);
                if (BH_SUCCESS != res) {
                    fprintf(stderr, "Unhandled error returned by bh_vcache_free(...) "
                                    "called from bh_ve_cpu_execute)\n");
                    return res;
                }
                break;
            case SYNC:
                if (jit_offload_) {
                    accelerator_.pull(operand);
                }
                break;
            default:
                break;
        }
    }

    return BH_SUCCESS;
}

bh_error Engine::execute(bh_ir* bhir)
{
    exec_count++;
    DEBUG(TAG, "EXEC #" << exec_count);
    bh_error res = BH_SUCCESS;

    //
    // Instantiate the tac-program and symbol-table
    uint64_t program_size = bhir->instr_list.size();
    vector<tac_t> program(program_size);                // Program
    SymbolTable symbol_table(program_size*6+2);         // SymbolTable

    instrs_to_tacs(*bhir, program, symbol_table);       // Map instructions to
                                                        // tac and symbol_table.

    Block block(symbol_table, program);                 // Construct a block

    //
    //  Map bh_kernels to Blocks one at a time and execute them.
    for(krnl_iter krnl = bhir->kernel_list.begin();
        krnl != bhir->kernel_list.end();
        ++krnl) {

        block.clear();                                  // Reset the block
        block.compose(*krnl);                           // Compose it based on kernel

        if ((block.omask() & EXTENSION)>0) {
            tac_t& tac = block.tac(0);
            map<bh_opcode,bh_extmethod_impl>::iterator ext;
            ext = extensions_.find(static_cast<bh_instruction*>(tac.ext)->opcode);
            if (ext != extensions_.end()) {
                bh_extmethod_impl extmethod = ext->second;
                res = extmethod(static_cast<bh_instruction*>(tac.ext), NULL);
                if (BH_SUCCESS != res) {
                    fprintf(stderr, "Unhandled error returned by extmethod(...) \n");
                    return res;
                }
            }
        } else if (jit_fusion_ && \
            (block.narray_tacs() > 1)) {                // FUSE_MODE

            DEBUG(TAG, "FUSE START");
            res = execute_block(symbol_table, program, block, *krnl);
            if (BH_SUCCESS != res) {
                return res;
            }
            DEBUG(TAG, "FUSE END");
        } else {                                        // SIJ_MODE
            DEBUG(TAG, "SIJ START");
            for(std::vector<uint64_t>::iterator idx_it = krnl->instr_indexes.begin();
                idx_it != krnl->instr_indexes.end();
                ++idx_it) {

                block.clear();                          // Reset the block
                block.compose(*idx_it, *idx_it);        // Compose based on one instruction

                // Generate/Load code and execute it
                res = execute_block(symbol_table, program, block, *krnl);
                if (BH_SUCCESS != res) {
                    return res;
                }
            }
            DEBUG(TAG, "SIJ END");
        }
    }
    return res;
}

bh_error Engine::register_extension(bh_component& instance, const char* name, bh_opcode opcode)
{
    bh_extmethod_impl extmethod;
    bh_error err = bh_component_extmethod(&instance, name, &extmethod);
    if (err != BH_SUCCESS) {
        return err;
    }

    if (extensions_.find(opcode) != extensions_.end()) {
        fprintf(stderr, "[CPU-VE] Warning, multiple registrations of the same"
               "extension method '%s' (opcode: %d)\n", name, (int)opcode);
    }
    extensions_[opcode] = extmethod;

    return BH_SUCCESS;
}

}}}
<commit_msg>cpu: Buffer-management for accelerators in runtime.<commit_after>#include "engine.hpp"
#include "timevault.hpp"

#include <algorithm>
#include <set>
#include <iomanip>

using namespace std;
using namespace bohrium::core;

namespace bohrium{
namespace engine {
namespace cpu {

typedef std::vector<bh_instruction> instr_iter;
typedef std::vector<bh_ir_kernel>::iterator krnl_iter;

const char Engine::TAG[] = "Engine";

Engine::Engine(
    const thread_binding binding,
    const size_t thread_limit,
    const size_t vcache_size,
    const bool preload,
    const bool jit_enabled,
    const bool jit_dumpsrc,
    const bool jit_fusion,
    const bool jit_contraction,
    const bool jit_offload,
    const string compiler_cmd,
    const string compiler_inc,
    const string compiler_lib,
    const string compiler_flg,
    const string compiler_ext,
    const string object_directory,
    const string template_directory,
    const string kernel_directory
    )
:   vcache_size_(vcache_size),
    preload_(preload),
    jit_enabled_(jit_enabled),
    jit_dumpsrc_(jit_dumpsrc),
    jit_fusion_(jit_fusion),
    jit_contraction_(jit_contraction),
    jit_offload_(jit_offload),
    storage_(object_directory, kernel_directory),
    plaid_(template_directory),
    compiler_(compiler_cmd, compiler_inc, compiler_lib, compiler_flg, compiler_ext),
    thread_control_(binding, thread_limit),
    accelerator_(0, jit_offload),
    exec_count(0)
{
    bh_vcache_init(vcache_size);    // Victim cache
    if (preload_) {                 // Object storage
        storage_.preload();
    }
    thread_control_.bind_threads(); // Thread control

    DEBUG(TAG, text());             // Print the engine configuration
}

Engine::~Engine()
{
    if (vcache_size_>0) {    // De-allocate the malloc-cache
        bh_vcache_clear();
        bh_vcache_delete();
    }
}

string Engine::text()
{
    stringstream ss;
    ss << "Engine {" << endl;
    ss << "  vcache_size = "        << this->vcache_size_ << endl;
    ss << "  preload = "            << this->preload_ << endl;
    ss << "  jit_enabled = "        << this->jit_enabled_ << endl;
    ss << "  jit_dumpsrc = "        << this->jit_dumpsrc_ << endl;
    ss << "  jit_fusion = "         << this->jit_fusion_ << endl;
    ss << "  jit_contraction = "    << this->jit_contraction_ << endl;
    ss << "  jit_offload = "        << this->jit_offload_ << endl;
    ss << "}" << endl;

    ss << thread_control_.text() << endl;
    ss << storage_.text() << endl;
    ss << compiler_.text() << endl;
    ss << plaid_.text() << endl;

    return ss.str();
}

bh_error Engine::execute_block(SymbolTable& symbol_table,
                            std::vector<tac_t>& program,
                            Block& block,
                            bh_ir_kernel& krnl
                            )
{
    bh_error res = BH_SUCCESS;

    bool consider_jit = jit_enabled_ and (block.narray_tacs() > 0);

    //
    // Turn temps into scalars aka array-contraction
    if (consider_jit and jit_contraction_) {
        for (bh_base* base: krnl.get_temps()) {
            for(size_t operand_idx = 0;
                operand_idx < block.noperands();
                ++operand_idx) {
                if (block.operand(operand_idx).base == base) {
                    symbol_table.turn_contractable(block.local_to_global(operand_idx));
                }
            }
        }
    }

    block.update_iterspace();                       // Update iterspace

    if (!block.symbolize()) {                       // Update block-symbol
        fprintf(stderr, "Engine::execute(...) == Failed creating symbol.\n");
        return BH_ERROR;
    }

    DEBUG(TAG, "EXECUTING "<< block.symbol());

    //
    // JIT-compile: generate source and compile code
    //
    if (consider_jit && \
        (!storage_.symbol_ready(block.symbol()))) {
        DEBUG(TAG, "JITTING " << block.text());

                                                        // Genereate source
        string sourcecode = codegen::Kernel(plaid_, block).generate_source();

        bool compile_res;
        if (jit_dumpsrc_==1) {                          // Compile via file
            core::write_file(                           // Dump to file
                storage_.src_abspath(block.symbol()),
                sourcecode.c_str(),
                sourcecode.size()
            );
            compile_res = compiler_.compile(            // Compile
                storage_.obj_abspath(block.symbol()),
                storage_.src_abspath(block.symbol())
            );
        } else {                                        // Compile via stdin
            compile_res = compiler_.compile(            // Compile
                storage_.obj_abspath(block.symbol()),
                sourcecode.c_str(),
                sourcecode.size()
            );
        }
        if (!compile_res) {
            fprintf(stderr, "Engine::execute(...) == Compilation failed.\n");

            return BH_ERROR;
        }
        storage_.add_symbol(                            // Inform storage
            block.symbol(),
            storage_.obj_filename(block.symbol())
        );
    }

    //
    // Load the compiled code
    //
    if ((block.narray_tacs() > 0) && \
        (!storage_.symbol_ready(block.symbol())) && \
        (!storage_.load(block.symbol()))) {             // Need but cannot load

        fprintf(stderr, "Engine::execute(...) == Failed loading object.\n");
        return BH_ERROR;
    }

    //
    // Buffer Management
    //
    // - allocate output buffer(s) on host
    // - allocate output buffer(s) on accelerator
    // - allocate input buffer(s) on accelerator
    // - push input buffer(s) to accelerator (TODO)
    //
    for(size_t i=0; i<block.ntacs(); ++i) {
        tac_t& tac = block.tac(i);

        if (!((tac.op & ARRAY_OPS)>0)) {
            continue;
        }
        switch(tac_noperands(tac)) {
            case 3:
                if ((symbol_table[tac.in2].layout & (DYNALLOC_LAYOUT))>0) {
                    if (jit_offload_) {
                        accelerator_.alloc(symbol_table[tac.in2]);
                    }
                }
            case 2:
                if ((symbol_table[tac.in1].layout & (DYNALLOC_LAYOUT))>0) {
                    if (jit_offload_) {
                        accelerator_.alloc(symbol_table[tac.in1]);
                    }
                }
            case 1:
                if ((symbol_table[tac.out].layout & (DYNALLOC_LAYOUT))>0) {
                    res = bh_vcache_malloc_base(symbol_table[tac.out].base);
                    if (BH_SUCCESS != res) {
                        fprintf(stderr, "Unhandled error returned by bh_vcache_malloc() "
                                        "called from bh_ve_cpu_execute()\n");
                        return res;
                    }
                    if (jit_offload_) {
                        accelerator_.alloc(symbol_table[tac.out]);
                    }
                }
                break;
        }
    }

    //
    // Execute array operations.
    //
    if (block.narray_tacs() > 0) {
        TIMER_START
        iterspace_t& iterspace = block.iterspace();   // retrieve iterspace
        storage_.funcs[block.symbol()](block.operands(), &iterspace);
        TIMER_STOP(block.text_compact())
    }

    //
    // Buffer Management
    //
    // - free buffer(s) on accelerator
    // - free buffer(s) on host
    // - pull buffer(s) from accelerator to host
    //
    for(size_t i=0; i<block.ntacs(); ++i) {
        tac_t& tac = block.tac(i);
        operand_t& operand = symbol_table[tac.out];

        switch(tac.oper) {

            case SYNC:              // Pull buffer from accelerator to host
                if (jit_offload_) {
                    accelerator_.pull(operand);
                }
                break;

            case DISCARD:           // Free buffer on accelerator
                if (jit_offload_) {
                    accelerator_.free(operand);
                }
                break;

            case FREE:              // NOTE: Isn't BH_FREE redundant?
                if (jit_offload_) {                         // Free buffer on accelerator
                    accelerator_.free(operand);             // Note: must be done prior to
                }                                           //       freeing on host.

                res = bh_vcache_free_base(operand.base);    // Free buffer on host
                if (BH_SUCCESS != res) {
                    fprintf(stderr, "Unhandled error returned by bh_vcache_free(...) "
                                    "called from bh_ve_cpu_execute)\n");
                    return res;
                }
                break;

            default:
                break;
        }
    }

    return BH_SUCCESS;
}

bh_error Engine::execute(bh_ir* bhir)
{
    exec_count++;
    DEBUG(TAG, "EXEC #" << exec_count);
    bh_error res = BH_SUCCESS;

    //
    // Instantiate the tac-program and symbol-table
    uint64_t program_size = bhir->instr_list.size();
    vector<tac_t> program(program_size);                // Program
    SymbolTable symbol_table(program_size*6+2);         // SymbolTable

    instrs_to_tacs(*bhir, program, symbol_table);       // Map instructions to
                                                        // tac and symbol_table.

    Block block(symbol_table, program);                 // Construct a block

    //
    //  Map bh_kernels to Blocks one at a time and execute them.
    for(krnl_iter krnl = bhir->kernel_list.begin();
        krnl != bhir->kernel_list.end();
        ++krnl) {

        block.clear();                                  // Reset the block
        block.compose(*krnl);                           // Compose it based on kernel

        if ((block.omask() & EXTENSION)>0) {
            tac_t& tac = block.tac(0);
            map<bh_opcode,bh_extmethod_impl>::iterator ext;
            ext = extensions_.find(static_cast<bh_instruction*>(tac.ext)->opcode);
            if (ext != extensions_.end()) {
                bh_extmethod_impl extmethod = ext->second;
                res = extmethod(static_cast<bh_instruction*>(tac.ext), NULL);
                if (BH_SUCCESS != res) {
                    fprintf(stderr, "Unhandled error returned by extmethod(...) \n");
                    return res;
                }
            }
        } else if (jit_fusion_ && \
            (block.narray_tacs() > 1)) {                // FUSE_MODE

            DEBUG(TAG, "FUSE START");
            res = execute_block(symbol_table, program, block, *krnl);
            if (BH_SUCCESS != res) {
                return res;
            }
            DEBUG(TAG, "FUSE END");
        } else {                                        // SIJ_MODE
            DEBUG(TAG, "SIJ START");
            for(std::vector<uint64_t>::iterator idx_it = krnl->instr_indexes.begin();
                idx_it != krnl->instr_indexes.end();
                ++idx_it) {

                block.clear();                          // Reset the block
                block.compose(*idx_it, *idx_it);        // Compose based on one instruction

                // Generate/Load code and execute it
                res = execute_block(symbol_table, program, block, *krnl);
                if (BH_SUCCESS != res) {
                    return res;
                }
            }
            DEBUG(TAG, "SIJ END");
        }
    }
    return res;
}

bh_error Engine::register_extension(bh_component& instance, const char* name, bh_opcode opcode)
{
    bh_extmethod_impl extmethod;
    bh_error err = bh_component_extmethod(&instance, name, &extmethod);
    if (err != BH_SUCCESS) {
        return err;
    }

    if (extensions_.find(opcode) != extensions_.end()) {
        fprintf(stderr, "[CPU-VE] Warning, multiple registrations of the same"
               "extension method '%s' (opcode: %d)\n", name, (int)opcode);
    }
    extensions_[opcode] = extmethod;

    return BH_SUCCESS;
}

}}}
<|endoftext|>


<commit_before>#include "PCH.h"
#include "Text.h"

#if ME_EDITOR
#include "imgui.h"
#include "misc/cpp/imgui_stdlib.h"
#endif
#include "Utils/HavanaUtils.h"

void Text::Init()
{
}

void Text::Serialize(json& outJson)
{
}

void Text::Deserialize(const json& inJson)
{
}

#if ME_EDITOR

void Text::OnEditorInspect()
{
	std::string text = SourceText;
	ImGui::InputText("Source Text", &text);
	if (text != SourceText)
	{
		SourceText = text;
		HasChanged = true;
	}
	HavanaUtils::EditableVector("Anchor Position", Anchor);
}

void Text::SetText(const std::string& NewText)
{
	SourceText = NewText;
}

#endif<commit_msg>📲 Build fix Sent from iPhone<commit_after>#include "PCH.h"
#include "Text.h"

#if ME_EDITOR
#include "imgui.h"
#include "misc/cpp/imgui_stdlib.h"
#endif
#include "Utils/HavanaUtils.h"

void Text::Init()
{
}

void Text::Serialize(json& outJson)
{
}

void Text::Deserialize(const json& inJson)
{
}

void Text::SetText(const std::string& NewText)
{
	SourceText = NewText;
}

#if ME_EDITOR

void Text::OnEditorInspect()
{
	std::string text = SourceText;
	ImGui::InputText("Source Text", &text);
	if (text != SourceText)
	{
		SourceText = text;
		HasChanged = true;
	}
	HavanaUtils::EditableVector("Anchor Position", Anchor);
}

#endif
<|endoftext|>


<commit_before>#include "cropeditor.hpp"

#include "cropscene.hpp"
#include "cropview.hpp"
#include <QDebug>
#include <QGraphicsPixmapItem>
#include <QGraphicsView>
#include <QTimer>
#include <settings.hpp>

CropEditor::CropEditor(QPixmap *image, QObject *parent) : QObject(parent) {
    scene = new CropScene(parent, image);
    view = new CropView(scene);
    QPixmap *scaled = new QPixmap();
    image->scaled(view->width(), view->height()).swap(*scaled);
    pixmapItem = new QGraphicsPixmapItem(*image);
    pixmapItem->setZValue(-1);
    scene->addItem(pixmapItem);
    scene->setSceneRect(image->rect());
    view->setGeometry(0, 0, image->width(), image->height());
    view->showFullScreen();

    QTimer::singleShot(0, [&] { view->showFullScreen(); });

    connect(scene, &CropScene::closedWithRect, this, &CropEditor::crop);
}

CropEditor::~CropEditor() {
    delete scene;
}

void CropEditor::crop(QRect rect) {
    QPixmap map = view->grab(rect);
    QPixmap *cropp = new QPixmap;
    map.swap(*cropp);
    delete view;
    emit cropped(cropp);
}
<commit_msg>Ohhhh that's why Retina did not work properly...<commit_after>#include "cropeditor.hpp"

#include "cropscene.hpp"
#include "cropview.hpp"
#include <QDebug>
#include <QGraphicsPixmapItem>
#include <QGraphicsView>
#include <QTimer>
#include <settings.hpp>

CropEditor::CropEditor(QPixmap *image, QObject *parent) : QObject(parent) {
    scene = new CropScene(parent, image);
    view = new CropView(scene);
    QPixmap *scaled = new QPixmap();
    image->scaled(view->width(), view->height()).swap(*scaled);
    pixmapItem = new QGraphicsPixmapItem(*scaled);
    pixmapItem->setZValue(-1);
    scene->addItem(pixmapItem);
    scene->setSceneRect(image->rect());
    view->setGeometry(0, 0, image->width(), image->height());
    view->showFullScreen();

    QTimer::singleShot(0, [&] { view->showFullScreen(); });

    connect(scene, &CropScene::closedWithRect, this, &CropEditor::crop);
}

CropEditor::~CropEditor() {
    delete scene;
}

void CropEditor::crop(QRect rect) {
    QPixmap map = view->grab(rect);
    QPixmap *cropp = new QPixmap;
    map.swap(*cropp);
    delete view;
    emit cropped(cropp);
}
<|endoftext|>


<commit_before>//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//

//
// bench.cpp : spdlog benchmarks
//
#include "spdlog/async_logger.h"
#include "spdlog/sinks/file_sinks.h"
#include "spdlog/sinks/null_sink.h"
#include "spdlog/spdlog.h"
#include "utils.h"
#include <atomic>
#include <cstdlib> // EXIT_FAILURE
#include <iostream>
#include <memory>
#include <string>
#include <thread>

using namespace std;
using namespace std::chrono;
using namespace spdlog;
using namespace spdlog::sinks;
using namespace utils;

void bench(int howmany, std::shared_ptr<spdlog::logger> log);
void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count);

int main(int argc, char *argv[])
{

    int queue_size = 1048576;
    int howmany = 1000000;
    int threads = 10;
    int file_size = 30 * 1024 * 1024;
    int rotating_files = 5;

    try
    {

        if (argc > 1)
            howmany = atoi(argv[1]);
        if (argc > 2)
            threads = atoi(argv[2]);
        if (argc > 3)
            queue_size = atoi(argv[3]);

        cout << "*******************************************************************************\n";
        cout << "Single thread, " << format(howmany) << " iterations" << endl;
        cout << "*******************************************************************************\n";

        auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st.log", file_size, rotating_files);
        bench(howmany, rotating_st);
        auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st.log");
        bench(howmany, daily_st);
        bench(howmany, spdlog::create<null_sink_st>("null_st"));

        cout << "\n*******************************************************************************\n";
        cout << threads << " threads sharing same logger, " << format(howmany) << " iterations" << endl;
        cout << "*******************************************************************************\n";

        auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt.log", file_size, rotating_files);
        bench_mt(howmany, rotating_mt, threads);

        auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt.log");
        bench_mt(howmany, daily_mt, threads);
        bench(howmany, spdlog::create<null_sink_st>("null_mt"));

        cout << "\n*******************************************************************************\n";
        cout << "async logging.. " << threads << " threads sharing same logger, " << format(howmany) << " iterations " << endl;
        cout << "*******************************************************************************\n";

        spdlog::set_async_mode(queue_size);

        for (int i = 0; i < 3; ++i)
        {
            auto as = spdlog::daily_logger_st("as", "logs/daily_async.log");
            bench_mt(howmany, as, threads);
            spdlog::drop("as");
        }
    }
    catch (std::exception &ex)
    {
        std::cerr << "Error: " << ex.what() << std::endl;
        perror("Last error");
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

void bench(int howmany, std::shared_ptr<spdlog::logger> log)
{
    cout << log->name() << "...\t\t" << flush;
    auto start = system_clock::now();
    for (auto i = 0; i < howmany; ++i)
    {
        log->info("Hello logger: msg number {}", i);
    }

    auto delta = system_clock::now() - start;
    auto delta_d = duration_cast<duration<double>>(delta).count();
    cout << format(int(howmany / delta_d)) << "/sec" << endl;
}

void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count)
{

    cout << log->name() << "...\t\t" << flush;
    std::atomic<int> msg_counter{0};
    vector<thread> threads;
    auto start = system_clock::now();
    for (int t = 0; t < thread_count; ++t)
    {
        threads.push_back(std::thread([&]() {
            for (;;)
            {
                int counter = ++msg_counter;
                if (counter > howmany)
                    break;
                log->info("Hello logger: msg number {}", counter);
            }
        }));
    }

    for (auto &t : threads)
    {
        t.join();
    };

    auto delta = system_clock::now() - start;
    auto delta_d = duration_cast<duration<double>>(delta).count();
    cout << format(int(howmany / delta_d)) << "/sec" << endl;
}
<commit_msg>updated bench to show elapsed too<commit_after>//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//

//
// bench.cpp : spdlog benchmarks
//
#include "spdlog/async_logger.h"
#include "spdlog/sinks/file_sinks.h"
#include "spdlog/sinks/null_sink.h"
#include "spdlog/spdlog.h"
#include "utils.h"
#include <atomic>
#include <cstdlib> // EXIT_FAILURE
#include <iostream>
#include <memory>
#include <string>
#include <thread>

using namespace std;
using namespace std::chrono;
using namespace spdlog;
using namespace spdlog::sinks;
using namespace utils;

void bench(int howmany, std::shared_ptr<spdlog::logger> log);
void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count);

int main(int argc, char *argv[])
{

    int queue_size = 1048576;
    int howmany = 1000000;
    int threads = 10;
    int file_size = 30 * 1024 * 1024;
    int rotating_files = 5;

    try
    {

        if (argc > 1)
            howmany = atoi(argv[1]);
        if (argc > 2)
            threads = atoi(argv[2]);
        if (argc > 3)
            queue_size = atoi(argv[3]);

        cout << "*******************************************************************************\n";
        cout << "Single thread, " << format(howmany) << " iterations" << endl;
        cout << "*******************************************************************************\n";

        auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st.log", file_size, rotating_files);
        bench(howmany, rotating_st);
        auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st.log");
        bench(howmany, daily_st);
        bench(howmany, spdlog::create<null_sink_st>("null_st"));

        cout << "\n*******************************************************************************\n";
        cout << threads << " threads sharing same logger, " << format(howmany) << " iterations" << endl;
        cout << "*******************************************************************************\n";

        auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt.log", file_size, rotating_files);
        bench_mt(howmany, rotating_mt, threads);

        auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt.log");
        bench_mt(howmany, daily_mt, threads);
        bench(howmany, spdlog::create<null_sink_st>("null_mt"));

        cout << "\n*******************************************************************************\n";
        cout << "async logging.. " << threads << " threads sharing same logger, " << format(howmany) << " iterations " << endl;
        cout << "*******************************************************************************\n";

        spdlog::set_async_mode(queue_size);

        for (int i = 0; i < 3; ++i)
        {
            auto as = spdlog::daily_logger_st("as", "logs/daily_async.log");
            bench_mt(howmany, as, threads);
            spdlog::drop("as");
        }
    }
    catch (std::exception &ex)
    {
        std::cerr << "Error: " << ex.what() << std::endl;
        perror("Last error");
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

void bench(int howmany, std::shared_ptr<spdlog::logger> log)
{
    cout << log->name() << "...\t\t" << flush;
    auto start = system_clock::now();
    for (auto i = 0; i < howmany; ++i)
    {
        log->info("Hello logger: msg number {}", i);
    }

    auto delta = system_clock::now() - start;
    auto delta_d = duration_cast<duration<double>>(delta).count();
    cout << "Elapsed: " << delta_d << "\t" << format(int(howmany / delta_d)) << "/sec" << endl;
}

void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count)
{

    cout << log->name() << "...\t\t" << flush;
    std::atomic<int> msg_counter{0};
    vector<thread> threads;
    auto start = system_clock::now();
    for (int t = 0; t < thread_count; ++t)
    {
        threads.push_back(std::thread([&]() {
            for (;;)
            {
                int counter = ++msg_counter;
                if (counter > howmany)
                    break;
                log->info("Hello logger: msg number {}", counter);
            }
        }));
    }

    for (auto &t : threads)
    {
        t.join();
    };

    auto delta = system_clock::now() - start;
    auto delta_d = duration_cast<duration<double>>(delta).count();
    cout << "Elapsed: " << delta_d << "\t" << format(int(howmany / delta_d)) << "/sec" << endl;
}
<|endoftext|>


<commit_before>/*
** Copyright 2011 Merethis
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <QScopedPointer>
#include "com/centreon/broker/compression/factory.hh"
#include "com/centreon/broker/compression/opener.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::compression;

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Default constructor.
 */
factory::factory() {}

/**
 *  Copy constructor.
 *
 *  @param[in] f Object to copy.
 */
factory::factory(factory const& f) : io::factory(f) {}

/**
 *  Destructor.
 */
factory::~factory() {}

/**
 *  Assignment operator.
 *
 *  @param[in] f Object to copy.
 *
 *  @return This object.
 */
factory& factory::operator=(factory const& f) {
  io::factory::operator=(f);
  return (*this);
}

/**
 *  Clone this object.
 *
 *  @return A copy of this object.
 */
io::factory* factory::clone() const {
  return (new factory(*this));
}

/**
 *  Check if an endpoint configuration match the compression layer.
 *
 *  @param[in] cfg       Configuration object.
 *  @param[in] is_input  Unused.
 *  @param[in] is_output Unused.
 *
 *  @return true if the configuration matches the compression layer.
 */
bool factory::has_endpoint(config::endpoint const& cfg,
                           bool is_input,
                           bool is_output) const {
  (void)is_input;
  (void)is_output;
  QMap<QString, QString>::const_iterator it(cfg.params.end());
  return ((cfg.params.end() != it)
          && (!it.value().compare("yes", Qt::CaseInsensitive)
              || !it.value().compare("enabled", Qt::CaseInsensitive)
              || it.value().toUInt()));
}

/**
 *  Create an endpoint matching the configuration object.
 *
 *  @param[in] cfg       Configuration object.
 *  @param[in] is_input  true if the endpoint should be an input object.
 *  @param[in] is_output true if the endpoint should be an output
 *                       object.
 *
 *  @return New endpoint object.
 */
io::endpoint* factory::new_endpoint(config::endpoint const& cfg,
                                    bool is_input,
                                    bool is_output,
                                    bool& is_acceptor) const {
  (void)is_input;
  (void)is_output;

  // Get compression level.
  int level(-1);
  QMap<QString, QString>::const_iterator
    it(cfg.params.find("compression_level"));
  if (it != cfg.params.end())
    level = it.value().toInt();

  // Get buffer size.
  unsigned int size(0);
  it = cfg.params.find("compression_buffer");
  if (it != cfg.params.end())
    size = it.value().toUInt();

  // Create compression object.
  QScopedPointer<compression::opener> openr(new compression::opener);
  openr->set_level(level);
  openr->set_size(size);

  return (openr.take());
}
<commit_msg>Fix a compilation warning.<commit_after>/*
** Copyright 2011 Merethis
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <QScopedPointer>
#include "com/centreon/broker/compression/factory.hh"
#include "com/centreon/broker/compression/opener.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::compression;

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Default constructor.
 */
factory::factory() {}

/**
 *  Copy constructor.
 *
 *  @param[in] f Object to copy.
 */
factory::factory(factory const& f) : io::factory(f) {}

/**
 *  Destructor.
 */
factory::~factory() {}

/**
 *  Assignment operator.
 *
 *  @param[in] f Object to copy.
 *
 *  @return This object.
 */
factory& factory::operator=(factory const& f) {
  io::factory::operator=(f);
  return (*this);
}

/**
 *  Clone this object.
 *
 *  @return A copy of this object.
 */
io::factory* factory::clone() const {
  return (new factory(*this));
}

/**
 *  Check if an endpoint configuration match the compression layer.
 *
 *  @param[in] cfg       Configuration object.
 *  @param[in] is_input  Unused.
 *  @param[in] is_output Unused.
 *
 *  @return true if the configuration matches the compression layer.
 */
bool factory::has_endpoint(config::endpoint const& cfg,
                           bool is_input,
                           bool is_output) const {
  (void)is_input;
  (void)is_output;
  QMap<QString, QString>::const_iterator it(cfg.params.end());
  return ((cfg.params.end() != it)
          && (!it.value().compare("yes", Qt::CaseInsensitive)
              || !it.value().compare("enabled", Qt::CaseInsensitive)
              || it.value().toUInt()));
}

/**
 *  Create an endpoint matching the configuration object.
 *
 *  @param[in] cfg       Configuration object.
 *  @param[in] is_input  true if the endpoint should be an input object.
 *  @param[in] is_output true if the endpoint should be an output
 *                       object.
 *
 *  @return New endpoint object.
 */
io::endpoint* factory::new_endpoint(config::endpoint const& cfg,
                                    bool is_input,
                                    bool is_output,
                                    bool& is_acceptor) const {
  (void)is_input;
  (void)is_output;
  (void)is_acceptor;

  // Get compression level.
  int level(-1);
  QMap<QString, QString>::const_iterator
    it(cfg.params.find("compression_level"));
  if (it != cfg.params.end())
    level = it.value().toInt();

  // Get buffer size.
  unsigned int size(0);
  it = cfg.params.find("compression_buffer");
  if (it != cfg.params.end())
    size = it.value().toUInt();

  // Create compression object.
  QScopedPointer<compression::opener> openr(new compression::opener);
  openr->set_level(level);
  openr->set_size(size);

  return (openr.take());
}
<|endoftext|>


<commit_before>#include "Hymn.hpp"

#include "Util/FileSystem.hpp"
#include "Manager/Managers.hpp"
#include "Manager/RenderManager.hpp"
#include "Manager/ResourceManager.hpp"
#include "Manager/PhysicsManager.hpp"
#include "Manager/ParticleManager.hpp"
#include "Manager/ScriptManager.hpp"
#include "Manager/SoundManager.hpp"
#include "Manager/DebugDrawingManager.hpp"
#include "DefaultDiffuse.png.hpp"
#include "DefaultNormal.png.hpp"
#include "DefaultSpecular.png.hpp"
#include "DefaultGlow.png.hpp"
#include "Entity/Entity.hpp"
#include "Geometry/RiggedModel.hpp"
#include "Geometry/StaticModel.hpp"
#include "Texture/Texture2D.hpp"
#include "Audio/SoundBuffer.hpp"
#include <json/json.h>
#include <fstream>
#include "Util/Profiling.hpp"

#include "Component/Animation.hpp"

using namespace std;

ActiveHymn::ActiveHymn() {
    defaultDiffuse = Managers().resourceManager->CreateTexture2D(DEFAULTDIFFUSE_PNG, DEFAULTDIFFUSE_PNG_LENGTH, true);
    defaultNormal = Managers().resourceManager->CreateTexture2D(DEFAULTNORMAL_PNG, DEFAULTNORMAL_PNG_LENGTH);
    defaultSpecular = Managers().resourceManager->CreateTexture2D(DEFAULTSPECULAR_PNG, DEFAULTSPECULAR_PNG_LENGTH);
    defaultGlow = Managers().resourceManager->CreateTexture2D(DEFAULTGLOW_PNG, DEFAULTGLOW_PNG_LENGTH);

    Clear();
}

ActiveHymn& ActiveHymn::GetInstance() {
    static ActiveHymn ActiveHymn;

    return ActiveHymn;
}

void ActiveHymn::Clear() {
    path = "";
    world.Clear();

    entityNumber = 1U;

    for (Geometry::Model* model : models) {
        delete model;
    }
    models.clear();
    modelNumber = 0U;

    for (Texture2D* texture : textures) {
        delete texture;
    }
    textures.clear();
    textureNumber = 0U;

    for (Audio::SoundBuffer* sound : sounds) {
        delete sound;
    }
    sounds.clear();
    soundNumber = 0U;
}

const string& ActiveHymn::GetPath() const {
    return path;
}

void ActiveHymn::SetPath(const string& path) {
    this->path = path;
    FileSystem::CreateDirectory(path.c_str());
    FileSystem::CreateDirectory((path + FileSystem::DELIMITER + "Models").c_str());
    FileSystem::CreateDirectory((path + FileSystem::DELIMITER + "Scripts").c_str());
    FileSystem::CreateDirectory((path + FileSystem::DELIMITER + "Sounds").c_str());
    FileSystem::CreateDirectory((path + FileSystem::DELIMITER + "Textures").c_str());
}

void ActiveHymn::Save() const {
    Json::Value root;

    // Save textures.
    Json::Value texturesNode;
    for (Texture2D* texture : textures) {
        texturesNode.append(texture->Save());
    }
    root["textures"] = texturesNode;

    // Save models.
    Json::Value modelsNode;
    for (Geometry::Model* model : models) {
        modelsNode.append(model->Save());
    }
    root["models"] = modelsNode;

    // Save sounds.
    Json::Value soundsNode;
    for (Audio::SoundBuffer* sound : sounds) {
        soundsNode.append(sound->Save());
    }
    root["sounds"] = soundsNode;

    // Save entities.
    Json::Value entitiesNode;
    for (Entity* entity : world.GetEntities()) {
        entitiesNode.append(entity->Save());
    }
    root["entities"] = entitiesNode;

    // Save to file.
    ofstream file(path + FileSystem::DELIMITER + "Hymn.json");
    file << root;
    file.close();
}

void ActiveHymn::Load(const string& path) {
    Clear();
    this->path = path;

    // Load Json document from file.
    Json::Value root;
    ifstream file(path + FileSystem::DELIMITER + "Hymn.json");
    file >> root;
    file.close();

    // Load textures.
    const Json::Value texturesNode = root["textures"];
    for (unsigned int i=0; i < texturesNode.size(); ++i) {
        Texture2D* texture = new Texture2D();
        texture->Load(texturesNode[i]);
        textures.push_back(texture);
    }

    // Load models.
    const Json::Value modelsNode = root["models"];
    for (unsigned int i=0; i < modelsNode.size(); ++i) {
        Geometry::Model* model;
        std::string type = modelsNode[i].get("type", "").asString();
        if (type == "Static") {
            model = new Geometry::StaticModel();
        } else {
            model = new Geometry::RiggedModel();
        }
        model->Load(modelsNode[i]);
        models.push_back(model);
    }

    // Load sounds.
    const Json::Value soundsNode = root["sounds"];
    for (unsigned int i=0; i < soundsNode.size(); ++i) {
        Audio::SoundBuffer* sound = new Audio::SoundBuffer();
        sound->Load(soundsNode[i]);
        sounds.push_back(sound);
    }

    // Load entities.
    const Json::Value entitiesNode = root["entities"];
    for (unsigned int i=0; i < entitiesNode.size(); ++i) {
        Entity* entity = world.CreateEntity("");
        entity->Load(entitiesNode[i]);
    }
}

void ActiveHymn::Update(float deltaTime) {
    { PROFILE("Run scripts.");
        Managers().scriptManager->Update(world);
    }

    { PROFILE("Update physics");
        Managers().physicsManager->Update(world, deltaTime);
    }

    { PROFILE("Update animations");
        for (Entity* entity : world.GetEntities()) {
            Component::Animation* anim = entity->GetComponent<Component::Animation>();
            if (anim != nullptr) {
                Geometry::RiggedModel* model = anim->riggedModel;
                if (model != nullptr) {
                    if (!model->animations.empty()) {
                        anim->time += deltaTime;
                        model->skeleton.Animate(&model->animations[0], anim->time);
                    }
                }
            }
        }
    }

    { PROFILE("Update particles");
        Managers().particleManager->Update(world, deltaTime);
    }

    { PROFILE("Update sounds");
        Managers().soundManager->Update(world);
    }

    { PROFILE("Update debug drawing");
        Managers().debugDrawingManager->Update(deltaTime);
    }

    { PROFILE("Clear killed entities/components");
        world.ClearKilled();
    }
}

void ActiveHymn::Render(bool soundSources, bool particleEmitters, bool lightSources) {
    { PROFILE("Render world");
        Managers().renderManager->Render(world);
    }

    if (soundSources || particleEmitters || lightSources) {
        { PROFILE("Render editor entities");
            Managers().renderManager->RenderEditorEntities(world, soundSources, particleEmitters, lightSources);
        }
    }

    { PROFILE("Render debug entities");
        Managers().debugDrawingManager->Render(world);
    }
}

ActiveHymn& Hymn() {
    return ActiveHymn::GetInstance();
}
<commit_msg>Create Scenes folder<commit_after>#include "Hymn.hpp"

#include "Util/FileSystem.hpp"
#include "Manager/Managers.hpp"
#include "Manager/RenderManager.hpp"
#include "Manager/ResourceManager.hpp"
#include "Manager/PhysicsManager.hpp"
#include "Manager/ParticleManager.hpp"
#include "Manager/ScriptManager.hpp"
#include "Manager/SoundManager.hpp"
#include "Manager/DebugDrawingManager.hpp"
#include "DefaultDiffuse.png.hpp"
#include "DefaultNormal.png.hpp"
#include "DefaultSpecular.png.hpp"
#include "DefaultGlow.png.hpp"
#include "Entity/Entity.hpp"
#include "Geometry/RiggedModel.hpp"
#include "Geometry/StaticModel.hpp"
#include "Texture/Texture2D.hpp"
#include "Audio/SoundBuffer.hpp"
#include <json/json.h>
#include <fstream>
#include "Util/Profiling.hpp"

#include "Component/Animation.hpp"

using namespace std;

ActiveHymn::ActiveHymn() {
    defaultDiffuse = Managers().resourceManager->CreateTexture2D(DEFAULTDIFFUSE_PNG, DEFAULTDIFFUSE_PNG_LENGTH, true);
    defaultNormal = Managers().resourceManager->CreateTexture2D(DEFAULTNORMAL_PNG, DEFAULTNORMAL_PNG_LENGTH);
    defaultSpecular = Managers().resourceManager->CreateTexture2D(DEFAULTSPECULAR_PNG, DEFAULTSPECULAR_PNG_LENGTH);
    defaultGlow = Managers().resourceManager->CreateTexture2D(DEFAULTGLOW_PNG, DEFAULTGLOW_PNG_LENGTH);

    Clear();
}

ActiveHymn& ActiveHymn::GetInstance() {
    static ActiveHymn ActiveHymn;

    return ActiveHymn;
}

void ActiveHymn::Clear() {
    path = "";
    world.Clear();

    entityNumber = 1U;

    for (Geometry::Model* model : models) {
        delete model;
    }
    models.clear();
    modelNumber = 0U;

    for (Texture2D* texture : textures) {
        delete texture;
    }
    textures.clear();
    textureNumber = 0U;

    for (Audio::SoundBuffer* sound : sounds) {
        delete sound;
    }
    sounds.clear();
    soundNumber = 0U;
}

const string& ActiveHymn::GetPath() const {
    return path;
}

void ActiveHymn::SetPath(const string& path) {
    this->path = path;
    FileSystem::CreateDirectory(path.c_str());
    FileSystem::CreateDirectory((path + FileSystem::DELIMITER + "Models").c_str());
    FileSystem::CreateDirectory((path + FileSystem::DELIMITER + "Scenes").c_str());
    FileSystem::CreateDirectory((path + FileSystem::DELIMITER + "Scripts").c_str());
    FileSystem::CreateDirectory((path + FileSystem::DELIMITER + "Sounds").c_str());
    FileSystem::CreateDirectory((path + FileSystem::DELIMITER + "Textures").c_str());
}

void ActiveHymn::Save() const {
    Json::Value root;

    // Save textures.
    Json::Value texturesNode;
    for (Texture2D* texture : textures) {
        texturesNode.append(texture->Save());
    }
    root["textures"] = texturesNode;

    // Save models.
    Json::Value modelsNode;
    for (Geometry::Model* model : models) {
        modelsNode.append(model->Save());
    }
    root["models"] = modelsNode;

    // Save sounds.
    Json::Value soundsNode;
    for (Audio::SoundBuffer* sound : sounds) {
        soundsNode.append(sound->Save());
    }
    root["sounds"] = soundsNode;

    // Save entities.
    Json::Value entitiesNode;
    for (Entity* entity : world.GetEntities()) {
        entitiesNode.append(entity->Save());
    }
    root["entities"] = entitiesNode;

    // Save to file.
    ofstream file(path + FileSystem::DELIMITER + "Hymn.json");
    file << root;
    file.close();
}

void ActiveHymn::Load(const string& path) {
    Clear();
    this->path = path;

    // Load Json document from file.
    Json::Value root;
    ifstream file(path + FileSystem::DELIMITER + "Hymn.json");
    file >> root;
    file.close();

    // Load textures.
    const Json::Value texturesNode = root["textures"];
    for (unsigned int i=0; i < texturesNode.size(); ++i) {
        Texture2D* texture = new Texture2D();
        texture->Load(texturesNode[i]);
        textures.push_back(texture);
    }

    // Load models.
    const Json::Value modelsNode = root["models"];
    for (unsigned int i=0; i < modelsNode.size(); ++i) {
        Geometry::Model* model;
        std::string type = modelsNode[i].get("type", "").asString();
        if (type == "Static") {
            model = new Geometry::StaticModel();
        } else {
            model = new Geometry::RiggedModel();
        }
        model->Load(modelsNode[i]);
        models.push_back(model);
    }

    // Load sounds.
    const Json::Value soundsNode = root["sounds"];
    for (unsigned int i=0; i < soundsNode.size(); ++i) {
        Audio::SoundBuffer* sound = new Audio::SoundBuffer();
        sound->Load(soundsNode[i]);
        sounds.push_back(sound);
    }

    // Load entities.
    const Json::Value entitiesNode = root["entities"];
    for (unsigned int i=0; i < entitiesNode.size(); ++i) {
        Entity* entity = world.CreateEntity("");
        entity->Load(entitiesNode[i]);
    }
}

void ActiveHymn::Update(float deltaTime) {
    { PROFILE("Run scripts.");
        Managers().scriptManager->Update(world);
    }

    { PROFILE("Update physics");
        Managers().physicsManager->Update(world, deltaTime);
    }

    { PROFILE("Update animations");
        for (Entity* entity : world.GetEntities()) {
            Component::Animation* anim = entity->GetComponent<Component::Animation>();
            if (anim != nullptr) {
                Geometry::RiggedModel* model = anim->riggedModel;
                if (model != nullptr) {
                    if (!model->animations.empty()) {
                        anim->time += deltaTime;
                        model->skeleton.Animate(&model->animations[0], anim->time);
                    }
                }
            }
        }
    }

    { PROFILE("Update particles");
        Managers().particleManager->Update(world, deltaTime);
    }

    { PROFILE("Update sounds");
        Managers().soundManager->Update(world);
    }

    { PROFILE("Update debug drawing");
        Managers().debugDrawingManager->Update(deltaTime);
    }

    { PROFILE("Clear killed entities/components");
        world.ClearKilled();
    }
}

void ActiveHymn::Render(bool soundSources, bool particleEmitters, bool lightSources) {
    { PROFILE("Render world");
        Managers().renderManager->Render(world);
    }

    if (soundSources || particleEmitters || lightSources) {
        { PROFILE("Render editor entities");
            Managers().renderManager->RenderEditorEntities(world, soundSources, particleEmitters, lightSources);
        }
    }

    { PROFILE("Render debug entities");
        Managers().debugDrawingManager->Render(world);
    }
}

ActiveHymn& Hymn() {
    return ActiveHymn::GetInstance();
}
<|endoftext|>


<commit_before>//=================================================================================================
//                    Copyright (C) 2017 Olivier Mallet - All Rights Reserved
//=================================================================================================

#ifndef CONVERTER_HPP
#define CONVERTER_HPP

namespace galgo {

//=================================================================================================

// convert unsigned long long integer to binary string
std::string GetBinary(uint64_t value)
{
   std::bitset<sizeof(uint64_t)*CHAR_BIT> bits(value);
   // NB: CHAR_BIT = number of bits in char usually 8 but not always on older machines
   return bits.to_string<char,std::char_traits<char>,std::allocator<char> >();
}

/*-------------------------------------------------------------------------------------------------*/

// convert binary string to unsigned long long integer
uint64_t GetValue(const std::string& s)
{
   uint64_t value, x = 0;
   for (std::string::const_iterator it = s.begin(), end = s.end(); it != end; ++it) {
      x = (x << 1) + (*it - '0');
   }
   memcpy(&value, &x, sizeof(uint64_t));

   return value;
}

//=================================================================================================

}

#endif
<commit_msg>Delete Converter.hpp<commit_after><|endoftext|>


<commit_before>#include "transmit.h"
#include "config.h"
#include "watchdog.h"
#include <SD.h>

#ifdef TRANSMITTER_WIFI
  AdafruitHTTP http;
  bool wifiConnected = false;
  volatile bool response_received = false;
  volatile bool transmit_success = false;
#endif

#ifdef TRANSMITTER_GSM
  #include <avr/dtostrf.h>

  HardwareSerial *fonaSerial = &Serial1;

  Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
  bool gsmConnected = false;
#endif

#ifdef TRANSMITTER_GSM
  bool fona_post(float temperature_f, float humidity, float heat_index, uint32_t current_time) {
    fona.HTTP_POST_end();

    uint16_t statuscode;
    int16_t length;

    char url[200];
    strcpy(url, CONFIG.data.endpoint_domain);
    strcat(url, CONFIG.data.endpoint_path);

    char data[200];

    char temperature_buffer[10];
    char humidity_buffer[10];
    char heat_index_buffer[10];

    dtostrf(temperature_f, 4, 3, temperature_buffer);
    dtostrf(humidity, 4, 3, humidity_buffer);
    dtostrf(heat_index, 4, 3, heat_index_buffer);

    sprintf(data, "temp=%s&humidity=%s&heat_index=%s&hub=%s&cell=%s&time=%d&sp=%d&cell_version=%s", temperature_buffer, humidity_buffer, heat_index_buffer, CONFIG.data.hub_id, CONFIG.data.cell_id, current_time, CONFIG.data.reading_interval_s, CODE_VERSION);

    Serial.print("posting to: "); Serial.println(url);
    Serial.print("with data: "); Serial.println(data);

    if (!fona.HTTP_POST_start(url, F("application/x-www-form-urlencoded"), (uint8_t *) data, strlen(data), &statuscode, (uint16_t *)&length)) {
      return false;
    }

    Serial.println("reading status");

    if (statuscode != 200) {
      Serial.print("status not 200: ");
      Serial.println(statuscode);
      return false;
    }

    fona.HTTP_POST_end();
    return true;
  }

  void connect_to_fona() {
    Serial.println('starting fona serial');
    fonaSerial->begin(4800);

    Serial.println('starting fona serial 2');
    if (!fona.begin(*fonaSerial)) {
      Serial.println("Couldn't find FONA");
      while(true); // watchdog will reboot
    }

    watchdog_feed();
    delay(2000);

    Serial.println('enabling FONA GPRS');

    uint32_t start = millis();

    while (!fona.enableGPRS(true)) {
      delay(1000);
      watchdog_feed();

      if (millis() - start > 30000) {
        Serial.println("failed to start FONA GPRS after 30 sec");
        while (true);
      }
    }

    Serial.println("Enabled FONA GRPS");

    gsmConnected = true;
  }

  bool _transmit(float temperature_f, float humidity, float heat_index, uint32_t current_time) {
    if (!CONFIG.data.cell_configured || !CONFIG.data.endpoint_configured) {
      Serial.println("cannot send data - not configured");
      return false;
    }

    if (!gsmConnected) connect_to_fona();
    watchdog_feed();

    int transmit_attempts = 1;

    while (!fona_post(temperature_f, humidity, heat_index, current_time)) {
      Serial.print("failed to POST, trying again... attempt #");
      Serial.println(transmit_attempts);

      if (transmit_attempts < 4) {
        transmit_attempts++;
        watchdog_feed();
        delay(500);
      } else {
        while (true);
      }
    }

    return true;
  }
#endif

#ifdef TRANSMITTER_WIFI
  void receive_callback(void) {
    http.respParseHeader();
    int status_received = http.respStatus();

    Serial.printf("transmitted - received status: (%d) \n", status_received);

    http.stop();
    response_received = true;
    transmit_success = (status_received == 200);
  }

  void connect_to_wifi() {
    Serial.print("Please wait while connecting to:");
    Serial.print(CONFIG.data.wifi_ssid);
    Serial.println("... ");

    if (Feather.connect(CONFIG.data.wifi_ssid, CONFIG.data.wifi_pass)) {
      Serial.println("Connected!");
      wifiConnected = true;
    } else {
      Serial.printf("Failed! %s (%d) \n", Feather.errstr());
    }
    Serial.println();

    if (!Feather.connected()) { return; }

    // Connected: Print network info
    Feather.printNetwork();

    // Tell the HTTP client to auto print error codes and halt on errors
    http.err_actions(true, true);

    // Set HTTP client verbose
    http.verbose(true);

    // Set the callback handlers
    http.setReceivedCallback(receive_callback);
  }

  bool _transmit(float temperature_f, float humidity, float heat_index, uint32_t current_time) {
    if (!CONFIG.data.cell_configured || !CONFIG.data.wifi_configured || !CONFIG.data.endpoint_configured) {
      Serial.println("cannot send data - not configured");
      return false;
    }

    while (!wifiConnected) { connect_to_wifi(); }

    http.connect(CONFIG.data.endpoint_domain, PORT); // Will halt if an error occurs

    http.addHeader("User-Agent", USER_AGENT_HEADER);
    http.addHeader("Connection", "close");
    http.addHeader("Content-Type", "application/x-www-form-urlencoded");

    char time_buffer[30];
    char temperature_buffer[30];
    char humidity_buffer[30];
    char heat_index_buffer[30];
    char reading_interval_buffer[30];

    sprintf(time_buffer, "%d", current_time);
    sprintf(reading_interval_buffer, "%d", CONFIG.data.reading_interval_s);
    sprintf(temperature_buffer, "%.3f", temperature_f);
    sprintf(humidity_buffer, "%.3f", humidity);
    sprintf(heat_index_buffer, "%.3f", heat_index);

    const char* post_data[][2] =
    {
      {"hub", CONFIG.data.hub_id},
      {"cell", CONFIG.data.cell_id},
      {"time", time_buffer},
      {"temp", temperature_buffer},
      {"humidity", humidity_buffer},
      {"sp", reading_interval_buffer},
      {"heat_index", heat_index_buffer},
      {"cell_version", CODE_VERSION},
    };
    int param_count = 8;

    response_received = false;
    transmit_success = false;

    http.post(CONFIG.data.endpoint_domain, CONFIG.data.endpoint_path, post_data, param_count); // Will halt if an error occurs

    while (!response_received || !transmit_success); // Hang if transmit doesn't complete or fails

    return true;
  }
#endif

typedef struct {
  float temperature_f;
  float humidity;
  float heat_index;
} temp_data_struct;

typedef union {
  temp_data_struct data;
  uint8_t raw[sizeof(temp_data_struct)];
} temp_data;

// Create a file on the SD card representing a temperature reading
// The file name is the unix timestamp, however, due to FAT naming conventions,
// we have to place a period in it.   e.g.   1500985299   ->  1500985.299
// The content of the file is the binary reading data struct.
void queue_transmission(char *filename, temp_data temp, uint32_t current_time) {
  char file_path[50];
  char timestamp[50];
  char timestamp_first_half[50];
  char timestamp_last_half[50];

  // FAT only allows 8 character names, so we make the last 3 digits of the
  // timestamp the file "extension"
  sprintf(timestamp, "%d", current_time);
  strncpy(timestamp_first_half, timestamp, 7);
  timestamp_first_half[7] = '\0';
  strncpy(timestamp_last_half, timestamp+7, 3);
  timestamp_last_half[3] = '\0';

  sprintf(filename, "%s.%s", timestamp_first_half, timestamp_last_half);
  sprintf(file_path, "pending/%s", filename);

  File temperature_file;
  SD.mkdir("pending");
  if (temperature_file = SD.open(file_path, FILE_WRITE | O_TRUNC)) {
    temperature_file.write(temp.raw, sizeof(temp));
    temperature_file.close();
  } else {
    Serial.println("unable to write temperature");
    while(true); // watchdog will reboot
  }
}

// Take a filename for a reading, read the temperature data and
// transmit it.  Then delete the file when the transfer is successful.
void transmit_queued_temp(char *filename) {
  watchdog_feed();

  File temperature_file;
  temp_data temperature;
  char read_time_buffer[100];
  char file_path[100];
  sprintf(file_path, "pending/%s", filename);

  Serial.print("transfering: ");
  Serial.println(filename);

  strncpy(read_time_buffer, filename, 7);
  strncpy(read_time_buffer+7, filename+8, 3);
  read_time_buffer[10] = '\0';

  uint32_t read_time = strtoul(read_time_buffer, NULL, 0);
  Serial.print("read time buf: ");
  Serial.println(read_time_buffer);
  Serial.print("read time: ");
  Serial.println(read_time);

  if (temperature_file = SD.open(file_path, FILE_READ)) {
    int read_size = temperature_file.read(temperature.raw, sizeof(temperature));

    if (sizeof(temperature) == read_size) {
      bool transmit_success = _transmit(temperature.data.temperature_f, temperature.data.humidity, temperature.data.heat_index, read_time);

      temperature_file.close();
      delay(100);

      if (transmit_success) {
        Serial.println("transferred.");

        if (SD.remove(file_path)) {
          Serial.println("removed.");
        } else {
          Serial.println("failed to remove file");
        }
      } else {
        Serial.println("failed to transfer");
      }
    } else {
      Serial.print("file incorrect size - expected: ");
      Serial.print(sizeof(temperature));
      Serial.print(", got: ");
      Serial.println(read_size);
    }
  } else {
    Serial.print("failed to open: ");
    Serial.println(filename);
  }

  watchdog_feed();
}

void transmit(float temperature_f, float humidity, float heat_index, uint32_t current_time) {
  watchdog_feed();

  temp_data temp;
  temp.data.temperature_f = temperature_f;
  temp.data.humidity = humidity;
  temp.data.heat_index = heat_index;

  char filename[100];
  queue_transmission(filename, temp, current_time);
  watchdog_feed();
  delay(1000);

  Serial.print("created file: ");
  Serial.println(filename);

  transmit_queued_temp(filename);

  File pending_dir = SD.open("pending");
  int temps_transfered_count = 0;

  while (temps_transfered_count < TRANSMITS_PER_LOOP) {
    File entry = pending_dir.openNextFile();
    if (!entry) { break; } // No more files

    strcpy(filename, entry.name());
    entry.close();

    transmit_queued_temp(filename);
    temps_transfered_count += 1;
  }

  pending_dir.close();
}
<commit_msg>remove prints<commit_after>#include "transmit.h"
#include "config.h"
#include "watchdog.h"
#include <SD.h>

#ifdef TRANSMITTER_WIFI
  AdafruitHTTP http;
  bool wifiConnected = false;
  volatile bool response_received = false;
  volatile bool transmit_success = false;
#endif

#ifdef TRANSMITTER_GSM
  #include <avr/dtostrf.h>

  HardwareSerial *fonaSerial = &Serial1;

  Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
  bool gsmConnected = false;
#endif

#ifdef TRANSMITTER_GSM
  bool fona_post(float temperature_f, float humidity, float heat_index, uint32_t current_time) {
    fona.HTTP_POST_end();

    uint16_t statuscode;
    int16_t length;

    char url[200];
    strcpy(url, CONFIG.data.endpoint_domain);
    strcat(url, CONFIG.data.endpoint_path);

    char data[200];

    char temperature_buffer[10];
    char humidity_buffer[10];
    char heat_index_buffer[10];

    dtostrf(temperature_f, 4, 3, temperature_buffer);
    dtostrf(humidity, 4, 3, humidity_buffer);
    dtostrf(heat_index, 4, 3, heat_index_buffer);

    sprintf(data, "temp=%s&humidity=%s&heat_index=%s&hub=%s&cell=%s&time=%d&sp=%d&cell_version=%s", temperature_buffer, humidity_buffer, heat_index_buffer, CONFIG.data.hub_id, CONFIG.data.cell_id, current_time, CONFIG.data.reading_interval_s, CODE_VERSION);

    Serial.print("posting to: "); Serial.println(url);
    Serial.print("with data: "); Serial.println(data);

    if (!fona.HTTP_POST_start(url, F("application/x-www-form-urlencoded"), (uint8_t *) data, strlen(data), &statuscode, (uint16_t *)&length)) {
      return false;
    }

    Serial.println("reading status");

    if (statuscode != 200) {
      Serial.print("status not 200: ");
      Serial.println(statuscode);
      return false;
    }

    fona.HTTP_POST_end();
    return true;
  }

  void connect_to_fona() {
    Serial.println('starting fona serial');
    fonaSerial->begin(4800);

    Serial.println('starting fona serial 2');
    if (!fona.begin(*fonaSerial)) {
      Serial.println("Couldn't find FONA");
      while(true); // watchdog will reboot
    }

    watchdog_feed();
    delay(2000);

    Serial.println('enabling FONA GPRS');

    uint32_t start = millis();

    while (!fona.enableGPRS(true)) {
      delay(1000);
      watchdog_feed();

      if (millis() - start > 30000) {
        Serial.println("failed to start FONA GPRS after 30 sec");
        while (true);
      }
    }

    Serial.println("Enabled FONA GRPS");

    gsmConnected = true;
  }

  bool _transmit(float temperature_f, float humidity, float heat_index, uint32_t current_time) {
    if (!CONFIG.data.cell_configured || !CONFIG.data.endpoint_configured) {
      Serial.println("cannot send data - not configured");
      return false;
    }

    if (!gsmConnected) connect_to_fona();
    watchdog_feed();

    int transmit_attempts = 1;

    while (!fona_post(temperature_f, humidity, heat_index, current_time)) {
      Serial.print("failed to POST, trying again... attempt #");
      Serial.println(transmit_attempts);

      if (transmit_attempts < 4) {
        transmit_attempts++;
        watchdog_feed();
        delay(500);
      } else {
        while (true);
      }
    }

    return true;
  }
#endif

#ifdef TRANSMITTER_WIFI
  void receive_callback(void) {
    http.respParseHeader();
    int status_received = http.respStatus();

    Serial.printf("transmitted - received status: (%d) \n", status_received);

    http.stop();
    response_received = true;
    transmit_success = (status_received == 200);
  }

  void connect_to_wifi() {
    Serial.print("Please wait while connecting to:");
    Serial.print(CONFIG.data.wifi_ssid);
    Serial.println("... ");

    if (Feather.connect(CONFIG.data.wifi_ssid, CONFIG.data.wifi_pass)) {
      Serial.println("Connected!");
      wifiConnected = true;
    } else {
      Serial.printf("Failed! %s (%d) \n", Feather.errstr());
    }
    Serial.println();

    if (!Feather.connected()) { return; }

    // Connected: Print network info
    Feather.printNetwork();

    // Tell the HTTP client to auto print error codes and halt on errors
    http.err_actions(true, true);

    // Set HTTP client verbose
    http.verbose(true);

    // Set the callback handlers
    http.setReceivedCallback(receive_callback);
  }

  bool _transmit(float temperature_f, float humidity, float heat_index, uint32_t current_time) {
    if (!CONFIG.data.cell_configured || !CONFIG.data.wifi_configured || !CONFIG.data.endpoint_configured) {
      Serial.println("cannot send data - not configured");
      return false;
    }

    while (!wifiConnected) { connect_to_wifi(); }

    http.connect(CONFIG.data.endpoint_domain, PORT); // Will halt if an error occurs

    http.addHeader("User-Agent", USER_AGENT_HEADER);
    http.addHeader("Connection", "close");
    http.addHeader("Content-Type", "application/x-www-form-urlencoded");

    char time_buffer[30];
    char temperature_buffer[30];
    char humidity_buffer[30];
    char heat_index_buffer[30];
    char reading_interval_buffer[30];

    sprintf(time_buffer, "%d", current_time);
    sprintf(reading_interval_buffer, "%d", CONFIG.data.reading_interval_s);
    sprintf(temperature_buffer, "%.3f", temperature_f);
    sprintf(humidity_buffer, "%.3f", humidity);
    sprintf(heat_index_buffer, "%.3f", heat_index);

    const char* post_data[][2] =
    {
      {"hub", CONFIG.data.hub_id},
      {"cell", CONFIG.data.cell_id},
      {"time", time_buffer},
      {"temp", temperature_buffer},
      {"humidity", humidity_buffer},
      {"sp", reading_interval_buffer},
      {"heat_index", heat_index_buffer},
      {"cell_version", CODE_VERSION},
    };
    int param_count = 8;

    response_received = false;
    transmit_success = false;

    http.post(CONFIG.data.endpoint_domain, CONFIG.data.endpoint_path, post_data, param_count); // Will halt if an error occurs

    while (!response_received || !transmit_success); // Hang if transmit doesn't complete or fails

    return true;
  }
#endif

typedef struct {
  float temperature_f;
  float humidity;
  float heat_index;
} temp_data_struct;

typedef union {
  temp_data_struct data;
  uint8_t raw[sizeof(temp_data_struct)];
} temp_data;

// Create a file on the SD card representing a temperature reading
// The file name is the unix timestamp, however, due to FAT naming conventions,
// we have to place a period in it.   e.g.   1500985299   ->  1500985.299
// The content of the file is the binary reading data struct.
void queue_transmission(char *filename, temp_data temp, uint32_t current_time) {
  char file_path[50];
  char timestamp[50];
  char timestamp_first_half[50];
  char timestamp_last_half[50];

  // FAT only allows 8 character names, so we make the last 3 digits of the
  // timestamp the file "extension"
  sprintf(timestamp, "%d", current_time);
  strncpy(timestamp_first_half, timestamp, 7);
  timestamp_first_half[7] = '\0';
  strncpy(timestamp_last_half, timestamp+7, 3);
  timestamp_last_half[3] = '\0';

  sprintf(filename, "%s.%s", timestamp_first_half, timestamp_last_half);
  sprintf(file_path, "pending/%s", filename);

  File temperature_file;
  SD.mkdir("pending");
  if (temperature_file = SD.open(file_path, FILE_WRITE | O_TRUNC)) {
    temperature_file.write(temp.raw, sizeof(temp));
    temperature_file.close();
  } else {
    Serial.println("unable to write temperature");
    while(true); // watchdog will reboot
  }
}

// Take a filename for a reading, read the temperature data and
// transmit it.  Then delete the file when the transfer is successful.
void transmit_queued_temp(char *filename) {
  watchdog_feed();

  File temperature_file;
  temp_data temperature;
  char read_time_buffer[100];
  char file_path[100];
  sprintf(file_path, "pending/%s", filename);

  Serial.print("transfering: ");
  Serial.println(filename);

  strncpy(read_time_buffer, filename, 7);
  strncpy(read_time_buffer+7, filename+8, 3);
  read_time_buffer[10] = '\0';

  uint32_t read_time = strtoul(read_time_buffer, NULL, 0);

  if (temperature_file = SD.open(file_path, FILE_READ)) {
    int read_size = temperature_file.read(temperature.raw, sizeof(temperature));

    if (sizeof(temperature) == read_size) {
      bool transmit_success = _transmit(temperature.data.temperature_f, temperature.data.humidity, temperature.data.heat_index, read_time);

      temperature_file.close();
      delay(100);

      if (transmit_success) {
        Serial.println("transferred.");

        if (SD.remove(file_path)) {
          Serial.println("removed.");
        } else {
          Serial.println("failed to remove file");
        }
      } else {
        Serial.println("failed to transfer");
      }
    } else {
      Serial.print("file incorrect size - expected: ");
      Serial.print(sizeof(temperature));
      Serial.print(", got: ");
      Serial.println(read_size);
    }
  } else {
    Serial.print("failed to open: ");
    Serial.println(filename);
  }

  watchdog_feed();
}

void transmit(float temperature_f, float humidity, float heat_index, uint32_t current_time) {
  watchdog_feed();

  temp_data temp;
  temp.data.temperature_f = temperature_f;
  temp.data.humidity = humidity;
  temp.data.heat_index = heat_index;

  char filename[100];
  queue_transmission(filename, temp, current_time);
  watchdog_feed();
  delay(1000);

  Serial.print("created file: ");
  Serial.println(filename);

  transmit_queued_temp(filename);

  File pending_dir = SD.open("pending");
  int temps_transfered_count = 0;

  while (temps_transfered_count < TRANSMITS_PER_LOOP) {
    File entry = pending_dir.openNextFile();
    if (!entry) { break; } // No more files

    strcpy(filename, entry.name());
    entry.close();

    transmit_queued_temp(filename);
    temps_transfered_count += 1;
  }

  pending_dir.close();
}
<|endoftext|>