Jump to content
IGNORED

#AtariWiFi - an Atari Network Adapter


tschak909

Recommended Posts

This project is currently in development.

 

ARDUINO CODE FOR THIS PROJECT IS HERE:

https://github.com/tschak909/atariwifi

 

I have been working for the last week and a half after getting @mozzwald's ESP12E prototype board on a new firmware that I want to turn an ESP8266 into a full fledged network adapter for the Atari 8-Bit.

 

I've talked about this on Facebook, and other places, but to quickly re-cap:

 

THIS IS NOT SOLELY AN ESP8266 MODEM EMULATOR.

 

The goal, is to make a useful network adapter for the Atari 8-bit systems, making an ESP8266 talk SIO protocol. This means that the network device can not only do the work of other WiFi modems, it can also handle reading and writing (including booting) of disks over the network (or Internet), using the TNFS protocol which is being borrowed from the Spectranet (ZX Spectrum network adapter) project, and it can also provide a high-level (CIO) interface to TCP/UDP/HTTP communication via an N: device, allowing for easy to write networking programs in BASIC or other languages.

 

so yeah:

 

"D:" for emulated disks over network

"R:" for wi-fi modem emulation

"N:" for Networking and adapter control tasks.

 

This provides a networking solution for the Atari 8-bit that does useful things out of the box.

 

It is way too early to talk about getting hardware out there, but if you would like to help code the firmware and/or test, then we can talk about getting hardware out there.

 

I have been writing lots of small test programs to figure out various issues.

 

Currently, the hardware has successfully booted Jumpman from its internal SPIFFS flash:

 

and I am currently in the middle of trying to do successful communication over UDP to a TNFS server. If anyone wants to help with writing a TNFS implementation in Arduino, the spec is here: http://spectrum.alioth.net/svn/filedetails.php?repname=Spectranet&path=%2Ftrunk%2Ftnfs%2Ftnfs-protocol.txt

 

and the test program for what I am currently doing with TNFS is here:

https://github.com/tschak909/atariwifi/blob/master/tests/tnfs/tnfs.ino

 

More to come, and am actively looking for volunteers to help write code and test things.

-Thom

  • Like 15
  • Thanks 1
Link to comment
Share on other sites

Something like this: (This is an early case/board from @mozzwald.) it is way too early to talk about distributing these, except for people who will help bring-up the device.

 

Image

 

Image

 

And keep in mind, I am genuinely asking, because while I am capable of accomplishing this single-handedly, I'd like to involve the community to help not only get this out faster, but to help bootstrap getting things written for it to use.

 

-Thom

 

  • Like 1
Link to comment
Share on other sites

Test #6 was successful, where I was attempting to connect to a TNFS server and read 128 byte sectors from a disk image:

 

While I did specify all the states, I did not implement close, or umount, as the test proved successful enough to move forward, but you can see what it takes to pull sectors down from the network:

 

/**
   Test #6 - See if we can make an ESP8266 talk TNFS!
*/

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

#define TNFS_SERVER "192.168.1.7"
#define TNFS_PORT 16384

enum {MOUNT, OPEN, READ, CLOSE, UMOUNT, DONE} tnfs_state=MOUNT;

WiFiUDP UDP;


byte tnfsPacket[512];
int tnfsPacketLen = 0;
byte tnfsReadfd=0;
byte tnfsRetryCount=0;
byte session_idl;
byte session_idh;
int start;
int dur;
int totalLen=0;
int sector;

/**
   Setup.
*/
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("#AtariWiFi Test #6: TNFS client");
  Serial.print("Connecting to WiFi...");
  WiFi.begin("Cherryhomes", "e1xb64XC46");

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Connected.");

  Serial.println("Initializing UDP.");
  UDP.begin(16384);
}

/**
 * Mount
 */
void tnfs_mount()
{
  memset(tnfsPacket,0,sizeof(tnfsPacket));
  tnfsPacket[0]=0x00;       // Session ID
  tnfsPacket[1]=0x00;       // "   "
  tnfsPacket[2]=tnfsRetryCount++; // Retry Count
  tnfsPacket[3]=0x00;       // Command
  tnfsPacket[4]=0x01;       // vers
  tnfsPacket[5]=0x00;       // "  "
  tnfsPacket[6]=0x00;       // Flags
  tnfsPacket[7]=0x00;       // "  "
  tnfsPacket[8]=0x2F;       // '/'
  tnfsPacket[9]=0x00;       // NUL terminated

  Serial.printf("Mounting / from %s, Attempt #%d\n\n",TNFS_SERVER,tnfsRetryCount);

  UDP.beginPacket(TNFS_SERVER,TNFS_PORT);
  UDP.write(tnfsPacket,10);
  UDP.endPacket();

  start=millis();
  dur=millis()-start;

  while (dur < 5000)
  {
    if (UDP.parsePacket())
    {
      int l=UDP.read(tnfsPacket,sizeof(tnfsPacket));
      if (tnfsPacket[4]==0)
      {
        // Successful
        Serial.printf("Successful. Version %d.%d - Session ID: 0x%02x%02x, Suggested Timeout: %d ms.\n",tnfsPacket[6],tnfsPacket[5],tnfsPacket[1],tnfsPacket[0],tnfsPacket[7]+256*tnfsPacket[8]);
        session_idl=tnfsPacket[0];
        session_idh=tnfsPacket[1];
        tnfs_state=OPEN;
        return;
      }
      else
      {
        // Error
        Serial.printf("Error #%02x\n",tnfsPacket[4]);
        return;
      }
    }
  }
  Serial.printf("Request timed out. Retrying...\n\n"); 
}

/**
 * Open
 */
void tnfs_open()
{
  int i=0;
  memset(tnfsPacket,0,sizeof(tnfsPacket));
  tnfsPacket[i++]=session_idl;       // Session ID
  tnfsPacket[i++]=session_idh;       // "   "
  tnfsPacket[i++]=tnfsRetryCount++; // Retry Count
  tnfsPacket[i++]=0x29;       // Command (open)
  tnfsPacket[i++]=0x01;       // Mode 1 (R/O)
  tnfsPacket[i++]=0x00;       // "  "
  tnfsPacket[i++]=0x01;       // Flags
  tnfsPacket[i++]=0x00;       // "  "
  tnfsPacket[i++]=0x2F;       // '/'
  tnfsPacket[i++]='j';        // Filename
  tnfsPacket[i++]='u';        //
  tnfsPacket[i++]='m';        //
  tnfsPacket[i++]='p';        //
  tnfsPacket[i++]='m';        //
  tnfsPacket[i++]='a';        //
  tnfsPacket[i++]='n';        //
  tnfsPacket[i++]='.';        //
  tnfsPacket[i++]='x';        //
  tnfsPacket[i++]='f';        //
  tnfsPacket[i++]='d';        //
  tnfsPacket[i++]=0x00;       // NUL terminated
  tnfsPacket[i++]=0x00;       // No username
  tnfsPacket[i++]=0x00;       // No password
  
  Serial.printf("Opening '/jumpman.xfd' read-only, Attempt #%d\n\n",tnfsRetryCount);

  UDP.beginPacket(TNFS_SERVER,TNFS_PORT);
  UDP.write(tnfsPacket,i);
  UDP.endPacket();

  start=millis();
  dur=millis()-start;

  while (dur < 5000)
  {
    if (UDP.parsePacket())
    {
      int l=UDP.read(tnfsPacket,sizeof(tnfsPacket));
      if (tnfsPacket[4]==0)
      {
        // Successful
        Serial.printf("Open successful, FD #%02x",tnfsPacket[5]);
        tnfsReadfd=tnfsPacket[5];
        tnfs_state=READ;
        sector=0;
        return;
      }
      else
      {
        // Error
        Serial.printf("Error #%02x\n",tnfsPacket[4]);
        return;
      }
    }
  }
  Serial.printf("Request timed out. Retrying...\n\n"); 
}


/**
 * Open
 */
void tnfs_read()
{
  int i=0;
  memset(tnfsPacket,0,sizeof(tnfsPacket));
  tnfsPacket[i++]=session_idl;       // Session ID
  tnfsPacket[i++]=session_idh;       // "   "
  tnfsPacket[i++]=tnfsRetryCount++; // Retry Count
  tnfsPacket[i++]=0x21;       // read
  tnfsPacket[i++]=tnfsReadfd;       // fd
  tnfsPacket[i++]=0x80;       // 128 bytes
  tnfsPacket[i++]=0x00;       // "   "
  
  Serial.printf("Reading next sector...\n\n");

  UDP.beginPacket(TNFS_SERVER,TNFS_PORT);
  UDP.write(tnfsPacket,i);
  UDP.endPacket();

  start=millis();
  dur=millis()-start;

  while (dur < 5000)
  {
    if (UDP.parsePacket())
    {
      int l=UDP.read(tnfsPacket,sizeof(tnfsPacket));
      if (tnfsPacket[4]==0)
      {
        // Successful
        Serial.printf("Sector #%d\n",sector++);
        for (i=7;i<135;i++)
        {
          Serial.printf("%02x ",tnfsPacket[i]);
          if (i%16==0)
            Serial.printf("\n");
        }
          
        if (totalLen>92160)
          tnfs_state=CLOSE;
        else
          totalLen+=128;
        return;
      }
      else
      {
        // Error
        Serial.printf("Error #%02x\n",tnfsPacket[4]);
        tnfs_state=CLOSE;
        return;
      }
    }
  }
  Serial.printf("Request timed out. Retrying...\n\n"); 
}

/**
   The main state machine.
*/
void loop() {

  switch (tnfs_state)
  {
    case MOUNT:
      tnfs_mount();
      break;
    case OPEN:
      tnfs_open();
      break;
    case READ:
      tnfs_read();
      break;
    case CLOSE:
      break;
    case UMOUNT:
      break;
    case DONE:
      break;
  }
}

Example output:

AtariWiFi Test #6: TNFS client
Connecting to WiFi......Connected.
Initializing UDP.
Mounting / from 192.168.1.7, Attempt #1

Successful. Version 1.0 - Session ID: 0x0029, Suggested Timeout: 1000 ms.
Opening '/jumpman.xfd' read-only, Attempt #2

Open successful, FD #00Reading next sector...

Sector #0
00 03 00 07 40 15 d8 a2 0c bd 
55 07 9d ff 02 ca d0 f7 20 53 e4 10 03 4c 35 07 
18 ad 04 03 69 80 8d 04 03 ad 05 03 69 00 8d 05 
03 ee 0a 03 c9 0a d0 e0 4c 00 08 a9 4c 8d 44 03 
a9 07 8d 45 03 a9 0a 8d 48 03 a2 00 20 56 e4 4c 
06 07 42 4f 4f 54 20 45 52 52 4f 52 30 01 52 40 
00 08 30 00 80 00 02 00 a5 44 69 00 8d 05 03 85 
44 60 8d 0b 03 8c 0a 03 a9 52 a0 40 90 04 a9 50 
a0 80 8d 02 03 8c Reading next sector...

Sector #1
a9 ee 8d 30 02 a9 08 8d 31 02 
a9 c6 8d c4 02 a9 0f 8d c5 02 a9 96 8d c6 02 a9 
03 85 cb a9 10 85 cc a2 00 a0 00 bd 0c 09 91 cb 
e8 c8 c0 04 d0 f5 18 a5 cb 69 0a 85 cb e0 40 d0 
e8 ad fc 9f f0 08 ad fc bf f0 03 4c 51 08 4c e0 
09 ea ea ea ea ea ea a5 6a c9 80 90 7c a2 0c bd 
4b 09 38 e9 20 9d ad 10 ca d0 f4 20 e4 08 ad d0 
09 8d 0a 03 ad d1 09 8d 0b 03 ad d4 09 8d 04 03 
ad d5 09 8d 05 03 Reading next sector...

Sector #2
20 53 e4 30 2c 18 ad 04 03 69 
80 8d 04 03 ad 05 03 69 00 8d 05 03 ee 0a 03 d0 
03 ee 0b 03 ad 0b 03 cd d3 09 d0 da ad 0a 03 cd 
d2 09 d0 d2 6c d6 09 a2 28 bd a7 09 38 e9 20 9d 
9f 10 ca d0 f4 4c d0 08 a2 28 bd 57 09 38 e9 20 
9d 9f 10 ca d0 f4 4c d0 08 a2 28 bd 7f 09 38 e9 
20 9d 9f 10 ca d0 f4 4c d0 08 c6 ce ea d0 fb c6 
cf d0 f7 60 70 70 70 70 70 70 48 00 10 08 08 08 
08 08 08 08 08 08 Reading next sector...

Sector #3
08 08 08 08 08 08 70 70 02 41 
ee 08 00 a0 0c 03 02 82 0f ff 0a a8 0c 03 22 80 
0c 03 82 80 0c 03 02 a8 0f ff 08 08 0c 03 20 0a 
0c 03 80 00 0c 03 00 00 0f ff 02 80 0c 03 02 80 
0c 03 00 00 0c 03 55 55 5f ff 44 44 4c 47 55 55 
5d 57 50 4c 45 41 53 45 20 57 41 49 54 2e 20 20 
20 20 20 20 50 4c 45 41 53 45 20 52 45 4d 4f 56 
45 20 41 4c 4c 20 43 41 52 54 52 49 44 47 45 53 
20 20 20 20 20 20 Reading next sector...

Now to marry this to the SIO test code (did this before I started this thread) to try and boot Jumpman off of the Internet. :)

-Thom

 

  • Like 5
Link to comment
Share on other sites

11 minutes ago, tschak909 said:

it's okay, pls understand, what I am doing right now are writing test programs.

 

These aren't production programs at all, but just the bare minimum to try and find potential problems, and do so as fast as I can. :)

 

If you want to hack on the code, please do! :)

 

-Thom

Cosign with @manterola we both played around with an ESP board a lot at Fujiyama .

I have another 3 weeks of vacation but my C experience dates back from 1994, and although I can handle reading code (Perl/Bash/C/Assembler/Python) to fix small fuckups at work, I'm not fluent enough to spit out working code as fast as you currently are doing :)

 

Out of interest and as a *NIX geek and network engineer, I do like the approach you are taking with this all-in-one device so I might be tempted to follow your code

along the way.

 

I got the same NodeMCU , what other parts do I need to replicate this setup ?
From mozzwald's schematic here 

 

I can see I would need the TTL shifter and a 1N4148 but what are the other parts (I'm an absolute noob regarding electronics) ?
Which 2 resistors ?

Link to comment
Share on other sites

@mozzwald and @jeffpiep are currently going back and forth on the schematic, we've been trying to make it powered by the Atari, but may have to drop this. We're currently all talking in a twitter group-message and stuff is going back and forth very quickly. 

 

Paging @mozzwald as he may be able to fill in the answers here. I have been getting boards from him and testing as I go along. 

 

My test rig snapped a wire due to a broken crimp, so a replacement is coming very soon. I went ahead and wrote test #7 in the mean time.

 

-Thom

Link to comment
Share on other sites

8 hours ago, Lastic said:

Cosign with @manterola we both played around with an ESP board a lot at Fujiyama .

I have another 3 weeks of vacation but my C experience dates back from 1994, and although I can handle reading code (Perl/Bash/C/Assembler/Python) to fix small fuckups at work, I'm not fluent enough to spit out working code as fast as you currently are doing :)

 

Out of interest and as a *NIX geek and network engineer, I do like the approach you are taking with this all-in-one device so I might be tempted to follow your code

along the way.

 

I got the same NodeMCU , what other parts do I need to replicate this setup ?
From mozzwald's schematic here 

 

I can see I would need the TTL shifter and a 1N4148 but what are the other parts (I'm an absolute noob regarding electronics) ?
Which 2 resistors ?

This is the last schematic posted by mozzwald in that thread.  The resistors appear to be 1K each.  He is calling for a 1N5819 Schottky diode instead of the 1N4148. 

 

image.thumb.png.5e917398721536a01a82dd5483617e26.png

Link to comment
Share on other sites

7 hours ago, Lastic said:

I got the same NodeMCU , what other parts do I need to replicate this setup ?
From mozzwald's schematic here 

 

I can see I would need the TTL shifter and a 1N4148 but what are the other parts (I'm an absolute noob regarding electronics) ?
Which 2 resistors ?

The biggest change to hardware is the fact that we no longer need the level shifter as the esp8266 is 5V *LOGIC* tolerant. The GPIO pins can handle voltages up to 5V, but the device must be powered with 3.3V still. This has actually been confirmed by the CEO of Espressif (on facebook of all places, see the comments in this link https://www.facebook.com/groups/1499045113679103/permalink/1731855033731442/?hc_location=ufi).

 

The current schematic is below.

sio-modem-nodemcu_01.thumb.jpg.0c9604d31aba9f1152ec66d53af14fb2.jpg

The switch allows the device to be powered from the SIO 5V or from the MicroUSB port on the nodemcu, the diode prevents USB power from entering the SIO bus.

 

The current topic of debate is with GPIO15 which if pulled HIGH when the esp8266 is powered on prevents it from booting normally. The 2k pull down resistor allows the esp8266 to boot, but pulls down DATAIN on the SIO bus to around 3.5V, iirc. This may or may not cause an issue with other devices on the chain. I tried and failed to get a NPN/Resistor/Capacitor pulldown to work.

 

At any rate, the above schematic is tested working with 3 boards I have made.

  • Like 1
Link to comment
Share on other sites

8 hours ago, Lastic said:

 

I can see I would need the TTL shifter and a 1N4148 but what are the other parts (I'm an absolute noob regarding electronics) ?
Which 2 resistors ?

A NodeMCU will work all by itself with not extra components as long as it's the only thing on the SIO bus. Just make the same pin assignments as the schematic.

Link to comment
Share on other sites

Holy crap, it worked!

Credit goes to @Mozzwald for this video, as this is his setup, my board interface broke, the day before, so I was unable to do this test.

This is the #AtariWiFi interface booting a copy of Jumpman off of a hosted server on DigitalOcean (therefore, over the Internet). The disk image is being hosted by a TNFS server running there.

The reason the beeps are so slow is literally because of the round trip of debug messages appearing in the ESP8266 serial monitor, with these disabled, the boot time is almost as fast as a real disk drive.

The next test program will be implementing a track buffer to improve performance.

My god, this is so awesome! 

 

This is with debug messages on:

 

This is with them turned off, data gathered from this suggests that some sector buffering is in order.

 

That's what the next test program will focus on.

-Thom

  • Like 14
Link to comment
Share on other sites

@mozzwald @jeffpiep thanks for the thorough explanation but like I said I'm an electronics noob.
As such I won't be wasting too much of your time since you are clearly busier and way more technical than I am :)


If I use only the NodeMCU on the SIO port are these connections correct ?

More specifically SIO 5V can go directly to Vin ?

The SIO GND pins 4 and 6 should both be connected ? To which of the 3 GND's on the NodeMCU or doesn't that matter ?

 

GPIO SIO
5 13
4 9
Vin 10
GND ? 4/6
16 8
12 7
13 5
15 3
Link to comment
Share on other sites

6 hours ago, mozzwald said:

The biggest change to hardware is the fact that we no longer need the level shifter as the esp8266 is 5V *LOGIC* tolerant. The GPIO pins can handle voltages up to 5V, but the device must be powered with 3.3V still. This has actually been confirmed by the CEO of Espressif (on facebook of all places, see the comments in this link https://www.facebook.com/groups/1499045113679103/permalink/1731855033731442/?hc_location=ufi).

 

The current schematic is below.

sio-modem-nodemcu_01.thumb.jpg.0c9604d31aba9f1152ec66d53af14fb2.jpg

The switch allows the device to be powered from the SIO 5V or from the MicroUSB port on the nodemcu, the diode prevents USB power from entering the SIO bus.

 

The current topic of debate is with GPIO15 which if pulled HIGH when the esp8266 is powered on prevents it from booting normally. The 2k pull down resistor allows the esp8266 to boot, but pulls down DATAIN on the SIO bus to around 3.5V, iirc. This may or may not cause an issue with other devices on the chain. I tried and failed to get a NPN/Resistor/Capacitor pulldown to work.

 

At any rate, the above schematic is tested working with 3 boards I have made.

Is the MSK12C02 of some special design, or just what was in the parts bin?  I'm not finding that part # on either Mouser or Digikey.

Link to comment
Share on other sites

Fantastic project, great work Thomas. I am definately going to try build one of these (for PAL my 600XL and 800XL).

 

Would love to contribute code / testing / 3D case designs etc, but will probably not get the time (too many other projects that I am obliged to finish first).

Link to comment
Share on other sites

7 hours ago, Lastic said:

If I use only the NodeMCU on the SIO port are these connections correct ?

More specifically SIO 5V can go directly to Vin ?

The SIO GND pins 4 and 6 should both be connected ? To which of the 3 GND's on the NodeMCU or doesn't that matter ?

 

GPIO SIO
5 13
4 9
Vin 10
GND ? 4/6
16 8
12 7
13 5
15 3

Your table is correct. Any single GND on the Nodemcu can go to either GND on SIO. Vin can go directly to 5V on SIO, but make sure you do not connect the Nodemcu Microusb to anything while it's plugged into the Atari or you will be pushing power back into it. If you add diode D2 (Schottky, ie 1N5819) then this is not an issue:

           D2

Vin-----|<-----SIO5V

  • Like 1
Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...