# Library for interfacing with a TSL2561 as used on the jeelabs lux plug

namespace eval jeelux {
    package require piio
    namespace path ::twowire

    variable slaveaddr 0x29

    variable regs {
	control 0x80 timing 0x81 threshlow 0xA2	threshhigh 0xA4
	interrupt 0x86 crc 0x88 id 0x8A	data0 0xAC data1 0xAE
    }

    namespace ensemble create -subcommands {
	luxplug close id channel lux
    }

    proc luxplug {bus {num 1}} {
	variable slaveaddr
	set fd [twowire $bus [expr {$slaveaddr + ($num << 4)}]]
	# Power up the device
	power $fd 1
	return $fd
    }

    proc close {fd} {
	# Power down the device
	power $fd 0
	chan close $fd
    }

    proc readreg {fd name} {
	variable regs
	set reg [dict get $regs $name]
	if {$reg & 0x20} {
	    return [readregword $fd $reg]
	} else {
	    return [readregbyte $fd $reg]
	}
    }

    proc writereg {fd name val} {
	variable regs
	set reg [dict get $regs $name]
	if {$reg & 0x20} {
	    writeregword $fd $reg $val
	} else {
	    writeregbyte $fd $reg $val
	}
    }

    # Control device power
    proc power {fd state} {
	writereg $fd control [expr {$state ? 3 : 0}]
    }

    # Get the individual light values
    proc channel {fd chan} {
	if {!$chan} {
	    return [readreg $fd data0]
	} else {
	    return [readreg $fd data1]
	}
    }

    # Product ID - is supposed to return 0x10, but comes out as 0x80
    proc id {fd} {
	return [readreg $fd id]
    }

    proc threshold {fd low high} {
	writereg $fd threshlow $low
	writereg $fd threshhigh $high
    }

    # T package
    proc lux {fd} {
	set scale [expr {1 << 14}]
	set ch0 [expr {([channel $fd 0] * $scale) >> 10}]
	# Prevent divide by zero situations
	if {$ch0 == 0} {return 0}
	set ch1 [expr {([channel $fd 1] * $scale) >> 10}]
	set ratio1 [expr {($ch1 << 10) / $ch0}]
	set ratio [expr {$ratio1 + 1 >> 1}]
	if {$ratio < 0} {
	    set b 0; set m 0
	} elseif {$ratio <= 0x0040} {
	    set b 0x01f2; set m 0x01be
	} elseif {$ratio <= 0x0040} {
	    set b 0x0214; set m 0x02d1
	} elseif {$ratio <= 0x00c0} {
	    set b 0x023f; set m 0x037b
	} elseif {$ratio <= 0x0100} {
	    set b 0x0270; set m 0x03fe
	} elseif {$ratio <= 0x0138} {
	    set b 0x016f; set m 0x01fc
	} elseif {$ratio <= 0x019a} {
	    set b 0x00d2; set m 0x00fb
	} elseif {$ratio <= 0x029a} {
	    set b 0x0018; set m 0x0012
	} else {
	    set b 0; set m 0
	}
	set temp [expr {$ch0 * $b - $ch1 * $m}]
	if {$temp < 0} {set temp 0}
	return [expr {($temp + (1 << 13)) >> 14}]
    }
}
