#!/usr/bin/env python
"""Raster power calibration/test script

Creates a row of small boxes with different pulse lengths.
"""
import driveboard as b
import sys, os, time, random
import numpy as np

box_size = 6.0 # mm
box_count = 10

feedrate = 8000 # mm/min
#pulse_freq = 1500 # Hz
pulse_freq = 600 # Hz
first_box_pulselength = 1 # increased by one for every box
#scanline_distance = 0.1 # mm between horizontal raster lines
scanline_distance = 0.3 # mm between horizontal raster lines

print 'pulse freq', pulse_freq, 'Hz'
print 'pulse duration (first box) %.0f us' % (b.PULSE_SECONDS * first_box_pulselength / 1e-6)
print 'pulse duration (last box)  %.0f us' % (b.PULSE_SECONDS * (first_box_pulselength+box_count-1) / 1e-6)
print 'intensity (first box): %.1f%%' % (100 * b.PULSE_SECONDS*first_box_pulselength*pulse_freq)
print 'intensity (last box) : %.1f%%' % (100 * b.PULSE_SECONDS*(first_box_pulselength+box_count-1)*pulse_freq)

watts_laser = 100.0
ws_mm = watts_laser * b.PULSE_SECONDS*(first_box_pulselength+box_count-1)*pulse_freq / (feedrate/60.0)
ws_mm2 = ws_mm / scanline_distance
print 'Energy density line (last box): %.3f J/mm' % ws_mm
print 'Energy density area (last box): %.3f J/mm^2' % ws_mm2

baudrate = 57600
serial_limit = baudrate/10/2 * 0.60 # overhead: 60% (can be reduced, TODO)
print '%.0f bytes per second (serial limit: about %d bytes per second)' % (pulse_freq, serial_limit)
if pulse_freq > serial_limit:
    print 'Pulse frequency (= data rate) too high for serial port!'
    sys.exit(1)

# opportunity for canceling with Ctrl-C :-)
print
print 'Starting in 3 seconds...'
time.sleep(3)

# for final cut
travel_feedrate = 8000
cut_feedrate = 1200 # mm/min
cut_intensity = 70 # percent

ACCELERATION = 1800000.0 # mm/min^2, divide by (60*60) to get mm/sec^2
accel_dist = 0.5 * feedrate**2 / ACCELERATION  * 1.1

def pulse_length_sweep(x0, y0):
    b.intensity(0)
    b.feedrate(travel_feedrate)
    x, y = x0, y0
    b.move(x, y)
    b.feedrate(feedrate)
    x += accel_dist
    b.move(x, y)
    
    box_time = box_size/(feedrate/60.0)
    box_pulses = box_time*pulse_freq
    print box_time, box_count, box_pulses
    
    total_pulses = int(round(box_count*box_pulses))

    bytes_per_second = box_pulses/box_time
    print '%d pulses, %.0f bytes per second (limit: %d bytes per second)' % (total_pulses, bytes_per_second, 57600/10/2 * .9)
    
    data = np.zeros(total_pulses, dtype='uint8')
    for i in range(box_count):
        p0 = int(round(total_pulses * i/box_count))
        p1 = int(round(total_pulses * (i+1)/box_count))
        data[p0:p1] = first_box_pulselength + i

    x += box_count*box_size
    print len(data), 'raster bytes'
    b.raster_move(x, y, data)

    x += accel_dist
    b.move(x, y)

def box_row(x0, y0, spacing_y):
    for y in np.arange(y0, y0+box_size, spacing_y/box_size):
        print 'y', y
        pulse_length_sweep(x0, y0+y)

def run():
    #b.stop()
    #b.unstop()
    b.homing()
    b.air_on()
    border_spacing = 0.5
    box_row(border_spacing, border_spacing, scanline_distance)

    # cut it out
    x0 = accel_dist
    x1 = accel_dist + 2*border_spacing + box_count*box_size
    y0 = 0
    y1 = box_size + 2*border_spacing
    b.move(x0, y0)
    b.feedrate(cut_feedrate)
    b.intensity(cut_intensity)
    b.move(x1, y0)
    b.move(x1, y1)
    b.move(x0, y1)
    b.move(x0, y0)
    b.intensity(0)
    b.move(0, 0)
    b.air_off()
    print 'done, waiting for execution...'

    # wait for job to finish
    time.sleep(2.0)
    while True:
        s = b.status()
        print s
        if s['stops']:
            print s
            raise RuntimeError
        if s['ready']:
            break
        time.sleep(5)
    print 'ready.'

try:
    b.connect()
    assert b.connected()
    print b.status()
    run()
finally:
    b.close()



