Search talk: string cmp

 
<< < 1 .. 10 11 12 (Page 12 of 12)

Post by anonymous on Hi, I try to send and receive data using a UDP connection via SysSocket 3.5.17.0. While sending data works fine, I have problems with the receiving part. I am able to capture the received data of client side in wireshark But unable to capture it on the codesys CODESYS Forge talk (Post)
Hi, I try to send and receive data using a UDP connection via SysSocket 3.5.17.0. While sending data works fine, I have problems with the receiving part.I am able to capture the data of client side in wireshark but i am unable to capture it in the codesys. Heres the below part of code of client side. PROGRAM POU_udpclient_program VAR istep : INT := 1;//step variable for state machine xStart: BOOL;// Flag to start the UDP protocol iecSocketId: syssocket_interfaces.RTS_IEC_HANDLE;//socket handle for receiving iecCreateResult: syssocket_interfaces.RTS_IEC_RESULT; ipAddr: syssocket.SOCKADDRESS;//Socket address structure for receiving sIpAddress : STRING := '192.168.0.2'; wPort: WORD:= 12346; iecConnectResult : syssocket_interfaces.RTS_IEC_RESULT;//connect paramters sDataRec : STRING[255];//Buffer for received data xiRecBytes : __XINT;//number of bytes received iecRecResult : syssocket_interfaces.RTS_IEC_RESULT;//receive data parameters iecCloseResult : syssocket_interfaces.RTS_IEC_RESULT; END_VAR syssocket.SysSockInetAddr(sIpAddress,ADR(ipAddr.sin_addr)); ipAddr.sin_family := syssocket.SOCKET_AF_INET; ipAddr.sin_port := syssocket.SysSockHtons(wPort); CASE istep OF 1: //create socket IF xStart THEN iecSocketId:= syssocket.SysSockCreate(syssocket.SOCKET_AF_INET,syssocket.SOCKET_DGRAM,syssocket.SOCKET_IPPROTO_IP,ADR(iecCreateResult)); IF iecSocketId = syssocket_interfaces.RTS_INVALID_HANDLE THEN xStart := FALSE; istep := 1; ELSE istep := 2; END_IF END_IF 2: //connect to socket server using setoption iecConnectResult := syssocket.SysSockSetOption(iecSocketId,syssocket.SOCKET_SOL,syssocket.SOCKET_SO_REUSEADDR,ADR(ipAddr),SIZEOF(ipAddr)); istep := 3; 3: //receive data xiRecBytes := syssocket.SysSockRecvFrom(iecSocketId,ADR(sDataRec),SIZEOF(sDataRec),0,ADR(ipAddr),SIZEOF(ipAddr),ADR(iecRecResult)); istep := 4; 4: //close socket iecCloseResult:= syssocket.SysSockClose(iecSocketId); xStart := FALSE; istep := 1; END_CASE
Last updated: 2024-06-03

Post by jeffg on ERROR: GetNetLinkSockAndInfoByMac(): could not open netlink socket: Too many open files CODESYS Forge talk (Post)
I just installed codesys runtime on a raspberry pi Cortex-A72 (ARM v8) 64-bit SoC @ 1.5GHz (Compute Module 4) I am running on Codesys control for raspberry pi 64 SL ver 4.13.0 and I keep getting a crash after about five to ten minutes. This program was running fine on a 32bit system with runtime 4.8 previously but they upgraded the panel PC cause it got smashed. Looking at the logs I see this error "ERROR: GetNetLinkSockAndInfoByMac(): could not open netlink socket: Too many open files" at the time of crash. I do have a UDP socket open for a serial to ethernet adapter and im wondering if maybe its opening a bunch of sockets and while receiving messages, Im not sending anything to the device only receiving. Below is the code used for the UDP VAR // Scale Comm fbPeerServer : NBS.UDP_Peer; ipAddress : NBS.IPv4Address; fbReceive : NBS.UDP_Receive; xPeerActiv : BOOL := TRUE; abyReceive : ARRAY [0..255] OF BYTE; sLastValidReceive : STRING(255); udiIndex : UDINT; END_VAR IF xPeerActiv AND NOT fbPeerServer.xBusy THEN ipAddress.SetInitialValue(ipAddress := gvlSettings.sIPAddres); fbPeerServer(xEnable := TRUE, itfIPAddress := ipAddress, uiPort := gvlSettings.uiPort); END_IF fbPeerServer(); fbReceive(xEnable := fbPeerServer.xBusy, itfPeer := fbPeerServer, pData := ADR(abyReceive), udiSize := SIZEOF(abyReceive)); IF fbReceive.udiCount > 0 THEN IF fbReceive.udiCount < SIZEOF(sLastValidReceive) THEN SysMem.SysMemCpy(pDest := ADR(sLastValidReceive), pSrc := ADR(abyReceive), udiCount := fbReceive.udiCount); // Set End of String sLastValidReceive[fbReceive.udiCount] := 0; END_IF END_IF If anyone as seen this I could really use some help figuring it out. I included the Log report
Last updated: 2024-09-19

Post by timvh on Detect "Cancel" Press in FileOpenSave Dialog CODESYS Forge talk (Post)
Maybe there is a better way, but a long time ago I created a test application that worked like this: With a button I opened the dialog and I added a "Input configuration - OnDialogClosed" "Execute ST-Code" action to this same button which called the following Function when the dialog was closed: F_OnFileDialogClosed(pClientData); Below this Function which handled the result: // This function is called from the visualization when the dialog is closed. FUNCTION F_OnFileDialogClosed : BOOL VAR_INPUT pClientData : POINTER TO VisuElems.VisuStructClientData; END_VAR VAR dialogMan : VisuElems.IDialogManager; FileOpenCloseDialog : VisuElems.IVisualisationDialog; result : VisuElems.Visu_DialogResult; _sFileName : STRING(255); END_VAR // the DialogManager is provided via the implicitly available VisuManager dialogMan := VisuElems.g_VisuManager.GetDialogManager(); IF dialogMan <> 0 AND pClientData <> 0 THEN FileOpenCloseDialog := dialogMan.GetDialog('VisuDialogs.FileOpenSave'); // gets the FileOpenSave dialog IF FileOpenCloseDialog <> 0 THEN result := FileOpenCloseDialog.GetResult(); // gets the result (OK, Cancel) of the dialog IF result = VisuElems.Visu_DialogResult.OK THEN // Original code gvlFile.FileListProvider(); _sFileName := CONCAT(gvlFile.FileListProvider._stDirectory, gvlFile.FileListProvider.stFile); // do something with this file name... END_IF END_IF END_IF
Last updated: 2023-09-19

Post by francescoc on Custom log CmpLog CODESYS Forge talk (Post)
Hi, I am trying to create a log in my application. Since I cannot find any documentation regarding modifying the codesys configuration file to be able to log in ms, i tried to create a new log via CmpLog.LogCreate. Below is the part of the code where I create the logger and write a test string. In the log tab of codesys I actually see the new log that was created, but it is empty, and in the folder I cannot find any files. I can't find any detailed documentation. Can you guys give me support? Are there any examples? Thank you IF NOT FirstCycle THEN LogName:= 'LOGS/TestLog'; LogOptions.bEnable:= 1; LogOptions.iMaxEntries:= 5000; LogOptions.iMaxFiles:= 100; LogOptions.iMaxFileSize:= 5000; LogOptions.szName:= LogName; LogOptions.uiType:= CmpLog.LogTypes.LT_TIMESTAMP_RTC_HIGHRES; LogOptions.uiFilter:= CmpLog.LogClass.LOG_ALL; LogHandle:= CmpLog.LogCreate(pOptions := ADR(LogOptions), pResult:= ADR(Result)); LogHandle:= CmpLog.LogOpen(pszName:= LogName, pResult:= Result); Component_Manager.CMAddComponent2('TestLogNEW', 16#00000001, ADR(udiCmpIdNEW), 0); CmpLog.LogAdd2(LogHandle, udiCmpIdNEW, CmpLog.LogClass.LOG_INFO, 1, 1, 'Logger started...'); END_IF IF TestWrite THEN TestWrite:= FALSE; CmpLog.LogAdd2(LogHandle, udiCmpIdNEW, CmpLog.LogClass.LOG_INFO, 1, 1, 'Write test'); END_IF
Last updated: 2024-03-16

Post by joshskellig on Publish a JSON payload via MQTT Publish (using IIot Libraries) CODESYS Forge talk (Post)
I am trying to figure out how to get a JSON payload to properly publish to my MQTT Broker. I am able to generate JSON using the examples from Codesys, but when I send that payload via MQTT there are characters that are extra or not recognized by my MQTT client. Any idea what could be causing it? PROGRAM PLC_PRG VAR hostname: STRING := 'localhost'; port: UINT := 1883; topic: WSTRING(1024) := "testing/"; payload: BYTE; factory : JSON.JSONDataFactory; eDataFactoryError : FBF.ERROR; pJsonData : POINTER TO JSON.JSONData := factory.Create(eError => eDataFactoryError); fb_JBuilder : JSON.JSONBuilder; wsValue : WSTRING := "Value1"; diRootIndex, diObject1Index : DINT; iValue : INT := 1234; jsonArrayWriter : JSON.JSONByteArrayWriter; wsJsonData : WSTRING(1000); xFirst : BOOL := TRUE; mqttClient: MQTT.MQTTClient; mqttPublish: MQTT.MQTTPublish; mqttPublishProperties: MQTT.MQTTPublishProperties := (bPayloadFormatIndicator := 1, wsContentType := "application/json"); END_VAR // Json Functionality IF xFirst THEN fb_JBuilder(pJsonData := pJsonData, diRootObj => diRootIndex); fb_JBuilder.SetKeyWithValue("Key1", wsValue, diParentIndex := diRootIndex); diObject1Index := fb_JBuilder.SetKeyWithObject("Key2", diParentIndex := diRootIndex); fb_JBuilder.SetKeyWithValue("Key3", iValue, diParentIndex := diObject1Index); xFirst := FALSE; END_IF jsonArrayWriter(pwData := ADR(wsJsonData), udiSize := SIZEOF(wsJsonData), jsonData := pJsonData^, xAsyncMode := FALSE); MSU.StrTrimW(pString:= ADR(wsJsonData)); // MQTT Functionality mqttClient( sHostname:=hostname, uiPort:=port, eMQTTVersion:=MQTT.MQTT_VERSION.V5 ); mqttPublish( mqttClient:=mqttClient, pbPayload:=ADR(wsJsonData), udiPayloadSize:=SIZEOF(wsJsonData), wsTopicName:=topic, mQTTPublishProperties:=mqttPublishProperties );
Last updated: 2024-04-10

Post by paulg on RasPi CAA Serial example - unexpected behavior during debug CODESYS Forge talk (Post)
I've trimmed down the CAA Serial Codesys example to only listen on one port but, when stepping through the Case structure in debug mode, it jumps out of the structure during a specific point in every scan (I'll point it out below after describing the setup and listing the code). I'm using a Pi 4 Model B, and I have an Arduino Nano Every plugged in via USB which is streaming the following serial message at 1 Hz: Time since opening connection: 1 s Time since opening connection: 2 s ...and so on. The Pi shows the Nano at /dev/ttyACM0 so I edited CODESYSControl_User.cfg to read: Linux.Devicefile=/dev/ttyACM The code in my PLC_PRG is (ignore some of the comments, I hadn't deleted them out from the original example): PROGRAM PLC_PRG VAR xStartTest : BOOL:= TRUE; iState : INT; xTestDone : BOOL;(* True, when the test was done succesfully *) (* Settings to communicate with the COM Port *) aCom1Params : ARRAY [1..7] OF COM.PARAMETER; como1 : COM.Open; comc1 : COM.Close; comw1 : COM.Write; comr1 : COM.Read; //sWrite : STRING := 'Test String!'; sRead : STRING(25); szRead : CAA.SIZE; xCom1OpenError : BOOL; xCom1CloseError : BOOL; xCom1WriteError : BOOL; xCom1ReadError : BOOL; END_VAR //This example shows the communication of two COM Ports with each other. //The first one writes a string of characters, which is read by the second one. //After successful execution, the two COM Ports are closed and the test is done. IF xStartTest THEN CASE iState OF 0: //The parameters are set for the COM Port aCom1Params[1].udiParameterId := COM.CAA_Parameter_Constants.udiPort; aCom1Params[1].udiValue := 1; // the correct Port should be adapted aCom1Params[2].udiParameterId := COM.CAA_Parameter_Constants.udiBaudrate; aCom1Params[2].udiValue := 115200; aCom1Params[3].udiParameterId := COM.CAA_Parameter_Constants.udiParity; aCom1Params[3].udiValue := INT_TO_UDINT(COM.PARITY.NONE); aCom1Params[4].udiParameterId := COM.CAA_Parameter_Constants.udiStopBits; aCom1Params[4].udiValue := INT_TO_UDINT(COM.STOPBIT.ONESTOPBIT); aCom1Params[5].udiParameterId := COM.CAA_Parameter_Constants.udiTimeout; aCom1Params[5].udiValue := 0; aCom1Params[6].udiParameterId := COM.CAA_Parameter_Constants.udiByteSize; aCom1Params[6].udiValue := 8; aCom1Params[7].udiParameterId := COM.CAA_Parameter_Constants.udiBinary; aCom1Params[7].udiValue := 0; //The first Port is opened with the given parameters como1(xExecute := TRUE, usiListLength:=SIZEOF(aCom1Params)/SIZEOF(COM.PARAMETER),pParameterList:= ADR(aCom1Params)); IF como1.xError THEN xCom1OpenError := TRUE; iState := 1000; END_IF //After a successful opening, the next state is reached IF como1.xDone THEN iState := 15; END_IF 15: // the reading process is started comr1(xExecute := TRUE,hCom:= como1.hCom, pBuffer:= ADR(sRead), szBuffer:= SIZEOF(sRead)); IF comr1.xError THEN xCom1ReadError := TRUE; END_IF //After completion the size of the written bytes are saved IF comr1.xDone OR comr1.xError THEN szRead := comr1.szSize; iState := 20; END_IF 20: // If everything was successful the ports are closed and the handles are released comc1(xExecute := TRUE,hCom:= como1.hCom); IF comc1.xError THEN xCom1CloseError := TRUE; END_IF IF comc1.xDone OR comc1.xError THEN iState := 25; END_IF 25: // The first port is closed and the used handle released xTestDone := TRUE; xStartTest := FALSE; iState := 0; como1(xExecute := FALSE); comw1(xExecute := FALSE); comc1(xExecute := FALSE); ELSE iState := 0; END_CASE END_IF I realize as I write this that the .udiPort should be 0 and not 1, but that shouldn't be causing the issue I'm seeing. I'm forcing xStartTest:=TRUE every scan so that I can step into each line and observe what's happening. What I see is that the port parameters are set and the port is opened with no errors, but the code jumps out of the case structure to the last line every time it reaches (and I step into) the iState:=15 line (at the end of the iState:=0 block). So every scan cycle it goes through the block for iState=0 and jumps out at the same spot. I'm a little new to PLC programming so I may be misunderstanding the flow, but shouldn't this case structure keep moving down in the same scan? If it only handles one case per scan, why doesn't the value of iState persist? Thanks! Update: I restarted the Codesys control today and I was then able to see an error for como1.eError of "WRONG_PARAMETER". I tried doing some digging and another post made me think I should add another line to CODESYSControl_User.cfg, so I now have: [SysCom] Linux.Devicefile=/dev/ttyACM portnum := COM.SysCom.SYS_COMPORT1 So now when I set .udiPort to 1, I get "NO_ERROR" but I also don't read anything from the port (i.e. szRead = 0 always). If I try setting the port to 0 (which I'm confused about, because I added a COMPORT1 line but the device shows on the Pi as ACM0), I get the "WRONG_PARAMETER" error again. Is there an easier way to troubleshoot the Pi and view what ports the Codesys runtime is actually able to see while the Pi is running?
Last updated: 2024-06-06

Post by caprez95 on Deleting the trend recording history CODESYS Forge talk (Post)
Hallo Ich möchte eine laufende Trendaufzeichnung stoppen, den Inhalt löschen und Trend-Diagramm auf 0 zurücksetzen. Laut Codesys soll das mit dem folgenden Code möglich sein: You can insert an input element in the visualization which the operator can use to delete the previous value recording in the trend visualization at runtime. The curve displayed until then is removed and the display starts over. In the application (example: in the program PLC_PRG), implement the following code: itfTrendRecording : ITrendRecording; itfTrendStorageWriter : ITrendStorageWriter; itfTrendStorageWriter3 : ITrendStorageWriter3; sTrendRecordingName : STRING := 'TrendRecording'; itfTrendRecording := GlobalInstances.g_TrendRecordingManager.FindTrendRecording(ADR(sTrendRecordingName)); xClearHistoryTrend: BOOL; IF xClearHistoryTrend THEN itfTrendRecording := GlobalInstances.g_TrendRecordingManager.FindTrendRecording(ADR(sTrendRecordingName)); IF itfTrendRecording <> 0 THEN itfTrendStorageWriter := itfTrendRecording.GetTrendStorageWriter(); IF __QUERYINTERFACE(itfTrendStorageWriter, itfTrendStorageWriter3) THEN itfTrendStorageWriter3.ClearHistory(); END_IF END_IF In the visualization of the trend recording, add a button for deleting the previous curve. Configure its Toggle property with the variable PLC_PRG.xClearHistoryTrend. ⇒ When xClearHistoryTrend is set to TRUE, the previously recorded curve is deleted. The recording immediately starts again. Dies löscht auch die Daten vom Trend, aber das Diagramm wird nicht auf 0 zurückgesetzt, sondern läuft einfach da weiter wo man gestoppt hat. Braucht es für den Diagramm-Reset noch einen zusätzlichen Befehl? Gruss
Last updated: 2024-06-11

Post by psychoengineer on Cannot Save CSV File on Windows Computer Using CODESYS and Control Win CODESYS Forge talk (Post)
I am currently working on a project using CODESYS and Control Win on a Windows computer. I've encountered an issue where I am unable to save a CSV file. I have followed the standard procedures and used the appropriate file handling functions, but the file is not being created or saved as expected. IF xStartTest THEN sFileName := '\logs.txt'; sFileName := CONCAT(gvl.g_sMainDirectory, sFileName); sFileNameCopy := '\CAAFileCopy.txt'; sFileNameCopy := CONCAT(gvl.g_sMainDirectory, sFileNameCopy); //eWriteState := FILE_OPEN_TRIGGER; xTestDone := FALSE; xError := FALSE; xStartTest := FALSE; END_IF VAR_GLOBAL g_sMainDirectory : STRING := 'C:\LogFiles'; // file path for CSV file END_VAR Despite this, the file does not appear in the specified directory, and no error messages are being generated. I've checked the directory permissions and ensured that the path is correct. Has anyone else experienced a similar issue or have any suggestions on how to resolve this? Any help would be greatly appreciated. Thank you!
Last updated: 2024-07-04

Post by fless on Von SNMP auf IIoT wechseln CODESYS Forge talk (Post)
Wie gesagt ich hatte noch keinen Kontakt mit SNMP. Um die Beispiele zu verstehen hier ein paar Tips: SetEngineId und CreateSNMPV3User sind Funktionsbausteine. Klicke rechts auf den Namen, Symbol suchen - Gehe zu Definition Dann sieht du entweder den Quelltext oder landest in der Bibliothek und kannst dir die Dokumentation ansehen. In deinen Fall siehst du den Quelltext. Die Funktionsbausteine sind in den Projekt POUs gespeichert weil das Projekt aus mehreren Applikationen besteht die alle diese FBs nutzen. sOID (drei Balken)oid → was wird da gemacht? In die Stringvariable sOID (String old ID?) wird der Inhalt von oid geschrieben. oid ist Member der Strukturvariable snmpVarBindings. Dem SNMP_SET Aufruf wird snmpVarBindings übergeben und geändert. Und da müsste doch irgendwo eine Verschlüsselung eingetragen werden oder? Beim Anlegen der SMNP-User wird ein Passwort vergeben, siehe CreateSNMPV3User. Dem SNMP_SET Aufruf wird nur der User übergeben, hier "readwrite". Die Bibliothek sucht sich die Einstellung des Users selbst.
Last updated: 2024-09-01

Post by dandyk on Dynamic Images CODESYS Forge talk (Post)
Hello, I have very similar problem, but it seems that your solution does not work for me. I am using TwinCAT XAE Shell v3.1.4024.55 and TwinCAT Runtime. Sorry for writing here on codesys forge, but since I found the only relevant topic here and since TwinCAT is almost the same with CODESYS in many applications, I chose to write here. I simply need to dynamically update image in visualization based on camera trigger (I am doing a machine vision application). Camera triggers an image, my program processes it (applies thresholding, draws contours etc...) and saves the processed image in the runtime location (the same one you were mentioning). This was done successfully. I need to make it work at runtime, while the program is executing and I need to refresh the image in the visualization each time camera triggers a new image and program processes it. When I create image element in the visualization and define the bitmap ID variable as STRING which contains the image ID defined in the image pool, then it displays the image in the image pool, but does not work at runtime, while the program is executing. I also used the Bitmap Version. I declared it in Global variable list as integer with initial value of 0 and wrote the variable in the bitmap version in the image element in visualization. Each time new image is saved to the runtime location, I wrote a program to increment Bitmap Version by 1. It increments and the image does not update in the visualization, unfortunately. I think that bitmap version is working correctly and deletes the cached image as it is supposed to, but the Image Pool does not update the image ID with the new image... the path to the image is always the same... only the actual image changes with the same file name. Image Pool is not dynamic and cannot refresh the image in the path to the actual one at runtime. How can I refresh the image ID in the image pool at runtime? Bitmap version only deletes cached image and reloads the image from the image ID, but the image ID has the same image, because image pool won't update at runtime. Do you know any solution to this problem?
Last updated: 2024-04-06

Post by ppix on Establishing TLS Connection with MQTT Broker using MQTT Client SL Package CODESYS Forge talk (Post)
I’m currently working on establishing a TLS connection with an MQTT broker using the MQTT Client SL package in CODESYS. While I’ve successfully established communication with the broker without TLS, I'm encountering issues when trying to enable TLS. In the 'MQTT Explorer' application, I can easily upload the server certificate (.crt), client certificate (.crt), and client key (.key). However, in CODESYS, I can’t find a way to upload my client key (.key file). Here's a summary of my current setup: Certificates: I have uploaded both the client and server certificates to the certificate store under the 'Trusted Certificates' folder in the security screen. TLS Context Initialization: Despite setting the _sCommonName as the name of my client certificate, a new self-signed certificate is created and placed within the device’s certificates. I then need to manually move this certificate to the trusted certificates folder. This results in three certificates in my trusted certs folder: client cert, server cert, and the newly created cert. _ciDefaultCertInfo : MQTT.NBS.CERT_INFO := (psInfo := ADR(_sCommonName), udiSize := TO_UDINT(LEN(_sCommonName))); // CN of the certificate (common name) _sCipherList : MQTT.NBS.CIPHER_LIST := STRUCT(psList := ADR('HIGH'), udiSize := 4); // Cipher string see https://www.openssl.org/docs/man1.1.1/man1/ciphers.html _tlsContext : MQTT.NBS.TLSContext := ( sUseCaseName := _sCommonName, // A certificate is stored in the certificate store with the use case name. You can choose any name. Here we use the common name. ePurpose := MQTT.NBS.PURPOSE.CLIENT_SIDE, // For client certificates set this to NBS.PURPOSE.CLIENT_SIDE sTLSVersion := '1.3', // The TLS version sCipherList := _sCipherList, // Set the cipher list sHostname := sHostname, // The hostname of the broker udiVerificationMode := 2, // 2 => Active Peer verification ciCertInfo := _ciDefaultCertInfo, // Set the cert info itfCertVerifer := 0); // 0 => No Verifier mqttClient : MQTT.MQTTClient := (xUseTLS:=TRUE, itfTLSContext := _tlsContext, itfAsyncProperty := _asyncProperty); Additional Details: In the client FB, I’ve set uiPort:= 8883, xUseTLS:= TRUE, and configured itfTLSContext as mentioned above. The certificates are encrypted with SHA256RSA. sHostname is the IP address of my broker. I’ve attached a copy of the client FB, which shows straight lines where variables are assigned and boxes where they are not. I am currently trying this on the only 2 compatible versions of COSDESYS with my controller (V3.5.15.20 and V3.5.18.40) My Question: How do I correctly set up this mTLS connection? What might I be missing? Any guidance or suggestions would be greatly appreciated, especially considering I’ve already successfully established a non-TLS connection with the same broker. Thank you in advance for your help!
Last updated: 2024-06-19

Post by ihatemaryfisher on Sorting array of any-sized structure CODESYS Forge talk (Post)
In my machine's operation, I need to display multiples tables containing arrays of structured variables. The arrays change during operation, and my supervisor has advised me to write a new bubble-sort for each array. I think I can make a function to sort an array of any data type. This was my own project, and I'm a relatively new coder. I want to know the weaknesses in my approach, and a better method, if one exists. As far as I can test, the function accepts an array of a structured variable of any size, and sort it by any VAR in that structure. But it relies heavily on pointers, which I've heard are bad practice? Function call: // SORT BY BYTE-SIZED VAR IF xDoIt[6] THEN FUNBubbleSortSansBuffer( IN_pbySourcePointer := ADR(astArray[1]), // address of first byte in first element of array IN_pbyComparePointer:= ADR(astArray[1].byCompByte), // points to first byte of the comparing variable (variable you sort by) IN_uiStructureSize := SIZEOF(TYPE_STRUCTURE), // size, in bytes, of the structured variable IN_uiCompareSize := SIZEOF(astArray[1].byCompByte), // size, in bytes, of the comparing variable (variable you sort by) diArrayElements := UPPER_BOUND(astArray,1), // number of elements in array IN_xSmallToLarge := xSortOrder // whether to sort by small2large or large2small ); END_IF Function: FUNCTION FUNBubbleSortSansBuffer : BOOL VAR_INPUT IN_pbySourcePointer : POINTER TO BYTE; // points to beginning of array (first byte of first element) IN_pbyComparePointer: POINTER TO BYTE; // points to first byte of the comparing variable (variable you sort by) IN_uiStructureSize : UINT; // size, in bytes, of the structured variable IN_uiCompareSize : UINT; // size, in bytes, of the comparing variable (variable you sort by) diArrayElements : DINT; // number of elements in array IN_xSmallToLarge : BOOL; // whether to sort by small2large or large2small END_VAR VAR j : DINT; // repeat iteration over array until array ends i : DINT; // iterarte over array, swapping when necesary k : DINT; // iterator from 1 to size of structure (stepping 'through' a single element in array) dwSize : DWORD; // internal var for use in MEMUtils.MemCpy(<size>) // FOR SORTING BY BYTE VAR pbySourcePointer : POINTER TO BYTE; pbySourcePointer2 : POINTER TO BYTE; pbyComparePointer : POINTER TO BYTE; pbyComparePointer2 : POINTER TO BYTE; pbyPointerToBuffer : POINTER TO BYTE; // pointer to single byte buffer byBufferByte : BYTE; // single byte buffer END_VAR dwSize := UINT_TO_DWORD(IN_uiStructureSize); // get structure size (number of bytes) pbyPointerToBuffer := ADR(byBufferByte); // assign pointer to address of buffer byte (because MEMUtils.MemCpy requires a pointer input) CASE IN_uiCompareSize OF // depending on the size of the VAR to sort by (current functionality for BYTE and WORD/INT 1: // BYTE (8 BIT) FOR j := 1 TO diArrayElements DO // for number of elements in array FOR i := 1 TO (diArrayElements-1) DO // same thing, but row[i+1] row is included in swap logic pbySourcePointer := IN_pbySourcePointer + dwSize*(i-1); // point at #1 byte in array element[i] pbySourcePointer2 := pbySourcePointer + dwSize; // point at #1 byte in array element[i+1] // NOTE: because of memory locations, each array element is offset from one another by a number of bytes equal to the size of the structure // We can "walk" from array[i] to array[i+1] via steps equal to the size of the structure // e.g., ADR(array[i+1]) == ADR(array[i]) + SIZEOF([array datatype]) pbyComparePointer := IN_pbyComparePointer + dwSize*(i-1); // point to sorting variable in array element[i] pbyComparePointer2 := pbyComparePointer + dwSize; // point to sorting variable in array element[i+1] // using sort order (small -> large/large -> small) IF SEL(IN_xSmallToLarge, (pbyComparePointer2^ > pbyComparePointer^),(pbyComparePointer2^ < pbyComparePointer^)) THEN // This is where it gets tricky. We've identified pointers for the starting bytes of aArray[i] and aArray[i+1] // and we know the size of aArray[i]. We are going to swap individual bytes, one at a time, from aArray[i] and aArray[i+1] // this allows us to use only a single byte var as a buffer or temporary data storage // e.g., consider a structure consisting of a word, a byte, and a string. it is stored like this // |------WORD-------| |--BYTE-| |STRING------...| // astArray[1] == 1000 0100 0010 0001 1100 0011 1010 1010.... etc // astArray[2] == 0001 0010 0100 1000 0011 1100 0101 0101.... etc // performing a single swap (copy into a buffer, etc.) of the first byte of each array element creates this // astArray[1] == 0001 0100 0010 0001 1100 0011 1010 1010.... etc // astArray[2] == 1000 0010 0100 1000 0011 1100 0101 0101.... etc // incrementing the pointer adresses for the swap by 1 and swapping again swaps the next byte in each array element // astArray[1] == 0001 0010 0010 0001 1100 0011 1010 1010.... etc // astArray[2] == 1000 0100 0100 1000 0011 1100 0101 0101.... etc // continuing this from k to SIZEOF(TYPE_STRUCTURE) results in a toally swapped row FOR k := 1 TO IN_uiStructureSize DO // copy single byte[k] of array element 1 to buffer MEMUtils.MemCpy(pbyDest := (pbyPointerToBuffer), pbySrc := (pbySourcePointer+k-1), dwSize := 1); // copy single byte[k] of array element 2 to 1 MEMUtils.MemCpy(pbyDest := pbySourcePointer+k-1, pbySrc := (pbySourcePointer2+k-1), dwSize := 1); // copy buffer to byte[k] array element 2 MEMUtils.MemCpy(pbyDest := (pbySourcePointer2+k-1), pbySrc := pbyPointerToBuffer, dwSize := 1); END_FOR END_IF END_FOR END_FOR
Last updated: 2023-08-17

<< < 1 .. 10 11 12 (Page 12 of 12)

Showing results of 287

Sort by relevance or date