Fabio Fumi / Mbed 2 deprecated Sharp_ce140f_emul

Dependencies:   mbed SDFileSystem

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 ////////////////////////////////////////////////////////
00002 // Sharp CE-140F diskette emulator
00003 //
00004 // v1 1/6/2022 - adaptation to MBed NUCLEO 
00005 // of the version received by contact@pockemul.com
00006 //
00007 ////////////////////////////////////////////////////////
00008 #include "mbed.h"
00009 
00010 #include "commands.h"
00011 
00012 #define DEBUG 1
00013 
00014 #define DEBUG_SIZE 1000 // print debug buffer
00015 #define NIBBLE_DELAY_1 100 // us
00016 #define NIBBLE_ACK_DELAY 100 // us
00017 #define BIT_DELAY_1 200 // us
00018 #define BIT_DELAY_2 2000 // us
00019 #define ACK_DELAY 20000 // us
00020 #define ACK_TIMEOUT 1 // s
00021 #define DATA_WAIT 9000 // us
00022 #define IN_DATAREADY_TIMEOUT 50000 // us
00023 #define OUT_NIBBLE_DELAY 5000 // us
00024 
00025 // input ports
00026 DigitalIn   in_BUSY     (PC_0);    
00027 InterruptIn irq_BUSY    (PC_0);    
00028 DigitalIn   in_D_OUT    (PC_1);    
00029 InterruptIn irq_D_OUT   (PC_1);
00030 DigitalIn   in_X_OUT    (D6);     
00031 InterruptIn irq_X_OUT   (D6);
00032 DigitalIn   in_D_IN     (D7);  
00033 DigitalIn   in_SEL_2    (D8); 
00034 DigitalIn   in_SEL_1    (D9);
00035 
00036 // output ports  
00037 DigitalOut        out_ACK     (D10);  
00038 DigitalOut        out_D_OUT   (D11);     
00039 DigitalOut        out_D_IN    (D12);     
00040 DigitalOut        out_SEL_2   (D14);     
00041 DigitalOut        out_SEL_1   (D15);     
00042 
00043 // info led
00044 DigitalOut        infoLed    (LED1); // D13
00045 
00046 // timers
00047 Timer             mainTimer;
00048 Timeout           ackOffTimeout;
00049 Timeout           inDataReadyTimeout;
00050 Ticker            outDataTicker;
00051 
00052 // PC comms
00053 RawSerial         pc(USBTX, USBRX); // D0, D1 ?
00054 InterruptIn       btn(USER_BUTTON);
00055 
00056 volatile uint8_t  deviceCode;
00057 volatile uint8_t  bitCount;
00058 volatile char     debugBuf[DEBUG_SIZE];
00059 volatile char     debugLine[80];
00060 volatile bool     highNibbleIn = false;
00061 volatile bool     highNibbleOut = false;
00062 volatile uint8_t  dataInByte;
00063 volatile uint8_t  dataOutByte;
00064 volatile uint16_t outDataPointer;
00065 
00066 #ifdef DEBUG
00067 void debug_log(const char *fmt, ...)
00068 {
00069     va_list va;
00070     va_start (va, fmt);
00071     sprintf((char*)debugLine,"%d ",mainTimer.read_us());
00072     strcat((char*)debugBuf,(char*)debugLine);
00073     vsprintf ((char*)debugLine, fmt, va);
00074     strcat((char*)debugBuf,(char*)debugLine);
00075     va_end (va);
00076 }
00077 #else
00078 void debug_log(const char *fmt, ...)
00079 {
00080     return;
00081 }
00082 #endif
00083 
00084 void btnRaised() 
00085 {
00086     uint8_t i = 20;
00087     while (i--) { infoLed =! infoLed; wait_ms(20); }
00088     // printout debug buffer
00089     pc.printf ( "%s", (char*)debugBuf );
00090     // reset status
00091     out_ACK = 0;
00092     infoLed = 0;
00093     irq_BUSY.rise(NULL);
00094     irq_BUSY.fall(NULL);
00095     sprintf ( (char*)debugBuf, "Reset\n\r" ); 
00096 }
00097 
00098 // a "timeout" on ACK line 
00099 void  ackOff ( void ) {
00100     out_ACK = 0; 
00101     infoLed = 0;
00102 }
00103 
00104 /* only if we replace testOutputSequence 
00105    with an asynchronous approach ...
00106 void outNibbleSend ( void ) {
00107     uint8_t t;
00108     pc.putc('o');
00109     debug_log ( "outNibbleSend (%d)\n", highNibbleOut);
00110     if ( out_ACK == 0 ) {
00111         wait_us(OUT_NIBBLE_DELAY); 
00112         if ( (outDataPointer < outBufPosition) & highNibbleOut ) {
00113             if ( highNibbleOut ) {
00114                 highNibbleOut = false;
00115                 t = (dataOutByte & 0x0F);
00116                 debug_log ( " %1X\n", dataOutByte, t);
00117             } else {
00118                 highNibbleOut = true;
00119                 dataOutByte = outDataBuf[ outDataPointer++ ];
00120                 t = (dataOutByte >> 4);
00121                 debug_log ( "dataOut 0x%02X %1X\n", dataOutByte, t);
00122             }
00123             
00124             out_SEL_1 = (t&0x01);
00125             out_SEL_2 = ((t&0x02)>>1);
00126             out_D_OUT = ((t&0x04)>>2);
00127             out_D_IN  = ((t&0x08)>>3);
00128             
00129             out_ACK = 1;
00130             
00131         } else {
00132             debug_log ( "dataOut complete\n"); 
00133         }
00134     } else {
00135         pc.putc('x');
00136         debug_log ( "outNibbleSend out_ACK!=0\n" ); 
00137     }
00138 }
00139 
00140 void outNibbleAck ( void ) {
00141     debug_log ( "outNibbleAck\n"); 
00142     if ( out_ACK == 1 ) {
00143         wait_us ( NIBBLE_ACK_DELAY );
00144         out_ACK = 0;
00145         infoLed = 0;
00146     } else {
00147         pc.putc('x');
00148         debug_log ( "outNibbleAck out_ACK!=1\n" ); 
00149     }
00150 }
00151 */
00152 
00153 void testOutputSequence ( void ) {
00154     uint8_t t;
00155     uint32_t nTimeout;
00156     
00157     pc.putc('o');
00158     pc.printf (" %d, %d", outDataPointer, outBufPosition);
00159     while ( outDataPointer < outBufPosition ) {
00160         wait_us (OUT_NIBBLE_DELAY);
00161         if ( highNibbleOut ) {
00162             highNibbleOut = false;
00163             t = (dataOutByte >> 4);
00164             outDataPointer++;
00165         } else {
00166             highNibbleOut = true;
00167             dataOutByte = outDataBuf[outDataPointer];
00168             debug_log ("%d: 0x%02X\n", outDataPointer, dataOutByte);
00169             t = (dataOutByte & 0x0F);
00170         }
00171         //debug_log ( " %u(%d):0x%1X\n", outDataPointer, (!highNibbleOut), t );
00172         
00173         out_SEL_1 = (t&0x01);
00174         out_SEL_2 = ((t&0x02)>>1);
00175         out_D_OUT = ((t&0x04)>>2);
00176         out_D_IN  = ((t&0x08)>>3);
00177         
00178         // nibble ready for PC to process
00179         out_ACK = 1;
00180         infoLed = 1;
00181         ackOffTimeout.attach( &ackOff, ACK_TIMEOUT ); // max time high ack 
00182         // wait for BUSY to go DOWN
00183         nTimeout = 50000; // max wait
00184         while ( in_BUSY && (nTimeout--) ) {
00185             wait_us (10);
00186         }  
00187         if (!nTimeout) {
00188             pc.putc('x');
00189             debug_log ( "PC error 1\n" );
00190             out_ACK = 0;
00191             infoLed = 0;
00192             break;
00193         };
00194         
00195         // then wait for busy to go UP 
00196         nTimeout = 50000; // max wait
00197         while ( !in_BUSY && (nTimeout--) ) {
00198             wait_us (10);
00199         }
00200         if (!nTimeout) {
00201             pc.putc('x');
00202             debug_log ( "PC error 2\n" );
00203             out_ACK = 0;
00204             infoLed = 0;
00205             break;
00206         };
00207         
00208         // data successfully received by PC
00209         // acknowledge before next nibble
00210         out_ACK = 0;
00211         infoLed = 0;
00212     } 
00213     debug_log ( "\nsend complete\n" );
00214     out_D_OUT = 0;
00215     out_D_IN  = 0;     
00216     out_SEL_2 = 0;     
00217     out_SEL_1 = 0;
00218 }
00219 
00220 void inDataReady ( void ) {
00221     
00222     pc.putc('c');
00223     // Command processing starts here ...
00224     debug_log ( "\nProcessing...\n" ) ;
00225     if ( inBufPosition > 0 ) {
00226         debug_log ( "inBufPosition %d...\n", inBufPosition) ; 
00227         // Verify checksum
00228         checksum=0;
00229         for (int i=0;i<inBufPosition-1;i++) {
00230             checksum = (inDataBuf[i]+checksum) & 0xff;
00231         }   
00232         debug_log ( "checksum 0x%02X vs 0x%02X\n" ,  checksum, inDataBuf[inBufPosition-1]); 
00233         if ( checksum == inDataBuf[inBufPosition-1]) {
00234             // processing command
00235             pc.printf(" 0x%02X\n\r", inDataBuf[0]);
00236             debug_log ( "command 0x%02X\n" , inDataBuf[0]); 
00237             outDataTicker.detach();   // safety ?       
00238             
00239             // decode and process commands
00240             ProcessCommand ();  
00241             inBufPosition = 0;
00242                        
00243             if ( outBufPosition > 0 ) {
00244                 // data ready for sending 
00245                 debug_log ( "dataout %u [%02X] -%d\n" , outBufPosition, checksum, in_BUSY); 
00246                 outDataPointer = 0;
00247                 highNibbleOut = false;
00248                 // 
00249                 irq_BUSY.fall(NULL);
00250                 irq_BUSY.rise(NULL);
00251                 
00252                 // This should be asynchronous?
00253                 testOutputSequence();
00254                 
00255             } else {
00256                 pc.putc('x');
00257                 debug_log ( "data prepare error\n"); 
00258             }
00259             
00260         } else
00261         {
00262             pc.putc('x');
00263             debug_log ( "checksum error\n"); 
00264         }
00265     }
00266 }
00267 
00268 void inNibbleReady ( void ) {
00269     // test lines
00270     char inNibble = ( in_SEL_1 + (in_SEL_2<<1) + (in_D_OUT<<2) + (in_D_IN<<3) );
00271     //debug_log ( "(%d) %01X \n", highNibbleIn, inNibble ) ; 
00272     if ( out_ACK == 0 ) {
00273         wait_us ( NIBBLE_DELAY_1 );
00274         out_ACK = 1;
00275         infoLed = 1;
00276         ackOffTimeout.attach( &ackOff, ACK_TIMEOUT ); // max time high ack
00277         if ( highNibbleIn ) {
00278             highNibbleIn = false;
00279             inDataBuf[inBufPosition] = (inNibble << 4) + inDataBuf[inBufPosition];
00280             checksum = (inDataBuf[inBufPosition] + checksum) & 0xff;
00281             //debug_log(" %u:%02X [%02X]\n", inBufPosition, inDataBuf[inBufPosition], checksum ) ;
00282             inBufPosition++; // should be circular for safety; may cut off data!
00283             // Data processing starts after last byte (timeout reset at each byte received) 
00284             inDataReadyTimeout.attach_us( &inDataReady, IN_DATAREADY_TIMEOUT );
00285         } else {
00286             highNibbleIn = true;
00287             inDataBuf[inBufPosition] = inNibble;
00288             //debug_log ( " %01X\n", inDataBuf[inBufPosition] ) ; 
00289         }
00290     } else {
00291         pc.putc('x');
00292         debug_log ( "inNibbleReady out_ACK!=0\n" ) ;
00293     }
00294 }
00295 
00296 void inNibbleAck ( void ) {
00297     // test lines
00298     //debug_log ( "ack (%01X)\n\r", ( in_SEL_1 + (in_SEL_2<<1) + (in_D_OUT<<2) + (in_D_IN<<3) )) ; 
00299     if ( out_ACK == 1 ) {
00300         wait_us ( NIBBLE_ACK_DELAY );
00301         out_ACK = 0;
00302         infoLed = 0;
00303     } else {
00304         pc.putc('x');
00305         debug_log ( "inNibbleAck out_ACK!=1\n" ); 
00306     }
00307 }
00308 
00309 // Serial bit receive
00310 void bitReady ( void ) {
00311     uint32_t nTimeout;
00312     
00313     if ( out_ACK == 1 ) {
00314         bool bit;
00315         wait_us ( BIT_DELAY_1 );
00316         bit = in_D_OUT; // get bit value
00317         //pc.putc(0x30+bit);pc.putc(' ');
00318         //sprintf ( (char*)debugLine, " bit %d: %d\n\r",  bitCount, bit ); 
00319         out_ACK = 0; // bit has been received
00320         infoLed = 0;
00321         deviceCode>>=1;
00322         if (bit) deviceCode|=0x80;
00323         if ((bitCount=(++bitCount)&7)==0) {
00324             // 8 bits received
00325             irq_BUSY.rise(NULL); // detach this IRQ
00326             pc.printf("d 0x%02X\n",deviceCode);
00327             debug_log ( "Device ID 0x%02X\n", deviceCode ); 
00328             if ( deviceCode == 0x41 ) {
00329                 // Sharp-PC is looking for a CE140F (device code 0x41) - Here we are!
00330                 sprintf ( (char*)debugLine, "%d CE140F\n\r", mainTimer.read_us()); strcat ((char*)debugBuf, (char*)debugLine) ;
00331                 inBufPosition = 0;
00332                 highNibbleIn = false;
00333                 checksum = 0;
00334                 // set data handshake triggers on the BUSY input
00335                 irq_BUSY.fall(&inNibbleAck);
00336                 irq_BUSY.rise(&inNibbleReady);
00337                 // check for both BUSY and X_OUT to go down, before starting data receive
00338                 nTimeout = 100000; // timeout: 1s
00339                 while ( ( in_X_OUT || in_BUSY ) && (nTimeout--) ) {
00340                     wait_us (10);
00341                 }
00342                 if (nTimeout) {
00343                     // ... start data handling ...
00344                     out_ACK = 1;
00345                     infoLed = 1;
00346                     wait_us ( DATA_WAIT );
00347                     out_ACK = 0;
00348                     infoLed = 0;
00349                 } else {
00350                     pc.putc('x');
00351                     debug_log ("Timeout!\n\r") ;
00352                 }
00353 
00354             } 
00355         } else {
00356             wait_us ( BIT_DELAY_2 );
00357             out_ACK = 1; // ready for a new bit
00358             infoLed = 1;
00359             ackOffTimeout.attach( &ackOff, ACK_TIMEOUT ); // max time high ack
00360         }
00361     }
00362 }
00363 
00364 void startDeviceCodeSeq ( void ) {
00365     
00366     wait_us (BIT_DELAY_1);
00367     if ( in_D_OUT == 1 ) {
00368         // Device Code transfer starts with both X_OUT and DOUT high
00369         // (X_OUT high with DOUT low is for cassette write)
00370         
00371         infoLed = 1;
00372         out_ACK = 1;
00373         ackOffTimeout.attach( &ackOff, ACK_TIMEOUT ); // max time high ack
00374         
00375         bitCount = 0;
00376         deviceCode = 0;
00377         sprintf ( (char*)debugBuf, "Device\n\r" ); 
00378 
00379         wait_us (ACK_DELAY) ;   //?? or, wait AFTER eabling trigger ??
00380         // serial bit trigger
00381         irq_BUSY.rise(&bitReady);
00382         irq_BUSY.fall(NULL);
00383         wait_us (ACK_DELAY) ;
00384     
00385     }
00386 }
00387 
00388 
00389 int main(void) {
00390     uint8_t i = 20;
00391 
00392     pc.baud ( 9600 ); 
00393     pc.printf ( "CE140F emulator init\n\r" );
00394     while (i--) { infoLed =! infoLed; wait_ms(20); }
00395     
00396     btn.rise(&btnRaised);
00397     inBufPosition = 0;
00398     
00399     // default input pull-down
00400     in_BUSY.mode(PullDown);
00401     in_D_OUT.mode(PullDown);
00402     in_X_OUT.mode(PullDown);
00403     in_D_IN.mode(PullDown);
00404     in_SEL_2.mode(PullDown);
00405     in_SEL_1.mode(PullDown);    
00406     
00407     // default outputs
00408     out_ACK = 0;
00409     out_D_OUT = 0;
00410     out_D_IN  = 0;     
00411     out_SEL_2 = 0;     
00412     out_SEL_1 = 0;
00413 
00414     // initial triggers (device sequence handshake)
00415     irq_X_OUT.rise(&startDeviceCodeSeq);
00416     
00417     mainTimer.reset();
00418     mainTimer.start();
00419     //sprintf ( (char*)debugBuf, "Start\n\r" );
00420     
00421     while (1) {
00422         wait (1); // logic handled with interrupts and timers
00423     }
00424 }