Wondering if there might be an example code (ideally python, but I could try converting C) anywhere for reading a given file from the SD card? I'm going to have a lua script making a bunch of files on the SD card with known names and want to read them from my computer without shutting down the labjack.
What operating system are you using? If you're using Windows, you can use the SD card utility.
We don't have an example, but the SD Card page describes how to do it. See the steps for "Read a file" under Common File I/O Operations.
We're using macOS. And I'm looking to do real-time extraction of the data as it is logged to file. I've been looking at the C examples, but is it possible the documentation is in error? There are address names referred to in the "Common File I/O operations" that are not present in the subsequent Register Listing. For example, "FILE_IO_NAME_READ_LEN", "FILE_IO_NAME_READ", "FILE_IO_NAME_WRITE_LEN", & "FILE_IO_NAME_WRITE".
Made some headway. Below is some python code implementing some operations, but I'm getting an FILE_IO_INVALID_OBJECT error when I get to the line with ljm.eReadName(handle,'FILE_IO_OPEN'). Any ideas what I'm doing wrong?
########
# Initialize
########
from labjack import ljm
handle = ljm.open(ljm.constants.dtT7, ljm.constants.ctANY, "ANY")
########
#Get name of current working directory
########
# 1) Write a value of 1 to FILE_IO_DIR_CURRENT. The error returned indicates whether there is a directory loaded as current. No error (0) indicates a valid directory.
ljm.eWriteName(handle,'FILE_IO_DIR_CURRENT',1)
# 2) Read FILE_IO_NAME_READ_LEN.
cwd_name_len = int(ljm.eReadName(handle,'FILE_IO_NAME_READ_LEN'))
# 3) Read an array of size FILE_IO_NAME_READ_LEN from FILE_IO_NAME_READ.
cwd_name_as_bytes = ljm.eReadNameByteArray(handle,'FILE_IO_PATH_READ',cwd_name_len)
#print(cwd_name_as_bytes) #show what we read
# convert to string
cwd_name_as_strings = "".join( chr(x) for x in cwd_name_as_bytes)
print([cwd_name_as_strings]) #encapsulated in [] to avoid showing empty space when string is "\x00"
########
# Get list of items in the CWD:
########
# 1) Write a value of 1 to FILE_IO_DIR_FIRST. The error returned indicates whether anything was found. No error (0) indicates that something was found. FILE_IO_NOT_FOUND (2960) indicates that nothing was found.
ljm.eWriteName(handle,'FILE_IO_DIR_FIRST',1)
#loop, reading name of one file per iteration
list_of_file_name_as_bytes = []
no_more_files = False
while not no_more_files:
# 2) Read FILE_IO_NAME_READ_LEN, FILE_IO_ATTRIBUTES, and FILE_IO_SIZE. Store the attributes and size associated with each file.
file_name_len = int(ljm.eReadName(handle,'FILE_IO_NAME_READ_LEN'))
# 3) Read an array from FILE_IO_NAME_READ of size FILE_IO_NAME_READ_LEN. This is the name of the file/folder.
file_name_as_bytes = ljm.eReadNameByteArray(handle,'FILE_IO_PATH_READ',file_name_len)
#print(file_name_as_bytes) #show what we read
#add to list
list_of_file_name_as_bytes.append(file_name_as_bytes)
# convert to string & print
file_name_as_strings = "".join( chr(x) for x in file_name_as_bytes)
print([file_name_as_strings]) #encapsulated in [] to avoid showing empty space when string is "\x00"
# 4) Write a value of 1 to FILE_IO_DIR_NEXT. The error returned indicates whether anything was found. No error (0) indicates that there are more items->go back to step 2. FILE_IO_INVALID_OBJECT (2809) and potentially error code FILE_IO_NOT_FOUND (2960) indicates that there are no more items->Done.
try:
ljm.eWriteName(handle,'FILE_IO_DIR_NEXT',1)
except:
no_more_files = True
########
# Read a file:
########
file_name_as_bytes = list_of_file_name_as_bytes[0] #cwd_name_as_bytes[0:-1]+list_of_file_name_as_bytes[0]
file_name_len = len(file_name_as_bytes)
# 1) Write the length of the file name to FILE_IO_NAME_WRITE_LEN (add 1 for the null terminator)
ljm.eWriteName(handle,'FILE_IO_NAME_WRITE_LEN',file_name_len)
# 2) Write the name to FILE_IO_NAME_WRITE (with null terminator)
ljm.eWriteNameByteArray(handle,'FILE_IO_NAME_WRITE',file_name_len,file_name_as_bytes)
# 3) Read from FILE_IO_OPEN
ljm.eReadName(handle,'FILE_IO_OPEN')
# 4) Read file data from FILE_IO_READ (using the size from FILE_IO_SIZE)
file_data_as_bytes = ljm.eReadNameByteArray(handle,'FILE_IO_READ',int(ljm.eReadName(handle,'FILE_IO_SIZE_BYTES')))
# 5) Write a value of 1 to FILE_IO_CLOSE
ljm.eWriteName(handle,'FILE_IO_CLOSE',1)
Sorry about that—there were old names being used on that page. I've updated the register names to be current. Thanks for pointing that out.
In regards to the FILE_IO_INVALID_OBJECT error, it looks like your code mentions that it should add one to the FILE_IO_PATH_WRITE_LEN_BYTES for the null terminator and and it also says that it should add a null terminator to FILE_IO_PATH_WRITE, but I can't tell that the code is doing those two things. The null terminator is 0.
The `ljm.eReadNameByteArray` command returns a byte array that contains a null byte at the end, so I don't think adding one is necessary. When I tried adding one, it yields the same error as noted above.
Also, some new typos on the docs page:
"Read an array of size FILE_IO_PATH_READ_LEN_BYTES from FILE_IO_PATH_READ_LEN_BYTES."
should be:
"Read an array of size FILE_IO_PATH_READ_LEN_BYTES from FILE_IO_PATH_READ."
"Read an array from FILE_IO_PATH_READ_LEN_BYTES of size FILE_IO_PATH_READ_LEN_BYTES."
should be:
"Read an array of size FILE_IO_PATH_READ_LEN_BYTES from FILE_IO_PATH_READ."
Thank you for pointing out the typos. They're fixed.
I've tried replicating the issue you're seeing and am having problems at the same spot as you. I will update this thread when I have something to report.
The documentation for "Read a file" was incorrect. I've bolded two corrections below:
Fantastic, that works. Thanks so much for your help!
Perfect, thanks for all your help. For posterity, here's the full python code:
########
# Initialize
########
from labjack import ljm
handle = ljm.open(ljm.constants.dtT7, ljm.constants.ctANY, "ANY")
########
#Get name of current working directory
########
# 1) Write a value of 1 to FILE_IO_DIR_CURRENT. The error returned indicates whether there is a directory loaded as current. No error (0) indicates a valid directory.
ljm.eWriteName(handle,'FILE_IO_DIR_CURRENT',1)
# 2) Read FILE_IO_PATH_READ_LEN_BYTES.
len_cwd_name_as_bytes = int(ljm.eReadName(handle,'FILE_IO_PATH_READ_LEN_BYTES'))
# 3) Read an array of size FILE_IO_PATH_READ_LEN_BYTES from FILE_IO_PATH_READ.
cwd_name_as_bytes = ljm.eReadNameByteArray(handle,'FILE_IO_PATH_READ',len_cwd_name_as_bytes)
print(cwd_name_as_bytes) #show what we read
# convert to string
cwd_name_as_string = "".join( chr(x) for x in cwd_name_as_bytes)
print([cwd_name_as_string]) #encapsulated in [] to avoid showing empty space when string is "\x00"
########
# Get list of items in the CWD:
########
# 1) Write a value of 1 to FILE_IO_DIR_FIRST. The error returned indicates whether anything was found. No error (0) indicates that something was found. FILE_IO_NOT_FOUND (2960) indicates that nothing was found.
ljm.eWriteName(handle,'FILE_IO_DIR_FIRST',1)
#loop, reading name of one file per iteration
list_of_file_name_as_bytes = []
list_of_file_sizes = []
more_files = True
while more_files:
#
# 2) Read FILE_IO_PATH_READ_LEN_BYTES
len_file_name_as_bytes = int(ljm.eReadName(handle,'FILE_IO_PATH_READ_LEN_BYTES'))
#
# 3) Read an array of size FILE_IO_PATH_READ_LEN_BYTES from FILE_IO_PATH_READ.
file_name_as_bytes = ljm.eReadNameByteArray(handle,'FILE_IO_PATH_READ',len_file_name_as_bytes)
#print(file_name_as_bytes) #show what we read
# 3b) Read FILE_IO_SIZE_BYTES
list_of_file_sizes.append(int(ljm.eReadName(handle,'FILE_IO_SIZE_BYTES')))
#
#add to list
list_of_file_name_as_bytes.append(file_name_as_bytes)
#
# convert to string & print
file_name_as_strings = "".join( chr(x) for x in file_name_as_bytes)
print([file_name_as_strings]) #encapsulated in [] to avoid showing empty space when string is "\x00"
#
# 4) Write a value of 1 to FILE_IO_DIR_NEXT. The error returned indicates whether anything was found. No error (0) indicates that there are more items->go back to step 2. FILE_IO_INVALID_OBJECT (2809) and potentially error code FILE_IO_NOT_FOUND (2960) indicates that there are no more items->Done.
try:
ljm.eWriteName(handle,'FILE_IO_DIR_NEXT',1)
except:
more_files = False
########
# Read a file:
########
#get values of a specific file from lists generated while listing files
size_of_file_data_as_bytes = list_of_file_sizes[0]
file_name_as_bytes = list_of_file_name_as_bytes[0]
len_file_name_as_bytes = len(file_name_as_bytes)
# 1) Write the length of the file name (including the null terminator) to FILE_IO_PATH_WRITE_LEN_BYTES
ljm.eWriteName(handle,'FILE_IO_PATH_WRITE_LEN_BYTES',len_file_name_as_bytes)
# 2) Write the name to FILE_IO_NAME_WRITE (with null terminator)
ljm.eWriteNameByteArray(handle,'FILE_IO_PATH_WRITE',len_file_name_as_bytes,file_name_as_bytes)
# 3) Write any value to FILE_IO_OPEN
ljm.eWriteName(handle,'FILE_IO_OPEN',1)
# 4) Read file data from FILE_IO_READ (using the size from FILE_IO_SIZE)
file_data_as_bytes = ljm.eReadNameByteArray(handle,'FILE_IO_READ',size_of_file_data_as_bytes)
# 5) Write a value of 1 to FILE_IO_CLOSE
ljm.eWriteName(handle,'FILE_IO_CLOSE',1)
#convert data bytes to string
file_data_as_string = "".join( chr(x) for x in file_data_as_bytes)
Hi, I'm new to the labjack and am just geting my head around LUA logging and file retrieval.
The SD Card datasheet page indicates "Create a directory: Unimplemented. Since Lua scripts currently do not have the ability to write files anywhere except the root directory, this feature is not implemented." No probelms here, makes sense.
However, my labjack LUA script writes the log file into whatever the CWD is - which seems to be based on some internal process saving settings rather than always in the root as per the datasheet information. See the screenshot of the file access utility and note where log1.csv has been placed by the lua script.
Secondary question: How do you change the CWD to a lower level? example if the CWD is "system volume information" and the desired CWD is the root, how do you get there?
I tested a few things and was only able to get the write directory set back to root by power cycling the unit. I will get the firmware department to look into this further.
The easy answer is to append '/' to the front of the file name. For example, "/log33.csv" will be placed in root of drive 0 (only drive available on the T7, and "log33.csv" will be placed in the CWD.
Thankyou. The '/' at the start of the filename seems to have the LUA placing the file in the root.
The next chapter is retrieveing the file. I'm using the example above for SD card access, and have yet to discover a way to force the CWD back to the root. I will try sending device reboot commands as a workaround for now.
With the LJM C/C++ examples (C_C++_LJM_2019-03-27, which is the current beta release), I'm able to use more/sd/change_directory.cpp to successfully change between root and non-root directories:
$ ./list_directory
Default Directory Contents:
Name Type Size
...
some_dir Folder
...
$ ./change_directory some_dir
$ ./print_working_directory
/some_dir
$ ./change_directory /
$ ./print_working_directory
/
The relevant code is in sd_util.hpp:
void GoToPath(int handle, const char * sdPath)
{
int err;
int errAddr = -1;
// Add 1 for null terminator
int pathLen = strlen(sdPath) + 1;
// 1) Write the length of the file name to FILE_IO_PATH_WRITE_LEN_BYTES
err = LJM_eWriteName(handle, "FILE_IO_PATH_WRITE_LEN_BYTES", pathLen);
ErrorCheck(err, "eWriteName(handle, FILE_IO_PATH_WRITE_LEN_BYTES)");
// 2) Write the directory string (converted to an array of bytes, with null
// terminator) to FILE_IO_PATH_WRITE. (array size = length from step 2)
err = LJM_eWriteNameByteArray(handle, "FILE_IO_PATH_WRITE", pathLen,
sdPath, &errAddr);
ErrorCheck(err, "eWriteNameByteArray(handle, FILE_IO_PATH_WRITE)");
// 3) Write a value of 1 to FILE_IO_DIR_CHANGE.
err = LJM_eWriteName(handle, "FILE_IO_DIR_CHANGE", 1);
ErrorCheck(err, "eWriteName(handle, FILE_IO_DIR_CHANGE)");
}
Hi,
I have a highspeed pump that i would like to control the speed using a slider as shown in the attached front panel. Currently, the pump is connected to TDAC0 on labjack and setted max. voltage of the pump is 10V. Can anyone help me where to put this slider in the block diagram to control the speed of the pump?
Thanks,
Start by connecting the slider to a numeric display. Then run the program and watch the display as you move the slider. You should get a range of number. That range can be configured within the control's options. Or we can apply some math to convert the slider's range to the desired voltage range. The calculated voltage can then be pipped into the eWriteName subVI that is setting TDAC0. You will need to disconnect the 10V control and connect in your calculated voltage.
working in python:
ljm.eWriteName(handle, "FILE_IO_PATH_WRITE_LEN_BYTES", 2)
ljm.eWriteNameArray(handle, "FILE_IO_PATH_WRITE", 2, "/\x00".encode("UTF-8"))
ljm.eWriteName(handle, "FILE_IO_DIR_CHANGE", 1)
This is now getting the logger back to the root directory.
thanks.