# esp32 - RMT and buzzer to generate morse code on pin 32
# Copytight by Anthony Vogelaar, Perth Scotland
# rev 0.10  2025-09-29
# rev 0.11  2025-10-09  added: isReady and words_per_minute as parameter

import	time
from	machine	import	Pin
from	esp32	import	RMT

# Implemented:
# MorseWriter(pin_nr=32, words_per_minute=10)
#    MorseWriter.outLine(line)
#    MorseWriter.isReady()		-->  bool

# ========================= Morse ========================

# dictionary with morse codes
morse_codes = {
    'A': '.-',		'B': '-...',	'C': '-.-.',	'D': '-..',
    'E': '.',		'F': '..-.',	'G': '--.',		'H': '....',
    'I': '..',		'J': '.---',	'K': '-.-',		'L': '.-..',
    'M': '--',		'N': '-.',		'O': '---',		'P': '.--.',
    'Q': '--.-',	'R': '.-.',		'S': '...',		'T': '-',
    'U': '..-',		'V': '...-',	'W': '.--',	    'X': '-..-',
    'Y': '-.--',	'Z': '--..',
    '1': '.----',	'2': '..---',	'3': '...--',	'4': '....-',
    '5': '.....',	'6': '-....',	'7': '--...',	'8': '---..',
    '9': '----.',	'0': '-----'}


# 5 words_per_minute requires a tick length of 60 Sec / 5 wpm / 50 word_length = 240 mSec
# as longest RMT delay is 80 MHz / 255 / 2^15-1 = 104 mSec  --> 3 RMT periods per tick
# write morse code to pin_nr
class MorseWriter:
    
    def __init__(self, pin_nr=32, words_per_minute=10):
        assert words_per_minute >= 5
        self.pin_nr = pin_nr
        self.buzzer = RMT(0, pin=pin_nr, clock_div=250)		# RMT clock is 320 kHz = 3.125 uSec
        tick_sec    = 60 / (words_per_minute * 50)
        self.period = int(tick_sec / (3.125e-6 * 3)) 		# 80 mSec for 10 words per minute
        
        
    def _dith(self, data):
        data += [1]*3 + [0]*3							# add: 1 tick on, 1 tick off
        

    def _dah(self, data):
        data += [1]*9 + [0]*3								# add: 3 ticks high, 1 tick off
        
        
    def _waitCh(self, data):
        data += [0]*6										# add: 2 ticks off
        

    def _waitWord(self, data):
        data += [0]*12										# add 4 ticks off


    def _addCh(self, ch, data):
        ch = ch.upper()
        if ch in morse_codes:
            code = morse_codes[ch]
            for bit in code:
                self._dith(data) if bit == '.' else self._dah(data)
            

    def _addWord(self, word, data):
        for ch in word:
            self._addCh(ch, data)
            self._waitCh(data)
            
            
    def outLine(self, line):
        data = []
        for word in line.split(' '):
            self._addWord(word, data)
            self._waitWord(data)
        self.buzzer.write_pulses(self.period, data)


    # return True if ready
    def isReady(self):
        return self.buzzer.wait_done()
    
# ========================== test ===========================

if __name__ == '__main__':
    
#    morse = MorseWriter()
    morse = MorseWriter(words_per_minute=10)
    morse.outLine('sos sos')
#  	morse.outLine('Het is mooi weer vandaag')
    while not morse.isReady():
        print('*', end='')
        time.sleep(1)
    print('\ndone')

# ========================== end ============================
