Jump to content

Photo

libti99 RS232 code needs some slight debugging.


6 replies to this topic

#1 tschak909 OFFLINE  

tschak909

    River Patroller

  • 3,088 posts
  • Location:USA

Posted Fri Feb 8, 2019 4:34 PM

Hey guys,

 

As some of you know, I've been writing a PLATO terminal emulator and have ported it over to the TI-99/4A, thus far, it has successfully been running on TIPI enabled machines, with excellent results.

 

It also works under the TI994W emulator, with RS232/1 emulation.

 

HOWEVER,

 

any form of real RS232 hardware, be it the PHP1700 sidecar, or the NanoPEBv1, the terminal refuses to receive or transmit any data.

 

I'm thinking the port may be initialized incorrectly, but I am not sure...

 

So I'm splaying out the source code for the routines I am using from Tursi's libti99, and maybe there may be something that was missed.

 

The relevant code in PLATOTERM is in io.c:

#include "io.h"
#include "protocol.h"
#include "vdp.h"
#include "conio.h"
#ifdef RS232
#include "rs232.h"
#endif
#ifdef TIPI
#include "tipi_msg.h"
#include "ti_socket.h"
#endif

BaudRate io_baud_rate;

void io_init(void)
{
#ifdef RS232
  rs232_setcontrol(RS232_CARD,RS232_9902A,RS232_CTRL_STOP_1|RS232_CTRL_NO_PARITY|RS232_CTRL_8_BIT);
  rs232_setbps(RS232_CARD,RS232_9902A,RS232_BPS_1200);
  io_baud_rate=BAUD_1200;
#endif
}

void io_set_baud_rate(void)
{
  #ifdef RS232
  int new_baud_rate;
  switch(io_baud_rate)
    {
    case BAUD_300:
      new_baud_rate=RS232_BPS_300;
      break;
    case BAUD_1200:
      new_baud_rate=RS232_BPS_1200;
      break;
    case BAUD_2400:
      new_baud_rate=RS232_BPS_2400;
      break;
    case BAUD_4800:
      new_baud_rate=RS232_BPS_4800;
      break;
    case BAUD_9600:
      new_baud_rate=RS232_BPS_9600;
      break;
    case BAUD_19200:
      new_baud_rate=RS232_BPS_19200;
      break;
    case BAUD_38400:
      new_baud_rate=RS232_BPS_38400;
      break;
    }
  rs232_setbps(RS232_CARD,RS232_9902A,new_baud_rate);
#endif
}

void io_toggle_baud_rate(void)
{
#ifdef RS232
  if (io_baud_rate==BAUD_38400)
    io_baud_rate=BAUD_300;
  else
    io_baud_rate++;
  io_set_baud_rate();
#endif
}

void io_send_byte(int b)
{
#ifdef RS232
  rs232_writebyte(RS232_CARD,RS232_9902A,b);
#endif
}

void io_main(void)
{
#ifdef RS232
  int ib;
  unsigned char b;
  if (rs232_poll(RS232_CARD,RS232_9902A))
    {
      ib=rs232_readbyte(RS232_CARD,RS232_9902A);
      b=ib;
      ShowPLATO(&b,1);
    }
#endif
}

void io_done()
{
}

and pulling down into the rs232 code, each of these functions, is a C wrapper which follows the same pattern:

* Activate card

* do its thing

* Deactivate card

 

rs232_setcontrol.c

// RS232 code for the TI-99/4A by Tursi
// You can copy this file and use it at will ;)

#include "rs232.h"

// sets the specified line format, use the RS232_CTRL_xxx bits
void rs232_setcontrol(int card, int uart, int control) {
    int rawCRU = rs232raw_getuart(card, uart);

    __asm__ (
        "  mov %0,r12\n"        // get the rawcru address
        "  sbo 31\n"            // reset
        "  sbz 21\n"            // rts/cts interrupts off
        "  sbz 20\n"            // timer ints off
        "  sbz 19\n"            // tx int off
        "  sbz 18\n"            // rx int off
        "  sbz 17\n"            // clear abort/BREAK
        "  sbz 15\n"            // clear loopback test mode
        "  sbo 14\n"            // request to write control word
        "  swpb %1\n"           // get the byte into the msb
        "  ldcr %1,8\n"         // write it
        "  swpb %1\n"           // fix the reg in case gcc wants it

        : : "r"(rawCRU), "r"(control) : "r12"
    );

    rs232raw_deactivateCard(card);
}

rs232_setbps.c

// RS232 code for the TI-99/4A by Tursi
// You can copy this file and use it at will ;)

#include "rs232.h"

// set the bitrate on the card and uart (sets both directions the same)
void rs232_setbps(int card, int uart, int bps) {
    int rawCRU = rs232raw_getuart(card, uart);

    __asm__ (
        "  mov %0,r12\n"        // get the rawcru address
        "  sbo 12\n"            // request write to recv rate
        "  ldcr %1,11\n"        // load recv rate (auto-decrements to send rate)
        "  ldcr %1,11\n"        // load send rate (Nouspikel says you can do both at once, but safer this way)
        : : "r" (rawCRU), "r" (bps) : "r12"
    );

    rs232raw_deactivateCard(card);
}

rs232_writebyte.c

// RS232 code for the TI-99/4A by Tursi
// You can copy this file and use it at will ;)

#include "rs232.h"

// writes a byte to the specified serial port - returns 0 if the byte could not be written
// (because the write register is full)
int rs232_writebyte(int card, int uart, int ch) {
    int rawCRU = rs232raw_getuart(card, uart);
    if (rs232raw_checkstatus(rawCRU) & 0x02) {
        rs232raw_writebyte(rawCRU, ch);
        rs232raw_deactivateCard(card);
        return 1;
    } else {
        rs232raw_deactivateCard(card);
        return 0;
    }
}

rs232_readbyte.c

// RS232 code for the TI-99/4A by Tursi
// You can copy this file and use it at will ;)

#include "rs232.h"

// reads a byte from the specified serial port, blocks - so always check rs232_poll first!
int rs232_readbyte(int card, int uart) {
    int ret;
    int rawCRU = rs232raw_getuart(card, uart);

    // infinite loop, so poll before you call me!
    while (!rs232raw_poll(rawCRU)) { }
    ret = rs232raw_readbyte(rawCRU);

    rs232raw_deactivateCard(card);

    return ret;
}

rs232_poll.c

// RS232 code for the TI-99/4A by Tursi
// You can copy this file and use it at will ;)

#include "rs232.h"

// test if a byte is available at the specied serial port (returns 0 if not, other value if so)
int rs232_poll(int card, int uart) {
    int ret;
    int rawCRU = rs232raw_getuart(card, uart);
    ret = rs232raw_poll(rawCRU);
    rs232raw_deactivateCard(card);

    return ret;
}

Now, each of these, calls various raw functions, including rs232raw_getuart() which is, supposed to activate the card.

// RS232 code for the TI-99/4A by Tursi
// You can copy this file and use it at will ;)

#include "rs232.h"

// activates the card, and calculates and returns the correct uart rawCRU address for
// the rest of the raw functions. You MUST call deactivateCard when done!
int rs232raw_getuart(int card, int uart) {
    rs232raw_activateCard(card);
    return card+uart;
}

rs232raw_activateCard.c

// RS232 code for the TI-99/4A by Tursi
// You can copy this file and use it at will ;)

#include "rs232.h"

// turns off the card and the card LED
void rs232raw_activateCard(int card) {
    __asm__ (
        "mov %0,r12\n\tsbo 0\n\rsbo 7" : : "r"(card) : "r12"
    );
}

and the corresponding rs232raw_deactivateCard.c

// RS232 code for the TI-99/4A by Tursi
// You can copy this file and use it at will ;)

#include "rs232.h"

// turns off the card and the card LED
void rs232raw_deactivateCard(int card) {
    __asm__ (
        "mov %0,r12\n\tsbz 7\n\rsbz 0" : : "r" (card) : "r12"
    );
}

rs232raw_poll.c

// RS232 code for the TI-99/4A by Tursi
// You can copy this file and use it at will ;)

#include "rs232.h"

// test if a byte is available at the specied serial port (returns 0 if not, other value for true)
int rs232raw_poll(int rawCRU) {
    int ret;

    __asm__ (
        "MOV %1,R12\n\tCLR %0\n\tTB 21\n\tJNE NCH\n\tSETO %0\nNCH" : "=rm" (ret) : "r" (rawCRU) : "r12"
    );

    return ret;
}

rs232raw_geterrs.c

// RS232 code for the TI-99/4A by Tursi
// You can copy this file and use it at will ;)

#include "rs232.h"

// return the error bits from the specified port (we don't check the timer here)
// 0x01 = reception error (set for any of the other three)
// 0x02 = parity error
// 0x04 = overflow error (receive data lost)
// 0x08 = frame error (line corruption or incorrect line format)
int rs232raw_geterrs(int rawCRU) {
    int ret;

    __asm__ (
        "mov %1,r12\n\tai r12,18\n\tclr %0\n\tstcr %0,4\n\tswpb %0" : "=rm" (ret) : "r" (rawCRU) : "r12"
    );

    return ret;
}

rs232raw_checkstatus.c

// RS232 code for the TI-99/4A by Tursi
// You can copy this file and use it at will ;)

#include "rs232.h"

// check the TX and RX status
// 0x01 = receive buffer contains a byte
// 0x02 = transmit buffer empty
// 0x04 = transmission line clear
// 0x08 = timer error (not used in this code)
// 0x10 = time elapsed (not used in this code)
// 0x20 = RTS (inverted)
// 0x40 = DSR (inverted)
// 0x80 = CTS (inverted)
int rs232raw_checkstatus(int rawCRU) {
    int ret;

    __asm__ (
        "mov %1,r12\n\tai r12,42\n\tclr %0\n\tstcr %0,8\n\tswpb %0" : "=rm" (ret) : "r" (rawCRU) : "r12"
    );

    return ret;
}

rs232raw_readbyte.c

// RS232 code for the TI-99/4A by Tursi
// You can copy this file and use it at will ;)

#include "rs232.h"

// reads a byte from the specified serial port - whatever is there. Does not check or
// block, so if you need correct data do a poll first!
int rs232raw_readbyte(int rawCRU) {
    int ret;

    __asm__ (
        "  mov %1,r12\n"        // get rawCRU
        "  clr %0\n"            // clear rx register
        "  stcr %0,8\n"         // get byte
        "  swpb %0\n"           // make LSB
        "  sbz 18\n"            // reset rx flag
        : "=rm" (ret) : "r" (rawCRU) : "r12"
    );

    return ret;
}

rs232raw_writebyte.c

// RS232 code for the TI-99/4A by Tursi
// You can copy this file and use it at will ;)

#include "rs232.h"

// writes a byte to the specified serial port - does not check the transmission register!
// this does manipulate RTS/DCD since everyone does ;)
void rs232raw_writebyte(int rawCRU, int ch) {
    __asm__ (
        "  mov %0,r12\n"        // get rawCRU
        "  sbo 16\n"            // set RTS low (this is what the card and FlipSide did...? maybe enables the write?)
        "  swpb %1\n"           // get the value into the MSB
        "  ldcr %1,8\n"         // write the byte
        "  sbz 16\n"            // set RTS high (will happen after transmission)
        /* "  swpb %1\n"                // fix the reg in case gcc wants it */
        : : "r" (rawCRU), "r" (ch) : "r12"
    );
}

....sorry for the huge pastes, but I'm really scratching my head here, I'm not sure what's wrong, as I'm not familiar with the behavior of the underlying UART or I/O subsystem enough to be able to diagnose.. can anyone provide some insight?

 

Thanks in advance,

-Thom



#2 arcadeshopper ONLINE  

arcadeshopper

    River Patroller

  • 4,178 posts
  • Location:Portland, Oregon USA

Posted Fri Feb 8, 2019 5:30 PM

probably should be in the development section maybe the admin/mods can move it there



#3 FarmerPotato OFFLINE  

FarmerPotato

    Moonsweeper

  • 257 posts
  • Location:Austin, TX

Posted Fri Feb 8, 2019 6:48 PM

Could it be your RS232 cable?  Does it work with other software? (like TI BASIC)

 

Here is one source of pinout info: http://www.nouspikel...titechpages.htm



#4 tschak909 OFFLINE  

tschak909

    River Patroller

  • Topic Starter
  • 3,088 posts
  • Location:USA

Posted Fri Feb 8, 2019 7:17 PM

oh crap, I did put it in the wrong section. sigh. it's been a long day.

 

@FarmerPotato, the cable is verified and working with multiple other programs.

 

-Thom



#5 arcadeshopper ONLINE  

arcadeshopper

    River Patroller

  • 4,178 posts
  • Location:Portland, Oregon USA

Posted Fri Feb 8, 2019 11:37 PM

Could it be your RS232 cable?  Does it work with other software? (like TI BASIC)
 
Here is one source of pinout info: http://www.nouspikel...titechpages.htm

I tried it on my set up which works fine with fast term and no data seems to be sent out

Sent from my LG-V530 using Tapatalk

#6 Tursi OFFLINE  

Tursi

    Quadrunner

  • 5,486 posts
  • HarmlessLion
  • Location:BUR

Posted Sun Feb 10, 2019 4:51 AM

Wrong section or not, let me copy out what I sent to Thom earlier tonight... I rebuilt my PEB and sat down to look at it. I confirmed that the configuration was wrong and poked around my docs until I found the original document I wrote my BBS from 28 years ago (Genial!)

The code in that document relied on a precise sequence of initialization, which I had of course removed when I did the library, so basically nothing went to the right place. I updated the library to set the configuration bits directly instead of making assumptions, and it seems to work now. Since it worked in TI99W, I suspect that TI99W either doesn't set all four register selection bits on reset or it clears them all after a register write (but that's a guess).

#7 tschak909 OFFLINE  

tschak909

    River Patroller

  • Topic Starter
  • 3,088 posts
  • Location:USA

Posted Thu Feb 14, 2019 6:19 PM

It looks like even with a tiny test harness (that outputs everything it sees immediately), I am missing characters. :( shit.

 

-Thom






0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users