<commit_before>/*
 * Copyright (C) 2004-2009  See the AUTHORS file for details.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation.
 */

#include "DCCSock.h"
#include "User.h"
#include "Utils.h"

CDCCSock::~CDCCSock() {
	if ((m_pFile) && (!m_bNoDelFile)) {
		m_pFile->Close();
		delete m_pFile;
	}
	if (m_pUser) {
		m_pUser->AddBytesRead(GetBytesRead());
		m_pUser->AddBytesWritten(GetBytesWritten());
	}
}

void CDCCSock::ReadData(const char* data, int len) {
	if (!m_pFile) {
		DEBUG("File not open! closing get.");
		m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - File not open!");
		Close();
	}

	// DCC specs says the receiving end sends the number of bytes it
	// received so far as a 4 byte integer in network byte order, so we need
	// uint32_t to do the job portably. This also means that the maximum
	// file that we can transfer is 4 GiB big (see OpenFile()).
	if (m_bSend) {
		m_sSendBuf.append(data, len);

		while (m_sSendBuf.size() >= 4) {
			uint32_t iRemoteSoFar;
			memcpy(&iRemoteSoFar, m_sSendBuf.data(), sizeof(iRemoteSoFar));
			iRemoteSoFar = ntohl(iRemoteSoFar);

			if ((iRemoteSoFar + 65536) >= m_uBytesSoFar) {
				SendPacket();
			}

			m_sSendBuf.erase(0, 4);
		}
	} else {
		m_pFile->Write(data, len);
		m_uBytesSoFar += len;
		uint32_t uSoFar = htonl(m_uBytesSoFar);
		Write((char*) &uSoFar, sizeof(uSoFar));

		if (m_uBytesSoFar >= m_uFileSize) {
			Close();
		}
	}
}

void CDCCSock::ConnectionRefused() {
	DEBUG(GetSockName() << " == ConnectionRefused()");
	m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Connection Refused.");
}

void CDCCSock::Timeout() {
	DEBUG(GetSockName() << " == Timeout()");
	m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Timed Out.");
}

void CDCCSock::SockError(int iErrno) {
	DEBUG(GetSockName() << " == SockError(" << iErrno << ")");
	m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Socket Error [" + CString(iErrno) + "]");
}

void CDCCSock::Connected() {
	DEBUG(GetSockName() << " == Connected(" << GetRemoteIP() << ")");
	m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Transfer Started.");

	if (m_bSend) {
		SendPacket();
	}

	SetTimeout(120);
}

void CDCCSock::Disconnected() {
	const CString sStart = ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - ";

	DEBUG(GetSockName() << " == Disconnected()");

	if (m_uBytesSoFar > m_uFileSize) {
		m_pUser->PutModule(m_sModuleName, sStart + "TooMuchData!");
	} else if (m_uBytesSoFar == m_uFileSize) {
		if (m_bSend) {
			m_pUser->PutModule(m_sModuleName, sStart + "Completed! - Sent [" + m_sLocalFile +
					"] at [" + CString((int) (GetAvgWrite() / 1024.0)) + " KiB/s ]");
		} else {
			m_pUser->PutModule(m_sModuleName, sStart + "Completed! - Saved to [" + m_sLocalFile +
					"] at [" + CString((int) (GetAvgRead() / 1024.0)) + " KiB/s ]");
		}
	} else {
		m_pUser->PutModule(m_sModuleName, sStart + "Incomplete!");
	}
}

void CDCCSock::SendPacket() {
	if (!m_pFile) {
		m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - File closed prematurely.");
		Close();
		return;
	}

	char szBuf[4096];
	int iLen = m_pFile->Read(szBuf, 4096);

	if (iLen < 0) {
		m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Error reading from file.");
		Close();
		return;
	}

	if (iLen > 0) {
		Write(szBuf, iLen);
		m_uBytesSoFar += iLen;
	}
}

Csock* CDCCSock::GetSockObj(const CString& sHost, unsigned short uPort) {
	Close();

	CDCCSock* pSock = new CDCCSock(m_pUser, m_sRemoteNick, m_sLocalFile, m_sModuleName, m_uFileSize, m_pFile);
	pSock->SetSockName("DCC::SEND::" + m_sRemoteNick);
	pSock->SetTimeout(120);
	pSock->SetFileName(m_sFileName);
	pSock->SetFileOffset(m_uBytesSoFar);
	m_bNoDelFile = true;

	return pSock;
}

CFile* CDCCSock::OpenFile(bool bWrite) {
	if ((m_pFile) || (m_sLocalFile.empty())) {
		m_pUser->PutModule(m_sModuleName, ((bWrite) ? "DCC <- [" : "DCC -> [") + m_sRemoteNick + "][" + m_sLocalFile + "] - Unable to open file.");
		return NULL;
	}

	m_pFile = new CFile(m_sLocalFile);

	if (bWrite) {
		if (m_pFile->Exists()) {
			delete m_pFile;
			m_pFile = NULL;
			m_pUser->PutModule(m_sModuleName, "DCC <- [" + m_sRemoteNick + "] - File already exists [" + m_sLocalFile + "]");
			return NULL;
		}

		if (!m_pFile->Open(O_WRONLY | O_TRUNC | O_CREAT)) {
			delete m_pFile;
			m_pFile = NULL;
			m_pUser->PutModule(m_sModuleName, "DCC <- [" + m_sRemoteNick + "] - Could not open file [" + m_sLocalFile + "]");
			return NULL;
		}
	} else {
		if (!m_pFile->IsReg()) {
			delete m_pFile;
			m_pFile = NULL;
			m_pUser->PutModule(m_sModuleName, "DCC -> [" + m_sRemoteNick + "] - Not a file [" + m_sLocalFile + "]");
			return NULL;
		}

		if (!m_pFile->Open()) {
			delete m_pFile;
			m_pFile = NULL;
			m_pUser->PutModule(m_sModuleName, "DCC -> [" + m_sRemoteNick + "] - Could not open file [" + m_sLocalFile + "]");
			return NULL;
		}

		// The DCC specs only allow file transfers with files smaller
		// than 4GiB (see ReadData()).
		off_t uFileSize = m_pFile->GetSize();
		if (uFileSize > 0xffffffff) {
			delete m_pFile;
			m_pFile = NULL;
			m_pUser->PutModule(m_sModuleName, "DCC -> [" + m_sRemoteNick + "] - File too large (>4 GiB) [" + m_sLocalFile + "]");
			return NULL;
		}

		m_uFileSize = (unsigned long) uFileSize;
	}

	m_sFileName = m_pFile->GetShortName();

	return m_pFile;
}

<commit_msg>DCCSock: Make sure we don't cache too much data in memory<commit_after>/*
 * Copyright (C) 2004-2009  See the AUTHORS file for details.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation.
 */

#include "DCCSock.h"
#include "User.h"
#include "Utils.h"

CDCCSock::~CDCCSock() {
	if ((m_pFile) && (!m_bNoDelFile)) {
		m_pFile->Close();
		delete m_pFile;
	}
	if (m_pUser) {
		m_pUser->AddBytesRead(GetBytesRead());
		m_pUser->AddBytesWritten(GetBytesWritten());
	}
}

void CDCCSock::ReadData(const char* data, int len) {
	if (!m_pFile) {
		DEBUG("File not open! closing get.");
		m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - File not open!");
		Close();
	}

	// DCC specs says the receiving end sends the number of bytes it
	// received so far as a 4 byte integer in network byte order, so we need
	// uint32_t to do the job portably. This also means that the maximum
	// file that we can transfer is 4 GiB big (see OpenFile()).
	if (m_bSend) {
		m_sSendBuf.append(data, len);

		while (m_sSendBuf.size() >= 4) {
			uint32_t iRemoteSoFar;
			memcpy(&iRemoteSoFar, m_sSendBuf.data(), sizeof(iRemoteSoFar));
			iRemoteSoFar = ntohl(iRemoteSoFar);

			if ((iRemoteSoFar + 65536) >= m_uBytesSoFar) {
				SendPacket();
			}

			m_sSendBuf.erase(0, 4);
		}
	} else {
		m_pFile->Write(data, len);
		m_uBytesSoFar += len;
		uint32_t uSoFar = htonl(m_uBytesSoFar);
		Write((char*) &uSoFar, sizeof(uSoFar));

		if (m_uBytesSoFar >= m_uFileSize) {
			Close();
		}
	}
}

void CDCCSock::ConnectionRefused() {
	DEBUG(GetSockName() << " == ConnectionRefused()");
	m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Connection Refused.");
}

void CDCCSock::Timeout() {
	DEBUG(GetSockName() << " == Timeout()");
	m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Timed Out.");
}

void CDCCSock::SockError(int iErrno) {
	DEBUG(GetSockName() << " == SockError(" << iErrno << ")");
	m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Socket Error [" + CString(iErrno) + "]");
}

void CDCCSock::Connected() {
	DEBUG(GetSockName() << " == Connected(" << GetRemoteIP() << ")");
	m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Transfer Started.");

	if (m_bSend) {
		SendPacket();
	}

	SetTimeout(120);
}

void CDCCSock::Disconnected() {
	const CString sStart = ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - ";

	DEBUG(GetSockName() << " == Disconnected()");

	if (m_uBytesSoFar > m_uFileSize) {
		m_pUser->PutModule(m_sModuleName, sStart + "TooMuchData!");
	} else if (m_uBytesSoFar == m_uFileSize) {
		if (m_bSend) {
			m_pUser->PutModule(m_sModuleName, sStart + "Completed! - Sent [" + m_sLocalFile +
					"] at [" + CString((int) (GetAvgWrite() / 1024.0)) + " KiB/s ]");
		} else {
			m_pUser->PutModule(m_sModuleName, sStart + "Completed! - Saved to [" + m_sLocalFile +
					"] at [" + CString((int) (GetAvgRead() / 1024.0)) + " KiB/s ]");
		}
	} else {
		m_pUser->PutModule(m_sModuleName, sStart + "Incomplete!");
	}
}

void CDCCSock::SendPacket() {
	if (!m_pFile) {
		m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - File closed prematurely.");
		Close();
		return;
	}

	if (GetInternalWriteBuffer().size() > 1024 * 1024) {
		// There is still enough data to be written, don't add more
		// stuff to that buffer.
		DEBUG("SendPacket(): Skipping send, buffer still full enough [" << GetInternalWriteBuffer().size() << "]["
				<< m_sRemoteNick << "][" << m_sFileName << "]");
		return;
	}

	char szBuf[4096];
	int iLen = m_pFile->Read(szBuf, 4096);

	if (iLen < 0) {
		m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Error reading from file.");
		Close();
		return;
	}

	if (iLen > 0) {
		Write(szBuf, iLen);
		m_uBytesSoFar += iLen;
	}
}

Csock* CDCCSock::GetSockObj(const CString& sHost, unsigned short uPort) {
	Close();

	CDCCSock* pSock = new CDCCSock(m_pUser, m_sRemoteNick, m_sLocalFile, m_sModuleName, m_uFileSize, m_pFile);
	pSock->SetSockName("DCC::SEND::" + m_sRemoteNick);
	pSock->SetTimeout(120);
	pSock->SetFileName(m_sFileName);
	pSock->SetFileOffset(m_uBytesSoFar);
	m_bNoDelFile = true;

	return pSock;
}

CFile* CDCCSock::OpenFile(bool bWrite) {
	if ((m_pFile) || (m_sLocalFile.empty())) {
		m_pUser->PutModule(m_sModuleName, ((bWrite) ? "DCC <- [" : "DCC -> [") + m_sRemoteNick + "][" + m_sLocalFile + "] - Unable to open file.");
		return NULL;
	}

	m_pFile = new CFile(m_sLocalFile);

	if (bWrite) {
		if (m_pFile->Exists()) {
			delete m_pFile;
			m_pFile = NULL;
			m_pUser->PutModule(m_sModuleName, "DCC <- [" + m_sRemoteNick + "] - File already exists [" + m_sLocalFile + "]");
			return NULL;
		}

		if (!m_pFile->Open(O_WRONLY | O_TRUNC | O_CREAT)) {
			delete m_pFile;
			m_pFile = NULL;
			m_pUser->PutModule(m_sModuleName, "DCC <- [" + m_sRemoteNick + "] - Could not open file [" + m_sLocalFile + "]");
			return NULL;
		}
	} else {
		if (!m_pFile->IsReg()) {
			delete m_pFile;
			m_pFile = NULL;
			m_pUser->PutModule(m_sModuleName, "DCC -> [" + m_sRemoteNick + "] - Not a file [" + m_sLocalFile + "]");
			return NULL;
		}

		if (!m_pFile->Open()) {
			delete m_pFile;
			m_pFile = NULL;
			m_pUser->PutModule(m_sModuleName, "DCC -> [" + m_sRemoteNick + "] - Could not open file [" + m_sLocalFile + "]");
			return NULL;
		}

		// The DCC specs only allow file transfers with files smaller
		// than 4GiB (see ReadData()).
		off_t uFileSize = m_pFile->GetSize();
		if (uFileSize > 0xffffffff) {
			delete m_pFile;
			m_pFile = NULL;
			m_pUser->PutModule(m_sModuleName, "DCC -> [" + m_sRemoteNick + "] - File too large (>4 GiB) [" + m_sLocalFile + "]");
			return NULL;
		}

		m_uFileSize = (unsigned long) uFileSize;
	}

	m_sFileName = m_pFile->GetShortName();

	return m_pFile;
}

<|endoftext|>


<commit_before>/*
 * DataSet.cpp
 *
 * Copyright (c) 2012 Tsukasa OMOTO <henry0312@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

/* This file is available under an MIT license. */

#include "DataSet.hpp"

/**
 * Constructor
 *
 * Load DataSet
 *
 * @param const char *dataset DataSet's filename
 */
DataSet::DataSet(const char *dataset)
    :M(0), V(0), N(0)
{
    loadDataSet(dataset);
}

/**
 * Constructor
 *
 * Load DataSet and Vocabulary
 *
 * @param const char *dataset DataSet's filename
 * @param const char *vocab Vocabulary's filename
 */
DataSet::DataSet(const char *dataset, const char *vocab)
    :M(0), V(0), N(0)
{
    loadDataSet(dataset);
    loadVocabulary(vocab);
}

/**
 * Load a file and Initialize variables
 *
 * @param const char *filename open *filename
 */
void DataSet::loadDataSet(const char *filename) {
    std::ifstream fin(filename);
    if (!fin) {
        std::cerr << "Can't open the file: " << filename << std::endl;
        exit(1);
    }

    // the 1st line : the number of docs
    fin >> M;
    docs.resize(M);
    n_m.resize(M, 0);

    // the 2nd line : the number of vocabulary
    fin >> V;

    // the 3rd line : the number of words
    fin >> N;

    // the following lines : docID vocab wordID count
    int m, v, cnt;
    while ( fin >> m >> v >> cnt ) {
        for (int i = 0; i < cnt; i++) {
            docs[m-1].push_back(v);
            n_m[m-1]++;
        }
    }

    fin.close();
}

/**
 * Loac Vocabulary
 *
 * @param const char *filename open *filename
 */
void DataSet::loadVocabulary(const char *filename) {
    std::ifstream fin(filename);
    if (!fin) {
        std::cerr << "Can't open the file: " << filename << std::endl;
        exit(1);
    }

    std::string buff;
    while ( fin >> buff ) {
        vocab.push_back(buff);
    }

    fin.close();
}
<commit_msg>Fix comment.<commit_after>/*
 * DataSet.cpp
 *
 * Copyright (c) 2012 Tsukasa OMOTO <henry0312@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

/* This file is available under an MIT license. */

#include "DataSet.hpp"

/**
 * Constructor
 *
 * Load DataSet
 *
 * @param const char *dataset DataSet's filename
 */
DataSet::DataSet(const char *dataset)
    :M(0), V(0), N(0)
{
    loadDataSet(dataset);
}

/**
 * Constructor
 *
 * Load DataSet and Vocabulary
 *
 * @param const char *dataset DataSet's filename
 * @param const char *vocab Vocabulary's filename
 */
DataSet::DataSet(const char *dataset, const char *vocab)
    :M(0), V(0), N(0)
{
    loadDataSet(dataset);
    loadVocabulary(vocab);
}

/**
 * Load a file and Initialize variables
 *
 * @param const char *filename open *filename
 */
void DataSet::loadDataSet(const char *filename) {
    std::ifstream fin(filename);
    if (!fin) {
        std::cerr << "Can't open the file: " << filename << std::endl;
        exit(1);
    }

    // the 1st line : the number of docs
    fin >> M;
    docs.resize(M);
    n_m.resize(M, 0);

    // the 2nd line : the number of vocabulary
    fin >> V;

    // the 3rd line : the number of words
    fin >> N;

    // the following lines : docID wordID count
    int m, v, cnt;
    while ( fin >> m >> v >> cnt ) {
        for (int i = 0; i < cnt; i++) {
            docs[m-1].push_back(v);
            n_m[m-1]++;
        }
    }

    fin.close();
}

/**
 * Loac Vocabulary
 *
 * @param const char *filename open *filename
 */
void DataSet::loadVocabulary(const char *filename) {
    std::ifstream fin(filename);
    if (!fin) {
        std::cerr << "Can't open the file: " << filename << std::endl;
        exit(1);
    }

    std::string buff;
    while ( fin >> buff ) {
        vocab.push_back(buff);
    }

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


<commit_before>/*
  Emon.cpp - Library for openenergymonitor
  Created by Trystan Lea, April 27 2010
  GNU GPL
*/

//#include "WProgram.h" un-comment for use on older versions of Arduino IDE
#include "EmonLib.h"

#if defined(ARDUINO) && ARDUINO >= 100

#include "Arduino.h"

#else

#include "WProgram.h"

#endif

//--------------------------------------------------------------------------------------
// Sets the pins to be used for voltage and current sensors
//--------------------------------------------------------------------------------------
void EnergyMonitor::voltage(int _inPinV, double _VCAL, double _PHASECAL)
{
   inPinV = _inPinV;
   VCAL = _VCAL;
   PHASECAL = _PHASECAL;
}

void EnergyMonitor::current(int _inPinI, double _ICAL)
{
   inPinI = _inPinI;
   ICAL = _ICAL;
}

//--------------------------------------------------------------------------------------
// Sets the pins to be used for voltage and current sensors based on emontx pin map
//--------------------------------------------------------------------------------------
void EnergyMonitor::voltageTX(double _VCAL, double _PHASECAL)
{
   inPinV = 2;
   VCAL = _VCAL;
   PHASECAL = _PHASECAL;
}

void EnergyMonitor::currentTX(int _channel, double _ICAL)
{
   if (_channel == 1) inPinI = 3;
   if (_channel == 2) inPinI = 0;
   if (_channel == 3) inPinI = 1;
   ICAL = _ICAL;
}

//--------------------------------------------------------------------------------------
// emon_calc procedure
// Calculates realPower,apparentPower,powerFactor,Vrms,Irms,kwh increment
// From a sample window of the mains AC voltage and current.
// The Sample window length is defined by the number of half wavelengths or crossings we choose to measure.
//--------------------------------------------------------------------------------------
void EnergyMonitor::calcVI(int crossings, int timeout)
{
  int SUPPLYVOLTAGE = readVcc();
  int crossCount = 0;                             //Used to measure number of times threshold is crossed.
  int numberOfSamples = 0;                        //This is now incremented

  //-------------------------------------------------------------------------------------------------------------------------
  // 1) Waits for the waveform to be close to 'zero' (500 adc) part in sin curve.
  //-------------------------------------------------------------------------------------------------------------------------
  boolean st=false;                                  //an indicator to exit the while loop

  unsigned long start = millis();    //millis()-start makes sure it doesnt get stuck in the loop if there is an error.

  while(st==false)                                   //the while loop...
  {
     startV = analogRead(inPinV);                    //using the voltage waveform
     if ((startV < 550) && (startV > 440)) st=true;  //check its within range
     if ((millis()-start)>timeout) st = true;
  }

  //-------------------------------------------------------------------------------------------------------------------------
  // 2) Main measurment loop
  //-------------------------------------------------------------------------------------------------------------------------
  start = millis();

  while ((crossCount < crossings) && ((millis()-start)<timeout))
  {
    numberOfSamples++;                            //Count number of times looped.

    lastSampleV=sampleV;                          //Used for digital high pass filter
    lastSampleI=sampleI;                          //Used for digital high pass filter

    lastFilteredV = filteredV;                    //Used for offset removal
    lastFilteredI = filteredI;                    //Used for offset removal

    //-----------------------------------------------------------------------------
    // A) Read in raw voltage and current samples
    //-----------------------------------------------------------------------------
    sampleV = analogRead(inPinV);                 //Read in raw voltage signal
    sampleI = analogRead(inPinI);                 //Read in raw current signal

    //-----------------------------------------------------------------------------
    // B) Apply digital high pass filters to remove 2.5V DC offset (centered on 0V).
    //-----------------------------------------------------------------------------
    filteredV = 0.996*(lastFilteredV+sampleV-lastSampleV);
    filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI);

    //-----------------------------------------------------------------------------
    // C) Root-mean-square method voltage
    //-----------------------------------------------------------------------------
    sqV= filteredV * filteredV;                 //1) square voltage values
    sumV += sqV;                                //2) sum

    //-----------------------------------------------------------------------------
    // D) Root-mean-square method current
    //-----------------------------------------------------------------------------
    sqI = filteredI * filteredI;                //1) square current values
    sumI += sqI;                                //2) sum

    //-----------------------------------------------------------------------------
    // E) Phase calibration
    //-----------------------------------------------------------------------------
    phaseShiftedV = lastFilteredV + PHASECAL * (filteredV - lastFilteredV);

    //-----------------------------------------------------------------------------
    // F) Instantaneous power calc
    //-----------------------------------------------------------------------------
    instP = phaseShiftedV * filteredI;          //Instantaneous Power
    sumP +=instP;                               //Sum

    //-----------------------------------------------------------------------------
    // G) Find the number of times the voltage has crossed the initial voltage
    //    - every 2 crosses we will have sampled 1 wavelength
    //    - so this method allows us to sample an integer number of half wavelengths which increases accuracy
    //-----------------------------------------------------------------------------
    lastVCross = checkVCross;
    if (sampleV > startV) checkVCross = true;
                     else checkVCross = false;
    if (numberOfSamples==1) lastVCross = checkVCross;

    if (lastVCross != checkVCross) crossCount++;
  }

  //-------------------------------------------------------------------------------------------------------------------------
  // 3) Post loop calculations
  //-------------------------------------------------------------------------------------------------------------------------
  //Calculation of the root of the mean of the voltage and current squared (rms)
  //Calibration coeficients applied.

  double V_RATIO = VCAL *((SUPPLYVOLTAGE/1000.0) / 1023.0);
  Vrms = V_RATIO * sqrt(sumV / numberOfSamples);

  double I_RATIO = ICAL *((SUPPLYVOLTAGE/1000.0) / 1023.0);
  Irms = I_RATIO * sqrt(sumI / numberOfSamples);

  //Calculation power values
  realPower = V_RATIO * I_RATIO * sumP / numberOfSamples;
  apparentPower = Vrms * Irms;
  powerFactor=realPower / apparentPower;

  //Reset accumulators
  sumV = 0;
  sumI = 0;
  sumP = 0;
//--------------------------------------------------------------------------------------
}

//--------------------------------------------------------------------------------------
double EnergyMonitor::calcIrms(int NUMBER_OF_SAMPLES)
{

int SUPPLYVOLTAGE = readVcc();

  for (int n = 0; n < NUMBER_OF_SAMPLES; n++)
  {
    lastSampleI = sampleI;
    sampleI = analogRead(inPinI);
    lastFilteredI = filteredI;
    filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI);

    // Root-mean-square method current
    // 1) square current values
    sqI = filteredI * filteredI;
    // 2) sum
    sumI += sqI;
  }

  double I_RATIO = ICAL *((SUPPLYVOLTAGE/1000.0) / 1023.0);
  Irms = I_RATIO * sqrt(sumI / NUMBER_OF_SAMPLES);

  //Reset accumulators
  sumI = 0;
//--------------------------------------------------------------------------------------

  return Irms;
}

void EnergyMonitor::serialprint()
{
    Serial.print(realPower);
    Serial.print(' ');
    Serial.print(apparentPower);
    Serial.print(' ');
    Serial.print(Vrms);
    Serial.print(' ');
    Serial.print(Irms);
    Serial.print(' ');
    Serial.print(powerFactor);
    Serial.println(' ');
    delay(100);
}

//thanks to http://hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino
//and Jérôme who alerted us to http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/

long EnergyMonitor::readVcc() {
  long result;
  #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__)
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
    ADMUX = _BV(MUX5) | _BV(MUX0);
  #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
  #endif

  delay(2);					// Wait for Vref to settle
  ADCSRA |= _BV(ADSC);				// Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1126400L / result;			//1100mV*1024 ADC steps http://openenergymonitor.org/emon/node/1186
  return result;
}

<commit_msg>correct missing #elif define for ATtiny85<commit_after>/*
  Emon.cpp - Library for openenergymonitor
  Created by Trystan Lea, April 27 2010
  GNU GPL
*/

//#include "WProgram.h" un-comment for use on older versions of Arduino IDE
#include "EmonLib.h"

#if defined(ARDUINO) && ARDUINO >= 100

#include "Arduino.h"

#else

#include "WProgram.h"

#endif

//--------------------------------------------------------------------------------------
// Sets the pins to be used for voltage and current sensors
//--------------------------------------------------------------------------------------
void EnergyMonitor::voltage(int _inPinV, double _VCAL, double _PHASECAL)
{
   inPinV = _inPinV;
   VCAL = _VCAL;
   PHASECAL = _PHASECAL;
}

void EnergyMonitor::current(int _inPinI, double _ICAL)
{
   inPinI = _inPinI;
   ICAL = _ICAL;
}

//--------------------------------------------------------------------------------------
// Sets the pins to be used for voltage and current sensors based on emontx pin map
//--------------------------------------------------------------------------------------
void EnergyMonitor::voltageTX(double _VCAL, double _PHASECAL)
{
   inPinV = 2;
   VCAL = _VCAL;
   PHASECAL = _PHASECAL;
}

void EnergyMonitor::currentTX(int _channel, double _ICAL)
{
   if (_channel == 1) inPinI = 3;
   if (_channel == 2) inPinI = 0;
   if (_channel == 3) inPinI = 1;
   ICAL = _ICAL;
}

//--------------------------------------------------------------------------------------
// emon_calc procedure
// Calculates realPower,apparentPower,powerFactor,Vrms,Irms,kwh increment
// From a sample window of the mains AC voltage and current.
// The Sample window length is defined by the number of half wavelengths or crossings we choose to measure.
//--------------------------------------------------------------------------------------
void EnergyMonitor::calcVI(int crossings, int timeout)
{
  int SUPPLYVOLTAGE = readVcc();
  int crossCount = 0;                             //Used to measure number of times threshold is crossed.
  int numberOfSamples = 0;                        //This is now incremented

  //-------------------------------------------------------------------------------------------------------------------------
  // 1) Waits for the waveform to be close to 'zero' (500 adc) part in sin curve.
  //-------------------------------------------------------------------------------------------------------------------------
  boolean st=false;                                  //an indicator to exit the while loop

  unsigned long start = millis();    //millis()-start makes sure it doesnt get stuck in the loop if there is an error.

  while(st==false)                                   //the while loop...
  {
     startV = analogRead(inPinV);                    //using the voltage waveform
     if ((startV < 550) && (startV > 440)) st=true;  //check its within range
     if ((millis()-start)>timeout) st = true;
  }

  //-------------------------------------------------------------------------------------------------------------------------
  // 2) Main measurment loop
  //-------------------------------------------------------------------------------------------------------------------------
  start = millis();

  while ((crossCount < crossings) && ((millis()-start)<timeout))
  {
    numberOfSamples++;                            //Count number of times looped.

    lastSampleV=sampleV;                          //Used for digital high pass filter
    lastSampleI=sampleI;                          //Used for digital high pass filter

    lastFilteredV = filteredV;                    //Used for offset removal
    lastFilteredI = filteredI;                    //Used for offset removal

    //-----------------------------------------------------------------------------
    // A) Read in raw voltage and current samples
    //-----------------------------------------------------------------------------
    sampleV = analogRead(inPinV);                 //Read in raw voltage signal
    sampleI = analogRead(inPinI);                 //Read in raw current signal

    //-----------------------------------------------------------------------------
    // B) Apply digital high pass filters to remove 2.5V DC offset (centered on 0V).
    //-----------------------------------------------------------------------------
    filteredV = 0.996*(lastFilteredV+sampleV-lastSampleV);
    filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI);

    //-----------------------------------------------------------------------------
    // C) Root-mean-square method voltage
    //-----------------------------------------------------------------------------
    sqV= filteredV * filteredV;                 //1) square voltage values
    sumV += sqV;                                //2) sum

    //-----------------------------------------------------------------------------
    // D) Root-mean-square method current
    //-----------------------------------------------------------------------------
    sqI = filteredI * filteredI;                //1) square current values
    sumI += sqI;                                //2) sum

    //-----------------------------------------------------------------------------
    // E) Phase calibration
    //-----------------------------------------------------------------------------
    phaseShiftedV = lastFilteredV + PHASECAL * (filteredV - lastFilteredV);

    //-----------------------------------------------------------------------------
    // F) Instantaneous power calc
    //-----------------------------------------------------------------------------
    instP = phaseShiftedV * filteredI;          //Instantaneous Power
    sumP +=instP;                               //Sum

    //-----------------------------------------------------------------------------
    // G) Find the number of times the voltage has crossed the initial voltage
    //    - every 2 crosses we will have sampled 1 wavelength
    //    - so this method allows us to sample an integer number of half wavelengths which increases accuracy
    //-----------------------------------------------------------------------------
    lastVCross = checkVCross;
    if (sampleV > startV) checkVCross = true;
                     else checkVCross = false;
    if (numberOfSamples==1) lastVCross = checkVCross;

    if (lastVCross != checkVCross) crossCount++;
  }

  //-------------------------------------------------------------------------------------------------------------------------
  // 3) Post loop calculations
  //-------------------------------------------------------------------------------------------------------------------------
  //Calculation of the root of the mean of the voltage and current squared (rms)
  //Calibration coeficients applied.

  double V_RATIO = VCAL *((SUPPLYVOLTAGE/1000.0) / 1023.0);
  Vrms = V_RATIO * sqrt(sumV / numberOfSamples);

  double I_RATIO = ICAL *((SUPPLYVOLTAGE/1000.0) / 1023.0);
  Irms = I_RATIO * sqrt(sumI / numberOfSamples);

  //Calculation power values
  realPower = V_RATIO * I_RATIO * sumP / numberOfSamples;
  apparentPower = Vrms * Irms;
  powerFactor=realPower / apparentPower;

  //Reset accumulators
  sumV = 0;
  sumI = 0;
  sumP = 0;
//--------------------------------------------------------------------------------------
}

//--------------------------------------------------------------------------------------
double EnergyMonitor::calcIrms(int NUMBER_OF_SAMPLES)
{

int SUPPLYVOLTAGE = readVcc();

  for (int n = 0; n < NUMBER_OF_SAMPLES; n++)
  {
    lastSampleI = sampleI;
    sampleI = analogRead(inPinI);
    lastFilteredI = filteredI;
    filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI);

    // Root-mean-square method current
    // 1) square current values
    sqI = filteredI * filteredI;
    // 2) sum
    sumI += sqI;
  }

  double I_RATIO = ICAL *((SUPPLYVOLTAGE/1000.0) / 1023.0);
  Irms = I_RATIO * sqrt(sumI / NUMBER_OF_SAMPLES);

  //Reset accumulators
  sumI = 0;
//--------------------------------------------------------------------------------------

  return Irms;
}

void EnergyMonitor::serialprint()
{
    Serial.print(realPower);
    Serial.print(' ');
    Serial.print(apparentPower);
    Serial.print(' ');
    Serial.print(Vrms);
    Serial.print(' ');
    Serial.print(Irms);
    Serial.print(' ');
    Serial.print(powerFactor);
    Serial.println(' ');
    delay(100);
}

//thanks to http://hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino
//and Jérôme who alerted us to http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/

long EnergyMonitor::readVcc() {
  long result;
  #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__)
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
  ADMUX = _BV(MUX5) | _BV(MUX0);
  #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
  ADMUX = _BV(MUX3) | _BV(MUX2);
  #endif

  delay(2);					// Wait for Vref to settle
  ADCSRA |= _BV(ADSC);				// Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1126400L / result;			//1100mV*1024 ADC steps http://openenergymonitor.org/emon/node/1186
  return result;
}

<|endoftext|>


<commit_before>#include "FATData.h"
#include <fstream>
#include <iostream>
#include <sys/stat.h>

using namespace std;

FATData::FATData(const char* mount)
{
  uint8_t* BPB = new uint8_t[BPB_SIZE];
  unsigned int FATSz;
  unsigned int ROOTSz;
  ifstream imageFile(mount, ios::in | ios::binary);
  imageFile.read((char*)BPB, BPB_SIZE);

  bytesPerSector = bytesToUnsigned(&BPB[BPB_BYTES_PER_SEC_OFFSET], BPB_BYTES_PER_SEC_SIZE);
  sectorsPerCluster = bytesToUnsigned(&BPB[BPB_SEC_PER_CLUS_OFFSET], BPB_SEC_PER_CLUS_SIZE);
  reservedSectorCount = bytesToUnsigned(&BPB[BPB_RSVD_SEC_CNT_OFFSET], BPB_RSVD_SEC_CNT_SIZE);
  rootEntityCount = bytesToUnsigned(&BPB[BPB_ROOT_ENT_CNT_OFFSET], BPB_ROOT_ENT_CNT_SIZE);
  totalSectors16 = bytesToUnsigned(&BPB[BPB_TOT_SEC_16_OFFSET],BPB_TOT_SEC_16_SIZE);
  FATSz16 = bytesToUnsigned(&BPB[BPB_FAT_SZ16_OFFSET], BPB_FAT_SZ16_SIZE);
  totalSectors32 = bytesToUnsigned(&BPB[BPB_TOT_SEC_32_OFFSET],BPB_TOT_SEC_32_SIZE);

  FATSz = BPB_NUM_FATS * FATSz16;
  ROOTSz = rootEntityCount * ROOT_ENT_SZ;
  FAT = new uint8_t[FATSz];
  ROOT = new uint8_t[ROOTSz];
  imageFile.read((char*)FAT, FATSz);
  imageFile.read((char*)ROOT, ROOTSz);

  imageFile.close();
  delete BPB;
}//FATData constructor

FATData::~FATData()
{
}//FATData destructor

unsigned int FATData::getBytesPerSector()
{
  return bytesPerSector;
}//unsigned int FATData::getBytesPerSector()

void FATData::fatls()
{
  cout << "   DATE   |  TIME  | TYPE |    SIZE   |    SFN      |  LFN\n";
}//void FATData::fatls()

//***************************************************************************//
// Begin Utility Functions for FATData                                       //
//***************************************************************************//
unsigned int bytesToUnsigned(uint8_t* start, unsigned int size)
{
  unsigned int accum = 0;
  for (unsigned int i = 0 ; i < size ; i++)
  {
    accum += ((unsigned int)start[i]) << (8 * i);
  }
  return accum;
}//unsigned int bytesToUnsigned(uint8_t* start, size)

<commit_msg>divided by 512<commit_after>#include "FATData.h"
#include <fstream>
#include <iostream>
#include <sys/stat.h>

using namespace std;

FATData::FATData(const char* mount)
{
  uint8_t* BPB = new uint8_t[BPB_SIZE];
  unsigned int FATSz;
  unsigned int ROOTSz;
  ifstream imageFile(mount, ios::in | ios::binary);
  imageFile.read((char*)BPB, BPB_SIZE);

  bytesPerSector = bytesToUnsigned(&BPB[BPB_BYTES_PER_SEC_OFFSET], BPB_BYTES_PER_SEC_SIZE);
  sectorsPerCluster = bytesToUnsigned(&BPB[BPB_SEC_PER_CLUS_OFFSET], BPB_SEC_PER_CLUS_SIZE);
  reservedSectorCount = bytesToUnsigned(&BPB[BPB_RSVD_SEC_CNT_OFFSET], BPB_RSVD_SEC_CNT_SIZE);
  rootEntityCount = bytesToUnsigned(&BPB[BPB_ROOT_ENT_CNT_OFFSET], BPB_ROOT_ENT_CNT_SIZE);
  totalSectors16 = bytesToUnsigned(&BPB[BPB_TOT_SEC_16_OFFSET],BPB_TOT_SEC_16_SIZE);
  FATSz16 = bytesToUnsigned(&BPB[BPB_FAT_SZ16_OFFSET], BPB_FAT_SZ16_SIZE);
  totalSectors32 = bytesToUnsigned(&BPB[BPB_TOT_SEC_32_OFFSET],BPB_TOT_SEC_32_SIZE);

  FATSz = BPB_NUM_FATS * FATSz16;
  ROOTSz = rootEntityCount * ROOT_ENT_SZ / 512; //Dividing by 512 is black magic from a handout
  FAT = new uint8_t[FATSz];
  ROOT = new uint8_t[ROOTSz];
  imageFile.read((char*)FAT, FATSz);
  imageFile.read((char*)ROOT, ROOTSz);

  imageFile.close();
  delete BPB;
}//FATData constructor

FATData::~FATData()
{
}//FATData destructor

unsigned int FATData::getBytesPerSector()
{
  return bytesPerSector;
}//unsigned int FATData::getBytesPerSector()

void FATData::fatls()
{
  cout << "   DATE   |  TIME  | TYPE |    SIZE   |    SFN      |  LFN\n";
}//void FATData::fatls()

//***************************************************************************//
// Begin Utility Functions for FATData                                       //
//***************************************************************************//
unsigned int bytesToUnsigned(uint8_t* start, unsigned int size)
{
  unsigned int accum = 0;
  for (unsigned int i = 0 ; i < size ; i++)
  {
    accum += ((unsigned int)start[i]) << (8 * i);
  }
  return accum;
}//unsigned int bytesToUnsigned(uint8_t* start, size)

<|endoftext|>


<commit_before>#include "player.h"
#include "json.h"
#include <iostream>
#include <cstdlib>

const char* Player::VERSION = "Default C++ player";

int Player::betRequest(json::Value game_state)
{
    std::cerr<<json::Serialize(game_state)<<std::endl;
    std::string s = json::Serialize(game_state);
    std::string delimiter = "},{";
    std::string token;
    size_t pos = 0;
    while ((pos = s.find(delimiter)) != std::string::npos) {
        token = s.substr(0,pos);
        std::cerr << token << std::endl;
        s.erase(0, pos + delimiter.length());
    }

    return 100;

}

void Player::showdown(json::Value game_state)
{
}
<commit_msg>add try catch<commit_after>#include "player.h"
#include "json.h"
#include <iostream>
#include <cstdlib>

const char* Player::VERSION = "Default C++ player";

int Player::betRequest(json::Value game_state)
{

    try {
        std::cerr<<json::Serialize(game_state)<<std::endl;
        std::string s = json::Serialize(game_state);
        std::string delimiter = "},{";
        std::string token;
        size_t pos = 0;
        while ((pos = s.find(delimiter)) != std::string::npos) {
            token = s.substr(0,pos);
            std::cerr << token << std::endl;
            s.erase(0, pos + delimiter.length());
        }

        return 100;

    } catch(const std::exception& e) {
        // in case it crashes
        return 100;
    }

}

void Player::showdown(json::Value game_state)
{
}
<|endoftext|>


<commit_before>#include "Clipper.h"
#include <algorithm>
#include <functional>

// Calculates the intersection point of a line segment lb->la which crosses the
// plane with normal 'n'.
static bool RayPlaneIntersection(const FLOATVECTOR3 &la,
                                 const FLOATVECTOR3 &lb,
                                 const FLOATVECTOR3 &n, const float D,
                                 FLOATVECTOR3 &hit)
{
  const float denom = n ^ (la - lb);

  if(EpsilonEqual(denom, 0.0f)) {
    return false;
  }

  const float t = ((n ^ la) + D) / denom;
  hit = la + (t*(lb - la));
  return true;
}

// Splits a triangle along a plane with the given normal.
// Assumes: plane's D == 0.
//          triangle does span the plane.
void SplitTriangle(FLOATVECTOR3 a,
                   FLOATVECTOR3 b,
                   FLOATVECTOR3 c,
                   float fa,
                   float fb,
                   float fc,
                   const FLOATVECTOR3 &normal,
                   const float D,
                   std::vector<FLOATVECTOR3>& out,
                   std::vector<FLOATVECTOR3>& newVerts)
{
  // rotation / mirroring.
  //            c
  //           o          Push `c' to be alone on one side of the plane, making
  //          / \         `a' and `b' on the other.  Later we'll be able to
  // plane ---------      assume that there will be an intersection with the
  //        /     \       clip plane along the lines `ac' and `bc'.  This
  //       o-------o      reduces the number of cases below.
  //      a         b

  // if fa*fc is non-negative, both have the same sign -- and thus are on the
  // same side of the plane.
  if(fa*fc >= 0) {
    std::swap(fb, fc);
    std::swap(b, c);
    std::swap(fa, fb);
    std::swap(a, b);
  } else if(fb*fc >= 0) {
    std::swap(fa, fc);
    std::swap(a, c);
    std::swap(fa, fb);
    std::swap(a, b);
  }

  // Find the intersection points.
  FLOATVECTOR3 A, B;
  RayPlaneIntersection(a,c, normal,D, A);
  RayPlaneIntersection(b,c, normal,D, B);

  if(fc >= 0) {
    out.push_back(a); out.push_back(b); out.push_back(A);
    out.push_back(b); out.push_back(B); out.push_back(A);
  } else {
    out.push_back(A); out.push_back(B); out.push_back(c);
  }
  newVerts.push_back(A);
  newVerts.push_back(B);
}

std::vector<FLOATVECTOR3> Clipper::TriPlane(std::vector<FLOATVECTOR3>& posData, const FLOATVECTOR3 &normal, const float D) {
  std::vector<FLOATVECTOR3> newVertices;
  std::vector<FLOATVECTOR3> out;
  if (posData.size() % 3 != 0) return newVertices;

  for(auto iter = posData.begin(); iter < (posData.end()-2); iter += 3) {

    const FLOATVECTOR3 &a = (*iter);
    const FLOATVECTOR3 &b = (*(iter+1));
    const FLOATVECTOR3 &c = (*(iter+2));

    float fa = (normal ^ a) + D;
    float fb = (normal ^ b) + D;
    float fc = (normal ^ c) + D;
    if(fabs(fa) < (2 * std::numeric_limits<float>::epsilon())) { fa = 0; }
    if(fabs(fb) < (2 * std::numeric_limits<float>::epsilon())) { fb = 0; }
    if(fabs(fc) < (2 * std::numeric_limits<float>::epsilon())) { fc = 0; }
    if(fa >= 0 && fb >= 0 && fc >= 0) {        // trivial reject
      // discard -- i.e. do nothing / ignore tri.
      continue;
    } else if(fa <= 0 && fb <= 0 && fc <= 0) { // trivial accept
      out.push_back(a);
      out.push_back(b);
      out.push_back(c);
    } else { // triangle spans plane -- must be split.
      std::vector<FLOATVECTOR3> tris, newVerts;
      SplitTriangle(a,b,c, fa,fb,fc,normal,D, tris, newVerts);

      // append triangles and vertices to lists
      out.insert(out.end(), tris.begin(), tris. end());
      newVertices.insert(newVertices.end(), newVerts.begin(), newVerts. end());
    }
  }

  posData = out;
  return newVertices;
}

struct {
  bool operator() (const FLOATVECTOR3& i, const FLOATVECTOR3& j) {
    return i.x < j.x || (i.x == j.x && i.y < j.y) || (i.x == j.x && i.y == j.y && i.z < j.z);
  }
} CompSorter;

static bool AngleSorter(const FLOATVECTOR3& i, const FLOATVECTOR3& j, const FLOATVECTOR3& center, const FLOATVECTOR3& refVec, const FLOATVECTOR3& normal) {
  FLOATVECTOR3 vecI = (i-center).normalized();
  float cosI = refVec ^ vecI;
  float sinI = (vecI % refVec)^ normal;

  FLOATVECTOR3 vecJ = (j-center).normalized();
  float cosJ = refVec ^ vecJ;
  float sinJ = (vecJ % refVec) ^ normal;

  float acI = atan2(sinI, cosI);
  float acJ = atan2(sinJ, cosJ);

  return acI > acJ;
}

void Clipper::BoxPlane(std::vector<FLOATVECTOR3>& posData, const FLOATVECTOR3 &normal, const float D) {

  std::vector<FLOATVECTOR3> newVertices = Clipper::TriPlane(posData, normal, D);

  if (newVertices.size() < 3) return;

  // remove duplicate vertices
  std::sort(newVertices.begin(), newVertices.end(), CompSorter);
  newVertices.erase(std::unique(newVertices.begin(), newVertices.end()), newVertices.end());

  // sort counter clockwise
  using namespace std::placeholders;

  FLOATVECTOR3 center;
  for (auto vertex = newVertices.begin();vertex<newVertices.end();++vertex) {
    center += *vertex;
  }
  center /= float(newVertices.size());

  std::sort(newVertices.begin(), newVertices.end(), std::bind(AngleSorter, _1, _2, center, (newVertices[0]-center).normalized(), normal ));

  // create a triangle fan with the newly created vertices to close the polytope
  for (auto vertex = newVertices.begin()+2;vertex<newVertices.end();++vertex) {
    posData.push_back(newVertices[0]);
    posData.push_back(*(vertex-1));
    posData.push_back(*(vertex));
  }

}

/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2012 Interactive Visualization and Data Analysis Group.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/
<commit_msg>Fix sorting code.<commit_after>#include "Clipper.h"
#include <algorithm>
#include <functional>

// Calculates the intersection point of a line segment lb->la which crosses the
// plane with normal 'n'.
static bool RayPlaneIntersection(const FLOATVECTOR3 &la,
                                 const FLOATVECTOR3 &lb,
                                 const FLOATVECTOR3 &n, const float D,
                                 FLOATVECTOR3 &hit)
{
  const float denom = n ^ (la - lb);

  if(EpsilonEqual(denom, 0.0f)) {
    return false;
  }

  const float t = ((n ^ la) + D) / denom;
  hit = la + (t*(lb - la));
  return true;
}

// Splits a triangle along a plane with the given normal.
// Assumes: plane's D == 0.
//          triangle does span the plane.
void SplitTriangle(FLOATVECTOR3 a,
                   FLOATVECTOR3 b,
                   FLOATVECTOR3 c,
                   float fa,
                   float fb,
                   float fc,
                   const FLOATVECTOR3 &normal,
                   const float D,
                   std::vector<FLOATVECTOR3>& out,
                   std::vector<FLOATVECTOR3>& newVerts)
{
  // rotation / mirroring.
  //            c
  //           o          Push `c' to be alone on one side of the plane, making
  //          / \         `a' and `b' on the other.  Later we'll be able to
  // plane ---------      assume that there will be an intersection with the
  //        /     \       clip plane along the lines `ac' and `bc'.  This
  //       o-------o      reduces the number of cases below.
  //      a         b

  // if fa*fc is non-negative, both have the same sign -- and thus are on the
  // same side of the plane.
  if(fa*fc >= 0) {
    std::swap(fb, fc);
    std::swap(b, c);
    std::swap(fa, fb);
    std::swap(a, b);
  } else if(fb*fc >= 0) {
    std::swap(fa, fc);
    std::swap(a, c);
    std::swap(fa, fb);
    std::swap(a, b);
  }

  // Find the intersection points.
  FLOATVECTOR3 A, B;
  RayPlaneIntersection(a,c, normal,D, A);
  RayPlaneIntersection(b,c, normal,D, B);

  if(fc >= 0) {
    out.push_back(a); out.push_back(b); out.push_back(A);
    out.push_back(b); out.push_back(B); out.push_back(A);
  } else {
    out.push_back(A); out.push_back(B); out.push_back(c);
  }
  newVerts.push_back(A);
  newVerts.push_back(B);
}

std::vector<FLOATVECTOR3> Clipper::TriPlane(std::vector<FLOATVECTOR3>& posData, const FLOATVECTOR3 &normal, const float D) {
  std::vector<FLOATVECTOR3> newVertices;
  std::vector<FLOATVECTOR3> out;
  if (posData.size() % 3 != 0) return newVertices;

  for(auto iter = posData.begin(); iter < (posData.end()-2); iter += 3) {

    const FLOATVECTOR3 &a = (*iter);
    const FLOATVECTOR3 &b = (*(iter+1));
    const FLOATVECTOR3 &c = (*(iter+2));

    float fa = (normal ^ a) + D;
    float fb = (normal ^ b) + D;
    float fc = (normal ^ c) + D;
    if(fabs(fa) < (2 * std::numeric_limits<float>::epsilon())) { fa = 0; }
    if(fabs(fb) < (2 * std::numeric_limits<float>::epsilon())) { fb = 0; }
    if(fabs(fc) < (2 * std::numeric_limits<float>::epsilon())) { fc = 0; }
    if(fa >= 0 && fb >= 0 && fc >= 0) {        // trivial reject
      // discard -- i.e. do nothing / ignore tri.
      continue;
    } else if(fa <= 0 && fb <= 0 && fc <= 0) { // trivial accept
      out.push_back(a);
      out.push_back(b);
      out.push_back(c);
    } else { // triangle spans plane -- must be split.
      std::vector<FLOATVECTOR3> tris, newVerts;
      SplitTriangle(a,b,c, fa,fb,fc,normal,D, tris, newVerts);

      // append triangles and vertices to lists
      out.insert(out.end(), tris.begin(), tris. end());
      newVertices.insert(newVertices.end(), newVerts.begin(), newVerts. end());
    }
  }

  posData = out;
  return newVertices;
}

struct CompSorter {
  bool operator() (const FLOATVECTOR3& i, const FLOATVECTOR3& j) const {
    return i.x < j.x || (i.x == j.x && i.y < j.y) ||
           (i.x == j.x && i.y == j.y && i.z < j.z);
  }
};

static bool AngleSorter(const FLOATVECTOR3& i, const FLOATVECTOR3& j, const FLOATVECTOR3& center, const FLOATVECTOR3& refVec, const FLOATVECTOR3& normal) {
  FLOATVECTOR3 vecI = (i-center).normalized();
  float cosI = refVec ^ vecI;
  float sinI = (vecI % refVec)^ normal;

  FLOATVECTOR3 vecJ = (j-center).normalized();
  float cosJ = refVec ^ vecJ;
  float sinJ = (vecJ % refVec) ^ normal;

  float acI = atan2(sinI, cosI);
  float acJ = atan2(sinJ, cosJ);

  return acI > acJ;
}

void Clipper::BoxPlane(std::vector<FLOATVECTOR3>& posData, const FLOATVECTOR3 &normal, const float D) {

  std::vector<FLOATVECTOR3> newVertices = Clipper::TriPlane(posData, normal, D);

  if (newVertices.size() < 3) return;

  // remove duplicate vertices
  std::sort(newVertices.begin(), newVertices.end(), CompSorter());
  newVertices.erase(std::unique(newVertices.begin(), newVertices.end()),
                    newVertices.end());

  // sort counter clockwise
  using namespace std::placeholders;

  FLOATVECTOR3 center;
  for (auto vertex = newVertices.begin();vertex<newVertices.end();++vertex) {
    center += *vertex;
  }
  center /= float(newVertices.size());

  std::sort(newVertices.begin(), newVertices.end(), std::bind(AngleSorter, _1, _2, center, (newVertices[0]-center).normalized(), normal ));

  // create a triangle fan with the newly created vertices to close the polytope
  for (auto vertex = newVertices.begin()+2;vertex<newVertices.end();++vertex) {
    posData.push_back(newVertices[0]);
    posData.push_back(*(vertex-1));
    posData.push_back(*(vertex));
  }

}

/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2012 Interactive Visualization and Data Analysis Group.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/
<|endoftext|>


<commit_before>#include <DO/Sara/Core/Math/UnivariatePolynomial.hpp>
#include <DO/Sara/Core/Math/NewtonRaphson.hpp>

#include <complex>
#include <ctime>
#include <memory>

namespace DO { namespace Sara {

  auto compute_moduli_lower_bound(const UnivariatePolynomial<double>& P)
      -> double
  {
    auto Q = P;
    Q[0] = -std::abs(Q[0] / Q[Q.degree()]);
    for (int i = 1; i <= Q.degree(); ++i)
      Q[i] = std::abs(Q[i] / Q[Q.degree()]);

    auto x = 1.;
    auto newton_raphson = NewtonRaphson<double>{Q};
    x = newton_raphson(x, 50);

    return x;
  }

  auto K1_no_shift_polynomial(const UnivariatePolynomial<double>& K0,
                              const UnivariatePolynomial<double>& P)
      -> UnivariatePolynomial<double>
  {
    // See stage 1 formula: no-shift process (page 556).
    auto K1 = (K0 - (K0(0) / P(0)) * P) / Z;
    return K1.first;
  }

  auto K1_fixed_shift_polynomial(const UnivariatePolynomial<double>& K0,
                                 const UnivariatePolynomial<double>& P,
                                 const UnivariatePolynomial<double>& sigma,
                                 const std::complex<double>& s1,
                                 const std::complex<double>& s2)
      -> UnivariatePolynomial<double>
  {
    return K0[Z] + P[Z]
  }

  auto K0_(const UnivariatePolynomial<double>& P)
      -> UnivariatePolynomial<double>
  {
    // Write the scaled recurrence formula (page 563).
    const auto n = P.degree();
    auto K0 = UnivariatePolynomial<double>{n - 1};

    for (int i = 0; i < n; ++i)
      K0[n - 1 - i] = ((n - i) * P[n - i]) / n;

    return K0;
  }

  auto K1_stage1(const UnivariatePolynomial<double>& K0,
                 const UnivariatePolynomial<double>& P)
      -> UnivariatePolynomial<double>
  {
    // See stage 1 formula: no-shift process (page 556).
    auto K1 = (K0 - (K0(0) / P(0)) * P) / Z;
    return K1.first;
  }

  auto K1_stage2(const UnivariatePolynomial<double>& K0,
                 const UnivariatePolynomial<double>& P,
                 const UnivariatePolynomial<double>& sigma,
                 const std::complex<double>& s1, const std::complex<double>& s2)
    -> UnivariatePolynomial<double>
  {
    return {};
  }

  //auto K1_stage2(const UnivariatePolynomial<double>& K0,
  //               const UnivariatePolynomial<double>& P,
  //               const UnivariatePolynomial<double>& sigma,
  //               const std::complex<double>& s1, const std::complex<double>& s2)
  //  -> std::array<double, 6>
  //{
  //  // See stage 2 formula (9.7) (page 563).
  //  Matrix4cd M;
  //  Vector4cd y;

  //  M << 1, -s2, 0,   0,
  //       0,   0, 1,  -1,
  //       1, -s1, 0,   0,
  //       0,   0, 1, -s1;

  //  y << P(s1), P(s2), K0(s1), K0(s2);
  //  Vector4cd x = M.colPivHouseholderQr().solve(y);

  //  const auto a = std::real(x[0]);
  //  const auto b = std::real(x[1]);
  //  const auto c = std::real(x[2]);
  //  const auto d = std::real(x[3]);

  //  const auto u = - std::real(s1 + s2);
  //  const auto v = - std::real(s1 * s2);

  //  return {a, b, c, d, u, v};
  //}

  //auto stage2(const UnivariatePolynomial<double>& K0_,
  //            const UnivariatePolynomial<double>& P,
  //            int L = 20) -> double
  //{
  //  const auto beta = compute_moduli_lower_bound(P);
  //  const auto s1 = beta; //* std::exp(i*rand());
  //  const auto s2 = std::conj(s1); //* std::exp(i*rand());
  //  const auto sigma = sigma_(s1);

  //  auto K0 = K0_;
  //  auto K1 = K1_stage2(P, K0, sigma, s1, std::conj(s1));
  //  auto K2 = K1_stage2(P, K1, sigma, s1, std::conj(s1));
  //  auto K3 = K1_stage2(P, K2, sigma, s1, std::conj(s1));
  //  auto K4 = K1_stage2(P, K3, sigma, s1, std::conj(s1));

  //  auto u = std::real(s1 + s2);
  //  auto t0 = s1 - (a0 - b0 * s2) / (c0 - d0 * s2);
  //  auto t1 = s1 - (a1 - b1 * s2) / (c1 - d1 * s2);
  //  auto t2 = s1 - (a2 - b2 * s2) / (c2 - d2 * s2);

  //  for (int i = 0; i < L; ++i)
  //  {
  //    K0 = K1;
  //    K1 = K2;
  //    K2 = K1_stage2(P, K1, sigma, s1, std::conj(s1));

  //    t0 = t1;
  //    t1 = t2;
  //    t2 = s1 - P(s1) / K2(s1);

  //    auto sigma_0 = sigma(K0, K1, K2, s1, s2);
  //    auto sigma_1 = sigma(K1, K2, K3, s1, s2);
  //    auto sigma_2 = sigma(K2, K3, K4, s1, s2);

  //    const auto v0 = sigma_0[0];
  //    const auto v1 = sigma_1[0];
  //    const auto v2 = sigma_2[0];

  //    // Convergence to rho_1?
  //    if (std::abs(t1 - t0) <= 0.5 * t0 && std::abs(t2 - t1) <= 0.5 * t1)
  //      return t2;

  //    // Convergence of sigma(z) to (z - rho_1) * (z - rho_2)?
  //    if (std::abs(v1 - v0) <= 0.5 * v0 && std::abs(v2 - v1) <= 0.5 * v1)
  //      return t2;
  //  }

  //  return std::numeric_limits<double>::infinity();
  //}

  //auto stage3(const UnivariatePolynomial<double>& K0_,
  //            const UnivariatePolynomial<double>& P,
  //            int L = 20) -> double
  //{
  //  const auto beta = compute_moduli_lower_bound(P);
  //  const auto s1 = beta; //* std::exp(i*rand());
  //  const auto s2 = std::conj(s1); //* std::exp(i*rand());
  //  const auto sigma = sigma_(s1);

  //  auto K0 = K0_;
  //  auto K1 = K1_stage2(P, K0, sigma, s1, std::conj(s1));
  //  auto K2 = K1_stage2(P, K1, sigma, s1, std::conj(s1));
  //  auto K3 = K1_stage2(P, K2, sigma, s1, std::conj(s1));
  //  auto K4 = K1_stage2(P, K3, sigma, s1, std::conj(s1));

  //  auto u = std::real(s1 + s2);
  //  auto t0 = s1 - (a0 - b0 * s2) / (c0 - d0 * s2);
  //  auto t1 = s1 - (a1 - b1 * s2) / (c1 - d1 * s2);
  //  auto t2 = s1 - (a2 - b2 * s2) / (c2 - d2 * s2);

  //  for (int i = 0; i < L; ++i)
  //  {
  //    K0 = K1;
  //    K1 = K2;
  //    K2 = K1_stage2(P, K1, sigma, s1, std::conj(s1));

  //    t0 = t1;
  //    t1 = t2;
  //    t2 = s1 - P(s1) / K2(s1);

  //    auto sigma_0 = sigma(K0, K1, K2, s1, s2);
  //    auto sigma_1 = sigma(K1, K2, K3, s1, s2);
  //    auto sigma_2 = sigma(K2, K3, K4, s1, s2);

  //    const auto v0 = sigma_0[0];
  //    const auto v1 = sigma_1[0];
  //    const auto v2 = sigma_2[0];

  //    // Convergence to rho_1?
  //    if (std::abs(t1 - t0) <= 0.5 * t0 && std::abs(t2 - t1) <= 0.5 * t1)
  //      return t2;

  //    // Convergence of sigma(z) to (z - rho_1) * (z - rho_2)?
  //    if (std::abs(v1 - v0) <= 0.5 * v0 && std::abs(v2 - v1) <= 0.5 * v1)
  //      return t2;
  //  }

  //  return std::numeric_limits<double>::infinity();
  //}
  //auto sigma_lambda(const UnivariatePolynomial<double>& K0,
  //                  const UnivariatePolynomial<double>& K1,
  //                  const UnivariatePolynomial<double>& K2,
  //                  const std::complex<double>& s1,
  //                  const std::complex<double>& s2)
  //    -> UnivariatePolynomial<double>
  //{
  //  // Use a, b, c, d, u, v.
  //  auto K0_s1 = c0 - d0 * s2, K0_s2 = c0 - d0 * s1;
  //  auto K1_s1 = c1 - d1 * s2, K1_s2 = c1 - d1 * s1;
  //  auto K2_s1 = c2 - d2 * s2, K2_s2 = c2 - d2 * s1;
  //  const auto det = K1_s1 * K2_s2 - K1_s2 * K2_s1;

  //  const auto m0 = K1_s1 * K2_s2 - K1_s2 * K2_s2;
  //  const auto m1 = K0_s2 * K2_s1 - K0_s1 * K2_s2;
  //  const auto m2 = K0_s1 * K1_s2 - K0_s2 * K1_s1;

  //  const auto sigma = (m0 * Z.pow<std::complex<double>>(2) + m1 * Z + m2) / det;

  //  return sigma;
  //}

  //sigma_lambda(

  //auto stage3(const UnivariatePolynomial<double>& K0,
  //            const UnivariatePolynomial<double>& sigma0,
  //            const UnivariatePolynomial<double>& P) -> void
  //{
  //}

  //auto sigma_(const std::complex<double>& s1) -> UnivariatePolynomial<double>
  //{
  //  auto res = UnivariatePolynomial<double>{};
  //  auto res_c = (Z - s1) * (Z - std::conj(s1));

  //  res._coeff.resize(res_c._coeff.size());
  //  for (auto i = 0u; i < res_c._coeff.size(); ++i)
  //    res[i] = std::real(res_c[i]);

  //  return res;
  //}

} /* namespace Sara */
} /* namespace DO */
<commit_msg>WIP: save work.<commit_after>#include <DO/Sara/Core/EigenExtension.hpp>
#include <DO/Sara/Core/Math/NewtonRaphson.hpp>
#include <DO/Sara/Core/Math/UnivariatePolynomial.hpp>

#include <complex>
#include <ctime>
#include <memory>

namespace DO { namespace Sara {

  auto compute_moduli_lower_bound(const UnivariatePolynomial<double>& P)
      -> double
  {
    auto Q = P;
    Q[0] = -std::abs(Q[0] / Q[Q.degree()]);
    for (int i = 1; i <= Q.degree(); ++i)
      Q[i] = std::abs(Q[i] / Q[Q.degree()]);

    auto x = 1.;
    auto newton_raphson = NewtonRaphson<double>{Q};
    x = newton_raphson(x, 50);

    return x;
  }

  // Sigma is a real polynomial. So (s1, s2) is a pair of identical real numbers
  // or a conjugate complex pair.
  auto sigma_generic_formula(const std::complex<double>& s1)
      -> UnivariatePolynomial<double>
  {
    const auto a = std::real(s1);
    const auto b = std::imag(s1);
    return Z.pow<double>(2) - 2 * a * Z + (a * a + b * b);
  }

  // See formula (2.2) at page 547.
  // Don't use because overflow and underflow problems would occur (page 563).
  auto K1_generic_recurrence_formula(const UnivariatePolynomial<double>& K0,
                                     const UnivariatePolynomial<double>& P,
                                     const UnivariatePolynomial<double>& sigma,
                                     const std::complex<double>& s1)
      -> UnivariatePolynomial<double>
  {
    const auto s2 = std::conj(s1);

    Matrix2cd a, b, c;
    a <<  P(s1),  P(s2),  //
         K0(s1), K0(s2);

    b <<     K0(s1),     K0(s2),  //
         s1 * P(s1), s2 * P(s2);

    c << s1 * P(s1), s2 * P(s2),  //
              P(s1),      P(s2);

    const auto m = std::real(a.determinant() / c.determinant());
    const auto n = std::real(b.determinant() / c.determinant());

    return ((K0 + (m * Z + n)*P) / sigma).first;
  }

  // See formula (2.7) at page 548.
  auto
  sigma_formula_from_shift_polynomials(const UnivariatePolynomial<double>& K0,
                                       const UnivariatePolynomial<double>& K1,
                                       const UnivariatePolynomial<double>& K2,
                                       const std::complex<double>& s1)
      -> UnivariatePolynomial<double>
  {
    const auto s2 = std::conj(s1);
    const auto a2 = std::real(K1(s1) * K2(s2) - K1(s2) * K2(s1));
    const auto a1 = std::real(K0(s2) * K2(s1) - K0(s1) * K2(s2));
    const auto a0 = std::real(K0(s1) * K1(s2) - K0(s2) * K1(s1));

    // return (a2 * Z.pow(2) + a1 * Z + a0) / a2;
    return Z.pow<double>(2) + (a1 / a2) * Z + (a0 / a2);
  }

  // See formula at "Stage 1: no-shift process" at page 556.
  auto K1_no_shift_polynomial(const UnivariatePolynomial<double>& K0,
                              const UnivariatePolynomial<double>& P)
      -> UnivariatePolynomial<double>
  {
    auto K1 = (K0 - (K0(0) / P(0)) * P) / Z;
    return K1.first;
  }

  // This is the scaled recurrence formula (page 563).
  auto K0_polynomial(const UnivariatePolynomial<double>& P)
      -> UnivariatePolynomial<double>
  {
    return derivative(P) / P.degree();
  }

  // Return linear polynomial remainder of division of:
  // - P  / sigma
  // - K0 / sigma
  //
  // Used for stage 2 (fixed-shift process).
  // TODO: For stage 2, P(s1) and P(s2) are evaluated only once.
  //
  // Used for stage 3 (variable-shift process).
  // TODO: s1 and s2 are updated every time.
  auto calculate_remainders(const UnivariatePolynomial<double>& P,
                            const UnivariatePolynomial<double>& K0,
                            const UnivariatePolynomial<double>& sigma,
                            const std::complex<double>& s1)
      -> std::pair<UnivariatePolynomial<double>, UnivariatePolynomial<double>>
  {
    const auto s2 = std::conj(s1);

    // See stage 2 formula (9.7) (page 563).
    Matrix4cd M;
    Vector4cd y;

    M << 1, -s2, 0,   0,
         0,   0, 1,  -1,
         1, -s1, 0,   0,
         0,   0, 1, -s1;

    y << P(s1), P(s2), K0(s1), K0(s2);
    Vector4cd x = M.colPivHouseholderQr().solve(y);

    const auto a = std::real(x[0]);
    const auto b = std::real(x[1]);
    const auto c = std::real(x[2]);
    const auto d = std::real(x[3]);

    const auto u = - std::real(s1 + s2);

    const auto P_remainder = b * (Z + u) + a;
    const auto K0_remainder = d * (Z + u) + c;

    return {P_remainder, K0_remainder};
  }

  //auto stage2(const UnivariatePolynomial<double>& K0_,
  //            const UnivariatePolynomial<double>& P,
  //            int L = 20) -> double
  //{
  //  const auto beta = compute_moduli_lower_bound(P);
  //  const auto s1 = beta; //* std::exp(i*rand());
  //  const auto s2 = std::conj(s1); //* std::exp(i*rand());
  //  const auto sigma = sigma_(s1);

  //  auto K0 = K0_;
  //  auto K1 = K1_stage2(P, K0, sigma, s1, std::conj(s1));
  //  auto K2 = K1_stage2(P, K1, sigma, s1, std::conj(s1));
  //  auto K3 = K1_stage2(P, K2, sigma, s1, std::conj(s1));
  //  auto K4 = K1_stage2(P, K3, sigma, s1, std::conj(s1));

  //  auto u = std::real(s1 + s2);
  //  auto t0 = s1 - (a0 - b0 * s2) / (c0 - d0 * s2);
  //  auto t1 = s1 - (a1 - b1 * s2) / (c1 - d1 * s2);
  //  auto t2 = s1 - (a2 - b2 * s2) / (c2 - d2 * s2);

  //  for (int i = 0; i < L; ++i)
  //  {
  //    K0 = K1;
  //    K1 = K2;
  //    K2 = K1_stage2(P, K1, sigma, s1, std::conj(s1));

  //    t0 = t1;
  //    t1 = t2;
  //    t2 = s1 - P(s1) / K2(s1);

  //    auto sigma_0 = sigma(K0, K1, K2, s1, s2);
  //    auto sigma_1 = sigma(K1, K2, K3, s1, s2);
  //    auto sigma_2 = sigma(K2, K3, K4, s1, s2);

  //    const auto v0 = sigma_0[0];
  //    const auto v1 = sigma_1[0];
  //    const auto v2 = sigma_2[0];

  //    // Convergence to rho_1?
  //    if (std::abs(t1 - t0) <= 0.5 * t0 && std::abs(t2 - t1) <= 0.5 * t1)
  //      return t2;

  //    // Convergence of sigma(z) to (z - rho_1) * (z - rho_2)?
  //    if (std::abs(v1 - v0) <= 0.5 * v0 && std::abs(v2 - v1) <= 0.5 * v1)
  //      return t2;
  //  }

  //  return std::numeric_limits<double>::infinity();
  //}

  //auto stage3(const UnivariatePolynomial<double>& K0_,
  //            const UnivariatePolynomial<double>& P,
  //            int L = 20) -> double
  //{
  //  const auto beta = compute_moduli_lower_bound(P);
  //  const auto s1 = beta; //* std::exp(i*rand());
  //  const auto s2 = std::conj(s1); //* std::exp(i*rand());
  //  const auto sigma = sigma_(s1);

  //  auto K0 = K0_;
  //  auto K1 = K1_stage2(P, K0, sigma, s1, std::conj(s1));
  //  auto K2 = K1_stage2(P, K1, sigma, s1, std::conj(s1));
  //  auto K3 = K1_stage2(P, K2, sigma, s1, std::conj(s1));
  //  auto K4 = K1_stage2(P, K3, sigma, s1, std::conj(s1));

  //  auto u = std::real(s1 + s2);
  //  auto t0 = s1 - (a0 - b0 * s2) / (c0 - d0 * s2);
  //  auto t1 = s1 - (a1 - b1 * s2) / (c1 - d1 * s2);
  //  auto t2 = s1 - (a2 - b2 * s2) / (c2 - d2 * s2);

  //  for (int i = 0; i < L; ++i)
  //  {
  //    K0 = K1;
  //    K1 = K2;
  //    K2 = K1_stage2(P, K1, sigma, s1, std::conj(s1));

  //    t0 = t1;
  //    t1 = t2;
  //    t2 = s1 - P(s1) / K2(s1);

  //    auto sigma_0 = sigma(K0, K1, K2, s1, s2);
  //    auto sigma_1 = sigma(K1, K2, K3, s1, s2);
  //    auto sigma_2 = sigma(K2, K3, K4, s1, s2);

  //    const auto v0 = sigma_0[0];
  //    const auto v1 = sigma_1[0];
  //    const auto v2 = sigma_2[0];

  //    // Convergence to rho_1?
  //    if (std::abs(t1 - t0) <= 0.5 * t0 && std::abs(t2 - t1) <= 0.5 * t1)
  //      return t2;

  //    // Convergence of sigma(z) to (z - rho_1) * (z - rho_2)?
  //    if (std::abs(v1 - v0) <= 0.5 * v0 && std::abs(v2 - v1) <= 0.5 * v1)
  //      return t2;
  //  }

  //  return std::numeric_limits<double>::infinity();
  //}
  //auto sigma_lambda(const UnivariatePolynomial<double>& K0,
  //                  const UnivariatePolynomial<double>& K1,
  //                  const UnivariatePolynomial<double>& K2,
  //                  const std::complex<double>& s1,
  //                  const std::complex<double>& s2)
  //    -> UnivariatePolynomial<double>
  //{
  //  // Use a, b, c, d, u, v.
  //  auto K0_s1 = c0 - d0 * s2, K0_s2 = c0 - d0 * s1;
  //  auto K1_s1 = c1 - d1 * s2, K1_s2 = c1 - d1 * s1;
  //  auto K2_s1 = c2 - d2 * s2, K2_s2 = c2 - d2 * s1;
  //  const auto det = K1_s1 * K2_s2 - K1_s2 * K2_s1;

  //  const auto m0 = K1_s1 * K2_s2 - K1_s2 * K2_s2;
  //  const auto m1 = K0_s2 * K2_s1 - K0_s1 * K2_s2;
  //  const auto m2 = K0_s1 * K1_s2 - K0_s2 * K1_s1;

  //  const auto sigma = (m0 * Z.pow<std::complex<double>>(2) + m1 * Z + m2) / det;

  //  return sigma;
  //}

  //sigma_lambda(

  //auto stage3(const UnivariatePolynomial<double>& K0,
  //            const UnivariatePolynomial<double>& sigma0,
  //            const UnivariatePolynomial<double>& P) -> void
  //{
  //}

  //auto sigma_(const std::complex<double>& s1) -> UnivariatePolynomial<double>
  //{
  //  auto res = UnivariatePolynomial<double>{};
  //  auto res_c = (Z - s1) * (Z - std::conj(s1));

  //  res._coeff.resize(res_c._coeff.size());
  //  for (auto i = 0u; i < res_c._coeff.size(); ++i)
  //    res[i] = std::real(res_c[i]);

  //  return res;
  //}

} /* namespace Sara */
} /* namespace DO */
<|endoftext|>


<commit_before>// Copyright (c) 2012, Sergey Zolotarev
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <cstddef>
#include <map>

#include "jit.h"
#include "jump-x86.h"
#include "plugin.h"
#include "pluginversion.h"

using namespace jit;

typedef void (*logprintf_t)(const char *format, ...);
static logprintf_t logprintf;

typedef std::map<AMX*, JIT*> JITMap;
static JITMap jit_map;

static JIT *GetJIT(AMX *amx) {
	JITMap::const_iterator it = jit_map.find(amx);
	if (it == jit_map.end()) {
		JIT *jit = new JIT(amx);
		jit_map.insert(std::make_pair(amx, jit));
		return jit;
	} else {
		return it->second;
	}
}

static void DeleteJIT(AMX *amx) {
	JITMap::iterator it = jit_map.find(amx);
	if (it != jit_map.end()) {
		delete it->second;
		jit_map.erase(it);
	}
}

static int AMXAPI amx_GetAddr_JIT(AMX *amx, cell amx_addr, cell **phys_addr) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	*phys_addr = reinterpret_cast<cell*>(amx->base + hdr->dat + amx_addr);
	return AMX_ERR_NONE;
}

static int AMXAPI amx_Exec_JIT(AMX *amx, cell *retval, int index) {
	if (index != AMX_EXEC_CONT) {
		return GetJIT(amx)->CallPublicFunction(index, retval);
	}
	return AMX_ERR_NONE;
}

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
	return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) {
	logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];

	new JumpX86(((void**)ppData[PLUGIN_DATA_AMX_EXPORTS])[PLUGIN_AMX_EXPORT_Exec], (void*)amx_Exec_JIT);
	new JumpX86(((void**)ppData[PLUGIN_DATA_AMX_EXPORTS])[PLUGIN_AMX_EXPORT_GetAddr], (void*)amx_GetAddr_JIT);

	logprintf("  JIT plugin v%s is OK.", PLUGIN_VERSION_STRING);

	return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload() {
	// nothing
}

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx) {
	return AMX_ERR_NONE;
}

PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx) {
	DeleteJIT(amx);
	return AMX_ERR_NONE;
}
<commit_msg>Delete all JIT instances in Unload()<commit_after>// Copyright (c) 2012, Sergey Zolotarev
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <cstddef>
#include <map>

#include "jit.h"
#include "jump-x86.h"
#include "plugin.h"
#include "pluginversion.h"

using namespace jit;

typedef void (*logprintf_t)(const char *format, ...);
static logprintf_t logprintf;

typedef std::map<AMX*, JIT*> JITMap;
static JITMap jit_map;

static JIT *GetJIT(AMX *amx) {
	JITMap::const_iterator it = jit_map.find(amx);
	if (it == jit_map.end()) {
		JIT *jit = new JIT(amx);
		jit_map.insert(std::make_pair(amx, jit));
		return jit;
	} else {
		return it->second;
	}
}

static void DeleteJIT(AMX *amx) {
	JITMap::iterator it = jit_map.find(amx);
	if (it != jit_map.end()) {
		delete it->second;
		jit_map.erase(it);
	}
}

static int AMXAPI amx_GetAddr_JIT(AMX *amx, cell amx_addr, cell **phys_addr) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	*phys_addr = reinterpret_cast<cell*>(amx->base + hdr->dat + amx_addr);
	return AMX_ERR_NONE;
}

static int AMXAPI amx_Exec_JIT(AMX *amx, cell *retval, int index) {
	if (index != AMX_EXEC_CONT) {
		return GetJIT(amx)->CallPublicFunction(index, retval);
	}
	return AMX_ERR_NONE;
}

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
	return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) {
	logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];

	new JumpX86(((void**)ppData[PLUGIN_DATA_AMX_EXPORTS])[PLUGIN_AMX_EXPORT_Exec], (void*)amx_Exec_JIT);
	new JumpX86(((void**)ppData[PLUGIN_DATA_AMX_EXPORTS])[PLUGIN_AMX_EXPORT_GetAddr], (void*)amx_GetAddr_JIT);

	logprintf("  JIT plugin v%s is OK.", PLUGIN_VERSION_STRING);

	return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload() {
	for (JITMap::iterator it = jit_map.begin(); it != jit_map.end(); ++it) {
		delete it->second;
	}
}

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx) {
	return AMX_ERR_NONE;
}

PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx) {
	DeleteJIT(amx);
	return AMX_ERR_NONE;
}
<|endoftext|>


<commit_before>/*
 * PCD8544 - Interface with Philips PCD8544 (or compatible) LCDs.
 *
 * Copyright (c) 2010 Carlos Rodrigues <cefrodrigues@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "PCD8544.h"

#if ARDUINO < 100
#include <WProgram.h>
#else
#include <Arduino.h>
#endif

#include <avr/pgmspace.h>

#define PCD8544_CMD  LOW
#define PCD8544_DATA HIGH

/*
 * If this was a ".h", it would get added to sketches when using
 * the "Sketch -> Import Library..." menu on the Arduino IDE...
 */
#include "charset.cpp"

PCD8544::PCD8544(unsigned char sclk, unsigned char sdin,
                 unsigned char dc, unsigned char reset,
                 unsigned char sce):
    pin_sclk(sclk),
    pin_sdin(sdin),
    pin_dc(dc),
    pin_reset(reset),
    pin_sce(sce)
{}

void PCD8544::begin(unsigned char width, unsigned char height, unsigned char model)
{
    this->width = width;
    this->height = height;

    // Only two chip variants are currently known/supported...
    this->model = (model == CHIP_ST7576) ? CHIP_ST7576 : CHIP_PCD8544;

    this->column = 0;
    this->line = 0;

    // Sanitize the custom glyphs...
    memset(this->custom, 0, sizeof(this->custom));

    // All pins are outputs (these displays cannot be read)...
    pinMode(this->pin_sclk, OUTPUT);
    pinMode(this->pin_sdin, OUTPUT);
    pinMode(this->pin_dc, OUTPUT);
    pinMode(this->pin_reset, OUTPUT);
    pinMode(this->pin_sce, OUTPUT);

    // Reset the controller state...
    digitalWrite(this->pin_reset, HIGH);
    digitalWrite(this->pin_sce, HIGH);
    digitalWrite(this->pin_reset, LOW);
    delay(100);
    digitalWrite(this->pin_reset, HIGH);

    // Set the LCD parameters...
    this->send(PCD8544_CMD, 0x21);  // extended instruction set control (H=1)
    this->send(PCD8544_CMD, 0x13);  // bias system (1:48)

    if (this->model == CHIP_ST7576) {
        this->send(PCD8544_CMD, 0xe0);  // higher Vop, too faint at default
        this->send(PCD8544_CMD, 0x05);  // partial display mode
    } else {
        this->send(PCD8544_CMD, 0xc2);  // default Vop (3.06 + 66 * 0.06 = 7V)
    }

    this->send(PCD8544_CMD, 0x20);  // extended instruction set control (H=0)
    this->send(PCD8544_CMD, 0x09);  // all display segments on

    // Clear RAM contents...
    this->clear();

    // Activate LCD...
    this->send(PCD8544_CMD, 0x08);  // display blank
    this->send(PCD8544_CMD, 0x0c);  // normal mode (0x0d = inverse mode)
    delay(100);

    // Place the cursor at the origin...
    this->send(PCD8544_CMD, 0x80);
    this->send(PCD8544_CMD, 0x40);
}

void PCD8544::stop()
{
    this->clear();
    this->setPower(false);
}

void PCD8544::clear()
{
    this->setCursor(0, 0);

    for (unsigned short i = 0; i < this->width * (this->height/8); i++) {
        this->send(PCD8544_DATA, 0x00);
    }

    this->setCursor(0, 0);
}

void PCD8544::clearLine()
{
    this->setCursor(0, this->line);

    for (unsigned char i = 0; i < this->width; i++) {
        this->send(PCD8544_DATA, 0x00);
    }

    this->setCursor(0, this->line);
}

void PCD8544::setPower(bool on)
{
    this->send(PCD8544_CMD, on ? 0x20 : 0x24);
}

inline void PCD8544::display()
{
    this->setPower(true);
}

inline void PCD8544::noDisplay()
{
    this->setPower(false);
}

void PCD8544::setInverse(bool inverse)
{
    this->send(PCD8544_CMD, inverse ? 0x0d : 0x0c);
}

void PCD8544::setContrast(unsigned char level)
{
    // The PCD8544 datasheet specifies a maximum Vop of 8.5V for safe
    // operation in low temperatures, which limits the contrast level.
    if (this->model == CHIP_PCD8544 && level > 90) {
        level = 90;  // Vop = 3.06 + 90 * 0.06 = 8.46V
    }

    // The ST7576 datasheet specifies a minimum Vop of 4V.
    if (this->model == CHIP_ST7576 && level < 36) {
        level = 36;  // Vop = 2.94 + 36 * 0.06 = 4.02V
    }

    this->send(PCD8544_CMD, 0x21);  // extended instruction set control (H=1)
    this->send(PCD8544_CMD, 0x80 | (level & 0x7f));
    this->send(PCD8544_CMD, 0x20);  // extended instruction set control (H=0)
}

void PCD8544::home()
{
    this->setCursor(0, this->line);
}

void PCD8544::setCursor(unsigned char column, unsigned char line)
{
    this->column = (column % this->width);
    this->line = (line % (this->height/9 + 1));

    this->send(PCD8544_CMD, 0x80 | this->column);
    this->send(PCD8544_CMD, 0x40 | this->line);
}

void PCD8544::createChar(unsigned char chr, const unsigned char *glyph)
{
    // ASCII 0-31 only...
    if (chr >= ' ') {
        return;
    }

    this->custom[chr] = glyph;
}

#if ARDUINO < 100
void PCD8544::write(uint8_t chr)
#else
size_t PCD8544::write(uint8_t chr)
#endif
{
    // ASCII 7-bit only...
    if (chr >= 0x80) {
#if ARDUINO < 100
        return;
#else
        return 0;
#endif
    }

    const unsigned char *glyph;
    unsigned char pgm_buffer[5];

    if (chr >= ' ') {
        // Regular ASCII characters are kept in flash to save RAM...
        memcpy_P(pgm_buffer, &charset[chr - ' '], sizeof(pgm_buffer));
        glyph = pgm_buffer;
    } else {
        // Custom glyphs, on the other hand, are stored in RAM...
        if (this->custom[chr]) {
            glyph = this->custom[chr];
        } else {
            // Default to a space character if unset...
            memcpy_P(pgm_buffer, &charset[0], sizeof(pgm_buffer));
            glyph = pgm_buffer;
        }
    }

    // Output one column at a time...
    for (unsigned char i = 0; i < 5; i++) {
        this->send(PCD8544_DATA, glyph[i]);
    }

    // One column between characters...
    this->send(PCD8544_DATA, 0x00);

    // Update the cursor position...
    this->column = (this->column + 6) % this->width;

    if (this->column == 0) {
        this->line = (this->line + 1) % (this->height/9 + 1);
    }

#if ARDUINO >= 100
    return 1;
#endif
}

void PCD8544::drawBitmap(const unsigned char *data, unsigned char columns, unsigned char lines)
{
    unsigned char scolumn = this->column;
    unsigned char sline = this->line;

    // The bitmap will be clipped at the right/bottom edge of the display...
    unsigned char mx = (scolumn + columns > this->width) ? (this->width - scolumn) : columns;
    unsigned char my = (sline + lines > this->height/8) ? (this->height/8 - sline) : lines;

    for (unsigned char y = 0; y < my; y++) {
        this->setCursor(scolumn, sline + y);

        for (unsigned char x = 0; x < mx; x++) {
            this->send(PCD8544_DATA, data[y * columns + x]);
        }
    }

    // Leave the cursor in a consistent position...
    this->setCursor(scolumn + columns, sline);
}

void PCD8544::drawColumn(unsigned char lines, unsigned char value)
{
    unsigned char scolumn = this->column;
    unsigned char sline = this->line;

    // Keep "value" within range...
    if (value > lines*8) {
        value = lines*8;
    }

    // Find the line where "value" resides...
    unsigned char mark = (lines*8 - 1 - value)/8;

    // Clear the lines above the mark...
    for (unsigned char line = 0; line < mark; line++) {
        this->setCursor(scolumn, sline + line);
        this->send(PCD8544_DATA, 0x00);
    }

    // Compute the byte to draw at the "mark" line...
    unsigned char b = 0xff;
    for (unsigned char i = 0; i < lines*8 - mark*8 - value; i++) {
        b <<= 1;
    }

    this->setCursor(scolumn, sline + mark);
    this->send(PCD8544_DATA, b);

    // Fill the lines below the mark...
    for (unsigned char line = mark + 1; line < lines; line++) {
        this->setCursor(scolumn, sline + line);
        this->send(PCD8544_DATA, 0xff);
    }

    // Leave the cursor in a consistent position...
    this->setCursor(scolumn + 1, sline);
}

void PCD8544::send(unsigned char type, unsigned char data)
{
    digitalWrite(this->pin_dc, type);

    digitalWrite(this->pin_sce, LOW);
    shiftOut(this->pin_sdin, this->pin_sclk, MSBFIRST, data);
    digitalWrite(this->pin_sce, HIGH);
}

/* vim: set expandtab ts=4 sw=4: */
<commit_msg>Correct comment for the ST7576 Vop equation.<commit_after>/*
 * PCD8544 - Interface with Philips PCD8544 (or compatible) LCDs.
 *
 * Copyright (c) 2010 Carlos Rodrigues <cefrodrigues@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "PCD8544.h"

#if ARDUINO < 100
#include <WProgram.h>
#else
#include <Arduino.h>
#endif

#include <avr/pgmspace.h>

#define PCD8544_CMD  LOW
#define PCD8544_DATA HIGH

/*
 * If this was a ".h", it would get added to sketches when using
 * the "Sketch -> Import Library..." menu on the Arduino IDE...
 */
#include "charset.cpp"

PCD8544::PCD8544(unsigned char sclk, unsigned char sdin,
                 unsigned char dc, unsigned char reset,
                 unsigned char sce):
    pin_sclk(sclk),
    pin_sdin(sdin),
    pin_dc(dc),
    pin_reset(reset),
    pin_sce(sce)
{}

void PCD8544::begin(unsigned char width, unsigned char height, unsigned char model)
{
    this->width = width;
    this->height = height;

    // Only two chip variants are currently known/supported...
    this->model = (model == CHIP_ST7576) ? CHIP_ST7576 : CHIP_PCD8544;

    this->column = 0;
    this->line = 0;

    // Sanitize the custom glyphs...
    memset(this->custom, 0, sizeof(this->custom));

    // All pins are outputs (these displays cannot be read)...
    pinMode(this->pin_sclk, OUTPUT);
    pinMode(this->pin_sdin, OUTPUT);
    pinMode(this->pin_dc, OUTPUT);
    pinMode(this->pin_reset, OUTPUT);
    pinMode(this->pin_sce, OUTPUT);

    // Reset the controller state...
    digitalWrite(this->pin_reset, HIGH);
    digitalWrite(this->pin_sce, HIGH);
    digitalWrite(this->pin_reset, LOW);
    delay(100);
    digitalWrite(this->pin_reset, HIGH);

    // Set the LCD parameters...
    this->send(PCD8544_CMD, 0x21);  // extended instruction set control (H=1)
    this->send(PCD8544_CMD, 0x13);  // bias system (1:48)

    if (this->model == CHIP_ST7576) {
        this->send(PCD8544_CMD, 0xe0);  // higher Vop, too faint at default
        this->send(PCD8544_CMD, 0x05);  // partial display mode
    } else {
        this->send(PCD8544_CMD, 0xc2);  // default Vop (3.06 + 66 * 0.06 = 7V)
    }

    this->send(PCD8544_CMD, 0x20);  // extended instruction set control (H=0)
    this->send(PCD8544_CMD, 0x09);  // all display segments on

    // Clear RAM contents...
    this->clear();

    // Activate LCD...
    this->send(PCD8544_CMD, 0x08);  // display blank
    this->send(PCD8544_CMD, 0x0c);  // normal mode (0x0d = inverse mode)
    delay(100);

    // Place the cursor at the origin...
    this->send(PCD8544_CMD, 0x80);
    this->send(PCD8544_CMD, 0x40);
}

void PCD8544::stop()
{
    this->clear();
    this->setPower(false);
}

void PCD8544::clear()
{
    this->setCursor(0, 0);

    for (unsigned short i = 0; i < this->width * (this->height/8); i++) {
        this->send(PCD8544_DATA, 0x00);
    }

    this->setCursor(0, 0);
}

void PCD8544::clearLine()
{
    this->setCursor(0, this->line);

    for (unsigned char i = 0; i < this->width; i++) {
        this->send(PCD8544_DATA, 0x00);
    }

    this->setCursor(0, this->line);
}

void PCD8544::setPower(bool on)
{
    this->send(PCD8544_CMD, on ? 0x20 : 0x24);
}

inline void PCD8544::display()
{
    this->setPower(true);
}

inline void PCD8544::noDisplay()
{
    this->setPower(false);
}

void PCD8544::setInverse(bool inverse)
{
    this->send(PCD8544_CMD, inverse ? 0x0d : 0x0c);
}

void PCD8544::setContrast(unsigned char level)
{
    // The PCD8544 datasheet specifies a maximum Vop of 8.5V for safe
    // operation in low temperatures, which limits the contrast level.
    if (this->model == CHIP_PCD8544 && level > 90) {
        level = 90;  // Vop = 3.06 + 90 * 0.06 = 8.46V
    }

    // The ST7576 datasheet specifies a minimum Vop of 4V.
    if (this->model == CHIP_ST7576 && level < 36) {
        level = 36;  // Vop = 2.94 + 36 * 0.03 = 4.02V
    }

    this->send(PCD8544_CMD, 0x21);  // extended instruction set control (H=1)
    this->send(PCD8544_CMD, 0x80 | (level & 0x7f));
    this->send(PCD8544_CMD, 0x20);  // extended instruction set control (H=0)
}

void PCD8544::home()
{
    this->setCursor(0, this->line);
}

void PCD8544::setCursor(unsigned char column, unsigned char line)
{
    this->column = (column % this->width);
    this->line = (line % (this->height/9 + 1));

    this->send(PCD8544_CMD, 0x80 | this->column);
    this->send(PCD8544_CMD, 0x40 | this->line);
}

void PCD8544::createChar(unsigned char chr, const unsigned char *glyph)
{
    // ASCII 0-31 only...
    if (chr >= ' ') {
        return;
    }

    this->custom[chr] = glyph;
}

#if ARDUINO < 100
void PCD8544::write(uint8_t chr)
#else
size_t PCD8544::write(uint8_t chr)
#endif
{
    // ASCII 7-bit only...
    if (chr >= 0x80) {
#if ARDUINO < 100
        return;
#else
        return 0;
#endif
    }

    const unsigned char *glyph;
    unsigned char pgm_buffer[5];

    if (chr >= ' ') {
        // Regular ASCII characters are kept in flash to save RAM...
        memcpy_P(pgm_buffer, &charset[chr - ' '], sizeof(pgm_buffer));
        glyph = pgm_buffer;
    } else {
        // Custom glyphs, on the other hand, are stored in RAM...
        if (this->custom[chr]) {
            glyph = this->custom[chr];
        } else {
            // Default to a space character if unset...
            memcpy_P(pgm_buffer, &charset[0], sizeof(pgm_buffer));
            glyph = pgm_buffer;
        }
    }

    // Output one column at a time...
    for (unsigned char i = 0; i < 5; i++) {
        this->send(PCD8544_DATA, glyph[i]);
    }

    // One column between characters...
    this->send(PCD8544_DATA, 0x00);

    // Update the cursor position...
    this->column = (this->column + 6) % this->width;

    if (this->column == 0) {
        this->line = (this->line + 1) % (this->height/9 + 1);
    }

#if ARDUINO >= 100
    return 1;
#endif
}

void PCD8544::drawBitmap(const unsigned char *data, unsigned char columns, unsigned char lines)
{
    unsigned char scolumn = this->column;
    unsigned char sline = this->line;

    // The bitmap will be clipped at the right/bottom edge of the display...
    unsigned char mx = (scolumn + columns > this->width) ? (this->width - scolumn) : columns;
    unsigned char my = (sline + lines > this->height/8) ? (this->height/8 - sline) : lines;

    for (unsigned char y = 0; y < my; y++) {
        this->setCursor(scolumn, sline + y);

        for (unsigned char x = 0; x < mx; x++) {
            this->send(PCD8544_DATA, data[y * columns + x]);
        }
    }

    // Leave the cursor in a consistent position...
    this->setCursor(scolumn + columns, sline);
}

void PCD8544::drawColumn(unsigned char lines, unsigned char value)
{
    unsigned char scolumn = this->column;
    unsigned char sline = this->line;

    // Keep "value" within range...
    if (value > lines*8) {
        value = lines*8;
    }

    // Find the line where "value" resides...
    unsigned char mark = (lines*8 - 1 - value)/8;

    // Clear the lines above the mark...
    for (unsigned char line = 0; line < mark; line++) {
        this->setCursor(scolumn, sline + line);
        this->send(PCD8544_DATA, 0x00);
    }

    // Compute the byte to draw at the "mark" line...
    unsigned char b = 0xff;
    for (unsigned char i = 0; i < lines*8 - mark*8 - value; i++) {
        b <<= 1;
    }

    this->setCursor(scolumn, sline + mark);
    this->send(PCD8544_DATA, b);

    // Fill the lines below the mark...
    for (unsigned char line = mark + 1; line < lines; line++) {
        this->setCursor(scolumn, sline + line);
        this->send(PCD8544_DATA, 0xff);
    }

    // Leave the cursor in a consistent position...
    this->setCursor(scolumn + 1, sline);
}

void PCD8544::send(unsigned char type, unsigned char data)
{
    digitalWrite(this->pin_dc, type);

    digitalWrite(this->pin_sce, LOW);
    shiftOut(this->pin_sdin, this->pin_sclk, MSBFIRST, data);
    digitalWrite(this->pin_sce, HIGH);
}

/* vim: set expandtab ts=4 sw=4: */
<|endoftext|>