Jump to content

All Activity

This stream auto-updates     

  1. Past hour
  2. I think we've articulated the goal well enough. However, a VIM doesn't necessarily have a reference like Queues et. al. so I'm not sure there would be an "uncomplicated" first order solution for it even though it's a kind of natural progression from singular VIMs to libraries of VIMs. In theory, the second order solution is to use those primitives internally since they have that behaviour which should propegate out but I was unable to see if that worked with DVRs and trying queues didn't illicit the behaviour.
  3. Hi Mike, Do you happen to have an example that updates more quickly? I read that you can bind the data last, but I tried this and I still see some performance issues when loading large amounts of data ~10,000 rows. Even when the data is loaded, scrolling seems to be laggy. Also by any change is there a way to have an embedded progress bar (with multiple colors) as a column type? Regards, Mike C
  4. Yes, that is the problem. If I connect a "Buffer" of a certain data type, the "Data" input should adapt to be that datatype. That's how Queues work, but there isn't a way I can identify to make VIMs work that way. Outputs adapt to inputs, but not unconnected inputs.
  5. Seems VIMs can no longer be used in polymorphic VIs either. I don't think this is a good idea. The VIMs I've played around with (before the type case structure was introduced) relied on at least one terminal having a type which would dictate the undefined types due to the nature of the internal polymorphic VIs (like a Queue or DVR). This is why I was trying to get a VIM to create a DVR which "should" define the type across all connected VIs which would solve this problem. In a nutshell, I'm expecting this set of VIMs (rightly or wrongly) to behave like the Queue, Notifier et. al. primitives when the Enqueue and Dequeue element terminal is unwired.
  6. Today
  7. Maybe we need a "placeholder" type, or "Your Type Here". Actually, NI seems to be using an "anything" cluster of zero elements in primitives like "Flatten To String" and "Flatten to JSON". This has never struck me as being flawed.
  8. So when I was playing around with this I would map my build folder, to the www folder of my webserver, with a symbolic link. This way I would build and it would already be in my web server folder ready to be used. Here is a very loose set of steps I did to map a folder from a build to a place that the webserver uses. I don't know of what NI uses on the hosting side and I've always just used XAMP which is Apache. Windows has a built in server too that works well enough for basic stuff.
  9. We have an undefined type. Create an output tunnel from Your Favorite Structure node and don't wire the inside. You'll get a void wire, which is distinct from a broken wire. Void is also the type of a wire output from a subVI call node when you delete the terminal from the subVI's connector pane. Void wires don't have a control/indicator, and most poly nodes won't adapt to void (deliberately), so the VIM instances cannot adapt to void type. Void is probably not what you're looking for. Something like empty cluster is what you're looking for, but VIMs deliberately cannot have that type in their conpane, and it contradicts a key principle of VIMs: the conpane shows the user the intended usage, and by having one required working base case, we avoid many of the ambiguous interpretation issues of C++ templates. The code has to be semantically valid for at least one set of types. Having a terminal whose type is "undefined" doesn't tell the user the kind of data that they should be wiring to that terminal. I see your problem. I don't see a solution at the moment. An undefined type seems fundamentally flawed to me.
  10. BTW, does anyone know of any other "malleable cluster" libraries or work using VIMs?
  11. 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've now getting the buffer wire to be unbroken when the Data input is unwired, by making the default Data an "undefined type" (a class call "Undefined Type"). I added a case that is unbroken when Data is this "undefined" type, which it is when the User has not wired that input. The error message the User gets in this case is just the one for a required input not being wired, which is much less confusing than a broken "Buffer" wire and an additional error message about type mismatch. AQ, what do you think about an actual "undefined type type in LabVIEW and/or NXG? One thing that could be useful for NXG is a undefined type in a cluster constant, which defines teh name of the item without the type, and allows the type to adapt to that supplied by the first Bundle-by-Name. This would avoid some of my concerns about clusters in NXG.
  12. Amazing! Thank you all so much for uploading those lectures and a special thank you to those how presented them. I wish we had a strong technical CLA here but we don't have such a large community as you do.
  13. I've definitely used it, although we ended up going with a different db so the code never got used for real. I think I had tried it on lvrt but I can't really remember. I tend to think that talking to a central db from an rt target tends to break the nicely distributed nature of the systems and so I'm more likely to use your sqlite on rt, but I get that for test systems and the like (now that PXI RT Linux is a thing) might be more likely to talk directly to a postgres database.
  14. Yesterday
  15. 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.)
  16. 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?
  17. 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.
  18. I have no idea why that limitation exists. I’ll ask on Monday.
  19. 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 by name" 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. 🙂
  20. Last week
  21. 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...
  22. 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).
  23. 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.
  24. 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.
  25. 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; }
  26. 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; }
  1. Load more activity
×
×
  • Create New...

Important Information

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