#include <avr/sleep.h>
#include <TinyWireM.h>
#include "MB85RC16.h"

#define FRAMsize 2048

PROGMEM prog_uint32_t crc_table[16] = {
  0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
  0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
  0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
  0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};

void setup() {
  TinyWireM.begin();
}

void loop() {
  // w8 for start
  delay(4000);

  trialPatch();         // 2160min. trial time
  bandwidthPatch(0, 4); // channel 0, 250Mhz
  bandwidthPatch(1, 4); // channel 1, 250Mhz
//  timeBase2nsPatch();   // 2ns time base
  timeBase1nsPatch();   // 1ns time base
  restoreCrc();         // fix CRC32

  for(;;) {
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();
    sleep_cpu();
  }
}

void bandwidthPatch(uint8_t channel, uint8_t bandwidth) {
  // bandwith 0=20Mhz, 1=OFF, 2=100Mhz, 3=200Mhz, 4=250Mhz

  if (channel > 1 || bandwidth > 4) return;
  if (channel == 0) setAddress(0x90);
  else setAddress(0xCC);
  TinyWireM.send(bandwidth);
  TinyWireM.endTransmission();  
}

void timeBase2nsPatch() {
  setAddress(0x4A);
  TinyWireM.send(0x02);
  TinyWireM.send(0x00);
  TinyWireM.endTransmission();  
  setAddress(0x56);
  TinyWireM.send(0x01);
  TinyWireM.send(0x00);
  TinyWireM.endTransmission();  
  setAddress(0x5A);
  TinyWireM.send(0xD0);
  TinyWireM.send(0x07);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.endTransmission();  
  setAddress(0x62);
  TinyWireM.send(0xE8);
  TinyWireM.send(0x03);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.endTransmission();  
} 

void timeBase1nsPatch() {
  setAddress(0x4A);
  TinyWireM.send(0x01);
  TinyWireM.send(0x00);
  TinyWireM.endTransmission();  
  setAddress(0x56);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.endTransmission();  
  setAddress(0x5A);
  TinyWireM.send(0xE8);
  TinyWireM.send(0x03);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.endTransmission();  
  setAddress(0x62);
  TinyWireM.send(0xF4);
  TinyWireM.send(0x01);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.endTransmission();  
} 

void trialPatch() {
  setAddress(0x7F6);
  TinyWireM.send(0x49);
  TinyWireM.send(0x0A);
  TinyWireM.send(0x00);
  TinyWireM.send(0x00);
  TinyWireM.endTransmission();  
} 

uint32_t crcUpdate(uint32_t crc, uint8_t data) {
  uint8_t tbl_idx;

  tbl_idx = crc ^ (data >> (0 * 4));
  crc = pgm_read_dword_near(crc_table + (tbl_idx & 0x0f)) ^ (crc >> 4);
  tbl_idx = crc ^ (data >> (1 * 4));
  crc = pgm_read_dword_near(crc_table + (tbl_idx & 0x0f)) ^ (crc >> 4);
  return crc;
}

void restoreCrc() {
  const uint16_t crcEnd = FRAMsize-10; 
  union uni{
    uint32_t crc;
    uint8_t b[4];
  } u;
  uint16_t i = 0;

  u.crc = 0xFFFFFFFF;
  do {
    readBytes(i, 8);
    while (TinyWireM.available() && i<crcEnd) {
      u.crc = crcUpdate(u.crc, TinyWireM.receive());
      i++;
    }
  } 
  while (i<crcEnd);
  u.crc = ~u.crc;

  // clear Buffer
  while (TinyWireM.available()) TinyWireM.receive();  

  // write crc32
  setAddress(0x7FC);
  TinyWireM.send(u.b[0]);
  TinyWireM.send(u.b[1]);
  TinyWireM.send(u.b[2]);
  TinyWireM.send(u.b[3]);
  TinyWireM.endTransmission();    
}


