You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This isn't really an 'issue' so can be closed by Mr Mockba, but I thought I might write some notes about the code that was changed to enable Kermit file transfers.
The board I am using is called ESPDUINO-32 and if you google this and select images, you can see it is an arduino form factor. I specifically went for the one with the large USB socket as this is plugged and unplugged many times and is mechanically stronger than the small ones. This particular board is not listed in the arduino IDE but it seems to compile ok with many of the ones that are listed. I used the first board in the list which is called ESP332 Dev Module.
Near the beginning of the RunCPM module are some ifdef's, I changed the pins for the SD card to 19,23 and 18, the CS pin is 5, and the led is on pin 2.
#elif defined ESP32 // ESP32 boards
SdFatSoftSpiEX<19, 23, 18> SD; // MISO, MOSI, SCK Some boards use 2,15,14,13, other 12,14,27,26
#define SDINIT 5 // CS
#define LED 2 // TTGO_T1=22 LOLIN32_Pro=5(inverted) DOIT_Esp32=2 ESP32-PICO-KIT=no led, Espduino pin 2
#define LEDinv 0
#define BOARD "ESPDUINO-32"
in void setup() I added the two new serial ports (the ESP32 has three uarts. Just a thought here, the DUE has 4 ports so this idea could also work on that board too).
For hardware I used Max3232 modules available on ebay. Run from the 3V3 pin. In keeping with the old-skool spirit, computers have male D9 plugs and devices (modems, terminals) are female D9. The female Max3232 modules are much more common - I had to search a bit to get the male ones. I made a crossover cable with two female sockets and pin 5 to 5, 2 to 3 and 3 to 2. I also had some modules with faults - some wouldn't work, and one had crosstalk between Tx and Rx so characters printed twice on the screen. I've also had some dodgy max3232 chips before and found that in this case it may be worth getting these from a big supplier like Radio Spares or Element 14 or similar.
I got a copy of generic Kermit from Columbia University. It is in the CP/M archives. This needs no modification at all. If anyone has problems getting this I'll post a copy here.
Below is a wall of code. This goes in the abstraction_arduino.h file. It needs to go above the console abstraction functions (I think this is because functions need to be declared before you use them, and this applies in .h files but not .ino files. ). Once this code is copied in, test everything still compiles ok. None of this should affect compilation as it isn't linked yet to any of the existing code.
// ***************************** Physical Device List **************************************
//CON: = TTY: CRT: BAT: UC1:
//RDR: = TTY: PTR: UR1: UR2:
//PUN: = TTY: PTP: UP1: UP2:
//LST: = TTY: CRT: LPT: UL1:
// TTY
void deviceTTYout(uint8_t ch) // same as _putch
{
Serial1.write(ch); // same as _putch but with buffer overflow protection
while (Serial1.availableForWrite() < 20) {
delay(100); // at 9600 baud, ESP32 output buffer is 128 bytes, if stops when only 20 chars left in the output buffer, and pause 100ms, then have about 115 left as sending about 1 per ms.
}
}
uint8_t deviceTTYavailable(void) { // same as _kbhit
return(Serial1.available());
}
uint8_t deviceTTYin(void) { // same as _getch
while (!Serial1.available());
return(Serial1.read());
}
uint8_t deviceTTYinEcho(void) { // same as _getche
uint8_t ch = deviceTTYin();
deviceTTYout(ch);
return(ch);
}
// CRT
void deviceCRTout(uint8_t ch) // same as _putch
{
Serial.write(ch); // same as _putch but with buffer overflow protection
while (Serial.availableForWrite() < 20) {
delay(100); // at 9600 baud, ESP32 output buffer is 128 bytes, if stop when only 20 chars left in the output buffer, and pause 100ms, then have about 115 left as sending about 1 per ms.
}
}
uint8_t deviceCRTavailable(void) { // same as _kbhit
return(Serial.available());
}
uint8_t deviceCRTin(void) { // same as _getch
while (!Serial.available());
return(Serial.read());
}
uint8_t deviceCRTinEcho(void) { // same as _getche
uint8_t ch = deviceCRTin();
deviceCRTout(ch);
return(ch);
}
// UR1
uint8_t deviceUR1in(void) {
uint8_t ch = 26;
return ch;
}
// UP1
void deviceUP1out(uint8_t ch) {
// add code here
}
// BAT, console device, input and output and can see if characters waiting, input used by Kermit as the default input device
void deviceBATout(uint8_t ch)
{
Serial2.write(ch); // same as _putch but with buffer overflow protection
while (Serial2.availableForWrite() < 20) {
delay(100); // at 9600 baud, ESP32 output buffer is 128 bytes, if stop when only 20 chars left in the output buffer, and pause 100ms, then have about 115 left as sending about 1 per ms.
}
}
uint8_t deviceBATavailable(void) {
return(Serial2.available());
}
uint8_t deviceBATin(void) {
while (!Serial2.available());
return(Serial2.read());
}
uint8_t deviceBATinEcho(void) {
uint8_t ch = deviceBATin();
deviceBATout(ch);
return(ch);
}
// UC1, console device
void deviceUC1out(uint8_t ch)
{
// add code here
}
uint8_t deviceUC1available(void) {
return(1); // add code here
}
uint8_t deviceUC1in(void) {
return(26); // add code here
}
uint8_t deviceUC1inEcho(void) {
uint8_t ch = deviceUC1in();
deviceUC1out(ch);
return(ch);
}
// PTR, reader device
uint8_t devicePTRin(void) {
return 26; // add code here
}
// UR2, reader device
uint8_t deviceUR2in(void) {
return 26; // add code here
}
// PTP, punch device
void devicePTPout(uint8_t ch) {
Serial2.write(ch); // used by Kermit as the default output device
while (Serial2.availableForWrite() < 20) {
delay(100); // at 9600 baud, if stop when only 20 chars left, and pause 100ms, then have about 115 left, as sending about 1 per ms. Should not need to do this if using small packets with Kermit
}
}
// UP2, punch device
void deviceUP2out(uint8_t ch) {
// add code here - eg write to file
}
// UL1, LST device
void deviceUL1out(uint8_t ch) {
// add code here - eg write to file
}
// LPT, LST device
void deviceLPTout(uint8_t ch) {
// add code here
}
// *************************************
// redirection for CON RDR PUN and LST eg CONin, CONout, CONavailable directed to one of four places depending on IOBYTE.
uint8_t iobyteCON()
{
uint8_t iobyte;
iobyte = _RamRead(0x0003);
iobyte = iobyte & 0x03; // mask off 00000011
return iobyte;
}
uint8_t iobyteRDR()
{
uint8_t iobyte;
iobyte = _RamRead(0x0003);
iobyte = iobyte & 0x0C; // mask off 00001100
iobyte = iobyte >> 2; // bitshift so low 2 bits
return iobyte;
}
uint8_t iobytePUN()
{
uint8_t iobyte;
iobyte = _RamRead(0x0003);
iobyte = iobyte & 0x30; // mask off 00110000
iobyte = iobyte >> 4; // bitshift so low 2 bits
return iobyte;
}
uint8_t iobyteLST()
{
uint8_t iobyte;
iobyte = _RamRead(0x0003);
iobyte = iobyte & 0xC0; // mask off 11000000
iobyte = iobyte >> 6; // bitshift so low 2 bits
return iobyte;
}
//CON: = TTY: CRT: BAT: UC1:
void outCON(uint8_t ch)
{
uint8_t iobyte;
iobyte = iobyteCON(); // 00, 01 10, 11
switch (iobyte) {
case 0: deviceTTYout(ch);
break;
case 1: deviceCRTout(ch);
break;
case 2: deviceBATout(ch);
break;
case 3: deviceUC1out(ch);
break;
}
}
uint8_t availableCON()
{
uint8_t iobyte;
uint8_t dataAvailable;
iobyte = iobyteCON(); // 00, 01 10, 11
switch (iobyte) {
case 0: dataAvailable = deviceTTYavailable();
break;
case 1: dataAvailable = deviceCRTavailable();
break;
case 2: dataAvailable = deviceBATavailable();
break;
case 3: dataAvailable = deviceUC1available();
break;
}
return dataAvailable;
}
uint8_t inCON(void)
{
uint8_t iobyte;
uint8_t dataIn;
iobyte = iobyteCON(); // 00, 01 10, 11
switch (iobyte) {
case 0: dataIn = deviceTTYin();
break;
case 1: dataIn = deviceCRTin();
break;
case 2: dataIn = deviceBATin();
break;
case 3: dataIn = deviceUC1in();
break;
}
return dataIn;
}
uint8_t echoCON()
{
uint8_t ch;
ch = inCON();
outCON(ch);
return(ch);
}
//RDR: = TTY: PTR: UR1: UR2:
uint8_t inRDR(void)
{
uint8_t iobyte;
uint8_t dataIn;
iobyte = iobyteRDR(); // 00, 01 10, 11
switch (iobyte) {
case 0: dataIn = deviceTTYin();
break;
case 1: dataIn = devicePTRin();
break;
case 2: dataIn = deviceUR1in();
break;
case 3: dataIn = deviceUR2in();
break;
}
return dataIn;
}
//PUN: = TTY: PTP: UP1: UP2:
void outPUN(uint8_t ch)
{
uint8_t iobyte;
iobyte = iobytePUN(); // 00, 01 10, 11
switch (iobyte) {
case 0: deviceTTYout(ch);
break;
case 1: devicePTPout(ch);
break;
case 2: deviceUP1out(ch);
break;
case 3: deviceUP2out(ch);
break;
}
}
//LST: = TTY: CRT: LPT: UL1:
void outLST(uint8_t ch)
{
uint8_t iobyte;
iobyte = iobyteLST(); // 00, 01 10, 11
switch (iobyte) {
case 0: deviceTTYout(ch);
break;
case 1: deviceCRTout(ch);
break;
case 2: deviceLPTout(ch);
break;
case 3: deviceUL1out(ch);
break;
}
}
Next is to change the console code so that instead of, say, sending a character to the Serial port, instead, redirect it to the code above. I found it safer when debugging to comment out code rather than delete it, so you can see what has been changed.
/* Console abstraction functions */
/*===============================================================================*/
uint8_t _kbhit(void) {
//return(Serial.available());
return availableCON(); // redirect based on iobyte
}
uint8_t _getch(void) {
//while (!Serial.available());
//return(Serial.read());
return inCON(); // redirect based on iobyte
}
uint8_t _getche(void) {
//uint8_t ch = _getch();
//Serial.write(ch);
//return(ch);
return echoCON(); // redirect based on iobyte
}
void _putch(uint8_t ch) {
//Serial.write(ch);
outCON(ch); // redirect based on iobyte
}
void _clrscr(void) {
Serial.println("\e[H\e[J"); // done once at startup so left as is
}
Looking back through the code. I think that is pretty much it. I did end up adding in a tiny bit of code in the cpm.h bdos function to redirect to the reader device, however in the code above the reader device doesn't do anything. But this does give an idea how to add in other devices.
/*
C = 3 : Auxiliary (Reader) input
Returns: A=Char
*/
case 3:
#ifdef ESP32
HL = inRDR();
#else
HL = 0x1a; // ^Z end file
#enif d
break;
Commented out the ioport ramwrite setting in cpm.h and moved it to the void setup() routine in RunCPM. I am not sure if this has been changed in a recent update. I did a clean install on 11th August and rebuilt it using these instructions and this did need to be changed. _RamWrite(0x0003, 0x3D);
Thinking how to use the ports, Grant Searle has a system where the first character that comes in defines which port is being used. I am thinking of something even simpler. For debugging the iobyte is set at startup so CON goes to CRT on the USB serial port. Once a board is working and it is going in a box, recompile with the iobyte set at startup to TTY which is on Serial 1. The box I am making has a hole for the USB socket so you can plug that in and that is for programming and for using a PC terminal program. Then a male D9 for TTY and that goes to a physical terminal (eg a PropTerm, or a Raspberry Pi, or one using an Arduino Uno). And the second male D9 is BAT: and that is for file transfers. I have some vague ideas that the 4th port could be something to do with Wifi or Bluetooth as these are both on the ESP32.
One small bug I am working on - kermit works rock solid between two boards, but when using teraterm with a kermit transfer, it seems to have many dropped packets. This is true at baud rates from 1200 to 115200. I have tried different Max3232 modules, different USB to serial devices and different boards. I haven't tried different terminal programs. This may not be such an issue, because the huge advantage of RunCPM over all other real and emulated CP/M systems is that it uses Fat32 files on the SD card. Thanks++ to Mr Borg for this :)
The text was updated successfully, but these errors were encountered:
Sorry, one more bit that needs adding from the bdos. The punch output needs to be redirected. This bit is a bit messy as I simply commented out the part that redirects to files. ?? redirect to files except on the esp32. Or put in an elif if the disk redirect is not selected. I'm not sure about how to add this. In any case the generic version of Kermit sends output to the punch device, and receives data via a redirected console device.
case 4:
//#ifdef USE_PUN
// if (!pun_open) {
// pun_dev = _sys_fopen_w((uint8*)pun_file);
// pun_open = TRUE;
// }
// if (pun_dev)
// _sys_fputc(LOW_REGISTER(DE), pun_dev);
//#endif
#ifdef ESP32
outPUN(LOW_REGISTER(DE));
#endif
break;
/*
C = 5 : Printer output
*/
case 5:
//#ifdef USE_LST
// if (!lst_open) {
// lst_dev = _sys_fopen_w((uint8*)lst_file);
// lst_open = TRUE;
// }
// if (lst_dev)
// _sys_fputc(LOW_REGISTER(DE), lst_dev);
//#endif
#ifdef ESP32
outLST(LOW_REGISTER(DE));
#endif
break;
This isn't really an 'issue' so can be closed by Mr Mockba, but I thought I might write some notes about the code that was changed to enable Kermit file transfers.
The board I am using is called ESPDUINO-32 and if you google this and select images, you can see it is an arduino form factor. I specifically went for the one with the large USB socket as this is plugged and unplugged many times and is mechanically stronger than the small ones. This particular board is not listed in the arduino IDE but it seems to compile ok with many of the ones that are listed. I used the first board in the list which is called ESP332 Dev Module.
Near the beginning of the RunCPM module are some ifdef's, I changed the pins for the SD card to 19,23 and 18, the CS pin is 5, and the led is on pin 2.
For hardware I used Max3232 modules available on ebay. Run from the 3V3 pin. In keeping with the old-skool spirit, computers have male D9 plugs and devices (modems, terminals) are female D9. The female Max3232 modules are much more common - I had to search a bit to get the male ones. I made a crossover cable with two female sockets and pin 5 to 5, 2 to 3 and 3 to 2. I also had some modules with faults - some wouldn't work, and one had crosstalk between Tx and Rx so characters printed twice on the screen. I've also had some dodgy max3232 chips before and found that in this case it may be worth getting these from a big supplier like Radio Spares or Element 14 or similar.
I got a copy of generic Kermit from Columbia University. It is in the CP/M archives. This needs no modification at all. If anyone has problems getting this I'll post a copy here.
Below is a wall of code. This goes in the abstraction_arduino.h file. It needs to go above the console abstraction functions (I think this is because functions need to be declared before you use them, and this applies in .h files but not .ino files. ). Once this code is copied in, test everything still compiles ok. None of this should affect compilation as it isn't linked yet to any of the existing code.
Commented out the ioport ramwrite setting in cpm.h and moved it to the void setup() routine in RunCPM. I am not sure if this has been changed in a recent update. I did a clean install on 11th August and rebuilt it using these instructions and this did need to be changed.
_RamWrite(0x0003, 0x3D);
Thinking how to use the ports, Grant Searle has a system where the first character that comes in defines which port is being used. I am thinking of something even simpler. For debugging the iobyte is set at startup so CON goes to CRT on the USB serial port. Once a board is working and it is going in a box, recompile with the iobyte set at startup to TTY which is on Serial 1. The box I am making has a hole for the USB socket so you can plug that in and that is for programming and for using a PC terminal program. Then a male D9 for TTY and that goes to a physical terminal (eg a PropTerm, or a Raspberry Pi, or one using an Arduino Uno). And the second male D9 is BAT: and that is for file transfers. I have some vague ideas that the 4th port could be something to do with Wifi or Bluetooth as these are both on the ESP32.
One small bug I am working on - kermit works rock solid between two boards, but when using teraterm with a kermit transfer, it seems to have many dropped packets. This is true at baud rates from 1200 to 115200. I have tried different Max3232 modules, different USB to serial devices and different boards. I haven't tried different terminal programs. This may not be such an issue, because the huge advantage of RunCPM over all other real and emulated CP/M systems is that it uses Fat32 files on the SD card. Thanks++ to Mr Borg for this :)
The text was updated successfully, but these errors were encountered: