#!/usr/bin/env python3

from pathlib import Path
import datetime
import math
import numpy as np
import uuid

def transition(n):
    return (1 - np.cos(np.linspace(0, np.pi, n)))/2

def template_var(ctype, name, value):
    value = list(value)
    yield f'const {ctype} {name}[{len(value)}] = {{'
    for elem in value:
        yield f'    {elem},'
    yield '};'

def quantize(fun, maxval):
    for val in fun:
        yield round(val*maxval)

def template(ctype, n, erange):
    yield ''
    yield '/* AUTO-GENERATED SOURCE! DO NOT MODIFY! */'
    yield f'/* Generated on {datetime.datetime.now()} by {Path(__file__).name} */'
    yield ''
    yield "#include <stdint.h>"
    yield ''
    vals = [x for e in transition(n) for x in [e, e]]
    yield from template_var(ctype, 'waveform_zero_one', quantize(vals, erange))
    yield ''
    vals = reversed(vals)
    yield from template_var(ctype, 'waveform_one_zero', quantize(vals, erange))
    yield ''

def header(ctype, n, erange):
    macro = f'__GEN_WAVE_TABLES_{str(uuid.uuid4()).upper().replace("-", "_")}__'
    yield f'#ifndef {macro}'
    yield f'#define {macro}'
    yield ''
    yield '/* AUTO-GENERATED SOURCE! DO NOT MODIFY! */'
    yield f'/* Generated on {datetime.datetime.now()} by {Path(__file__).name} */'
    yield ''
    yield "#include <stdint.h>"
    yield ''
    yield f'#define WAVEFORM_CONST_ZERO {0}'
    yield f'#define WAVEFORM_CONST_ONE 0x{erange:x}'
    yield ''
    yield f'extern const {ctype} waveform_zero_one[{2*n}];'
    yield f'extern const {ctype} waveform_one_zero[{2*n}];'
    yield ''
    yield f'#endif /* {macro} */'

if __name__ == '__main__':
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument('--table-size', type=int, default=32)
    parser.add_argument('--range', type=int, default=250)
    parser.add_argument('--header', action='store_true')
    parser.add_argument('--storage-type', type=str, default='uint16_t')
    parser.add_argument('outfile', type=argparse.FileType('w'))
    args = parser.parse_args()

    if args.header:
        args.outfile.write('\n'.join(header(args.storage_type, args.table_size, args.range)) + '\n')
    else:
        args.outfile.write('\n'.join(template(args.storage_type, args.table_size, args.range)) + '\n')
