<commit_before>/**
 * Copyright 2016 Michal Korbela, Filip Pokrývka, Ondřej Slámečka
 * See the LICENSE file for more information.
 */
#include <iostream>
#include <vector>

#include "../mnist/include/mnist/mnist_reader.hpp"

#include "MLP.hpp"

int main() {
    MLP nn({2, 2, 1});
    nn.randomize_weights(-1, 1);

    for (int i = 0; i < 10000; ++i) {
        nn.learn({0, 0}, {0}, 0.5, 0.1);
        nn.learn({0, 1}, {1}, 0.5, 0.1);
        nn.learn({1, 0}, {1}, 0.5, 0.1);
        nn.learn({1, 1}, {0}, 0.5, 0.1);
    }

    std::vector<double> r = nn.feed({1, 1});
    std::cout << "exp 0, act " << r[0] << std::endl;

    r = nn.feed({1, 0});
    std::cout << "exp 1, act " << r[0] << std::endl;

    r = nn.feed({0, 1});
    std::cout << "exp 1, act " << r[0] << std::endl;

    r = nn.feed({0, 0});
    std::cout << "exp 0, act "  << r[0] << std::endl;

    // auto dataset =
    //     mnist::read_dataset<std::vector, std::vector, uint8_t, uint8_t>();

    // for (int i = 255; i --> 0; ) {
        // if (dataset.training_images[5][i] > 0) {
            // std::cout << i << std::endl;
            // std::cout << dataset.training_images[5][i] << std::endl;
            // break;
        // }
    // }

    return 0;
}
<commit_msg>first attempt<commit_after>/**
 * Copyright 2016 Michal Korbela, Filip Pokrývka, Ondřej Slámečka
 * See the LICENSE file for more information.
 */
#include <iostream>
#include <vector>
#include <queue>

#include <algorithm>
#include <ctime>
#include <cstdlib>

//#include "../mnist/include/mnist/mnist_reader.hpp"

#include "brca_image.hpp"

#include "MLP.hpp"

double validate(MLP &nn, std::vector<BrcaImage> &validation, std::queue<double> &q, double treshold) {
    int corr = 0;
    int unsure = 0;
    std::vector<double> r;
    for(int i = 0; i<validation.size(); i++) {
        r = nn.feed(validation[i].data);
        if (r[0] >0.1 && r[0] < 0.9) {
            unsure++;
            continue;
        }
        bool res=0;
        if(r[0] > 0.9) res=1;
        if(res == validation[i].malignant) {
            corr++;
        }
    }
    std::cout << "validation: " << corr << "/" << validation.size() << " = " << (corr*100.0)/validation.size() << "%" << " (" << unsure << " unsure)" << std::endl;
    if (unsure == 100) std::cout << "unsure: " << r[0] << std::endl;

    return (corr*100.0)/validation.size();
}

int main(int argc, char** argv) {
    if (argc != 2 ) {
        throw std::invalid_argument("No data file specified "
                                "please provide it as first parameter");
    }

    MLP nn({30,90,1});

    std::vector<BrcaImage> all_data = parse_brca_dataset(argv[1]);
    nn.randomize_weights(-1, 1);
    std::queue<double>q;
    while(validate(nn, all_data, q, 0.2) > 1.0) {
        std::cout << "reinitializing weights" << std::endl;
        nn.randomize_weights(-1, 1);
    }

    //std::srand(unsigned(std::time(0)));
    //std::random_shuffle(all_data.begin(), all_data.end());
/*    int iter = 30000;
    for (int z = 0; z < iter; ++z) {
        if(z%(iter/100) == 0) {
            std::cout << z*100/iter << "%" << std::endl;
        }
        for(int i = 0, k=0; i<50; ++k) {
            if(all_data[k].malignant) {
                nn.learn(all_data[k].data, {all_data[k].malignant}, 0.5, 0.1);
                i++;
            }
        }
        for(int i = 0, k=0; i<50; ++k) {
            if(!all_data[k].malignant) {
                nn.learn(all_data[k].data, {all_data[k].malignant}, 0.5, 0.1);
                i++;
            }
        }
    }*/

    int training_size = 50;
    int validation_size = 100;
    int tot_size = (training_size + validation_size) / 2;
    std::vector<BrcaImage> training, validation;
    for(int i = 0, k=0; i<tot_size; ++k) {
        if(all_data[k].malignant) {
            if(i<training_size/2)
                training.push_back(all_data[k]);
            else
                validation.push_back(all_data[k]);
            i++;
        }
    }
    for(int i = 0, k=0; i<tot_size; ++k) {
        if(!all_data[k].malignant) {
            if(i<training_size/2)
                training.push_back(all_data[k]);
            else
                validation.push_back(all_data[k]);
            i++;
        }
    }

    int queue_size = 5;
    int interval = 1000;
    std::queue<double> efficiency;
    double treshold = 95.0;
    for(int i = 0; i<queue_size; i++) efficiency.push(0);

//    while(validate(nn, validation, efficiency, treshold) < treshold) {
    while(validate(nn, all_data, efficiency, treshold) < treshold) {
        for(int i = 0; i<interval; i++) {
            for(int j = 0; j<training_size; j++) {
                nn.learn(training[j].data, {(double) training[j].malignant}, 0.5, 0.1);
            }
        }
    }

    /*
    for (int z = 0; z < iter; ++z) {
        if(z%(iter/100) == 0) {
            std::cout << z*100/iter << "%" << std::endl;
        }
        for(int i = 0, k=0; i<50; ++k) {
            if(all_data[k].malignant) {
                nn.learn(all_data[k].data, {all_data[k].malignant}, 0.5, 0.1);
                i++;
            }
        }
        for(int i = 0, k=0; i<50; ++k) {
            if(!all_data[k].malignant) {
                nn.learn(all_data[k].data, {all_data[k].malignant}, 0.5, 0.1);
                i++;
            }
        }
    }*/

    int corrm=0, corrn=0;
    for (int i = 0; i < all_data.size(); i++) {
        std::vector<double> r = nn.feed(all_data[i].data);
        if(all_data[i].malignant && r[0]>0.5) corrm++;
        if(!all_data[i].malignant && r[0]<0.5) corrn++;
        std:: cout << "exp " << all_data[i].malignant << ", act " << r[0] << std::endl;
    }
    std::cout << corrm << " " << corrn << " " << corrn+corrm << "/" << all_data.size() << " = " << ((double)corrm+corrn)/all_data.size() <<  "%" << std::endl;
/*
    std::vector<double> r = nn.feed({1, 1});
    std::cout << "exp 0, act " << r[0] << std::endl;

    r = nn.feed({1, 0});
    std::cout << "exp 1, act " << r[0] << std::endl;

    r = nn.feed({0, 1});
    std::cout << "exp 1, act " << r[0] << std::endl;

    r = nn.feed({0, 0});
    std::cout << "exp 0, act "  << r[0] << std::endl; */

    // auto dataset =
    //     mnist::read_dataset<std::vector, std::vector, uint8_t, uint8_t>();

    // for (int i = 255; i --> 0; ) {
        // if (dataset.training_images[5][i] > 0) {
            // std::cout << i << std::endl;
            // std::cout << dataset.training_images[5][i] << std::endl;
            // break;
        // }
    // }

    return 0;
}
<|endoftext|>


<commit_before>// todo:
// autonomous drive

#define VERSION "mBot Hackaton"
#define DISTANCECMCRITICAL 20
#define PUBLSIHINTERVAL 1000
#define WAITINTERVAL 5000
#define MOVESPEEDMAX 230

#include <Arduino.h>

#include <Streaming.h>
#include <MeMCore.h>

MeDCMotor motorL(M1);
MeDCMotor motorR(M2);
MeLineFollower lineFollower(PORT_2);
MeTemperature temperature(PORT_1, SLOT2);
MeUltrasonicSensor ultrasonicSensor(PORT_3);
MeLightSensor lightSensor(PORT_6);
MeIR ir;
MeRGBLed rgbLed(PORT_7, 2);
MeBuzzer buzzer;

double distanceCm = 0.0;
int moveSpeed = 100;
int lineFollowFlag = 0;
uint8_t readSensors = 0;
uint8_t randNumber;
bool start = false;
bool moveBot = false;
bool makeNoise = false;

unsigned long publishTimer = millis();
bool wait = false;
unsigned long waitTimer = millis();
bool tryFollowLine = true;
unsigned long tryFollowLineTimer = millis();

void Forward() {
  moveBot = true;
  motorL.run(-moveSpeed);
  motorR.run(moveSpeed);
}

void Backward() {
  moveBot = true;
  motorL.run(moveSpeed);
  motorR.run(-moveSpeed);
}

void TurnLeft() {
  moveBot = true;
  motorL.run(-moveSpeed / 10);
  motorR.run(moveSpeed);
}

void TurnRight() {
  moveBot = true;
  motorL.run(-moveSpeed);
  motorR.run(moveSpeed / 10);
}

void Stop() {
  moveBot = false;
  motorL.run(0);
  motorR.run(0);
}

void Autonomous() {
    randomSeed(analogRead(6));
    randNumber = random(2);
    if (distanceCm > 15 || distanceCm == 0) {
      Forward();
    } else if (distanceCm > 10) {
      switch (randNumber)
      {
        case 0:
          TurnLeft();
          delay(200);
          break;
        case 1:
          TurnRight();
          delay(200);
          break;
      }
    } else {
      Backward();
      delay(400);
    }
    delay(100);
}

void bottomPressed() {
    start = !start;
    if (start) {
      rgbLed.setColor(1, 0, 10, 0);
      rgbLed.show();
    } else {
      rgbLed.setColor(1, 0, 0, 0);
      rgbLed.show();
      Stop();
    }
    delay(250);
}

void bottomCheck() {
  if (analogRead(A7) == 0) {
    bottomPressed();
  }
}

void irControl() {
  uint32_t value;

  if (ir.decode()) {
    value = ir.value;
    switch (value >> 16 & 0xff) {
      case IR_BUTTON_LEFT:
        TurnLeft();
        break;
      case IR_BUTTON_RIGHT:
        TurnRight();
        break;
      case IR_BUTTON_DOWN:
        Backward();
        break;
      case IR_BUTTON_UP:
        Forward();
        break;
      case IR_BUTTON_SETTING:
        Stop();
        break;
      case IR_BUTTON_A:
        bottomPressed();
      break;
    }
  }
}

void noise() {
  if (!moveBot and start) {
    if (wait == false) {
      wait = true;
      waitTimer = millis();
    }
    if (wait and millis() - waitTimer > WAITINTERVAL) {
      makeNoise = true;
      //buzzer.tone(262, 100);
      rgbLed.setColor(2, 10, 0, 0);
      rgbLed.show();
    } else {
      rgbLed.setColor(2, 0, 0, 10);
      rgbLed.show();
    }
  } else {
    wait = false;
    makeNoise = false;
    buzzer.noTone();
    rgbLed.setColor(2, 0, 0, 0);
    rgbLed.show();
  }
}

void readData() {
  readSensors = lineFollower.readSensors();
  distanceCm = ultrasonicSensor.distanceCm();
}

void sendData() {
  if (millis() - publishTimer > PUBLSIHINTERVAL) {
    publishTimer = millis();
    Serial << endl << "start: " << start << endl;
    Serial << "moveBot: " << moveBot << endl;
    Serial << "tryFollowLine: " << tryFollowLine << endl;
    Serial << "makeNoise: " << makeNoise << endl;
    Serial << "readSensors: " << readSensors << endl;
    Serial << "temperature: " << temperature.temperature() << endl;
    Serial << "lightSensor: " << lightSensor.read() << endl;
    Serial << "distanceCm: " << distanceCm << endl;
  }
}

void setup() {
  Serial.begin(115200);
  Serial << endl << VERSION << endl << endl;
  pinMode(A7, INPUT);
  ir.begin();
  rgbLed.setColor(0, 0, 0, 0);
  rgbLed.show();
}

void loop() {
  bottomCheck();
  irControl();
  readData();
  sendData();
  noise();
  if (start) {
    if (distanceCm < DISTANCECMCRITICAL and distanceCm > 0) {
      Stop();
      tryFollowLine = true;
    } else {
      moveBot = true;
      if (moveSpeed > MOVESPEEDMAX) {
        moveSpeed = 230;
      }
      switch (readSensors) {
        case S1_IN_S2_IN:
          tryFollowLine = true;
          Forward();
          lineFollowFlag = 10;
          break;
        case S1_IN_S2_OUT:
          tryFollowLine = true;
          Forward();
          if (lineFollowFlag > 1) lineFollowFlag--;
          break;
        case S1_OUT_S2_IN:
          tryFollowLine = true;
          Forward();
          if (lineFollowFlag < 20) lineFollowFlag++;
          break;
        case S1_OUT_S2_OUT:
          if (tryFollowLine) {
            tryFollowLine = !tryFollowLine;
            tryFollowLineTimer = millis();
          }
          if (millis() - tryFollowLineTimer < 3000) {
            if (lineFollowFlag == 10) Backward();
            if (lineFollowFlag < 10) TurnLeft();
            if (lineFollowFlag > 10) TurnRight();
          } else {
            Stop();
//            Autonomous();
          }
          break;
      }
    }
  }
}
<commit_msg>rename and autonomous mode<commit_after>// todo:
// autonomous drive

#define VERSION "mBot Hackaton"
#define DISTANCECMCRITICAL 20
#define DISTANCECMWARNING 30
#define PUBLSIHINTERVAL 2000
#define WAITINTERVAL 5000
#define MOVESPEEDMAX 230

#include <Arduino.h>

#include <Streaming.h>
#include <MeMCore.h>

enum direction { FORWARD, BACKWARD, LEFT, RIGHT, STOP } moveDirection = STOP;

MeDCMotor motorL(M1);
MeDCMotor motorR(M2);
MeLineFollower lineFollower(PORT_2);
MeTemperature temperature(PORT_1, SLOT2);
MeUltrasonicSensor ultrasonicSensor(PORT_3);
MeLightSensor lightSensor(PORT_6);
MeIR ir;
MeRGBLed rgbLed(PORT_7, 2);
MeBuzzer buzzer;

double distanceCm = 0.0;
int moveSpeed = 100;
int lineFollowFlag = 0;
uint8_t readSensors = 0;
bool start = false;
bool moveBot = false;
bool makeNoise = false;
bool distanceCheckOK = true;

unsigned long publishTimer = millis();
bool wait = false;
unsigned long waitTimer = millis();
bool tryFollowLine = true;
unsigned long tryFollowLineTimer = millis();

void forward() {
  moveBot = true;
  motorL.run(-moveSpeed);
  motorR.run(moveSpeed);
}

void backward() {
  moveBot = true;
  motorL.run(moveSpeed);
  motorR.run(-moveSpeed);
}

void turnLeft() {
  moveBot = true;
  motorL.run(-moveSpeed / 10);
  motorR.run(moveSpeed);
}

void turnRight() {
  moveBot = true;
  motorL.run(-moveSpeed);
  motorR.run(moveSpeed / 10);
}

void stop() {
  moveBot = false;
  motorL.run(0);
  motorR.run(0);
}

void move() {
  if (distanceCheckOK) {
    switch (moveDirection) {
      case FORWARD:
      forward();
      break;
      case BACKWARD:
      backward();
      break;
      case LEFT:
      turnLeft();
      break;
      case RIGHT:
      turnRight();
      break;
      case STOP:
      stop();
      break;
    }
  } else {
    switch (moveDirection) {
      case BACKWARD:
      backward();
      break;
      default:
      moveDirection = STOP;
      stop();
      break;
    }
  }
}

void toggleStart() {
  start = !start;
  if (start) {
    rgbLed.setColor(1, 0, 10, 0);
    rgbLed.show();
  } else {
    rgbLed.setColor(1, 0, 0, 0);
    rgbLed.show();
    moveDirection = STOP;
  }
  delay(250);
}

void bottomCheck() {
  if (analogRead(A7) == 0) {
    toggleStart();
  }
}

void irCheck() {
  uint32_t value;

  if (ir.decode()) {
    value = ir.value;
    switch (value >> 16 & 0xff) {
      case IR_BUTTON_LEFT:
      moveDirection = LEFT;
      break;
      case IR_BUTTON_RIGHT:
      moveDirection = RIGHT;
      break;
      case IR_BUTTON_DOWN:
      moveDirection = BACKWARD;
      break;
      case IR_BUTTON_UP:
      moveDirection = FORWARD;
      break;
      case IR_BUTTON_SETTING:
      moveDirection = STOP;
      break;
      case IR_BUTTON_A:
      toggleStart();
      break;
    }
  }
}

void noiseCheck() {
  if (!moveBot and start) {
    if (wait == false) {
      wait = true;
      waitTimer = millis();
    }
    if (wait and millis() - waitTimer > WAITINTERVAL) {
      makeNoise = true;
      //buzzer.tone(262, 100);
      rgbLed.setColor(2, 10, 0, 0);
      rgbLed.show();
    } else {
      rgbLed.setColor(2, 0, 0, 10);
      rgbLed.show();
    }
  } else {
    wait = false;
    makeNoise = false;
    buzzer.noTone();
    rgbLed.setColor(2, 0, 0, 0);
    rgbLed.show();
  }
}

bool distanceCheck(double distanceCmLimit) {
  if (distanceCm < distanceCmLimit) {
    return false;
  } else {
    return true;
  }
}

void autonomous() {
  uint8_t randNumber;

  randomSeed(analogRead(6));
  randNumber = random(2);
  if (distanceCheckOK) {
    moveDirection = FORWARD;
  } else {
      moveDirection = BACKWARD;
      move();
      delay(400);
    switch (randNumber) {
      case 0:
      moveDirection = LEFT;
      turnLeft();
      delay(200);
      break;
      case 1:
      moveDirection = RIGHT;
      turnRight();
      delay(200);
      break;
    }
  }
  delay(100);
}

void readData() {
  readSensors = lineFollower.readSensors();
  distanceCm = ultrasonicSensor.distanceCm();
}

void sendData() {
  if (millis() - publishTimer > PUBLSIHINTERVAL) {
    publishTimer = millis();
    Serial << endl << "start: " << start << endl;
    Serial << "moveBot: " << moveBot << endl;
    Serial << "tryFollowLine: " << tryFollowLine << endl;
    Serial << "makeNoise: " << makeNoise << endl;
    Serial << "readSensors: " << readSensors << endl;
    Serial << "temperature: " << temperature.temperature() << endl;
    Serial << "lightSensor: " << lightSensor.read() << endl;
    Serial << "distanceCm: " << distanceCm << endl;
  }
}

void setup() {
  Serial.begin(115200);
  Serial << endl << VERSION << endl << endl;
  pinMode(A7, INPUT);
  ir.begin();
  rgbLed.setColor(0, 0, 0, 0);
  rgbLed.show();
}

void loop() {
  bottomCheck();
  irCheck();
  readData();
  sendData();
  noiseCheck();
  distanceCheckOK = distanceCheck(DISTANCECMCRITICAL);
  move();
  if (start) {
    if (moveSpeed > MOVESPEEDMAX) {
      moveSpeed = 230;
    }
    switch (readSensors) {
      case S1_IN_S2_IN:
      tryFollowLine = true;
      moveDirection = FORWARD;
      lineFollowFlag = 10;
      break;
      case S1_IN_S2_OUT:
      tryFollowLine = true;
      moveDirection = FORWARD;
      if (lineFollowFlag > 1) lineFollowFlag--;
      break;
      case S1_OUT_S2_IN:
      tryFollowLine = true;
      moveDirection = FORWARD;
      if (lineFollowFlag < 20) lineFollowFlag++;
      break;
      case S1_OUT_S2_OUT:
      if (tryFollowLine) {
        tryFollowLine = !tryFollowLine;
        tryFollowLineTimer = millis();
      }
      if (millis() - tryFollowLineTimer < 3000) {
        if (lineFollowFlag == 10) moveDirection = BACKWARD;
        if (lineFollowFlag < 10) moveDirection = LEFT;
        if (lineFollowFlag > 10) moveDirection = RIGHT;
      } else {
        //        moveDirection = STOP;
        autonomous();
      }
      break;
    }
  }
}
<|endoftext|>


<commit_before>#include "Arduino.h"

#include <SPI.h>
#include <Wire.h>

#include "cc1101_868_3.h"

class SPITransaction {
 public:
  SPITransaction(int slave_select_pin)
      : slave_select_pin_(slave_select_pin) {
    digitalWrite(slave_select_pin_, LOW);
    SPI.beginTransaction(SPISettings(50000, MSBFIRST, SPI_MODE0));
  }

  ~SPITransaction() {
    digitalWrite(slave_select_pin_, HIGH);
    SPI.endTransaction();
  }

 private:
  const int slave_select_pin_;
};

class SHT31D {
  static const uint8_t kSensorAddress = 0x44;
  static const uint16_t kSoftReset = 0x30a2;
  static const uint16_t kReadSensor = 0x2400;

 public:
  void Init() {
    WriteCommand(kSoftReset);
    delay(10);
  }

  struct Reading {
    float temperature;
    float humidity;

    Reading(float temperature, float humidity)
        : temperature(temperature),
          humidity(humidity) {}
  };

 private:
  static float ConvertTemperature(uint16_t raw_temp) {
    return -45 + 175 * (float(raw_temp) / 0xffff);
  }

  static float ConvertHumidity(uint16_t raw_humidity) {
    return 100 * (float(raw_humidity) / 0xffff);
  }

  static bool WriteCommand(uint16_t command) {
    Wire.beginTransmission(kSensorAddress);
    Wire.write(command >> 8);
    Wire.write(command & 0xff);
    return Wire.endTransmission() == 0;
  }

 public:
  Reading ReadTemperatureAndHumidity() {
    WriteCommand(kReadSensor);
    delay(500);
    Wire.requestFrom(kSensorAddress, uint8_t(6));
    if (Wire.available() == 6) {
      uint16_t raw_temp = (Wire.read() << 8) | (Wire.read() & 0xff);
      uint8_t temp_crc = Wire.read();
      uint16_t raw_humidity = (Wire.read() << 8) | (Wire.read() & 0xff);
      uint8_t humidity_crc = Wire.read();
      return Reading(ConvertTemperature(raw_temp), ConvertHumidity(raw_humidity));
    }
    Serial.println("Failed to read sensor");
    return Reading(0.0f, 0.0f);
  }
};

class CC1101 {
 private:
  const int kSlaveSelectPin = 10;
  const int kGDO0Pin = 5;
  const int kGDO2Pin = 6;

  const byte kWriteSingleByte = 0x00;
  const byte kWriteBurst = 0x40;
  const byte kReadBurst = 0xc0;
  const byte kReadSingleByte = 0x80;

  const byte kSRES = 0x30;
  const byte kSTX = 0x35;
  const byte kSFTX = 0x3b;
  const byte kSIDLE = 0x36;

  const byte kIOCFG0Config = 0x07;
  const byte kIOCFG1Config = 0x2e;
  const byte kIOCFG2Config = 0x06;

  const byte kIOCFG0 = 0x02;
  const byte kIOCFG1 = 0x01;
  const byte kIOCFG2 = 0x00;

  const byte kTXFIFO = 0x3f;

  const byte kFIFOTHR = 0x03;
  const byte kSYNC1 = 0x04;
  const byte kSYNC0 = 0x05;

  const byte kPKTLEN = 0x06;
  const byte kPKTCTRL1 = 0x07;
  const byte kPKTCTRL0 = 0x08;

  const byte kADDR = 0x09;

  const byte kCHANNR = 0x0a;
  const byte kFSCTRL1 = 0x0b;
  const byte kFSCTRL0 = 0x0c;

  const byte kFREQ2 = 0x0d;
  const byte kFREQ1 = 0x0e;
  const byte kFREQ0 = 0x0f;

  const byte kMDMCFG4 = 0x10;
  const byte kMDMCFG3 = 0x11;
  const byte kMDMCFG2 = 0x12;
  const byte kMDMCFG1 = 0x13;
  const byte kMDMCFG0 = 0x14;

  const byte kDEVIATN = 0x15;

  const byte kMCSM2 = 0x16;
  const byte kMCSM1 = 0x17;
  const byte kMCSM0 = 0x18;

  const byte kFOCCFG = 0x19;
  const byte kBSCFG = 0x1a;

  const byte kAGCCTRL2 = 0x1b;
  const byte kAGCCTRL1 = 0x1c;
  const byte kAGCCTRL0 = 0x1d;

  const byte kFREND1 = 0x21;
  const byte kFREND0 = 0x22;

  const byte kFSCAL3 = 0x23;
  const byte kFSCAL2 = 0x24;
  const byte kFSCAL1 = 0x25;
  const byte kFSCAL0 = 0x26;

  const byte kFSTEST = 0x29;
  const byte kTEST2 = 0x2c;
  const byte kTEST1 = 0x2d;
  const byte kTEST0 = 0x2e;

  byte ReadRegister(byte addr) {
    SPITransaction transaction(kSlaveSelectPin);

    SPI.transfer(addr | kReadSingleByte);
    byte reply = SPI.transfer(0x00);

    return reply;
  }

  void WriteByte(byte address, byte data) {
    SPITransaction transaction(kSlaveSelectPin);
    SPI.transfer(address | kWriteSingleByte);
    SPI.transfer(data);
  }

  void Strobe(byte command) {
    SPITransaction transaction(kSlaveSelectPin);
    SPI.transfer(command);
  }

  void WriteBurst(byte address, byte* data, int length) {
    SPITransaction transaction(kSlaveSelectPin);
    SPI.transfer(address | kWriteBurst);
    for (int i = 0; i < length; ++i) {
      data[i] = SPI.transfer(data[i]);
    }
  }

  void ReadBurst(byte address, byte* buffer, int length) {
    SPITransaction transaction(kSlaveSelectPin);
    SPI.transfer(address | kReadBurst);
    for (int i = 0; i < length; ++i) {
      buffer[i] = SPI.transfer(0x00);
    }
  }

 public:
  void SendPacket(byte* buffer, byte length) {
    Serial.println("Sending packet");
    WriteByte(kTXFIFO, length);
    WriteBurst(kTXFIFO, buffer, length);
    // Send the packet.
    Strobe(kSTX);

    // Wait for sync word to transmit.
    while(!digitalRead(kGDO2Pin)) {}
    // Wait for packet to be sent.
    while(digitalRead(kGDO2Pin)) {}

    // Return to idle state.
    Strobe(kSIDLE);
    // Flush the TXFIFO buffer.
    Strobe(kSFTX);
    Serial.println("Sent packet");
  }

  void Reset() {
    pinMode(kGDO0Pin, INPUT);
    pinMode(kGDO2Pin, INPUT);
    pinMode(kSlaveSelectPin, OUTPUT);

    Strobe(kSRES);
    delay(100);

    WriteByte(kFSCTRL1, FSCTRL1);
    WriteByte(kFSCTRL0, FSCTRL0);

    WriteByte(kFREQ2, FREQ2);
    WriteByte(kFREQ1, FREQ1);
    WriteByte(kFREQ0, FREQ0);

    WriteByte(kMDMCFG4, MDMCFG4);
    WriteByte(kMDMCFG3, MDMCFG3);
    WriteByte(kMDMCFG2, MDMCFG2);
    WriteByte(kMDMCFG1, MDMCFG1);
    WriteByte(kMDMCFG0, MDMCFG0);

    WriteByte(kCHANNR, CHANNR);
    WriteByte(kDEVIATN, DEVIATN);
    WriteByte(kFREND1, FREND1);
    WriteByte(kFREND0, FREND0);
    WriteByte(kMCSM2, MCSM2);
    WriteByte(kMCSM1, MCSM1);
    WriteByte(kMCSM0, MCSM0);
    WriteByte(kFOCCFG, FOCCFG);
    WriteByte(kBSCFG, BSCFG);

    WriteByte(kAGCCTRL2, AGCCTRL2);
    WriteByte(kAGCCTRL1, AGCCTRL1);
    WriteByte(kAGCCTRL0, AGCCTRL0);

    WriteByte(kFSCAL3, FSCAL3);
    WriteByte(kFSCAL2, FSCAL2);
    WriteByte(kFSCAL1, FSCAL1);
    WriteByte(kFSCAL0, FSCAL0);

    WriteByte(kFSTEST, FSTEST);
    WriteByte(kTEST2, TEST2);
    WriteByte(kTEST1, TEST1);
    WriteByte(kTEST0, TEST0);

    WriteByte(kIOCFG0, kIOCFG0Config);
    WriteByte(kIOCFG1, kIOCFG1Config);
    WriteByte(kIOCFG2, kIOCFG2Config);

    WriteByte(kPKTCTRL1, PKTCTRL1);
    WriteByte(kPKTCTRL0, PKTCTRL0);

    WriteByte(kADDR, ADDR);

    WriteByte(kPKTLEN, PKTLEN);

    WriteByte(kSYNC1, 0x42);
    WriteByte(kSYNC0, 0x42);

    Serial.print(ReadRegister(0xf0));
    Serial.print(ReadRegister(0xf1));
  }
};

static SHT31D sensor;
static CC1101 radio;

void setup() {
  // initialize LED digital pin as an output.
  pinMode(LED_BUILTIN, OUTPUT);

  Serial.begin(115200);

  Wire.begin();
  SPI.begin();

  sensor.Init();
  radio.Reset();

  delay(100);
}

void loop() {
  // turn the LED on (HIGH is the voltage level)
  digitalWrite(LED_BUILTIN, HIGH);

  // wait for a second
  delay(1000);

  // turn the LED off by making the voltage LOW
  digitalWrite(LED_BUILTIN, LOW);

  Serial.write("Hello world!\n");

   // wait for a second
  delay(1000);

  SHT31D::Reading reading = sensor.ReadTemperatureAndHumidity();
  Serial.print(reading.temperature);
  Serial.println();
  Serial.print(reading.humidity);
  Serial.println();

  uint16_t temp = uint16_t(reading.temperature * 100.0f);
  uint16_t humidity = uint16_t(reading.humidity * 100.0f);

  byte packet[] = {byte(temp >> 8), byte(temp & 0xff), byte(humidity >> 8), byte(humidity & 0xff)};
  radio.SendPacket(packet, sizeof(packet));
}<commit_msg>Upload reading from Arduino every 30s.<commit_after>#include "Arduino.h"

#include <SPI.h>
#include <Wire.h>

#include "cc1101_868_3.h"

class SPITransaction {
 public:
  SPITransaction(int slave_select_pin)
      : slave_select_pin_(slave_select_pin) {
    digitalWrite(slave_select_pin_, LOW);
    SPI.beginTransaction(SPISettings(50000, MSBFIRST, SPI_MODE0));
  }

  ~SPITransaction() {
    digitalWrite(slave_select_pin_, HIGH);
    SPI.endTransaction();
  }

 private:
  const int slave_select_pin_;
};

class SHT31D {
  static const uint8_t kSensorAddress = 0x44;
  static const uint16_t kSoftReset = 0x30a2;
  static const uint16_t kReadSensor = 0x2400;

 public:
  void Init() {
    WriteCommand(kSoftReset);
    delay(10);
  }

  struct Reading {
    float temperature;
    float humidity;

    Reading(float temperature, float humidity)
        : temperature(temperature),
          humidity(humidity) {}
  };

 private:
  static float ConvertTemperature(uint16_t raw_temp) {
    return -45 + 175 * (float(raw_temp) / 0xffff);
  }

  static float ConvertHumidity(uint16_t raw_humidity) {
    return 100 * (float(raw_humidity) / 0xffff);
  }

  static bool WriteCommand(uint16_t command) {
    Wire.beginTransmission(kSensorAddress);
    Wire.write(command >> 8);
    Wire.write(command & 0xff);
    return Wire.endTransmission() == 0;
  }

 public:
  Reading ReadTemperatureAndHumidity() {
    WriteCommand(kReadSensor);
    delay(500);
    Wire.requestFrom(kSensorAddress, uint8_t(6));
    if (Wire.available() == 6) {
      uint16_t raw_temp = (Wire.read() << 8) | (Wire.read() & 0xff);
      uint8_t temp_crc = Wire.read();
      uint16_t raw_humidity = (Wire.read() << 8) | (Wire.read() & 0xff);
      uint8_t humidity_crc = Wire.read();
      return Reading(ConvertTemperature(raw_temp), ConvertHumidity(raw_humidity));
    }
    Serial.println("Failed to read sensor");
    return Reading(0.0f, 0.0f);
  }
};

class CC1101 {
 private:
  const int kSlaveSelectPin = 10;
  const int kGDO0Pin = 5;
  const int kGDO2Pin = 6;

  const byte kWriteSingleByte = 0x00;
  const byte kWriteBurst = 0x40;
  const byte kReadBurst = 0xc0;
  const byte kReadSingleByte = 0x80;

  const byte kSRES = 0x30;
  const byte kSTX = 0x35;
  const byte kSFTX = 0x3b;
  const byte kSIDLE = 0x36;

  const byte kIOCFG0Config = 0x07;
  const byte kIOCFG1Config = 0x2e;
  const byte kIOCFG2Config = 0x06;

  const byte kIOCFG0 = 0x02;
  const byte kIOCFG1 = 0x01;
  const byte kIOCFG2 = 0x00;

  const byte kTXFIFO = 0x3f;

  const byte kFIFOTHR = 0x03;
  const byte kSYNC1 = 0x04;
  const byte kSYNC0 = 0x05;

  const byte kPKTLEN = 0x06;
  const byte kPKTCTRL1 = 0x07;
  const byte kPKTCTRL0 = 0x08;

  const byte kADDR = 0x09;

  const byte kCHANNR = 0x0a;
  const byte kFSCTRL1 = 0x0b;
  const byte kFSCTRL0 = 0x0c;

  const byte kFREQ2 = 0x0d;
  const byte kFREQ1 = 0x0e;
  const byte kFREQ0 = 0x0f;

  const byte kMDMCFG4 = 0x10;
  const byte kMDMCFG3 = 0x11;
  const byte kMDMCFG2 = 0x12;
  const byte kMDMCFG1 = 0x13;
  const byte kMDMCFG0 = 0x14;

  const byte kDEVIATN = 0x15;

  const byte kMCSM2 = 0x16;
  const byte kMCSM1 = 0x17;
  const byte kMCSM0 = 0x18;

  const byte kFOCCFG = 0x19;
  const byte kBSCFG = 0x1a;

  const byte kAGCCTRL2 = 0x1b;
  const byte kAGCCTRL1 = 0x1c;
  const byte kAGCCTRL0 = 0x1d;

  const byte kFREND1 = 0x21;
  const byte kFREND0 = 0x22;

  const byte kFSCAL3 = 0x23;
  const byte kFSCAL2 = 0x24;
  const byte kFSCAL1 = 0x25;
  const byte kFSCAL0 = 0x26;

  const byte kFSTEST = 0x29;
  const byte kTEST2 = 0x2c;
  const byte kTEST1 = 0x2d;
  const byte kTEST0 = 0x2e;

  byte ReadRegister(byte addr) {
    SPITransaction transaction(kSlaveSelectPin);

    SPI.transfer(addr | kReadSingleByte);
    byte reply = SPI.transfer(0x00);

    return reply;
  }

  void WriteByte(byte address, byte data) {
    SPITransaction transaction(kSlaveSelectPin);
    SPI.transfer(address | kWriteSingleByte);
    SPI.transfer(data);
  }

  void Strobe(byte command) {
    SPITransaction transaction(kSlaveSelectPin);
    SPI.transfer(command);
  }

  void WriteBurst(byte address, byte* data, int length) {
    SPITransaction transaction(kSlaveSelectPin);
    SPI.transfer(address | kWriteBurst);
    for (int i = 0; i < length; ++i) {
      data[i] = SPI.transfer(data[i]);
    }
  }

  void ReadBurst(byte address, byte* buffer, int length) {
    SPITransaction transaction(kSlaveSelectPin);
    SPI.transfer(address | kReadBurst);
    for (int i = 0; i < length; ++i) {
      buffer[i] = SPI.transfer(0x00);
    }
  }

 public:
  void SendPacket(byte* buffer, byte length) {
    Serial.println("Sending packet");
    WriteByte(kTXFIFO, length);
    WriteBurst(kTXFIFO, buffer, length);
    // Send the packet.
    Strobe(kSTX);

    // Wait for sync word to transmit.
    while(!digitalRead(kGDO2Pin)) {}
    // Wait for packet to be sent.
    while(digitalRead(kGDO2Pin)) {}

    // Return to idle state.
    Strobe(kSIDLE);
    // Flush the TXFIFO buffer.
    Strobe(kSFTX);
    Serial.println("Sent packet");
  }

  void Reset() {
    pinMode(kGDO0Pin, INPUT);
    pinMode(kGDO2Pin, INPUT);
    pinMode(kSlaveSelectPin, OUTPUT);

    Strobe(kSRES);
    delay(100);

    WriteByte(kFSCTRL1, FSCTRL1);
    WriteByte(kFSCTRL0, FSCTRL0);

    WriteByte(kFREQ2, FREQ2);
    WriteByte(kFREQ1, FREQ1);
    WriteByte(kFREQ0, FREQ0);

    WriteByte(kMDMCFG4, MDMCFG4);
    WriteByte(kMDMCFG3, MDMCFG3);
    WriteByte(kMDMCFG2, MDMCFG2);
    WriteByte(kMDMCFG1, MDMCFG1);
    WriteByte(kMDMCFG0, MDMCFG0);

    WriteByte(kCHANNR, CHANNR);
    WriteByte(kDEVIATN, DEVIATN);
    WriteByte(kFREND1, FREND1);
    WriteByte(kFREND0, FREND0);
    WriteByte(kMCSM2, MCSM2);
    WriteByte(kMCSM1, MCSM1);
    WriteByte(kMCSM0, MCSM0);
    WriteByte(kFOCCFG, FOCCFG);
    WriteByte(kBSCFG, BSCFG);

    WriteByte(kAGCCTRL2, AGCCTRL2);
    WriteByte(kAGCCTRL1, AGCCTRL1);
    WriteByte(kAGCCTRL0, AGCCTRL0);

    WriteByte(kFSCAL3, FSCAL3);
    WriteByte(kFSCAL2, FSCAL2);
    WriteByte(kFSCAL1, FSCAL1);
    WriteByte(kFSCAL0, FSCAL0);

    WriteByte(kFSTEST, FSTEST);
    WriteByte(kTEST2, TEST2);
    WriteByte(kTEST1, TEST1);
    WriteByte(kTEST0, TEST0);

    WriteByte(kIOCFG0, kIOCFG0Config);
    WriteByte(kIOCFG1, kIOCFG1Config);
    WriteByte(kIOCFG2, kIOCFG2Config);

    WriteByte(kPKTCTRL1, PKTCTRL1);
    WriteByte(kPKTCTRL0, PKTCTRL0);

    WriteByte(kADDR, ADDR);

    WriteByte(kPKTLEN, PKTLEN);

    WriteByte(kSYNC1, 0x42);
    WriteByte(kSYNC0, 0x42);

    Serial.print(ReadRegister(0xf0));
    Serial.print(ReadRegister(0xf1));
  }
};

static SHT31D sensor;
static CC1101 radio;

void setup() {
  // initialize LED digital pin as an output.
  pinMode(LED_BUILTIN, OUTPUT);

  Serial.begin(115200);

  Wire.begin();
  SPI.begin();

  sensor.Init();
  radio.Reset();

  delay(100);
}

void loop() {
  Serial.write("Hello world!\n");

  SHT31D::Reading reading = sensor.ReadTemperatureAndHumidity();
  Serial.print(reading.temperature);
  Serial.println();
  Serial.print(reading.humidity);
  Serial.println();

  uint16_t temp = uint16_t(reading.temperature * 100.0f);
  uint16_t humidity = uint16_t(reading.humidity * 100.0f);

  byte packet[] = {byte(temp >> 8), byte(temp & 0xff), byte(humidity >> 8), byte(humidity & 0xff)};
  radio.SendPacket(packet, sizeof(packet));

   // wait for a bit
  delay(30000);
}<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <cstdint>
#include <algorithm>
#include <memory>
#include <thread>

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

#include "dcpu.hpp"
#include "disassembler.hpp"

#include "gclock.hpp"
#include "fake_lem1802.hpp"
#include "lem1802.hpp"
#include "lem1803.hpp"

using namespace cpu;

const long TOTALCPUS    = 215*16;
const long PERTHREAD    = 16;  // At 16 looks that is the ideal for the FX-4100
#define THREADS           (TOTALCPUS/PERTHREAD)
const long CYCLES       = 1000*1000;

const int BATCH         = 10;

std::vector<std::vector<std::shared_ptr<DCPU>>> threads;
uint16_t* data;
size_t size = 0;

void benchmark();
void step();
void one_bench();
void run100k();

void cpu_in_thread(int n);

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

    char* filename;
    std::ifstream binfile;

   /* std::cout << "cpu " << sizeof(DCPU) << " IHardware " << sizeof(IHardware);
    std::cout << " fake_LEM1802 " << sizeof(Fake_Lem1802) << std::endl;*/

    if (argc <= 1) {
        std::cerr << "Missing input file\n";
        return 0;
    }

    filename = argv[1];
    std::cout <<  "Input BIN File : " << filename << "\n";

    binfile.open (filename, std::ios::in | std::ios::binary );

    if (!binfile) {
        std::cerr << "ERROR: I can open file\n";
        exit (1);
    }

    // get length of file:
    binfile.seekg (0, binfile.end);
    size = binfile.tellg();
    binfile.seekg (0, binfile.beg);

    data = new uint16_t[size / 2 + 1]();
    std::fill_n (data, size / 2, 0); // Clean it

    int i = 0;

    while (! binfile.eof() ) {
        uint16_t word = 0;
        binfile.read ( (char*) &word, 2);
        unsigned char tmp = ( (word & 0xFF00) >> 8) & 0x00FF;
        word = ( (word & 0x00FF) << 8) | tmp;
        data[i] = word;
        i++;
    }

    binfile.close();

    std::cout << "Readed " << size << " bytes - " << size / 2 << " words\n";
    size /= 2;

badchar:
    std::cout << "Select what to do :" << std::endl;
    std::cout << "\tb -> benchmark  s -> step execution o-> benchmark one VM r-> run 800k cycles";
    std::cout << std::endl << std::endl;
    char choose;
    std::cin >> choose;

    if (choose == 'b' || choose == 'B') {
        benchmark();
    } else if ( choose == 's' || choose == 'S') {
        step();
    } else if ( choose == 'o' || choose == 'O') {
        one_bench();
    } else if ( choose == 'r' || choose == 'R') {
        run100k();
    } else {
        goto badchar; /// HATE ME!!!!
    }

    delete[] data;

    return 0;
}

void benchmark()
{
    // Load program to all CPUs
    for (int u=0; u< THREADS; u++) {
        std::vector<std::shared_ptr<DCPU>> cpus;
        cpus.reserve (PERTHREAD);
        for (int i = 0; i< PERTHREAD; i++) {
            auto cpu = std::make_shared<DCPU>();
            //auto screen = std::make_shared<Fake_Lem1802>();
            //screen->setEnable(false); // We not desire to write to stdout
            //cpu->attachHardware (screen);
            cpu->reset();
            cpu->loadProgram (data, size);

            cpus.push_back(cpu);
        }

        threads.push_back(cpus);

    }

    std::thread tds[THREADS];

    printf("Threads %ld\t CPU PerThread %ld\t", THREADS, PERTHREAD);
    printf("N cpus %ld\n", PERTHREAD * THREADS);
    printf("Cycles %ld\n", CYCLES);

    auto start = std::chrono::high_resolution_clock::now();

    for (int i=0; i< THREADS; i++) {
        tds[i] = std::thread(cpu_in_thread, i);
    }

    for (int i=0; i< THREADS; i++) {
        tds[i].join();
    }

	auto end = std::chrono::high_resolution_clock::now();
    auto dur = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
	std::cout << "Measured time: " << dur.count() << "ms" << std::endl;

}

void step() {
    using namespace std;
    auto cpu = make_shared<DCPU>();

    auto screen1 = std::make_shared<Lem1802>();
    cpu->attachHardware (screen1);
    auto screen2 = std::make_shared<Lem1803>();
    cpu->attachHardware (screen2);

    cpu->reset();
    cpu->loadProgram (data, size);

    char c = getchar();
    while (1) {
        c = getchar();
        if (c == 'f' || c == 'q' || c == '\n' )
            break;
    }

    while (c != 'q') {

        cout << cpu->dumpRegisters() << endl;
        cout << "T cycles " << dec << cpu->getTotCycles() << endl;
        cout << "> " << cpu->dumpRam() << " - ";
        string s = disassembly(cpu->getMem() + cpu->GetPC(), 3);
        cout << s << endl;

        if (cpu->GetSP() != 0x0000)
            cout << "STACK : "<< cpu->dumpRam(cpu->GetSP(), 0xFFFF) << endl;

        if (c == 'f') {
            for (int i = 0; i < 100; i++)
                cpu->tick();
        } else {
            if (cpu->tick())
                cout << "Execute! ";
        }
        cout << endl;

        while (1) {
            c = getchar();
            if (c == 'f' || c == 'q' || c == '\n' )
                break;
        }

    }

}

void one_bench() {
    using namespace std;
    using namespace std::chrono;

    const int times = 200;

    high_resolution_clock::time_point  starts[times];
    high_resolution_clock::time_point  creates[times];
    high_resolution_clock::time_point  loadstarts[times];
    high_resolution_clock::time_point  loads[times];
    high_resolution_clock::time_point  finishs[times];

    for (int x=0; x < times; x++) {
        using namespace std::chrono;
        starts[x] = high_resolution_clock::now();
        auto cpu = make_shared<DCPU>();

        creates[x] = high_resolution_clock::now();

        auto screen = make_shared<Fake_Lem1802>();
        screen->setEnable(false); // We not desire to write to stdout
        cpu->attachHardware (screen);

        loadstarts[x] = high_resolution_clock::now();

        cpu->reset();
        cpu->loadProgram (data, size);

        loads[x] = high_resolution_clock::now();

        for (int i=0; i < 10000; i++) {
            cpu->tick();
        }
        finishs[x] = high_resolution_clock::now();
    }

    double d_create, d_load, d_execute;
    d_create = d_load = d_execute = 0;

    for (int x=0; x < times; x++) {

        auto tmp = duration_cast<chrono::microseconds>
            (creates[x] - starts[x]);
        d_create += tmp.count();

        tmp = duration_cast<chrono::microseconds>
            (loads[x] - loadstarts[x]);
        d_load += tmp.count();

        tmp = duration_cast<chrono::microseconds>
            (finishs[x] - loads[x]);

        d_execute += tmp.count();

    }
    d_create /= times;
    d_load /= times;
    d_execute /= times;

    cout << "Measured time: " << endl;
    cout << "\tCreating time "<< d_create << "us" << endl;
    cout << "\tLoad time "<< d_load << "us" << endl;
    cout << "\tExecute 10k cycles time "<< d_execute << "us" << endl;

}

void run100k() {

    using namespace std;
    using namespace std::chrono;

    auto cpu = make_shared<DCPU>();
    auto screen1 = std::make_shared<Lem1803>();
    cpu->attachHardware (screen1);

    auto screen2 = make_shared<Lem1802>();
    cpu->attachHardware (screen2);

    // FIXME See what fails with clock
    auto clock = make_shared<Generic_Clock>();
    cpu->attachHardware (clock);

    cpu->reset();
    cpu->loadProgram (data, size);

    high_resolution_clock::time_point b, e;
    char c;
    do {
        for (int i=0; i < 800000; i++) {
            b =  high_resolution_clock::now();
            cpu->tick();
            e =  high_resolution_clock::now();

            auto delta = duration_cast<chrono::nanoseconds>(e - b);
            auto rest = nanoseconds(1000000000/cpu->cpu_clock)-delta;

            if ((i % 50000) == 0) { // Not show running speed every clock tick
                double p = nanoseconds(1000000000/cpu->cpu_clock).count() /
                    (double)(delta.count() + rest.count());
                cerr << "Delta :" << delta.count() << " ns ";
                cerr << "Rest :" << rest.count() << " ns ";
                cerr << " Running at "<< p*100.0 << " % speed." << endl;
            }
            //this_thread::sleep_for(duration_cast<chrono::nanoseconds>(rest));
        }
        cout << "Press q to exit. Other key to run more." << std::endl;
        cin >> c;
    } while (c != 'q' && c!= 'Q');

}

// Runs PERTHREAD cpus, doing CYCLES cycles
void cpu_in_thread(int n) {
    auto cpus = threads[n];
    for (long i=0; i < CYCLES; i+= BATCH) {
        for (auto c = cpus.begin(); c != cpus.end(); c++) {
            for ( int j=0; j < BATCH; j++)
                (*c)->tick();
        }
    }
}

<commit_msg>Fixed<commit_after>#include <iostream>
#include <fstream>
#include <cstdint>
#include <algorithm>
#include <memory>
#include <thread>

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

#include "dcpu.hpp"
#include "disassembler.hpp"

#include "gclock.hpp"
#include "fake_lem1802.hpp"
#include "lem1802.hpp"
#include "lem1803.hpp"

using namespace cpu;

const long TOTALCPUS    = 215*16;
const long PERTHREAD    = 16;  // At 16 looks that is the ideal for the FX-4100
#define THREADS           (TOTALCPUS/PERTHREAD)
const long CYCLES       = 1000*1000;

const int BATCH         = 10;

std::vector<std::vector<std::shared_ptr<DCPU>>> threads;
uint16_t* data;
size_t size = 0;

void benchmark();
void step();
void one_bench();
void run100k();

void cpu_in_thread(int n);

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

    char* filename;
    std::ifstream binfile;

   /* std::cout << "cpu " << sizeof(DCPU) << " IHardware " << sizeof(IHardware);
    std::cout << " fake_LEM1802 " << sizeof(Fake_Lem1802) << std::endl;*/

    if (argc <= 1) {
        std::cerr << "Missing input file\n";
        return 0;
    }

    filename = argv[1];
    std::cout <<  "Input BIN File : " << filename << "\n";

    binfile.open (filename, std::ios::in | std::ios::binary );

    if (!binfile) {
        std::cerr << "ERROR: I can open file\n";
        exit (1);
    }

    // get length of file:
    binfile.seekg (0, binfile.end);
    size = binfile.tellg();
    binfile.seekg (0, binfile.beg);

    data = new uint16_t[size / 2 + 1]();
    std::fill_n (data, size / 2, 0); // Clean it

    int i = 0;

    while (! binfile.eof() ) {
        uint16_t word = 0;
        binfile.read ( (char*) &word, 2);
        unsigned char tmp = ( (word & 0xFF00) >> 8) & 0x00FF;
        word = ( (word & 0x00FF) << 8) | tmp;
        data[i] = word;
        i++;
    }

    binfile.close();

    std::cout << "Readed " << size << " bytes - " << size / 2 << " words\n";
    size /= 2;

badchar:
    std::cout << "Select what to do :" << std::endl;
    std::cout << "\tb -> benchmark  s -> step execution o-> benchmark one VM r-> run 800k cycles";
    std::cout << std::endl << std::endl;
    char choose;
    std::cin >> choose;

    if (choose == 'b' || choose == 'B') {
        benchmark();
    } else if ( choose == 's' || choose == 'S') {
        step();
    } else if ( choose == 'o' || choose == 'O') {
        one_bench();
    } else if ( choose == 'r' || choose == 'R') {
        run100k();
    } else {
        goto badchar; /// HATE ME!!!!
    }

    delete[] data;

    return 0;
}

void benchmark()
{
    // Load program to all CPUs
    for (int u=0; u< THREADS; u++) {
        std::vector<std::shared_ptr<DCPU>> cpus;
        cpus.reserve (PERTHREAD);
        for (int i = 0; i< PERTHREAD; i++) {
            auto cpu = std::make_shared<DCPU>();
            //auto screen = std::make_shared<Fake_Lem1802>();
            //screen->setEnable(false); // We not desire to write to stdout
            //cpu->attachHardware (screen);
            cpu->reset();
            cpu->loadProgram (data, size);

            cpus.push_back(cpu);
        }

        threads.push_back(cpus);

    }

    std::thread tds[THREADS];

    printf("Threads %ld\t CPU PerThread %ld\t", THREADS, PERTHREAD);
    printf("N cpus %ld\n", PERTHREAD * THREADS);
    printf("Cycles %ld\n", CYCLES);

    auto start = std::chrono::high_resolution_clock::now();

    for (int i=0; i< THREADS; i++) {
        tds[i] = std::thread(cpu_in_thread, i);
    }

    for (int i=0; i< THREADS; i++) {
        tds[i].join();
    }

	auto end = std::chrono::high_resolution_clock::now();
    auto dur = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
	std::cout << "Measured time: " << dur.count() << "ms" << std::endl;

}

void step() {
    using namespace std;
    auto cpu = make_shared<DCPU>();

    auto screen1 = std::make_shared<Lem1802>();
    cpu->attachHardware (screen1);
    auto screen2 = std::make_shared<Lem1803>();
    cpu->attachHardware (screen2);

    cpu->reset();
    cpu->loadProgram (data, size);

    char c = getchar();
    while (1) {
        c = getchar();
        if (c == 'f' || c == 'q' || c == '\n' )
            break;
    }

    while (c != 'q') {

        cout << cpu->dumpRegisters() << endl;
        cout << "T cycles " << dec << cpu->getTotCycles() << endl;
        cout << "> " << cpu->dumpRam() << " - ";
        string s = disassembly(cpu->getMem() + cpu->GetPC(), 3);
        cout << s << endl;

        if (cpu->GetSP() != 0x0000)
            cout << "STACK : "<< cpu->dumpRam(cpu->GetSP(), 0xFFFF) << endl;

        if (c == 'f') {
            for (int i = 0; i < 100; i++)
                cpu->tick();
        } else {
            if (cpu->tick())
                cout << "Execute! ";
        }
        cout << endl;

        while (1) {
            c = getchar();
            if (c == 'f' || c == 'q' || c == '\n' )
                break;
        }

    }

}

void one_bench() {
    using namespace std;
    using namespace std::chrono;

    const int times = 200;

    high_resolution_clock::time_point  starts[times];
    high_resolution_clock::time_point  creates[times];
    high_resolution_clock::time_point  loadstarts[times];
    high_resolution_clock::time_point  loads[times];
    high_resolution_clock::time_point  finishs[times];

    for (int x=0; x < times; x++) {
        using namespace std::chrono;
        starts[x] = high_resolution_clock::now();
        auto cpu = make_shared<DCPU>();

        creates[x] = high_resolution_clock::now();

        auto screen = make_shared<Fake_Lem1802>();
        screen->setEnable(false); // We not desire to write to stdout
        cpu->attachHardware (screen);

        loadstarts[x] = high_resolution_clock::now();

        cpu->reset();
        cpu->loadProgram (data, size);

        loads[x] = high_resolution_clock::now();

        for (int i=0; i < 10000; i++) {
            cpu->tick();
        }
        finishs[x] = high_resolution_clock::now();
    }

    double d_create, d_load, d_execute;
    d_create = d_load = d_execute = 0;

    for (int x=0; x < times; x++) {

        auto tmp = duration_cast<chrono::microseconds>
            (creates[x] - starts[x]);
        d_create += tmp.count();

        tmp = duration_cast<chrono::microseconds>
            (loads[x] - loadstarts[x]);
        d_load += tmp.count();

        tmp = duration_cast<chrono::microseconds>
            (finishs[x] - loads[x]);

        d_execute += tmp.count();

    }
    d_create /= times;
    d_load /= times;
    d_execute /= times;

    cout << "Measured time: " << endl;
    cout << "\tCreating time "<< d_create << "us" << endl;
    cout << "\tLoad time "<< d_load << "us" << endl;
    cout << "\tExecute 10k cycles time "<< d_execute << "us" << endl;

}

void run100k() {

    using namespace std;
    using namespace std::chrono;

    auto cpu = make_shared<DCPU>();
    auto screen1 = std::make_shared<Lem1803>();
    cpu->attachHardware (screen1);

    auto screen2 = make_shared<Lem1802>();
    cpu->attachHardware (screen2);

    auto clock = make_shared<Generic_Clock>();
    cpu->attachHardware (clock);

    cpu->reset();
    cpu->loadProgram (data, size);

    high_resolution_clock::time_point b, e;
    char c;
    do {
        for (int i=0; i < 800000; i++) {
            b =  high_resolution_clock::now();
            cpu->tick();
            e =  high_resolution_clock::now();

            auto delta = duration_cast<chrono::nanoseconds>(e - b);
            auto rest = nanoseconds(1000000000/cpu->cpu_clock)-delta;

            if ((i % 50000) == 0) { // Not show running speed every clock tick
                double p = nanoseconds(1000000000/cpu->cpu_clock).count() /
                    (double)(delta.count() + rest.count());
                cerr << "Delta :" << delta.count() << " ns ";
                cerr << "Rest :" << rest.count() << " ns ";
                cerr << " Running at "<< p*100.0 << " % speed." << endl;
            }
            //this_thread::sleep_for(duration_cast<chrono::nanoseconds>(rest));
        }
        cout << "Press q to exit. Other key to run more." << std::endl;
        cin >> c;
    } while (c != 'q' && c!= 'Q');

}

// Runs PERTHREAD cpus, doing CYCLES cycles
void cpu_in_thread(int n) {
    auto cpus = threads[n];
    for (long i=0; i < CYCLES; i+= BATCH) {
        for (auto c = cpus.begin(); c != cpus.end(); c++) {
            for ( int j=0; j < BATCH; j++)
                (*c)->tick();
        }
    }
}

<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <map>
#include <memory>

#include <cstdlib>

#include "output.hxx"
#include "threaded-manager.hxx"
#include "tile.hxx"
#include "exceptions.hxx"

using namespace game_of_life;

using std::vector;
using std::string;

using std::exception;
using std::domain_error;

using std::map;

using std::cin;
using std::istringstream;
using std::ifstream;

vector<string> split(const string& s)
{
    vector<string> ret;
    istringstream iss(s);
    string w;
    while (iss >> w)
        if (!w.empty())
            ret.push_back(w);
    return ret;
}

int toInt(const string &s)
{
    int ret = 0;
    if (s.size() > 8)
        throw domain_error(string("\"") + s + "\" is too long for int");
    for (size_t i = 0; i < s.size(); ++i)
    {
        char c = s[i];
        if (c >= '0' && c <= '9')
            ret = ret * 10 + c - '0';
        else
            throw domain_error(string("\"") + s + "\" is not an integer");
    }
    return ret;
}

ThreadedManager manager;
Matrix matrix;

typedef const vector<string>& Params;
typedef void (*CommandHandler)(Params);

void checkParamCount(const string& tag, Params p, size_t lo, size_t hi)
{
    if (p.size() > hi)
        throw IncorrectCommandException(tag + "too much parameters");
    if (p.size() < lo)
        throw IncorrectCommandException(tag + "too few parameters");
}

void start(Params p)
{
    static const string TAG("START: ");

    if (manager.getState() != ThreadedManager::NOT_STARTED)
        throw IncorrectCommandException(TAG + "already started");
    checkParamCount(TAG, p, 2, 3);

    int concurrency;
    try
    {
        concurrency = toInt(p[0]);
        if (concurrency <= 0)
            throw IncorrectCommandException(TAG + "incorrect concurrency");
        if (p.size() == 3)
        {
            int h = toInt(p[1]), w = toInt(p[2]);
            if (h <= 0 || w <= 0)
                throw IncorrectCommandException(TAG + "incorrect matrix size");
            matrix = Matrix::random(h, w, 42);
        }
        else
        {
            try
            {
                ifstream csv(p[1].data());
                matrix = Matrix::fromCsv(csv);
            }
            catch (exception& e)
            {
                throw IncorrectCommandException(TAG + e.what());
            }
        }
    }
    catch (domain_error& e)
    {
        throw IncorrectCommandException(TAG + e.what());
    }
    debug(TAG + "starting the manager");
    manager.start(matrix, concurrency);
}

void status(Params p)
{
    static const string TAG("STATUS: ");
    checkParamCount(TAG, p, 0, 0);

    Manager::State state = manager.getState();

    OstreamLocker o(out());
    o << "System state: " << manager.stateStr(state) << "\n";
    if (state != Manager::NOT_STARTED && state != Manager::RUNNING)
    {
        o << "After iteration " << manager.getShared().getStop() << ":\n";
        matrix.output(o.get());
    }
}

void run(Params p)
{
    static const string TAG("RUN: ");
    checkParamCount(TAG, p, 1, 1);

    int runs;
    switch (manager.getState())
    {
    case Manager::NOT_STARTED:
        throw IncorrectCommandException(
                TAG + "task unknown, use START to initialize.");
    case Manager::STOPPED:
        try
        {
            runs = toInt(p[0]);
        }
        catch (domain_error& e)
        {
            throw IncorrectCommandException(TAG + e.what());
        }
        debug(TAG + "trying to add " + p[0] + " iterations");
        manager.runForMore(runs);
        break;
    default:
        throw IncorrectCommandException(TAG + "system is busy");
    }
}

void stop(Params p)
{
    static const string TAG("STOP: ");
    checkParamCount(TAG, p, 0, 0);

    switch (manager.getState())
    {
    case Manager::RUNNING:
        debug(TAG + "stopping");
        manager.pauseAll();
        manager.wakeWhenStateIs(Manager::STOPPED);
        debug(TAG + "awake and stopped");
        out() << "Stopped at " << manager.getShared().getStop() << "\n";
        break;
    default:
        throw IncorrectCommandException(TAG + "not running");
    }
}

void quit(Params p)
{
    static const string TAG("QUIT: ");
    checkParamCount(TAG, p, 0, 0);

    debug(TAG);
    if (manager.getState() != Manager::NOT_STARTED)
    {
        debug(TAG + "manager has started, trying to shut him");
        manager.shutdown();
        manager.join();
        debug(TAG + "joined the manager");
    }
    debug(TAG + "exiting the program gracefully ----------");
    exit(0);
}

void unknownCommand(const string& s)
{
    throw IncorrectCommandException(string("\"") + s + "\" is not supported ._.");
}

int main()
{
    map<string, CommandHandler> cmdMap;
    cmdMap["START"] = start;
    cmdMap["STATUS"] = status;
    cmdMap["RUN"] = run;
    cmdMap["STOP"] = stop;
    cmdMap["QUIT"] = quit;

    string line;
    debug("---------------- RESTART ----------------------");
    while (out("game-of-life: "), getline(cin, line))
    {
        vector<string> words = split(line);

        if (words.empty())
            continue;

        string cmd = words[0];
        for (size_t i = 0; i < cmd.size(); ++i)
            cmd[i] = toupper(cmd[i]);

        words.erase(words.begin());

        map<string, CommandHandler>::iterator it = cmdMap.find(cmd);
        try
        {
            if (it != cmdMap.end())
                it->second(words);
            else
                unknownCommand(cmd);
        }
        catch (IncorrectCommandException& e)
        {
            err() << e.what() << "\n";
        }
    }
    out("quit\n");
    quit(vector<string>());
}

<commit_msg>Handle bad_alloc<commit_after>#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <map>
#include <memory>

#include <cstdlib>

#include "output.hxx"
#include "threaded-manager.hxx"
#include "tile.hxx"
#include "exceptions.hxx"

using namespace game_of_life;

using std::vector;
using std::string;

using std::exception;
using std::domain_error;
using std::bad_alloc;

using std::map;

using std::cin;
using std::istringstream;
using std::ifstream;

vector<string> split(const string& s)
{
    vector<string> ret;
    istringstream iss(s);
    string w;
    while (iss >> w)
        if (!w.empty())
            ret.push_back(w);
    return ret;
}

int toInt(const string &s)
{
    int ret = 0;
    if (s.size() > 8)
        throw domain_error(string("\"") + s + "\" is too long for int");
    for (size_t i = 0; i < s.size(); ++i)
    {
        char c = s[i];
        if (c >= '0' && c <= '9')
            ret = ret * 10 + c - '0';
        else
            throw domain_error(string("\"") + s + "\" is not an integer");
    }
    return ret;
}

ThreadedManager manager;
Matrix matrix;

typedef const vector<string>& Params;
typedef void (*CommandHandler)(Params);

void checkParamCount(const string& tag, Params p, size_t lo, size_t hi)
{
    if (p.size() > hi)
        throw IncorrectCommandException(tag + "too much parameters");
    if (p.size() < lo)
        throw IncorrectCommandException(tag + "too few parameters");
}

void start(Params p)
{
    static const string TAG("START: ");

    if (manager.getState() != ThreadedManager::NOT_STARTED)
        throw IncorrectCommandException(TAG + "already started");
    checkParamCount(TAG, p, 2, 3);

    int concurrency;
    try
    {
        concurrency = toInt(p[0]);
        if (concurrency <= 0)
            throw IncorrectCommandException(TAG + "incorrect concurrency");
        if (p.size() == 3)
        {
            int h = toInt(p[1]), w = toInt(p[2]);
            if (h <= 0 || w <= 0)
                throw IncorrectCommandException(TAG + "incorrect matrix size");
            matrix = Matrix::random(h, w, 42);
        }
        else
        {
            try
            {
                ifstream csv(p[1].data());
                matrix = Matrix::fromCsv(csv);
            }
            catch (exception& e)
            {
                throw IncorrectCommandException(TAG + e.what());
            }
        }
    }
    catch (domain_error& e)
    {
        throw IncorrectCommandException(TAG + e.what());
    }
    catch (bad_alloc& e)
    {
        throw IncorrectCommandException(TAG +
                "couldn't allocate enough memory");
    }
    debug(TAG + "starting the manager");
    manager.start(matrix, concurrency);
}

void status(Params p)
{
    static const string TAG("STATUS: ");
    checkParamCount(TAG, p, 0, 0);

    Manager::State state = manager.getState();

    OstreamLocker o(out());
    o << "System state: " << manager.stateStr(state) << "\n";
    if (state != Manager::NOT_STARTED && state != Manager::RUNNING)
    {
        o << "After iteration " << manager.getShared().getStop() << ":\n";
        matrix.output(o.get());
    }
}

void run(Params p)
{
    static const string TAG("RUN: ");
    checkParamCount(TAG, p, 1, 1);

    int runs;
    switch (manager.getState())
    {
    case Manager::NOT_STARTED:
        throw IncorrectCommandException(
                TAG + "task unknown, use START to initialize.");
    case Manager::STOPPED:
        try
        {
            runs = toInt(p[0]);
        }
        catch (domain_error& e)
        {
            throw IncorrectCommandException(TAG + e.what());
        }
        debug(TAG + "trying to add " + p[0] + " iterations");
        manager.runForMore(runs);
        break;
    default:
        throw IncorrectCommandException(TAG + "system is busy");
    }
}

void stop(Params p)
{
    static const string TAG("STOP: ");
    checkParamCount(TAG, p, 0, 0);

    switch (manager.getState())
    {
    case Manager::RUNNING:
        debug(TAG + "stopping");
        manager.pauseAll();
        manager.wakeWhenStateIs(Manager::STOPPED);
        debug(TAG + "awake and stopped");
        out() << "Stopped at " << manager.getShared().getStop() << "\n";
        break;
    default:
        throw IncorrectCommandException(TAG + "not running");
    }
}

void quit(Params p)
{
    static const string TAG("QUIT: ");
    checkParamCount(TAG, p, 0, 0);

    debug(TAG);
    if (manager.getState() != Manager::NOT_STARTED)
    {
        debug(TAG + "manager has started, trying to shut him");
        manager.shutdown();
        manager.join();
        debug(TAG + "joined the manager");
    }
    debug(TAG + "exiting the program gracefully ----------");
    exit(0);
}

void unknownCommand(const string& s)
{
    throw IncorrectCommandException(string("\"") + s + "\" is not supported ._.");
}

int main()
{
    map<string, CommandHandler> cmdMap;
    cmdMap["START"] = start;
    cmdMap["STATUS"] = status;
    cmdMap["RUN"] = run;
    cmdMap["STOP"] = stop;
    cmdMap["QUIT"] = quit;

    string line;
    debug("---------------- RESTART ----------------------");
    while (out("game-of-life: "), getline(cin, line))
    {
        vector<string> words = split(line);

        if (words.empty())
            continue;

        string cmd = words[0];
        for (size_t i = 0; i < cmd.size(); ++i)
            cmd[i] = toupper(cmd[i]);

        words.erase(words.begin());

        map<string, CommandHandler>::iterator it = cmdMap.find(cmd);
        try
        {
            if (it != cmdMap.end())
                it->second(words);
            else
                unknownCommand(cmd);
        }
        catch (IncorrectCommandException& e)
        {
            err() << e.what() << "\n";
        }
    }
    out("quit\n");
    quit(vector<string>());
}

<|endoftext|>


<commit_before>/*
   Copyright (c) 2015, 2016, Andreas Fett
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright notice, this
     list of conditions and the following disclaimer.

   * Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include <iobuf.h>

void iobuf::fill(size_t size)
{
	assert(wstart_ + size <= capacity_);
	wstart_ += size;
}

size_t iobuf::rsize() const
{
	return wstart_ - rstart_;
}

void *iobuf::rstart() const
{
	return (char *)data_ + rstart_;
}

size_t iobuf::wsize() const
{
	return capacity_ - wstart_;
}

void *iobuf::wstart() const
{
	return (char *)data_ + wstart_;
}

void iobuf::drain(size_t size)
{
	assert(size <= rsize());

	rstart_ += size;
	if (rstart_ == wstart_) {
		wstart_ = 0;
		rstart_ = 0;
	}
}

iobuf::iobuf()
:
	data_(0),
	capacity_(0),
	rstart_(0),
	wstart_(0)
{ }

iobuf::iobuf(size_t size)
:
	data_(0),
	capacity_(0),
	rstart_(0),
	wstart_(0)
{
	grow(size);
}

iobuf::~iobuf()
{
	free(data_);
}

void iobuf::reserve(size_t size)
{
	if (size == 0) {
		return;
	}

	if (size <= wsize()) {
		return;
	}

	if (rstart_ != 0) {
		reclaim();
	}

	if (size <= wsize()) {
		return;
	}

	grow(capacity_ + (size - wsize()));
}

void iobuf::grow(size_t capacity)
{
	assert(capacity > capacity_);

	void *n(realloc(data_, capacity));
	if (n != NULL) {
		data_ = n;
		capacity_ = capacity;
	}
}

void iobuf::reclaim()
{
	size_t srsize(rsize());
	memmove(data_, rstart(), srsize);
	rstart_ = 0;
	wstart_ = srsize;
}
<commit_msg>iobuf: use c++ style cstdlib includes<commit_after>/*
   Copyright (c) 2015, 2016, Andreas Fett
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright notice, this
     list of conditions and the following disclaimer.

   * Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <cassert>
#include <cstdlib>
#include <cstring>

#include <iobuf.h>

void iobuf::fill(size_t size)
{
	assert(wstart_ + size <= capacity_);
	wstart_ += size;
}

size_t iobuf::rsize() const
{
	return wstart_ - rstart_;
}

void *iobuf::rstart() const
{
	return (char *)data_ + rstart_;
}

size_t iobuf::wsize() const
{
	return capacity_ - wstart_;
}

void *iobuf::wstart() const
{
	return (char *)data_ + wstart_;
}

void iobuf::drain(size_t size)
{
	assert(size <= rsize());

	rstart_ += size;
	if (rstart_ == wstart_) {
		wstart_ = 0;
		rstart_ = 0;
	}
}

iobuf::iobuf()
:
	data_(0),
	capacity_(0),
	rstart_(0),
	wstart_(0)
{ }

iobuf::iobuf(size_t size)
:
	data_(0),
	capacity_(0),
	rstart_(0),
	wstart_(0)
{
	grow(size);
}

iobuf::~iobuf()
{
	free(data_);
}

void iobuf::reserve(size_t size)
{
	if (size == 0) {
		return;
	}

	if (size <= wsize()) {
		return;
	}

	if (rstart_ != 0) {
		reclaim();
	}

	if (size <= wsize()) {
		return;
	}

	grow(capacity_ + (size - wsize()));
}

void iobuf::grow(size_t capacity)
{
	assert(capacity > capacity_);

	void *n(realloc(data_, capacity));
	if (n != NULL) {
		data_ = n;
		capacity_ = capacity;
	}
}

void iobuf::reclaim()
{
	size_t srsize(rsize());
	memmove(data_, rstart(), srsize);
	rstart_ = 0;
	wstart_ = srsize;
}
<|endoftext|>


<commit_before> /**
 * Copyright (C) 2014 Lantern
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "natty.h"

#include <utility>

#include "talk/app/webrtc/videosourceinterface.h"
#include "talk/base/common.h"
#include "talk/base/json.h"
#include "talk/base/logging.h"
#include "talk/media/devices/devicemanager.h"

#define DEBUG(fmt, ...) printf("%s:%d: " fmt, __FILE__, __LINE__, __VA_ARGS__);

  // Names used for a IceCandidate JSON object.
  const char kCandidateSdpMidName[] = "sdpMid";
  const char kCandidateSdpMlineIndexName[] = "sdpMLineIndex";
  const char kCandidateSdpName[] = "candidate";

  typedef webrtc::PeerConnectionInterface::IceServers IceServers;
  typedef webrtc::PeerConnectionInterface::IceServer IceServer;;

  // Names used for a SessionDescription JSON object.
  const char kSessionDescriptionTypeName[] = "type";
  const char kSessionDescriptionSdpName[] = "sdp";

  class DummySetSessionDescriptionObserver
      : public webrtc::SetSessionDescriptionObserver {
   public:
    static DummySetSessionDescriptionObserver* Create() {
      return
          new talk_base::RefCountedObject<DummySetSessionDescriptionObserver>();
    }
    virtual void OnSuccess() {
      LOG(INFO) << __FUNCTION__;
    }
    virtual void OnFailure(const std::string& error) {
      LOG(INFO) << __FUNCTION__ << " " << error;
    }

   protected:
    DummySetSessionDescriptionObserver() {}
    ~DummySetSessionDescriptionObserver() {}
  };

  Natty::Natty(PeerConnectionClient* client, talk_base::Thread* thread)
    : peer_id_(-1),
      thread(talk_base::Thread::Current()),
      client_(client) {
    client_->RegisterObserver(this);
  }

  Natty::~Natty() {
    ASSERT(peer_connection_.get() == NULL);
  }

  bool Natty::connection_active() const {
    return peer_connection_.get() != NULL;
  }

  PeerConnectionClient* Natty::GetClient() {
    return client_;
  }

  void Natty::SetupSocketServer() {
    talk_base::InitializeSSL();
    Init("107.170.244.214", 8888);
    //Init("127.0.0.1", 8888);
    //InitializePeerConnection();
  }

  void Natty::Shutdown() {
    client_->SignOut();
    talk_base::CleanupSSL();
    thread->Quit();
    thread->set_socketserver(NULL);
  }

void Natty::ConnectToPeer(int peer_id) {
  printf("Trying to connect to peer %d\n", peer_id);
  ASSERT(peer_id_ == -1);
  ASSERT(peer_id != -1);

  if (InitializePeerConnection()) {
    peer_id_ = peer_id;
    peer_connection_->CreateOffer(this, NULL);
  }
}

std::string GetEnvVarOrDefault(const char* env_var_name,
    const char* default_value) {
  std::string value;
  const char* env_var = getenv(env_var_name);
  if (env_var)
    value = env_var;

  if (value.empty())
    value = default_value;

  return value;
}

std::string GetPeerConnectionString() {
  //return GetEnvVarOrDefault("WEBRTC_CONNECT", "stun:stun.l.google.com:19302");
  return GetEnvVarOrDefault("WEBRTC_CONNECT", "stun:stun3.l.google.com:19302");
}

bool Natty::InitializePeerConnection() {

  IceServers servers;
  IceServer server;

  ASSERT(peer_connection_factory_.get() == NULL);
  ASSERT(peer_connection_.get() == NULL);

  peer_connection_factory_  = webrtc::CreatePeerConnectionFactory();

  if (!peer_connection_factory_.get()) {
    printf("Failed to initialize peer connection factory\n");
    DeletePeerConnection();
    return false;
  }
  printf("Created peer connection factory\n");

  server.uri = GetPeerConnectionString();
  servers.push_back(server);

  peer_connection_ = peer_connection_factory_->CreatePeerConnection(servers, NULL, NULL, this);
  if (!peer_connection_.get()) {
    printf("create peer connection failed\n");
    DeletePeerConnection();
  }
  const webrtc::SessionDescriptionInterface* session = peer_connection_->local_description();

  printf("successfully created peer connection\n");
  /* create offer */
  peer_connection_->CreateOffer(this, NULL);
  return peer_connection_.get() != NULL;
}

void Natty::DeletePeerConnection() {
  printf("Deleting peer connection\n");
  peer_connection_ = NULL;
  peer_connection_factory_ = NULL;
  peer_id_ = -1;
  Natty::Shutdown();
}

//
// PeerConnectionObserver implementation.
//

void Natty::OnError() {
  LOG(LS_ERROR) << __FUNCTION__;
}

void Natty::OnAddStream(webrtc::MediaStreamInterface* stream) {

}

void Natty::OnRemoveStream(webrtc::MediaStreamInterface* stream) {
  LOG(INFO) << __FUNCTION__ << " " << stream->label();
  stream->AddRef();
}

void Natty::ShowCandidate(const webrtc::IceCandidateInterface* candidate) {
  std::string out;
  const cricket::Candidate& cand = candidate->candidate();
  const talk_base::SocketAddress & address = cand.address();
  candidate->ToString(&out);

  printf("Ice Candidate %s", out.c_str());
  printf("%s\n", cand.ToString().c_str());
  printf("%s\n", address.ToString().c_str());

}

void Natty::OnIceCandidate(const webrtc::IceCandidateInterface* candidate) {
  LOG(INFO) << __FUNCTION__ << " " << candidate->sdp_mline_index();
  Json::StyledWriter writer;
  Json::Value jmessage;

  jmessage[kCandidateSdpMidName] = candidate->sdp_mid();
  jmessage[kCandidateSdpMlineIndexName] = candidate->sdp_mline_index();
  std::string sdp;
  if (!candidate->ToString(&sdp)) {
    LOG(LS_ERROR) << "Failed to serialize candidate";
    return;
  }
  jmessage[kCandidateSdpName] = sdp;
  SendMessage(writer.write(jmessage));

  ShowCandidate(candidate);
}

void Natty::OnRenegotiationNeeded() {
  printf("Renegotiation neeced\n");
  peer_connection_->CreateOffer(this, NULL);

}

//
// PeerConnectionClientObserver implementation.
//

void Natty::OnSignedIn() {
  printf("Successfully connected to signaling server\n");

}

void Natty::OnDisconnected() {

  DeletePeerConnection();

}

void Natty::OnPeerConnected(int id, const std::string& name) {
  printf("Another peer connected! %d %s\n", id, name.c_str());
  //peer_connection_->CreateOffer(this, NULL);
  ConnectToPeer(id);
  //client_->SendToPeer(id, "hello there");

}

void Natty::OnPeerDisconnected(int id) {
  if (id == peer_id_) {
    //DEBUG("Our peer is gone.\n");
  }
}

void Natty::OnMessageFromPeer(int peer_id, const std::string& message) {
  Json::Reader reader;
  Json::Value jmessage;

  ASSERT(peer_id_ == peer_id || peer_id_ == -1);
  ASSERT(!message.empty());
  printf("Got message from peer; id: %d message: %s\n", peer_id, message.c_str());

  if (!peer_connection_.get()) {
    ASSERT(peer_id_ == -1);
    peer_id_ = peer_id;

    if (!InitializePeerConnection()) {
      printf("Failed to initialize our PeerConnection instance");
      client_->SignOut();
      return;
    }
  } else if (peer_id != peer_id_) {
    ASSERT(peer_id_ != -1);
    printf("Received message from an unknown peer\n");
    return;
  }

  if (!reader.parse(message, jmessage)) {
    printf("Received an unknown message.\n");
    return;
  }
  std::string type;
  std::string json_object;

  GetStringFromJsonObject(jmessage, kSessionDescriptionTypeName, &type);
  if (!type.empty()) {
    std::string sdp;
    if (!GetStringFromJsonObject(jmessage, kSessionDescriptionSdpName, &sdp)) {
      LOG(WARNING) << "Can't parse received session description message.";
      return;
    }
    webrtc::SessionDescriptionInterface* session_description(
        webrtc::CreateSessionDescription(type, sdp));
    if (!session_description) {
      LOG(WARNING) << "Can't parse received session description message.";
      return;
    }
    LOG(INFO) << " Received session description :" << message;
    peer_connection_->SetRemoteDescription(
        DummySetSessionDescriptionObserver::Create(), session_description);
    if (session_description->type() ==
        webrtc::SessionDescriptionInterface::kOffer) {
      peer_connection_->CreateAnswer(this, NULL);
    }
    return;
  } else {
    std::string sdp_mid;
    int sdp_mlineindex = 0;
    std::string sdp;
    if (!GetStringFromJsonObject(jmessage, kCandidateSdpMidName, &sdp_mid) ||
        !GetIntFromJsonObject(jmessage, kCandidateSdpMlineIndexName,
                              &sdp_mlineindex) ||
        !GetStringFromJsonObject(jmessage, kCandidateSdpName, &sdp)) {
      printf("Can't parse received message.\n");
      return;
    }
    talk_base::scoped_ptr<webrtc::IceCandidateInterface> candidate(
        webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, sdp));
    printf("Remote candidate information\n");
    Natty::ShowCandidate(candidate.get());
    if (!candidate.get()) {
      LOG(WARNING) << "Can't parse received candidate message.";
      return;
    }
    if (!peer_connection_->AddIceCandidate(candidate.get())) {
      LOG(WARNING) << "Failed to apply the received candidate";
      return;
    }
    LOG(INFO) << " Received candidate :" << message;
    return;
  }
}

void Natty::OnMessageSent(int err) {

}

// PeerConnectionObserver implementation.
void Natty::OnServerConnectionFailure() {

}

std::string GetPeerName() {
  char computer_name[256];
  if (gethostname(computer_name, ARRAY_SIZE(computer_name)) != 0)
    strcpy(computer_name, "host");
  std::string ret(GetEnvVarOrDefault("USERNAME", "user"));
  ret += '@';
  ret += computer_name;
  return ret;
}

void Natty::Init(const std::string& server, int port) {
  if (client_->is_connected())
    return;
  server_ = server;
  client_->Connect(server, port, GetPeerName());
}

void Natty::OnSuccess(webrtc::SessionDescriptionInterface* desc) {
  printf("setting local description\n");
  peer_connection_->SetLocalDescription(
      DummySetSessionDescriptionObserver::Create(), desc);
  Json::StyledWriter writer;
  Json::Value jmessage;
  jmessage[kSessionDescriptionTypeName] = desc->type();
  std::string sdp;
  desc->ToString(&sdp);
  jmessage[kSessionDescriptionSdpName] = sdp;
  printf("Sending my sdp info %s\n", sdp.c_str());
  SendMessage(writer.write(jmessage));
}

void Natty::OnFailure(const std::string& error) {
    LOG(LERROR) << error;
}

void Natty::SendMessage(const std::string& json_object) {
  std::string* msg = new std::string(json_object);
  if (msg) {
    printf("Message is %s\n", msg->c_str());
    pending_messages_.push_back(msg);
    if (!pending_messages_.empty() && !client_->IsSendingMessage()) {
      msg = pending_messages_.front();
      pending_messages_.pop_front();

      if (!client_->SendToPeer(peer_id_, *msg) && peer_id_ != -1) {
        printf("Sending message to peer failed\n");
        DisconnectFromServer();
      }
      delete msg;
    }

    if (!peer_connection_.get())
      peer_id_ = -1;
  }
}

void Natty::DisconnectFromServer() {
  if (client_->is_connected())
    client_->SignOut();
}

<commit_msg>make sure we disconnect cleanly from server<commit_after> /**
 * Copyright (C) 2014 Lantern
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "natty.h"

#include <utility>

#include "talk/app/webrtc/videosourceinterface.h"
#include "talk/base/common.h"
#include "talk/base/json.h"
#include "talk/base/logging.h"
#include "talk/media/devices/devicemanager.h"

#define DEBUG(fmt, ...) printf("%s:%d: " fmt, __FILE__, __LINE__, __VA_ARGS__);

  // Names used for a IceCandidate JSON object.
  const char kCandidateSdpMidName[] = "sdpMid";
  const char kCandidateSdpMlineIndexName[] = "sdpMLineIndex";
  const char kCandidateSdpName[] = "candidate";

  typedef webrtc::PeerConnectionInterface::IceServers IceServers;
  typedef webrtc::PeerConnectionInterface::IceServer IceServer;;

  // Names used for a SessionDescription JSON object.
  const char kSessionDescriptionTypeName[] = "type";
  const char kSessionDescriptionSdpName[] = "sdp";

  class DummySetSessionDescriptionObserver
      : public webrtc::SetSessionDescriptionObserver {
   public:
    static DummySetSessionDescriptionObserver* Create() {
      return
          new talk_base::RefCountedObject<DummySetSessionDescriptionObserver>();
    }
    virtual void OnSuccess() {
      LOG(INFO) << __FUNCTION__;
    }
    virtual void OnFailure(const std::string& error) {
      LOG(INFO) << __FUNCTION__ << " " << error;
    }

   protected:
    DummySetSessionDescriptionObserver() {}
    ~DummySetSessionDescriptionObserver() {}
  };

  Natty::Natty(PeerConnectionClient* client, talk_base::Thread* thread)
    : peer_id_(-1),
      thread(talk_base::Thread::Current()),
      client_(client) {
    client_->RegisterObserver(this);
  }

  Natty::~Natty() {
    ASSERT(peer_connection_.get() == NULL);
  }

  bool Natty::connection_active() const {
    return peer_connection_.get() != NULL;
  }

  PeerConnectionClient* Natty::GetClient() {
    return client_;
  }

  void Natty::SetupSocketServer() {
    talk_base::InitializeSSL();
    Init("107.170.244.214", 8888);
    //Init("127.0.0.1", 8888);
    //InitializePeerConnection();
  }

  void Natty::Shutdown() {
    talk_base::CleanupSSL();
    thread->Quit();
    thread->set_socketserver(NULL);
  }

void Natty::ConnectToPeer(int peer_id) {
  printf("Trying to connect to peer %d\n", peer_id);
  ASSERT(peer_id_ == -1);
  ASSERT(peer_id != -1);

  if (InitializePeerConnection()) {
    peer_id_ = peer_id;
    peer_connection_->CreateOffer(this, NULL);
  }
}

std::string GetEnvVarOrDefault(const char* env_var_name,
    const char* default_value) {
  std::string value;
  const char* env_var = getenv(env_var_name);
  if (env_var)
    value = env_var;

  if (value.empty())
    value = default_value;

  return value;
}

std::string GetPeerConnectionString() {
  //return GetEnvVarOrDefault("WEBRTC_CONNECT", "stun:stun.l.google.com:19302");
  return GetEnvVarOrDefault("WEBRTC_CONNECT", "stun:stun3.l.google.com:19302");
}

bool Natty::InitializePeerConnection() {

  IceServers servers;
  IceServer server;

  ASSERT(peer_connection_factory_.get() == NULL);
  ASSERT(peer_connection_.get() == NULL);

  peer_connection_factory_  = webrtc::CreatePeerConnectionFactory();

  if (!peer_connection_factory_.get()) {
    printf("Failed to initialize peer connection factory\n");
    DeletePeerConnection();
    return false;
  }
  printf("Created peer connection factory\n");

  server.uri = GetPeerConnectionString();
  servers.push_back(server);

  peer_connection_ = peer_connection_factory_->CreatePeerConnection(servers, NULL, NULL, this);
  if (!peer_connection_.get()) {
    printf("create peer connection failed\n");
    DeletePeerConnection();
  }
  const webrtc::SessionDescriptionInterface* session = peer_connection_->local_description();

  printf("successfully created peer connection\n");
  /* create offer */
  peer_connection_->CreateOffer(this, NULL);
  return peer_connection_.get() != NULL;
}

void Natty::DeletePeerConnection() {
  printf("Deleting peer connection\n");
  DisconnectFromServer();
  peer_connection_ = NULL;
  peer_connection_factory_ = NULL;
  peer_id_ = -1;
  Natty::Shutdown();
}

//
// PeerConnectionObserver implementation.
//

void Natty::OnError() {
  LOG(LS_ERROR) << __FUNCTION__;
}

void Natty::OnAddStream(webrtc::MediaStreamInterface* stream) {

}

void Natty::OnRemoveStream(webrtc::MediaStreamInterface* stream) {
  LOG(INFO) << __FUNCTION__ << " " << stream->label();
  stream->AddRef();
}

void Natty::ShowCandidate(const webrtc::IceCandidateInterface* candidate) {
  std::string out;
  const cricket::Candidate& cand = candidate->candidate();
  const talk_base::SocketAddress & address = cand.address();
  candidate->ToString(&out);

  printf("Ice Candidate %s", out.c_str());
  printf("%s\n", cand.ToString().c_str());
  printf("%s\n", address.ToString().c_str());

}

void Natty::OnIceCandidate(const webrtc::IceCandidateInterface* candidate) {
  LOG(INFO) << __FUNCTION__ << " " << candidate->sdp_mline_index();
  Json::StyledWriter writer;
  Json::Value jmessage;

  jmessage[kCandidateSdpMidName] = candidate->sdp_mid();
  jmessage[kCandidateSdpMlineIndexName] = candidate->sdp_mline_index();
  std::string sdp;
  if (!candidate->ToString(&sdp)) {
    LOG(LS_ERROR) << "Failed to serialize candidate";
    return;
  }
  jmessage[kCandidateSdpName] = sdp;
  SendMessage(writer.write(jmessage));

  ShowCandidate(candidate);
}

void Natty::OnRenegotiationNeeded() {
  printf("Renegotiation neeced\n");
  peer_connection_->CreateOffer(this, NULL);

}

//
// PeerConnectionClientObserver implementation.
//

void Natty::OnSignedIn() {
  printf("Successfully connected to signaling server\n");

}

void Natty::OnDisconnected() {

  DeletePeerConnection();

}

void Natty::OnPeerConnected(int id, const std::string& name) {
  printf("Another peer connected! %d %s\n", id, name.c_str());
  //peer_connection_->CreateOffer(this, NULL);
  ConnectToPeer(id);
  //client_->SendToPeer(id, "hello there");

}

void Natty::OnPeerDisconnected(int id) {
  if (id == peer_id_) {
    //DEBUG("Our peer is gone.\n");
  }
}

void Natty::OnMessageFromPeer(int peer_id, const std::string& message) {
  Json::Reader reader;
  Json::Value jmessage;

  ASSERT(peer_id_ == peer_id || peer_id_ == -1);
  ASSERT(!message.empty());
  printf("Got message from peer; id: %d message: %s\n", peer_id, message.c_str());

  if (!peer_connection_.get()) {
    ASSERT(peer_id_ == -1);
    peer_id_ = peer_id;

    if (!InitializePeerConnection()) {
      printf("Failed to initialize our PeerConnection instance");
      client_->SignOut();
      return;
    }
  } else if (peer_id != peer_id_) {
    ASSERT(peer_id_ != -1);
    printf("Received message from an unknown peer\n");
    return;
  }

  if (!reader.parse(message, jmessage)) {
    printf("Received an unknown message.\n");
    return;
  }
  std::string type;
  std::string json_object;

  GetStringFromJsonObject(jmessage, kSessionDescriptionTypeName, &type);
  if (!type.empty()) {
    std::string sdp;
    if (!GetStringFromJsonObject(jmessage, kSessionDescriptionSdpName, &sdp)) {
      LOG(WARNING) << "Can't parse received session description message.";
      return;
    }
    webrtc::SessionDescriptionInterface* session_description(
        webrtc::CreateSessionDescription(type, sdp));
    if (!session_description) {
      LOG(WARNING) << "Can't parse received session description message.";
      return;
    }
    printf("Received session description; sending answer back\n");
    peer_connection_->SetRemoteDescription(
        DummySetSessionDescriptionObserver::Create(), session_description);
    if (session_description->type() ==
        webrtc::SessionDescriptionInterface::kOffer) {
      peer_connection_->CreateAnswer(this, NULL);
    }
    return;
  } else {
    std::string sdp_mid;
    int sdp_mlineindex = 0;
    std::string sdp;
    if (!GetStringFromJsonObject(jmessage, kCandidateSdpMidName, &sdp_mid) ||
        !GetIntFromJsonObject(jmessage, kCandidateSdpMlineIndexName,
                              &sdp_mlineindex) ||
        !GetStringFromJsonObject(jmessage, kCandidateSdpName, &sdp)) {
      printf("Can't parse received message.\n");
      return;
    }
    talk_base::scoped_ptr<webrtc::IceCandidateInterface> candidate(
        webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, sdp));
    printf("Remote candidate information\n");
    Natty::ShowCandidate(candidate.get());
    if (!candidate.get()) {
      LOG(WARNING) << "Can't parse received candidate message.";
      return;
    }
    if (!peer_connection_->AddIceCandidate(candidate.get())) {
      LOG(WARNING) << "Failed to apply the received candidate";
      return;
    }
    LOG(INFO) << " Received candidate :" << message;
    return;
  }
}

void Natty::OnMessageSent(int err) {

}

// PeerConnectionObserver implementation.
void Natty::OnServerConnectionFailure() {

}

std::string GetPeerName() {
  char computer_name[256];
  if (gethostname(computer_name, ARRAY_SIZE(computer_name)) != 0)
    strcpy(computer_name, "host");
  std::string ret(GetEnvVarOrDefault("USERNAME", "user"));
  ret += '@';
  ret += computer_name;
  return ret;
}

void Natty::Init(const std::string& server, int port) {
  if (client_->is_connected())
    return;
  server_ = server;
  client_->Connect(server, port, GetPeerName());
}

void Natty::OnSuccess(webrtc::SessionDescriptionInterface* desc) {
  printf("setting local description\n");
  peer_connection_->SetLocalDescription(
      DummySetSessionDescriptionObserver::Create(), desc);
  Json::StyledWriter writer;
  Json::Value jmessage;
  jmessage[kSessionDescriptionTypeName] = desc->type();
  std::string sdp;
  desc->ToString(&sdp);
  jmessage[kSessionDescriptionSdpName] = sdp;
  printf("Sending my sdp info %s\n", sdp.c_str());
  SendMessage(writer.write(jmessage));
}

void Natty::OnFailure(const std::string& error) {
    LOG(LERROR) << error;
}

void Natty::SendMessage(const std::string& json_object) {
  std::string* msg = new std::string(json_object);
  if (msg) {
    printf("Message is %s\n", msg->c_str());
    pending_messages_.push_back(msg);
    if (!pending_messages_.empty() && !client_->IsSendingMessage()) {
      msg = pending_messages_.front();
      pending_messages_.pop_front();

      if (!client_->SendToPeer(peer_id_, *msg) && peer_id_ != -1) {
        printf("Sending message to peer failed\n");
        DisconnectFromServer();
      }
      delete msg;
    }

    if (!peer_connection_.get())
      peer_id_ = -1;
  }
}

void Natty::DisconnectFromServer() {
  if (client_->is_connected())
    client_->SignOut();
}

<|endoftext|>