
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <time.h>
#include <sys/time.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <string>

static const char *device = "/dev/spidev0.0";

static void spi_write(int fd, unsigned char c)
{
	int ret;
	unsigned char rx[1];
	struct spi_ioc_transfer tr;
	tr.tx_buf = (unsigned long)&c;
	tr.rx_buf = (unsigned long)rx;
	tr.len = 1;
	tr.delay_usecs = 0;
	tr.speed_hz = 100000;
	tr.bits_per_word = 8;

	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	if (ret < 0) throw std::string("can't send data");
}

unsigned long convert_ymd_to_cjd(int year, int month, int day)
{
	if (month < 3) {
		month += 9;
		year--;
	} else {
		month -= 3;
	}
	year += 4800;
	int c = year / 100;
	return c * 146097 / 4 + (year - c * 100) * 1461 / 4 + (153 * month + 2) / 5 + day - 32045;
}

void convert_cjd_to_ymd(unsigned long j, int *year, int *month, int *day)
{
	int y, m, d;
	y = (j * 4 + 128179) / 146097;
	d = (j * 4 - y * 146097 + 128179) / 4 * 4 + 3;
	j = d / 1461;
	d = (d - j * 1461) / 4 * 5 + 2;
	m = d / 153;
	d = (d - m * 153) / 5 + 1;
	y = (y - 48) * 100 + j;
	if (m < 10) {
		m += 3;
	} else {
		m -= 9;
		y++;
	}
	*year = y;
	*month = m;
	*day = d;
}



int main(int argc, char *argv[])
{
	int ret = 0;
	int fd = -1;

	tzset();

	try {

		unsigned char mode = 0;
		unsigned char bits = 8;
		unsigned long speed = 100000;
		uint16_t delay;

		fd = open(device, O_RDWR);
		if (fd == -1) throw std::string("can't open device");

		ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
		if (ret == -1) throw std::string("can't set spi mode");

		ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
		if (ret == -1) throw std::string("can't get spi mode");

		ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
		if (ret == -1) throw std::string("can't set bits per word");

		ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
		if (ret == -1) throw std::string("can't get bits per word");

		ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
		if (ret == -1) throw std::string("can't set max speed hz");

		ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
		if (ret == -1) throw std::string("can't get max speed hz");

#if 0
		spi_write(fd, 0xd0);
		spi_write(fd, 0xc1);
		spi_write(fd, 0xb2);
		spi_write(fd, 0xa3);
		spi_write(fd, 0x94);
		spi_write(fd, 0x85);
		spi_write(fd, 0x76);
		spi_write(fd, 0x67);
		spi_write(fd, 0x50);
		spi_write(fd, 0x41);
		spi_write(fd, 0x32);
		spi_write(fd, 0x23);
		spi_write(fd, 0x14);
		spi_write(fd, 0x05);
#else
	while (1) {
		struct timeval tv;
		struct timezone tz;
		gettimeofday(&tv, &tz);
		unsigned long t = convert_ymd_to_cjd(1970, 1, 1);

//		unsigned long sec = tv.tv_sec - tz.tz_minuteswest * 60;
		unsigned long sec = tv.tv_sec - timezone;

		if (tv.tv_usec > 0 && tv.tv_usec < 1000000) {
			int w = 1000000 - tv.tv_usec;
			usleep(w);
			sec++;
		}

		unsigned long cjd = sec / (24 * 60 * 60) + 2440588;
		int year, month, day, hour, minute, second;
		convert_cjd_to_ymd(cjd, &year, &month, &day);
		hour = sec / (60 * 60) % 24;
		minute = sec / 60 % 60;
		second = sec % 60;
//		printf("%04u-%02u-%02u %02u:%02u:%02u\n", year, month, day, hour, minute, second);

		spi_write(fd, 0xd0 + year / 1000 % 10);
		spi_write(fd, 0xc0 + year / 100 % 10);
		spi_write(fd, 0xb0 + year / 10 % 10);
		spi_write(fd, 0xa0 + year % 10);
		spi_write(fd, 0x90 + month / 10 % 10);
		spi_write(fd, 0x80 + month % 10);
		spi_write(fd, 0x70 + day / 10 % 10);
		spi_write(fd, 0x60 + day % 10);
		spi_write(fd, 0x50 + hour / 10 % 10);
		spi_write(fd, 0x40 + hour % 10);
		spi_write(fd, 0x30 + minute / 10 % 10);
		spi_write(fd, 0x20 + minute % 10);
		spi_write(fd, 0x10 + second / 10 % 10);
		spi_write(fd, 0x00 + second % 10);
	}
#endif

		close(fd);
	} catch (std::string const &e) {
		if (fd >= 0) {
			close(fd);
		}
		puts(e.c_str());
	}

	return ret;
}
