/*  
Use ALSA and soundcard to sample a signal from a signal source and save  it with as .raw file
 * */

// compile with :  gcc -o fskmod fskmod.c -lasound -lrt -lm -ldl 
// run with : ./fskmod plughw:1,0

/*********************************************************************/
// hw:1,0 accesses the hardware device directly.
// plughw:1,0 inserts sample rate and format conversion plugins, if needed.
/* *******************************************************************/

#include <stdio.h> 
#include <stdlib.h>
#include <string.h> 
#include <alsa/asoundlib.h> 
#include <unistd.h> 
#include <math.h> 
#include <time.h> 


///////////////////////PROTOTYPE FUNCTION/////////////////////////////


int main(int argc, char *argv[]) {
   
  int i,j;
  int err;
  int16_t *buffer; // buffer integer 16bits
  int rtime= 120;
  int buffer_frames_12 = (rtime*12000.); // alokasi buffer sampling 12 KHz
  unsigned int rate = 12000;// sampling rate
  char* devcID;// Sound Card ID
  snd_pcm_t *playback_handle;
  snd_pcm_hw_params_t *hw_params;
  snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; 
  clock_t t0;
  float tdecimasi=0.0;
  unsigned int min,max;
  char namafile[30];


  // frame mono 1327200 == 110,6 detik sampling 12000
  // frekuensi 1500 Hz
  // 1 blok = 0,6827 detik
  // 1 blok = 8192 sampel 

  // 162 blok = 162 x 0,6827 = 110,6 detik

  devcID = malloc(sizeof(char) * 50); 
  if (argc > 1){
    devcID = argv[1];
   
  }
  else {
    devcID = "plughw:1,0"; //default soundcard
  }


  /********Membuka peranti dalam mode playback*************/

  if ((err = snd_pcm_open(&playback_handle, devcID, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
    fprintf(stderr, "tidak dapat membuka perangkat %s (%s)\n",devcID,snd_strerror(err));
    exit(1);
  } else {fprintf(stdout, "perangkat berhasil dibuka\n");}

  /**************Penambahan struktur parameter********************/

  if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) {
    fprintf(stderr, "mustahil untuk menambahkan parameter (%s)\n",
	    snd_strerror(err));
    exit(1);
  }   else { fprintf(stdout, "parameter tambahkan\n"); }
  if ((err = snd_pcm_hw_params_any(playback_handle, hw_params)) < 0) {
    fprintf(stderr, "tidak dapat menginisialisasi parameter (%s)\n",
	    snd_strerror(err));
    exit(1);
  }   else { fprintf(stdout, "parameter diinisialisasi\n"); }


  /*******************Konfigurasi tipe akses ****************************/

  if ((err = snd_pcm_hw_params_set_access(playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
    fprintf(stderr, "tidak dapat mengonfigurasi jenis akses (%s)\n",
	    snd_strerror(err));
    exit(1);
  }   else { fprintf(stdout, "jenis konfigurasi akses!\n"); }

  /********************************Format data****************************/

  if ((err = snd_pcm_hw_params_set_format(playback_handle, hw_params, format)) < 0) {
    fprintf(stderr, "tidak dapat mengatur format (%s)\n",
	    snd_strerror(err));
    exit(1);
  }   else { fprintf(stdout, "format standar\n"); }

  /********************Mengatur frekuensi pengambilan sampel*************/

  //  if ((err = snd_pcm_hw_params_set_rate_near(playback_handle, hw_params, &rate, 0)) < 0) {

  if ((err = snd_pcm_hw_params_set_rate_near(playback_handle, hw_params, &rate, 0)) < 0) {
    fprintf(stderr, "tidak mungkin untuk mengatur frekuensi sampling (%s)\n",
	    snd_strerror(err));
    exit(1);
  }   else { fprintf(stdout, "frekuensi sampling sesuai seting: %d (Hz)\n",rate); }

  /********************Setel jumlah saluran (Mono atau stereo)***************/

  err = snd_pcm_hw_params_get_channels_min(hw_params, &min);
  if (err < 0) {
    fprintf(stderr, "cannot get minimum channels count: %s\n",
	    snd_strerror(err));
    snd_pcm_close(playback_handle);
    return 1;
  }
  err = snd_pcm_hw_params_get_channels_max(hw_params, &max);
  if (err < 0) {
    fprintf(stderr, "cannot get maximum channels count: %s\n",
	    snd_strerror(err));
    snd_pcm_close(playback_handle);
    return 1;
  }
  //  printf("Channels:");
  //  for (i = min; i <= max; ++i) {
  //    if (!snd_pcm_hw_params_test_channels(playback_handle, hw_params, i))
      //      printf(" %u ", i);
  //  }


  //  if ((err = snd_pcm_hw_params_set_channels(playback_handle, hw_params, min)) < 0) {

  if ((err = snd_pcm_hw_params_set_channels(playback_handle, hw_params, min)) < 0) {
    fprintf(stderr, "tidak mungkin untuk mengatur jumlah saluran (%s)\n",
	    snd_strerror(err));
    exit(1);
  }   else { fprintf(stdout, "jumlah saluran diset: %d ",min); }

  unsigned int tmp;
  snd_pcm_hw_params_get_channels(hw_params, &tmp);
  printf("(hasil: %i)\n", tmp);

  /////////////////////////////////////////////////////////////////////////

  if ((err = snd_pcm_hw_params(playback_handle, hw_params)) < 0) {
    fprintf(stderr, "mustahil untuk menerapkan parameter (%s)\n",
	    snd_strerror(err));
    exit(1);
  }   else {
    fprintf(stdout, "\nPenerapan parameter...\n");
  }

  //  snd_pcm_hw_params_free(hw_params);// membersihkan struktur parameter
  //  fprintf(stdout, "parameter dihapus\n"); 

  /************Persiapan sound card untuk playback***************************/

  if ((err = snd_pcm_prepare(playback_handle)) < 0) {
    fprintf(stderr, "mustahil untuk menyiapkan kartu untuk registrasi (%s)\n",
	    snd_strerror(err));
    exit(1);
  }   else { fprintf(stdout, "siap playback... \n"); }
   
  buffer = malloc(buffer_frames_12 * snd_pcm_format_width(format));
  fprintf(stdout, "memori sudah dialokasikan!!\n");

  float  panjang=1327200./12000;
  printf("\npanjang= %f\n",panjang);
  //  for(k=0;k<1327200;k++){
  //        buffer[k]=(int16_t)(8000.*sin(2.*pi*(1500./12000.)*(double)k));
  //  }

  int ii;
  double twopidt, df, dphi, phase[162], duaphi=2.*3.14159265, f0=1500.;
  twopidt=duaphi/12000.;
  df=375.0/256.0;
  //  dt=1/375.0;
  //  idelay=t0/dt;
    
  FILE *f;
  int symbols[162];
  f=fopen("./simbol.txt","r");
  if(f==NULL){
    printf("\nfile error...\n");
    exit(1);
  }
    for (i=0; i<162; i++) {
      if((fscanf(f, "%d ", &symbols[i]))==0)exit(-1);
    }
    fclose(f);
    
    for (i=0; i<162; i++) {
      //      fsk4= (((double)symbols[i]-df)*df);
      dphi=twopidt*(f0 + ( (double)symbols[i]-df)*df );
      //            printf("simbol= %d --> dphi= %f; --> fsk4= %f \n", symbols[i],dphi,fsk4);
      //            getchar();
      
	for ( j=0; j<8192; j++ ) {
	ii=8192*i+j;
	if(i==0)buffer[ii]=(int16_t)(4000.*sin(dphi*(double)j));
	if(i>0) buffer[ii]=(int16_t)(4000.*sin(dphi*(double)j+phase[i-1]));
	//	if(i>0) buffer[ii]=(int16_t)(4000.*sin(dphi*(double)j));
	if(i==0)phase[i]=dphi*8192.;
	if(i>0)phase[i]=phase[i-1]+(dphi*8192.);

	}
    }

    /*
    for(j=2*8180; j<(2*8180)+50; j++)
      printf("%d\n",buffer[j]);
    */
    
    t0=clock();
    tdecimasi += (float)(clock()-t0)/CLOCKS_PER_SEC;
    printf("\ntime: %f\n",tdecimasi);


  // Menunggu waktu menit genab

  /*

  time_t t = time(NULL);
  struct tm tm = *localtime(&t);
  while(tm.tm_min%2 == 0){
  printf("sekarang: %d-%d-%d %d:%d:%d\n", tm.tm_year+1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
  t = time(NULL);
  tm = *localtime(&t);
  sleep(1);
  system("clear");
  }
  while(tm.tm_min%2 == 1){
  printf("sekarang: %d-%d-%d %d:%d:%d\n", tm.tm_year+1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
  t = time(NULL);
  tm = *localtime(&t);
  sleep(1);
  system("clear");
  if(tm.tm_min%2 ==0)
  //  if(tm.tm_sec==58)
    printf("sekarang: %d:%d:%d\n", tm.tm_hour,tm.tm_min, tm.tm_sec);
    sprintf(namafile,"%d:%d:%d:%d:%d.raw", tm.tm_year+1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min+1);
  }

  */

  fprintf(stdout,"sedang playback data...[%s]\n",namafile);

  //baca data dan mainkan ke output sound card

  time_t t = time(NULL);
  struct tm tm = *localtime(&t);
  printf("mulai: %d:%d:%d\n", tm.tm_hour, tm.tm_min, tm.tm_sec);

  if ((err = snd_pcm_writei(playback_handle, buffer, buffer_frames_12)) == -EPIPE) {
   printf("\nXRUN...\n");
   snd_pcm_prepare(playback_handle);
  }else if (err < 0){
    printf("ERROR. Can't write to PCM device. %s\n", snd_strerror(err));
  }
  printf("\nerr= %d\n",err);

  t = time(NULL);
  tm = *localtime(&t);
  printf("selesai: %d:%d:%d\n", tm.tm_hour, tm.tm_min, tm.tm_sec);

  f=fopen("./simbol.WAV","wb");
  if(f==NULL){
    printf("\nfile error...\n");
    exit(1);
  }
  fwrite(buffer,2,22,f);            //write header
  fwrite(buffer, sizeof(int16_t), buffer_frames_12, f);    /* jika mono */
  fclose(f);
  free(buffer);
  snd_pcm_close(playback_handle);

}

