
/*** header section ***/
/* general */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

/* player */
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/cdrom.h>
#define MONITOR_MAX 6

/** vars section **/
char command, volume, prev_volume;
const int stat_play  = 2;
const int stat_pause = 1;
const int stat_stop  = 0;
int status;

const char *cd_device = "/dev/cdrom";
const char *io_device = "/dev/mylp0";

const int play_track = 2;
int cd_fd, io_fd;
struct cdrom_ti ti;                 /* track/index info */
struct cdrom_volctrl volctrl;       /* volume settings */
time_t all_time, current_time, start_time;
int led_status, led_count;

/*** I/O section ***/
void io_init(void){
  io_fd = open(io_device, O_RDWR);
}

void io_get(void){
  char str[3];
  read(io_fd, str, 3);
  command = str[0];
  prev_volume = volume;
  volume = str[1];
}


void io_set(void){
  char c;
  time_t new_time;
  time(&new_time);
  if(status == stat_stop){
    if(led_count++ > 2){
      led_status++;
      led_count = 0;
    }
    start_time = current_time = 0;
    if(led_status == MONITOR_MAX * 2) led_status = 0;
    if(led_status < MONITOR_MAX){
      c = 1 << (led_status);
    } else {
      c = (1 << (MONITOR_MAX * 2 - led_status - 1));
    }
  } else {
    int bright;
    if(new_time - start_time >= all_time){
      status = stat_stop;
    }
    if(led_count++ > 2){
      led_status++;
      led_count = 0;
    }
    if(status == stat_pause){
      start_time += (new_time - current_time);
    }
    bright = MONITOR_MAX * (new_time - start_time) / all_time;
    c = 1 << (bright + (led_status %2));
    c--;
  }
  current_time = new_time;
  write(io_fd, &c, 1);
}


/*** Player section ***/
void cd_init(void){
  int temp;
  struct cdrom_tocentry tocentry;     /* TOC entry */
  cd_fd = open(cd_device, O_RDONLY);
  tocentry.cdte_track = play_track;
  tocentry.cdte_format = CDROM_MSF;
  ioctl(cd_fd, CDROMREADTOCENTRY, &tocentry);
  all_time = - tocentry.cdte_addr.msf.minute * 60 + tocentry.cdte_addr.msf.second;

  tocentry.cdte_track = play_track + 1;
  tocentry.cdte_format = CDROM_MSF;
  ioctl(cd_fd, CDROMREADTOCENTRY, &tocentry);
  all_time += tocentry.cdte_addr.msf.minute * 60 + tocentry.cdte_addr.msf.second;
}

void cd_time_init(void){  
  time(&start_time);
  current_time = start_time;
  led_status = 0;
  led_count = 0;
}

void cd_finalize(void){
  close(cd_fd);
}

int cd_play(void){
  ti.cdti_trk0 = play_track;
  ti.cdti_ind0 = 0;
  ti.cdti_trk1 = play_track;
  ti.cdti_ind1 = 0;
  return ioctl(cd_fd, CDROMPLAYTRKIND, &ti);
}

int cd_stop(void){
  return ioctl(cd_fd, CDROMSTOP);
}

int cd_pause(void){
  return ioctl(cd_fd, CDROMPAUSE);
}

int cd_resume(void){
  return ioctl(cd_fd, CDROMRESUME);
}

int cd_volume(void){
  volctrl.channel0 = volume + 128;
  volctrl.channel1 = volume + 128;
  volctrl.channel2 = 0;
  volctrl.channel3 = 0;
  return ioctl(cd_fd, CDROMVOLCTRL, &volctrl);
}

int main(){
  int i;
  status = stat_stop;
  io_init();
  cd_init();
  for(i = 0; ; i++){
    io_get();
    if(i % 10 == 0){
      printf("[status = %d, volume = %d]\n", status, volume);
    }
    if(status == stat_stop && command == stat_play){
      cd_time_init();
      cd_play();
    } else if(status == stat_play && command == stat_pause){
      cd_pause();
    } else if(status == stat_pause && command == stat_play){
      cd_resume();
    } else if(command == stat_stop){
      cd_stop();
    }
    if(prev_volume != volume){
      cd_volume();
    }
    status = command;
    io_set();
    usleep(10 * 1000);
  }
}
