bozimmerman/Zimodem

Using Zimodem/c64net from cc65?

MartinEmrich opened this issue · 4 comments

Hi!

Just dusted off my good old C64 and soldering iron, and built myself a c64net adapter (using this schematic: https://www.c64-wiki.de/wiki/Wifi-Adapter (the schematic at the bottom).

I got the demo programs included in Zimodem working, and took a look at some telnet BBSes... Yay!

Now I try to write some software to use it, using cc65, I want to interact with a service running on my PC.

I use some code found here: https://coronax.wordpress.com/2015/01/06/figuring-out-commodore-64-rs-232/ (the last comment at the bottom of the page).
Apparently the cbm_k_* functions are wrappers around the Kernal routines, essentially doing the same as OPEN 2,.., PRINT#2, GET#2 etc.

But I run in some issues: as soon as the connection to my server (simple TCP service running on my PC) is established, I sometimes receive junk characters, sometimes I see parts of the text sent by the server.
Looks like baud rate/handshake/transmission issues. (I rule out ASCII/PETSCII conversion issues, I only send the string "alive" so far, some times it is even received correctly)

Now I am confused:

  • Are the Kernal routines supposed to work at all? (I found several posts on the internet stating they are buggy). Don't the example programs use them, too?
  • Is Zimodem 3.4 with the schematic I use capable of hardware handshake? the D1/D2 pins are connected to User Port PB1/PB6. Do the Kernal routines support hardware handshake?
  • I tried both hardware and software handshake (second byte of OPEN filename both 0x00 and 0x01, and both ATF0 and ATF1) and see no real difference.
  • If someone knows cc65: How do I do non-blocking I/O? I see no means of clearing/flushing the receive buffer, If no more characters are waiting, reading from the serial port blocks...

Thanks,

Martin

  1. Yes. The kernal routines should work fine. The sample disk that comes with the firmware uses the kernal in both BASIC (in some examples) and ML (in most).
  2. You'll have to compare the pin assignments of your schematic with ours to answer that first question.
    2a. No, the C64 kernal does not manage hardware handshaking, you need to do that by hand. The typical way is to watch the two buffer index registers to see how full or empty the buffer is, and alter the UP pins accordingly.
  3. AFAIK, the kernal doesn't manage software handshaking either. Also needs to be done manually. I've tried SWHS in programs like Novaterm in ATF1 mode, and it definitely works. Novaterm can also prove hardware HS as well.
  4. Can't help you there, man., as I only program Commodore software on Commodore computers (and then use a conversion tool to publish on github).

Oh, the earlier problem definitely sounds like a baud rate issue, but it might also be a buffer overflow issue? It's hard to say from way over here.

Thanks... Buffer issues are unlikely, my little TCP test service sends only a few bytes.

But my current assumption is that the code generated by cc65 somehow meddles around with interrupts or timing, conflicting with the kernal serial routines. I'll investigate in that direction.

I made some progress, maybe someone will find this helpful:

I had no success with using the Kernal routines from my C program. I also had issues from BASIC; while INPUT# works fine, repeatedly calling GET# also returned garbled characters.

Then I found a serial driver for cc65 at https://github.com/nanoflite/c64-up2400-cc65.
The catch: it only supports 2400baud. It apparently also only works if the Kernal serial routines have not been initialized, so I was unable to switch Zimodem from 1200 to 2400baud "on the fly" first.

I thus switched my board to 2400baud permanently via the USB terminal on my PC (open serial monitor with 1200baud, enter ATB2400, switch to 2400baud, then enter AT&W to save permanently).

Now this little program works:

#include <conio.h>
#include <stdio.h>
#include <unistd.h>
#include <serial.h>
#include <string.h>

void test_port()
{
    /* Warning: c64-up2400 _only_ supports 2400baud (source: 
       https://modelrail.otenko.com/electronics/commodore-64-serial-interface-to-arduino) */

    const struct ser_params sp = {SER_BAUD_2400, SER_BITS_8, SER_STOP_1, SER_PAR_NONE, SER_HS_NONE};
    unsigned char i = 0;
    const unsigned char *cmd = "ATI5\r\n";
    unsigned char rc = 0;
    unsigned char c = 0;

    printf("Loading driver...");
    rc = ser_load_driver("c64-up2400.ser");
    printf("Result: %u\n", rc);
    if (rc != 0)
    {
        printf("Loading failed, aborting.");
        /* check if the driver is on your floppy with the correct name:
           c64-up2400.ser (all caps on LOAD"$",8) */
        return;
    }

    // open serial port
    rc = ser_open(&sp);
    printf("ser_open rc=%u\n", rc);

    // enable serial (Source: http://www.cbmstuff.com/forum/printthread.php?tid=353)
    rc = ser_ioctl(1, NULL);
    printf("ser_ioctl rc=%u\n", rc);

    // send some command
    i = 0;
    do
    {
        do
        {
            rc = ser_put(cmd[i]);
            if (rc == SER_ERR_OVERFLOW)
            {
                printf("overflow\r");
            }
        } while (rc == SER_ERR_OVERFLOW);
        ++i;
    } while (cmd[i] != 0);

    printf("sent %s\n", cmd);

    // read response
    while (1)
    {
        rc = ser_get(&c);
        if (rc != SER_ERR_NO_DATA)
        {
            printf("%c", c);
            //printf("Got: %c (0x%02x)\r", c, c);
        }
    }
}

void main()
{
    test_port();
}

Cheers,
Martin