Components and supplies
Arduino MP3 Shield
Arduino Mega 2560
Project description
Code
Arduino Code
c_cpp
1// include SPI, MP3 and SD libraries 2#include <SPI.h> 3#include <Adafruit_VS1053.h> 4#include <SD.h> 5 6// Replies to be sent to the Atari 7const byte ACK = 0x41; 8const byte NAK = 0x4E; 9const byte COMPLETE = 0x43; 10const byte ERR = 0x45; 11 12// Sector size is 128 bytes 13const unsigned long MAX_SECTOR_SIZE = 128; 14 15// Commands received from the Atari 16const byte CMD_FORMAT = 0x21; 17const byte CMD_FORMAT_MD = 0x22; 18const byte CMD_POLL = 0x3F; 19const byte CMD_PUT = 0x50; 20const byte CMD_READ = 0x52; 21const byte CMD_STATUS = 0x53; 22const byte CMD_WRITE = 0x57; 23 24// Other 25const unsigned long READ_CMD_TIMEOUT = 500; 26const unsigned long READ_FRAME_TIMEOUT = 2000; 27const byte DELAY_T2 = 1; 28const byte DELAY_T3 = 2; 29const byte DELAY_T4 = 1; 30const byte DELAY_T5 = 1; 31 32// Whizzosoftware allows for up to 8 drives and an 850 module. 33// Modified to include a printer 34const byte DEVICE_D1 = 0x31; 35const byte DEVICE_D2 = 0x32; 36const byte DEVICE_D3 = 0x33; 37const byte DEVICE_D4 = 0x34; 38const byte DEVICE_D5 = 0x35; 39const byte DEVICE_D6 = 0x36; 40const byte DEVICE_D7 = 0x37; 41const byte DEVICE_D8 = 0x38; 42const byte PRINTER = 0x40; 43const byte DEVICE_R1 = 0x50; 44 45 46#define PIN_ATARI_CMD 2 // the Atari SIO command line 47#define SIO_UART Serial3 48#define SIO_CALLBACK serialEvent3 49 50 51// These are the pins used for the music maker shield 52#define SHIELD_RESET -1 // VS1053 reset pin (unused!) 53#define SHIELD_CS 7 // VS1053 chip select pin (output) 54#define SHIELD_DCS 6 // VS1053 Data/command select pin (output) 55 56// These are common pins between breakout and shield 57#define CARDCS 4 // Card chip select pin 58 59// DREQ should be an Int pin, see 60#define DREQ 3 // VS1053 Data request, ideally an Interrupt pin 61 62Adafruit_VS1053_FilePlayer musicPlayer = Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS); 63 64// variable used to produce the directory listing 65String filelist; 66byte dirlist; 67byte* pdirlist; 68String playfile; 69 70//Command frame structure 71const byte COMMAND_FRAME_SIZE = 5; 72struct CommandFrame { 73 byte deviceId; 74 byte command; 75 byte aux1; 76 byte aux2; 77 byte checksum; 78}; 79 80 81// variables used in serial communication 82int m_cmdPinState; 83int m_cmdPin; 84Stream* m_stream; 85unsigned long m_startTimeoutInterval; 86CommandFrame m_cmdFrame; 87byte* m_cmdFramePtr; 88byte m_sectorBuffer[MAX_SECTOR_SIZE + 1]; 89byte* m_putSectorBufferPtr; 90int m_putBytesRemaining; 91 92void resetCommandFrameBuffer(); 93void dumpCommandFrame(); 94byte processCommand(); 95byte checksum(byte* chunk, int length); 96void cmdPutSector(int deviceId); 97void doPutSector(); 98boolean isChecksumValid(); 99boolean isCommandForThisDevice(); 100boolean isValidCommand(); 101boolean isValidDevice(byte b); 102boolean isValidAuxData(); 103void cmdGetStatus(); 104void printDirectory(File dir); 105void cmdGetSector(int deviceId); 106 107 108void setup() { 109 110 // initialize serial port to Atari 111 SIO_UART.begin(19200); 112 Serial.begin(19200); // does not like different baud rates 113 Serial.println("Go!"); 114 115 pinMode(PIN_ATARI_CMD, INPUT); 116 m_cmdPinState = 1; // initial state 117 m_cmdPin = PIN_ATARI_CMD; 118 119 Serial.println("Adafruit VS1053 Simple Test"); 120 121 if (! musicPlayer.begin()) { // initialise the music player 122 Serial.println(F("Couldn't find VS1053, do you have the right pins defined?")); 123 while (1); 124 } 125 Serial.println(F("VS1053 found")); 126 127 if (!SD.begin(CARDCS)) { 128 Serial.println(F("SD failed, or not present")); 129 while (1); // don't do anything more 130 } 131 132 // list files 133 printDirectory(SD.open("/")); 134 135 // Set volume for left, right channels. lower numbers == louder volume! 136 musicPlayer.setVolume(20,20); 137 138 139 // If DREQ is on an interrupt pin (on uno, #2 or #3) we can do background 140 // audio playing 141 musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT); // DREQ int 142 143} 144 145void loop() { 146 147 switch (m_cmdPinState) { 148 case 1: 149 // initial state 150 if (digitalRead(m_cmdPin) == HIGH) 151 { 152 m_cmdPinState = 2; 153 } 154 break; 155 case 2: 156 // waiting for start 157 if (digitalRead(m_cmdPin) == LOW) { 158 m_cmdPinState = 3; 159 resetCommandFrameBuffer(); 160 Serial.println("Cmd pin low"); 161 } 162 break; 163 case 3: 164 // Read command 165 m_startTimeoutInterval = millis(); 166 // if command frame is fully read... 167 if (m_cmdFramePtr - (byte*)&m_cmdFrame == COMMAND_FRAME_SIZE) 168 { 169 Serial.println("Frame Read"); 170 dumpCommandFrame(); 171 // process command frame 172 if (isChecksumValid() && isCommandForThisDevice()) 173 { 174 Serial.println("For this device and checksum okay"); 175 if (isValidCommand() && isValidAuxData()) 176 { 177 m_cmdPinState = processCommand(); 178 Serial.print("New cmd status "); 179 Serial.println(m_cmdPinState); 180 } 181 else 182 { 183 m_cmdPinState = 2; //wait for start 184 Serial.println("Invalid Command"); 185 } 186 } 187 else 188 { 189 m_cmdPinState = 2; //wait for start 190 Serial.println("Not this device or checksum error"); 191 } 192 // otherwise, check for command read timeout 193 } 194 else if (millis() - m_startTimeoutInterval > READ_CMD_TIMEOUT) 195 { 196 m_cmdPinState = 2; //wait for start 197 Serial.println("Time out"); 198 } 199 break; 200 case 4: 201 // Read data frame 202 // Serial.println("Read data frame"); 203 // check for timeout 204 if (millis() - m_startTimeoutInterval > READ_FRAME_TIMEOUT) { 205 m_cmdPinState = 2; //wait for start 206 } 207 break; 208 case 5: 209 // wait for end 210 211 if (digitalRead(m_cmdPin) == HIGH) 212 { 213 m_cmdPinState = 2; // wait for start 214 Serial.println("Wait for end done"); 215 } 216 break; 217 } 218} 219 220 221 222void SIO_CALLBACK() 223{ 224 // read the next byte from the bus 225 byte b = SIO_UART.read(); 226 227 228 switch (m_cmdPinState) { 229 // if we read a valid device byte and are in a "command wait" state, come out of it and 230 // process the byte 231 case 1: //initial state 232 case 2: // wait for command 233 case 5: // wait for end 234 if (digitalRead(m_cmdPin) == LOW && isValidDevice(b)) { 235 m_cmdPinState = 3; // Read 236 resetCommandFrameBuffer(); 237 } 238 else 239 { 240 break; 241 } 242 // if we're reading a command frame... 243 case 3: //read 244 { 245 // read the data into the command frame 246 // sometimes we see extra bytes between command frames on the bus while reading a command and things get lost -- 247 // the isValidDevice() check prevents a command frame read from getting corrupted by them 248 249 int idx = (int)m_cmdFramePtr - (int)&m_cmdFrame; 250 if (idx < COMMAND_FRAME_SIZE && (idx > 0 || (idx == 0 && isValidDevice(b)))) { 251 *m_cmdFramePtr = b; 252 m_cmdFramePtr++; 253 return; 254 } 255 break; 256 } 257 // if we're reading a data frame... 258 case 4: 259 { 260 // add byte to read sector buffer 261 *m_putSectorBufferPtr = b; 262 m_putSectorBufferPtr++; 263 m_putBytesRemaining--; 264 265 if (m_putBytesRemaining == 0 || b == 0x9b) 266 { 267 doPutSector(); 268 } 269 break; 270 } 271 default: 272 273 break; 274 } 275} 276 277void cmdPutSector(int deviceId) { 278 // send ACK 279 delay(DELAY_T2); 280 SIO_UART.write(ACK); 281 Serial.println("Put sector ACK"); 282 283 m_putBytesRemaining = MAX_SECTOR_SIZE; 284 m_putSectorBufferPtr = m_sectorBuffer; 285 286} 287 288void doPutSector() 289{ 290 int sectorSize = m_putSectorBufferPtr - m_sectorBuffer - 1; 291 int j; 292 293 // clear playfile 294 playfile = ""; 295 296 // send ACK 297 delay(2); 298 299 SIO_UART.write(ACK); 300 Serial.println("doPutSector ACK"); 301 302 for (j=0; j <2; j++) 303 { 304 delay(1); 305 306 // send COMPLETE 307 SIO_UART.write(COMPLETE); 308 } 309 Serial.println("doPutSector complete"); 310 311 // get filename 312 for (int i = 0; i < sectorSize; i++) 313 { 314 playfile += (char)m_sectorBuffer[i]; 315 } 316 317 // change state 318 m_cmdPinState = 2; //wait for start 319 320 321 322// check for repeated frame buffer 323 if (playfile[0] == m_cmdFrame.deviceId && 324 playfile[1] == m_cmdFrame.command) 325 { 326 playfile = playfile.substring(5, playfile.length()); 327 } 328 329 330 musicPlayer.startPlayingFile(playfile.c_str()); 331 } 332 333 334boolean isChecksumValid() { 335 byte chkSum = checksum((byte*)&m_cmdFrame, 4); 336 if (chkSum != m_cmdFrame.checksum) 337 { 338 Serial.println("Checksum fail"); 339 return false; 340 } 341 else 342 { 343 Serial.println("Checksum pass"); 344 return true; 345 } 346} 347 348boolean isCommandForThisDevice() { 349 350boolean result = (m_cmdFrame.deviceId == PRINTER || 351 m_cmdFrame.deviceId == DEVICE_D2); 352 353 return result; 354} 355 356boolean isValidCommand() { 357 boolean result = (m_cmdFrame.command == CMD_READ || 358 m_cmdFrame.command == CMD_WRITE || 359 m_cmdFrame.command == CMD_STATUS || 360 m_cmdFrame.command == CMD_PUT || 361 m_cmdFrame.command == CMD_FORMAT || 362 m_cmdFrame.command == CMD_FORMAT_MD); 363 364 if (!result) { 365 result = 0; 366 } 367 368 return result; 369} 370 371boolean isValidDevice(byte b) { 372 boolean result = (b == DEVICE_D1 || 373 b == DEVICE_D2 || 374 b == DEVICE_D3 || 375 b == DEVICE_D4 || 376 b == DEVICE_D5 || 377 b == DEVICE_D6 || 378 b == DEVICE_D7 || 379 b == DEVICE_D8 || 380 b == PRINTER || 381 b == DEVICE_R1); 382 383 if (!result) { 384 result = 0; 385 } 386 387 return result; 388} 389 390boolean isValidAuxData() { 391 return true; 392} 393 394 395void cmdGetStatus(int deviceId) 396{ 397 byte b[4] = {0, 0, 2, 0}; 398 byte chksum; 399 400 chksum = checksum((byte*)b, 4); 401 // send ACK 402 delay(DELAY_T2); 403 SIO_UART.write(ACK); 404 Serial.println("ACK"); 405 406 // send complete 407 delay(DELAY_T5); 408 SIO_UART.write(COMPLETE); 409 Serial.println("Get status COMPLETE"); 410 411 412 // send status to bus 413 for (int i = 0; i < 4; i++) { 414 SIO_UART.write(b[i]); 415 } 416 417 SIO_UART.write(chksum); 418 419} 420 421 422 423byte checksum(byte* chunk, int length) { 424 int chkSum = 0; 425 for (int i = 0; i < length; i++) 426 { 427 chkSum = chkSum + chunk[i]; 428 if (chkSum >= 256) 429 { 430 chkSum = (chkSum -256) +1; 431 } 432 433 } 434 return (byte)chkSum; 435} 436 437 438 439byte processCommand() { 440 int deviceId = 1; 441 byte nextCmdPinState = 5; // wait for end 442 443 switch (m_cmdFrame.command) { 444 case CMD_READ: 445 cmdGetSector(deviceId); 446 break; 447 case CMD_PUT: 448 case CMD_WRITE: 449 cmdPutSector(deviceId); 450 nextCmdPinState = 4; // read data frame 451 m_startTimeoutInterval = millis(); 452 break; 453 case CMD_STATUS: 454 cmdGetStatus(deviceId); 455 break; 456 case CMD_FORMAT: 457 //cmdFormat(deviceId, DENSITY_SD); 458 break; 459 case CMD_FORMAT_MD: 460 //cmdFormat(deviceId, DENSITY_ED); 461 break; 462 default: 463 //m_sdriveHandler.processCommand(&m_cmdFrame, m_stream); 464 break; 465 } 466 467 return nextCmdPinState; 468} 469 470 471void dumpCommandFrame() { 472 473 Serial.println(m_cmdFrame.deviceId, HEX); 474 Serial.println(m_cmdFrame.command, HEX); 475 Serial.println(m_cmdFrame.aux1, HEX); 476 Serial.println(m_cmdFrame.aux2, HEX); 477 Serial.println(m_cmdFrame.checksum, HEX); 478 479} 480 481 482void resetCommandFrameBuffer() { 483 // reset last command frame info 484 memset(&m_cmdFrame, 0, sizeof(m_cmdFrame)); 485 m_cmdFramePtr = (byte*)&m_cmdFrame; 486 Serial.println("buffer reset"); 487} 488 489 490 491void printDirectory(File dir) 492{ 493 String tempName; 494 int i; 495 int dot; 496 String fileHeader = "00000"; 497 498 while(true) { 499 500 File entry = dir.openNextFile(); 501 if (! entry) 502 { 503 // no more files 504 //Serial.println("**nomorefiles**"); 505 break; 506 } 507 508 if (!entry.isDirectory()) 509 { 510 511 // each entry needs to be in the format 5 digits 8 characters 3 ext (16 chrs long) 512 filelist += fileHeader; 513 tempName = entry.name(); 514 dot = tempName.indexOf("."); 515 516 filelist += tempName.substring(0, dot); 517 518 if (dot<8) 519 { 520 for (i=0; i<(8-dot); i++) 521 { 522 filelist += " "; 523 } 524 } 525 526 filelist += tempName.substring(dot+1, tempName.length()); 527 528 } 529 entry.close(); 530 } 531 532 533 // convert to byte array 534 pdirlist = &dirlist; 535 for (i =0; i<129; i++) 536 { 537 if (filelist.length()>i) 538 { 539 *pdirlist = (byte)filelist[i]; 540 } 541 else 542 { 543 *pdirlist = 0; 544 } 545 pdirlist ++; 546 } 547} 548 549 550void cmdGetSector(int deviceId) { 551 552int i; 553 554 // send ACK 555 delay(2); 556 SIO_UART.write(ACK); 557 Serial.println("Get sector ACK"); 558 559 // write data frame + checksum 560 // send complete 561 delay(1); 562 SIO_UART.write(COMPLETE); 563 Serial.println("Get sector COMPLETE"); 564 SIO_UART.flush(); 565 566 Serial.println("Directory"); 567 568 for (i=0; i<128; i++) 569 { 570 SIO_UART.write((byte)filelist[i]); 571 } 572 573 574 // write checksum 575 byte chksum = checksum(&dirlist, filelist.length()); 576 SIO_UART.write(chksum); 577 Serial.print("Get sector checksum "); 578 Serial.println(chksum); 579 580 581 SIO_UART.flush(); 582}
Comments
Only logged in users can leave comments
amurison718
0 Followers
•0 Projects
Table of contents
Intro
1
0