<commit_before>/*
 * LCALIFLateralConn.cpp
 *
 *  Created on: Oct 3, 2012
 *      Author: pschultz
 */

#include "LCALIFLateralConn.hpp"

namespace PV {

LCALIFLateralConn::LCALIFLateralConn()
{
   initialize_base();
}

LCALIFLateralConn::LCALIFLateralConn(const char * name, HyPerCol * hc, HyPerLayer * pre, HyPerLayer * post,
      const char * filename, InitWeights *weightInit) {
   initialize_base();
   initialize(name, hc, pre, post, filename, weightInit);
}

LCALIFLateralConn::~LCALIFLateralConn()
{
}

int LCALIFLateralConn::initialize_base() {
   integratedSpikeCount = NULL;
   return PV_SUCCESS;
}

int LCALIFLateralConn::initialize(const char * name, HyPerCol * hc, HyPerLayer * pre, HyPerLayer * post,
      const char * filename, InitWeights * weightInit) {
   int status = HyPerConn::initialize(name, hc, pre, post, filename, weightInit);
   LCALIFLayer * lcapre = dynamic_cast<LCALIFLayer * >(pre);
   LCALIFLayer * lcapost = dynamic_cast<LCALIFLayer *>(post);
   if (lcapre == NULL || lcapost == NULL) {
      if (parent->columnId()==0) {
         fprintf(stderr, "LCALIFLateralConn \"%s\": Presynaptic layer \"%s\" and postsynaptic layer \"%s\" must both be LCALIFLayers.\n", name, pre->getName(), post->getName());
      }
      abort();
   }
   const PVLayerLoc * preloc = pre->getLayerLoc();
   const PVLayerLoc * postloc = post->getLayerLoc();
   int nxpre = preloc->nx; int nxpost = postloc->nx;
   int nypre = preloc->ny; int nypost = postloc->ny;
   int nfpre = preloc->nf; int nfpost = postloc->nf;
   int nbpre = preloc->nb; int nbpost = postloc->nb;
   if (nxpre!=nxpost || nypre!=nypost || nfpre!=nfpost || nbpre!=nbpost) {
      if (parent->columnId()==0) {
         fprintf(stderr, "LCALIFLateralConn: pre- and post-synaptic layers must have the same geometry (including margin width)\n");
         fprintf(stderr, "  Pre:  nx=%d, ny=%d, nf=%d, nb=%d\n", nxpre, nypre, nfpre, nbpre);
         fprintf(stderr, "  Post: nx=%d, ny=%d, nf=%d, nb=%d\n", nxpost, nypost, nfpost, nbpost);
      }
      abort();
   }
   integratedSpikeCount = (float *) calloc(pre->getNumExtended(), sizeof(float)); // Spike counts initialized to 0
   return status;
}

int LCALIFLateralConn::setParams(PVParams * params) {
   int status = HyPerConn::setParams(params);
   integrationTimeConstant = readIntegrationTimeConstant();
   inhibitionTimeConstant = readAdaptationTimeConstant();
   return status;
}

int LCALIFLateralConn::calc_dW(int axonId) {
   assert(axonId>=0 && axonId < numberOfAxonalArborLists());
   updateIntegratedSpikeCount();
   pvdata_t * gSyn_buffer_start = post->getChannel(channel);
   LCALIFLayer * lcapre = dynamic_cast<LCALIFLayer *>(pre);
   assert(lcapre != NULL);
   pvdata_t targetRate = lcapre->getTargetRate();
   pvdata_t target_rate_sq = targetRate * targetRate;
   float dt_inh = parent->getDeltaTime()/inhibitionTimeConstant;
   float tausq = integrationTimeConstant*integrationTimeConstant;
   const PVPatchStrides * strides  = getPostNonextStrides();
   const int sx = strides->sx;
   const int sy = strides->sy;
   const int sf = strides->sf;
   const PVLayerLoc * postloc = post->getLayerLoc();
   const int nxpost = postloc->nx;
   const int nypost = postloc->ny;
   const int nfpost = postloc->nf;
   const int nbpost = postloc->nb;

   for (int kPre=0; kPre<getNumWeightPatches(); kPre++) {
      // The weight p(x,y,f) connects a presynaptic neuron in extended space to a postsynaptic neuron in restricted space.
      // We need to get the indices.  The presynaptic index is k.  To get the postsynaptic index, find
      // The memory location this weight is mapped to and subtract it from the start of the postsynaptic GSyn buffer.
      pvdata_t * gSyn_patch_start = getGSynPatchStart(kPre, axonId);
      int patch_start_index = gSyn_patch_start - gSyn_buffer_start;
      const PVPatch * p = getWeights(kPre, axonId);
      pvdata_t * dw_data = get_dwData(axonId,kPre);
      int nx = p->nx;
      int ny = p->ny;
      for (int y=0; y<ny; y++) {
         for (int x=0; x<nx; x++) {
            for (int f=0; f<nfp; f++) {
               int postindex = patch_start_index + sy*y + sx*x + sf*f;
               int postindexext = kIndexExtended(postindex, nxpost, nypost, nfpost, nbpost);
               pvdata_t delta_weight = dt_inh*(integratedSpikeCount[kPre]*integratedSpikeCount[postindexext]/tausq/target_rate_sq-1.0);
               dw_data[sxp*x + syp*y + sfp*f] = delta_weight;
            }
         }
      }
   }
   return PV_SUCCESS;
}

int LCALIFLateralConn::updateWeights(int axonId) {
   for (int kPre=0; kPre<getNumWeightPatches(); kPre++) {
      const PVPatch * p = getWeights(kPre, axonId);
      pvdata_t * dw_data = get_dwData(axonId,kPre);
      pvdata_t * w_data = get_wData(axonId,kPre);
      int nx = p->nx;
      int ny = p->ny;
      for (int y=0; y<ny; y++) {
         for (int x=0; x<nx; x++) {
            for (int f=0; f<nfp; f++) {
               w_data[sxp*x + syp*y + sfp*f] += dw_data[sxp*x + syp*y + sfp*f];
            }
         }
      }
   }
   return PV_SUCCESS;
}

int LCALIFLateralConn::updateIntegratedSpikeCount() {
   float exp_dt_tau = exp(-parent->getDeltaTime()/integrationTimeConstant);
   pvdata_t * activity = pre->getActivity();
   for (int k=0; k<getNumWeightPatches(); k++) {
      integratedSpikeCount[k] = exp_dt_tau*(integratedSpikeCount[k]+activity[k]);
   }
   return PV_SUCCESS;
}

int LCALIFLateralConn::checkpointWrite(const char * cpDir) {
   int status = HyPerConn::checkpointWrite(cpDir);
   // TODO write integratedSpikeCount to checkpoint
   return status;
}

int LCALIFLateralConn::checkpointRead(const char * cpDir, float* timef) {
   int status = HyPerConn::checkpointRead(cpDir, timef);
   // TODO read integratedSpikeCount from checkpoint
   return status;
}

} /* namespace PV */
<commit_msg>LCALIFLateralConn frees integratedSpikeCount in destructor<commit_after>/*
 * LCALIFLateralConn.cpp
 *
 *  Created on: Oct 3, 2012
 *      Author: pschultz
 */

#include "LCALIFLateralConn.hpp"

namespace PV {

LCALIFLateralConn::LCALIFLateralConn()
{
   initialize_base();
}

LCALIFLateralConn::LCALIFLateralConn(const char * name, HyPerCol * hc, HyPerLayer * pre, HyPerLayer * post,
      const char * filename, InitWeights *weightInit) {
   initialize_base();
   initialize(name, hc, pre, post, filename, weightInit);
}

LCALIFLateralConn::~LCALIFLateralConn()
{
   free(integratedSpikeCount); integratedSpikeCount = NULL;
}

int LCALIFLateralConn::initialize_base() {
   integratedSpikeCount = NULL;
   return PV_SUCCESS;
}

int LCALIFLateralConn::initialize(const char * name, HyPerCol * hc, HyPerLayer * pre, HyPerLayer * post,
      const char * filename, InitWeights * weightInit) {
   int status = HyPerConn::initialize(name, hc, pre, post, filename, weightInit);
   LCALIFLayer * lcapre = dynamic_cast<LCALIFLayer * >(pre);
   LCALIFLayer * lcapost = dynamic_cast<LCALIFLayer *>(post);
   if (lcapre == NULL || lcapost == NULL) {
      if (parent->columnId()==0) {
         fprintf(stderr, "LCALIFLateralConn \"%s\": Presynaptic layer \"%s\" and postsynaptic layer \"%s\" must both be LCALIFLayers.\n", name, pre->getName(), post->getName());
      }
      abort();
   }
   const PVLayerLoc * preloc = pre->getLayerLoc();
   const PVLayerLoc * postloc = post->getLayerLoc();
   int nxpre = preloc->nx; int nxpost = postloc->nx;
   int nypre = preloc->ny; int nypost = postloc->ny;
   int nfpre = preloc->nf; int nfpost = postloc->nf;
   int nbpre = preloc->nb; int nbpost = postloc->nb;
   if (nxpre!=nxpost || nypre!=nypost || nfpre!=nfpost || nbpre!=nbpost) {
      if (parent->columnId()==0) {
         fprintf(stderr, "LCALIFLateralConn: pre- and post-synaptic layers must have the same geometry (including margin width)\n");
         fprintf(stderr, "  Pre:  nx=%d, ny=%d, nf=%d, nb=%d\n", nxpre, nypre, nfpre, nbpre);
         fprintf(stderr, "  Post: nx=%d, ny=%d, nf=%d, nb=%d\n", nxpost, nypost, nfpost, nbpost);
      }
      abort();
   }
   integratedSpikeCount = (float *) calloc(pre->getNumExtended(), sizeof(float)); // Spike counts initialized to 0
   return status;
}

int LCALIFLateralConn::setParams(PVParams * params) {
   int status = HyPerConn::setParams(params);
   integrationTimeConstant = readIntegrationTimeConstant();
   inhibitionTimeConstant = readAdaptationTimeConstant();
   return status;
}

int LCALIFLateralConn::calc_dW(int axonId) {
   assert(axonId>=0 && axonId < numberOfAxonalArborLists());
   updateIntegratedSpikeCount();
   pvdata_t * gSyn_buffer_start = post->getChannel(channel);
   LCALIFLayer * lcapre = dynamic_cast<LCALIFLayer *>(pre);
   assert(lcapre != NULL);
   pvdata_t targetRate = lcapre->getTargetRate();
   pvdata_t target_rate_sq = targetRate * targetRate;
   float dt_inh = parent->getDeltaTime()/inhibitionTimeConstant;
   float tausq = integrationTimeConstant*integrationTimeConstant;
   const PVPatchStrides * strides  = getPostNonextStrides();
   const int sx = strides->sx;
   const int sy = strides->sy;
   const int sf = strides->sf;
   const PVLayerLoc * postloc = post->getLayerLoc();
   const int nxpost = postloc->nx;
   const int nypost = postloc->ny;
   const int nfpost = postloc->nf;
   const int nbpost = postloc->nb;

   for (int kPre=0; kPre<getNumWeightPatches(); kPre++) {
      // The weight p(x,y,f) connects a presynaptic neuron in extended space to a postsynaptic neuron in restricted space.
      // We need to get the indices.  The presynaptic index is k.  To get the postsynaptic index, find
      // The memory location this weight is mapped to and subtract it from the start of the postsynaptic GSyn buffer.
      pvdata_t * gSyn_patch_start = getGSynPatchStart(kPre, axonId);
      int patch_start_index = gSyn_patch_start - gSyn_buffer_start;
      const PVPatch * p = getWeights(kPre, axonId);
      pvdata_t * dw_data = get_dwData(axonId,kPre);
      int nx = p->nx;
      int ny = p->ny;
      for (int y=0; y<ny; y++) {
         for (int x=0; x<nx; x++) {
            for (int f=0; f<nfp; f++) {
               int postindex = patch_start_index + sy*y + sx*x + sf*f;
               int postindexext = kIndexExtended(postindex, nxpost, nypost, nfpost, nbpost);
               pvdata_t delta_weight = dt_inh*(integratedSpikeCount[kPre]*integratedSpikeCount[postindexext]/tausq/target_rate_sq-1.0);
               dw_data[sxp*x + syp*y + sfp*f] = delta_weight;
            }
         }
      }
   }
   return PV_SUCCESS;
}

int LCALIFLateralConn::updateWeights(int axonId) {
   for (int kPre=0; kPre<getNumWeightPatches(); kPre++) {
      const PVPatch * p = getWeights(kPre, axonId);
      pvdata_t * dw_data = get_dwData(axonId,kPre);
      pvdata_t * w_data = get_wData(axonId,kPre);
      int nx = p->nx;
      int ny = p->ny;
      for (int y=0; y<ny; y++) {
         for (int x=0; x<nx; x++) {
            for (int f=0; f<nfp; f++) {
               w_data[sxp*x + syp*y + sfp*f] += dw_data[sxp*x + syp*y + sfp*f];
            }
         }
      }
   }
   return PV_SUCCESS;
}

int LCALIFLateralConn::updateIntegratedSpikeCount() {
   float exp_dt_tau = exp(-parent->getDeltaTime()/integrationTimeConstant);
   pvdata_t * activity = pre->getActivity();
   for (int k=0; k<getNumWeightPatches(); k++) {
      integratedSpikeCount[k] = exp_dt_tau*(integratedSpikeCount[k]+activity[k]);
   }
   return PV_SUCCESS;
}

int LCALIFLateralConn::checkpointWrite(const char * cpDir) {
   int status = HyPerConn::checkpointWrite(cpDir);
   // TODO write integratedSpikeCount to checkpoint
   return status;
}

int LCALIFLateralConn::checkpointRead(const char * cpDir, float* timef) {
   int status = HyPerConn::checkpointRead(cpDir, timef);
   // TODO read integratedSpikeCount from checkpoint
   return status;
}

} /* namespace PV */
<|endoftext|>


<commit_before>//=====================================================================//
/*!	@file
	@brief	Renesas R8C Series Programmer (Flash Writer)
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "r8c_protocol.hpp"
#include <iostream>
#include <iomanip>
#include <random>
#include "motsx_io.hpp"

static const std::string version_ = "0.20b";

void dump_(const uint8_t* top, uint32_t len, uint32_t ofs, uint32_t w = 16)
{
	using namespace std;
	cout << hex;

	uint32_t l = 0;
	for(uint32_t i = 0; i < len; ++i) {
		if(l == 0) {
			cout << uppercase << setw(4) << setfill('0') << ofs << "- ";
		}
		int d = static_cast<int>(*top);
		++top;
		cout << uppercase << setw(2) << setfill('0') << d;
		++l;
		++ofs;
		if(l >= w) {
			cout << endl;
			l = 0;
		} else {
			cout << ' ';
		}
	}

	cout << dec;
}

class r8c_prog {
	bool	verbose_;
	r8c::protocol	proto_;
	std::string		ver_;
	r8c::protocol::id_t	id_;

public:
	r8c_prog(bool verbose) : verbose_(verbose) {
		id_.fill();
	}

	bool start(const std::string& path, uint32_t brate) {
		using namespace r8c;

		// 開始
		if(!proto_.start(path)) {
			std::cerr << "Can't open path: '" << path << "'" << std::endl;
			return false;
		}

		// コネクション
		if(!proto_.connection()) {
			proto_.end();
			std::cerr << "Connection device error..." << std::endl;
			return false;
		}
		if(verbose_) {
			std::cout << "Connection OK." << std::endl;
		}

		// ボーレート変更
		speed_t speed;
		switch(brate) {
		case 9600:   speed = B9600;   break;
		case 19200:  speed = B19200;  break;
		case 38400:  speed = B38400;  break;
		case 57600:  speed = B57600;  break;
		case 115200: speed = B115200; break;
		default:
			proto_.end();
			std::cerr << "Baud rate error: " << brate << std::endl;
			return false;
		}

		if(!proto_.change_speed(speed)) {
			proto_.end();
			std::cerr << "Change speed error: " << brate << std::endl;
			return false;
		}
		if(verbose_) {
			std::cout << "Change speed OK: " << brate << " [bps]" << std::endl;
		}

		// バージョンの取得
		ver_ = proto_.get_version();
		if(ver_.empty()) {
			proto_.end();
			std::cerr << "Get version error..." << std::endl;
			return false;
		}
		if(verbose_) {
			std::cout << "Version: '" << ver_ << "'" << std::endl;
		}

		// ID チェック認証
		if(!proto_.id_inspection(id_)) {
			std::cerr << "ID error: ";
			for(int i = 0; i < 7; ++i) {
				std::cerr << std::hex << std::setw(2) << std::uppercase << std::setfill('0')
						  << "0x" << static_cast<int>(id_.buff[i]) << ' ';
			}
			proto_.end();
			std::cerr << std::dec << std::endl;
			return false;
		}
		if(verbose_) {
			std::cout << "ID OK: ";
			for(int i = 0; i < 7; ++i) {
				std::cout << std::hex << std::setw(2) << std::uppercase << std::setfill('0')
						  << "0x" << static_cast<int>(id_.buff[i]) << ' ';
			}
			std::cout << std::endl;
		}

		return true;
	}

	bool erase(uint32_t top) {
		// イレース
		if(!proto_.erase_page(top)) {
			std::cerr << "Erase error: " << std::hex << std::setw(6)
					  << static_cast<int>(top) << " to " << static_cast<int>(top + 255)
					  << std::endl;
			return false;
		}
		return true;
	}

	bool write(uint32_t top, const uint8_t* data) {
		using namespace r8c;
		// ページ書き込み
		if(!proto_.write_page(top, data)) {
   			std::cerr << "Write error: " << std::hex << std::setw(6)
					  << static_cast<int>(top) << " to " << static_cast<int>(top + 255)
					  << std::endl;
			return false;
		}
		return true;
   	}

	bool verify(uint32_t top, const uint8_t* data) {
		// ページ読み込み
		uint8_t tmp[256];
   		if(!proto_.read_page(top, tmp)) {
   			std::cerr << "Read error: " << std::hex << std::setw(6)
					  << static_cast<int>(top) << " to " << static_cast<int>(top + 255)
					  << std::endl;
   			return false;
   		}

		for(int i = 0; i < 256; ++i) {
			if(data[i] != tmp[i]) {
   			std::cerr << "Verify error: " << std::hex << std::setw(6)
					  << "0x" << static_cast<int>(top)
					  << std::setw(2) << static_cast<int>(data[top + i]) << " -> "
					  << static_cast<int>(tmp[i])
					  << std::endl;
				return false;
			}
		}
		return true;
	}

#if 0
   		std::mt19937 mt(0x1234);
   		protocol::array_type ar;
   		for(int i = 0; i < 256; ++i) {
   			ar.push_back(mt() & 255);
   		}
   		dump_(&ar[0], 256, 0x8000);
#endif

	void end() {
		proto_.end();
	}
};

static bool erase_(r8c_prog& prog, utils::motsx_io& motf)
{
	std::cout << "Erase:  ";
	bool noerr = true;
	for(uint32_t a = motf.get_min(); a <= motf.get_max(); a += 256) {
		const std::vector<uint8_t>& mem = motf.get_memory();
		bool erase = false;
		for(int i = 0; i < 256; ++i) {
			if(mem[a + i] != 0xff) {
				erase = true;
				break;
			}
		}
		if(erase) {
			if(!prog.erase(a)) {
				noerr = false;
				break;
			}
			std::cout << '#' << std::flush;
		}
	}
	std::cout << std::endl;

	return noerr;
}

static bool write_(r8c_prog& prog, utils::motsx_io& motf)
{
	bool noerr = true;
	std::cout << "Write:  ";
	for(uint32_t a = motf.get_min(); a <= motf.get_max(); a += 256) {
		const std::vector<uint8_t>& mem = motf.get_memory();
		bool skip = true;
		for(int i = 0; i < 256; ++i) {
			if(mem[a + i] != 0xff) {
				skip = false;
				break;
			}
		}
		if(skip) continue;

		if(!prog.write(a, &mem[a])) {
			noerr = false;
			break;
		}
		std::cout << '#' << std::flush;
	}
	std::cout << std::endl;

	return noerr;
}

static bool verify_(r8c_prog& prog, utils::motsx_io& motf)
{
	bool noerr = true;
	std::cout << "Verify: ";
	for(uint32_t a = motf.get_min(); a <= motf.get_max(); a += 256) {
		const std::vector<uint8_t>& mem = motf.get_memory();
		bool skip = true;
		for(int i = 0; i < 256; ++i) {
			if(mem[a + i] != 0xff) {
				skip = false;
				break;
			}
		}
		if(skip) continue;

		if(!prog.verify(a, &mem[a])) {
			noerr = false;
			break;
		}
		std::cout << '#' << std::flush;
	}
	std::cout << std::endl;

	return noerr;
}

struct options {
	bool verbose;
	std::string	inp_file;
	std::string	device;
	bool	dv;
	uint32_t	baud_rate;
	bool	br;
	std::string dev_path;
	bool	dp;

	bool	erase;
	bool	write;
	bool	verify;

	options() : verbose(false),
				inp_file(),
				device(), dv(false),
				baud_rate(57600), br(false),
				dev_path(), dp(false),
				erase(false), write(false), verify(false) { }

	void set_speed(const std::string& t) {
		int val;
	   	if(utils::string_to_int(t, val)) {
	   		baud_rate = val;
	   	} else {
	   		std::cerr << "Options error: baud rate speed: " << t << std::endl;
	   	}
	}

	void set_str(const std::string& t) {
		if(br) {
			set_speed(t);
			br = false;
		} else if(dv) {
			device = t;
			dv = false;
		} else if(dp) {
			dev_path = t;
			dp = false;
		} else {
			inp_file = t;
		}
	}
};

static void title_(const std::string& cmd)
{
	using namespace std;

	std::string c = utils::get_file_base(cmd);

	cout << "Renesas R8C Series Programmer Version" << version_ << endl;
	cout << "Copyright (C) 2015, Hiramatsu Kunihito (hira@rvf-rc45.net)" << endl;
	cout << "usage:" << endl;
	cout << c << "[options] [mot/id/conf file] ..." << endl;
	cout << endl;
	cout << "Options :" << endl;
	cout << "-d, --device=DEVICE\t\tSpecify device name" << endl;
	cout << "-e, --erase\t\t\tPerform a device erase to a minimum" << endl;
//	cout << "-E, --erase-all, --erase-chip\tPerform rom and data flash erase" << endl;
//	cout << "    --erase-rom\t\t\tPerform rom flash erase" << endl;
//	cout << "    --erase-data\t\tPerform data flash erase" << endl;
//	cout << "-i, --id=xx:xx:xx:xx:xx:xx:xx\tSpecify protect ID" << endl;
	cout << "-p, --programmer=PROGRAMMER\tSpecify programmer name" << endl;
	cout << "-P, --port=PORT\t\t\tSpecify serial port" << endl;
//	cout << "-q\t\t\t\tQuell progress output" << endl;
//	cout << "-r, --read\t\t\tPerform data read" << endl;
	cout << "-s, --speed=SPEED\t\tSpecify serial speed" << endl;
	cout << "-v, --verify\t\t\tPerform data verify" << endl;
//	cout << "    --device-list\t\tDisplay device list" << endl;
//	cout << "    --programmer-list\t\tDisplay programmer list" << endl;
	cout << "-V, --verbose\t\t\tVerbose output" << endl;
	cout << "-w, --write\t\t\tPerform data write" << endl;
//	cout << "-h, --help\t\t\tDisplay this" << endl;
//	cout << "    --version\t\t\tDisplay version No." << endl;
}

int main(int argc, char* argv[])
{
	if(argc == 1) {
		title_(argv[0]);
		return 0;
	}

	options opt;
	for(int i = 1; i < argc; ++i) {
		const std::string p = argv[i];
		if(p[0] == '-') {
			if(p == "-V" || p == "-verbose") opt.verbose = true;
			else if(p == "-s") opt.br = true;
			else if(p == "-d") opt.dv = true;
			else if(p == "-P") opt.dp = true;
			else if(p == "-e" || p == "--erase") opt.erase = true;
			else if(p == "-w" || p == "--write") opt.write = true;
			else if(p == "-v" || p == "--verify") opt.verify = true;
		} else {
			opt.set_str(p);
		}
	}

	utils::motsx_io motf;
	if(!motf.load(opt.inp_file)) {
		std::cerr << "Can't load input file: '" << opt.inp_file << "'" << std::endl;
		return -1;
	}
	if(opt.verbose) {
		std::cout << "Load data: ";
		std::cout << std::hex << std::uppercase << std::setfill('0')
				  << std::setw(6) << static_cast<int>(motf.get_min()) << " to "
				  << std::setw(6) << static_cast<int>(motf.get_max())
				  << std::dec << std::endl;
	}

	// test
	if(opt.dev_path.empty()) {
		opt.dev_path = "/dev/tty.usbserial-A600e0xq";
	}
	r8c_prog prog(opt.verbose);
	if(!prog.start(opt.dev_path, opt.baud_rate)) {
		return -1;
	}

	if(opt.erase) {
		if(!erase_(prog, motf)) {
			return -1;
		}
	}

	if(opt.write) {
		if(!write_(prog, motf)) {
			return -1;
		}
	}

	if(opt.verify) {
		if(!verify_(prog, motf)) {
			return -1;
		}
	}

}
<commit_msg>update progress<commit_after>//=====================================================================//
/*!	@file
	@brief	Renesas R8C Series Programmer (Flash Writer)
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "r8c_protocol.hpp"
#include <iostream>
#include <iomanip>
#include <random>
#include "motsx_io.hpp"

static const std::string version_ = "0.30b";
static const uint32_t progress_num_ = 50;
static const char progress_cha_ = '#';

void dump_(const uint8_t* top, uint32_t len, uint32_t ofs, uint32_t w = 16)
{
	using namespace std;
	cout << hex;

	uint32_t l = 0;
	for(uint32_t i = 0; i < len; ++i) {
		if(l == 0) {
			cout << uppercase << setw(4) << setfill('0') << ofs << "- ";
		}
		int d = static_cast<int>(*top);
		++top;
		cout << uppercase << setw(2) << setfill('0') << d;
		++l;
		++ofs;
		if(l >= w) {
			cout << endl;
			l = 0;
		} else {
			cout << ' ';
		}
	}

	cout << dec;
}

#if 0
   		std::mt19937 mt(0x1234);
   		protocol::array_type ar;
   		for(int i = 0; i < 256; ++i) {
   			ar.push_back(mt() & 255);
   		}
   		dump_(&ar[0], 256, 0x8000);
#endif

class r8c_prog {
	bool	verbose_;
	r8c::protocol	proto_;
	std::string		ver_;
	r8c::protocol::id_t	id_;

public:
	r8c_prog(bool verbose) : verbose_(verbose) {
		id_.fill();
	}

	bool start(const std::string& path, uint32_t brate) {
		using namespace r8c;

		// 開始
		if(!proto_.start(path)) {
			std::cerr << "Can't open path: '" << path << "'" << std::endl;
			return false;
		}

		// コネクション
		if(!proto_.connection()) {
			proto_.end();
			std::cerr << "Connection device error..." << std::endl;
			return false;
		}
		if(verbose_) {
			std::cout << "Connection OK." << std::endl;
		}

		// ボーレート変更
		speed_t speed;
		switch(brate) {
		case 9600:   speed = B9600;   break;
		case 19200:  speed = B19200;  break;
		case 38400:  speed = B38400;  break;
		case 57600:  speed = B57600;  break;
		case 115200: speed = B115200; break;
		default:
			proto_.end();
			std::cerr << "Baud rate error: " << brate << std::endl;
			return false;
		}

		if(!proto_.change_speed(speed)) {
			proto_.end();
			std::cerr << "Change speed error: " << brate << std::endl;
			return false;
		}
		if(verbose_) {
			std::cout << "Change speed OK: " << brate << " [bps]" << std::endl;
		}

		// バージョンの取得
		ver_ = proto_.get_version();
		if(ver_.empty()) {
			proto_.end();
			std::cerr << "Get version error..." << std::endl;
			return false;
		}
		if(verbose_) {
			std::cout << "Version: '" << ver_ << "'" << std::endl;
		}

		// ID チェック認証
		if(!proto_.id_inspection(id_)) {
			std::cerr << "ID error: ";
			for(int i = 0; i < 7; ++i) {
				std::cerr << std::hex << std::setw(2) << std::uppercase << std::setfill('0')
						  << "0x" << static_cast<int>(id_.buff[i]) << ' ';
			}
			proto_.end();
			std::cerr << std::dec << std::endl;
			return false;
		}
		if(verbose_) {
			std::cout << "ID OK: ";
			for(int i = 0; i < 7; ++i) {
				std::cout << std::hex << std::setw(2) << std::uppercase << std::setfill('0')
						  << "0x" << static_cast<int>(id_.buff[i]) << ' ';
			}
			std::cout << std::endl;
		}

		return true;
	}

	bool erase(uint32_t top) {
		// イレース
		if(!proto_.erase_page(top)) {
			std::cerr << "Erase error: " << std::hex << std::setw(6)
					  << static_cast<int>(top) << " to " << static_cast<int>(top + 255)
					  << std::endl;
			return false;
		}
		return true;
	}

	bool write(uint32_t top, const uint8_t* data) {
		using namespace r8c;
		// ページ書き込み
		if(!proto_.write_page(top, data)) {
   			std::cerr << "Write error: " << std::hex << std::setw(6)
					  << static_cast<int>(top) << " to " << static_cast<int>(top + 255)
					  << std::endl;
			return false;
		}
		return true;
   	}

	bool verify(uint32_t top, const uint8_t* data) {
		// ページ読み込み
		uint8_t tmp[256];
   		if(!proto_.read_page(top, tmp)) {
   			std::cerr << "Read error: " << std::hex << std::setw(6)
					  << static_cast<int>(top) << " to " << static_cast<int>(top + 255)
					  << std::endl;
   			return false;
   		}

		for(int i = 0; i < 256; ++i) {
			if(data[i] != tmp[i]) {
   			std::cerr << "Verify error: " << std::hex << std::setw(6)
					  << "0x" << static_cast<int>(top)
					  << std::setw(2) << static_cast<int>(data[top + i]) << " -> "
					  << static_cast<int>(tmp[i])
					  << std::endl;
				return false;
			}
		}
		return true;
	}

	void end() {
		proto_.end();
	}
};

static bool erase_(r8c_prog& prog, utils::motsx_io& motf)
{
	bool noerr = true;
	std::cout << "Erase:  ";
	uint32_t pcn = 0;
	uint32_t n = 0;
	for(uint32_t a = motf.get_min(); a <= motf.get_max(); a += 256) {
		if(!motf.find_page(a)) continue;

   		if(!prog.erase(a)) {
   			noerr = false;
   			break;
   		}
   		++n;
   		uint32_t pos = progress_num_ * n / motf.get_total_page();
   		for(int i = 0; i < (pos - pcn); ++i) {
   			std::cout << progress_cha_ << std::flush;
   		}
   		pcn = pos;
	}
	std::cout << std::endl << std::flush;

	return noerr;
}

static bool write_(r8c_prog& prog, utils::motsx_io& motf)
{
	bool noerr = true;
	std::cout << "Write:  ";
	uint32_t pcn = 0;
	uint32_t n = 0;
	for(uint32_t a = motf.get_min(); a <= motf.get_max(); a += 256) {
		if(!motf.find_page(a)) continue;

		if(!prog.write(a, motf.get_memory(a).data())) {
			noerr = false;
			break;
		}
   		++n;
   		uint32_t pos = progress_num_ * n / motf.get_total_page();
   		for(int i = 0; i < (pos - pcn); ++i) {
   			std::cout << progress_cha_ << std::flush;
   		}
   		pcn = pos;
	}
	std::cout << std::endl << std::flush;

	return noerr;
}

static bool verify_(r8c_prog& prog, utils::motsx_io& motf)
{
	bool noerr = true;
	std::cout << "Verify: ";
	uint32_t pcn = 0;
	uint32_t n = 0;
	for(uint32_t a = motf.get_min(); a <= motf.get_max(); a += 256) {
		if(!motf.find_page(a)) continue;

		if(!prog.verify(a, motf.get_memory(a).data())) {
			noerr = false;
			break;
		}
   		++n;
   		uint32_t pos = progress_num_ * n / motf.get_total_page();
   		for(int i = 0; i < (pos - pcn); ++i) {
   			std::cout << progress_cha_ << std::flush;
   		}
   		pcn = pos;
	}
	std::cout << std::endl << std::flush;

	return noerr;
}

struct options {
	bool verbose;
	std::string	inp_file;
	std::string	device;
	bool	dv;
	uint32_t	baud_rate;
	bool	br;
	std::string dev_path;
	bool	dp;

	bool	erase;
	bool	write;
	bool	verify;

	options() : verbose(false),
				inp_file(),
				device(), dv(false),
				baud_rate(57600), br(false),
				dev_path(), dp(false),
				erase(false), write(false), verify(false) { }

	void set_speed(const std::string& t) {
		int val;
	   	if(utils::string_to_int(t, val)) {
	   		baud_rate = val;
	   	} else {
	   		std::cerr << "Options error: baud rate speed: " << t << std::endl;
	   	}
	}

	void set_str(const std::string& t) {
		if(br) {
			set_speed(t);
			br = false;
		} else if(dv) {
			device = t;
			dv = false;
		} else if(dp) {
			dev_path = t;
			dp = false;
		} else {
			inp_file = t;
		}
	}
};

static void title_(const std::string& cmd)
{
	using namespace std;

	std::string c = utils::get_file_base(cmd);

	cout << "Renesas R8C Series Programmer Version" << version_ << endl;
	cout << "Copyright (C) 2015, Hiramatsu Kunihito (hira@rvf-rc45.net)" << endl;
	cout << "usage:" << endl;
	cout << c << "[options] [mot/id/conf file] ..." << endl;
	cout << endl;
	cout << "Options :" << endl;
	cout << "-d, --device=DEVICE\t\tSpecify device name" << endl;
	cout << "-e, --erase\t\t\tPerform a device erase to a minimum" << endl;
//	cout << "-E, --erase-all, --erase-chip\tPerform rom and data flash erase" << endl;
//	cout << "    --erase-rom\t\t\tPerform rom flash erase" << endl;
//	cout << "    --erase-data\t\tPerform data flash erase" << endl;
//	cout << "-i, --id=xx:xx:xx:xx:xx:xx:xx\tSpecify protect ID" << endl;
	cout << "-p, --programmer=PROGRAMMER\tSpecify programmer name" << endl;
	cout << "-P, --port=PORT\t\t\tSpecify serial port" << endl;
//	cout << "-q\t\t\t\tQuell progress output" << endl;
//	cout << "-r, --read\t\t\tPerform data read" << endl;
	cout << "-s, --speed=SPEED\t\tSpecify serial speed" << endl;
	cout << "-v, --verify\t\t\tPerform data verify" << endl;
//	cout << "    --device-list\t\tDisplay device list" << endl;
//	cout << "    --programmer-list\t\tDisplay programmer list" << endl;
	cout << "-V, --verbose\t\t\tVerbose output" << endl;
	cout << "-w, --write\t\t\tPerform data write" << endl;
//	cout << "-h, --help\t\t\tDisplay this" << endl;
//	cout << "    --version\t\t\tDisplay version No." << endl;
}

int main(int argc, char* argv[])
{
	if(argc == 1) {
		title_(argv[0]);
		return 0;
	}

	options opt;
	for(int i = 1; i < argc; ++i) {
		const std::string p = argv[i];
		if(p[0] == '-') {
			if(p == "-V" || p == "-verbose") opt.verbose = true;
			else if(p == "-s") opt.br = true;
			else if(p == "-d") opt.dv = true;
			else if(p == "-P") opt.dp = true;
			else if(p == "-e" || p == "--erase") opt.erase = true;
			else if(p == "-w" || p == "--write") opt.write = true;
			else if(p == "-v" || p == "--verify") opt.verify = true;
		} else {
			opt.set_str(p);
		}
	}

	// モトローラーSフォーマットファイルの読み込み
	utils::motsx_io motf;
	if(!opt.inp_file.empty()) {
		if(!motf.load(opt.inp_file)) {
			std::cerr << "Can't load input file: '" << opt.inp_file << "'" << std::endl;
			return -1;
		}
		if(opt.verbose) {
			motf.list_memory_map();
		}
	}

	// test
	if(opt.dev_path.empty()) {
		opt.dev_path = "/dev/tty.usbserial-A600e0xq";
	}

	r8c_prog prog(opt.verbose);
	if(!prog.start(opt.dev_path, opt.baud_rate)) {
		return -1;
	}

	if(opt.erase) {
		if(!erase_(prog, motf)) {
			return -1;
		}
	}

	if(opt.write) {
		if(!write_(prog, motf)) {
			return -1;
		}
	}

	if(opt.verify) {
		if(!verify_(prog, motf)) {
			return -1;
		}
	}
}
<|endoftext|>


<commit_before>#include <mist/procs.h>
#include <mist/config.h>
#include <mist/timing.h>
#include <mist/stream.h>
#include <mist/dtsc.h>
#include <mist/defines.h>
#include <mist/shared_memory.h>
#include "controller_streams.h"
#include "controller_capabilities.h"
#include "controller_storage.h"
#include "controller_statistics.h"
#include "controller_limits.h" /*LTS*/
#include <sys/stat.h>
#include <map>

///\brief Holds everything unique to the controller.
namespace Controller {

  ///\brief Checks whether two streams are equal.
  ///\param one The first stream for the comparison.
  ///\param two The second stream for the comparison.
  ///\return True if the streams are equal, false otherwise.
  bool streamsEqual(JSON::Value & one, JSON::Value & two){
    if (one.isMember("source") != two.isMember("source") || one["source"] != two["source"]){
      return false;
    }

    /// \todo Change this to use capabilities["inputs"] and only compare required/optional parameters.
    /// \todo Maybe change this to check for correct source and/or required parameters.

    //temporary: compare the two JSON::Value objects.
    return one==two;

    //nothing different? return true by default
    //return true;
  }

  ///\brief Checks the validity of a stream, updates internal stream status.
  ///\param name The name of the stream
  ///\param data The corresponding configuration values.
  void checkStream(std::string name, JSON::Value & data){
    std::string prevState = data["error"].asStringRef();
    data["online"] = (std::string)"Checking...";
    data.removeMember("error");
    std::string URL;
    if (data.isMember("channel") && data["channel"].isMember("URL")){
      URL = data["channel"]["URL"].asString();
    }
    if (data.isMember("source")){
      URL = data["source"].asString();
    }
    if (URL == ""){
      data["error"] = "Stream offline: Missing source parameter!";
      if (data["error"].asStringRef() != prevState){
        Log("STRM", "Error for stream " + name + "! Source parameter missing.");
      }
      return;
    }
    if (URL.substr(0, 1) != "/"){
      //push-style stream
      if (hasViewers(name)){
        data["meta"].null();
        char streamPageName[NAME_BUFFER_SIZE];
        snprintf(streamPageName, NAME_BUFFER_SIZE, SHM_STREAM_INDEX, name.c_str());
        IPC::sharedPage streamIndex(streamPageName, DEFAULT_META_PAGE_SIZE, false, false);
        if (!streamIndex.mapped){
          return;
        }
        unsigned int i = 0;
        JSON::fromDTMI((const unsigned char*)streamIndex.mapped + 8, streamIndex.len - 8, i, data["meta"]);
        if (data["meta"].isMember("tracks") && data["meta"]["tracks"].size()){
          for(JSON::ObjIter trackIt = data["meta"]["tracks"].ObjBegin(); trackIt != data["meta"]["tracks"].ObjEnd(); trackIt++){
            trackIt->second.removeMember("fragments");
            trackIt->second.removeMember("keys");
            trackIt->second.removeMember("keysizes");
            trackIt->second.removeMember("parts");
            trackIt->second.removeMember("ivecs");/*LTS*/
          }
        }
      }
      return;
    }
    if (URL.substr(0, 1) == "/"){
      //vod-style stream
      data.removeMember("error");
      struct stat fileinfo;
      if (stat(URL.c_str(), &fileinfo) != 0){
        data["error"] = "Stream offline: Not found: " + URL;
        if (data["error"].asStringRef() != prevState){
          Log("BUFF", "Warning for VoD stream " + name + "! File not found: " + URL);
        }
        data["online"] = 0;
        return;
      }
      bool getMeta = false;
      if ( !data.isMember("l_meta") || fileinfo.st_mtime != data["l_meta"].asInt()){
        DEBUG_MSG(DLVL_INSANE, "File for stream %s is newer than metadata - triggering reload", name.c_str());
        getMeta = true;
        data["l_meta"] = (long long)fileinfo.st_mtime;
      }
      if (stat((URL+".dtsh").c_str(), &fileinfo) == 0 && !S_ISDIR(fileinfo.st_mode)){
        if ( !data.isMember("h_meta") || fileinfo.st_mtime != data["h_meta"].asInt()){
          DEBUG_MSG(DLVL_INSANE, "DTSH for stream %s is newer than metadata - triggering reload", name.c_str());
          getMeta = true;
          data["h_meta"] = (long long)fileinfo.st_mtime;
        }
      }
      if ( !getMeta && data.isMember("meta") && data["meta"].isMember("tracks")){
        if (!data["meta"]["tracks"]){
          data["error"] = "Stream offline: Corrupt file?";
          if (data["error"].asStringRef() != prevState){
            Log("WARN", "Source file " + URL + " seems to be corrupt.");
          }
          data["online"] = 0;
          return;
        }else{
          if (!getMeta && data["meta"].packedSize() > 10*1024 * data["meta"]["tracks"].size()){
            DEBUG_MSG(DLVL_WARN, "Metadata for stream %s is quite big (%u b) - assuming corruption and forcing reload", name.c_str(), data["meta"].packedSize());
            getMeta = true;
          }
        }
      }else{
        DEBUG_MSG(DLVL_INSANE, "Invalid metadata (no tracks object) for stream %s - triggering reload", name.c_str());
        getMeta = true;
      }
      if (*(URL.rbegin()) == '/'){
        getMeta = false;
      }
      if (getMeta){
        // if the file isn't dtsc and there's no dtsh file, run getStream on it
        // this guarantees that if the stream is playable, it now has a valid header.
        DEBUG_MSG(DLVL_INSANE, "(re)loading metadata for stream %s", name.c_str());
        Util::startInput(name);
        DEBUG_MSG(DLVL_INSANE, "Waiting for stream %s to open...", name.c_str());
        //wait for the stream
        {
          char streamPageName[NAME_BUFFER_SIZE];
          snprintf(streamPageName, NAME_BUFFER_SIZE, SHM_STREAM_INDEX, name.c_str());
          IPC::sharedPage streamIndex(streamPageName, DEFAULT_META_PAGE_SIZE, false, false);
          if (!streamIndex.mapped){
            DEBUG_MSG(DLVL_INSANE, "Stream %s opening failed! Cancelling and marking as corrupt.", name.c_str());
            data["meta"].null();
            data["meta"]["tracks"].null();
            data["error"] = "Stream offline: Corrupt file?";
            if (data["error"].asStringRef() != prevState){
              Log("WARN", "Source file " + URL + " seems to be corrupt.");
            }
            data["online"] = 0;
            return;
          }
          unsigned int i = 0;
          JSON::fromDTMI((const unsigned char*)streamIndex.mapped + 8, streamIndex.len - 8, i, data["meta"]);
          if (data["meta"].isMember("tracks") && data["meta"]["tracks"].size()){
            for(JSON::ObjIter trackIt = data["meta"]["tracks"].ObjBegin(); trackIt != data["meta"]["tracks"].ObjEnd(); trackIt++){
              trackIt->second.removeMember("fragments");
              trackIt->second.removeMember("keys");
              trackIt->second.removeMember("keysizes");
              trackIt->second.removeMember("parts");
              trackIt->second.removeMember("ivecs");
            }
          }
          if ( !data["meta"] || !data["meta"].isMember("tracks") || !data["meta"]["tracks"]){
            data["error"] = "Stream offline: Corrupt file?";
            if (data["error"].asStringRef() != prevState){
              Log("WARN", "Source file " + URL + " seems to be corrupt.");
            }
            data["online"] = 0;
            return;
          }
          DEBUG_MSG(DLVL_INSANE, "Metadata for stream %s (re)loaded", name.c_str());
        }
        DEBUG_MSG(DLVL_INSANE, "Stream %s opened", name.c_str());
      }
      if (!hasViewers(name)){
        if ( !data.isMember("error")){
          data["error"] = "Available";
        }
        data["online"] = 2;
      }else{
        data["online"] = 1;
      }
      checkServerLimits(); /*LTS*/
      return;
    }
    /// \todo Implement ffmpeg pulling again?
    //Util::Procs::Start(name, "ffmpeg -re -async 2 -i " + URL + " -f flv -", Util::getMyPath() + "MistFLV2DTSC", Util::getMyPath() + buffcmd);
    //Log("BUFF", "(re)starting stream buffer " + name + " for ffmpeg data: ffmpeg -re -async 2 -i " + URL + " -f flv -");

    //not recognized
    data["error"] = "Invalid source format";
    if (data["error"].asStringRef() != prevState){
      Log("STRM", "Invalid source format for stream " + name + "!");
    }
    return;
  }

  ///\brief Checks all streams, restoring if needed.
  ///\param data The stream configuration for the server.
  void CheckAllStreams(JSON::Value & data){
    long long int currTime = Util::epoch();
    for (JSON::ObjIter jit = data.ObjBegin(); jit != data.ObjEnd(); jit++){
      checkStream(jit->first, jit->second);
      if (!jit->second.isMember("name")){
        jit->second["name"] = jit->first;
      }
      if (!hasViewers(jit->first)){
        if (jit->second.isMember("source") && jit->second["source"].asString().substr(0, 1) == "/" && jit->second.isMember("error")
            && jit->second["error"].asString().substr(0,15) != "Stream offline:"){
          jit->second["online"] = 2;
        }else{
          if (jit->second.isMember("error") && jit->second["error"].asString() == "Available"){
            jit->second.removeMember("error");
          }
          jit->second["online"] = 0;
        }
        checkServerLimits(); /*LTS*/
      }else{
        // assume all is fine
        jit->second.removeMember("error");
        jit->second["online"] = 1;
        // check if source is valid
        //if (jit->second.isMember("live") && !jit->second.isMember("meta") || !jit->second["meta"]){
        if ( (jit->second.isMember("meta") && !jit->second["meta"].isMember("tracks"))){
          jit->second["online"] = 0;
          jit->second["error"] = "No (valid) source connected ";
        }else{
          // for live streams, keep track of activity
          if (jit->second.isMember("meta") && jit->second["meta"].isMember("live")){
            static std::map<std::string, liveCheck> checker;
            //check H264 tracks for optimality
            if (jit->second.isMember("meta") && jit->second["meta"].isMember("tracks")){
              for (JSON::ObjIter trIt = jit->second["meta"]["tracks"].ObjBegin(); trIt != jit->second["meta"]["tracks"].ObjEnd(); trIt++){
                if (trIt->second["lastms"].asInt() > checker[jit->first].lastms){
                  checker[jit->first].lastms = trIt->second["lastms"].asInt();
                  checker[jit->first].last_active = currTime;
                }
                /*LTS-START*/
                if (trIt->second["firstms"].asInt() > Storage["streams"][jit->first]["cut"].asInt()){
                  Storage["streams"][jit->first].removeMember("cut");
                }
                /*LTS-END*/
              }
            }
            // mark stream as offline if no activity for 5 seconds
            //if (jit->second.isMember("last_active") && jit->second["last_active"].asInt() < currTime - 5){
            if (checker[jit->first].last_active < currTime - 5){
              jit->second["online"] = 2;
              jit->second["error"] = "Source not active";
            }
          }
        }
      }
    }
    static JSON::Value strlist;
    bool changed = false;
    if (strlist["config"] != Storage["config"]){
      strlist["config"] = Storage["config"];
      changed = true;
    }
    if (strlist["streams"] != Storage["streams"]){
      strlist["streams"] = Storage["streams"];
      changed = true;
    }
    if (changed){
      writeConfig();
    }
  }

  void AddStreams(JSON::Value & in, JSON::Value & out){
    //check for new streams and updates
    for (JSON::ObjIter jit = in.ObjBegin(); jit != in.ObjEnd(); jit++){
      if (out.isMember(jit->first)){
        if ( !streamsEqual(jit->second, out[jit->first])){
          out[jit->first] = jit->second;
          out[jit->first]["name"] = jit->first;
          Log("STRM", std::string("Updated stream ") + jit->first);
        }
      }else{
        out[jit->first] = jit->second;
        out[jit->first]["name"] = jit->first;
        Log("STRM", std::string("New stream ") + jit->first);
      }
    }
  }

  ///\brief Parse a given stream configuration.
  ///\param in The requested configuration.
  ///\param out The new configuration after parsing.
  ///
  /// \api
  /// `"streams"` requests take the form of:
  /// ~~~~~~~~~~~~~~~{.js}
  /// {
  ///   "streamname_here": { //name of the stream
  ///     "source": "/mnt/media/a.dtsc" //full path to a VoD file, or "push://" followed by the IP or hostname of the machine allowed to push live data. Empty means everyone is allowed to push live data.
  ///     "DVR": 30000 //optional. For live streams, indicates the requested minimum size of the available DVR buffer in milliseconds.
  ///   },
  ///   //the above structure repeated for all configured streams
  /// }
  /// ~~~~~~~~~~~~~~~
  /// and are responded to as:
  /// ~~~~~~~~~~~~~~~{.js}
  /// {
  ///   "streamname_here": { //name of the configured stream
  ///     "error": "Available", //error state, if any. "Available" is a special value for VoD streams, indicating it has no current viewers (is not active), but is available for activation.
  ///     "h_meta": 1398113185, //unix time the stream header (if any) was last processed for metadata
  ///     "l_meta": 1398115447, //unix time the stream itself was last processed for metadata
  ///     "meta": { //available metadata for this stream, if any
  ///       "format": "dtsc", //detected media source format
  ///       "tracks": { //list of tracks in this stream
  ///         "audio_AAC_2ch_48000hz_2": {//human-readable track name
  ///           "bps": 16043,
  ///           "channels": 2,
  ///           "codec": "AAC",
  ///           "firstms": 0,
  ///           "init": "\u0011Vå\u0000",
  ///           "lastms": 596480,
  ///           "rate": 48000,
  ///           "size": 16,
  ///           "trackid": 2,
  ///           "type": "audio"
  ///         },
  ///         //the above structure repeated for all tracks
  ///       },
  ///       "vod": 1 //indicates VoD stream, or "live" to indicated live stream.
  ///     },
  ///     "name": "a", //the stream name, guaranteed to be equal to the object name.
  ///     "online": 2, //online state. 0 = error, 1 = active, 2 = inactive.
  ///     "source": "/home/thulinma/a.dtsc" //source for this stream, as configured.
  ///   },
  ///   //the above structure repeated for all configured streams
  /// }
  /// ~~~~~~~~~~~~~~~
  /// Through this request, ALL streams must always be configured. To remove a stream, simply leave it out of the request. To add a stream, simply add it to the request. To edit a stream, simply edit it in the request. The LTS edition has additional requests that allow per-stream changing of the configuration.
  void CheckStreams(JSON::Value & in, JSON::Value & out){
    //check for new streams and updates
    AddStreams(in, out);

    //check for deleted streams
    std::set<std::string> toDelete;
    for (JSON::ObjIter jit = out.ObjBegin(); jit != out.ObjEnd(); jit++){
      if ( !in.isMember(jit->first)){
        toDelete.insert(jit->first);
        Log("STRM", std::string("Deleted stream ") + jit->first);
      }
    }
    //actually delete the streams
    while (toDelete.size() > 0){
      std::string deleting = *(toDelete.begin());
      out.removeMember(deleting);
      toDelete.erase(deleting);
    }

    //update old-style configurations to new-style
    for (JSON::ObjIter jit = in.ObjBegin(); jit != in.ObjEnd(); jit++){
      if (jit->second.isMember("channel")){
        if ( !jit->second.isMember("source")){
          jit->second["source"] = jit->second["channel"]["URL"];
        }
        jit->second.removeMember("channel");
      }
      if (jit->second.isMember("preset")){
        jit->second.removeMember("preset");
      }
    }

  }

} //Controller namespace
<commit_msg>Removed metadata parsing from controller for better stability and faster stream handling.<commit_after>#include <mist/procs.h>
#include <mist/config.h>
#include <mist/timing.h>
#include <mist/stream.h>
#include <mist/dtsc.h>
#include <mist/defines.h>
#include <mist/shared_memory.h>
#include "controller_streams.h"
#include "controller_capabilities.h"
#include "controller_storage.h"
#include "controller_statistics.h"
#include "controller_limits.h" /*LTS*/
#include <sys/stat.h>
#include <map>

///\brief Holds everything unique to the controller.
namespace Controller {

  ///\brief Checks whether two streams are equal.
  ///\param one The first stream for the comparison.
  ///\param two The second stream for the comparison.
  ///\return True if the streams are equal, false otherwise.
  bool streamsEqual(JSON::Value & one, JSON::Value & two){
    if (one.isMember("source") != two.isMember("source") || one["source"] != two["source"]){
      return false;
    }

    /// \todo Change this to use capabilities["inputs"] and only compare required/optional parameters.
    /// \todo Maybe change this to check for correct source and/or required parameters.

    //temporary: compare the two JSON::Value objects.
    return one==two;

    //nothing different? return true by default
    //return true;
  }

  ///\brief Checks the validity of a stream, updates internal stream status.
  ///\param name The name of the stream
  ///\param data The corresponding configuration values.
  void checkStream(std::string name, JSON::Value & data){
    std::string prevState = data["error"].asStringRef();
    data["online"] = (std::string)"Checking...";
    data.removeMember("error");
    std::string URL;
    if (data.isMember("channel") && data["channel"].isMember("URL")){
      URL = data["channel"]["URL"].asString();
    }
    if (data.isMember("source")){
      URL = data["source"].asString();
    }
    if (URL == ""){
      data["error"] = "Stream offline: Missing source parameter!";
      if (data["error"].asStringRef() != prevState){
        Log("STRM", "Error for stream " + name + "! Source parameter missing.");
      }
      return;
    }
    if (URL.substr(0, 1) != "/"){
      //push-style stream
      return;
    }
    if (URL.substr(0, 1) == "/"){
      //vod-style stream
      data.removeMember("error");
      struct stat fileinfo;
      if (stat(URL.c_str(), &fileinfo) != 0){
        data["error"] = "Stream offline: Not found: " + URL;
        if (data["error"].asStringRef() != prevState){
          Log("BUFF", "Warning for VoD stream " + name + "! File not found: " + URL);
        }
        data["online"] = 0;
        return;
      }
      if (!hasViewers(name)){
        if ( !data.isMember("error")){
          data["error"] = "Available";
        }
        data["online"] = 2;
      }else{
        data["online"] = 1;
      }
      checkServerLimits(); /*LTS*/
      return;
    }
    //not recognized
    data["error"] = "Invalid source format";
    if (data["error"].asStringRef() != prevState){
      Log("STRM", "Invalid source format for stream " + name + "!");
    }
    return;
  }

  ///\brief Checks all streams, restoring if needed.
  ///\param data The stream configuration for the server.
  void CheckAllStreams(JSON::Value & data){
    long long int currTime = Util::epoch();
    for (JSON::ObjIter jit = data.ObjBegin(); jit != data.ObjEnd(); jit++){
      checkStream(jit->first, jit->second);
      if (!jit->second.isMember("name")){
        jit->second["name"] = jit->first;
      }
      if (!hasViewers(jit->first)){
        if (jit->second.isMember("source") && jit->second["source"].asString().substr(0, 1) == "/" && jit->second.isMember("error")
            && jit->second["error"].asString().substr(0,15) != "Stream offline:"){
          jit->second["online"] = 2;
        }else{
          if (jit->second.isMember("error") && jit->second["error"].asString() == "Available"){
            jit->second.removeMember("error");
          }
          jit->second["online"] = 0;
        }
        checkServerLimits(); /*LTS*/
      }else{
        // assume all is fine
        jit->second.removeMember("error");
        jit->second["online"] = 1;
      }
    }
    static JSON::Value strlist;
    bool changed = false;
    if (strlist["config"] != Storage["config"]){
      strlist["config"] = Storage["config"];
      changed = true;
    }
    if (strlist["streams"] != Storage["streams"]){
      strlist["streams"] = Storage["streams"];
      changed = true;
    }
    if (changed){
      writeConfig();
    }
  }

  void AddStreams(JSON::Value & in, JSON::Value & out){
    //check for new streams and updates
    for (JSON::ObjIter jit = in.ObjBegin(); jit != in.ObjEnd(); jit++){
      if (out.isMember(jit->first)){
        if ( !streamsEqual(jit->second, out[jit->first])){
          out[jit->first] = jit->second;
          out[jit->first]["name"] = jit->first;
          Log("STRM", std::string("Updated stream ") + jit->first);
        }
      }else{
        out[jit->first] = jit->second;
        out[jit->first]["name"] = jit->first;
        Log("STRM", std::string("New stream ") + jit->first);
      }
    }
  }

  ///\brief Parse a given stream configuration.
  ///\param in The requested configuration.
  ///\param out The new configuration after parsing.
  ///
  /// \api
  /// `"streams"` requests take the form of:
  /// ~~~~~~~~~~~~~~~{.js}
  /// {
  ///   "streamname_here": { //name of the stream
  ///     "source": "/mnt/media/a.dtsc" //full path to a VoD file, or "push://" followed by the IP or hostname of the machine allowed to push live data. Empty means everyone is allowed to push live data.
  ///     "DVR": 30000 //optional. For live streams, indicates the requested minimum size of the available DVR buffer in milliseconds.
  ///   },
  ///   //the above structure repeated for all configured streams
  /// }
  /// ~~~~~~~~~~~~~~~
  /// and are responded to as:
  /// ~~~~~~~~~~~~~~~{.js}
  /// {
  ///   "streamname_here": { //name of the configured stream
  ///     "error": "Available", //error state, if any. "Available" is a special value for VoD streams, indicating it has no current viewers (is not active), but is available for activation.
  ///     "h_meta": 1398113185, //unix time the stream header (if any) was last processed for metadata
  ///     "l_meta": 1398115447, //unix time the stream itself was last processed for metadata
  ///     "meta": { //available metadata for this stream, if any
  ///       "format": "dtsc", //detected media source format
  ///       "tracks": { //list of tracks in this stream
  ///         "audio_AAC_2ch_48000hz_2": {//human-readable track name
  ///           "bps": 16043,
  ///           "channels": 2,
  ///           "codec": "AAC",
  ///           "firstms": 0,
  ///           "init": "\u0011Vå\u0000",
  ///           "lastms": 596480,
  ///           "rate": 48000,
  ///           "size": 16,
  ///           "trackid": 2,
  ///           "type": "audio"
  ///         },
  ///         //the above structure repeated for all tracks
  ///       },
  ///       "vod": 1 //indicates VoD stream, or "live" to indicated live stream.
  ///     },
  ///     "name": "a", //the stream name, guaranteed to be equal to the object name.
  ///     "online": 2, //online state. 0 = error, 1 = active, 2 = inactive.
  ///     "source": "/home/thulinma/a.dtsc" //source for this stream, as configured.
  ///   },
  ///   //the above structure repeated for all configured streams
  /// }
  /// ~~~~~~~~~~~~~~~
  /// Through this request, ALL streams must always be configured. To remove a stream, simply leave it out of the request. To add a stream, simply add it to the request. To edit a stream, simply edit it in the request. The LTS edition has additional requests that allow per-stream changing of the configuration.
  void CheckStreams(JSON::Value & in, JSON::Value & out){
    //check for new streams and updates
    AddStreams(in, out);

    //check for deleted streams
    std::set<std::string> toDelete;
    for (JSON::ObjIter jit = out.ObjBegin(); jit != out.ObjEnd(); jit++){
      if ( !in.isMember(jit->first)){
        toDelete.insert(jit->first);
        Log("STRM", std::string("Deleted stream ") + jit->first);
      }
    }
    //actually delete the streams
    while (toDelete.size() > 0){
      std::string deleting = *(toDelete.begin());
      out.removeMember(deleting);
      toDelete.erase(deleting);
    }

    //update old-style configurations to new-style
    for (JSON::ObjIter jit = in.ObjBegin(); jit != in.ObjEnd(); jit++){
      if (jit->second.isMember("channel")){
        if ( !jit->second.isMember("source")){
          jit->second["source"] = jit->second["channel"]["URL"];
        }
        jit->second.removeMember("channel");
      }
      if (jit->second.isMember("preset")){
        jit->second.removeMember("preset");
      }
    }

  }

} //Controller namespace
<|endoftext|>


<commit_before>/*
 * Copyright 2015 gRPC authors.
 *
 * 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 <grpcpp/completion_queue.h>

#include <memory>

#include <grpc/grpc.h>
#include <grpc/support/cpu.h>
#include <grpc/support/log.h>
#include <grpcpp/impl/grpc_library.h>
#include <grpcpp/support/time.h>

#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/gprpp/thd.h"

namespace grpc {
namespace {

internal::GrpcLibraryInitializer g_gli_initializer;

gpr_once g_once_init_callback_alternative = GPR_ONCE_INIT;
grpc_core::ManualConstructor<grpc_core::Mutex> g_callback_alternative_mu;

// Implement a ref-counted callback CQ for global use in the alternative
// implementation so that its threads are only created once. Do this using
// explicit ref-counts and raw pointers rather than a shared-ptr since that
// has a non-trivial destructor and thus can't be used for global variables.
struct CallbackAlternativeCQ {
  int refs = 0;         // GUARDED_BY(g_callback_alternative_mu);
  CompletionQueue* cq;  // GUARDED_BY(g_callback_alternative_mu);
  std::vector<grpc_core::Thread>*
      nexting_threads;  // GUARDED_BY(g_callback_alternative_mu);

  CompletionQueue* Ref() {
    grpc_core::MutexLock lock(&*g_callback_alternative_mu);
    refs++;
    if (refs == 1) {
      cq = new CompletionQueue;
      int num_nexting_threads = GPR_CLAMP(gpr_cpu_num_cores() / 2, 2, 16);
      nexting_threads = new std::vector<grpc_core::Thread>;
      for (int i = 0; i < num_nexting_threads; i++) {
        nexting_threads->emplace_back(
            "nexting_thread",
            [](void* arg) {
              grpc_completion_queue* cq =
                  static_cast<CompletionQueue*>(arg)->cq();
              while (true) {
                // Use the raw Core next function rather than the C++ Next since
                // Next incorporates FinalizeResult and we actually want that
                // called from the callback functor itself.
                // TODO(vjpai): Migrate below to next without a timeout or idle
                // phase. That's currently starving out some other polling,
                // though.
                auto ev = grpc_completion_queue_next(
                    cq,
                    gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
                                 gpr_time_from_millis(1000, GPR_TIMESPAN)),
                    nullptr);
                if (ev.type == GRPC_QUEUE_SHUTDOWN) {
                  return;
                }
                if (ev.type == GRPC_QUEUE_TIMEOUT) {
                  gpr_sleep_until(
                      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
                                   gpr_time_from_millis(100, GPR_TIMESPAN)));
                  continue;
                }
                GPR_DEBUG_ASSERT(ev.type == GRPC_OP_COMPLETE);
                // We can always execute the callback inline rather than
                // pushing it to another Executor thread because this
                // thread is definitely running on a background thread, does not
                // hold any application locks before executing the callback,
                // and cannot be entered recursively.
                auto* functor =
                    static_cast<grpc_experimental_completion_queue_functor*>(
                        ev.tag);
                functor->functor_run(functor, ev.success);
              }
            },
            cq);
      }
      for (auto& th : *nexting_threads) {
        th.Start();
      }
    }
    return cq;
  }

  void Unref() {
    grpc_core::MutexLock lock(&*g_callback_alternative_mu);
    refs--;
    if (refs == 0) {
      cq->Shutdown();
      for (auto& th : *nexting_threads) {
        th.Join();
      }
      delete nexting_threads;
      delete cq;
    }
  }
};

CallbackAlternativeCQ g_callback_alternative_cq;

}  // namespace

// 'CompletionQueue' constructor can safely call GrpcLibraryCodegen(false) here
// i.e not have GrpcLibraryCodegen call grpc_init(). This is because, to create
// a 'grpc_completion_queue' instance (which is being passed as the input to
// this constructor), one must have already called grpc_init().
CompletionQueue::CompletionQueue(grpc_completion_queue* take)
    : GrpcLibraryCodegen(false), cq_(take) {
  InitialAvalanching();
}

void CompletionQueue::Shutdown() {
  g_gli_initializer.summon();
#ifndef NDEBUG
  if (!ServerListEmpty()) {
    gpr_log(GPR_ERROR,
            "CompletionQueue shutdown being shutdown before its server.");
  }
#endif
  CompleteAvalanching();
}

CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal(
    void** tag, bool* ok, gpr_timespec deadline) {
  for (;;) {
    auto ev = grpc_completion_queue_next(cq_, deadline, nullptr);
    switch (ev.type) {
      case GRPC_QUEUE_TIMEOUT:
        return TIMEOUT;
      case GRPC_QUEUE_SHUTDOWN:
        return SHUTDOWN;
      case GRPC_OP_COMPLETE:
        auto core_cq_tag =
            static_cast<::grpc::internal::CompletionQueueTag*>(ev.tag);
        *ok = ev.success != 0;
        *tag = core_cq_tag;
        if (core_cq_tag->FinalizeResult(tag, ok)) {
          return GOT_EVENT;
        }
        break;
    }
  }
}

CompletionQueue::CompletionQueueTLSCache::CompletionQueueTLSCache(
    CompletionQueue* cq)
    : cq_(cq), flushed_(false) {
  grpc_completion_queue_thread_local_cache_init(cq_->cq_);
}

CompletionQueue::CompletionQueueTLSCache::~CompletionQueueTLSCache() {
  GPR_ASSERT(flushed_);
}

bool CompletionQueue::CompletionQueueTLSCache::Flush(void** tag, bool* ok) {
  int res = 0;
  void* res_tag;
  flushed_ = true;
  if (grpc_completion_queue_thread_local_cache_flush(cq_->cq_, &res_tag,
                                                     &res)) {
    auto core_cq_tag =
        static_cast<::grpc::internal::CompletionQueueTag*>(res_tag);
    *ok = res == 1;
    if (core_cq_tag->FinalizeResult(tag, ok)) {
      return true;
    }
  }
  return false;
}

CompletionQueue* CompletionQueue::CallbackAlternativeCQ() {
  gpr_once_init(&g_once_init_callback_alternative,
                [] { g_callback_alternative_mu.Init(); });
  return g_callback_alternative_cq.Ref();
}

void CompletionQueue::ReleaseCallbackAlternativeCQ(CompletionQueue* cq) {
  GPR_DEBUG_ASSERT(cq == g_callback_alternative_cq.cq);
  g_callback_alternative_cq.Unref();
}

}  // namespace grpc
<commit_msg>Fix unused param warning<commit_after>/*
 * Copyright 2015 gRPC authors.
 *
 * 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 <grpcpp/completion_queue.h>

#include <memory>

#include <grpc/grpc.h>
#include <grpc/support/cpu.h>
#include <grpc/support/log.h>
#include <grpcpp/impl/grpc_library.h>
#include <grpcpp/support/time.h>

#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/gprpp/thd.h"

namespace grpc {
namespace {

internal::GrpcLibraryInitializer g_gli_initializer;

gpr_once g_once_init_callback_alternative = GPR_ONCE_INIT;
grpc_core::ManualConstructor<grpc_core::Mutex> g_callback_alternative_mu;

// Implement a ref-counted callback CQ for global use in the alternative
// implementation so that its threads are only created once. Do this using
// explicit ref-counts and raw pointers rather than a shared-ptr since that
// has a non-trivial destructor and thus can't be used for global variables.
struct CallbackAlternativeCQ {
  int refs = 0;         // GUARDED_BY(g_callback_alternative_mu);
  CompletionQueue* cq;  // GUARDED_BY(g_callback_alternative_mu);
  std::vector<grpc_core::Thread>*
      nexting_threads;  // GUARDED_BY(g_callback_alternative_mu);

  CompletionQueue* Ref() {
    grpc_core::MutexLock lock(&*g_callback_alternative_mu);
    refs++;
    if (refs == 1) {
      cq = new CompletionQueue;
      int num_nexting_threads = GPR_CLAMP(gpr_cpu_num_cores() / 2, 2, 16);
      nexting_threads = new std::vector<grpc_core::Thread>;
      for (int i = 0; i < num_nexting_threads; i++) {
        nexting_threads->emplace_back(
            "nexting_thread",
            [](void* arg) {
              grpc_completion_queue* cq =
                  static_cast<CompletionQueue*>(arg)->cq();
              while (true) {
                // Use the raw Core next function rather than the C++ Next since
                // Next incorporates FinalizeResult and we actually want that
                // called from the callback functor itself.
                // TODO(vjpai): Migrate below to next without a timeout or idle
                // phase. That's currently starving out some other polling,
                // though.
                auto ev = grpc_completion_queue_next(
                    cq,
                    gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
                                 gpr_time_from_millis(1000, GPR_TIMESPAN)),
                    nullptr);
                if (ev.type == GRPC_QUEUE_SHUTDOWN) {
                  return;
                }
                if (ev.type == GRPC_QUEUE_TIMEOUT) {
                  gpr_sleep_until(
                      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
                                   gpr_time_from_millis(100, GPR_TIMESPAN)));
                  continue;
                }
                GPR_DEBUG_ASSERT(ev.type == GRPC_OP_COMPLETE);
                // We can always execute the callback inline rather than
                // pushing it to another Executor thread because this
                // thread is definitely running on a background thread, does not
                // hold any application locks before executing the callback,
                // and cannot be entered recursively.
                auto* functor =
                    static_cast<grpc_experimental_completion_queue_functor*>(
                        ev.tag);
                functor->functor_run(functor, ev.success);
              }
            },
            cq);
      }
      for (auto& th : *nexting_threads) {
        th.Start();
      }
    }
    return cq;
  }

  void Unref() {
    grpc_core::MutexLock lock(&*g_callback_alternative_mu);
    refs--;
    if (refs == 0) {
      cq->Shutdown();
      for (auto& th : *nexting_threads) {
        th.Join();
      }
      delete nexting_threads;
      delete cq;
    }
  }
};

CallbackAlternativeCQ g_callback_alternative_cq;

}  // namespace

// 'CompletionQueue' constructor can safely call GrpcLibraryCodegen(false) here
// i.e not have GrpcLibraryCodegen call grpc_init(). This is because, to create
// a 'grpc_completion_queue' instance (which is being passed as the input to
// this constructor), one must have already called grpc_init().
CompletionQueue::CompletionQueue(grpc_completion_queue* take)
    : GrpcLibraryCodegen(false), cq_(take) {
  InitialAvalanching();
}

void CompletionQueue::Shutdown() {
  g_gli_initializer.summon();
#ifndef NDEBUG
  if (!ServerListEmpty()) {
    gpr_log(GPR_ERROR,
            "CompletionQueue shutdown being shutdown before its server.");
  }
#endif
  CompleteAvalanching();
}

CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal(
    void** tag, bool* ok, gpr_timespec deadline) {
  for (;;) {
    auto ev = grpc_completion_queue_next(cq_, deadline, nullptr);
    switch (ev.type) {
      case GRPC_QUEUE_TIMEOUT:
        return TIMEOUT;
      case GRPC_QUEUE_SHUTDOWN:
        return SHUTDOWN;
      case GRPC_OP_COMPLETE:
        auto core_cq_tag =
            static_cast<::grpc::internal::CompletionQueueTag*>(ev.tag);
        *ok = ev.success != 0;
        *tag = core_cq_tag;
        if (core_cq_tag->FinalizeResult(tag, ok)) {
          return GOT_EVENT;
        }
        break;
    }
  }
}

CompletionQueue::CompletionQueueTLSCache::CompletionQueueTLSCache(
    CompletionQueue* cq)
    : cq_(cq), flushed_(false) {
  grpc_completion_queue_thread_local_cache_init(cq_->cq_);
}

CompletionQueue::CompletionQueueTLSCache::~CompletionQueueTLSCache() {
  GPR_ASSERT(flushed_);
}

bool CompletionQueue::CompletionQueueTLSCache::Flush(void** tag, bool* ok) {
  int res = 0;
  void* res_tag;
  flushed_ = true;
  if (grpc_completion_queue_thread_local_cache_flush(cq_->cq_, &res_tag,
                                                     &res)) {
    auto core_cq_tag =
        static_cast<::grpc::internal::CompletionQueueTag*>(res_tag);
    *ok = res == 1;
    if (core_cq_tag->FinalizeResult(tag, ok)) {
      return true;
    }
  }
  return false;
}

CompletionQueue* CompletionQueue::CallbackAlternativeCQ() {
  gpr_once_init(&g_once_init_callback_alternative,
                [] { g_callback_alternative_mu.Init(); });
  return g_callback_alternative_cq.Ref();
}

void CompletionQueue::ReleaseCallbackAlternativeCQ(CompletionQueue* cq) {
  (void)cq;
  GPR_DEBUG_ASSERT(cq == g_callback_alternative_cq.cq);
  g_callback_alternative_cq.Unref();
}

}  // namespace grpc
<|endoftext|>


<commit_before>/*
 * DesktopMainWindow.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "DesktopMainWindow.hpp"

#include <algorithm>

#include <QtGui>
#include <QtWebKit>

#include <boost/bind.hpp>
#include <boost/format.hpp>

#include <core/FilePath.hpp>
#include <core/system/System.hpp>

#include "DesktopGwtCallback.hpp"
#include "DesktopMenuCallback.hpp"
#include "DesktopWebView.hpp"
#include "DesktopOptions.hpp"
#include "DesktopSlotBinders.hpp"
#include "DesktopUtils.hpp"
#include "DesktopSessionLauncher.hpp"

using namespace core;

namespace desktop {

MainWindow::MainWindow(QUrl url) :
      GwtWindow(false, false, url, NULL),
      menuCallback_(this),
      gwtCallback_(this, this),
      updateChecker_(this),
      pSessionLauncher_(NULL),
      pCurrentSessionProcess_(NULL)
{
   quitConfirmed_ = false;
   pToolbar_->setVisible(false);

   // initialize zoom levels
   zoomLevels_.push_back(0.7);
   zoomLevels_.push_back(0.8);
   zoomLevels_.push_back(0.9);
   zoomLevels_.push_back(1.0);
   zoomLevels_.push_back(1.1);
   zoomLevels_.push_back(1.20);
   zoomLevels_.push_back(1.30);
   zoomLevels_.push_back(1.40);
   zoomLevels_.push_back(1.50);
   zoomLevels_.push_back(1.75);
   zoomLevels_.push_back(2.00);

   // Dummy menu bar to deal with the fact that
   // the real menu bar isn't ready until well
   // after startup.
   QMenuBar* pMainMenuStub = new QMenuBar(this);
   pMainMenuStub->addMenu(QString::fromUtf8("File"));
   pMainMenuStub->addMenu(QString::fromUtf8("Edit"));
   pMainMenuStub->addMenu(QString::fromUtf8("Code"));
   pMainMenuStub->addMenu(QString::fromUtf8("View"));
   pMainMenuStub->addMenu(QString::fromUtf8("Plots"));
   pMainMenuStub->addMenu(QString::fromUtf8("Session"));
   pMainMenuStub->addMenu(QString::fromUtf8("Project"));
   pMainMenuStub->addMenu(QString::fromUtf8("Build"));
   pMainMenuStub->addMenu(QString::fromUtf8("Tools"));
   pMainMenuStub->addMenu(QString::fromUtf8("Help"));
   setMenuBar(pMainMenuStub);

   connect(&menuCallback_, SIGNAL(menuBarCompleted(QMenuBar*)),
           this, SLOT(setMenuBar(QMenuBar*)));
   connect(&menuCallback_, SIGNAL(commandInvoked(QString)),
           this, SLOT(invokeCommand(QString)));
   connect(&menuCallback_, SIGNAL(manageCommand(QString,QAction*)),
           this, SLOT(manageCommand(QString,QAction*)));

   connect(&menuCallback_, SIGNAL(zoomIn()), this, SLOT(zoomIn()));
   connect(&menuCallback_, SIGNAL(zoomOut()), this, SLOT(zoomOut()));

   connect(&gwtCallback_, SIGNAL(workbenchInitialized()),
           this, SIGNAL(firstWorkbenchInitialized()));
   connect(&gwtCallback_, SIGNAL(workbenchInitialized()),
           this, SLOT(onWorkbenchInitialized()));

   connect(webView(), SIGNAL(onCloseWindowShortcut()),
           this, SLOT(onCloseWindowShortcut()));

   connect(qApp, SIGNAL(commitDataRequest(QSessionManager&)),
           this, SLOT(commitDataRequest(QSessionManager&)),
           Qt::DirectConnection);

   setWindowIcon(QIcon(QString::fromAscii(":/icons/RStudio.ico")));

   setWindowTitle(QString::fromAscii("RStudio"));

#ifdef Q_OS_MAC
   QMenuBar* pDefaultMenu = new QMenuBar();
   pDefaultMenu->addMenu(new WindowMenu());
#endif

   desktop::enableFullscreenMode(this, true);

   //setContentsMargins(10000, 0, -10000, 0);
   setStyleSheet(QString::fromAscii("QMainWindow { background: #e1e2e5; }"));
}

QString MainWindow::getSumatraPdfExePath()
{
   QWebFrame* pMainFrame = webView()->page()->mainFrame();
   QString sumatraPath = pMainFrame->evaluateJavaScript(QString::fromAscii(
                    "window.desktopHooks.getSumatraPdfExePath()")).toString();
   return sumatraPath;
}

void MainWindow::launchSession(bool reload)
{
   Error error = pSessionLauncher_->launchNextSession(reload);
   if (error)
   {
      LOG_ERROR(error);

      showMessageBox(QMessageBox::Critical,
                     this,
                     QString::fromUtf8("RStudio"),
                     QString::fromUtf8("The R session failed to start."));

      quit();
   }
}

void MainWindow::onCloseWindowShortcut()
{
   QWebFrame* pMainFrame = webView()->page()->mainFrame();

   bool closeSourceDocEnabled = pMainFrame->evaluateJavaScript(
      QString::fromAscii(
         "window.desktopHooks.isCommandEnabled('closeSourceDoc')")).toBool();

   if (!closeSourceDocEnabled)
      close();
}

void MainWindow::onWorkbenchInitialized()
{
   //QTimer::singleShot(300, this, SLOT(resetMargins()));

   // reset state (in case this occurred in response to a manual reload
   // or reload for a new project context)
   quitConfirmed_ = false;

   // see if there is a project dir to display in the titlebar
   // if there are unsaved changes then resolve them before exiting
   QVariant vProjectDir = webView()->page()->mainFrame()->evaluateJavaScript(
         QString::fromAscii("window.desktopHooks.getActiveProjectDir()"));
   QString projectDir = vProjectDir.toString();
   if (projectDir.length() > 0)
      setWindowTitle(projectDir + QString::fromAscii(" - RStudio"));
   else
      setWindowTitle(QString::fromAscii("RStudio"));

   avoidMoveCursorIfNecessary();

   // check for updates
   updateChecker_.performCheck(false);
}

void MainWindow::resetMargins()
{
   setContentsMargins(0, 0, 0, 0);
}

// this notification occurs when windows or X11 is shutting
// down -- in this case we want to be a good citizen and just
// exit right away so we notify the gwt callback that a legit
// quit and exit is on the way and we set the quitConfirmed_
// flag so no prompting occurs (note that source documents
// have already been auto-saved so will be restored next time
// the current project context is opened)
void MainWindow::commitDataRequest(QSessionManager &manager)
{
   gwtCallback_.setPendingQuit(PendingQuitAndExit);
   quitConfirmed_ = true;
}

void MainWindow::loadUrl(const QUrl& url)
{
   webView()->setBaseUrl(url);
   webView()->load(url);
}

void MainWindow::quit()
{
   quitConfirmed_ = true;
   close();
}

void MainWindow::onJavaScriptWindowObjectCleared()
{
   double zoomLevel = options().zoomLevel();
   if (zoomLevel != webView()->zoomFactor())
      webView()->setZoomFactor(zoomLevel);

   webView()->page()->mainFrame()->addToJavaScriptWindowObject(
         QString::fromAscii("desktop"),
         &gwtCallback_,
         QScriptEngine::QtOwnership);
   webView()->page()->mainFrame()->addToJavaScriptWindowObject(
         QString::fromAscii("desktopMenuCallback"),
         &menuCallback_,
         QScriptEngine::QtOwnership);
}

void MainWindow::invokeCommand(QString commandId)
{
   webView()->page()->mainFrame()->evaluateJavaScript(
         QString::fromAscii("window.desktopHooks.invokeCommand('") + commandId + QString::fromAscii("');"));
}

void MainWindow::zoomIn()
{
   // get next greatest value
   std::vector<double>::const_iterator it = std::upper_bound(
            zoomLevels_.begin(), zoomLevels_.end(), options().zoomLevel());
   if (it != zoomLevels_.end())
   {
      options().setZoomLevel(*it);
      webView()->reload();
   }
}

void MainWindow::zoomOut()
{
   // get next smallest value
   std::vector<double>::const_iterator it = std::lower_bound(
            zoomLevels_.begin(), zoomLevels_.end(), options().zoomLevel());
   if (it != zoomLevels_.begin() && it != zoomLevels_.end())
   {
      options().setZoomLevel(*(it-1));
      webView()->reload();
   }
}

void MainWindow::manageCommand(QString cmdId, QAction* action)
{
   QWebFrame* pMainFrame = webView()->page()->mainFrame();
   action->setVisible(pMainFrame->evaluateJavaScript(
         QString::fromAscii("window.desktopHooks.isCommandVisible('") + cmdId + QString::fromAscii("')")).toBool());
   action->setEnabled(pMainFrame->evaluateJavaScript(
         QString::fromAscii("window.desktopHooks.isCommandEnabled('") + cmdId + QString::fromAscii("')")).toBool());
   action->setText(pMainFrame->evaluateJavaScript(
         QString::fromAscii("window.desktopHooks.getCommandLabel('") + cmdId + QString::fromAscii("')")).toString());
}

void MainWindow::evaluateJavaScript(QString jsCode)
{
   QWebFrame* pMainFrame = webView()->page()->mainFrame();
   pMainFrame->evaluateJavaScript(jsCode);
}

void MainWindow::closeEvent(QCloseEvent* pEvent)
{
   QWebFrame* pFrame = webView()->page()->mainFrame();
   if (!pFrame)
   {
       pEvent->accept();
       return;
   }

   QVariant hasQuitR = pFrame->evaluateJavaScript(QString::fromAscii("!!window.desktopHooks"));

   if (quitConfirmed_
       || !hasQuitR.toBool()
       || pCurrentSessionProcess_ == NULL
       || pCurrentSessionProcess_->state() != QProcess::Running)
   {
      pEvent->accept();
   }
   else
   {
      pFrame->evaluateJavaScript(QString::fromAscii("window.desktopHooks.quitR()"));
      pEvent->ignore();
   }
}

void MainWindow::setMenuBar(QMenuBar *pMenubar)
{
   delete menuBar();
   this->QMainWindow::setMenuBar(pMenubar);
}

void MainWindow::openFileInRStudio(QString path)
{
   QFileInfo fileInfo(path);
   if (!fileInfo.isAbsolute() || !fileInfo.exists() || !fileInfo.isFile())
      return;

   path = path.replace(QString::fromAscii("\\"), QString::fromAscii("\\\\"))
          .replace(QString::fromAscii("\""), QString::fromAscii("\\\""))
          .replace(QString::fromAscii("\n"), QString::fromAscii("\\n"));

   webView()->page()->mainFrame()->evaluateJavaScript(
         QString::fromAscii("window.desktopHooks.openFile(\"") + path + QString::fromAscii("\")"));
}

void MainWindow::checkForUpdates()
{
   updateChecker_.performCheck(true);
}

void MainWindow::onPdfViewerClosed(QString pdfPath)
{
   webView()->page()->mainFrame()->evaluateJavaScript(
            QString::fromAscii("window.synctexNotifyPdfViewerClosed(\"") +
                                         pdfPath + QString::fromAscii("\")"));
}

void MainWindow::onPdfViewerSyncSource(QString srcFile, int line, int column)
{
   boost::format fmt("window.desktopSynctexInverseSearch(\"%1%\", %2%, %3%)");
   std::string js = boost::str(fmt % srcFile.toStdString() % line % column);

   webView()->page()->mainFrame()->evaluateJavaScript(
                                                   QString::fromStdString(js));
}

// private interface for SessionLauncher

void MainWindow::setSessionLauncher(SessionLauncher* pSessionLauncher)
{
   pSessionLauncher_ = pSessionLauncher;
}

void MainWindow::setSessionProcess(QProcess* pSessionProcess)
{
   pCurrentSessionProcess_ = pSessionProcess;
}

// allow SessionLauncher to collect restart requests from GwtCallback
int MainWindow::collectPendingQuitRequest()
{
   return gwtCallback_.collectPendingQuitRequest();
}

bool MainWindow::desktopHooksAvailable()
{
   return webView()->page()->mainFrame()->evaluateJavaScript(
                        QString::fromAscii("!!window.desktopHooks")).toBool();
}

void MainWindow::onActivated()
{
   if (desktopHooksAvailable())
      invokeCommand(QString::fromAscii("vcsRefreshNoError"));
}

} // namespace desktop
<commit_msg>eliminate low magification zooming (caused scrolling performance problems)<commit_after>/*
 * DesktopMainWindow.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "DesktopMainWindow.hpp"

#include <algorithm>

#include <QtGui>
#include <QtWebKit>

#include <boost/bind.hpp>
#include <boost/format.hpp>

#include <core/FilePath.hpp>
#include <core/system/System.hpp>

#include "DesktopGwtCallback.hpp"
#include "DesktopMenuCallback.hpp"
#include "DesktopWebView.hpp"
#include "DesktopOptions.hpp"
#include "DesktopSlotBinders.hpp"
#include "DesktopUtils.hpp"
#include "DesktopSessionLauncher.hpp"

using namespace core;

namespace desktop {

MainWindow::MainWindow(QUrl url) :
      GwtWindow(false, false, url, NULL),
      menuCallback_(this),
      gwtCallback_(this, this),
      updateChecker_(this),
      pSessionLauncher_(NULL),
      pCurrentSessionProcess_(NULL)
{
   quitConfirmed_ = false;
   pToolbar_->setVisible(false);

   // initialize zoom levels
   zoomLevels_.push_back(1.0);
   zoomLevels_.push_back(1.1);
   zoomLevels_.push_back(1.20);
   zoomLevels_.push_back(1.30);
   zoomLevels_.push_back(1.40);
   zoomLevels_.push_back(1.50);
   zoomLevels_.push_back(1.75);
   zoomLevels_.push_back(2.00);

   // Dummy menu bar to deal with the fact that
   // the real menu bar isn't ready until well
   // after startup.
   QMenuBar* pMainMenuStub = new QMenuBar(this);
   pMainMenuStub->addMenu(QString::fromUtf8("File"));
   pMainMenuStub->addMenu(QString::fromUtf8("Edit"));
   pMainMenuStub->addMenu(QString::fromUtf8("Code"));
   pMainMenuStub->addMenu(QString::fromUtf8("View"));
   pMainMenuStub->addMenu(QString::fromUtf8("Plots"));
   pMainMenuStub->addMenu(QString::fromUtf8("Session"));
   pMainMenuStub->addMenu(QString::fromUtf8("Project"));
   pMainMenuStub->addMenu(QString::fromUtf8("Build"));
   pMainMenuStub->addMenu(QString::fromUtf8("Tools"));
   pMainMenuStub->addMenu(QString::fromUtf8("Help"));
   setMenuBar(pMainMenuStub);

   connect(&menuCallback_, SIGNAL(menuBarCompleted(QMenuBar*)),
           this, SLOT(setMenuBar(QMenuBar*)));
   connect(&menuCallback_, SIGNAL(commandInvoked(QString)),
           this, SLOT(invokeCommand(QString)));
   connect(&menuCallback_, SIGNAL(manageCommand(QString,QAction*)),
           this, SLOT(manageCommand(QString,QAction*)));

   connect(&menuCallback_, SIGNAL(zoomIn()), this, SLOT(zoomIn()));
   connect(&menuCallback_, SIGNAL(zoomOut()), this, SLOT(zoomOut()));

   connect(&gwtCallback_, SIGNAL(workbenchInitialized()),
           this, SIGNAL(firstWorkbenchInitialized()));
   connect(&gwtCallback_, SIGNAL(workbenchInitialized()),
           this, SLOT(onWorkbenchInitialized()));

   connect(webView(), SIGNAL(onCloseWindowShortcut()),
           this, SLOT(onCloseWindowShortcut()));

   connect(qApp, SIGNAL(commitDataRequest(QSessionManager&)),
           this, SLOT(commitDataRequest(QSessionManager&)),
           Qt::DirectConnection);

   setWindowIcon(QIcon(QString::fromAscii(":/icons/RStudio.ico")));

   setWindowTitle(QString::fromAscii("RStudio"));

#ifdef Q_OS_MAC
   QMenuBar* pDefaultMenu = new QMenuBar();
   pDefaultMenu->addMenu(new WindowMenu());
#endif

   desktop::enableFullscreenMode(this, true);

   //setContentsMargins(10000, 0, -10000, 0);
   setStyleSheet(QString::fromAscii("QMainWindow { background: #e1e2e5; }"));
}

QString MainWindow::getSumatraPdfExePath()
{
   QWebFrame* pMainFrame = webView()->page()->mainFrame();
   QString sumatraPath = pMainFrame->evaluateJavaScript(QString::fromAscii(
                    "window.desktopHooks.getSumatraPdfExePath()")).toString();
   return sumatraPath;
}

void MainWindow::launchSession(bool reload)
{
   Error error = pSessionLauncher_->launchNextSession(reload);
   if (error)
   {
      LOG_ERROR(error);

      showMessageBox(QMessageBox::Critical,
                     this,
                     QString::fromUtf8("RStudio"),
                     QString::fromUtf8("The R session failed to start."));

      quit();
   }
}

void MainWindow::onCloseWindowShortcut()
{
   QWebFrame* pMainFrame = webView()->page()->mainFrame();

   bool closeSourceDocEnabled = pMainFrame->evaluateJavaScript(
      QString::fromAscii(
         "window.desktopHooks.isCommandEnabled('closeSourceDoc')")).toBool();

   if (!closeSourceDocEnabled)
      close();
}

void MainWindow::onWorkbenchInitialized()
{
   //QTimer::singleShot(300, this, SLOT(resetMargins()));

   // reset state (in case this occurred in response to a manual reload
   // or reload for a new project context)
   quitConfirmed_ = false;

   // see if there is a project dir to display in the titlebar
   // if there are unsaved changes then resolve them before exiting
   QVariant vProjectDir = webView()->page()->mainFrame()->evaluateJavaScript(
         QString::fromAscii("window.desktopHooks.getActiveProjectDir()"));
   QString projectDir = vProjectDir.toString();
   if (projectDir.length() > 0)
      setWindowTitle(projectDir + QString::fromAscii(" - RStudio"));
   else
      setWindowTitle(QString::fromAscii("RStudio"));

   avoidMoveCursorIfNecessary();

   // check for updates
   updateChecker_.performCheck(false);
}

void MainWindow::resetMargins()
{
   setContentsMargins(0, 0, 0, 0);
}

// this notification occurs when windows or X11 is shutting
// down -- in this case we want to be a good citizen and just
// exit right away so we notify the gwt callback that a legit
// quit and exit is on the way and we set the quitConfirmed_
// flag so no prompting occurs (note that source documents
// have already been auto-saved so will be restored next time
// the current project context is opened)
void MainWindow::commitDataRequest(QSessionManager &manager)
{
   gwtCallback_.setPendingQuit(PendingQuitAndExit);
   quitConfirmed_ = true;
}

void MainWindow::loadUrl(const QUrl& url)
{
   webView()->setBaseUrl(url);
   webView()->load(url);
}

void MainWindow::quit()
{
   quitConfirmed_ = true;
   close();
}

void MainWindow::onJavaScriptWindowObjectCleared()
{
   double zoomLevel = options().zoomLevel();
   if (zoomLevel != webView()->zoomFactor())
      webView()->setZoomFactor(zoomLevel);

   webView()->page()->mainFrame()->addToJavaScriptWindowObject(
         QString::fromAscii("desktop"),
         &gwtCallback_,
         QScriptEngine::QtOwnership);
   webView()->page()->mainFrame()->addToJavaScriptWindowObject(
         QString::fromAscii("desktopMenuCallback"),
         &menuCallback_,
         QScriptEngine::QtOwnership);
}

void MainWindow::invokeCommand(QString commandId)
{
   webView()->page()->mainFrame()->evaluateJavaScript(
         QString::fromAscii("window.desktopHooks.invokeCommand('") + commandId + QString::fromAscii("');"));
}

void MainWindow::zoomIn()
{
   // get next greatest value
   std::vector<double>::const_iterator it = std::upper_bound(
            zoomLevels_.begin(), zoomLevels_.end(), options().zoomLevel());
   if (it != zoomLevels_.end())
   {
      options().setZoomLevel(*it);
      webView()->reload();
   }
}

void MainWindow::zoomOut()
{
   // get next smallest value
   std::vector<double>::const_iterator it = std::lower_bound(
            zoomLevels_.begin(), zoomLevels_.end(), options().zoomLevel());
   if (it != zoomLevels_.begin() && it != zoomLevels_.end())
   {
      options().setZoomLevel(*(it-1));
      webView()->reload();
   }
}

void MainWindow::manageCommand(QString cmdId, QAction* action)
{
   QWebFrame* pMainFrame = webView()->page()->mainFrame();
   action->setVisible(pMainFrame->evaluateJavaScript(
         QString::fromAscii("window.desktopHooks.isCommandVisible('") + cmdId + QString::fromAscii("')")).toBool());
   action->setEnabled(pMainFrame->evaluateJavaScript(
         QString::fromAscii("window.desktopHooks.isCommandEnabled('") + cmdId + QString::fromAscii("')")).toBool());
   action->setText(pMainFrame->evaluateJavaScript(
         QString::fromAscii("window.desktopHooks.getCommandLabel('") + cmdId + QString::fromAscii("')")).toString());
}

void MainWindow::evaluateJavaScript(QString jsCode)
{
   QWebFrame* pMainFrame = webView()->page()->mainFrame();
   pMainFrame->evaluateJavaScript(jsCode);
}

void MainWindow::closeEvent(QCloseEvent* pEvent)
{
   QWebFrame* pFrame = webView()->page()->mainFrame();
   if (!pFrame)
   {
       pEvent->accept();
       return;
   }

   QVariant hasQuitR = pFrame->evaluateJavaScript(QString::fromAscii("!!window.desktopHooks"));

   if (quitConfirmed_
       || !hasQuitR.toBool()
       || pCurrentSessionProcess_ == NULL
       || pCurrentSessionProcess_->state() != QProcess::Running)
   {
      pEvent->accept();
   }
   else
   {
      pFrame->evaluateJavaScript(QString::fromAscii("window.desktopHooks.quitR()"));
      pEvent->ignore();
   }
}

void MainWindow::setMenuBar(QMenuBar *pMenubar)
{
   delete menuBar();
   this->QMainWindow::setMenuBar(pMenubar);
}

void MainWindow::openFileInRStudio(QString path)
{
   QFileInfo fileInfo(path);
   if (!fileInfo.isAbsolute() || !fileInfo.exists() || !fileInfo.isFile())
      return;

   path = path.replace(QString::fromAscii("\\"), QString::fromAscii("\\\\"))
          .replace(QString::fromAscii("\""), QString::fromAscii("\\\""))
          .replace(QString::fromAscii("\n"), QString::fromAscii("\\n"));

   webView()->page()->mainFrame()->evaluateJavaScript(
         QString::fromAscii("window.desktopHooks.openFile(\"") + path + QString::fromAscii("\")"));
}

void MainWindow::checkForUpdates()
{
   updateChecker_.performCheck(true);
}

void MainWindow::onPdfViewerClosed(QString pdfPath)
{
   webView()->page()->mainFrame()->evaluateJavaScript(
            QString::fromAscii("window.synctexNotifyPdfViewerClosed(\"") +
                                         pdfPath + QString::fromAscii("\")"));
}

void MainWindow::onPdfViewerSyncSource(QString srcFile, int line, int column)
{
   boost::format fmt("window.desktopSynctexInverseSearch(\"%1%\", %2%, %3%)");
   std::string js = boost::str(fmt % srcFile.toStdString() % line % column);

   webView()->page()->mainFrame()->evaluateJavaScript(
                                                   QString::fromStdString(js));
}

// private interface for SessionLauncher

void MainWindow::setSessionLauncher(SessionLauncher* pSessionLauncher)
{
   pSessionLauncher_ = pSessionLauncher;
}

void MainWindow::setSessionProcess(QProcess* pSessionProcess)
{
   pCurrentSessionProcess_ = pSessionProcess;
}

// allow SessionLauncher to collect restart requests from GwtCallback
int MainWindow::collectPendingQuitRequest()
{
   return gwtCallback_.collectPendingQuitRequest();
}

bool MainWindow::desktopHooksAvailable()
{
   return webView()->page()->mainFrame()->evaluateJavaScript(
                        QString::fromAscii("!!window.desktopHooks")).toBool();
}

void MainWindow::onActivated()
{
   if (desktopHooksAvailable())
      invokeCommand(QString::fromAscii("vcsRefreshNoError"));
}

} // namespace desktop
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdint.h>
#include <chrono>

typedef unsigned char byte;

struct args
{
    byte *plain_ptr;
    uint64_t plain_num_bytes;
    byte *auth_ptr;
    uint64_t auth_num_bytes;
    byte *iv_ptr;
    byte *expanded_key_ptr;
    byte *out_ptr;
    byte *tag_ptr;
};

extern "C" void aes_key_expansion(byte *key_ptr, byte *key_expansion_ptr);
extern "C" void gcm_encrypt(args *a);
extern "C" int gcm_decrypt(args *a);

byte key[16] =
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
byte key_expansion[11 * 16];

byte plain[32] =
    { 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215,
      216, 217, 218, 99,  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
    };
byte auth[1]; // actually size 0
byte iv[16] =
    { 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 0, 0, 0, 0 };
byte out[32];
byte tag[16];

void printbytes(char *label, byte *b, int len)
{
    printf("%s:", label);
    for (int i = 0; i < len; i++) printf(" %2x", unsigned(b[i]));
    printf("\n");
}

int main()
{
    printf("hello\n");

    args a;
    a.plain_ptr = plain;
    a.plain_num_bytes = 19;
    a.auth_ptr = auth;
    a.auth_num_bytes = 0;
    a.iv_ptr = iv;
    a.expanded_key_ptr = key_expansion;
    a.out_ptr = out;
    a.tag_ptr = tag;
    printbytes("key", key, 16);
    aes_key_expansion(key, key_expansion);
    printbytes("key_expansion", key_expansion, 11 * 16);
    gcm_encrypt(&a);
    printbytes("cipher", out, 19);
    printbytes("tag", tag, 16);

    a.out_ptr = plain;
    a.plain_ptr = out;
    int ret = gcm_decrypt(&a);
    printf("gcm_decrypt returned %d\n", ret);
    printbytes("plaintext", plain, 19);

    int nblocks = 256;
    byte *plain2 = new byte[nblocks * 16];
    byte *out2 = new byte[nblocks * 16];
    for (int i = 0; i < nblocks * 16; i++)
    {
        plain2[i] = i % 256;
    }
    a.plain_ptr = plain2;
    a.plain_num_bytes = nblocks * 16;
    a.out_ptr = out2;
    for (int i = 0; i < 10; i++)
    {
        auto time1 = std::chrono::high_resolution_clock::now();
        int n = 10000;
        for (int j = 0; j < n; j++)
        {
            gcm_encrypt(&a);
        }
        auto time2 = std::chrono::high_resolution_clock::now();
        int dt = std::chrono::duration_cast<std::chrono::microseconds>(time2 - time1).count();
        printf("time = %d microseconds for %d iterations (%lf MB/s)\n", dt, n, double(n) * (nblocks * 16) / dt);
    }
    printbytes("cipher", out2, 16);
    printbytes("tag", tag, 16);

    printf("goodbye\n");
    return 0;
}
<commit_msg>Update the names used in the test function<commit_after>#include <stdio.h>
#include <stdint.h>
#include <chrono>

typedef unsigned char byte;

struct args
{
    byte *plain_ptr;
    uint64_t plain_num_bytes;
    byte *auth_ptr;
    uint64_t auth_num_bytes;
    byte *iv_ptr;
    byte *expanded_key_ptr;
    byte *out_ptr;
    byte *tag_ptr;
};

extern "C" void aes128_key_expansion(byte *key_ptr, byte *key_expansion_ptr);
extern "C" void gcm128_encrypt(args *a);
extern "C" int gcm128_decrypt(args *a);

byte key[16] =
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
byte key_expansion[11 * 16];

byte plain[32] =
    { 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215,
      216, 217, 218, 99,  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
    };
byte auth[1]; // actually size 0
byte iv[16] =
    { 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 0, 0, 0, 0 };
byte out[32];
byte tag[16];

void printbytes(char *label, byte *b, int len)
{
    printf("%s:", label);
    for (int i = 0; i < len; i++) printf(" %2x", unsigned(b[i]));
    printf("\n");
}

int main()
{
    printf("hello\n");

    args a;
    a.plain_ptr = plain;
    a.plain_num_bytes = 19;
    a.auth_ptr = auth;
    a.auth_num_bytes = 0;
    a.iv_ptr = iv;
    a.expanded_key_ptr = key_expansion;
    a.out_ptr = out;
    a.tag_ptr = tag;
    printbytes("key", key, 16);
    aes128_key_expansion(key, key_expansion);
    printbytes("key_expansion", key_expansion, 11 * 16);
    gcm128_encrypt(&a);
    printbytes("cipher", out, 19);
    printbytes("tag", tag, 16);

    a.out_ptr = plain;
    a.plain_ptr = out;
    int ret = gcm128_decrypt(&a);
    printf("gcm_decrypt returned %d\n", ret);
    printbytes("plaintext", plain, 19);

    int nblocks = 256;
    byte *plain2 = new byte[nblocks * 16];
    byte *out2 = new byte[nblocks * 16];
    for (int i = 0; i < nblocks * 16; i++)
    {
        plain2[i] = i % 256;
    }
    a.plain_ptr = plain2;
    a.plain_num_bytes = nblocks * 16;
    a.out_ptr = out2;
    for (int i = 0; i < 10; i++)
    {
        auto time1 = std::chrono::high_resolution_clock::now();
        int n = 10000;
        for (int j = 0; j < n; j++)
        {
            gcm128_encrypt(&a);
        }
        auto time2 = std::chrono::high_resolution_clock::now();
        int dt = std::chrono::duration_cast<std::chrono::microseconds>(time2 - time1).count();
        printf("time = %d microseconds for %d iterations (%lf MB/s)\n", dt, n, double(n) * (nblocks * 16) / dt);
    }
    printbytes("cipher", out2, 16);
    printbytes("tag", tag, 16);

    printf("goodbye\n");
    return 0;
}
<|endoftext|>