Jump to content

All Activity

This stream auto-updates     

  1. Today
  2. I’m pretty sure that’s the easiest to implement, so I’m liking your opinion. (Trying to be non-biased, I do think that’s the better option from usability. If I pick a name in a template, it’s because I expect the provided thing to use that name. It is consistent with the class method behavior, but for cluster fields.)
  3. Not sure if this is the right place for this, so mods please feel free to move if it is not. I have just started to play around with the Web Module in NXG 4.0. There are quite a few tutorials around, but (unless I have missed something) all of them seem to gloss over the task of getting a trivially simple web VI actually running locally. After a bit of head scratching I did manage to get something up and running eventually, but have a question which is hopefully simple for anyone who has used the Web Module. When running the web VI inside the NXG IDE, is there anything actually hosting it? In other words can I visit some address from my web browse to see it running while I am developing it? Or do I have to build (i.e. turn into html and JS) and then copy the files manually to my NI Web Server directory?
  4. I'm favouring just freeze the name, as that is simplest for the User to understand, given that it is difficult to diagnose, let alone fix, any problem if the name adaption goes wrong.
  5. I have no idea why that limitation exists. I’ll ask on Monday.
  6. Huh. I never considered that case. Everything is behaving as designed... but that’s clearly not desirable. So far, no node has custom type prop behavior when inside a VIM other than the adaptive class method calls. You’re suggesting (I think rightly) that (un)bundle nodes need to adapt different inside VIMs than in VIs. I’d have to teach the bundle by name nodes to have deeper history than they currently have so they always compute from original configuration instead of latest configuration. Or... would it be better to just freeze the named bundle nodes inside VIMs so they always look for the exact name? There’s some risk with either solution to break existing VIMs, but the current model seems mostly useless. What option sounds best? One of the two options is waaaaay easier to implement, and I’m trying not to let that sway me. 🙂
  7. Yesterday
  8. Hello there, Exactly the same problem trying to call dynamically a .m script from a LV exe in LV 2017 (so it is run in the MathScriptNode). It works using the IDE but not as an exe. Has there been any changes from NI on this? Thx. Note: guessing no, as the .m files are interpreted & compiled at build time since the interpreter is not included in the run-time engine...
  9. Question for AQ: I'm trying to use "Unbundle by name" to access the elements of the cluster (the buffer array and the index integers). This works, but if the User accidently connects a cluster without the right-named elements, the unbundles can get scrambled, and not properly reset to the right names when a proper Buffer cluster is attached. The only solution then is to delete that VIM instance and re-drop it from the pallets. I can't find a solution and may have to switch to an unnamed unbundle, using the positions in the cluster. That is less than ideal, and won't work in NXG (you know my negative opinions on cluster changes made in NXG).
  10. DVRs can be used, but not created or destroyed, inside an inline VI. Not clear to me why that is. Thus this library can handle buffers inside DVRs, but the User has to explicitly create a by-value buffer and put it in a DVR themselves.
  11. DVRs in VIMs works just fine (just double checked). It has worked since the feature released, still works in 2019. I have no idea what you’re talking about.
  12. Last week
  13. There were a few errors in how you created the linked list. I did this and did a quick test and it seemed to work. The chunk in the debugger is expected. The debugger does not know anything about LabVIEW Long Pascal handles and that they contain an int32 cnt parameter in front of the string and no NULL termination character. So it sees a char array element and tries to interpret it until it sees a NULL value, which is of course more or less beyond the actual valid information. #include "extcode.h" #include "stdlib.h" #include "string.h" typedef struct IIR_USB_RELAY_DEVICE_INFO { char *serial_number; struct IIR_USB_RELAY_DEVICE_INFO *next; } IIR_USB_RELAY_DEVICE_INFO_T; static IIR_USB_RELAY_DEVICE_INFO_T* iir_usb_relay_device_enumerate() { int i, len; IIR_USB_RELAY_DEVICE_INFO_T *ptr, *deviceInfo = NULL; const char* sn[] = { "abcd", "efgh", "ijkl", NULL }; for (i = 0; sn[i]; i++) { IIR_USB_RELAY_DEVICE_INFO_T* info = (IIR_USB_RELAY_DEVICE_INFO_T*)malloc(sizeof(IIR_USB_RELAY_DEVICE_INFO_T)); len = (int32)strlen(sn[i]) + 1; info->serial_number = (unsigned char*)malloc(len); memcpy(info->serial_number, sn[i], len); info->next = NULL; if (!deviceInfo) { deviceInfo = info; } else { ptr->next = info; } ptr = info; } return deviceInfo; } static void iir_usb_relay_device_free_enumerate(IIR_USB_RELAY_DEVICE_INFO_T *deviceInfo) { IIR_USB_RELAY_DEVICE_INFO_T *ptr; while (deviceInfo) { ptr = deviceInfo; deviceInfo = deviceInfo->next; free(ptr->serial_number); free(ptr); } } #define EXPORT_API __declspec(dllexport) /* Make sure to wrap any data structure definitions that are passed from and to LabVIEW with the two include files that make sure to set and reset the memory alignment to what LabVIEW expects for the current platform */ #include "lv_prolog.h" typedef struct { int32 cnt; LStrHandle elm[]; } **LStrArrayHandle; #include "lv_epilog.h" /* define a typecode that depends on the bitness of the platform to indicate the pointer size */ #if IsOpSystem64Bit #define uPtr uQ #else #define uPtr uL #endif MgErr EXPORT_API iir_get_serial_numbers(LStrArrayHandle *arr) { MgErr err = mgNoErr; LStrHandle *pH = NULL; int len, i, n = (*arr) ? (**arr)->cnt : 0; IIR_USB_RELAY_DEVICE_INFO_T *ptr, *deviceInfo = iir_usb_relay_device_enumerate(); /* This only works reliably if there is guaranteed that the deviceInfo linked list won't change in the background while we are in this function! */ for (i = 0, ptr = deviceInfo; ptr; ptr = ptr->next, i++) { /* Resize the array handle only in power of 2 intervals to reduce the potential overhead for resizing and reallocating the array buffer every time! */ if (i >= n) { if (n) n = n << 1; else n = 8; err = NumericArrayResize(uPtr, 1, (UHandle*)arr, n); if (err) break; } len = (int32)strlen(ptr->serial_number); pH = (**arr)->elm + i; err = NumericArrayResize(uB, 1, (UHandle*)pH, len); if (!err) { MoveBlock(ptr->serial_number, LStrBuf(**pH), len); LStrLen(**pH) = len; } else break; } iir_usb_relay_device_free_enumerate(deviceInfo); /* If we did not find any device AND the incoming array was empty it may be NULL as this is the canonical empty array value in LabVIEW. So check that we have not such a canonical empty array before trying to do anything with it! It is valid to return a valid array handle with the count value set to 0 to indicate an empty array!*/ if (*arr) { /* If the incoming array was bigger than the new one, make sure to deallocate superfluous strings in the array! This may look superstitious but is a very valid possibility as LabVIEW may decide to reuse the array from a previous call to this function in a any Call Library Node instance! */ n = (**arr)->cnt; for (pH = (**arr)->elm + (n - 1); n > i; n--, pH--) { if (*pH) { DSDisposeHandle(*pH); *pH = NULL; } } (**arr)->cnt = i; } return err; }
  14. Ah, that makes sense. Needs to be a pointer to the handle... I am not currently crashing mid-function anymore, but i do crash when it reaches the end. I have attached the code as it stands now. I'm creating a linked list myself since I don't have access to the hardware. I am seeing something strange in the visual studio debugger. Notice the value of the str variable in hdl has some junk after "efgh." It's making me think something in the resize and MoveBlock aren't quite right, but I can't figure out what. int EXPORT_API iir_get_serial_numbers(LStrArrayHandle *arr) { MgErr err = mgNoErr; IIR_USB_RELAY_DEVICE_INFO_T* ptr = NULL; IIR_USB_RELAY_DEVICE_INFO_T* deviceInfo = NULL; IIR_USB_RELAY_DEVICE_INFO_T *prev = NULL; LStrHandle *pH = NULL; const char* sn[] = { "abcd", "efgh", "ijkl" }; int len, i = 0, n = (*arr) ? (**arr)->cnt : 0; for (int j = 0;j < 3;++j) { IIR_USB_RELAY_DEVICE_INFO_T* info = (IIR_USB_RELAY_DEVICE_INFO_T*)malloc(sizeof(IIR_USB_RELAY_DEVICE_INFO_T)); info->serial_number = (unsigned char*)malloc(5*sizeof(unsigned char*)); strcpy_s(info->serial_number,5*sizeof(unsigned char*),sn[j]); info->next = NULL; if (!deviceInfo) { deviceInfo = info; } else { prev->next = info; } prev = info; } //IIR_USB_RELAY_DEVICE_INFO_T* deviceInfo = (IIR_USB_RELAY_DEVICE_INFO_T*)iir_usb_relay_device_enumerate(); /* This only works reliably if there is guaranteed that the deviceInfo linked list won't change in the background while we are in this function! */ for (ptr = deviceInfo; ptr; ptr = ptr->next, i++) { /* Resize the array handle only in power of 2 intervals to reduce the potential overhead for resizing and reallocating the array buffer every time! */ if (i >= n) { if (n) n = n << 1; else n = 8; err = NumericArrayResize(uPtr, 1, (UHandle*)arr, n); if (err) break; } len = strlen(ptr->serial_number); pH = (**arr)->elm + i; err = NumericArrayResize(uB, 1, (UHandle*)pH, len); if (!err) { MoveBlock(ptr->serial_number, LStrBuf(**pH), len); LStrLen(**pH) = len; } else break; } if (deviceInfo) { IIR_USB_RELAY_DEVICE_INFO_T *t; while (deviceInfo != NULL) { t = deviceInfo; deviceInfo = deviceInfo->next; free(t); } } /* If we did not find any device AND the incoming array was empty it may be NULL as this is the canonical empty array value in LabVIEW. So check that we have not such a canonical empty array before trying to do anything with it! It is valid to return a valid array handle with the count value set to 0 to indicate an empty array!*/ if (*arr) { /* If the incoming array was bigger than the new one, make sure to deallocate superfluous strings in the array! This may look superstitious but is a very valid possibility as LabVIEW may decide to reuse the array from a previous call to this function in a any Call Library Node instance! */ n = (**arr)->cnt; for (pH = (**arr)->elm + (n - 1); n > i; n--, pH--) { if (*pH) { DSDisposeHandle(*pH); *pH = NULL; } } (**arr)->cnt = i + 1; char buf[1024]; LStrHandle hdl; for (int k = 0; k < ((**arr)->cnt);++k) { hdl = (**arr)->elm[k]; } } //iir_usb_relay_device_free_enumerate(deviceInfo); return err; }
  15. Where can I sign the petition to hand over NI's social media accounts to you?
  16. All of the presentations are now on the LabVIEW Wiki. You can find them at: https://labviewwiki.org/wiki/Americas_CLA_Summit_2019 Thanks Kevin Shirey and Mark Balla for producing the videos and all those that volunteered to run the cameras. This is an awesome resource to be able to go re-watch and review these great presentations again or for those that couldn't join us in person to be able to view them as well.
  17. uQ is the LabVIEW typcode for an unsigned 8 byte integer (uInt64). uL is the typecode for a uInt32. These are the sizes of a pointer in the respective environment and a LabVIEW handle is a pointer! You are right of course. That was a typo! But the real typo is in the declaration: LStrHandle *pH = NULL; The rest of the code is meant to have this variable be a reference to the handle not the handle itself.
  18. Thanks @Stinus Olsen, will look into some of these. The tool I made can now extract and re-create most VIs, like this: ./readRSRC.py -vvv -x -i './examples/empty_vifile_lv14f1.vi' ./readRSRC.py -vvv -c -m './empty_vifile_lv14f1.xml' cmp -l './examples/empty_vifile_lv14f1.vi' './empty_vifile_lv14f1.vi' Though there are still a few for which `cmp` shows difference between original file and re-created one (I've run it on the standard VIs from LV2014, on thousands of files only a few had differences). Also, it currently leaves all Blocks as BIN files - does not parse their content.
  19. I assume you meant this video? There is this older video of Dr. T and Jeff K. introducing a LabVIEW Basics Interactive CD-ROM (~LabVIEW 4), but it's not as exciting as the LabVIEW 5 promo.
  20. If you do this, you still end up with a broken buffer wire (you just also get a broken data wire if you choose to incorrectly wire in a scalar). Note that the type of the output wire now matches the input wire now instead of being a DVR. I am using LV2019 64-bit in case 2018 32-bit has a different implementation. If you then convert the malleable vi to an instance vi or copy the type specialization node into the top-level vi, both wires unbreak. Also note that nothing changes if you also do the same change (adding a third case with a passthrough on top and broken data wire on bottom) on the Add to Buffer (By Value).vim called in the Type Specialization [0] and [1] cases.
  21. Never mind. It seems that you cannot have DVRs inside VIMs any more.
  22. Actually, I did this yesterday to try and figure out the datatypes 😂. I thought some other magic was happening but I suppose not. I guess my question then becomes, why do we choose the particular sizes for uPtr, and how does that translate to our struct size? I suppose I'm just not understanding the relation between uPtr, the cast of arr to UHandle, and 'n' in terms of what is being done inside that resize function. Anyways, unfortunately I keep crashing here: err = NumericArrayResize(uB, 1, (UHandle*)pH, len); I did get a compiler error here: pH = (**strArr)->elm + i; I assume it should be (*strArr) -> elm + i; but I'm not certain. I did change it to this however to get it to compile I have confirmed my variable 'len' = 4 for my serial_number 'abcd' Other than that, I'm not sure what the problem may be. Do we need to include the \0 in the len? I believe doing (UHandle*)(&pH) gets us closer?
  23. A string array is simply an array handle of string handles! Sounds clear doesn't it? 😄 In reality we didn't just arbitrarily create this data structure but LKSH simply defined it knowing how a LabVIEW array of string handles is defined. You can actually get this definition from LabVIEW by creating the Call Library Node with the Parameter configured to Adapt to Type, Pass Array Handle Pointer, then right click on the Call Library Node and select "Create .c file". LabVIEW then creates a C file with all datatype definitions and an empty function body.
  24. That should work. That is how the Assert Type VIs work.
  25. If you have suggestions for how to report those errors, I'm all ears. I've been in hours of design meetings trying to come up with some algorithm for reversing type prop to figure out which inputs contributed to a given break *and* figuring out how to get the errors invalidated when the VIM gets edited. The current "break them all" is the best we've got at this time. There are some simple cases where the VIM's FP term connects directly to a particular node and the node refuses that input, but the further downstream, the harder it gets. And the most syntactically correct solution is "any wire that connects to the node is at fault", but that is essentially equivalent to the current solution as soon as you put one Type Specialization structure or error Case structure down (those tend to encompass the whole diagram, so all the FP terms wire into them). Opening the instance VI and looking at the diagram to see what broke is the best I've got. I would like to make the diagram visible without having to convert the instance to a real VI, but if there's a better option, please let me (and the rest of R&D) know.
  26. Looking at the API, I believe this is the case. @Rolf Kalbermatter would you mind explaining what is happening with the first NumericArrayResize? The one for the string buffer is pretty self explanatory, but I don't quite understand how the first one that resizes the LStrArrayHandle works. How does the function know how to resize memory for a data structure that we have defined ourselves?
  1. Load more activity
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.