Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed SDFileSystem
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 }
Generated on Tue Jul 19 2022 14:03:17 by
1.7.2