Connecting Arduino Uno to Vietnam War teletype

Hello All,

I would really appreciate some assistance with my project as there is not much online that I can find.

I recently finished restoring a 1960s Kleinschmidt teletypewriter TT4C/TG that was used by the Army during the Vietnam War. I have the machine working and now I am trying to connect it to my computer through an Arduino Uno. The Arduino controls a relay and the relay controls the 110vDC current loop for the teletype. The relay has an input voltage range of 3.5-32vDC so I can directly connect it to the 5v output pins of the Arduino.

The teletype works on baudot code, which is similar to morse code and a precursor to ASCII (I think). Baudot code uses ‘mark’ and ‘space’, just like morse code uses dots and dashes, except there is no difference in time. A mark, or marking impulse, opens the current loop circuit for 22ms and a space, or spacing impulse, closes the circuit for 22ms. These occur in groups of five with a start and stop, and the teletype converts them into a letter or figure and prints it on the paper roll. For example, the letter R is: start, space, mark, space, mark, space, stop. The letter Y is: start, mark, space, mark, space, mark, stop.

The idea is to use the Arduino to convert a letter input from the serial communicator to baudot code through the relay. In theory, if you type the letter ‘R’ into the serial the Arduino then turns the output pin off for 22ms, then on for 22ms, then off for 22ms, etc.

The base for my code comes from this video: Arduino Morse Code Translator - YouTube

There are two main challenges I need assistance with:

1. The output pin stays HIGH regardless of whether there is anything in the serial. If send a letter through the serial, the pin does not go LOW for the time it should.
2. When there is nothing in the serial I need the output pin to be HIGH so the current loop circuit is complete, otherwise the teletype goes a bit funny. I was originally going to include the line ‘digitalWrite (4, HIGH)’ in the loop section of the code, but I think that would cancel out the translating function so I removed it. If anyone knows how I would write this in code please let me know!

Any assistance would be great! Thank you!

Here is my code (I have removed letters D-Z and all numbers and figures due to the forum’s character limit but they all follow the same pattern as A, B, and C):

//NOTE: INPUT TO SERIAL MUST BE ALL CAPS
//NOTE: INPUT TO SERIAL MUST NOT CONTAIN APOSTROPHES
//NOTE: ALWAYS END SENTENCE WITH FULL STOP

String BaudotCode = "";              //string to store input from serial monitor
byte BaudotCodeLength = 0;          //byte to store length of BaudotCode
char i;                             // char for parsing of BaudotCode
int relay = 4;                      //relay output is set to pin 4

//--------------------------------------------------------------------
//                                  SETUP
//---------------------------------------------------------------

void setup() {
  // put your setup code here, to run once:
  
  pinMode(relay, OUTPUT);           //output to arduino relay
 
  Serial.begin(9600);               //turn on serial monitor at 9600 baud
  
}

//-------------------------------------------------------------------
//                                  FUNCTIONS
//-----------------------------------------------------------------


void START(){
  digitalWrite(relay, LOW);             //start impuse set to turn relay off for 22 milliseconds
  delay(22); 
}

void MARKING_IMPULSE(){
  digitalWrite(relay, HIGH);            //mark impuse set to turn relay on for 22 milliseconds
  delay(22);
}

void SPACING_IMPULSE(){
  digitalWrite(relay, LOW);             //space impuse set to turn relay off for 22 milliseconds
  delay(22);
}

void STOP(){
  digitalWrite(relay, HIGH);            //stop impuse set to turn relay on for 31 milliseconds
  delay(31);
}

void LTRS_SHIFT(){
  digitalWrite(relay, LOW);              //start impulse
  delay(22);
  digitalWrite(relay, HIGH);             //five marking impulses and a stop impulse
  delay(141);
}

void FIGS_SHIFT(){
  digitalWrite(relay, LOW);             //start impulse
  delay(22);
  digitalWrite(relay, HIGH);            //two marking impulses
  delay(44);
  digitalWrite(relay, LOW);             //one space impulse
  delay(22);
  digitalWrite(relay, HIGH);            //two marking impulses and a stop impulse
  delay(75);
}

void CAR_RET(){
  digitalWrite(relay, LOW);             //start impulse and three spacing impulses
  delay(88);
  digitalWrite(relay, HIGH);            //one marking impulse
  delay(22);
  digitalWrite(relay, LOW);             //one space impulse
  delay(22);
  digitalWrite(relay, HIGH);            //stop impulse
  delay(31);
}

void LINE_FEED(){
  digitalWrite(relay, LOW);             //start impulse and a space impulse
  delay(44);
  digitalWrite(relay, HIGH);            //marking impulse
  delay(22);
  digitalWrite(relay, LOW);             //three spacing impulses
  delay(66);
  digitalWrite(relay, HIGH);            //stop impulse
  delay(31);
}

void translate(){                   //translate character to baudot code
  switch(i){
    case 'A':                         //if it is an A
    START();                          //start impulse
    MARKING_IMPULSE();                //marking impulse
    MARKING_IMPULSE();                //marking impulse
    SPACING_IMPULSE();                //spacing impulse
    SPACING_IMPULSE();                //spacing impulse
    SPACING_IMPULSE();                //spacing impulse
    STOP();                           //stop impulse
   break;
   case 'B':
    START();
    MARKING_IMPULSE();
    SPACING_IMPULSE(); 
    SPACING_IMPULSE();
    MARKING_IMPULSE();
    MARKING_IMPULSE();              
    STOP();
   break;
   case 'C':
    START();
    SPACING_IMPULSE();
    MARKING_IMPULSE();
    MARKING_IMPULSE();
    MARKING_IMPULSE();
    SPACING_IMPULSE();
    STOP();
   break;
   
  }
}

void doString(){                         //parse the string
  BaudotCodeLength = BaudotCode.length();          //determine the length of the string
  for(int x = 0;x<=BaudotCodeLength;x++){     //repeat parsing until end of the string
    i = BaudotCode.charAt(x);                 //get charachter at position x
    translate();                         //translate charachter into baudot code
  }
  }


//----------------------------------------------------------
//                      LOOP
//----------------------------------------------------------

void loop(){
  // put your main code here, to run repeatedly:

  while (Serial.available()) {            //when new information in serial
    char inChar = (char)Serial.read();    //get the new byte
    BaudotCode += inChar;                      //add it to BaudotCode
    if (inChar == 'n') {                  //if receive as CR
      Serial.println(BaudotCode);
      doString();                         //process the string
    }
  }
  delay(1000);                            //delay between strings
  BaudotCode = "";                              //reset string
}

You may get some inspiration from this video Teletype as a Linux terminal and others in the series but there is not much detail as to the use of an Arduino

WARNING : be careful that you don't spend the rest of the day/week exploring the videos on the channel, especially those about the repair and operation of an Apollo Guidance Computer

His videos are fantastic! I have watched all of them on his restoration of the teletype. His means of making it a linux terminal are far beyond my skills, haha.

I have not watched the Apollo guidance computer videos, thank you for the recommendation/warning!

i modified your code. doesn’t look like you can append a char to a String so i modified loop() and doString() to used char strings. Also I think you’re looking for ‘\n’ not ‘n’

i also found a baudot table and added it. Don’t know what characters correspond to Figure and Letter

//NOTE: INPUT TO SERIAL MUST BE ALL CAPS
//NOTE: INPUT TO SERIAL MUST NOT CONTAIN APOSTROPHES
//NOTE: ALWAYS END SENTENCE WITH FULL STOP
String BaudotCode = "";
//string to store input from serial monitor
byte BaudotCodeLength = 0;
//byte to store length of BaudotCode
char i;
// char for parsing of BaudotCode
#if 0
int relay = 4;
#else
int relay = 10;
#endif
//relay output is set to pin 4

// -----------------------------------------------------------------------------
// https://cs.stanford.edu/people/eroberts/courses/soco/projects/2008-09/colossus/baudot.html

struct Baudot {
    char c;
    byte code;
};

Baudot baudot [] = {
    { 'T',   0x1 },
    { '\r',  0x2 },
    { 'O',   0x3 },
    { ' ',   0x4 },
    { 'H',   0x5 },
    { 'N',   0x6 },
    { 'M',   0x7 },
    { '\n',  0x8 },
    { 'L',   0x9 },
    { 'R',   0xA },
    { 'G',   0xB },
    { 'I',   0xC },
    { 'P',   0xD },
    { 'C',   0xE },
    { 'V',   0xF },
    { 'E',   0x10 },
    { 'Z',   0x11 },
    { 'D',   0x12 },
    { 'B',   0x13 },
    { 'S',   0x14 },
    { 'Y',   0x15 },
    { 'F',   0x16 },
    { 'X',   0x17 },
    { 'A',   0x18 },
    { 'W',   0x19 },
    { 'J',   0x1A },
    { 'U',   0x1C },
    { 'Q',   0x1D },
    { 'K',   0x1E },
};

#define N_BAUDOT    (sizeof(baudot)/sizeof(Baudot))

#define NO_BAUDOT   0xFF

// -------------------------------------
byte getBaudotCode (char c)
{
    for (unsigned n = 0; n < N_BAUDOT; n++)
        if (baudot [n].c == c)
            return baudot [n].code;
    
    return NO_BAUDOT;
}

//--------------------------------------------------------------------
//                                  SETUP
//---------------------------------------------------------------
void setup() {
    // put your setup code here, to run once:
    pinMode(relay, OUTPUT); //output to arduino relay
    Serial.begin(9600);     //turn on serial monitor at 9600 baud

    Serial.println ("Baudot");
}

//-------------------------------------------------------------------
//                                  FUNCTIONS
//-----------------------------------------------------------------
void START(){
    digitalWrite(relay, LOW);
    //start impuse set to turn relay off for 22 milliseconds
    delay(22);
}

void MARKING_IMPULSE(){
    digitalWrite(relay, HIGH);
    //mark impuse set to turn relay on for 22 milliseconds
    delay(22);
}

void SPACING_IMPULSE(){
    digitalWrite(relay, LOW);
    //space impuse set to turn relay off for 22 milliseconds
    delay(22);
}

void STOP(){
    digitalWrite(relay, HIGH);
    //stop impuse set to turn relay on for 31 milliseconds
    delay(31);
}

void LTRS_SHIFT(){
    digitalWrite(relay, LOW);
    //start impulse
    delay(22);
    digitalWrite(relay, HIGH);
    //five marking impulses and a stop impulse
    delay(141);
}

void FIGS_SHIFT(){
    digitalWrite(relay, LOW);
    //start impulse
    delay(22);
    digitalWrite(relay, HIGH);
    //two marking impulses
    delay(44);
    digitalWrite(relay, LOW);
    //one space impulse
    delay(22);
    digitalWrite(relay, HIGH);
    //two marking impulses and a stop impulse
    delay(75);
}

void CAR_RET(){
    digitalWrite(relay, LOW);
    //start impulse and three spacing impulses
    delay(88);
    digitalWrite(relay, HIGH);
    //one marking impulse
    delay(22);
    digitalWrite(relay, LOW);
    //one space impulse
    delay(22);
    digitalWrite(relay, HIGH);
    //stop impulse
    delay(31);
}

void LINE_FEED(){
    digitalWrite(relay, LOW);
    //start impulse and a space impulse
    delay(44);
    digitalWrite(relay, HIGH);
    //marking impulse
    delay(22);
    digitalWrite(relay, LOW);
    //three spacing impulses
    delay(66);
    digitalWrite(relay, HIGH);
    //stop impulse
    delay(31);
}

void
sendCode (
    byte code)
{
    START ();
    for (int n = 0; n < 5; n++)  {
        if (0x10 & code) 
            MARKING_IMPULSE();
        else
            SPACING_IMPULSE();
        code <<= 1;
    }
    STOP ();
}

void translate(){                   //translate character to baudot code
    switch(i){
    case 'A':                         //if it is an A
        START();
        //start impulse
        MARKING_IMPULSE();
        //marking impulse
        MARKING_IMPULSE();
        //marking impulse
        SPACING_IMPULSE();
        //spacing impulse
        SPACING_IMPULSE();
        //spacing impulse
        SPACING_IMPULSE();
        //spacing impulse
        STOP();
        //stop impulse
        break;
    case 'B':
        START();
        MARKING_IMPULSE();
        SPACING_IMPULSE();
        SPACING_IMPULSE();
        MARKING_IMPULSE();
        MARKING_IMPULSE();
        STOP();
        break;
    case 'C':
        START();
        SPACING_IMPULSE();
        MARKING_IMPULSE();
        MARKING_IMPULSE();
        MARKING_IMPULSE();
        SPACING_IMPULSE();
        STOP();
        break;

    default:
        byte code = getBaudotCode (i);
        if (NO_BAUDOT != code)
            sendCode (code);
        break;
    }

}

void doString (){                         //parse the string
    BaudotCodeLength = BaudotCode.length();

    char s [80];
    sprintf (s, "%s: [%d] %s", __func__, BaudotCodeLength, BaudotCode.c_str());
    Serial.println (s);

    //determine the length of the string
    for(int x = 0;x<=BaudotCodeLength;x++){     //repeat parsing until end of the string
        i = BaudotCode.charAt(x);
        //get charachter at position x
        translate();
        //translate charachter into baudot code
    }
}

void doCstring (
    char *s )
{                         //parse the string
    int  len = strlen (s);

    char t [80];
    sprintf (t, "%s: [%d] %s", __func__, len, s);
    Serial.println (t);

    for(int n = 0; n < len; n++) {
        i = s [n];
        translate();
        delay (250);
    }
}

//----------------------------------------------------------
//                      LOOP
//----------------------------------------------------------
char str [80];
int  idx = 0;

void
loop (void)
{
    while (Serial.available()) {            //when new information in serial
        char inChar = Serial.read(); //get the new byte
        Serial.print (inChar);

        str [idx++] = inChar;

        if (inChar == '\n') {                  //if receive as CR
            str [idx] = 0;

            Serial.println(BaudotCode);
            doCstring (str);
            idx = 0;
        }
    }
}

// -----------------------------------------------------------------------------
void loop_0(){
    // put your main code here, to run repeatedly:
    while (Serial.available()) {            //when new information in serial
        char inChar = (char)Serial.read(); //get the new byte
        Serial.print (inChar);

        BaudotCode += inChar;               //add it to BaudotCode
#if 0
        if (inChar == 'n') {                  //if receive as CR
#else
        if (inChar == '\n') {                  //if receive as CR
#endif
            Serial.println(BaudotCode);
            doString();
            //process the string
        }

    }

 // delay(1000);
    //delay between strings
    BaudotCode = "";
    //reset string
}

Thank you! I really appreciate it. I will have a go at uploading this to my Arduino and see if I can get it to operate the relay.

Your code worked gcjr!

I had to adjust the timing down from 22 to 15, and I removed the STOP() delay and now it works well!

I will have a go at adding in figures. For that, I need to signal figures shift, and then the corresponding code, and then letters shift. Would that look like:

Baudot baudot [] = {
                                             // Letters A-Z in here
    { '5',  0x1B, 0x1, 0x1F },     //figures shift, then 5, then letters shift to return to letters
    { '9',  0x1B, 0x3, 0x1F },
    { ',',   0x1B, 0x6, 0x1F },
    { '.',   0x1B, 0x7, 0x1F },
    { ')',   0x1B, 0x9, 0x1F },
    { '4',   0x1B, 0xA, 0x1F },
    { '&',   0x1B, 0xB, 0x1F },
    { '8',   0x1B,  0xC, 0x1F },
    { '0',   0x1B, 0xD, 0x1F },
    { ':',   0x1B,  0xE, 0x1F },
    { ';',   0x1B,  0xF, 0x1F },
    { '3',   0x1B,  0x10, 0x1F },
    { '"',    0x1B,  0x11, 0x1F },
    { '

Also, to get super technical, the teletype can only print a line that is 69 characters long before it needs to signal carriage return and line feed. Would this work to make that happen:

void doCstring (
    char *s )
{                         
    int  len = strlen (s);

    char t [80];
    sprintf (t, "%s: [%d] %s", __func__, len, s);
    Serial.println (t);

    for(int n = 0; n < len; n++) {
        i = s [n];
        translate();
        delay (250);

    if(n =69, \n, \r)         //this is the code I want to add to make it signal CR and LF on the 69 char.

    }
}

Thank you!

,  0x1B, 0x12, 0x1F },
    { ‘?’,  0x1B, 0x13, 0x1F },
    { ‘*’,  0x1B, 0x14, 0x1F },    //asterisk used to signal bell
    { ‘6’,  0x1B, 0x15, 0x1F },
    { ‘!’,  0x1B, 0x16, 0x1F },
    { ‘/’,  0x1B, 0x17, 0x1F },
    { ‘-’,  0x1B, 0x18, 0x1F },
    { ‘2’,  0x1B, 0x19, 0x1F },
    { ‘’’,  0x1B, 0x1A, 0x1F },
    { ‘7’,  0x1B, 0x1C, 0x1F },
    { ‘1’,  0x1B, 0x1D, 0x1F },
    { ‘(’,  0x1B, 0x1E, 0x1F },
};


Also, to get super technical, the teletype can only print a line that is 69 characters long before it needs to signal carriage return and line feed. Would this work to make that happen:

§DISCOURSE_HOISTED_CODE_1§


Thank you!

![Thank you gcjr.jpg|431x645](upload://cgsXWHpO9rxys6Q7qNeJont4aJi.jpeg)

Don’t forget to insert a delay after every CR - those heads can take a loooong time to travel!

True indeed, nothing like a modern printer or fax, haha. Luckily gcjr already has it covered! There is a 250ms delay after each cr.

thanks for the note. very nice!

this isn’t right (you don’t want to set “n” to 69)

if(n =69, \n, \r)
if (69 <= n)
     // do what needs to be done

there are several things that could be better even in the code i sent you. One is not rely on a global variable to print allowing you to insert additional characters (\r, \n) in the string you want to display

i cleaned up the code I previously sent you, removing functions I replaced and got rid of translate. I assume you will see the reason if you haven’t done them already.

included change for line limit

you didn’t post the structure for your baudot table so i just used what I had. I believe I understand the need to translate a single char into multiple chars.

//NOTE: INPUT TO SERIAL MUST BE ALL CAPS
//NOTE: INPUT TO SERIAL MUST NOT CONTAIN APOSTROPHES
//NOTE: ALWAYS END SENTENCE WITH FULL STOP

// static String BaudotCode = "";     //string to store input from serial monitor

#if 0
int relay = 4;              //relay output is set to pin 4
#else
int relay = 10;
#endif
// -----------------------------------------------------------------------------
// https://cs.stanford.edu/people/eroberts/courses/soco/projects/2008-09/colossus/baudot.html

#if 1
struct Baudot {
    char c;
    byte code;
};

Baudot baudot [] = {
    { 'T',   0x1 },
    { '\r',  0x2 },
    { 'O',   0x3 },
    { ' ',   0x4 },
    { 'H',   0x5 },
    { 'N',   0x6 },
    { 'M',   0x7 },
    { '\n',  0x8 },
    { 'L',   0x9 },
    { 'R',   0xA },
    { 'G',   0xB },
    { 'I',   0xC },
    { 'P',   0xD },
    { 'C',   0xE },
    { 'V',   0xF },
    { 'E',   0x10 },
    { 'Z',   0x11 },
    { 'D',   0x12 },
    { 'B',   0x13 },
    { 'S',   0x14 },
    { 'Y',   0x15 },
    { 'F',   0x16 },
    { 'X',   0x17 },
    { 'A',   0x18 },
    { 'W',   0x19 },
    { 'J',   0x1A },
    { 'U',   0x1C },
    { 'Q',   0x1D },
    { 'K',   0x1E },
};
#endif

#define N_BAUDOT (sizeof (baudot)/sizeof (Baudot))
#define NO_BAUDOT   0xFF
// -------------------------------------
static byte getBaudotCode (char c)
{
    for (unsigned n = 0; n < N_BAUDOT; n++)
        if (baudot [n].c == c)
            return baudot [n].code;
    return NO_BAUDOT;
}

//--------------------------------------------------------------------
//                                  SETUP
//---------------------------------------------------------------
void setup () {
    pinMode (relay, OUTPUT);     //output to arduino relay
    Serial.begin (9600);         //turn on serial monitor at 9600 baud
    Serial.println ("Baudot");
}

//-------------------------------------------------------------------
//                                  FUNCTIONS
//-----------------------------------------------------------------
#define DELAY1  22
#define DELAY2  31

void START (){
    digitalWrite (relay, LOW);
    //start impuse set to turn relay off for 22 milliseconds
    delay (DELAY1);
}

void MARKING_IMPULSE (){
    digitalWrite (relay, HIGH);
    //mark impuse set to turn relay on for 22 milliseconds
    delay (DELAY1);
}

void SPACING_IMPULSE (){
    digitalWrite (relay, LOW);
    //space impuse set to turn relay off for 22 milliseconds
    delay (DELAY1);
}

void STOP (){
    digitalWrite (relay, HIGH);
    //stop impuse set to turn relay on for 31 milliseconds
    delay (DELAY2);
}

#if 0
void LTRS_SHIFT (){
    digitalWrite (relay, LOW);
    //start impulse
    delay (22);
    digitalWrite (relay, HIGH);
    //five marking impulses and a stop impulse
    delay (141);
}

void FIGS_SHIFT (){
    digitalWrite (relay, LOW);
    //start impulse
    delay (22);
    digitalWrite (relay, HIGH);
    //two marking impulses
    delay (44);
    digitalWrite (relay, LOW);
    //one space impulse
    delay (22);
    digitalWrite (relay, HIGH);
    //two marking impulses and a stop impulse
    delay (75);
}

void CAR_RET (){
    digitalWrite (relay, LOW);
    //start impulse and three spacing impulses
    delay (88);
    digitalWrite (relay, HIGH);
    //one marking impulse
    delay (22);
    digitalWrite (relay, LOW);
    //one space impulse
    delay (22);
    digitalWrite (relay, HIGH);
    //stop impulse
    delay (31);
}

void LINE_FEED (){
    digitalWrite (relay, LOW);
    //start impulse and a space impulse
    delay (44);
    digitalWrite (relay, HIGH);
    //marking impulse
    delay (22);
    digitalWrite (relay, LOW);
    //three spacing impulses
    delay (66);
    digitalWrite (relay, HIGH);
    //stop impulse
    delay (31);
}
#endif

// -----------------------------------------------------------------------------
void
sendCode (
byte code)
{
    START ();
    for (int n = 0; n < 5; n++)  {
        if (0x10 & code)
        MARKING_IMPULSE ();
        else
        SPACING_IMPULSE ();
        code <<= 1;
    }

    STOP ();

#if 0       // to see individual characters
    delay (250);
#endif
}

// -----------------------------------------------------------------------------
void doCstring (
char *s )
{                         //parse the string
    int  len = strlen (s);
    char t [80];
    sprintf (t, "%s: [%d] %s", __func__, len, s);
    Serial.println (t);

    for (int n = 0; n < len; n++) {
        byte code = getBaudotCode (s [n]);
        if (NO_BAUDOT != code)
            sendCode (code);

#define LINE_LEN_LIMIT   69
        if (LINE_LEN_LIMIT == n)  {
            Serial.println ("EOL limit");
            sendCode ('\r');
            sendCode ('\n');
        }
    }
}

//----------------------------------------------------------
//                      LOOP
//----------------------------------------------------------
char str [80];
int  idx = 0;
void
loop (void)
{
    while (Serial.available ()) {            //when new information in serial
        char inChar = Serial.read ();
        //get the new byte
        Serial.print (inChar);
        str [idx++] = inChar;
        if (inChar == '\n') {                  //if receive as CR
            str [idx] = 0;
            doCstring (str);
            idx = 0;
        }

    }

}

would like to see a picture of the teletype

i added a 250 delay to see the individual chars on a LED.

i think you should test for 'r and add a delay

For clarity and simplicity, I might be inclined to do the following:

#define MARK  HIGH  // these could be swapped easily if
#define SPACE LOW  // wiring/logic changed for any reason
...
...

void START ()
{
    digitalWrite (relay, SPACE);
    delay (DELAY1);
}

void MARKING_IMPULSE ()
{
    digitalWrite (relay, MARK);
    delay (DELAY1);
}

void SPACING_IMPULSE ()
{
    digitalWrite (relay, SPACE);
    delay (DELAY1);
}

Thank you both for your assistance, this is going really well!

I’ve attached a couple of photos for you as requested.

I used the new code and after some changes to the delay timing I managed to get it working. I changed DELAY1 from 22 to 15, and DELAY 2 from 31 to 9. With the new code and the timing changes it works almost perfectly, and a lot faster too. The new code is causing the teletype to print 3-4 times faster than the original code and it’s awesome.

To test the teletype I write out the alphabet multiple times, that way I can easily see if there are any errors. It can type out the alphabet accurately and consistently 2-3 times in a row without any issues so I am fairly confident the timing is correct.

I tried inserting a number here but it did not work. Instead of printing the number 5 it printed the letter H. In baudot code, every letter is also a number or symbol and to know the difference the teletype has to be in ‘Figures’ or ‘Letters’ beforehand. I find it easier to keep the teletype in Letters by default. To print a Figure, it needs to receive ‘Figures Shift’ (0x1B) then print the corresponding letter (i.e.: 5 = T, 4 = R, etc), and then receive ‘Letters Shift’ (0x1F) to return to printing letters by default.

Do you know how to do this? My way does not work.

Baudot baudot [] = {
    { 'T',   0x1 },
    { '\r',  0x2 },
    { 'O',   0x3 },
    { ' ',   0x4 },
    { 'H',   0x5 },
    { 'N',   0x6 },
    { 'M',   0x7 },
    { '\n',  0x8 },
    { 'L',   0x9 },
    { 'R',   0xA },
    { 'G',   0xB },
    { 'I',   0xC },
    { 'P',   0xD },
    { 'C',   0xE },
    { 'V',   0xF },
    { 'E',   0x10 },
    { 'Z',   0x11 },
    { 'D',   0x12 },
    { 'B',   0x13 },
    { 'S',   0x14 },
    { 'Y',   0x15 },
    { 'F',   0x16 },
    { 'X',   0x17 },
    { 'A',   0x18 },
    { 'W',   0x19 },
    { 'J',   0x1A },
    { 'U',   0x1C },
    { 'Q',   0x1D },
    { 'K',   0x1E },
    {'5',  "0x1B, 0x1, 0x1F"}, //this was my attempt at the number 5
};

The \n function works perfectly. The \r function does not though, \r causes the teletype to do the same action as \n. I don’t think this is an issue with the teletype as all the other functions work, but it could be.

Probably related to the \r function, but after the 69th character the teletype just prints ‘R’ repeatedly rather than executing the \n and \r codes. I’m a bit stumped on this part as 0x2 is correct for carriage return, but the timing works for all other functions.

I’d keep a global state variable to track whether you’re in letter-shift or numeric-shift.
If you’re about to print a digit, check the state variable, and if you’re already in letter-shift, insert a numeric-shift character before printing the digit.
Don’t forget to change the state variable.

Good thinking, that way if there are a few numbers or symbols to be printed, such as '2020!' the teletype won't jump between Figs and Letters on each, but stay in Figs until it needs to return to letters again.

I'll have a go at some code for that.

thanks for the photo of the machine

I have added in figures and tried to get a global variable working but it has not worked. Here is the full code, I have added the figures to the baudot table and the code just after it.

//NOTE: INPUT TO SERIAL MUST BE ALL CAPS
//NOTE: INPUT TO SERIAL MUST NOT CONTAIN APOSTROPHES

String BaudotCode = "";     //string to store input from serial monitor

#if 0
int relay = 4;              //relay output is set to pin 4
#else
int relay = 10;
#endif
// -----------------------------------------------------------------------------
// https://cs.stanford.edu/people/eroberts/courses/soco/projects/2008-09/colossus/baudot.html

#if 1
struct Baudot {
    char c;
    byte code;
};

Baudot baudot [] = {
    { 'T',   0x1 },
    { '\r',  0x2 },
    { 'O',   0x3 },
    { ' ',   0x4 },
    { 'H',   0x5 },
    { 'N',   0x6 },
    { 'M',   0x7 },
    { '\n',  0x8 },
    { 'L',   0x9 },
    { 'R',   0xA },
    { 'G',   0xB },
    { 'I',   0xC },
    { 'P',   0xD },
    { 'C',   0xE },
    { 'V',   0xF },
    { 'E',   0x10 },
    { 'Z',   0x11 },
    { 'D',   0x12 },
    { 'B',   0x13 },
    { 'S',   0x14 },
    { 'Y',   0x15 },
    { 'F',   0x16 },
    { 'X',   0x17 },
    { 'A',   0x18 },
    { 'W',   0x19 },
    { 'J',   0x1A },
    { 'U',   0x1C },
    { 'Q',   0x1D },
    { 'K',   0x1E },
    { '\f',  0x1B },  //Figures shift
    { '\t',  0x1F },  //Letters shift
    { '5',   0x1 },
    { '9',   0x3 },
    { ',',   0x6 },
    { '.',   0x7 },
    { ')',   0x9 },
    { '4',   0xA },
    { '&',   0xB },
    { '8',   0xC },
    { '0',   0xD },
    { ':',   0xE },
    { ';',   0xF },
    { '3',   0x10 },
    { '"',   0x11 },
    { '

I don’t think my code is right because I cannot figure out how to get the Arduino to monitor whether it is in Figures shift or Letters shift.

I am also getting the error code ‘expected unqualified-id before ‘for’’.

Any assistance would be really appreciated - thank you!,  0x12 },
    { ‘?’,  0x13 },
    { ‘*’,  0x14 },  //Bell
    { ‘6’,  0x15 },
    { ‘!’,  0x16 },
    { ‘/’,  0x17 },
    { ‘-’,  0x18 },
    { ‘2’,  0x19 },
    { ‘7’,  0x1C },
    { ‘1’,  0x1D },
    { ‘(’,  0x1E },
};

#define FIGURES_SHIFT = ‘\f’
#define LETTERS_SHIFT = ‘\t’

for ( char c == ‘5’, ‘9’, ‘,’, ‘.’, ‘)’, ‘4’, ‘&’, ‘8’, ‘0’, ‘:’, ‘;’, ‘3’, ‘"’, ’


I don't think my code is right because I cannot figure out how to get the Arduino to monitor whether it is in Figures shift or Letters shift. 

I am also getting the error code 'expected unqualified-id before 'for''. 

Any assistance would be really appreciated - thank you!, '?', '*', '6', '!', '/', '-', '2', '7', '1', '('){
    if LETTERS_SHIFT {        // if the teletype is in Letters shift                                                                           
    sendCode ('\f');              // send signal for Figures shift
    }
}

for (char c == 'T', 'O', 'H', 'N', 'M', 'L', 'R', 'G', 'I', 'P', 'C', 'V', 'E', 'Z', 'D', 'B', 'S', 'Y', 'F', 'X', 'A', 'W', 'J', 'U', 'Q', 'K') {  
    if FIGURES_SHIFT {       //if the teletype is in Figures shift
    sendCode ('\t');             // send signal for Letters shift
    }
}

    

#endif

#define N_BAUDOT (sizeof (baudot)/sizeof (Baudot))
#define NO_BAUDOT   0xFF
// -------------------------------------
static byte getBaudotCode (char c)
{
    for (unsigned n = 0; n < N_BAUDOT; n++)
        if (baudot [n].c == c)
            return baudot [n].code;
    return NO_BAUDOT;
}

//--------------------------------------------------------------------
//                                  SETUP
//---------------------------------------------------------------
void setup () {
    pinMode (relay, OUTPUT);     //output to arduino relay
    Serial.begin (9600);         //turn on serial monitor at 9600 baud
    Serial.println ("Baudot");
}

//-------------------------------------------------------------------
//                                  FUNCTIONS
//-----------------------------------------------------------------
#define DELAY1  15
#define DELAY2  9

void START (){
    digitalWrite (relay, LOW);        //start impuse set to turn relay off for 22 milliseconds
    delay (DELAY1);
}

void MARKING_IMPULSE (){
    digitalWrite (relay, HIGH);        //mark impuse set to turn relay on for 22 milliseconds
    delay (DELAY1);
}

void SPACING_IMPULSE (){
    digitalWrite (relay, LOW);         //space impuse set to turn relay off for 22 milliseconds
    delay (DELAY1);
}

void STOP (){
    digitalWrite (relay, HIGH);         //stop impuse set to turn relay on for 31 milliseconds
    delay (DELAY2);
}

#if 0


void CAR_RET (){
    digitalWrite (relay, LOW);          //start impulse and three spacing impulses
    delay (88);
    digitalWrite (relay, HIGH);          //one marking impulse
    delay (22);
    digitalWrite (relay, LOW);          //one space impulse
    delay (22);
    digitalWrite (relay, HIGH);           //stop impulse
    delay (31);
}

#endif

// -----------------------------------------------------------------------------
void
sendCode (
byte code)
{
    START ();
    for (int n = 0; n < 5; n++)  {
        if (0x10 & code)
        MARKING_IMPULSE ();
        else
        SPACING_IMPULSE ();
        code <<= 1;
    }

    STOP ();

#if 0                                  // to see individual characters
    delay (250);
#endif
}

// -----------------------------------------------------------------------------
void doCstring (
char *s )
{                                       //parse the string
    int  len = strlen (s);
    char t [80];
    sprintf (t, "%s: [%d] %s", __func__, len, s);
    Serial.println (t);

    for (int n = 0; n < len; n++) {
        byte code = getBaudotCode (s [n]);
        if (NO_BAUDOT != code)
            sendCode (code);

#define LINE_LEN_LIMIT   69
        if (LINE_LEN_LIMIT == n)  {
            Serial.println ("EOL limit");
            sendCode ('\r');
            sendCode ('\n');
        }
    }
}

//----------------------------------------------------------
//                      LOOP
//----------------------------------------------------------
char str [80];
int  idx = 0;
void
loop (void)
{
    while (Serial.available ()) {            //when new information in serial
        char inChar = Serial.read ();       //get the new byte
        Serial.print (inChar);
        str [idx++] = inChar;
        if (inChar == '\n') {                  //if receive as CR
            str [idx] = 0;
            doCstring (str);
            idx = 0;
        }

    }

}

I don’t think my code is right because I cannot figure out how to get the Arduino to monitor whether it is in Figures shift or Letters shift.

I am also getting the error code ‘expected unqualified-id before ‘for’’.

Any assistance would be really appreciated - thank you!

Those first two for loops aren’t in a function.

You could test the character using “isdigit” which returns true if the character is in the range ‘0’…‘9’ inclusive.

i modified the code (a lot)

seems to me to need to identify whether the character is a letter or figure, keep track of which mode you’re in and send the shift code if the mode doesn’t match the character.

so i added a type field to the table, a few code values for Letter and Figure shift and modified doCstring() to send the shifts when there a change between a letter and figure.

I also added a test for carriage return in sendCode() and added a 250 msec delay (not sure it’s long enough; linefeed should be sent last)

//NOTE: INPUT TO SERIAL MUST BE ALL CAPS
//NOTE: INPUT TO SERIAL MUST NOT CONTAIN APOSTROPHES
String BaudotCode = "";
//string to store input from serial monitor
#if 0
int relay = 4;
//relay output is set to pin 4
#else
int relay = 10;
#endif

char t [80];    // for use with sprintf

// -----------------------------------------------------------------------------
// https://cs.stanford.edu/people/eroberts/courses/soco/projects/2008-09/colossus/baudot.html

enum { CTL, LTR, FIG };

int ltrFig = CTL;

struct Baudot {
    char c;
    int  type;
    byte code;
};

byte codeLtr = 0x1F;
byte codeFig = 0x1B;
byte codeCR  = 0x02;

Baudot baudot [] = {
    { 'T',   LTR,  0x1 },
    { '\r',  LTR,  0x2 },
    { 'O',   LTR,  0x3 },
    { ' ',   LTR,  0x4 },
    { 'H',   LTR,  0x5 },
    { 'N',   LTR,  0x6 },
    { 'M',   LTR,  0x7 },
    { '\n',  LTR,  0x8 },
    { 'L',   LTR,  0x9 },
    { 'R',   LTR,  0xA },
    { 'G',   LTR,  0xB },
    { 'I',   LTR,  0xC },
    { 'P',   LTR,  0xD },
    { 'C',   LTR,  0xE },
    { 'V',   LTR,  0xF },
    { 'E',   LTR,  0x10 },
    { 'Z',   LTR,  0x11 },
    { 'D',   LTR,  0x12 },
    { 'B',   LTR,  0x13 },
    { 'S',   LTR,  0x14 },
    { 'Y',   LTR,  0x15 },
    { 'F',   LTR,  0x16 },
    { 'X',   LTR,  0x17 },
    { 'A',   LTR,  0x18 },
    { 'W',   LTR,  0x19 },
    { 'J',   LTR,  0x1A },
    { 'U',   LTR,  0x1C },
    { 'Q',   LTR,  0x1D },
    { 'K',   LTR,  0x1E },

    { '\f',  CTL,  0x1B },  //Figures shift
    { '\t',  CTL,  0x1F },  //Letters shift

    { '5',   FIG,  0x1 },
    { '9',   FIG,  0x3 },
    { ',',   FIG,  0x6 },
    { '.',   FIG,  0x7 },
    { ')',   FIG,  0x9 },
    { '4',   FIG,  0xA },
    { '&',   FIG,  0xB },
    { '8',   FIG,  0xC },
    { '0',   FIG,  0xD },
    { ':',   FIG,  0xE },
    { ';',   FIG,  0xF },
    { '3',   FIG,  0x10 },
    { '"',   FIG,  0x11 },
    { '

,  FIG,  0x12 },
    { ‘?’,  FIG,  0x13 },
    { ‘*’,  FIG,  0x14 },  //Bell
    { ‘6’,  FIG,  0x15 },
    { ‘!’,  FIG,  0x16 },
    { ‘/’,  FIG,  0x17 },
    { ‘-’,  FIG,  0x18 },
    { ‘2’,  FIG,  0x19 },
    { ‘7’,  FIG,  0x1C },
    { ‘1’,  FIG,  0x1D },
    { ‘(’,  FIG,  0x1E },
};

#if 0
#define FIGURES_SHIFT = ‘\f’
#define LETTERS_SHIFT = ‘\t’
for ( char c == ‘5’, ‘9’, ‘,’, ‘.’, ‘)’, ‘4’, ‘&’, ‘8’, ‘0’, ‘:’, ‘;’, ‘3’, ‘"’, ’


, '?', '*', '6', '!', '/', '-', '2', '7', '1', '('){
    if LETTERS_SHIFT {        // if the teletype is in Letters shift
        sendCode ('\f');
        // send signal for Figures shift
    }

}

for (char c == 'T', 'O', 'H', 'N', 'M', 'L', 'R', 'G', 'I', 'P', 'C', 'V', 'E', 'Z', 'D', 'B', 'S', 'Y', 'F', 'X', 'A', 'W', 'J', 'U', 'Q', 'K') {
    if FIGURES_SHIFT {       //if the teletype is in Figures shift
        sendCode ('\t');
        // send signal for Letters shift
    }
}
#endif

#define N_BAUDOT (sizeof (baudot)/sizeof (Baudot))
#define NO_BAUDOT   0xFF

// -------------------------------------
Baudot * getBaudotCode (char c)
{
    for (unsigned n = 0; n < N_BAUDOT; n++)
        if (baudot [n].c == c)
            return & baudot [n];
    return NULL;
}

//--------------------------------------------------------------------
//                                  SETUP
//---------------------------------------------------------------
void setup () {
    pinMode (relay, OUTPUT);
    //output to arduino relay
    Serial.begin (9600);
    //turn on serial monitor at 9600 baud
    Serial.println ("Baudot");
}

//-------------------------------------------------------------------
//                                  FUNCTIONS
//-----------------------------------------------------------------
# define DELAY1  15
# define DELAY2  9

void START (){
    digitalWrite (relay, LOW);
    //start impuse set to turn relay off for 22 milliseconds
    delay (DELAY1);
}

void MARKING_IMPULSE (){
    digitalWrite (relay, HIGH);
    //mark impuse set to turn relay on for 22 milliseconds
    delay (DELAY1);
}

void SPACING_IMPULSE (){
    digitalWrite (relay, LOW);
    //space impuse set to turn relay off for 22 milliseconds
    delay (DELAY1);
}

void STOP (){
    digitalWrite (relay, HIGH);
    //stop impuse set to turn relay on for 31 milliseconds
    delay (DELAY2);
}

#if 0
void CAR_RET (){
    digitalWrite (relay, LOW);
    //start impulse and three spacing impulses
    delay (88);
    digitalWrite (relay, HIGH);
    //one marking impulse
    delay (22);
    digitalWrite (relay, LOW);
    //one space impulse
    delay (22);
    digitalWrite (relay, HIGH);
    //stop impulse
    delay (31);
}

#endif
// -----------------------------------------------------------------------------
void
sendCode (
    byte code)
{
    sprintf (t, "  %s: 0x%02x", __func__, code);
    Serial.println (t);

    START ();
    for (int n = 0; n < 5; n++)  {
        if (0x10 & code)
        MARKING_IMPULSE ();
        else
        SPACING_IMPULSE ();
        code <<= 1;
    }

    STOP ();

    if (codeCR == code)
        delay (250);   

// #define SLOW
#ifdef SLOW           // to see individual characters
    delay (250);
#endif
}

// -----------------------------------------------------------------------------
void doCstring (
    char *s )
{                                       //parse the string
    int  len = strlen (s);
    sprintf (t, "%s: [%d] %s", __func__, len, s);
    Serial.print   (t);             // s terminated w/ \n

    for (int n = 0; n < len; n++) {
        Baudot *b = getBaudotCode (s [n]);

        if (! b)  {
            sprintf (t, "%s: invalid char %c", __func__, s [n]); 
            Serial.println (t);
            continue;
        }

        if (ltrFig != b->type)  {
            ltrFig = b->type;

            byte code;
            if (FIG == ltrFig)  {
                code = codeFig;
                Serial.println ("doCstring: Figure shift");
            }
            else {
                code = codeLtr;
                Serial.println ("doCstring: Letter shift");
            }
            
            sendCode (code);
        }

        sendCode (b->code);

        #define LINE_LEN_LIMIT   69
        if (LINE_LEN_LIMIT == n)  {
            Serial.println ("EOL limit");
            sendCode ('\r');
            sendCode ('\n');
        }
    }
}

//----------------------------------------------------------
//                      LOOP
//----------------------------------------------------------
char str [80];
int  idx = 0;
void
loop (void)
{
    while (Serial.available ()) {            //when new information in serial
        char inChar = Serial.read ();
        //get the new byte
 //     Serial.print (inChar);
        str [idx++] = inChar;
        if (inChar == '\n') {                  //if receive as CR
            str [idx] = 0;
            doCstring (str);
            idx = 0;
        }
    }
}

if (codeCR == code) Didn’t you just left-shift “code” five places?

TheMemberFormerlyKnownAsAWOL:
if (codeCR == code) Didn’t you just left-shift “code” five places?

don’t understand. “five places”?