diff --git a/deps/labjack/ljacklm/libljacklm/ljacklm.c b/deps/labjack/ljacklm/libljacklm/ljacklm.c index 6896ab6..0febd8c 100644 --- a/deps/labjack/ljacklm/libljacklm/ljacklm.c +++ b/deps/labjack/ljacklm/libljacklm/ljacklm.c @@ -1471,6 +1471,84 @@ float GetDriverVersion( void) return VERSION; } +const char *StaticErrorString(long errorcode) { + if(BitTst(errorcode,8)) + { + errorcode -= STREAMBUFF_ERROR_OFFSET_LJ; + } + switch(errorcode) + { + case 0: return "No error"; + case 1: return "Unknown error"; + case 2: return "No LabJacks found"; + case 3: return "LabJack n not found"; + case 4: return "Set USB buffer error"; + case 5: return "Open handle error"; + case 6: return "Close handle error"; + case 7: return "Invalid ID"; + case 8: return "Invalid array size or value"; + case 9: return "Invalid power index"; + case 10: return "FCDD size too big"; + case 11: return "HVC size too big"; + case 12: return "Read error"; + case 13: return "Read timeout error"; + case 14: return "Write error"; + case 15: return "Turbo error"; + case 16: return "Illegal channel index"; + case 17: return "Illegal gain index"; + case 18: return "Illegal AI command"; + case 19: return "Illegal AO command"; + case 20: return "Bits out of range"; + case 21: return "Illegal number of channels"; + case 22: return "Illegal scan rate"; + case 23: return "Illegal number of samples"; + case 24: return "AI response error"; + case 25: return "LabJack RAM checksum error"; + case 26: return "AI sequence error"; + case 27: return "Maximum number of streams reached"; + case 28: return "AI stream start error"; + case 29: return "PC buffer overflow"; + case 30: return "LabJack buffer overflow"; + case 31: return "Stream read timeout"; + case 32: return "Illegal number of scans"; + case 33: return "No stream was found"; + case 40: return "Illegal input"; + case 41: return "Echo error"; + case 42: return "Data echo error"; + case 43: return "Response error"; + case 44: return "Asynch timeout error"; + case 45: return "Asynch start bit error"; + case 46: return "Asynch framing error"; + case 47: return "Asynch digital I/O state or tris error"; + case 48: return "Caps error"; + case 49: return "Caps error"; + case 50: return "Caps error"; + case 51: return "HID number caps error"; + case 52: return "HID get attributes warning"; + case 57: return "Wrong firmware version error"; + case 58: return "Digital I/O state or tris error"; + case 64: return "Could not claim all LabJacks"; + case 65: return "Error releasing all LabJacks"; + case 66: return "Could not claim LabJack"; + case 67: return "Error releasing LabJack"; + case 68: return "Claimed abandoned LabJack"; + case 69: return "Local ID -1 thread stopped"; + case 70: return "Stop thread timeout"; + case 71: return "Thread termination failed"; + case 72: return "Feature handle creation failed"; + case 73: return "Mutex creation failed"; + case 80: return "Synch CS state or tris error"; + case 81: return "Synch SCK tris error"; + case 82: return "Synch MISO tris error"; + case 83: return "Synch MOSI tris error"; + case 89: return "SHT1X communication error - CRC"; + case 90: return "SHT1X communication error - MeasReady"; + case 91: return "SHT1X communication error - ACK"; + case 92: return "SHT1X serial reset error"; + default: return "Unknown error code"; + } +} + //====================================================================== //GetErrorString @@ -1485,149 +1563,7 @@ float GetDriverVersion( void) void GetErrorString( long errorcode, char *errorString) { - if(BitTst(errorcode,8)) - { - errorcode -= STREAMBUFF_ERROR_OFFSET_LJ; - } - switch(errorcode) - { - case 0: errorString = strcpy(errorString,"No error"); - break; - case 1: errorString = strcpy(errorString,"Unknown error"); - break; - case 2: errorString = strcpy(errorString,"No LabJacks found"); - break; - case 3: errorString = strcpy(errorString,"LabJack n not found"); - break; - case 4: errorString = strcpy(errorString,"Set USB buffer error"); - break; - case 5: errorString = strcpy(errorString,"Open handle error"); - break; - case 6: errorString = strcpy(errorString,"Close handle error"); - break; - case 7: errorString = strcpy(errorString,"Invalid ID"); - break; - case 8: errorString = strcpy(errorString,"Invalid array size or value"); - break; - case 9: errorString = strcpy(errorString,"Invalid power index"); - break; - case 10: errorString = strcpy(errorString,"FCDD size too big"); - break; - case 11: errorString = strcpy(errorString,"HVC size too big"); - break; - case 12: errorString = strcpy(errorString,"Read error"); - break; - case 13: errorString = strcpy(errorString,"Read timeout error"); - break; - case 14: errorString = strcpy(errorString,"Write error"); - break; - case 15: errorString = strcpy(errorString,"Turbo error"); - break; - case 16: errorString = strcpy(errorString,"Illegal channel index"); - break; - case 17: errorString = strcpy(errorString,"Illegal gain index"); - break; - case 18: errorString = strcpy(errorString,"Illegal AI command"); - break; - case 19: errorString = strcpy(errorString,"Illegal AO command"); - break; - case 20: errorString = strcpy(errorString,"Bits out of range"); - break; - case 21: errorString = strcpy(errorString,"Illegal number of channels"); - break; - case 22: errorString = strcpy(errorString,"Illegal scan rate"); - break; - case 23: errorString = strcpy(errorString,"Illegal number of samples"); - break; - case 24: errorString = strcpy(errorString,"AI response error"); - break; - case 25: errorString = strcpy(errorString,"LabJack RAM checksum error"); - break; - case 26: errorString = strcpy(errorString,"AI sequence error"); - break; - case 27: errorString = strcpy(errorString,"Maximum number of streams reached"); - break; - case 28: errorString = strcpy(errorString,"AI stream start error"); - break; - case 29: errorString = strcpy(errorString,"PC buffer overflow"); - break; - case 30: errorString = strcpy(errorString,"LabJack buffer overflow"); - break; - case 31: errorString = strcpy(errorString,"Stream read timeout"); - break; - case 32: errorString = strcpy(errorString,"Illegal number of scans"); - break; - case 33: errorString = strcpy(errorString,"No stream was found"); - break; - case 40: errorString = strcpy(errorString,"Illegal input"); - break; - case 41: errorString = strcpy(errorString,"Echo error"); - break; - case 42: errorString = strcpy(errorString,"Data echo error"); - break; - case 43: errorString = strcpy(errorString,"Response error"); - break; - case 44: errorString = strcpy(errorString,"Asynch timeout error"); - break; - case 45: errorString = strcpy(errorString,"Asynch start bit error"); - break; - case 46: errorString = strcpy(errorString,"Asynch framing error"); - break; - case 47: errorString = strcpy(errorString,"Asynch digital I/O state or tris error"); - break; - case 48: errorString = strcpy(errorString,"Caps error"); - break; - case 49: errorString = strcpy(errorString,"Caps error"); - break; - case 50: errorString = strcpy(errorString,"Caps error"); - break; - case 51: errorString = strcpy(errorString,"HID number caps error"); - break; - case 52: errorString = strcpy(errorString,"HID get attributes warning"); - break; - case 57: errorString = strcpy(errorString,"Wrong firmware version error"); - break; - case 58: errorString = strcpy(errorString,"Digital I/O state or tris error"); - break; - case 64: errorString = strcpy(errorString,"Could not claim all LabJacks"); - break; - case 65: errorString = strcpy(errorString,"Error releasing all LabJacks"); - break; - case 66: errorString = strcpy(errorString,"Could not claim LabJack"); - break; - case 67: errorString = strcpy(errorString,"Error releasing LabJack"); - break; - case 68: errorString = strcpy(errorString,"Claimed abandoned LabJack"); - break; - case 69: errorString = strcpy(errorString,"Local ID -1 thread stopped"); - break; - case 70: errorString = strcpy(errorString,"Stop thread timeout"); - break; - case 71: errorString = strcpy(errorString,"Thread termination failed"); - break; - case 72: errorString = strcpy(errorString,"Feature handle creation failed"); - break; - case 73: errorString = strcpy(errorString,"Mutex creation failed"); - break; - case 80: errorString = strcpy(errorString,"Synch CS state or tris error"); - break; - case 81: errorString = strcpy(errorString,"Synch SCK tris error"); - break; - case 82: errorString = strcpy(errorString,"Synch MISO tris error"); - break; - case 83: errorString = strcpy(errorString,"Synch MOSI tris error"); - break; - case 89: errorString = strcpy(errorString,"SHT1X communication error - CRC"); - break; - case 90: errorString = strcpy(errorString,"SHT1X communication error - MeasReady"); - break; - case 91: errorString = strcpy(errorString,"SHT1X communication error - ACK"); - break; - case 92: errorString = strcpy(errorString,"SHT1X serial reset error"); - break; - - default: errorString=strcpy(errorString,"Unknown error code"); - } + errorString = strcpy(errorString, StaticErrorString(errorcode)); return; } diff --git a/deps/labjack/ljacklm/libljacklm/ljacklm.h b/deps/labjack/ljacklm/libljacklm/ljacklm.h index b5f675d..84ac2f5 100644 --- a/deps/labjack/ljacklm/libljacklm/ljacklm.h +++ b/deps/labjack/ljacklm/libljacklm/ljacklm.h @@ -798,6 +798,8 @@ long DigitalIO( long *idnum, float GetDriverVersion( void); +const char *StaticErrorString(long errorcode); + //====================================================================== //GetErrorString // diff --git a/src/ljacklm.zig b/src/ljacklm.zig index c29ff4d..c25892e 100644 --- a/src/ljacklm.zig +++ b/src/ljacklm.zig @@ -1,336 +1,774 @@ -pub extern fn EAnalogIn( - idnum: *c_long, - demo: c_long, - channel: c_long, - gain: c_long, - overVoltage: *c_long, - voltage: *f32, -) c_long; +const std = @import("std"); -pub extern fn EAnalogOut( - idnum: *c_long, - demo: c_long, - analogOut0: f32, - analogOut1: f32, -) c_long; +pub fn getDriverVersion() f32 { + return c_api.GetDriverVersion(); +} -pub extern fn ECount( - idnum: *c_long, - demo: c_long, - resetCounter: c_long, - count: *f64, - ms: *f64, -) c_long; +pub const Labjack = struct { + id: ?u32 = null, + demo: bool = false, -pub extern fn EDigitalIn( - idnum: *c_long, - demo: c_long, - channel: c_long, - readD: c_long, - state: [*c]c_long, -) c_long; + pub fn autodetect() Labjack { + return .{}; + } -pub extern fn EDigitalOut( - idnum: *c_long, - demo: c_long, - channel: c_long, - writeD: c_long, - state: c_long, -) c_long; + pub fn firmwareVersion(self: Labjack) LabjackError!f32 { + var id = self.cId(); + const version = c_api.GetFirmwareVersion(&id); -pub extern fn AsynchConfig( - idnum: *c_long, - demo: c_long, - timeoutMult: c_long, - configA: c_long, - configB: c_long, - configTE: c_long, - fullA: c_long, - fullB: c_long, - fullC: c_long, - halfA: c_long, - halfB: c_long, - halfC: c_long, -) c_long; + return if (version == 0) + @as(c_api.LabjackCError, @bitCast(id)).toError() + else + version; + } -pub extern fn Asynch( - idnum: *c_long, - demo: c_long, - portB: c_long, - enableTE: c_long, - enableTO: c_long, - enableDel: c_long, - baudrate: c_long, - numWrite: c_long, - numRead: c_long, - data: [*c]c_long, -) c_long; + /// Read one analog input channel, either single-ended or differential + pub fn analogReadOne(self: Labjack, input: AnalogInput) LabjackError!AnalogReadResult { + if (!input.channel.isDifferential() and input.gain != 0) { + return error.InvalidGain; + } -pub extern fn AISample( - idnum: *c_long, - demo: c_long, - stateIO: [*c]c_long, - updateIO: c_long, - ledOn: c_long, - numChannels: c_long, - channels: [*c]c_long, - gains: [*c]c_long, - disableCal: c_long, - overVoltage: [*c]c_long, - voltages: [*c]f32, -) c_long; + var id = self.cId(); + var over_v: c_long = 0; + var res: AnalogReadResult = undefined; -pub extern fn AIBurst( - idnum: *c_long, - demo: c_long, - stateIOin: c_long, - updateIO: c_long, - ledOn: c_long, - numChannels: c_long, - channels: [*c]c_long, - gains: [*c]c_long, - scanRate: [*c]f32, - disableCal: c_long, - triggerIO: c_long, - triggerState: c_long, - numScans: c_long, - timeout: c_long, - voltages: [*c][4]f32, - stateIOout: [*c]c_long, - overVoltage: [*c]c_long, - transferMode: c_long, -) c_long; + const status = c_api.EAnalogIn( + &id, + @intFromBool(self.demo), + input.channelNumber(), + input.gain, + &over_v, + &res.voltage, + ); -pub extern fn AIStreamStart( - idnum: *c_long, - demo: c_long, - stateIOin: c_long, - updateIO: c_long, - ledOn: c_long, - numChannels: c_long, - channels: [*c]c_long, - gains: [*c]c_long, - scanRate: [*c]f32, - disableCal: c_long, - reserved1: c_long, - readCount: c_long, -) c_long; + if (status.okay()) { + res.over_voltage = over_v > 0; + return res; + } else { + return status.toError(); + } + } -pub extern fn AIStreamRead( - localID: c_long, - numScans: c_long, - timeout: c_long, - voltages: [*c][4]f32, - stateIOout: [*c]c_long, - reserved: [*c]c_long, - ljScanBacklog: [*c]c_long, - overVoltage: [*c]c_long, -) c_long; + pub fn digitalWriteOne(self: Labjack, output: DigitalOutput) LabjackError!void { + var id = self.cId(); + const status = c_api.EDigitalOut( + &id, + @intFromBool(self.demo), + output.channelNumber(), + @intFromBool(output.isDLine()), + @intFromBool(output.level), + ); -pub extern fn AIStreamClear( - localID: c_long, -) c_long; + if (!status.okay()) + return status.toError(); + } -pub extern fn AOUpdate( - idnum: *c_long, - demo: c_long, - trisD: c_long, - trisIO: c_long, - stateD: [*c]c_long, - stateIO: [*c]c_long, - updateDigital: c_long, - resetCounter: c_long, - count: [*c]c_ulong, - analogOut0: f32, - analogOut1: f32, -) c_long; + pub fn readAnalogWriteDigital( + self: Labjack, + comptime incount: u3, + inputs: [incount]AnalogInput, + outputs: ?[4]bool, + ledOn: bool, + ) LabjackError![incount]AnalogReadResult { + var id = self.cId(); + var out_states: c_long = if (outputs) |out| + PackedOutput.fromBoolArray(out).toCLong() + else + 0; + var in_channels: [incount]c_long = undefined; + var gains: [incount]c_long = undefined; + for (inputs, &in_channels, &gains) |from, *inc, *gain| { + inc.* = from.channelNumber(); + gain.* = from.gain; + } + var v_out: [4]f32 = .{0} ** 4; + var over_v: c_long = 0; -pub extern fn BitsToVolts( - chnum: c_long, - chgain: c_long, - bits: c_long, - volts: [*c]f32, -) c_long; + const status = c_api.AISample( + &id, + @intFromBool(self.demo), + &out_states, + @intFromBool(outputs != null), + @intFromBool(ledOn), + incount, + &in_channels, + &gains, + @intFromBool(false), + &over_v, + &v_out, + ); -pub extern fn VoltsToBits( - chnum: c_long, - chgain: c_long, - volts: f32, - bits: [*c]c_long, -) c_long; + if (!status.okay()) + return status.toError(); -pub extern fn Counter( - idnum: *c_long, - demo: c_long, - stateD: [*c]c_long, - stateIO: [*c]c_long, - resetCounter: c_long, - enableSTB: c_long, - count: [*c]c_ulong, -) c_long; + var result: [incount]AnalogReadResult = undefined; + for (v_out[0..incount], &result) |raw, *res| { + res.voltage = raw; + // there's no information about which channel had over voltage, so + // maybe we should return a different type + res.over_voltage = over_v > 0; + } -pub extern fn DigitalIO( - idnum: *c_long, - demo: c_long, - trisD: [*c]c_long, - trisIO: c_long, - stateD: [*c]c_long, - stateIO: [*c]c_long, - updateDigital: c_long, - outputD: [*c]c_long, -) c_long; + return result; + } -pub extern fn GetDriverVersion() f32; + fn cId(self: Labjack) c_long { + return self.id orelse -1; + } +}; -pub extern fn GetErrorString( - errorcode: c_long, - errorString: *[50]u8, -) void; +pub const AnalogInput = struct { + channel: AnalogInputChannel, + gain: Gain = 0, -pub extern fn GetFirmwareVersion(idnum: *c_long) f32; + pub fn channelNumber(self: AnalogInput) u4 { + return @intFromEnum(self.channel); + } +}; -pub extern fn ListAll( - productIDList: *[127]c_long, - serialnumList: *[127]c_long, - localIDList: *[127]c_long, - powerList: *[127]c_long, - calMatrix: *[127][20]c_long, - numberFound: *c_long, - fcddMaxSize: *c_long, - hvcMaxSize: *c_long, -) c_long; +pub const AnalogReadResult = struct { + voltage: f32, + over_voltage: bool, +}; -pub extern fn LocalID( - idnum: *c_long, - localID: c_long, -) c_long; +pub const DigitalOutput = struct { + channel: DigitalOutputChannel, + level: bool, -pub extern fn PulseOut( - idnum: *c_long, - demo: c_long, - lowFirst: c_long, - bitSelect: c_long, - numPulses: c_long, - timeB1: c_long, - timeC1: c_long, - timeB2: c_long, - timeC2: c_long, -) c_long; + pub fn channelNumber(self: DigitalOutput) u4 { + return self.channel.channelNumber(); + } -pub extern fn PulseOutStart( - idnum: *c_long, - demo: c_long, - lowFirst: c_long, - bitSelect: c_long, - numPulses: c_long, - timeB1: c_long, - timeC1: c_long, - timeB2: c_long, - timeC2: c_long, -) c_long; + pub fn isDLine(self: DigitalOutput) bool { + return self.channel.isDLine(); + } +}; -pub extern fn PulseOutFinish( - idnum: *c_long, - demo: c_long, - timeoutMS: c_long, -) c_long; +pub const AnalogInputChannel = enum(u4) { + ai0 = 0, + ai1 = 1, + ai2 = 2, + ai3 = 3, + ai4 = 4, + ai5 = 5, + ai6 = 6, + ai7 = 7, -pub extern fn PulseOutCalc( - frequency: [*c]f32, - timeB: [*c]c_long, - timeC: [*c]c_long, -) c_long; + diff_01 = 8, + diff_23 = 9, + diff_45 = 10, + diff_67 = 11, -pub extern fn ReEnum( - idnum: *c_long, -) c_long; + pub fn isDifferential(self: AnalogInputChannel) bool { + return switch (self) { + .diff_01, .diff_23, .diff_45, .diff_67 => true, + else => false, + }; + } +}; -pub extern fn Reset( - idnum: *c_long, -) c_long; +pub const DigitalOutputChannel = union(enum) { + io: u2, + d: u4, -pub extern fn ResetLJ( - idnum: *c_long, -) c_long; + pub fn channelNumber(self: DigitalOutputChannel) u4 { + return switch (self) { + inline else => |val| val, + }; + } -pub extern fn SHT1X( - idnum: *c_long, - demo: c_long, - softComm: c_long, - mode: c_long, - statusReg: c_long, - tempC: [*c]f32, - tempF: [*c]f32, - rh: [*c]f32, -) c_long; + pub fn isDLine(self: DigitalOutputChannel) bool { + return self == .d; + } +}; -pub extern fn SHTComm( - idnum: *c_long, - softComm: c_long, - waitMeas: c_long, - serialReset: c_long, - dataRate: c_long, - numWrite: c_long, - numRead: c_long, - datatx: [*c]u8, - datarx: [*c]u8, -) c_long; +// differential only +// 0 => G=1 ±20 volts +// 1 => G=2 ±10 volts +// 2 => G=4 ±5 volts +// 3 => G=5 ±4 volts +// 4 => G=8 ±2.5 volts +// 5 => G=10 ±2 volts +// 6 => G=16 ±1.25 volts +// 7 => G=20 ±1 volt +pub const Gain = u3; -pub extern fn SHTCRC( - statusReg: c_long, - numWrite: c_long, - numRead: c_long, - datatx: [*c]u8, - datarx: [*c]u8, -) c_long; +pub const PackedOutput = packed struct(u4) { + io0: bool, + io1: bool, + io2: bool, + io3: bool, -pub extern fn Synch( - idnum: *c_long, - demo: c_long, - mode: c_long, - msDelay: c_long, - husDelay: c_long, - controlCS: c_long, - csLine: c_long, - csState: c_long, - configD: c_long, - numWriteRead: c_long, - data: [*c]c_long, -) c_long; + pub fn fromBoolArray(states: [4]bool) PackedOutput { + return .{ + .io0 = states[0], + .io1 = states[1], + .io2 = states[2], + .io3 = states[3], + }; + } -pub extern fn Watchdog( - idnum: *c_long, - demo: c_long, - active: c_long, - timeout: c_long, - reset: c_long, - activeD0: c_long, - activeD1: c_long, - activeD8: c_long, - stateD0: c_long, - stateD1: c_long, - stateD8: c_long, -) c_long; + pub fn toCLong(self: PackedOutput) c_long { + return @as(u4, @bitCast(self)); + } +}; -pub extern fn ReadMem( - idnum: *c_long, - address: c_long, - data3: [*c]c_long, - data2: [*c]c_long, - data1: [*c]c_long, - data0: [*c]c_long, -) c_long; +pub const c_api = struct { + pub extern fn EAnalogIn( + idnum: *c_long, + demo: c_long, + channel: c_long, + gain: c_long, + overVoltage: *c_long, + voltage: *f32, + ) LabjackCError; -pub extern fn WriteMem( - idnum: *c_long, - unlocked: c_long, - address: c_long, - data3: c_long, - data2: c_long, - data1: c_long, - data0: c_long, -) c_long; + pub extern fn EAnalogOut( + idnum: *c_long, + demo: c_long, + analogOut0: f32, + analogOut1: f32, + ) LabjackCError; -pub extern fn CloseLabJack( - localID: c_long, -) c_long; + pub extern fn ECount( + idnum: *c_long, + demo: c_long, + resetCounter: c_long, + count: *f64, + ms: *f64, + ) LabjackCError; + + pub extern fn EDigitalIn( + idnum: *c_long, + demo: c_long, + channel: c_long, + readD: c_long, + state: *c_long, + ) LabjackCError; + + pub extern fn EDigitalOut( + idnum: *c_long, + demo: c_long, + channel: c_long, + writeD: c_long, + state: c_long, + ) LabjackCError; + + pub extern fn AsynchConfig( + idnum: *c_long, + demo: c_long, + timeoutMult: c_long, + configA: c_long, + configB: c_long, + configTE: c_long, + fullA: c_long, + fullB: c_long, + fullC: c_long, + halfA: c_long, + halfB: c_long, + halfC: c_long, + ) LabjackCError; + + pub extern fn Asynch( + idnum: *c_long, + demo: c_long, + portB: c_long, + enableTE: c_long, + enableTO: c_long, + enableDel: c_long, + baudrate: c_long, + numWrite: c_long, + numRead: c_long, + data: [*]c_long, + ) LabjackCError; + + pub extern fn AISample( + idnum: *c_long, + demo: c_long, + stateIO: *c_long, + updateIO: c_long, + ledOn: c_long, + numChannels: c_long, + channels: [*]c_long, // numChannels length + gains: [*]c_long, // numChannels length + disableCal: c_long, + overVoltage: *c_long, + voltages: *[4]f32, + ) LabjackCError; + + pub extern fn AIBurst( + idnum: *c_long, + demo: c_long, + stateIOin: c_long, + updateIO: c_long, + ledOn: c_long, + numChannels: c_long, + channels: [*]c_long, // numChannels length + gains: [*]c_long, // numChannels length + scanRate: *f32, + disableCal: c_long, + triggerIO: c_long, // 0=none, 1=IO0, or 2=IO1 + triggerState: c_long, + numScans: c_long, + timeout: c_long, + voltages: *[4096][4]f32, + stateIOout: *[4096]c_long, + overVoltage: *c_long, + transferMode: c_long, // 0=auto,1=normal,2=turbo + ) LabjackCError; + + pub extern fn AIStreamStart( + idnum: *c_long, + demo: c_long, + stateIOin: c_long, + updateIO: c_long, + ledOn: c_long, + numChannels: c_long, + channels: [*]c_long, // numChannels length + gains: [*]c_long, // numChannels length + scanRate: *f32, + disableCal: c_long, + reserved1: c_long, // always 0 + readCount: c_long, + ) LabjackCError; + + pub extern fn AIStreamRead( + localID: c_long, + numScans: c_long, + timeout: c_long, + voltages: *[4096][4]f32, + stateIOout: *[4096]c_long, + reserved: ?*c_long, // unused + ljScanBacklog: *c_long, + overVoltage: *c_long, + ) LabjackCError; + + pub extern fn AIStreamClear( + localID: c_long, + ) LabjackCError; + + pub extern fn AOUpdate( + idnum: *c_long, + demo: c_long, + trisD: c_long, + trisIO: c_long, + stateD: [*c]c_long, + stateIO: [*c]c_long, + updateDigital: c_long, + resetCounter: c_long, + count: [*c]c_ulong, + analogOut0: f32, + analogOut1: f32, + ) LabjackCError; + + pub extern fn BitsToVolts( + chnum: c_long, + chgain: c_long, + bits: c_long, + volts: [*c]f32, + ) LabjackCError; + + pub extern fn VoltsToBits( + chnum: c_long, + chgain: c_long, + volts: f32, + bits: [*c]c_long, + ) LabjackCError; + + pub extern fn Counter( + idnum: *c_long, + demo: c_long, + stateD: [*c]c_long, + stateIO: [*c]c_long, + resetCounter: c_long, + enableSTB: c_long, + count: [*c]c_ulong, + ) LabjackCError; + + pub extern fn DigitalIO( + idnum: *c_long, + demo: c_long, + trisD: *c_long, // 16 bits + trisIO: c_long, // 4 bits + stateD: *c_long, // 16 bits + stateIO: *c_long, // 4 bits + updateDigital: c_long, + outputD: *c_long, // 16 bits + ) LabjackCError; + + pub extern fn GetDriverVersion() f32; + pub extern fn StaticErrorString(errorcode: c_long) [*:0]const u8; + pub extern fn GetErrorString(errorcode: c_long, errorString: *[50]u8) void; + pub extern fn GetFirmwareVersion(idnum: *c_long) f32; + + pub extern fn ListAll( + productIDList: *[127]c_long, + serialnumList: *[127]c_long, + localIDList: *[127]c_long, + powerList: *[127]c_long, + calMatrix: *[127][20]c_long, + numberFound: *c_long, + fcddMaxSize: *c_long, + hvcMaxSize: *c_long, + ) LabjackCError; + + pub extern fn LocalID( + idnum: *c_long, + localID: c_long, + ) LabjackCError; + + pub extern fn PulseOut( + idnum: *c_long, + demo: c_long, + lowFirst: c_long, + bitSelect: c_long, + numPulses: c_long, + timeB1: c_long, + timeC1: c_long, + timeB2: c_long, + timeC2: c_long, + ) LabjackCError; + + pub extern fn PulseOutStart( + idnum: *c_long, + demo: c_long, + lowFirst: c_long, + bitSelect: c_long, + numPulses: c_long, + timeB1: c_long, + timeC1: c_long, + timeB2: c_long, + timeC2: c_long, + ) LabjackCError; + + pub extern fn PulseOutFinish( + idnum: *c_long, + demo: c_long, + timeoutMS: c_long, + ) LabjackCError; + + pub extern fn PulseOutCalc( + frequency: *f32, + timeB: *c_long, + timeC: *c_long, + ) LabjackCError; + + pub extern fn ReEnum(idnum: *c_long) LabjackCError; + pub extern fn Reset(idnum: *c_long) LabjackCError; + pub extern fn ResetLJ(idnum: *c_long) LabjackCError; + pub extern fn CloseLabJack(localID: c_long) LabjackCError; + + pub extern fn SHT1X( + idnum: *c_long, + demo: c_long, + softComm: c_long, + mode: c_long, + statusReg: c_long, + tempC: *f32, + tempF: *f32, + rh: *f32, + ) LabjackCError; + + pub extern fn SHTComm( + idnum: *c_long, + softComm: c_long, + waitMeas: c_long, + serialReset: c_long, + dataRate: c_long, + numWrite: c_long, + numRead: c_long, + datatx: [*]u8, // numWrite length + datarx: [*]u8, // numRead length + ) LabjackCError; + + pub extern fn SHTCRC( + statusReg: c_long, + numWrite: c_long, + numRead: c_long, + datatx: *[4]u8, + datarx: *[4]u8, + ) LabjackCError; + + pub extern fn Synch( + idnum: *c_long, + demo: c_long, + mode: c_long, + msDelay: c_long, + husDelay: c_long, + controlCS: c_long, + csLine: c_long, + csState: c_long, + configD: c_long, + numWriteRead: c_long, + data: *[18]c_long, + ) LabjackCError; + + pub extern fn Watchdog( + idnum: *c_long, + demo: c_long, + active: c_long, + timeout: c_long, + reset: c_long, + activeD0: c_long, + activeD1: c_long, + activeD8: c_long, + stateD0: c_long, + stateD1: c_long, + stateD8: c_long, + ) LabjackCError; + + pub extern fn ReadMem( + idnum: *c_long, + address: c_long, + data3: *c_long, + data2: *c_long, + data1: *c_long, + data0: *c_long, + ) LabjackCError; + + pub extern fn WriteMem( + idnum: *c_long, + unlocked: c_long, + address: c_long, + data3: c_long, + data2: c_long, + data1: c_long, + data0: c_long, + ) LabjackCError; + + pub const LabjackCError = packed struct(c_ulong) { + code: LabjackErrorCode, + stream_thread_error_flag: u1, + firmware_version_error_flag: u1, + _unused: switch (@typeInfo(c_ulong).Int.bits) { + 32 => u22, + 64 => u54, + else => @compileError("c_ulong has a mystery number of bits"), + }, + + pub fn okay(self: LabjackCError) bool { + return self.code == .no_error; + } + + pub fn toError(self: LabjackCError) LabjackError { + return switch (self.code) { + .no_error => error.UnknownError, + .unknown_error => error.UnknownError, + .no_devices_found => error.NoDevicesFound, + .device_n_not_found => error.DeviceNNotFound, + .set_buffer_error => error.SetBufferError, + .open_handle_error => error.OpenHandleError, + .close_handle_error => error.CloseHandleError, + .invalid_id => error.InvalidId, + .array_size_or_value_error => error.ArraySizeOrValueError, + .invalid_power_index => error.InvalidPowerIndex, + .fcdd_size => error.FcddSize, + .hvc_size => error.HvcSize, + .read_error => error.ReadError, + .read_timeout_error => error.ReadTimeoutError, + .write_error => error.WriteError, + .feature_error => error.FeatureError, + .illegal_channel => error.IllegalChannel, + .illegal_gain_index => error.IllegalGainIndex, + .illegal_ai_command => error.IllegalAiCommand, + .illegal_ao_command => error.IllegalAoCommand, + .bits_out_of_range => error.BitsOutOfRange, + .illegal_number_of_channels => error.IllegalNumberOfChannels, + .illegal_scan_rate => error.IllegalScanRate, + .illegal_num_samples => error.IllegalNumSamples, + .ai_response_error => error.AiResponseError, + .ram_cs_error => error.RamCsError, + .ai_sequence_error => error.AiSequenceError, + .num_streams_error => error.NumStreamsError, + .ai_stream_start => error.AiStreamStart, + .pc_buff_overflow => error.PcBuffOverflow, + .lj_buff_overflow => error.LjBuffOverflow, + .stream_read_timeout => error.StreamReadTimeout, + .illegal_num_scans => error.IllegalNumScans, + .no_stream_found => error.NoStreamFound, + .illegal_input_error => error.IllegalInput, + .echo_error => error.EchoError, + .data_echo_error => error.DataEchoError, + .response_error => error.ResponseError, + .asynch_timeout_error => error.AsynchTimeout, + .asynch_start_error => error.AsynchStartError, + .asynch_frame_error => error.AsynchFrameError, + .asynch_dio_config_error => error.AsynchDioConfigError, + .input_caps_error => error.InputCapsError, + .output_caps_error => error.OutputCapsError, + .feature_caps_error => error.FeatureCapsError, + .num_caps_error => error.NumCapsError, + .get_attributes_warning => error.GetAttributesWarning, + .wrong_firmware_version => error.WrongFirmwareVersion, + .dio_config_error => error.DioConfigError, + .claim_all_devices => error.ClaimAllDevices, + .release_all_devices => error.ReleaseAllDevices, + .claim_device => error.ClaimDevice, + .release_device => error.ReleaseDevice, + .claimed_abandoned => error.ClaimedAbandoned, + .localid_neg => error.LocalidNeg, + .stop_thread_timeout => error.StopThreadTimeout, + .terminate_thread => error.TerminateThread, + .feature_handle => error.FeatureHandle, + .create_mutex => error.CreateMutex, + .synch_csstatetris_error => error.SynchCsstatetrisError, + .synch_scktris_error => error.SynchScktrisError, + .synch_misotris_error => error.SynchMisotrisError, + .synch_mositris_error => error.SynchMositrisError, + .sht1x_crc_error => error.Sht1xCrcError, + .sht1x_measready_error => error.Sht1xMeasreadyError, + .sht1x_ack_error => error.Sht1xAckError, + .sht1x_serial_reset_error => error.Sht1xSerialResetError, + _ => error.UnknownErrorCode, + }; + } + + pub const LabjackErrorCode = enum(u8) { + no_error = 0, // must be 0 + unknown_error = 1, + no_devices_found = 2, + device_n_not_found = 3, + set_buffer_error = 4, + open_handle_error = 5, + close_handle_error = 6, + invalid_id = 7, + array_size_or_value_error = 8, + invalid_power_index = 9, + fcdd_size = 10, + hvc_size = 11, + read_error = 12, + read_timeout_error = 13, + write_error = 14, + feature_error = 15, + illegal_channel = 16, + illegal_gain_index = 17, + illegal_ai_command = 18, + illegal_ao_command = 19, + bits_out_of_range = 20, + illegal_number_of_channels = 21, + illegal_scan_rate = 22, + illegal_num_samples = 23, + ai_response_error = 24, + ram_cs_error = 25, + ai_sequence_error = 26, + num_streams_error = 27, + ai_stream_start = 28, + pc_buff_overflow = 29, + lj_buff_overflow = 30, + stream_read_timeout = 31, + illegal_num_scans = 32, + no_stream_found = 33, + illegal_input_error = 40, + echo_error = 41, + data_echo_error = 42, + response_error = 43, + asynch_timeout_error = 44, + asynch_start_error = 45, + asynch_frame_error = 46, + asynch_dio_config_error = 47, + input_caps_error = 48, + output_caps_error = 49, + feature_caps_error = 50, + num_caps_error = 51, + get_attributes_warning = 52, + wrong_firmware_version = 57, + dio_config_error = 58, + claim_all_devices = 64, + release_all_devices = 65, + claim_device = 66, + release_device = 67, + claimed_abandoned = 68, + localid_neg = 69, + stop_thread_timeout = 70, + terminate_thread = 71, + feature_handle = 72, + create_mutex = 73, + synch_csstatetris_error = 80, + synch_scktris_error = 81, + synch_misotris_error = 82, + synch_mositris_error = 83, + sht1x_crc_error = 89, + sht1x_measready_error = 90, + sht1x_ack_error = 91, + sht1x_serial_reset_error = 92, + _, + + pub fn describe(self: LabjackErrorCode) []const u8 { + const res = StaticErrorString(@intFromEnum(self)); + return std.mem.sliceTo(res, 0); + } + }; + }; +}; + +pub const LabjackError = error{ + UnknownError, + NoDevicesFound, + DeviceNNotFound, + SetBufferError, + OpenHandleError, + CloseHandleError, + InvalidId, + ArraySizeOrValueError, + InvalidPowerIndex, + FcddSize, + HvcSize, + ReadError, + ReadTimeoutError, + WriteError, + FeatureError, + IllegalChannel, + IllegalGainIndex, + IllegalAiCommand, + IllegalAoCommand, + BitsOutOfRange, + IllegalNumberOfChannels, + IllegalScanRate, + IllegalNumSamples, + AiResponseError, + RamCsError, + AiSequenceError, + NumStreamsError, + AiStreamStart, + PcBuffOverflow, + LjBuffOverflow, + StreamReadTimeout, + IllegalNumScans, + NoStreamFound, + IllegalInput, + EchoError, + DataEchoError, + ResponseError, + AsynchTimeout, + AsynchStartError, + AsynchFrameError, + AsynchDioConfigError, + InputCapsError, + OutputCapsError, + FeatureCapsError, + NumCapsError, + GetAttributesWarning, + WrongFirmwareVersion, + DioConfigError, + ClaimAllDevices, + ReleaseAllDevices, + ClaimDevice, + ReleaseDevice, + ClaimedAbandoned, + LocalidNeg, + StopThreadTimeout, + TerminateThread, + FeatureHandle, + CreateMutex, + SynchCsstatetrisError, + SynchScktrisError, + SynchMisotrisError, + SynchMositrisError, + Sht1xCrcError, + Sht1xMeasreadyError, + Sht1xAckError, + Sht1xSerialResetError, + UnknownErrorCode, + // + InvalidGain, +}; diff --git a/src/main.zig b/src/main.zig index fa78189..f72cbc0 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3,6 +3,23 @@ const std = @import("std"); const ljack = @import("./ljacklm.zig"); pub fn main() !void { - const ver = ljack.GetDriverVersion(); + const ver = ljack.getDriverVersion(); std.debug.print("Driver version: {d}\n", .{ver}); + + const device = ljack.Labjack.autodetect(); + + const in = try device.analogReadOne(.{ .channel = .diff_01, .gain = 2 }); + std.debug.print("Read voltage: {d}. Overvolt: {}\n", .{ in.voltage, in.over_voltage }); + try device.digitalWriteOne(.{ .channel = .{ .io = 0 }, .level = true }); + + const sample = try device.readAnalogWriteDigital( + 2, + .{ .{ .channel = .diff_01, .gain = 2 }, .{ .channel = .diff_23, .gain = 2 } }, + .{false} ** 4, + true, + ); + + for (sample, 0..) |input, idx| { + std.debug.print(" channel {d}: {d} V\n", .{ idx, input.voltage }); + } }