Skip to content

Commit b47881e

Browse files
authored
Merge pull request adafruit#1095 from jedgarpark/baudot-tty
first commit
2 parents fc3d004 + 9305d08 commit b47881e

File tree

2 files changed

+439
-0
lines changed

2 files changed

+439
-0
lines changed

Baudot_TTY/baudot_tty.py

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
### Baudot TTY Message Transmitter
2+
3+
### The 5-bit mode is defined in ANSI TIA/EIA-825 (2000)
4+
### "A Frequency Shift Keyed Modem for use on the Public Switched Telephone Network"
5+
6+
import time
7+
import math
8+
import array
9+
import board
10+
from audiocore import RawSample
11+
import audiopwmio
12+
13+
# constants for sine wave generation
14+
SIN_LENGTH = 100 # more is less choppy
15+
SIN_AMPLITUDE = 2 ** 12 # 0 (min) to 32768 (max) 8192 is nice
16+
SIN_OFFSET = 32767.5 # for 16bit range, (2**16 - 1) / 2
17+
DELTA_PI = 2 * math.pi / SIN_LENGTH # happy little constant
18+
19+
sine_wave = [
20+
int(SIN_OFFSET + SIN_AMPLITUDE * math.sin(DELTA_PI * i)) for i in range(SIN_LENGTH)
21+
]
22+
tones = (
23+
RawSample(array.array("H", sine_wave), sample_rate=1800 * SIN_LENGTH), # Bit 0
24+
RawSample(array.array("H", sine_wave), sample_rate=1400 * SIN_LENGTH), # Bit 1
25+
)
26+
27+
bit_0 = tones[0]
28+
bit_1 = tones[1]
29+
carrier = tones[1]
30+
31+
32+
char_pause = 0.1 # pause time between chars, set to 0 for fastest rate possible
33+
34+
dac = audiopwmio.PWMAudioOut(
35+
board.A2
36+
) # the CLUE edge connector marked "#0" to STEMMA speaker
37+
# The CLUE's on-board speaker works OK, not great, just crank amplitude to full before trying.
38+
# dac = audiopwmio.PWMAudioOut(board.SPEAKER)
39+
40+
41+
LTRS = (
42+
"\b",
43+
"E",
44+
"\n",
45+
"A",
46+
" ",
47+
"S",
48+
"I",
49+
"U",
50+
"\r",
51+
"D",
52+
"R",
53+
"J",
54+
"N",
55+
"F",
56+
"C",
57+
"K",
58+
"T",
59+
"Z",
60+
"L",
61+
"W",
62+
"H",
63+
"Y",
64+
"P",
65+
"Q",
66+
"O",
67+
"B",
68+
"G",
69+
"FIGS",
70+
"M",
71+
"X",
72+
"V",
73+
"LTRS",
74+
)
75+
76+
FIGS = (
77+
"\b",
78+
"3",
79+
"\n",
80+
"-",
81+
" ",
82+
"-",
83+
"8",
84+
"7",
85+
"\r",
86+
"$",
87+
"4",
88+
"'",
89+
",",
90+
"!",
91+
":",
92+
"(",
93+
"5",
94+
'"',
95+
")",
96+
"2",
97+
"=",
98+
"6",
99+
"0",
100+
"1",
101+
"9",
102+
"?",
103+
"+",
104+
"FIGS",
105+
".",
106+
"/",
107+
";",
108+
"LTRS",
109+
)
110+
111+
char_count = 0
112+
current_mode = LTRS
113+
114+
# The 5-bit Baudot text telephone (TTY) mode is a Frequency Shift Keyed modem
115+
# for use on the Public Switched Telephone network.
116+
#
117+
# Definitions:
118+
# Carrier tone is a 1400Hz tone.
119+
# Binary 0 is an 1800Hz tone.
120+
# Binary 1 is a 1400Hz tone.
121+
# Bit duration is 20ms.
122+
123+
# Two modes exist: Letters, aka LTRS, for alphabet characters
124+
# and Figures aka FIGS for numbers and symbols. These modes are switched by
125+
# sending the appropriate 5-bit LTRS or FIGS character.
126+
#
127+
# Character transmission sequence:
128+
# Carrier tone transmits for 150ms before each character.
129+
# Start bit is a binary 0 (sounded for one bit duration of 20ms).
130+
# 5-bit character code can be a combination of binary 0s and binary 1s.
131+
# Stop bit is a binary 1 with a minimum duration of 1-1/2 bits (30ms)
132+
#
133+
#
134+
135+
136+
def baudot_bit(pitch=bit_1, duration=0.022): # spec says 20ms, but adjusted as needed
137+
dac.play(pitch, loop=True)
138+
time.sleep(duration)
139+
# dac.stop()
140+
141+
142+
def baudot_carrier(duration=0.15): # Carrier tone is transmitted for 150 ms before the
143+
# first character is transmitted
144+
baudot_bit(carrier, duration)
145+
dac.stop()
146+
147+
148+
def baudot_start():
149+
baudot_bit(bit_0)
150+
151+
152+
def baudot_stop():
153+
baudot_bit(bit_1, 0.04) # minimum duration is 30ms
154+
dac.stop()
155+
156+
157+
def send_character(value):
158+
baudot_carrier() # send carrier tone
159+
baudot_start() # send start bit tone
160+
for i in range(5): # send each bit of the character
161+
bit = (value >> i) & 0x01 # bit shift and bit mask to get value of each bit
162+
baudot_bit(tones[bit]) # send each bit, either 0 or 1, of a character
163+
baudot_stop() # send stop bit
164+
baudot_carrier() # not to spec, but works better to extend carrier
165+
166+
167+
def send_message(text):
168+
global char_count, current_mode # pylint: disable=global-statement
169+
for char in text:
170+
if char not in LTRS and char not in FIGS: # just skip unknown characters
171+
print("Unknown character:", char)
172+
continue
173+
174+
if char not in current_mode: # switch mode
175+
if current_mode == LTRS:
176+
print("Switching mode to FIGS")
177+
current_mode = FIGS
178+
send_character(current_mode.index("FIGS"))
179+
elif current_mode == FIGS:
180+
print("Switching mode to LTRS")
181+
current_mode = LTRS
182+
send_character(current_mode.index("LTRS"))
183+
# Send char mode at beginning of message and every 72 characters
184+
if char_count >= 72 or char_count == 0:
185+
print("Resending mode")
186+
if current_mode == LTRS:
187+
send_character(current_mode.index("LTRS"))
188+
elif current_mode == FIGS:
189+
send_character(current_mode.index("FIGS"))
190+
# reset counter
191+
char_count = 0
192+
print(char)
193+
send_character(current_mode.index(char))
194+
time.sleep(char_pause)
195+
# increment counter
196+
char_count += 1
197+
198+
199+
while True:
200+
send_message("\nADAFRUIT 1234567890 -$!+='()/:;?,. ")
201+
time.sleep(2)
202+
send_message("\nWELCOME TO JOHN PARK'S WORKSHOP!")
203+
time.sleep(3)
204+
send_message("\nWOULD YOU LIKE TO PLAY A GAME?")
205+
time.sleep(5)
206+
207+
# here's an example of sending a character
208+
# send_character(current_mode.index("A"))
209+
# time.sleep(char_pause)

0 commit comments

Comments
 (0)