/*--------------------------------------------------------
  Sega CD Transfer Compatible Dumper for Arduino
  Arduino用 Sega CD Transfer対応 ダンプ処理(Simple Hexa dump)
 About this:
  You can dump via USB serial communication using Sega CD Transfer.
  (Simple Hexa dump)
 How to use:
 (1)Save dump data to log file with terminal app.
   Teraterm Proのログ機能でHEXファイルに保存します
 (2)Use the editor to delete the message string in the header and footer.
   ログファイルをエディタで編集して余分な文字列(ヘッダ、フッタ)を削除します。
 (3)In order to convert the log file to binary, enter the following command at the Windows command prompt.
   Windowsのコマンドプロンプトで下記のコマンドでバイナリ変換します。
  
   > certutil -f -decodehex [infile] [outfile] 4
 NOTE:
   This sketch file is for use with Arduino Leonardo/Arduino Pro Micro only.
   Please refer to the official page of sparkfun for how to use Pro Micro.
    https://learn.sparkfun.com/tutorials/pro-micro--fio-v3-hookup-guide/
 注意:
  このスケッチは、Arduino Leonardo/Pro Micro(ATmega 32U4搭載)専用です。
  メガドライブ側の読み出しを最速で行うためポート(PinD)アクセスを利用しており、
  他マイコンと互換性がありません。
[Reference]
 Sega CD Transfer Suite
  https://www.retrodev.com/transfer.html
 UCON64
  https://ucon64.sourceforge.io/
 I/O ポートの制御
  http://rio.la.coocan.jp/lab/driver24/004hardware.html
 2020.8.2 BLUE( qze12045@nifty.com )
--------------------------------------------------------*/
// 通信用パラメータ
#define     _BAUDRATE   115200  // 通信速度 115200Bps
 
//  Sega CD Transfer Ports
#define     MD_D0       3       // PD0/Pin3
#define     MD_D1       2       // PD1/Pin2
#define     MD_D2       1       // PD2/Pin1(RX1)
#define     MD_D3       0       // PD3/Pin0(TX1)
#define     MD_ERR      4       // PD4/Pin4 Error信号
#define     MD_SEL      6       // PD7/Pin6 Select信号
#define     MD_ALF      5       // PC6/Pin5 Auto Line Feed信号ポート番号
 
// Sega CD Transfer Control
#define     ERRWAIT     9000    // ERR WAIT
#define     ERR         0x10    // Error bit mask
 
#define WAIT_ERRLo(x) for(int i=0 ; i<x ; i++ ){if(!(PIND & ERR)) break;}
#define WAIT_ERRHi(x) for(int i=0 ; i<x ; i++ ){if(PIND & ERR) break;}
 
//////////////////////////////////////
// Sega CD transfer 1バイト読出し
//////////////////////////////////////
unsigned char byte_dump(void)
{
unsigned char   data=0;
 
    noInterrupts(); //Disable Interrupts
 
    // Auto Line Feed = Hi
    digitalWrite(MD_ALF, HIGH );
    // Wait ERR=Hi
    WAIT_ERRHi(ERRWAIT);
 
    data = PIND & 0xf;
 
    // Auto Line Feed = Lo
    digitalWrite(MD_ALF, LOW );
    // Wait  ERR=Lo
    WAIT_ERRLo(ERRWAIT);
 
    // Auto Line Feed = Hi
    digitalWrite(MD_ALF, HIGH );
    // Wait ERR=Hi
    WAIT_ERRHi(ERRWAIT);
 
    data |= (PIND & 0xf)<<4;
 
    // Auto Line Feed = Lo
    digitalWrite(MD_ALF, LOW );
    //  Wait ERR=Lo
    WAIT_ERRLo(ERRWAIT);
 
    interrupts(); //Enable Interrupts
 
    return data;
}
 
//////////////////////////////////////
// read dump size
//////////////////////////////////////
unsigned char read_dump_size(void)
{
    // Sega CD Transfer connect check
    while (PIND & ERR){}
    return byte_dump();
}
//////////////////////////////////////
// initialize
//////////////////////////////////////
void setup() {
// put your setup code here, to run once:
 
    // initialize port(INPUT_PULLUP)
    pinMode(MD_D0, INPUT_PULLUP);
    pinMode(MD_D1, INPUT_PULLUP);
    pinMode(MD_D2, INPUT_PULLUP);
    pinMode(MD_D3, INPUT_PULLUP);
    pinMode(MD_ERR, INPUT_PULLUP);
    pinMode(MD_SEL, INPUT_PULLUP);
 
    // Auto Line Feed(OUTPUT)
    pinMode(MD_ALF, OUTPUT);
    // Auto Line Feed = Lo
    digitalWrite(MD_ALF, LOW );
 
    Serial.begin(_BAUDRATE);
    // Arduino Leonardo/Arduino Pro Micro only.
    while (!Serial){}
}
 
//////////////////////////////////////
// main loop
//////////////////////////////////////
void loop() {
// put your main code here, to run repeatedly:
 
long dump = 0;  // count of dump data
long size = 0;  // size of dump data
int cnt = 0;    // index of data dump
unsigned char data = 0; // Sega CD transfer data
 
    Serial.print("Sega CD Transfer Compatible Dumper for Arduino.\r\n");
    Serial.print("Waiting for Respons from Genesis/MegaDrive...\r\n");
    
    size = (long)read_dump_size();
 
    Serial.print("Link achieved.  Dumping ");
    Serial.print(size,DEC);
    Serial.print(" Megabits...\r\n");
 
    size = (size+1)<<16;
 
    while (dump < size)
    {
        // Dump 1 Byte
        data = byte_dump();
        
        if(!(data & 0xf0))
        {
            Serial.print("0");
        }
        Serial.print(data,HEX);
        if( ++cnt >= 16 )
        {
            Serial.print("\r\n");
            cnt = 0;
        }
        else
        {
            Serial.print(" ");
        }
        dump++;
    }
    Serial.print("Dump data send finished.\r\n\r\n");
}