# Reference sheet for FPGA commands through microcontroller

import hid
import struct

MAX_DC = 2400

# all of the FPGA commands begin with the hid code 'e'
# the next byte is the action to take:
#       'R' - reset, asserts the reset pin for 500ms which puts 
#           all of the fpga logic in its initial condition
#       'B' - reconfig, reloads the FPGA settings from SPI flash.
#           this effectively does the same things as reset right now
#       'I' - sends a command over I2C:
#           first byte after 'I': number of bytes to send
#           second byte: register to send to
#               Reg 0x00 - Camera register address high byte
#               Reg 0x01 - Camera register address low byte
#               Reg 0x02 - Camera register new value (also triggers sending the command to the camera)
#               Reg 0x10 - PWM duty cycle high byte
#               Reg 0x11 - PWM duty cycle low byte (also triggers updating the pwm)
#           Registers auto-increment, so a camera register can be updated with a single transaction like:
#               send_feature_report(bytes([0, ord('e'), ord('I'), 4, 0x00, 0x30, 0x0A, 0x04]))
#           This will send the value 0x04 to camera register 0x300A
#           Note that both cameras will be updated simultaneously
#           PWM setting example:
#               send_feature_report(bytes([0, ord('e'), ord('I'), 3, 0x10, 0x01, 0x33]))
#           Sets the new duty cycle to 0x0133

# Additional notes:
# PWM duty is currently just a counter value. The PWM is set to 10kHz, which on the 24MHz clock means
# it counts up to 2,400 and then repeats. So the PWM duty cycle is only meaningful between the values
# of 0 (zero % duty) and 2400 (100% duty). If you want to set 35%, for example, multiply 2400 by 0.35
# = 840, and then convert to hex => 0x0348 => 0x03, 0x48

def reset_fpga():
    hid.Device(vid=0x35bd,pid=0x0101).send_feature_report(bytes([0,ord('e'),ord('R')]))


def reconfig_fpga():
    hid.Device(vid=0x35bd,pid=0x0101).send_feature_report(bytes([0,ord('e'),ord('B')]))

def set_pwm_duty(duty_cycle_percent):
    # duty_cycle_percent should be between 0 -> 100
    if(duty_cycle_percent < 0):
        duty_cycle_percent = 0
    if(duty_cycle_percent > 100):
        duty_cycle_percent = 100
        
    new_dc = int(MAX_DC * duty_cycle_percent / 100.0)
    val_bytes = struct.pack('>H',new_dc)
    hid.Device(vid=0x35bd,pid=0x0101).send_feature_report(bytes([0,ord('e'),ord('I'),3,0x10])+val_bytes)

def set_cam_reg(reg_addr, reg_value):
    # reg_addr is 16 bit (can vary from 0x0000 to 0xFFFF)
    # reg_value is 8 bit (so only 0x00 to 0xFF)
    reg_setting = struct.pack('>HB',reg_addr, reg_value)
    hid.Device(vid=0x35bd,pid=0x0101).send_feature_report(bytes([0,ord('e'),ord('I'),4,0x00])+reg_setting)