powerpic

Replacement board for a Casio CA-53W

import xml.etree.ElementTree as ET
from sys import argv
from copy import deepcopy

tree = ET.parse('watch_display.svg')
ns = { 
    "inkscape": "http://www.inkscape.org/namespaces/inkscape",
    "svg": "http://www.w3.org/2000/svg"
}


A=1        # Top      Center
B=2        # Top      Right
C=4        # Bottom   Right
D=8        # Bottom   Center
E=0x10     # Bottom   Left
F=0x20     # Top      Left
G=0x40     # Center   Center
P=0x80     # Period   (Not implemented)

H=0x100    # Extra segments for the secondary display. (Not implemented)
I=0x200
J=0x400

seg_map = [
    'a',
    'b',
    'c',
    'd',
    'e',
    'f',
    'g'
]

font = [

    # Punctuation
    0x0,                # Space
    B|C|P,              # !
    B|F,                # "
    0x0,                # # ???
    0x0,                # $ ???
    0x0,                # % ???
    0x0,                # & ???
    F,                  # ' Top left
    B|C,                # ( Line on right side
    E|F,                # ) Line on left side
    A|B|F|G,            # * Like a degrees sign
    D|E,                # + Kinda like a shorter L
    E,                  # , Bottom left
    G,                  # -
    P,                  # . This adds a period but takes up a space.
    B|E|G,              # /

    # Numbers 0-9
    A|B|C|D|E|F,        # 0
    B|C,                # 1
    A|B|D|E|G,          # 2
    A|B|C|D|G,          # 3
    B|C|F|G,            # 4
    A|C|D|F|G,          # 5
    A|C|D|E|F|G,        # 6
    A|B|C|F,            # 7
    A|B|C|D|E|F|G,      # 8
    A|B|C|D|F|G,        # 9

    # Punctuation
    0x0,                # : ???
    0x0,                # ; ???
    D|E|G,              # < Like c
    D|G,                # =
    C|D|G,              # > Like a backwards c
    A|B|E|G,            # ? No dot - kinda weird
    0x0,                # @ ???
    
    # Uppercase alphabet
    A|B|C|E|F|G,        # A
    F|E|G|C|D,          # B ** Lowercase
    A|D|E|F,            # C
    B|C|D|E|G,          # D ** Lowercase
    A|D|E|F|G,          # E
    A|E|F|G,            # F
    A|C|D|E|F|G,        # G
    B|C|E|F|G,          # H
    E|F,                # I Like 1 except on the left
    B|C|D|E,            # J
    B|C|E|F|G,          # K Like H and X
    D|E|F,              # L
    A|C|E,              # M Kinda weird
    A|B|C|E|F,          # N ** Big lowercase n
    A|B|C|D|E|F,        # O
    A|B|E|F|G,          # P
    A|B|C|D|E|F,        # Q Like O
    A|E|F,              # R ** Lowercase, but big
    A|C|D|F|G,          # S Like a 5
    A|E|F,              # T Upside down L
    B|C|D|E|F,          # U Like V
    B|C|D|E|F,          # V Like U
    B|D|F,              # W Kinda weird
    B|C|E|F|G,          # X Like H and K
    B|C|F|G,            # Y
    A|B|D|E|G,          # Z

    # Punctuation
    A|D|E|F,            # [ Like C
    C|F|G,              # \ backslash
    A|B|C|D,            # ] Like a backwards C
    A|B|F,              # ^
    D,                  # _
    B,                  # ` Top right
    
    # Lowercase alphabet
    A|B|C|E|F|G,        # A ** Uppercase
    F|E|G|C|D,          # b
    D|E|G,              # c
    B|C|D|E|G,          # d
    A|D|E|F|G,          # E ** Uppercase
    A|E|F|G,            # f
    A|B|C|D|F|G,        # g
    C|E|F|G,            # h
    E,                  # i No dot, on left
    B|C|D|E,            # J
    B|C|E|F|G,          # K ** Uppercase Like H and X
    D|E|F,              # l Like a capitol I
    A|C|E,              # M Kinda weird
    C|E|G,              # n
    C|D|E|G,            # o
    A|B|E|F|G,          # P ** Uppercase
    A|B|C|F|G,          # q Backwards P
    E|G,                # R ** Lowercase
    A|C|D|F|G,          # S Like a 5
    D|E|F|G,            # t
    C|D|E,              # u Like v
    C|D|E,              # v Like u
    B|D|F,              # W Kinda weird
    B|C|E|F|G,          # X ** Uppercase Like H and K
    B|C|D|F|G,          # Y
    A|B|D|E|G,          # Z ** Uppercase pretty much

    # Punctuation
    B|C|G,              # {
    B|C,                # | Left side
    E|F|G,              # }
    A,                  # ~ Top segment
]


def get_segments(ch):
    ch = ord(ch)
    if ch <= 9:
        ch += 16
    else:
        ch -= 32
    return font[ch]

def display_primary_segments(disp, position, segments):
    for i in range(7):
        if (1 << i) & segments:
            segment = disp.findall(f".//*[@inkscape:label='primary']/*/*[@inkscape:label='{position}{seg_map[i]}']", ns)[0]
            segment.attrib['style'] = segment.attrib['style'].replace('fill-opacity:0', 'fill-opacity:1')

def display_primary_character(disp, position, ch):
    display_primary_segments(disp, position, get_segments(ch))

def display_primary_string(disp, position, st):
    for ch in st:
        display_primary_character(disp, position, ch)
        position += 1

def display_secondary_segments(display, position, segments):
    for i in range(7):
        if (1 << i) & segments:
            segment = display.findall(f".//*[@inkscape:label='secondary']/*/*[@inkscape:label='{position}{seg_map[i]}']", ns)[0]
            segment.attrib['style'] = segment.attrib['style'].replace('fill-opacity:0', 'fill-opacity:1')

def display_secondary_character(display, position, ch):
    display_secondary_segments(display, position, get_segments(ch))

def display_secondary_string(display, position, st):
    for ch in st:
        display_secondary_character(display, position, ch)
        position += 1

def display_punctuation(display, punctuation):
    for p in punctuation:
        if p == '0': # Colon
            segment = display.findall(f".//*[@inkscape:label='punctuation']/svg:path[@inkscape:label='colon']", ns)[0]
        elif p == '1':
            segment = display.findall(f".//*[@inkscape:label='punctuation']/svg:path[@inkscape:label='1']", ns)[0]
        elif p == '2':
            segment = display.findall(f".//*[@inkscape:label='punctuation']/svg:path[@inkscape:label='2']", ns)[0]
        elif p == '3':
            segment = display.findall(f".//*[@inkscape:label='punctuation']/svg:path[@inkscape:label='3']", ns)[0]
        elif p == '4':
            segment = display.findall(f".//*[@inkscape:label='punctuation']/svg:path[@inkscape:label='4']", ns)[0]
        elif p == '5':
            segment = display.findall(f".//*[@inkscape:label='punctuation']/svg:path[@inkscape:label='5']", ns)[0]
        elif p == '6':
            segment = display.findall(f".//*[@inkscape:label='punctuation']/svg:path[@inkscape:label='6']", ns)[0]
        elif p == '7':
            segment = display.findall(f".//*[@inkscape:label='punctuation']/svg:path[@inkscape:label='7']", ns)[0]
        elif p == '8':
            segment = display.findall(f".//*[@inkscape:label='punctuation']/svg:path[@inkscape:label='8']", ns)[0]
        else:
            print(f"Unknown punctuation segment: {p}")
            continue
        segment.attrib['style'] = segment.attrib['style'].replace('fill-opacity:0', 'fill-opacity:1')


def display_signs(display, signs):
    for sign in signs:
        if sign == '+':
            segments = display.findall(f".//*[@inkscape:label='plus']/svg:path", ns)
        elif sign == '-':
            segments = display.findall(f".//*[@inkscape:label='minus']/svg:path", ns)
        elif sign == '*':
            segments = display.findall(f".//*[@inkscape:label='multiply']/svg:path", ns)
        elif sign == '\\':
            segments = display.findall(f".//*[@inkscape:label='divide']/svg:path", ns)
        else:
            print(f"Unknown sign display segment: {sign}")
            continue
        for segment in segments:
            segment.attrib['style'] = segment.attrib['style'].replace('fill-opacity:0', 'fill-opacity:1')

def display_misc(display, misc):
    for m in misc:
        if m == 'a':
            segment = display.findall(f".//*[@inkscape:label='am']", ns)[0]
        elif m == 'p':
            segment = display.findall(f".//*[@inkscape:label='pm']", ns)[0]
        elif m == 'k':
            segment = display.findall(f".//*[@inkscape:label='k']", ns)[0]
        elif m == 'b':
            segment = display.findall(f".//*[@inkscape:label='bell']", ns)[0]
        elif m == 'w':
            segment = display.findall(f".//*[@inkscape:label='wave']", ns)[0]
        else:
            print(f"Unknown misc display segment' : '{m}'")
            continue
        segment.attrib['style'] = segment.attrib['style'].replace('fill-opacity:0', 'fill-opacity:1')

def gen_display(display):
    print(display)
    worktree = deepcopy(tree)
    workroot = worktree.getroot()
    if display[1]:
        display_primary_string(workroot, 1, display[1])
    if display[2]:
        display_secondary_string(workroot, 1, display[2])
    if display[3]:
        display_signs(workroot, display[3])
    if display[4]:
        display_misc(workroot, display[4])
    if display[5]:
        display_punctuation(workroot, display[5])
    worktree.write(display[0] + '.svg')


if __name__ == '__main__':
    if len(argv) > 1:
        if len(argv) == 2 and argv[1].endswith('.csv'):
            import csv
            with open(argv[1], newline='') as csvfile:
                screenreader = csv.reader(csvfile)
                header = next(screenreader)
                for row in screenreader:
                    gen_display(row)
        elif len(argv) > 2:
            # display_primary_string(1, argv[1])
            display = ['', '', '', '', '', '']
            display[0] = argv[1]
            display[1] = argv[2]
            if len(argv) > 3:
                display[2] = argv[3]
                if len(argv) > 4:
                    display[3] = argv[4]
                    if len(argv) > 5:
                        display[4] = argv[5]
                        if len(argv) > 6:
                            display[5] = argv[6]
                            if len(argv) > 7:
                                print(f"Ignoring args: {argv[7:]}")
            gen_display(display)


        else:
            print('Required args: <name> <primary> [secondary [signs [misc]]]')
            print('           or: <filename.csv> of csv displays')

    else:
        print('Required args: <name> <primary> [secondary [signs [misc]]]')
        print('           or: <filename.csv> of csv displays')
        # gen_svg()
        # tree.write('test.svg')