Advertisement
Guest User

Untitled

a guest
Mar 23rd, 2018
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.58 KB | None | 0 0
  1. #include <avr/io.h>
  2. #include <avr/interrupt.h>
  3.  
  4. #include <util/delay.h>
  5.  
  6. #include <stdbool.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9.  
  10. #include "lcd.h"
  11. #include "pff.h"
  12.  
  13.  
  14. FATFS fs; // sistemul de fisiere
  15.  
  16.  
  17. void IO_init(void)
  18. {
  19. DDRA &= ~(1 << PA5); // BTN6 ca input, fara pull-up
  20.  
  21. DDRB &= ~(1 << PB2); // PB2 ca input, cu pull-up
  22. PORTB |= (1 << PB2);
  23.  
  24. DDRD &= ~(1 << PD6); // PD6 ca input, cu pull-up
  25. PORTD |= (1 << PD6);
  26. }
  27.  
  28.  
  29. /*---------------------------------------------------------------------------*/
  30. /* Player audio */
  31. /*---------------------------------------------------------------------------*/
  32.  
  33. /*
  34. * Four-Character Code - folosit pentru a indentifica formate de date
  35. */
  36. #define FCC(c1, c2, c3, c4) \
  37. (((DWORD)(c4) << 24) + \
  38. ((DWORD)(c3) << 16) + \
  39. (( WORD)(c2) << 8) + \
  40. (( BYTE)(c1) << 0))
  41.  
  42.  
  43. uint8_t buf[2][256]; // wave output buffers (double buffering)
  44. const uint16_t buf_size = 256; // front and back buffer sizes
  45. volatile uint8_t buf_front = 0; // front buffer index (current buffer used)
  46. volatile uint8_t buf_pos = 0; // current buffer position
  47. volatile uint8_t buf_sync = 0;
  48.  
  49. #define BUF_FRONT (buf[buf_front])
  50. #define BUF_BACK (buf[1 - buf_front])
  51.  
  52.  
  53. ISR(TIMER0_COMPA_vect)
  54. {
  55. OCR1B = BUF_FRONT[buf_pos++];
  56.  
  57. // swap buffers when end is reached (end is 256 <=> overflow to 0)
  58. if(buf_pos == 0)
  59. buf_front = 1 - buf_front;
  60. }
  61.  
  62. void timer0_start(void)
  63. {
  64. // interrupt on compare A
  65. TIMSK0 |= (1 << OCIE0A);
  66. // CTC, top OCRA
  67. TCCR0B |= (0 << WGM02);
  68. TCCR0A |= (1 << WGM01) | (0 << WGM00);
  69. // prescaler 8
  70. TCCR0B |= (2 << CS00);
  71. }
  72.  
  73. void timer0_stop(void)
  74. {
  75. TCCR0B = 0;
  76. TCCR0A = 0;
  77. TIMSK0 = 0;
  78. OCR0A = 0;
  79. TCNT0 = 0;
  80. }
  81.  
  82. void timer1_start(void)
  83. {
  84. // 8-bit FastPWM
  85. TCCR1B |= (1 << WGM12);
  86. TCCR1A |= (1 << WGM10);
  87. // channel B inverted
  88. TCCR1A |= (1 << COM1B0) | (1 << COM1B1);
  89. // prescaler 1
  90. TCCR1B |= (1 << CS10);
  91. }
  92.  
  93. void timer1_stop(void)
  94. {
  95. TCCR1B = 0;
  96. TCCR1A = 0;
  97. OCR1B = 0;
  98. TCNT1 = 0;
  99. }
  100.  
  101. bool continue_play()
  102. {
  103. if((PINB & (1 << PB2)) == 0 && (PIND & (1 << PD6)) == 0)
  104. return false;
  105.  
  106. return true;
  107. }
  108.  
  109. /*
  110. * Incarca header-ul unui fisier WAVE
  111. *
  112. * @return DWORD
  113. * 0 => format invalid
  114. * 1 => eroare I/O
  115. * >1 => numarul de sample-uri
  116. */
  117. DWORD load_header(void)
  118. {
  119. DWORD size;
  120. WORD ret;
  121.  
  122. // citeste header-ul (12 octeti)
  123. if(pf_read(BUF_FRONT, 12, &ret))
  124. return 1;
  125.  
  126. if(ret != 12 || LD_DWORD(BUF_FRONT + 8) != FCC('W','A','V','E'))
  127. return 0;
  128.  
  129. for(;;)
  130. {
  131. // citeste chunk ID si size
  132. pf_read(BUF_FRONT, 8, &ret);
  133. if(ret != 8)
  134. return 0;
  135.  
  136. size = LD_DWORD(&BUF_FRONT[4]);
  137.  
  138. // verifica FCC
  139. switch(LD_DWORD(&BUF_FRONT[0]))
  140. {
  141. // 'fmt ' chunk
  142. case FCC('f','m','t',' '):
  143. // verifica size
  144. if(size > 100 || size < 16) return 0;
  145.  
  146. // citeste continutul
  147. pf_read(BUF_FRONT, size, &ret);
  148. // verifica codificarea
  149. if(ret != size || BUF_FRONT[0] != 1) return 0;
  150. // verifica numarul de canale
  151. if(BUF_FRONT[2] != 1 && BUF_FRONT[2] != 2) return 0;
  152. // verifica rezolutia
  153. if(BUF_FRONT[14] != 8 && BUF_FRONT[14] != 16) return 0;
  154.  
  155. // seteaza sampling rate-ul
  156. OCR0A = (BYTE)(F_CPU / 8 / LD_WORD(&BUF_FRONT[4])) - 1;
  157. break;
  158.  
  159. // 'data' chunk => incepe redarea
  160. case FCC('d','a','t','a'):
  161. return size;
  162.  
  163. // 'LIST' chunk => skip
  164. case FCC('L','I','S','T'):
  165. // 'fact' chunk => skip
  166. case FCC('f','a','c','t'):
  167. pf_lseek(fs.fptr + size);
  168. break;
  169.  
  170. // chunk necunoscut => eroare
  171. default:
  172. return 0;
  173. }
  174. }
  175.  
  176. return 0;
  177. }
  178.  
  179. /*
  180. * Functie care reda un fisier audio
  181. *
  182. * path - calea absoluta a fisierului
  183. *
  184. * @return UINT
  185. * FR_OK daca a rulat cu succes fisierul
  186. */
  187. UINT play(const char *path)
  188. {
  189. FRESULT ret;
  190.  
  191. if((ret = pf_open(path)) == FR_OK)
  192. {
  193. WORD bytes_read;
  194.  
  195. // incarca header-ul fisierului
  196. DWORD current_size = load_header();
  197. if(current_size < buf_size)
  198. return FR_NO_FILE;
  199.  
  200. // align to sector boundary
  201. ret = pf_lseek((fs.fptr + 511) & ~511);
  202. if(ret != FR_OK)
  203. return ret;
  204.  
  205. // fill front buffer
  206. ret = pf_read(BUF_FRONT, buf_size, &bytes_read);
  207. if(ret != FR_OK)
  208. return ret;
  209. if(bytes_read < buf_size)
  210. return ret;
  211.  
  212. // reset front buffer index
  213. buf_pos = 0;
  214.  
  215. // start output
  216. timer0_start();
  217. timer1_start();
  218. DDRD |= (1 << PD4);
  219.  
  220. while(continue_play())
  221. {
  222. uint8_t old_buf_front = buf_front;
  223.  
  224. // fill back buffer
  225. ret = pf_read(BUF_BACK, buf_size, &bytes_read);
  226. if(ret != FR_OK)
  227. break;
  228. if(bytes_read < buf_size)
  229. break;
  230.  
  231. // wait for buffer swap
  232. while(old_buf_front == buf_front) ;
  233. }
  234.  
  235. // stop output
  236. DDRD &= ~(1 << PD4);
  237. timer1_stop();
  238. timer0_stop();
  239. }
  240.  
  241. return ret;
  242. }
  243.  
  244.  
  245. /*---------------------------------------------------------------------------*/
  246. /* Ceas */
  247. /*---------------------------------------------------------------------------*/
  248.  
  249. volatile uint8_t hours = 0;
  250. volatile uint8_t minutes = 0;
  251. volatile uint8_t seconds = 0;
  252.  
  253.  
  254. ISR(TIMER2_COMPA_vect)
  255. {
  256. static uint16_t miliseconds = 0;
  257.  
  258. if(++miliseconds != 1000)
  259. return;
  260. miliseconds = 0;
  261.  
  262. if(++seconds == 60)
  263. {
  264. seconds = 0;
  265.  
  266. if(++minutes == 60)
  267. {
  268. minutes = 0;
  269.  
  270. if(++hours == 24)
  271. hours = 0;
  272. }
  273. }
  274.  
  275. char buf[9];
  276. snprintf(buf, sizeof(buf), "%02d:%02d:%02d", hours, minutes, seconds);
  277.  
  278. LCD_clear_bottom_line();
  279. LCD_printAt(0x40, buf);
  280. }
  281.  
  282. void timer2_init(void)
  283. {
  284. // set compare at each milisecond
  285. OCR2A = 124;
  286. // interrupt on compare A
  287. TIMSK2 |= (1 << OCIE2A);
  288. // CTC, top OCRA
  289. TCCR2A |= (1 << WGM21);
  290. // prescaler 128
  291. TCCR2B |= (1 << CS20) | (1 << CS22);
  292. }
  293.  
  294. #define MUSIC "music"
  295.  
  296. /*---------------------------------------------------------------------------*/
  297. /* Task 1 */
  298. /*---------------------------------------------------------------------------*/
  299.  
  300. /*
  301. * Listeaza pe LCD continutul folder-ului primit ca parametru
  302. */
  303. void list(const char *folder)
  304. {
  305. DIR dir;
  306. if(pf_opendir(&dir, folder) != FR_OK)
  307. {
  308. LCD_printAt(0x00, "path not found");
  309. return;
  310. }
  311.  
  312. FILINFO file;
  313. while(pf_readdir(&dir, &file) == FR_OK &&
  314. file.fname != NULL && file.fname[0] != '\0')
  315. {
  316. LCD_clear_top_line();
  317. LCD_printAt(0x00, file.fname);
  318.  
  319. _delay_ms(200);
  320. }
  321. }
  322.  
  323. void task1()
  324. {
  325. // TODO: Task 1
  326. if(!(PINB & (1 << PB2)) && !(PINA & (1 << PA5)))
  327. {
  328. LCD_clear_top_line();
  329.  
  330. list("music");
  331.  
  332. LCD_clear_top_line();
  333. }
  334. }
  335.  
  336.  
  337. /*---------------------------------------------------------------------------*/
  338. /* Task 2 and 3 */
  339. /*---------------------------------------------------------------------------*/
  340.  
  341. /*
  342. * Cauta si returneaza al n-lea fisier din folder-ul primit
  343. */
  344. void get_music(int n, const char *folder, char *filename)
  345. {
  346. // TODO: Task 3
  347. filename[0] = '\0';
  348.  
  349. DIR dir;
  350. if(pf_opendir(&dir, folder) != FR_OK)
  351. return;
  352.  
  353. FILINFO file;
  354. while(n >= 0 && pf_readdir(&dir, &file) == FR_OK &&
  355. file.fname != NULL && file.fname[0] != '\0')
  356. {
  357. if((file.fattrib & (AM_DIR | AM_HID)) == 0 &&
  358. strstr(file.fname, ".WAV") != NULL)
  359. {
  360. n--;
  361. }
  362. }
  363.  
  364. strcpy(filename, file.fname);
  365. }
  366.  
  367. void task2and3()
  368. {
  369. static int track = 0;
  370. static char path[] = MUSIC"/01-SUP~1.WAV";
  371. char * const filename = &path[sizeof(MUSIC)];
  372.  
  373. /* Conditia de declansare: PB2 low, PD6 low */
  374. if(!(PINB & (1 << PB2)) || !(PIND & (1 << PD6)))
  375. {
  376. // TODO: Task 3
  377. LCD_clear_top_line();
  378.  
  379. DIR dir;
  380. if(pf_opendir(&dir, MUSIC) != FR_OK)
  381. {
  382. LCD_printAt(0x00, MUSIC"missing");
  383. return;
  384. }
  385. }
  386.  
  387. /* Conditia de declansare: PB2 low, PD6 high */
  388. if(!(PINB & (1 << PB2)) && (PIND & (1 << PD6)))
  389. {
  390. // TODO: Task 3
  391. track++;
  392.  
  393. filename[-1] = '\0';
  394. get_music(track, path, filename);
  395. filename[-1] = '/';
  396.  
  397. if(filename[0] == '\0')
  398. {
  399. track = 0;
  400.  
  401. filename[-1] = '\0';
  402. get_music(track, path, filename);
  403. filename[-1] = '/';
  404. }
  405. }
  406.  
  407. /* Conditia de declansare: PB2 high, PD6 low */
  408. if(!(PIND & (1 << PD6)))
  409. {
  410. // TODO Task 2
  411. LCD_printAt(0x00, filename);
  412.  
  413. play(path);
  414. }
  415. }
  416.  
  417.  
  418. /*---------------------------------------------------------------------------*/
  419. /* Task 6 */
  420. /*---------------------------------------------------------------------------*/
  421.  
  422. #define SPEECH "speech"
  423.  
  424.  
  425. /*
  426. * Anunta numarul
  427. */
  428. void say_number(uint8_t number)
  429. {
  430. // TODO 6 - functie ajutatoare
  431. (void)number;
  432. }
  433.  
  434. /*
  435. * Anunta ora completa
  436. */
  437. void say_time(uint8_t hours, uint8_t minutes, uint8_t seconds)
  438. {
  439. // TODO 6 - functie ajutatoare
  440. (void)hours;
  441. (void)minutes;
  442. (void)seconds;
  443. }
  444.  
  445. void task6()
  446. {
  447. if(PINA & (1 << PA5))
  448. {
  449. LCD_clear_top_line();
  450.  
  451. DIR dir;
  452. if(pf_opendir(&dir, SPEECH) != FR_OK)
  453. {
  454. LCD_printAt(0x00, SPEECH" missing");
  455. return;
  456. }
  457.  
  458. LCD_printAt(0x00, "Anunta ora");
  459.  
  460. // TODO 6
  461.  
  462. LCD_clear_top_line();
  463. }
  464. }
  465.  
  466.  
  467. int main (void)
  468. {
  469. IO_init();
  470. LCD_init();
  471. timer2_init();
  472.  
  473. sei();
  474.  
  475. for(;;)
  476. {
  477. // mount filesystem
  478. LCD_printAt(0x00, "mounting...");
  479.  
  480. if(pf_mount(&fs) != FR_OK)
  481. {
  482. // wait a while and retry
  483. _delay_ms(1000);
  484. continue;
  485. }
  486.  
  487. LCD_clear_top_line();
  488. LCD_printAt(0x00, "mounted!");
  489. _delay_ms(1000);
  490. LCD_clear_top_line();
  491.  
  492. for(;;)
  493. {
  494. task1();
  495. task2and3();
  496. // task6();
  497.  
  498. _delay_ms(200);
  499. }
  500. }
  501.  
  502. return 0;
  503. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement