mym2serial.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*******************************************************************
  2. * MYM Player to Serial port
  3. * (c) 2014 Manoel "Godzil" Trapier
  4. *
  5. * This file is base on the mym2ym by
  6. * Marq/Lieves!Tuore & Fit (marq@iki.fi)
  7. *
  8. * The YM writing part have been removed and replaced by code to
  9. * send register dump to the serial port.
  10. **************************** Licence ******************************
  11. * This file is licenced under the licence:
  12. * WTFPL v2 Postal Card Edition:
  13. *
  14. * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
  15. * Version 2, December 2004
  16. *
  17. * Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
  18. *
  19. * Everyone is permitted to copy and distribute verbatim or modified
  20. * copies of this license document, and changing it is allowed as long
  21. * as the name is changed.
  22. *
  23. * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
  24. * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
  25. *
  26. * 0. You just DO WHAT THE FUCK YOU WANT TO.
  27. * 1. If you like this software you can send me a (virtual) postals
  28. * card. Details bellow:
  29. *
  30. * < godzil-nospambot at godzil dot net >
  31. *
  32. * If you want to send a real postal card, send me an email, I'll
  33. * give you my address. Of course remove the -nospambot from my
  34. * e-mail address.
  35. *
  36. ******************************************************************/
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include <unistd.h>
  41. #include <fcntl.h>
  42. #include <termios.h>
  43. #include <errno.h>
  44. #define REGS 14
  45. #define FRAG 128 /* Nuber of rows to compress at a time */
  46. #define OFFNUM 14 /* Bits needed to store off+num of FRAG */
  47. unsigned readbits(int bits,FILE *f);
  48. int set_interface_attribs (int fd, int speed, int parity)
  49. {
  50. struct termios tty;
  51. memset (&tty, 0, sizeof tty);
  52. if (tcgetattr (fd, &tty) != 0)
  53. {
  54. printf("error %d from tcgetattr", errno);
  55. return -1;
  56. }
  57. cfsetospeed (&tty, speed);
  58. cfsetispeed (&tty, speed);
  59. tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
  60. // disable IGNBRK for mismatched speed tests; otherwise receive break
  61. // as \000 chars
  62. tty.c_iflag &= ~IGNBRK; // disable break processing
  63. tty.c_lflag = 0; // no signaling chars, no echo,
  64. // no canonical processing
  65. tty.c_oflag = 0; // no remapping, no delays
  66. tty.c_cc[VMIN] = 0; // read doesn't block
  67. tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
  68. tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
  69. tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
  70. // enable reading
  71. tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
  72. tty.c_cflag |= parity;
  73. tty.c_cflag &= ~CSTOPB;
  74. tty.c_cflag &= ~CRTSCTS;
  75. if (tcsetattr (fd, TCSANOW, &tty) != 0)
  76. {
  77. printf ("error %d from tcsetattr", errno);
  78. return -1;
  79. }
  80. return 0;
  81. }
  82. void set_blocking (int fd, int should_block)
  83. {
  84. struct termios tty;
  85. memset (&tty, 0, sizeof tty);
  86. if (tcgetattr (fd, &tty) != 0)
  87. {
  88. printf ("error %d from tggetattr", errno);
  89. return;
  90. }
  91. tty.c_cc[VMIN] = should_block ? 1 : 0;
  92. tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
  93. if (tcsetattr (fd, TCSANOW, &tty) != 0)
  94. printf ("error %d setting term attributes", errno);
  95. }
  96. int main(int argc,char *argv[])
  97. {
  98. unsigned char *data[REGS], /* The unpacked YM data */
  99. c;
  100. int serial_fd;
  101. unsigned current[REGS];
  102. FILE *f;
  103. long n,i,row,index,compoff,compnum,
  104. bytes=0,
  105. regbits[REGS]={8,4,8,4, 8,4,5,8, 5,5,5,8, 8,8}; /* Bits per PSG reg */
  106. unsigned long rows;
  107. if(argc!=3)
  108. {
  109. printf("Usage: mym2serial source.mym /dev/serial\n");
  110. return(EXIT_FAILURE);
  111. }
  112. if((f=fopen(argv[1],"rb"))==NULL)
  113. {
  114. printf("File open error.\n");
  115. return(EXIT_FAILURE);
  116. }
  117. rows=fgetc(f); /* Read the number of rows */
  118. rows+=fgetc(f)<<8u;
  119. for(n=0;n<REGS;n++) /* Allocate memory for rows */
  120. {
  121. if((data[n]=(unsigned char *)malloc(rows+FRAG))==NULL)
  122. {
  123. printf("Out of memory.\n");
  124. exit(EXIT_FAILURE);
  125. }
  126. }
  127. for(n=0;n<rows;n+=FRAG) /* Go through rows... */
  128. {
  129. for(i=0;i<REGS;i++) /* ... and registers */
  130. {
  131. index=0;
  132. if(!readbits(1,f)) /* Totally unchanged fragment */
  133. {
  134. for(row=0;row<FRAG;row++)
  135. data[i][n+row]=current[i];
  136. continue;
  137. }
  138. while(index<FRAG) /* Packed fragment */
  139. {
  140. if(!readbits(1,f)) /* Unchanged register */
  141. {
  142. data[i][n+index]=current[i];
  143. index++;
  144. }
  145. else
  146. {
  147. if(readbits(1,f)) /* Raw data */
  148. {
  149. c=readbits(regbits[i],f);
  150. current[i]=data[i][n+index]=c;
  151. index++;
  152. }
  153. else /* Reference to previous data */
  154. {
  155. compoff=readbits(OFFNUM/2,f)+index;
  156. compnum=readbits(OFFNUM/2,f)+1;
  157. for(row=0;row<compnum;row++)
  158. {
  159. c=data[i][n-FRAG+compoff+row];
  160. data[i][n+index]=current[i]=c;
  161. index++;
  162. }
  163. }
  164. }
  165. }
  166. }
  167. }
  168. fclose(f);
  169. serial_fd = open (argv[2], O_RDWR | O_NOCTTY | O_SYNC);
  170. if (serial_fd > 0)
  171. {
  172. char buffer[14];
  173. printf("Serial opened...\n");
  174. set_interface_attribs (serial_fd, B115200, 0); // 115200 8n1
  175. set_blocking (serial_fd, 0);
  176. /* Wait a little bit to be sure that the other end is ready... */
  177. sleep(2);
  178. printf("Playing now!\n");
  179. for(n=0;n<rows;n++)
  180. {
  181. for(i=0;i<REGS;i++)
  182. {
  183. buffer[i] = data[i][n];
  184. }
  185. write(serial_fd, buffer, 14);
  186. // 50Hz so wait a little bit...
  187. printf("\rVBL%ld ", n);
  188. fflush(stdout);
  189. usleep(20*1000); /* 50Hz */
  190. }
  191. printf("\n");
  192. }
  193. else
  194. {
  195. printf("Opening error...\n");
  196. }
  197. return(EXIT_SUCCESS);
  198. }
  199. /* Reads bits from a while */
  200. unsigned readbits(int bits,FILE *f)
  201. {
  202. static unsigned char byte;
  203. static int off=7;
  204. unsigned n,data=0;
  205. /* Go through the bits and read a whole byte if needed */
  206. for(n=0;n<bits;n++)
  207. {
  208. data<<=1;
  209. if(++off==8)
  210. {
  211. byte=fgetc(f);
  212. off=0;
  213. }
  214. if(byte&(0x80>>off))
  215. data++;
  216. }
  217. return(data);
  218. }