<commit_before>/*
  ePaper.cpp
  2013 Copyright (c) Seeed Technology Inc.  All right reserved.

  Modified by Loovee
  www.seeedstudio.com
  2013-7-2

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <Arduino.h>
#include <SPI.h>
#include "GT20L16_drive.h"
#include "ePaper.h"

static void spi_on()
{
    SPI.begin();
    //SPI.setClockDivider(SPI_CLOCK_DIV2);
    //SPI_put(0x00);
    //SPI_put(0x00);
}

/*********************************************************************************************************
* \brief According to EPD size and temperature to get stage_time
* \note Refer to COG document Section 5.3 for more details
*
* \param EPD_type_index The defined EPD size
**********************************************************************************************************/
void ePaper::begin(EPD_size sz)
{
    size = sz;
    direction = DIRNORMAL;

    switch(size)
    {
        case EPD_1_44:              // 128*96
        SIZE_LEN    = 128;
        SIZE_WIDTH  = 96;
        break;

        case EPD_2_0:               // 200*96
        SIZE_LEN    = 200;
        SIZE_WIDTH  = 96;
        break;

        case EPD_2_7:               // 264*176
        SIZE_LEN    = 264;
        SIZE_WIDTH  = 176;
        break;

        default:
        println_ep("wrong size");
        while(1);                   // die here
    }

    DISP_LEN    = SIZE_LEN;
    DISP_WIDTH  = SIZE_WIDTH;

    EPD.begin(size);
    init_io();
}

void ePaper::spi_detach()
{
}
/*********************************************************************************************************
** Function name:           begin
** Descriptions:            begin
*********************************************************************************************************/
void ePaper::setDirection(EPD_DIR dir)
{
    // direction = dir;

    // if((direction == DIRLEFT) || (direction == DIRRIGHT))
    // {
    //     DISP_LEN    = SIZE_WIDTH;
    //     DISP_WIDTH  = SIZE_LEN;
    // }

    //eSD.setDirection(direction);
}
/*********************************************************************************************************
** Function name:           start
** Descriptions:            start
*********************************************************************************************************/
void ePaper::start()
{
    EPD.start();                 // power up the EPD panel

    int tmp = getTemperature();
    Serial.print("temperature: ");
    EPD.setFactor(getTemperature());         // adjust for current temperature
}

/*********************************************************************************************************
** Function name:           end
** Descriptions:            end
*********************************************************************************************************/
void ePaper::end()
{
    EPD.end();
}

/*********************************************************************************************************
** Function name:           init_io
** Descriptions:            init IO
*********************************************************************************************************/
void ePaper::init_io()
{
    // init IO
    pinMode(Pin_BUSY, INPUT);
    pinMode(Pin_RESET, OUTPUT);
    pinMode(Pin_PANEL_ON, OUTPUT);
    pinMode(Pin_DISCHARGE, OUTPUT);
    pinMode(Pin_BORDER, OUTPUT);
    pinMode(Pin_EPD_CS, OUTPUT);
    pinMode(Pin_SD_CS, OUTPUT);

    pinMode(9, OUTPUT);
    digitalWrite(9, HIGH);

    digitalWrite(Pin_RESET, LOW);
    digitalWrite(Pin_PANEL_ON, LOW);
    digitalWrite(Pin_DISCHARGE, LOW);
    digitalWrite(Pin_BORDER, LOW);
    digitalWrite(Pin_EPD_CS, HIGH);
    digitalWrite(Pin_SD_CS, HIGH);

    // init SPI
    SPI.begin();
    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE0);
    //SPI.setClockDivider(SPI_CLOCK_DIV2);
}

/*********************************************************************************************************
** Function name:           getTemperature
** Descriptions:            get temperature of sensor
*********************************************************************************************************/
int ePaper::getTemperature()
{
    int sum = 0;
    for(int i=0; i<32; i++)
    {
        sum += analogRead(Pin_TEMPERATURE);
    }
    sum  = sum >> 5;

    float temp = 209.56-121.7*(float(sum)/1023.0*5.0);

    return (int)temp;
}

/*********************************************************************************************************
** Function name:           drawUnicode
** Descriptions:            draw a unicode
*********************************************************************************************************/
int ePaper::drawUnicode(unsigned int uniCode, int x, int y)
{

   // if(((x+16)>= DISP_LEN) || ((y+16) >= DISP_WIDTH) || x<0 || y<0) return 0;

    int dtaLen = GT20L16.getMatrixUnicode(uniCode, tMatrix);

    int pX      = 0;
    int pY      = 0;
    int color   = 0;
    //spi_on();
    for(int k = 0; k<2; k++)
    {
        for(int i=0; i<8; i++)
        {
            for(int j=0; j<(dtaLen/2); j++)
            {

                if(tMatrix[j+(dtaLen/2)*k] & (0x01<<(7-i)))
                {
                    color = 1;
                }
                else
                {
                    color = 0;
                }

                pX = x + j;
                pY = y + k*8+i;

                drawPixel(pX, pY, color);
            }
        }
    }

    return dtaLen/2;        // x +
}

int ePaper::drawUnicode(unsigned char *matrix, int x, int y)
{

   // if(((x+16)>= DISP_LEN) || ((y+16) >= DISP_WIDTH) || x<0 || y<0) return 0;

    int dtaLen  = 32;
    int pX      = 0;
    int pY      = 0;
    int color   = 0;
    //spi_on();
    for(int k = 0; k<2; k++)
    {
        for(int i=0; i<8; i++)
        {
            for(int j=0; j<(dtaLen/2); j++)
            {

                if(matrix[j+(dtaLen/2)*k] & (0x01<<(7-i)))
                {
                    color = 1;
                }
                else
                {
                    color = 0;
                }

                pX = x + j;
                pY = y + k*8+i;

                drawPixel(pX, pY, color);
            }
        }
    }

    return dtaLen/2;        // x +
}

/*********************************************************************************************************
** Function name:           drawUnicodeString
** Descriptions:            draw string
*********************************************************************************************************/
int ePaper::drawUnicodeString(unsigned int *uniCode, int len, int x, int y)
{
    int xPlus = 0;
    int xSum  = 0;

    for(int i=0; i<len; i++)
    {
        xPlus = drawUnicode(uniCode[i], x, y);
        x += xPlus;
        xSum += xPlus;
    }
    return xSum;
}

/*********************************************************************************************************
** Function name:           drawChar
** Descriptions:            draw char
*********************************************************************************************************/
int ePaper::drawChar(char c, int x, int y)
{
    return drawUnicode(c, x, y);
}

/*********************************************************************************************************
** Function name:           drawString
** Descriptions:            draw string
*********************************************************************************************************/
int ePaper::drawString(char *string, int poX, int poY)
{
    int sumX = 0;

    while(*string)
    {

        int xPlus = drawChar(*string, poX, poY);
        sumX += xPlus;
        *string++;

        if(poX < 200)
        {
            poX += xPlus;                                     /* Move cursor right            */
        }
    }

    return sumX;
}

/*********************************************************************************************************
** Function name:           drawNumber
** Descriptions:            drawNumber
*********************************************************************************************************/
int ePaper::drawNumber(long long_num,int poX, int poY)
{
    char tmp[10];
    sprintf(tmp, "%d", long_num);
    return drawString(tmp, poX, poY);

}

/*********************************************************************************************************
** Function name:           drawFloat
** Descriptions:            drawFloat
*********************************************************************************************************/
int ePaper::drawFloat(float floatNumber, int decimal, int poX, int poY)
{
    unsigned long temp=0;
    float decy=0.0;
    float rounding = 0.5;
    unsigned char f=0;

    float eep = 0.000001;

    int sumX    = 0;
    int xPlus   = 0;

    if(floatNumber-0.0 < eep)       // floatNumber < 0
    {
        xPlus = drawChar('-',poX, poY);
        floatNumber = -floatNumber;

        poX  += xPlus;
        sumX += xPlus;
    }

    for (unsigned char i=0; i<decimal; ++i)
    {
        rounding /= 10.0;
    }

    floatNumber += rounding;

    temp = (long)floatNumber;

    xPlus = drawNumber(temp,poX, poY);

    poX  += xPlus;
    sumX += xPlus;

    if(decimal>0)
    {
        xPlus = drawChar('.',poX, poY);
        poX += xPlus;                                       /* Move cursor right            */
        sumX += xPlus;
    }
    else
    {
        return sumX;
    }

    decy = floatNumber - temp;
    for(unsigned char i=0; i<decimal; i++)
    {
        decy *= 10;                                                      /* for the next decimal         */
        temp = decy;                                                    /* get the decimal              */
        xPlus = drawNumber(temp,poX, poY);

        poX += xPlus;                                       /* Move cursor right            */
        sumX += xPlus;
        decy -= temp;
    }
    return sumX;
}

/*********************************************************************************************************
** Function name:           drawLine
** Descriptions:            drawLine
*********************************************************************************************************/
void ePaper::drawLine(int x0, int y0, int x1, int y1)
{

    init_io();

    int x = x1-x0;
    int y = y1-y0;
    int dx = abs(x), sx = x0<x1 ? 1 : -1;
    int dy = -abs(y), sy = y0<y1 ? 1 : -1;
    int err = dx+dy, e2;
    for (;;)
    {
        drawPixel(x0,y0,1);
        e2 = 2*err;
        if (e2 >= dy)
        {
            if (x0 == x1) break;
            err += dy; x0 += sx;
        }
        if (e2 <= dx)
        {
            if (y0 == y1) break;
            err += dx; y0 += sy;
        }
    }
}

/*********************************************************************************************************
** Function name:           clear_sd
** Descriptions:            clear sd card
*********************************************************************************************************/
void ePaper::clear_sd()
{

    init_io();

    for(int i=0; i<DISP_WIDTH; i++)
    {
        for(int j=0; j<DISP_LEN; j++)
        {
            drawPixel(j, i, 0);

        }
    }
}

/*********************************************************************************************************
** Function name:           drawCircle
** Descriptions:            drawCircle
*********************************************************************************************************/
void ePaper::drawCircle(int poX, int poY, int r)
{

    init_io();
    int x = -r, y = 0, err = 2-2*r, e2;
    do {
        drawPixel(poX-x, poY+y, 1);
        drawPixel(poX+x, poY+y, 1);
        drawPixel(poX+x, poY-y, 1);
        drawPixel(poX-x, poY-y, 1);
        e2 = err;
        if (e2 <= y) {
            err += ++y*2+1;
            if (-x == y && e2 <= x) e2 = 0;
        }
        if (e2 > x) err += ++x*2+1;
    } while (x <= 0);
}

/*********************************************************************************************************
** Function name:           drawHorizontalLine
** Descriptions:            drawHorizontalLine
*********************************************************************************************************/
void ePaper::drawHorizontalLine( int poX, int poY, int len)
{
    drawLine(poX, poY, poX+len, poY);
}

/*********************************************************************************************************
** Function name:           drawVerticalLine
** Descriptions:            drawVerticalLine
*********************************************************************************************************/
void ePaper::drawVerticalLine( int poX, int poY, int len)
{
    drawLine(poX, poY, poX, poY+len);
}

/*********************************************************************************************************
** Function name:           drawRectangle
** Descriptions:            drawRectangle
*********************************************************************************************************/
void ePaper::drawRectangle(int poX, int poY, int len, int width)
{
    drawHorizontalLine(poX, poY, len);
    drawHorizontalLine(poX, poY+width, len);
    drawVerticalLine(poX, poY, width);
    drawVerticalLine(poX + len, poY, width);
}

/*********************************************************************************************************
** Function name:           fillCircle
** Descriptions:            fillCircle
*********************************************************************************************************/
void ePaper::fillCircle(int poX, int poY, int r)
{
    int x = -r, y = 0, err = 2-2*r, e2;

    do {

        drawVerticalLine(poX-x, poY-y, 2*y);
        drawVerticalLine(poX+x, poY-y, 2*y);

        e2 = err;
        if (e2 <= y) {
            err += ++y*2+1;
            if (-x == y && e2 <= x) e2 = 0;
        }
        if (e2 > x) err += ++x*2+1;
    } while (x <= 0);

}

/*********************************************************************************************************
** Function name:           drawTraingle
** Descriptions:            drawTraingle
*********************************************************************************************************/
void ePaper::drawTraingle( int poX1, int poY1, int poX2, int poY2, int poX3, int poY3)
{
    drawLine(poX1, poY1, poX2, poY2);
    drawLine(poX1, poY1, poX3, poY3);
    drawLine(poX2, poY2, poX3, poY3);
}

/*********************************************************************************************************
** Function name:           drawTraingle
** Descriptions:            drawTraingle
*********************************************************************************************************/
void ePaper::fillRectangle(int poX, int poY, int len, int width)
{
    for(int i=0; i<width; i++)
    {
        drawHorizontalLine(poX, poY+i, len);
    }
}

/*********************************************************************************************************
** Function name:           display
** Descriptions:            you should use this function once after finish drawing
*********************************************************************************************************/
unsigned char ePaper::display()
{
    start();
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega328P__)
    EPD.image_sd();
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    EPD.image_sram(eSD.sram_image);
#endif
    end();
}

ePaper EPAPER;
/*********************************************************************************************************
  END FILE
*********************************************************************************************************/
<commit_msg>Removed size switch and set direction<commit_after>/*
  ePaper.cpp
  2013 Copyright (c) Seeed Technology Inc.  All right reserved.

  Modified by Loovee
  www.seeedstudio.com
  2013-7-2

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <Arduino.h>
#include <SPI.h>
#include "GT20L16_drive.h"
#include "ePaper.h"

static void spi_on()
{
    SPI.begin();
    //SPI.setClockDivider(SPI_CLOCK_DIV2);
    //SPI_put(0x00);
    //SPI_put(0x00);
}

/*********************************************************************************************************
* \brief According to EPD size and temperature to get stage_time
* \note Refer to COG document Section 5.3 for more details
*
* \param EPD_type_index The defined EPD size
**********************************************************************************************************/
void ePaper::begin(EPD_size sz)
{
    size = sz;
    direction = DIRNORMAL;

    DISP_LEN    = 200;
    DISP_WIDTH  = 96;

    EPD.begin(size);
    init_io();
}

/*********************************************************************************************************
** Function name:           start
** Descriptions:            start
*********************************************************************************************************/
void ePaper::start()
{
    EPD.start();                 // power up the EPD panel

    int tmp = getTemperature();
    Serial.print("temperature: ");
    EPD.setFactor(getTemperature());         // adjust for current temperature
}

/*********************************************************************************************************
** Function name:           end
** Descriptions:            end
*********************************************************************************************************/
void ePaper::end()
{
    EPD.end();
}

/*********************************************************************************************************
** Function name:           init_io
** Descriptions:            init IO
*********************************************************************************************************/
void ePaper::init_io()
{
    // init IO
    pinMode(Pin_BUSY, INPUT);
    pinMode(Pin_RESET, OUTPUT);
    pinMode(Pin_PANEL_ON, OUTPUT);
    pinMode(Pin_DISCHARGE, OUTPUT);
    pinMode(Pin_BORDER, OUTPUT);
    pinMode(Pin_EPD_CS, OUTPUT);
    pinMode(Pin_SD_CS, OUTPUT);

    pinMode(9, OUTPUT);
    digitalWrite(9, HIGH);

    digitalWrite(Pin_RESET, LOW);
    digitalWrite(Pin_PANEL_ON, LOW);
    digitalWrite(Pin_DISCHARGE, LOW);
    digitalWrite(Pin_BORDER, LOW);
    digitalWrite(Pin_EPD_CS, HIGH);
    digitalWrite(Pin_SD_CS, HIGH);

    // init SPI
    SPI.begin();
    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE0);
    //SPI.setClockDivider(SPI_CLOCK_DIV2);
}

/*********************************************************************************************************
** Function name:           getTemperature
** Descriptions:            get temperature of sensor
*********************************************************************************************************/
int ePaper::getTemperature()
{
    int sum = 0;
    for(int i=0; i<32; i++)
    {
        sum += analogRead(Pin_TEMPERATURE);
    }
    sum  = sum >> 5;

    float temp = 209.56-121.7*(float(sum)/1023.0*5.0);

    return (int)temp;
}

/*********************************************************************************************************
** Function name:           drawUnicode
** Descriptions:            draw a unicode
*********************************************************************************************************/
int ePaper::drawUnicode(unsigned int uniCode, int x, int y)
{

   // if(((x+16)>= DISP_LEN) || ((y+16) >= DISP_WIDTH) || x<0 || y<0) return 0;

    int dtaLen = GT20L16.getMatrixUnicode(uniCode, tMatrix);

    int pX      = 0;
    int pY      = 0;
    int color   = 0;
    //spi_on();
    for(int k = 0; k<2; k++)
    {
        for(int i=0; i<8; i++)
        {
            for(int j=0; j<(dtaLen/2); j++)
            {

                if(tMatrix[j+(dtaLen/2)*k] & (0x01<<(7-i)))
                {
                    color = 1;
                }
                else
                {
                    color = 0;
                }

                pX = x + j;
                pY = y + k*8+i;

                drawPixel(pX, pY, color);
            }
        }
    }

    return dtaLen/2;        // x +
}

int ePaper::drawUnicode(unsigned char *matrix, int x, int y)
{

   // if(((x+16)>= DISP_LEN) || ((y+16) >= DISP_WIDTH) || x<0 || y<0) return 0;

    int dtaLen  = 32;
    int pX      = 0;
    int pY      = 0;
    int color   = 0;
    //spi_on();
    for(int k = 0; k<2; k++)
    {
        for(int i=0; i<8; i++)
        {
            for(int j=0; j<(dtaLen/2); j++)
            {

                if(matrix[j+(dtaLen/2)*k] & (0x01<<(7-i)))
                {
                    color = 1;
                }
                else
                {
                    color = 0;
                }

                pX = x + j;
                pY = y + k*8+i;

                drawPixel(pX, pY, color);
            }
        }
    }

    return dtaLen/2;        // x +
}

/*********************************************************************************************************
** Function name:           drawUnicodeString
** Descriptions:            draw string
*********************************************************************************************************/
int ePaper::drawUnicodeString(unsigned int *uniCode, int len, int x, int y)
{
    int xPlus = 0;
    int xSum  = 0;

    for(int i=0; i<len; i++)
    {
        xPlus = drawUnicode(uniCode[i], x, y);
        x += xPlus;
        xSum += xPlus;
    }
    return xSum;
}

/*********************************************************************************************************
** Function name:           drawChar
** Descriptions:            draw char
*********************************************************************************************************/
int ePaper::drawChar(char c, int x, int y)
{
    return drawUnicode(c, x, y);
}

/*********************************************************************************************************
** Function name:           drawString
** Descriptions:            draw string
*********************************************************************************************************/
int ePaper::drawString(char *string, int poX, int poY)
{
    int sumX = 0;

    while(*string)
    {

        int xPlus = drawChar(*string, poX, poY);
        sumX += xPlus;
        *string++;

        if(poX < 200)
        {
            poX += xPlus;                                     /* Move cursor right            */
        }
    }

    return sumX;
}

/*********************************************************************************************************
** Function name:           drawNumber
** Descriptions:            drawNumber
*********************************************************************************************************/
int ePaper::drawNumber(long long_num,int poX, int poY)
{
    char tmp[10];
    sprintf(tmp, "%d", long_num);
    return drawString(tmp, poX, poY);

}

/*********************************************************************************************************
** Function name:           drawFloat
** Descriptions:            drawFloat
*********************************************************************************************************/
int ePaper::drawFloat(float floatNumber, int decimal, int poX, int poY)
{
    unsigned long temp=0;
    float decy=0.0;
    float rounding = 0.5;
    unsigned char f=0;

    float eep = 0.000001;

    int sumX    = 0;
    int xPlus   = 0;

    if(floatNumber-0.0 < eep)       // floatNumber < 0
    {
        xPlus = drawChar('-',poX, poY);
        floatNumber = -floatNumber;

        poX  += xPlus;
        sumX += xPlus;
    }

    for (unsigned char i=0; i<decimal; ++i)
    {
        rounding /= 10.0;
    }

    floatNumber += rounding;

    temp = (long)floatNumber;

    xPlus = drawNumber(temp,poX, poY);

    poX  += xPlus;
    sumX += xPlus;

    if(decimal>0)
    {
        xPlus = drawChar('.',poX, poY);
        poX += xPlus;                                       /* Move cursor right            */
        sumX += xPlus;
    }
    else
    {
        return sumX;
    }

    decy = floatNumber - temp;
    for(unsigned char i=0; i<decimal; i++)
    {
        decy *= 10;                                                      /* for the next decimal         */
        temp = decy;                                                    /* get the decimal              */
        xPlus = drawNumber(temp,poX, poY);

        poX += xPlus;                                       /* Move cursor right            */
        sumX += xPlus;
        decy -= temp;
    }
    return sumX;
}

/*********************************************************************************************************
** Function name:           drawLine
** Descriptions:            drawLine
*********************************************************************************************************/
void ePaper::drawLine(int x0, int y0, int x1, int y1)
{

    init_io();

    int x = x1-x0;
    int y = y1-y0;
    int dx = abs(x), sx = x0<x1 ? 1 : -1;
    int dy = -abs(y), sy = y0<y1 ? 1 : -1;
    int err = dx+dy, e2;
    for (;;)
    {
        drawPixel(x0,y0,1);
        e2 = 2*err;
        if (e2 >= dy)
        {
            if (x0 == x1) break;
            err += dy; x0 += sx;
        }
        if (e2 <= dx)
        {
            if (y0 == y1) break;
            err += dx; y0 += sy;
        }
    }
}

/*********************************************************************************************************
** Function name:           clear_sd
** Descriptions:            clear sd card
*********************************************************************************************************/
void ePaper::clear_sd()
{

    init_io();

    for(int i=0; i<DISP_WIDTH; i++)
    {
        for(int j=0; j<DISP_LEN; j++)
        {
            drawPixel(j, i, 0);

        }
    }
}

/*********************************************************************************************************
** Function name:           drawCircle
** Descriptions:            drawCircle
*********************************************************************************************************/
void ePaper::drawCircle(int poX, int poY, int r)
{

    init_io();
    int x = -r, y = 0, err = 2-2*r, e2;
    do {
        drawPixel(poX-x, poY+y, 1);
        drawPixel(poX+x, poY+y, 1);
        drawPixel(poX+x, poY-y, 1);
        drawPixel(poX-x, poY-y, 1);
        e2 = err;
        if (e2 <= y) {
            err += ++y*2+1;
            if (-x == y && e2 <= x) e2 = 0;
        }
        if (e2 > x) err += ++x*2+1;
    } while (x <= 0);
}

/*********************************************************************************************************
** Function name:           drawHorizontalLine
** Descriptions:            drawHorizontalLine
*********************************************************************************************************/
void ePaper::drawHorizontalLine( int poX, int poY, int len)
{
    drawLine(poX, poY, poX+len, poY);
}

/*********************************************************************************************************
** Function name:           drawVerticalLine
** Descriptions:            drawVerticalLine
*********************************************************************************************************/
void ePaper::drawVerticalLine( int poX, int poY, int len)
{
    drawLine(poX, poY, poX, poY+len);
}

/*********************************************************************************************************
** Function name:           drawRectangle
** Descriptions:            drawRectangle
*********************************************************************************************************/
void ePaper::drawRectangle(int poX, int poY, int len, int width)
{
    drawHorizontalLine(poX, poY, len);
    drawHorizontalLine(poX, poY+width, len);
    drawVerticalLine(poX, poY, width);
    drawVerticalLine(poX + len, poY, width);
}

/*********************************************************************************************************
** Function name:           fillCircle
** Descriptions:            fillCircle
*********************************************************************************************************/
void ePaper::fillCircle(int poX, int poY, int r)
{
    int x = -r, y = 0, err = 2-2*r, e2;

    do {

        drawVerticalLine(poX-x, poY-y, 2*y);
        drawVerticalLine(poX+x, poY-y, 2*y);

        e2 = err;
        if (e2 <= y) {
            err += ++y*2+1;
            if (-x == y && e2 <= x) e2 = 0;
        }
        if (e2 > x) err += ++x*2+1;
    } while (x <= 0);

}

/*********************************************************************************************************
** Function name:           drawTraingle
** Descriptions:            drawTraingle
*********************************************************************************************************/
void ePaper::drawTraingle( int poX1, int poY1, int poX2, int poY2, int poX3, int poY3)
{
    drawLine(poX1, poY1, poX2, poY2);
    drawLine(poX1, poY1, poX3, poY3);
    drawLine(poX2, poY2, poX3, poY3);
}

/*********************************************************************************************************
** Function name:           drawTraingle
** Descriptions:            drawTraingle
*********************************************************************************************************/
void ePaper::fillRectangle(int poX, int poY, int len, int width)
{
    for(int i=0; i<width; i++)
    {
        drawHorizontalLine(poX, poY+i, len);
    }
}

/*********************************************************************************************************
** Function name:           display
** Descriptions:            you should use this function once after finish drawing
*********************************************************************************************************/
unsigned char ePaper::display()
{
    start();
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega328P__)
    EPD.image_sd();
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    EPD.image_sram(eSD.sram_image);
#endif
    end();
}

ePaper EPAPER;
/*********************************************************************************************************
  END FILE
*********************************************************************************************************/
<|endoftext|>


<commit_before>#include "monitoringthread.h"
#include "pcloudapp.h"

MonitoringThread::MonitoringThread(PCloudApp *a)
{
    app=a;
    connect(this, SIGNAL(sendMessageSignal(QString, QString)), app, SLOT(showTrayMessage(QString, QString)));
    connect(this, SIGNAL(setOnlineStatus(bool)), app, SLOT(setOnlineStatus(bool)));
}

typedef struct {
    uint32_t type;
    uint32_t length;
    char buff[4096];
} msg;

void MonitoringThread::run()
{
    int unsigned cnt;
    msg m;
    sleep(2);
    cnt=0;
    while (1){
        QFile file(app->settings->get("path")+"/.pfs_settings/events");
        if (file.open(QFile::ReadOnly)){
            if (file.read((char *)&m, sizeof(m))>=8){
                if (m.type&8)
                    emit setOnlineStatus((m.type&4)>0);
                else if (m.type&1 || cnt>2){
                    m.buff[m.length]=0;
                    app->lastMessageType=m.type;
                    emit sendMessageSignal(m.buff, "");
                }
                file.close();
                continue;
            }
            file.close();
        }
        sleep(1);
        cnt++;
    }
}

<commit_msg>Notification changes<commit_after>#include "monitoringthread.h"
#include "pcloudapp.h"

MonitoringThread::MonitoringThread(PCloudApp *a)
{
    app=a;
    connect(this, SIGNAL(sendMessageSignal(QString, QString)), app, SLOT(showTrayMessage(QString, QString)));
    connect(this, SIGNAL(setOnlineStatus(bool)), app, SLOT(setOnlineStatus(bool)));
}

typedef struct {
    uint32_t type;
    uint32_t length;
    char buff[4096];
} msg;

void MonitoringThread::run()
{
    int unsigned cnt;
    msg m;
    sleep(2);
    cnt=0;
    while (1){
        QFile file(app->settings->get("path")+"/.pfs_settings/events");
        if (file.open(QFile::ReadOnly)){
            if (file.read((char *)&m, sizeof(m))>=8){
                emit setOnlineStatus(true);
                if (m.type&1 || cnt>2){
                    m.buff[m.length]=0;
                    app->lastMessageType=m.type;
                    emit sendMessageSignal(m.buff, "");
                }
                file.close();
                continue;
            }
            file.close();
        }
        else{
            emit setOnlineStatus(false);
        }
        sleep(1);
        cnt++;
    }
}

<|endoftext|>


<commit_before>/**
 * \file
 * \brief SignalsWaitOperationsTestCase class implementation
 *
 * \author Copyright (C) 2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-04-02
 */

#include "SignalsWaitOperationsTestCase.hpp"

#include "waitForNextTick.hpp"

#include "distortos/ThisThread-Signals.hpp"
#include "distortos/ThisThread.hpp"
#include "distortos/ThreadBase.hpp"
#include "distortos/SoftwareTimer.hpp"
#include "distortos/statistics.hpp"

#include <cerrno>

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// single duration used in tests
constexpr auto singleDuration = TickClock::duration{1};

/// long duration used in tests
constexpr auto longDuration = singleDuration * 10;

/// expected number of context switches in waitForNextTick(): main -> idle -> main
constexpr decltype(statistics::getContextSwitchCount()) waitForNextTickContextSwitchCount {2};

/// expected number of context switches in phase1 block involving timed-out tryWaitFor() or tryWaitUntil() (excluding
/// waitForNextTick()): 1 - main thread blocks waiting for signals (main -> idle), 2 - main thread wakes up
/// (idle -> main)
constexpr decltype(statistics::getContextSwitchCount()) phase1TimedOutWaitContextSwitchCount {2};

/// expected number of context switches in phase2 block involving software timer (excluding waitForNextTick()): 1 - main
/// thread blocks waiting for signals (main -> idle), 2 - main thread is unblocked by interrupt (idle -> main)
constexpr decltype(statistics::getContextSwitchCount()) phase2SoftwareTimerContextSwitchCount {2};

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Tests whether no signals are pending for current thread.
 *
 * \return true if test succeeded, false otherwise
 */

bool testSelfNoSignalsPending()
{
	const auto pendingSignalSet = ThisThread::Signals::getPendingSignalSet();
	const auto pendingBitset = pendingSignalSet.getBitset();
	return pendingBitset.none();
}

/**
 * \brief Tests whether exactly one signal is pending for current thread.
 *
 * \param [in] signalNumber is the signal number that may be pending for current thread
 *
 * \return true if test succeeded, false otherwise
 */

bool testSelfOneSignalPending(const uint8_t signalNumber)
{
	auto pendingSignalSet = ThisThread::Signals::getPendingSignalSet();
	const auto testResult = pendingSignalSet.test(signalNumber);
	if (testResult.first != 0 || testResult.second != true)	// selected signal number must be pending
		return false;
	// no other signal may be pending
	const auto ret = pendingSignalSet.remove(signalNumber);
	if (ret != 0)
		return false;
	const auto pendingBitset = pendingSignalSet.getBitset();
	return pendingBitset.none();
}

/**
 * \brief Tests generation of signal for current thread.
 *
 * Initially no signals may be pending for current thread. After call to ThisThread::Signals::generateSignal() exactly
 * one signal - \a signalNumber - must be pending.
 *
 * \param [in] signalNumber is the signal number that will be generated
 *
 * \return true if test succeeded, false otherwise
 */

bool testSelfGenerateSignal(const uint8_t signalNumber)
{
	{
		const auto ret = testSelfNoSignalsPending();	// initially no signals may be pending
		if (ret != true)
			return ret;
	}

	{
		const auto ret = ThisThread::Signals::generateSignal(signalNumber);
		if (ret != 0)
			return false;
	}

	return testSelfOneSignalPending(signalNumber);
}

/**
 * \brief Phase 1 of test case.
 *
 * Tests whether all ThisThread::Signals::tryWait*() functions properly ignore pending signal that is not included in
 * SignalSet and accept it otherwise.
 *
 * \return true if test succeeded, false otherwise
 */

bool phase1()
{
	const SignalSet fullSignalSet {SignalSet::full};

	{
		constexpr uint8_t testSignalNumber {19};

		{
			const auto ret = testSelfGenerateSignal(testSignalNumber);
			if (ret != true)
				return ret;
		}

		{
			SignalSet excludingSignalSet {SignalSet::full};
			const auto ret = excludingSignalSet.remove(testSignalNumber);
			if (ret != 0)
				return false;

			waitForNextTick();

			// no signals are pending, so ThisThread::Signals::tryWait() should fail immediately
			const auto start = TickClock::now();
			const auto tryWaitResult = ThisThread::Signals::tryWait(excludingSignalSet);
			if (tryWaitResult.first != EAGAIN || TickClock::now() != start)
				return false;
		}

		{
			// one signal is pending, so ThisThread::Signals::tryWait() must succeed immediately
			waitForNextTick();
			const auto start = TickClock::now();
			const auto tryWaitResult = ThisThread::Signals::tryWait(fullSignalSet);
			auto& signalInformation = tryWaitResult.second;
			if (tryWaitResult.first != 0 || signalInformation.getSignalNumber() != testSignalNumber ||
					signalInformation.getCode() != SignalInformation::Code::Generated || start != TickClock::now())
				return false;
		}
	}

	{
		constexpr uint8_t testSignalNumber {8};

		{
			const auto ret = testSelfGenerateSignal(testSignalNumber);
			if (ret != true)
				return ret;
		}

		{
			SignalSet excludingSignalSet {SignalSet::full};
			const auto ret = excludingSignalSet.remove(testSignalNumber);
			if (ret != 0)
				return false;

			waitForNextTick();

			const auto contextSwitchCount = statistics::getContextSwitchCount();

			// no signals are pending, so ThisThread::Signals::tryWaitFor() should time-out at expected time
			const auto start = TickClock::now();
			const auto tryWaitResult = ThisThread::Signals::tryWaitFor(excludingSignalSet, singleDuration);
			const auto realDuration = TickClock::now() - start;
			if (tryWaitResult.first != ETIMEDOUT || realDuration != singleDuration + decltype(singleDuration){1} ||
					statistics::getContextSwitchCount() - contextSwitchCount != phase1TimedOutWaitContextSwitchCount)
				return false;
		}

		{
			// one signal is pending, so ThisThread::Signals::tryWaitFor() must succeed immediately
			waitForNextTick();
			const auto start = TickClock::now();
			const auto tryWaitResult = ThisThread::Signals::tryWaitFor(fullSignalSet, singleDuration);
			auto& signalInformation = tryWaitResult.second;
			if (tryWaitResult.first != 0 || signalInformation.getSignalNumber() != testSignalNumber ||
					signalInformation.getCode() != SignalInformation::Code::Generated || start != TickClock::now())
				return false;
		}
	}

	{
		constexpr uint8_t testSignalNumber {22};

		{
			const auto ret = testSelfGenerateSignal(testSignalNumber);
			if (ret != true)
				return ret;
		}

		{
			SignalSet excludingSignalSet {SignalSet::full};

			{
				const auto ret = excludingSignalSet.remove(testSignalNumber);
				if (ret != 0)
					return false;
			}

			waitForNextTick();

			const auto contextSwitchCount = statistics::getContextSwitchCount();

			// no signals are pending, so ThisThread::Signals::tryWaitUntil() should time-out at exact expected time
			const auto requestedTimePoint = TickClock::now() + singleDuration;
			const auto tryWaitResult = ThisThread::Signals::tryWaitUntil(excludingSignalSet, requestedTimePoint);
			if (tryWaitResult.first != ETIMEDOUT || requestedTimePoint != TickClock::now() ||
					statistics::getContextSwitchCount() - contextSwitchCount != phase1TimedOutWaitContextSwitchCount)
				return false;
		}

		{
			// one signal is pending, so ThisThread::Signals::tryWaitUntil() must succeed immediately
			waitForNextTick();
			const auto start = TickClock::now();
			const auto tryWaitResult = ThisThread::Signals::tryWaitUntil(fullSignalSet, start + singleDuration);
			auto& signalInformation = tryWaitResult.second;
			if (tryWaitResult.first != 0 || signalInformation.getSignalNumber() != testSignalNumber ||
					signalInformation.getCode() != SignalInformation::Code::Generated || start != TickClock::now())
				return false;
		}
	}

	return testSelfNoSignalsPending();
}

/**
 * \brief Phase 2 of test case.
 *
 * Tests interrupt -> thread communication scenario. Main (current) thread waits for signals. Software timer generates
 * signal for main thread at specified time point from interrupt context, main thread is expected to accept this signal
 * (with ThisThread::Signals::wait(), ThisThread::Signals::tryWaitFor() and ThisThread::Signals::tryWaitUntil()) in the
 * same moment.
 *
 * \return true if test succeeded, false otherwise
 */

bool phase2()
{
	const SignalSet fullSignalSet {SignalSet::full};
	auto& mainThread = ThisThread::get();
	uint8_t sharedSignalNumber {};
	auto softwareTimer = makeSoftwareTimer(
			[&mainThread, &sharedSignalNumber]()
			{
				mainThread.generateSignal(sharedSignalNumber);
			});

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;
		sharedSignalNumber = 3;
		softwareTimer.start(wakeUpTimePoint);

		// no signals are currently pending, but ThisThread::Signals::wait() should succeed at expected time
		const auto waitResult = ThisThread::Signals::wait(fullSignalSet);
		const auto wokenUpTimePoint = TickClock::now();
		auto& signalInformation = waitResult.second;
		if (waitResult.first != 0 || signalInformation.getSignalNumber() != sharedSignalNumber ||
				signalInformation.getCode() != SignalInformation::Code::Generated ||
				wakeUpTimePoint != wokenUpTimePoint ||
				statistics::getContextSwitchCount() - contextSwitchCount != phase2SoftwareTimerContextSwitchCount)
			return false;
	}

	{
		const auto ret = testSelfNoSignalsPending();	// no signals may be pending
		if (ret != true)
			return ret;
	}

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;
		sharedSignalNumber = 26;
		softwareTimer.start(wakeUpTimePoint);

		// no signals are currently pending, but ThisThread::Signals::tryWaitFor() should succeed at expected time
		const auto tryWaitResult = ThisThread::Signals::tryWaitFor(fullSignalSet, wakeUpTimePoint - TickClock::now() +
				longDuration);
		const auto wokenUpTimePoint = TickClock::now();
		auto& signalInformation = tryWaitResult.second;
		if (tryWaitResult.first != 0 || signalInformation.getSignalNumber() != sharedSignalNumber ||
				signalInformation.getCode() != SignalInformation::Code::Generated ||
				wakeUpTimePoint != wokenUpTimePoint ||
				statistics::getContextSwitchCount() - contextSwitchCount != phase2SoftwareTimerContextSwitchCount)
			return false;
	}

	{
		const auto ret = testSelfNoSignalsPending();	// no signals may be pending
		if (ret != true)
			return ret;
	}

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;
		sharedSignalNumber = 5;
		softwareTimer.start(wakeUpTimePoint);

		// no signals are currently pending, but ThisThread::Signals::tryWaitUntil() should succeed at expected time
		const auto tryWaitResult = ThisThread::Signals::tryWaitUntil(fullSignalSet, wakeUpTimePoint + longDuration);
		const auto wokenUpTimePoint = TickClock::now();
		auto& signalInformation = tryWaitResult.second;
		if (tryWaitResult.first != 0 || signalInformation.getSignalNumber() != sharedSignalNumber ||
				signalInformation.getCode() != SignalInformation::Code::Generated ||
				wakeUpTimePoint != wokenUpTimePoint ||
				statistics::getContextSwitchCount() - contextSwitchCount != phase2SoftwareTimerContextSwitchCount)
			return false;
	}

	{
		const auto ret = testSelfNoSignalsPending();	// no signals may be pending
		if (ret != true)
			return ret;
	}

	return true;
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool SignalsWaitOperationsTestCase::run_() const
{
	constexpr auto phase1ExpectedContextSwitchCount = 6 * waitForNextTickContextSwitchCount +
			2 * phase1TimedOutWaitContextSwitchCount;
	constexpr auto phase2ExpectedContextSwitchCount = 3 * waitForNextTickContextSwitchCount +
			3 * phase2SoftwareTimerContextSwitchCount;
	constexpr auto expectedContextSwitchCount = phase1ExpectedContextSwitchCount + phase2ExpectedContextSwitchCount;

	const auto contextSwitchCount = statistics::getContextSwitchCount();

	for (const auto& function : {phase1, phase2})
	{
		{
			const auto ret = testSelfNoSignalsPending();	// initially no signals may be pending
			if (ret != true)
				return ret;
		}

		const auto ret = function();
		if (ret != true)
			return ret;
	}

	const auto ret = testSelfNoSignalsPending();	// after the test no signals may be pending
	if (ret != true)
		return ret;

	if (statistics::getContextSwitchCount() - contextSwitchCount != expectedContextSwitchCount)
		return false;

	return true;
}

}	// namespace test

}	// namespace distortos
<commit_msg>test, SignalsWaitOperationsTestCase: add local testReceivedGeneratedSignal() and use it in test phases<commit_after>/**
 * \file
 * \brief SignalsWaitOperationsTestCase class implementation
 *
 * \author Copyright (C) 2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-04-02
 */

#include "SignalsWaitOperationsTestCase.hpp"

#include "waitForNextTick.hpp"

#include "distortos/ThisThread-Signals.hpp"
#include "distortos/ThisThread.hpp"
#include "distortos/ThreadBase.hpp"
#include "distortos/SoftwareTimer.hpp"
#include "distortos/statistics.hpp"

#include <cerrno>

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// single duration used in tests
constexpr auto singleDuration = TickClock::duration{1};

/// long duration used in tests
constexpr auto longDuration = singleDuration * 10;

/// expected number of context switches in waitForNextTick(): main -> idle -> main
constexpr decltype(statistics::getContextSwitchCount()) waitForNextTickContextSwitchCount {2};

/// expected number of context switches in phase1 block involving timed-out tryWaitFor() or tryWaitUntil() (excluding
/// waitForNextTick()): 1 - main thread blocks waiting for signals (main -> idle), 2 - main thread wakes up
/// (idle -> main)
constexpr decltype(statistics::getContextSwitchCount()) phase1TimedOutWaitContextSwitchCount {2};

/// expected number of context switches in phase2 block involving software timer (excluding waitForNextTick()): 1 - main
/// thread blocks waiting for signals (main -> idle), 2 - main thread is unblocked by interrupt (idle -> main)
constexpr decltype(statistics::getContextSwitchCount()) phase2SoftwareTimerContextSwitchCount {2};

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Tests whether received SignalInformation object matches the signal that was generated.
 *
 * \param [in] signalInformation is a reference to received SignalInformation object
 * \param [in] signalNumber is the signal number that was generated
 *
 * \return true if test succeeded, false otherwise
 */

bool testReceivedGeneratedSignal(const SignalInformation& signalInformation, const uint8_t signalNumber)
{
	return signalInformation.getSignalNumber() == signalNumber &&
			signalInformation.getCode() == SignalInformation::Code::Generated;
}

/**
 * \brief Tests whether no signals are pending for current thread.
 *
 * \return true if test succeeded, false otherwise
 */

bool testSelfNoSignalsPending()
{
	const auto pendingSignalSet = ThisThread::Signals::getPendingSignalSet();
	const auto pendingBitset = pendingSignalSet.getBitset();
	return pendingBitset.none();
}

/**
 * \brief Tests whether exactly one signal is pending for current thread.
 *
 * \param [in] signalNumber is the signal number that may be pending for current thread
 *
 * \return true if test succeeded, false otherwise
 */

bool testSelfOneSignalPending(const uint8_t signalNumber)
{
	auto pendingSignalSet = ThisThread::Signals::getPendingSignalSet();
	const auto testResult = pendingSignalSet.test(signalNumber);
	if (testResult.first != 0 || testResult.second != true)	// selected signal number must be pending
		return false;
	// no other signal may be pending
	const auto ret = pendingSignalSet.remove(signalNumber);
	if (ret != 0)
		return false;
	const auto pendingBitset = pendingSignalSet.getBitset();
	return pendingBitset.none();
}

/**
 * \brief Tests generation of signal for current thread.
 *
 * Initially no signals may be pending for current thread. After call to ThisThread::Signals::generateSignal() exactly
 * one signal - \a signalNumber - must be pending.
 *
 * \param [in] signalNumber is the signal number that will be generated
 *
 * \return true if test succeeded, false otherwise
 */

bool testSelfGenerateSignal(const uint8_t signalNumber)
{
	{
		const auto ret = testSelfNoSignalsPending();	// initially no signals may be pending
		if (ret != true)
			return ret;
	}

	{
		const auto ret = ThisThread::Signals::generateSignal(signalNumber);
		if (ret != 0)
			return false;
	}

	return testSelfOneSignalPending(signalNumber);
}

/**
 * \brief Phase 1 of test case.
 *
 * Tests whether all ThisThread::Signals::tryWait*() functions properly ignore pending signal that is not included in
 * SignalSet and accept it otherwise.
 *
 * \return true if test succeeded, false otherwise
 */

bool phase1()
{
	const SignalSet fullSignalSet {SignalSet::full};

	{
		constexpr uint8_t testSignalNumber {19};

		{
			const auto ret = testSelfGenerateSignal(testSignalNumber);
			if (ret != true)
				return ret;
		}

		{
			SignalSet excludingSignalSet {SignalSet::full};
			const auto ret = excludingSignalSet.remove(testSignalNumber);
			if (ret != 0)
				return false;

			waitForNextTick();

			// no signals are pending, so ThisThread::Signals::tryWait() should fail immediately
			const auto start = TickClock::now();
			const auto tryWaitResult = ThisThread::Signals::tryWait(excludingSignalSet);
			if (tryWaitResult.first != EAGAIN || TickClock::now() != start)
				return false;
		}

		{
			// one signal is pending, so ThisThread::Signals::tryWait() must succeed immediately
			waitForNextTick();
			const auto start = TickClock::now();
			const auto tryWaitResult = ThisThread::Signals::tryWait(fullSignalSet);
			auto& signalInformation = tryWaitResult.second;
			if (tryWaitResult.first != 0 || testReceivedGeneratedSignal(signalInformation, testSignalNumber) != true ||
					start != TickClock::now())
				return false;
		}
	}

	{
		constexpr uint8_t testSignalNumber {8};

		{
			const auto ret = testSelfGenerateSignal(testSignalNumber);
			if (ret != true)
				return ret;
		}

		{
			SignalSet excludingSignalSet {SignalSet::full};
			const auto ret = excludingSignalSet.remove(testSignalNumber);
			if (ret != 0)
				return false;

			waitForNextTick();

			const auto contextSwitchCount = statistics::getContextSwitchCount();

			// no signals are pending, so ThisThread::Signals::tryWaitFor() should time-out at expected time
			const auto start = TickClock::now();
			const auto tryWaitResult = ThisThread::Signals::tryWaitFor(excludingSignalSet, singleDuration);
			const auto realDuration = TickClock::now() - start;
			if (tryWaitResult.first != ETIMEDOUT || realDuration != singleDuration + decltype(singleDuration){1} ||
					statistics::getContextSwitchCount() - contextSwitchCount != phase1TimedOutWaitContextSwitchCount)
				return false;
		}

		{
			// one signal is pending, so ThisThread::Signals::tryWaitFor() must succeed immediately
			waitForNextTick();
			const auto start = TickClock::now();
			const auto tryWaitResult = ThisThread::Signals::tryWaitFor(fullSignalSet, singleDuration);
			auto& signalInformation = tryWaitResult.second;
			if (tryWaitResult.first != 0 || testReceivedGeneratedSignal(signalInformation, testSignalNumber) != true ||
					start != TickClock::now())
				return false;
		}
	}

	{
		constexpr uint8_t testSignalNumber {22};

		{
			const auto ret = testSelfGenerateSignal(testSignalNumber);
			if (ret != true)
				return ret;
		}

		{
			SignalSet excludingSignalSet {SignalSet::full};

			{
				const auto ret = excludingSignalSet.remove(testSignalNumber);
				if (ret != 0)
					return false;
			}

			waitForNextTick();

			const auto contextSwitchCount = statistics::getContextSwitchCount();

			// no signals are pending, so ThisThread::Signals::tryWaitUntil() should time-out at exact expected time
			const auto requestedTimePoint = TickClock::now() + singleDuration;
			const auto tryWaitResult = ThisThread::Signals::tryWaitUntil(excludingSignalSet, requestedTimePoint);
			if (tryWaitResult.first != ETIMEDOUT || requestedTimePoint != TickClock::now() ||
					statistics::getContextSwitchCount() - contextSwitchCount != phase1TimedOutWaitContextSwitchCount)
				return false;
		}

		{
			// one signal is pending, so ThisThread::Signals::tryWaitUntil() must succeed immediately
			waitForNextTick();
			const auto start = TickClock::now();
			const auto tryWaitResult = ThisThread::Signals::tryWaitUntil(fullSignalSet, start + singleDuration);
			auto& signalInformation = tryWaitResult.second;
			if (tryWaitResult.first != 0 || testReceivedGeneratedSignal(signalInformation, testSignalNumber) != true ||
					start != TickClock::now())
				return false;
		}
	}

	return testSelfNoSignalsPending();
}

/**
 * \brief Phase 2 of test case.
 *
 * Tests interrupt -> thread communication scenario. Main (current) thread waits for signals. Software timer generates
 * signal for main thread at specified time point from interrupt context, main thread is expected to accept this signal
 * (with ThisThread::Signals::wait(), ThisThread::Signals::tryWaitFor() and ThisThread::Signals::tryWaitUntil()) in the
 * same moment.
 *
 * \return true if test succeeded, false otherwise
 */

bool phase2()
{
	const SignalSet fullSignalSet {SignalSet::full};
	auto& mainThread = ThisThread::get();
	uint8_t sharedSignalNumber {};
	auto softwareTimer = makeSoftwareTimer(
			[&mainThread, &sharedSignalNumber]()
			{
				mainThread.generateSignal(sharedSignalNumber);
			});

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;
		sharedSignalNumber = 3;
		softwareTimer.start(wakeUpTimePoint);

		// no signals are currently pending, but ThisThread::Signals::wait() should succeed at expected time
		const auto waitResult = ThisThread::Signals::wait(fullSignalSet);
		const auto wokenUpTimePoint = TickClock::now();
		auto& signalInformation = waitResult.second;
		if (waitResult.first != 0 || testReceivedGeneratedSignal(signalInformation, sharedSignalNumber) != true ||
				wakeUpTimePoint != wokenUpTimePoint ||
				statistics::getContextSwitchCount() - contextSwitchCount != phase2SoftwareTimerContextSwitchCount)
			return false;
	}

	{
		const auto ret = testSelfNoSignalsPending();	// no signals may be pending
		if (ret != true)
			return ret;
	}

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;
		sharedSignalNumber = 26;
		softwareTimer.start(wakeUpTimePoint);

		// no signals are currently pending, but ThisThread::Signals::tryWaitFor() should succeed at expected time
		const auto tryWaitResult = ThisThread::Signals::tryWaitFor(fullSignalSet, wakeUpTimePoint - TickClock::now() +
				longDuration);
		const auto wokenUpTimePoint = TickClock::now();
		auto& signalInformation = tryWaitResult.second;
		if (tryWaitResult.first != 0 || testReceivedGeneratedSignal(signalInformation, sharedSignalNumber) != true ||
				wakeUpTimePoint != wokenUpTimePoint ||
				statistics::getContextSwitchCount() - contextSwitchCount != phase2SoftwareTimerContextSwitchCount)
			return false;
	}

	{
		const auto ret = testSelfNoSignalsPending();	// no signals may be pending
		if (ret != true)
			return ret;
	}

	{
		waitForNextTick();

		const auto contextSwitchCount = statistics::getContextSwitchCount();
		const auto wakeUpTimePoint = TickClock::now() + longDuration;
		sharedSignalNumber = 5;
		softwareTimer.start(wakeUpTimePoint);

		// no signals are currently pending, but ThisThread::Signals::tryWaitUntil() should succeed at expected time
		const auto tryWaitResult = ThisThread::Signals::tryWaitUntil(fullSignalSet, wakeUpTimePoint + longDuration);
		const auto wokenUpTimePoint = TickClock::now();
		auto& signalInformation = tryWaitResult.second;
		if (tryWaitResult.first != 0 || testReceivedGeneratedSignal(signalInformation, sharedSignalNumber) != true ||
				wakeUpTimePoint != wokenUpTimePoint ||
				statistics::getContextSwitchCount() - contextSwitchCount != phase2SoftwareTimerContextSwitchCount)
			return false;
	}

	{
		const auto ret = testSelfNoSignalsPending();	// no signals may be pending
		if (ret != true)
			return ret;
	}

	return true;
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool SignalsWaitOperationsTestCase::run_() const
{
	constexpr auto phase1ExpectedContextSwitchCount = 6 * waitForNextTickContextSwitchCount +
			2 * phase1TimedOutWaitContextSwitchCount;
	constexpr auto phase2ExpectedContextSwitchCount = 3 * waitForNextTickContextSwitchCount +
			3 * phase2SoftwareTimerContextSwitchCount;
	constexpr auto expectedContextSwitchCount = phase1ExpectedContextSwitchCount + phase2ExpectedContextSwitchCount;

	const auto contextSwitchCount = statistics::getContextSwitchCount();

	for (const auto& function : {phase1, phase2})
	{
		{
			const auto ret = testSelfNoSignalsPending();	// initially no signals may be pending
			if (ret != true)
				return ret;
		}

		const auto ret = function();
		if (ret != true)
			return ret;
	}

	const auto ret = testSelfNoSignalsPending();	// after the test no signals may be pending
	if (ret != true)
		return ret;

	if (statistics::getContextSwitchCount() - contextSwitchCount != expectedContextSwitchCount)
		return false;

	return true;
}

}	// namespace test

}	// namespace distortos
<|endoftext|>


<commit_before>/* vim:set ft=cpp ts=4 sw=4 sts=4 et cindent: */
/*
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MIT
 *
 * Copyright (c) 2010-2013 Alan Antonuk
 *
 * 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.
 * ***** END LICENSE BLOCK *****
 */

#include "connected_test.h"

using namespace AmqpClient;

TEST_F(connected_test, first_channel)
{
    channel->DeclareExchange("test_channel_exchange", Channel::EXCHANGE_TYPE_FANOUT, false, false, true);
    channel->DeleteExchange("test_channel_exchange");
}

// Check to see that channels are reused properly
TEST_F(connected_test, channel_reuse)
{
    channel->DeclareExchange("test_channel_exchange1", Channel::EXCHANGE_TYPE_FANOUT, false, false, true);
    channel->DeclareExchange("test_channel_exchange2", Channel::EXCHANGE_TYPE_FANOUT, false, false, true);
    channel->DeleteExchange("test_channel_exchange1");
    channel->DeleteExchange("test_channel_exchange2");
}

// Check to see that a new channel is created when a channel is put in an exception state
TEST_F(connected_test, channel_recover_from_error)
{
    EXPECT_THROW(channel->DeclareExchange("test_channel_exchangedoesnotexist", Channel::EXCHANGE_TYPE_FANOUT, true, false, true), ChannelException);

    channel->DeclareExchange("test_channel_exchange", Channel::EXCHANGE_TYPE_FANOUT, false, false, true);
    channel->DeleteExchange("test_channel_exchange");
}

TEST_F(connected_test, channel_publish_success1)
{
    BasicMessage::ptr_t message = BasicMessage::Create("Test message");

    channel->BasicPublish("", "test_channel_routingkey", message, false, false);
}

TEST_F(connected_test, channel_publish_success2)
{
    BasicMessage::ptr_t message = BasicMessage::Create("Test message");

    channel->BasicPublish("", "test_channel_routingkey", message, false, false);
    channel->BasicPublish("", "test_channel_routingkey", message, false, false);
}

TEST_F(connected_test, channel_publish_returned_mandatory)
{
    BasicMessage::ptr_t message = BasicMessage::Create("Test message");

    EXPECT_THROW(channel->BasicPublish("", "test_channel_noqueue", message, true, false), MessageReturnedException);
}

TEST_F(connected_test, DISABLED_channel_publish_returned_immediate)
{
    BasicMessage::ptr_t message = BasicMessage::Create("Test message");
    std::string queue_name = channel->DeclareQueue("");

    EXPECT_THROW(channel->BasicPublish("", queue_name, message, false, true), MessageReturnedException);
}

TEST_F(connected_test, channel_publish_bad_exchange)
{
    BasicMessage::ptr_t message = BasicMessage::Create("Test message");

    EXPECT_THROW(channel->BasicPublish("test_channel_badexchange", "test_channel_rk", message, false, false), ChannelException);
}

TEST_F(connected_test, channel_publish_bad_exchange_recover)
{
    BasicMessage::ptr_t message = BasicMessage::Create("Test message");

    EXPECT_THROW(channel->BasicPublish("test_channel_badexchange", "test_channel_rk", message, false, false), ChannelException);

    channel->BasicPublish("", "test_channel_rk", message, false, false);
}

TEST_F(connected_test, channel_consume_success)
{
    BasicMessage::ptr_t message = BasicMessage::Create("Test message");
    std::string queue = channel->DeclareQueue("");
    channel->BasicPublish("", queue, message);

    std::string consumer = channel->BasicConsume(queue);

    Envelope::ptr_t consumed_envelope;
    EXPECT_TRUE(channel->BasicConsumeMessage(consumer, consumed_envelope));
}

TEST_F(connected_test, channel_consume_success_timeout)
{
    BasicMessage::ptr_t message = BasicMessage::Create("Test message");
    std::string queue = channel->DeclareQueue("");

    std::string consumer = channel->BasicConsume(queue, "", true, false);
    channel->BasicPublish("", queue, message);

    Envelope::ptr_t consumed_envelope;
    EXPECT_TRUE(channel->BasicConsumeMessage(consumer, consumed_envelope, 1));
}

TEST(test_channels, big_message)
{
    Channel::ptr_t channel = Channel::Create(connected_test::GetBrokerHost(), 5672, "guest", "guest", "/", 4096);
    BasicMessage::ptr_t message = BasicMessage::Create(std::string(4099, 'a'));

    std::string queue = channel->DeclareQueue("");

    std::string consumer = channel->BasicConsume(queue);
    channel->BasicPublish("", queue, message);

    Envelope::ptr_t consumed_envelope;
    EXPECT_TRUE(channel->BasicConsumeMessage(consumer, consumed_envelope));
}
<commit_msg>test: bump timeout on channel_consume_success_timeout<commit_after>/* vim:set ft=cpp ts=4 sw=4 sts=4 et cindent: */
/*
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MIT
 *
 * Copyright (c) 2010-2013 Alan Antonuk
 *
 * 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.
 * ***** END LICENSE BLOCK *****
 */

#include "connected_test.h"

using namespace AmqpClient;

TEST_F(connected_test, first_channel)
{
    channel->DeclareExchange("test_channel_exchange", Channel::EXCHANGE_TYPE_FANOUT, false, false, true);
    channel->DeleteExchange("test_channel_exchange");
}

// Check to see that channels are reused properly
TEST_F(connected_test, channel_reuse)
{
    channel->DeclareExchange("test_channel_exchange1", Channel::EXCHANGE_TYPE_FANOUT, false, false, true);
    channel->DeclareExchange("test_channel_exchange2", Channel::EXCHANGE_TYPE_FANOUT, false, false, true);
    channel->DeleteExchange("test_channel_exchange1");
    channel->DeleteExchange("test_channel_exchange2");
}

// Check to see that a new channel is created when a channel is put in an exception state
TEST_F(connected_test, channel_recover_from_error)
{
    EXPECT_THROW(channel->DeclareExchange("test_channel_exchangedoesnotexist", Channel::EXCHANGE_TYPE_FANOUT, true, false, true), ChannelException);

    channel->DeclareExchange("test_channel_exchange", Channel::EXCHANGE_TYPE_FANOUT, false, false, true);
    channel->DeleteExchange("test_channel_exchange");
}

TEST_F(connected_test, channel_publish_success1)
{
    BasicMessage::ptr_t message = BasicMessage::Create("Test message");

    channel->BasicPublish("", "test_channel_routingkey", message, false, false);
}

TEST_F(connected_test, channel_publish_success2)
{
    BasicMessage::ptr_t message = BasicMessage::Create("Test message");

    channel->BasicPublish("", "test_channel_routingkey", message, false, false);
    channel->BasicPublish("", "test_channel_routingkey", message, false, false);
}

TEST_F(connected_test, channel_publish_returned_mandatory)
{
    BasicMessage::ptr_t message = BasicMessage::Create("Test message");

    EXPECT_THROW(channel->BasicPublish("", "test_channel_noqueue", message, true, false), MessageReturnedException);
}

TEST_F(connected_test, DISABLED_channel_publish_returned_immediate)
{
    BasicMessage::ptr_t message = BasicMessage::Create("Test message");
    std::string queue_name = channel->DeclareQueue("");

    EXPECT_THROW(channel->BasicPublish("", queue_name, message, false, true), MessageReturnedException);
}

TEST_F(connected_test, channel_publish_bad_exchange)
{
    BasicMessage::ptr_t message = BasicMessage::Create("Test message");

    EXPECT_THROW(channel->BasicPublish("test_channel_badexchange", "test_channel_rk", message, false, false), ChannelException);
}

TEST_F(connected_test, channel_publish_bad_exchange_recover)
{
    BasicMessage::ptr_t message = BasicMessage::Create("Test message");

    EXPECT_THROW(channel->BasicPublish("test_channel_badexchange", "test_channel_rk", message, false, false), ChannelException);

    channel->BasicPublish("", "test_channel_rk", message, false, false);
}

TEST_F(connected_test, channel_consume_success)
{
    BasicMessage::ptr_t message = BasicMessage::Create("Test message");
    std::string queue = channel->DeclareQueue("");
    channel->BasicPublish("", queue, message);

    std::string consumer = channel->BasicConsume(queue);

    Envelope::ptr_t consumed_envelope;
    EXPECT_TRUE(channel->BasicConsumeMessage(consumer, consumed_envelope));
}

TEST_F(connected_test, channel_consume_success_timeout)
{
    BasicMessage::ptr_t message = BasicMessage::Create("Test message");
    std::string queue = channel->DeclareQueue("");

    std::string consumer = channel->BasicConsume(queue, "", true, false);
    channel->BasicPublish("", queue, message);

    Envelope::ptr_t consumed_envelope;
    EXPECT_TRUE(channel->BasicConsumeMessage(consumer, consumed_envelope, 5000));
}

TEST(test_channels, big_message)
{
    Channel::ptr_t channel = Channel::Create(connected_test::GetBrokerHost(), 5672, "guest", "guest", "/", 4096);
    BasicMessage::ptr_t message = BasicMessage::Create(std::string(4099, 'a'));

    std::string queue = channel->DeclareQueue("");

    std::string consumer = channel->BasicConsume(queue);
    channel->BasicPublish("", queue, message);

    Envelope::ptr_t consumed_envelope;
    EXPECT_TRUE(channel->BasicConsumeMessage(consumer, consumed_envelope));
}
<|endoftext|>


<commit_before>#include <Nazara/Math/Ray.hpp>
#include <Catch/catch.hpp>

SCENARIO("Ray", "[MATH][RAY]")
{
	GIVEN("Two same Rays (0, 0, 0) -> (0, 1, 0)")
	{
		Nz::Rayf ray(Nz::Ray<int>(Nz::Plane<int>::XY(), Nz::Plane<int>::YZ()));
		Nz::Rayf secondRay(0.f, 0.f, 0.f, 0.f, 1.f, 0.f);

		WHEN("We compare them")
		{
			THEN("They are the same and Y axis")
			{
				REQUIRE(ray == secondRay);
				REQUIRE(ray == Nz::Rayf::AxisY());
			}
		}

		WHEN("We ask for the closest point")
		{
			THEN("The point that is multiple on the Nz::Ray, is at multiple")
			{
				REQUIRE(ray.ClosestPoint(secondRay.GetPoint(1.f)) == Approx(1.f));
			}
		}

		WHEN("We ask for intersection")
		{
			THEN("For the Box collision's")
			{
				float tmpClosest;
				float tmpFurthest;

				CHECK(ray.Intersect(Nz::Boxf(-0.5f, 1.f, -0.5f, 1.f, 1.f, 1.f), &tmpClosest, &tmpFurthest));
				REQUIRE(ray.GetPoint(tmpClosest) == Nz::Vector3f::UnitY());
				REQUIRE(ray.GetPoint(tmpFurthest) == (Nz::Vector3f::UnitY() * 2.f));
				CHECK(!ray.Intersect(Nz::Boxf(-10.f, 1.f, -10.f, 1.f, 1.f, 1.f), &tmpClosest, &tmpFurthest));
			}

			THEN("For the Nz::Plane collision's")
			{
				float tmpHit;

				CHECK(ray.Intersect(Nz::Planef(Nz::Vector3f::UnitY(), 1.f), &tmpHit));
				REQUIRE(ray.GetPoint(tmpHit) == Nz::Vector3f::UnitY());
				CHECK(ray.Intersect(Nz::Planef::XZ(), &tmpHit));
				REQUIRE(ray.GetPoint(tmpHit) == Nz::Vector3f::Zero());
				CHECK(ray.Intersect(Nz::Planef(Nz::Vector3f::UnitY(), 2.f), &tmpHit));
				REQUIRE(ray.GetPoint(tmpHit) == 2.f * Nz::Vector3f::UnitY());

				CHECK(!ray.Intersect(Nz::Planef(Nz::Vector3f::UnitX(), 1.f)));
			}

			THEN("For the Sphere collision's")
			{
				float tmpClosest;
				float tmpFurthest;

				CHECK(ray.Intersect(Nz::Spheref(Nz::Vector3f::UnitY(), 0.1f), &tmpClosest, &tmpFurthest));
				REQUIRE(ray.GetPoint(tmpClosest) == Nz::Vector3f::UnitY() * 0.9f);
				REQUIRE(ray.GetPoint(tmpFurthest) == (Nz::Vector3f::UnitY() * 1.1f));

				CHECK(!ray.Intersect(Nz::Spheref(Nz::Vector3f::UnitX(), 0.9f)));
			}

			THEN("For the OBB collision's")
			{
				float tmpClosest;
				float tmpFurthest;

				Nz::OrientedBoxf obb(-0.5f, 1.f, -0.5f, 1.f, 1.f, 1.f);
				obb.Update(Nz::Matrix4f::Rotate(Nz::EulerAnglesf(0.f, 90.f, 0.f).ToQuaternion()));

				CHECK(ray.Intersect(obb, &tmpClosest, &tmpFurthest));
				REQUIRE(ray.GetPoint(tmpClosest) == Nz::Vector3f::UnitY());
				REQUIRE(ray.GetPoint(tmpFurthest) == (Nz::Vector3f::UnitY() * 2.f));

				obb = Nz::OrientedBoxf(-10.f, 1.f, -10.f, 1.f, 1.f, 1.f);
				obb.Update(Nz::Matrix4f::Rotate(Nz::EulerAnglesf(0.f, 0.f, 90.f).ToQuaternion()));
				CHECK(!ray.Intersect(obb, &tmpClosest, &tmpFurthest));
			}

			THEN("For the bounding volume collision's")
			{
				Nz::BoundingVolumef nullVolume(Nz::Extend_Null);
				CHECK(!ray.Intersect(nullVolume));

				float tmpClosest = -1.f;
				float tmpFurthest = -1.f;
				Nz::BoundingVolumef infiniteVolume(Nz::Extend_Infinite);
				CHECK(ray.Intersect(infiniteVolume, &tmpClosest, &tmpFurthest));
				CHECK(tmpClosest == Approx(0.f));
				CHECK(tmpFurthest == std::numeric_limits<float>::infinity());
			}

			THEN("For the triangle collision's")
			{
				Nz::Vector3f firstPoint(0.f, 1.f, 1.f);
				Nz::Vector3f secondPoint(-1.f, 1.f, -1.f);
				Nz::Vector3f thidPoint(1.f, 1.f, -1.f);
				float tmpHit = -1.f;

				CHECK(ray.Intersect(firstPoint, secondPoint, thidPoint, &tmpHit));
				REQUIRE(ray.GetPoint(tmpHit) == Nz::Vector3f::UnitY());

				Nz::Vector3f offset = Nz::Vector3f(10.f, 0.f, 10.f);
				CHECK(!ray.Intersect(firstPoint + offset, secondPoint + offset, thidPoint + offset, &tmpHit));
			}
		}

		WHEN("We try to lerp")
		{
			THEN("Compilation should be fine")
			{
				Nz::Rayf AxisX = Nz::Rayf::AxisX();
				Nz::Rayf AxisY = Nz::Rayf::AxisY();
				REQUIRE(Nz::Rayf::Lerp(AxisX, AxisY, 0.5f) == (Nz::Rayf(Nz::Vector3f::Zero(), Nz::Vector3f(0.5f, 0.5f, 0.f))));
			}
		}
	}
}
<commit_msg>Update Ray.cpp<commit_after>#include <Nazara/Math/Ray.hpp>
#include <Catch/catch.hpp>

SCENARIO("Ray", "[MATH][RAY]")
{
	GIVEN("Two same Rays (0, 0, 0) -> (0, 1, 0)")
	{
		Nz::Rayf ray(Nz::Ray<int>(Nz::Plane<int>::XY(), Nz::Plane<int>::YZ()));
		Nz::Rayf secondRay(0.f, 0.f, 0.f, 0.f, 1.f, 0.f);

		WHEN("We compare them")
		{
			THEN("They are the same and Y axis")
			{
				REQUIRE(ray == secondRay);
				REQUIRE(ray == Nz::Rayf::AxisY());
			}
		}

		WHEN("We ask for the closest point")
		{
			THEN("The point that is multiple on the Nz::Ray, is at multiple")
			{
				REQUIRE(ray.ClosestPoint(secondRay.GetPoint(1.f)) == Approx(1.f));
			}
		}

		WHEN("We ask for intersection")
		{
			THEN("For the Box collision's")
			{
				float tmpClosest;
				float tmpFurthest;

				REQUIRE(ray.Intersect(Nz::Boxf(-0.5f, 1.f, -0.5f, 1.f, 1.f, 1.f), &tmpClosest, &tmpFurthest));
				CHECK(ray.GetPoint(tmpClosest) == Nz::Vector3f::UnitY());
				CHECK(ray.GetPoint(tmpFurthest) == (Nz::Vector3f::UnitY() * 2.f));
				REQUIRE(!ray.Intersect(Nz::Boxf(-10.f, 1.f, -10.f, 1.f, 1.f, 1.f), &tmpClosest, &tmpFurthest));
			}

			THEN("For the Nz::Plane collision's")
			{
				float tmpHit = -1.f;

				REQUIRE(ray.Intersect(Nz::Planef(Nz::Vector3f::UnitY(), 1.f), &tmpHit));
				CHECK(ray.GetPoint(tmpHit) == Nz::Vector3f::UnitY());
				REQUIRE(ray.Intersect(Nz::Planef::XZ(), &tmpHit));
				CHECK(ray.GetPoint(tmpHit) == Nz::Vector3f::Zero());
				REQUIRE(ray.Intersect(Nz::Planef(Nz::Vector3f::UnitY(), 2.f), &tmpHit));
				CHECK(ray.GetPoint(tmpHit) == 2.f * Nz::Vector3f::UnitY());

				CHECK(!ray.Intersect(Nz::Planef(Nz::Vector3f::UnitX(), 1.f)));
			}

			THEN("For the Sphere collision's")
			{
				float tmpClosest;
				float tmpFurthest;

				CHECK(ray.Intersect(Nz::Spheref(Nz::Vector3f::UnitY(), 0.1f), &tmpClosest, &tmpFurthest));
				REQUIRE(ray.GetPoint(tmpClosest) == Nz::Vector3f::UnitY() * 0.9f);
				REQUIRE(ray.GetPoint(tmpFurthest) == (Nz::Vector3f::UnitY() * 1.1f));

				CHECK(!ray.Intersect(Nz::Spheref(Nz::Vector3f::UnitX(), 0.9f)));
			}

			THEN("For the OBB collision's")
			{
				float tmpClosest;
				float tmpFurthest;

				Nz::OrientedBoxf obb(-0.5f, 1.f, -0.5f, 1.f, 1.f, 1.f);
				obb.Update(Nz::Matrix4f::Rotate(Nz::EulerAnglesf(0.f, 90.f, 0.f).ToQuaternion()));

				CHECK(ray.Intersect(obb, &tmpClosest, &tmpFurthest));
				REQUIRE(ray.GetPoint(tmpClosest) == Nz::Vector3f::UnitY());
				REQUIRE(ray.GetPoint(tmpFurthest) == (Nz::Vector3f::UnitY() * 2.f));

				obb = Nz::OrientedBoxf(-10.f, 1.f, -10.f, 1.f, 1.f, 1.f);
				obb.Update(Nz::Matrix4f::Rotate(Nz::EulerAnglesf(0.f, 0.f, 90.f).ToQuaternion()));
				CHECK(!ray.Intersect(obb, &tmpClosest, &tmpFurthest));
			}

			THEN("For the bounding volume collision's")
			{
				Nz::BoundingVolumef nullVolume(Nz::Extend_Null);
				CHECK(!ray.Intersect(nullVolume));

				float tmpClosest = -1.f;
				float tmpFurthest = -1.f;
				Nz::BoundingVolumef infiniteVolume(Nz::Extend_Infinite);
				CHECK(ray.Intersect(infiniteVolume, &tmpClosest, &tmpFurthest));
				CHECK(tmpClosest == Approx(0.f));
				CHECK(tmpFurthest == std::numeric_limits<float>::infinity());
			}

			THEN("For the triangle collision's")
			{
				Nz::Vector3f firstPoint(0.f, 1.f, 1.f);
				Nz::Vector3f secondPoint(-1.f, 1.f, -1.f);
				Nz::Vector3f thidPoint(1.f, 1.f, -1.f);
				float tmpHit = -1.f;

				CHECK(ray.Intersect(firstPoint, secondPoint, thidPoint, &tmpHit));
				REQUIRE(ray.GetPoint(tmpHit) == Nz::Vector3f::UnitY());

				Nz::Vector3f offset = Nz::Vector3f(10.f, 0.f, 10.f);
				CHECK(!ray.Intersect(firstPoint + offset, secondPoint + offset, thidPoint + offset, &tmpHit));
			}
		}

		WHEN("We try to lerp")
		{
			THEN("Compilation should be fine")
			{
				Nz::Rayf AxisX = Nz::Rayf::AxisX();
				Nz::Rayf AxisY = Nz::Rayf::AxisY();
				REQUIRE(Nz::Rayf::Lerp(AxisX, AxisY, 0.5f) == (Nz::Rayf(Nz::Vector3f::Zero(), Nz::Vector3f(0.5f, 0.5f, 0.f))));
			}
		}
	}
}
<|endoftext|>


<commit_before>/*
 * This file is part of the Yildiz-Engine project, licenced under the MIT License  (MIT)
 *
 * Copyright (c) 2019 Grégory Van den Borre
 *
 * More infos available: https://engine.yildiz-games.be
 *
 * 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.
 */

#ifndef SELECTIONRECTANGLE_H
#define SELECTIONRECTANGLE_H

#define SELECTIONRECTANGLE yz::SelectionRectangle

#include <Ogre.h>
#include "Material.hpp"
#include <Overlay/OgreOverlayManager.h>

namespace yz {

	/**
	*@author Grégory Van den Borre
	*/
class SelectionRectangle {

    public:

        SelectionRectangle(yz::Material* material, yz::Material* content);
        void hide();
        void update(const Ogre::Real x1, const Ogre::Real y1, const Ogre::Real x2, const Ogre::Real y2);

    private:
        Ogre::OverlayElement* top;
        Ogre::OverlayElement* bottom;
        Ogre::OverlayElement* left;
        Ogre::OverlayElement* right;

        Ogre::OverlayElement* content;

};
}

#endif
<commit_msg>Update SelectionRectangle.hpp<commit_after>/*
 * This file is part of the Yildiz-Engine project, licenced under the MIT License  (MIT)
 *
 * Copyright (c) 2019 Grégory Van den Borre
 *
 * More infos available: https://engine.yildiz-games.be
 *
 * 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.
 */

#ifndef SELECTIONRECTANGLE_H
#define SELECTIONRECTANGLE_H

#define SELECTIONRECTANGLE yz::SelectionRectangle

#include <Ogre.h>
#include <OgreOverlayManager.h>
#include <OgreOverlayElement.h>
#include <OgreOverlay.h>

#include "Material.hpp"

namespace yz {

	/**
	*@author Grégory Van den Borre
	*/
class SelectionRectangle {

    public:

        SelectionRectangle(yz::Material* material, yz::Material* content);
        void hide();
        void update(const Ogre::Real x1, const Ogre::Real y1, const Ogre::Real x2, const Ogre::Real y2);

    private:
        Ogre::OverlayElement* top;
        Ogre::OverlayElement* bottom;
        Ogre::OverlayElement* left;
        Ogre::OverlayElement* right;

        Ogre::OverlayElement* content;

};
}

#endif
<|endoftext|>


<commit_before>#ifndef OPENGM_NEW_VISITOR_HXX
#define OPENGM_NEW_VISITOR_HXX

#include <iostream>
#include <opengm/opengm.hxx>
#include <opengm/utilities/timer.hxx>

namespace opengm{
namespace visitors{

struct VisitorReturnFlag{
	enum VisitorReturnFlagValues{
		continueInf			=0,
		stopInfBoundReached	=1,
		stopInfTimeout    	=2
	};

	const static size_t ContinueInf = 0;
};

template<class INFERENCE>
class EmptyVisitor{
public:
	EmptyVisitor(){
	}
	void begin(INFERENCE & inf){
	}
	size_t operator()(INFERENCE & inf){
		return static_cast<size_t>(VisitorReturnFlag::continueInf);
	}
	void end(INFERENCE & inf){
	}
};

template<class INFERENCE>
class VerboseVisitor{
public:
	VerboseVisitor(const size_t visithNth=1,const bool multiline=false)
	: 	iteration_(0),
		visithNth_(visithNth),
		multiline_(multiline){
	}
	void begin(INFERENCE & inf){
		std::cout<<"begin: value "<<inf.value()<<" bound "<<inf.bound()<<"\n";
		++iteration_;
	}
	size_t operator()(INFERENCE & inf){
		if((iteration_)%visithNth_==0){
			std::cout<<"step: "<<iteration_<<" value "<<inf.value()<<" bound "<<inf.bound()<<"\n";
		}
		++iteration_;
		return static_cast<size_t>(VisitorReturnFlag::continueInf);
	}
	void end(INFERENCE & inf){
		std::cout<<"value "<<inf.value()<<" bound "<<inf.bound()<<"\n";
	}
private:
	size_t iteration_;
	size_t visithNth_;
	bool   multiline_;
};

template<class INFERENCE>
class TimingVisitor{
public:
	typedef typename  INFERENCE::ValueType ValueType;

	TimingVisitor(
		const size_t visithNth=1,
		const size_t reserve=0,
		const bool 	 verbose=true,
		const bool   multiline=true,
		const double timeLimit=std::numeric_limits<double>::infinity()
	)
	:
		protocolMap_(),
		times_(),
		values_(),
		bounds_(),
		iterations_(),
		timer_(),
		iteration_(0),
		visithNth_(visithNth),
		multiline_(multiline),
		timeLimit_(timeLimit),
 		totalTime_(0.0)
	{
		// allocate all protocolated items
		ctime_		= & protocolMap_["ctime"]    ;
		times_      = & protocolMap_["times"]    ;
		values_     = & protocolMap_["values"]   ;
		bounds_     = & protocolMap_["bounds"]   ;
		iterations_ = & protocolMap_["iteration"];

		// reservations
		if(reserve>0){
			times_->reserve(reserve);
			values_->reserve(reserve);
			bounds_->reserve(reserve);
			iterations_->reserve(reserve);
		}

		// start timer to measure time from
		// constructor call to "begin" call
		timer_.tic();
	}

	void begin(INFERENCE & inf){

		// stop timer which measured time from
		// constructor call to this "begin" call
		timer_.toc();
		// store values bound time and iteration number
		const ValueType val=inf.value();
		const ValueType bound=inf.bound();
		ctime_->push_back(timer_.elapsedTime());
        times_->push_back(0);
        values_->push_back(val);
        bounds_->push_back(bound);
        iterations_->push_back(double(iteration_));

        // print step
        if(verbose_)
        	std::cout<<"value "<<val<<" bound "<<bound<<"\n";
        // increment iteration
        ++iteration_;
		// restart timer
		timer_.reset();
		timer_.tic();
	}

	size_t operator()(INFERENCE & inf){

		if(iteration_%visithNth_==0){
			// stop timer
			timer_.toc();

			// store values bound time and iteration number
			const ValueType val 	=inf.value();
			const ValueType bound 	=inf.bound();
			const double 	t    	= timer_.elapsedTime();
	        times_->push_back(t);
	        values_->push_back(val);
	        bounds_->push_back(bound);
	        iterations_->push_back(double(iteration_));
	        // increment total time
	        totalTime_+=t;
	        if(verbose_){
	        	std::cout<<"step: "<<iteration_<<" value "<<val<<" bound "<<bound<<" [ "<<totalTime_ << "]" <<"\n";
	        }
	        // restart timer
	        timer_.reset();
			timer_.tic();
    	}
        ++iteration_;

        // check is time limit reached
		if(totalTime_<timeLimit_){
			return static_cast<size_t>(VisitorReturnFlag::continueInf);
		}
		else{
			if(verbose_)
				std::cout<<"timeout reached\n";
			return static_cast<size_t>(VisitorReturnFlag::stopInfTimeout);
		}
	}

	void end(INFERENCE & inf){
		// stop timer
		timer_.toc();
		// store values bound time and iteration number
		const ValueType val=inf.value();
		const ValueType bound=inf.bound();
 		times_->push_back(timer_.elapsedTime());
        values_->push_back(val);
        bounds_->push_back(bound);
        iterations_->push_back(double(iteration_));
        if(verbose_){
        	std::cout<<"value "<<val<<" bound "<<bound<<"\n";
        }
	}

	// timing visitor specific interface

	const std::map< std::string, std::vector<double  > > & protocolMap()const{
		return protocolMap_;
	}

	const std::vector<double> & getConstructionTime()const{
		return *ctime_;
	}
	const std::vector<double> & getTimes			()const{
		return *times_;
	}
	const std::vector<double> & getValues			()const{
		return *values_;
	}
	const std::vector<double> & getBounds			()const{
		return *bounds_;
	}
	const std::vector<double> & getIterations		()const{
		return *iterations_;
	}

private:

	std::map< std::string, std::vector<double  > >  protocolMap_;

	std::vector<double  > * ctime_;
	std::vector<double  > * times_;
	std::vector<double  > * values_;
	std::vector<double  > * bounds_;
	std::vector<double  > * iterations_;
	opengm::Timer timer_;
	opengm::Timer totalTimer_;
	size_t iteration_;
	size_t visithNth_;
	bool verbose_;
	bool   multiline_;

	double timeLimit_;
	double totalTime_;
};
}
}

#endif //OPENGM_NEW_VISITOR_HXX<commit_msg>changed enum to const static in visitor return flags<commit_after>#ifndef OPENGM_NEW_VISITOR_HXX
#define OPENGM_NEW_VISITOR_HXX

#include <iostream>
#include <opengm/opengm.hxx>
#include <opengm/utilities/timer.hxx>

namespace opengm{
namespace visitors{

struct VisitorReturnFlag{
    /*
    enum VisitorReturnFlagValues{
        continueInf         =0,
        stopInfBoundReached =1,
        stopInfTimeout      =2
    };
    */
    const static size_t ContinueInf = 0;
    const static size_t StopInfBoundReached = 1;
    const static size_t StopInfTimeout = 2;
};

template<class INFERENCE>
class EmptyVisitor{
public:
    EmptyVisitor(){
    }
    void begin(INFERENCE & inf){
    }
    size_t operator()(INFERENCE & inf){
        return static_cast<size_t>(VisitorReturnFlag::continueInf);
    }
    void end(INFERENCE & inf){
    }
};

template<class INFERENCE>
class VerboseVisitor{
public:
    VerboseVisitor(const size_t visithNth=1,const bool multiline=false)
    :   iteration_(0),
        visithNth_(visithNth),
        multiline_(multiline){
    }
    void begin(INFERENCE & inf){
        std::cout<<"begin: value "<<inf.value()<<" bound "<<inf.bound()<<"\n";
        ++iteration_;
    }
    size_t operator()(INFERENCE & inf){
        if((iteration_)%visithNth_==0){
            std::cout<<"step: "<<iteration_<<" value "<<inf.value()<<" bound "<<inf.bound()<<"\n";
        }
        ++iteration_;
        return static_cast<size_t>(VisitorReturnFlag::continueInf);
    }
    void end(INFERENCE & inf){
        std::cout<<"value "<<inf.value()<<" bound "<<inf.bound()<<"\n";
    }
private:
    size_t iteration_;
    size_t visithNth_;
    bool   multiline_;
};

TimingVisitor<LF>::print

template<class INFERENCE>
class TimingVisitor{
public:
    typedef typename  INFERENCE::ValueType ValueType;

    TimingVisitor(
        const size_t visithNth=1,
        const size_t reserve=0,
        const bool   verbose=true,
        const bool   multiline=true,
        const double timeLimit=std::numeric_limits<double>::infinity()
    )
    :
        protocolMap_(),
        times_(),
        values_(),
        bounds_(),
        iterations_(),
        timer_(),
        iteration_(0),
        visithNth_(visithNth),
        multiline_(multiline),
        timeLimit_(timeLimit),
        totalTime_(0.0)
    {
        // allocate all protocolated items
        ctime_      = & protocolMap_["ctime"]    ;
        times_      = & protocolMap_["times"]    ;
        values_     = & protocolMap_["values"]   ;
        bounds_     = & protocolMap_["bounds"]   ;
        iterations_ = & protocolMap_["iteration"];

        // reservations
        if(reserve>0){
            times_->reserve(reserve);
            values_->reserve(reserve);
            bounds_->reserve(reserve);
            iterations_->reserve(reserve);
        }

        // start timer to measure time from
        // constructor call to "begin" call
        timer_.tic();
    }

    void begin(INFERENCE & inf){

        // stop timer which measured time from
        // constructor call to this "begin" call
        timer_.toc();
        // store values bound time and iteration number
        const ValueType val=inf.value();
        const ValueType bound=inf.bound();
        ctime_->push_back(timer_.elapsedTime());
        times_->push_back(0);
        values_->push_back(val);
        bounds_->push_back(bound);
        iterations_->push_back(double(iteration_));

        // print step
        if(verbose_)
            std::cout<<"value "<<val<<" bound "<<bound<<"\n";
        // increment iteration
        ++iteration_;
        // restart timer
        timer_.reset();
        timer_.tic();
    }

    size_t operator()(INFERENCE & inf){

        if(iteration_%visithNth_==0){
            // stop timer
            timer_.toc();

            // store values bound time and iteration number
            const ValueType val     =inf.value();
            const ValueType bound   =inf.bound();
            const double    t       = timer_.elapsedTime();
            times_->push_back(t);
            values_->push_back(val);
            bounds_->push_back(bound);
            iterations_->push_back(double(iteration_));
            // increment total time
            totalTime_+=t;
            if(verbose_){
                std::cout<<"step: "<<iteration_<<" value "<<val<<" bound "<<bound<<" [ "<<totalTime_ << "]" <<"\n";
            }
            // restart timer
            timer_.reset();
            timer_.tic();
        }
        ++iteration_;

        // check is time limit reached
        if(totalTime_<timeLimit_){
            return static_cast<size_t>(VisitorReturnFlag::continueInf);
        }
        else{
            if(verbose_)
                std::cout<<"timeout reached\n";
            return static_cast<size_t>(VisitorReturnFlag::stopInfTimeout);
        }
    }

    void end(INFERENCE & inf){
        // stop timer
        timer_.toc();
        // store values bound time and iteration number
        const ValueType val=inf.value();
        const ValueType bound=inf.bound();
        times_->push_back(timer_.elapsedTime());
        values_->push_back(val);
        bounds_->push_back(bound);
        iterations_->push_back(double(iteration_));
        if(verbose_){
            std::cout<<"value "<<val<<" bound "<<bound<<"\n";
        }
    }

    // timing visitor specific interface

    const std::map< std::string, std::vector<double  > > & protocolMap()const{
        return protocolMap_;
    }

    const std::vector<double> & getConstructionTime()const{
        return *ctime_;
    }
    const std::vector<double> & getTimes            ()const{
        return *times_;
    }
    const std::vector<double> & getValues           ()const{
        return *values_;
    }
    const std::vector<double> & getBounds           ()const{
        return *bounds_;
    }
    const std::vector<double> & getIterations       ()const{
        return *iterations_;
    }

private:

    std::map< std::string, std::vector<double  > >  protocolMap_;

    std::vector<double  > * ctime_;
    std::vector<double  > * times_;
    std::vector<double  > * values_;
    std::vector<double  > * bounds_;
    std::vector<double  > * iterations_;
    opengm::Timer timer_;
    opengm::Timer totalTimer_;
    size_t iteration_;
    size_t visithNth_;
    bool verbose_;
    bool   multiline_;

    double timeLimit_;
    double totalTime_;
};
}
}

#endif //OPENGM_NEW_VISITOR_HXX<|endoftext|>