Post by gilbert-mh on CAA net base TCP client cause PLC to crash - Kernel message : N0HZ_local_softirq_pending 80
CODESYS Forge
talk
(Post)
Hello all, I have been trying to implement a TCP client on a Festo PLC (CPX-E-CEC-M1) and it looks like it works well except that after some time (greatly varies between a few hours to more than 100h) my PLC crash. When I look into the log file the only thing I see is that before the crash happens a few kernel warnings : N0HZ_local_softirq_pending 80 and then the crash. I've looked into this warning and from what I could find on the net it seems that this is warning is triggered when the ethernet link is down. I've tried to correct this bug for quite some time and what I know is that : - The crash is caused by my TCP client, when I remove it from my code I see no crash - The crash happens more quickly the more the TCP client is used. - The time before the crash is not directly proportional to the number of communications or their size. But it looks like it is just more likely to happen if the client connect to the server at a higher frequency. - The precedent observation makes it seem unlikely that the crash is caused by some memory overflow because then the crash speed would be more proportional to the amount of data exchanged. SO from these observations, I believe that the crash could be caused by the PLC trying to connect to a server while there is some kind of issue with the ethernet link resulting in the PLC getting stuck in some indefinite state and making it crash. This still seems a bit unlikely to me because if the ethernet is down it simply shouldn't be able to contact the server and the communication would just fail which doesn't cause my PLC to crash. Has anyone encountered the same kind of problem (with the same kernel message) ? I am pretty sure the warning is not the direct cause of the crash but just an indicator that something is wrong with my PLC. Thanks in advance
Last updated: 2024-01-12
Post by risele on dynamic modbus devices
CODESYS Forge
talk
(Post)
Have the same issue: I'm making a test setup for modbus devices testing and calibration. One is run for every possible address, and it starts with minimal request: if the device is found, it continue to work with it, otherwise it's set to Disabled temporary. Those state machines are running under FOR cycle, and disabled are just skipped. Every instance have its own timer for not running too frequently and a start delay, so the actual requests are separate in time. I also check not for a single error, but have some timer to allow one-two timeouts. The small program disables and re-enables devices temporary (manually, since i could not iterate over MB devices). VAR Reset:ARRAY[1..GVL_MB.MD_COUNT] OF R_TRIG; i:INT; END_VAR {IF hasconstantvalue(GVL_MB.MD_COUNT, 1, >= )} i:=1; MD_1.Enable:=GVL_MB.MDPortsEnable[i]; Reset[i](CLK:=GVL_MB.MDPortsEnable[i]); MD_1.xReset:=Reset[i].Q; {END_IF} {IF hasconstantvalue(GVL_MB.MD_COUNT, 2, >= )} i:=2; MD_2.Enable:=GVL_MB.MDPortsEnable[i]; Reset[i](CLK:=GVL_MB.MDPortsEnable[i]); MD_2.xReset:=Reset[i].Q; {END_IF} There is also program to re-enable devices periodically. METHOD ScanBus VAR_INPUT END_VAR VAR j:INT; (*block auto scanning if calibration is running for any device since it's data-reach process that should not be interrupted with modbus timeouts *) CalibrationBusy:BOOL:=FALSE; END_VAR CalibrationBusy:=FALSE; FOR j:=1 TO GVL_MB.MD_COUNT DO CalibrationBusy:=CalibrationBusy OR MD_Calibrate.AutoTesters[j].xBusy; END_FOR; IF CalibrationBusy THEN RETURN; END_IF tBusScanSchedule(IN:=(NOT tBusScanSchedule.Q), PT:=tBusScanPeriod); IF (NOT tBusScanDelayer.Q) AND (tBusScanSchedule.Q OR (NOT xFirstScanPerforemed)) THEN xBusScanBusy:=TRUE; MissingCounter:=0; xFirstScanPerforemed:=TRUE; FOR j:=1 TO GVL_MB.MD_COUNT DO (* MD_Calibrate is main calibration program. Identifiers - is array of State machines mentioned above Phase_Faulted is a state of Identifiers where I'm sure device is missing on the bus *) IF MD_Calibrate.Identifiers[j].state=eStateMDIdentifier.Phase_Faulted THEN MD_Calibrate.Identifiers[j].Rescan(); MissingCounter:=MissingCounter+1; END_IF END_FOR END_IF tBusScanPauser(IN:=tBusScanDelayer.Q AND (MissingCounter>0),PT:=tBusScanDelay*MissingCounter); xBusScanBusy:=tBusScanPauser.Q; xFirstScanPerforemed:=xFirstScanPerforemed OR tBusScanPauser.ET>=tBusScanPauser.PT; Also the GUI have buttons for each address possible that re-enables the device if required.
Last updated: 2026-02-13
Post by alexschooneveld on OPC UA PubSub SL 1.3 β UADP WriterGroup with assigned PSS.SecurityGroup still publishes plaintext
CODESYS Forge
talk
(Post)
I am currently investigating an OPC UA PubSub connection over UDP. When I don't use encryption, the publish and subscribe are working correctly. But with encryption it does not. Environment OPC UA PubSub SL 1.3.0.0 (namespace UADP) OPC UA PubSub Security 1.3.0.0 (namespace PSS) OPC UA PubSub Base 1.3.0.0 (namespace PSB, incl. PSS.SecurityGroup / PSS.CONFIG) Programmatic PubSub in a CFC: UADP.Configuration β UADP.Connection β UADP.writerGroup β UADP.writer β writerDataSet, plus a CyclicCall gated by xEnable. Goal: publish secured UADP, SignAndEncrypt, policy PubSub-Aes256-CTR. What I do (one-shot, before xEnable := TRUE): fbSecurityGroup.SetInitialValue( 'http://opcfoundation.org/UA/SecurityPolicy#PubSub-Aes256-CTR', PSB.SECURITY.SIGNING_AND_ENCRYPTION); stSecurityCfg := fbSecurityGroup.GetConfig(eErrorID => eError); // eError=NO_ERROR, udiEncryptionKeySize=32 eError := fbSecurityGroup.SetSecurityKeys(udiTokenId, ADR(abyKey), SIZEOF(abyKey), 2436001000); // eError=NO_ERROR, SIZEOF=68 // writerGroup.itfSecurityGroup := fbSecurityGroup -- set in the WriterGroup block's Parameters (a per-scan code write got overwritten) What I verified eError = NO_ERROR after both GetConfig and SetSecurityKeys; udiEncryptionKeySize = 32. Key length = 68 bytes (signing 32 β encrypt 32 β nonce 4). itfSecurityGroup is set via the WriterGroup's Parameters (so it isn't clobbered each scan). Init runs before xEnable (the writer doesn't run with xEnable=FALSE). The UADP.writerGroup FB exposes only itfSecurityGroup for security β no SecurityMode/MessageSecurityMode property. Result: the published datagrams are still plaintext β ExtendedFlags1 = 0x01 (security bit 0x10 clear), no security header: b1 01 29 00 0f 16 00 β¦ (PublisherId 41, WriterGroupId 22, RawData, no security) Questions With UADP.writerGroup, is assigning a configured + keyed PSS.SecurityGroup to itfSecurityGroup sufficient to enable message security, or is there an additional step/property/method to switch the WriterGroup to SignAndEncrypt? At what point in the WriterGroup lifecycle is itfSecurityGroup read? Must it be assigned/keyed before xActive, and does the group need a stopβstart to pick it up? Is there a required call order, and does SetSecurityKeys need to be called once or repeatedly? Should security be configured on the Connection/Configuration level rather than (or in addition to) the WriterGroup? Is there a working example of secured (SignAndEncrypt) programmatic UADP publishing with this library, or a known limitation in 1.3? How can I read back at runtime whether security is actually active (via itfDiagnostics or similar)? Additional information I can confirm that the consumer side works β i.e. a standard subscriber decrypts the same keys fine β so the keys/profile aren't the issue. The Wireshark capture of the published message is: 0000 b1 01 29 00 0f 16 00 df 0d bb 25 01 00 0e 00 1b ..).......%..... 0010 0e 00 00 00 00 00 00 00 ........
Last updated: 2026-06-22
Post by alexschooneveld on OPC UA PubSub SL 1.3 β UADP WriterGroup with assigned PSS.SecurityGroup still publishes plaintext
CODESYS Forge
talk
(Post)
I am currently investigating an OPC UA PubSub connection over UDP. When I don't use encryption, the publish and subscribe are working correctly. But with encryption it does not. Environment OPC UA PubSub SL 1.3.0.0 (namespace UADP) OPC UA PubSub Security 1.3.0.0 (namespace PSS) OPC UA PubSub Base 1.3.0.0 (namespace PSB, incl. PSS.SecurityGroup / PSS.CONFIG) Programmatic PubSub in a CFC: UADP.Configuration β UADP.Connection β UADP.writerGroup β UADP.writer β writerDataSet, plus a CyclicCall gated by xEnable. Goal: publish secured UADP, SignAndEncrypt, policy PubSub-Aes256-CTR. What I do (one-shot, before xEnable := TRUE): fbSecurityGroup.SetInitialValue( 'http://opcfoundation.org/UA/SecurityPolicy#PubSub-Aes256-CTR', PSB.SECURITY.SIGNING_AND_ENCRYPTION); stSecurityCfg := fbSecurityGroup.GetConfig(eErrorID => eError); // eError=NO_ERROR, udiEncryptionKeySize=32 eError := fbSecurityGroup.SetSecurityKeys(udiTokenId, ADR(abyKey), SIZEOF(abyKey), 2436001000); // eError=NO_ERROR, SIZEOF=68 // writerGroup.itfSecurityGroup := fbSecurityGroup -- set in the WriterGroup block's Parameters (a per-scan code write got overwritten) What I verified eError = NO_ERROR after both GetConfig and SetSecurityKeys; udiEncryptionKeySize = 32. Key length = 68 bytes (signing 32 β encrypt 32 β nonce 4). itfSecurityGroup is set via the WriterGroup's Parameters (so it isn't clobbered each scan). Init runs before xEnable (the writer doesn't run with xEnable=FALSE). The UADP.writerGroup FB exposes only itfSecurityGroup for security β no SecurityMode/MessageSecurityMode property. Result: the published datagrams are still plaintext β ExtendedFlags1 = 0x01 (security bit 0x10 clear), no security header: b1 01 29 00 0f 16 00 β¦ (PublisherId 41, WriterGroupId 22, RawData, no security) Questions With UADP.writerGroup, is assigning a configured + keyed PSS.SecurityGroup to itfSecurityGroup sufficient to enable message security, or is there an additional step/property/method to switch the WriterGroup to SignAndEncrypt? At what point in the WriterGroup lifecycle is itfSecurityGroup read? Must it be assigned/keyed before xActive, and does the group need a stopβstart to pick it up? Is there a required call order, and does SetSecurityKeys need to be called once or repeatedly? Should security be configured on the Connection/Configuration level rather than (or in addition to) the WriterGroup? Is there a working example of secured (SignAndEncrypt) programmatic UADP publishing with this library, or a known limitation in 1.3? How can I read back at runtime whether security is actually active (via itfDiagnostics or similar)? Additional information I can confirm that the consumer side works β i.e. a standard subscriber decrypts the same keys fine β so the keys/profile aren't the issue. The Wireshark capture of the published message is: 0000 b1 01 29 00 0f 16 00 df 0d bb 25 01 00 0e 00 1b ..).......%..... 0010 0e 00 00 00 00 00 00 00 ........
Last updated: 2026-06-22
Post by mubeta on Some 'pathetic' errors in SoftMotion program
CODESYS Forge
talk
(Post)
Hello everyone, I have a very simple program for the process, but it's driving me crazy and I can't see the problems I'm left with: Short topological description: Dual Core Berghof controller with softmotion runtime version 3.5.19.30; Two axes with servodrive on canopen bus, clocked distributed from master; Ethercat I/O node; 2 ms ethercat task, 2 ms canopen bus cycle time; I/O objects of the canopen master and canopen drives connected to the ethercat task cycle; Problem 1: Two separate programs each manage their own axis and drive, with separate state machines. A first axis moves primarily in velocity, except having to position itself absolutely at a predetermined point at the end of the job; the second axis, on the other hand, is a paper unwinder that changes, for each job cycle, from actions in absolute, relative, and cam displacement with the master axis. Well, the state machine of both axes was written in such a way as to call running the useful FB and change it on state change in this way: CASE i_stateMachine OF 0: o_Power(Enable := TRUE, bRegulatorOn := FALSE, bDriveStart := FALSE, Axis := o_PaperUnwinderAxis); o_MoveAbs(Execute := FALSE, Axis := o_PaperUnwinderAxis); o_MoveRel(Execute := FALSE, Axis := o_PaperUnwinderAxis); o_CamSelect(Execute := FALSE, Master := o_MachineAxis, Slave := o_PaperUnwinderAxis, CamTable := cam_PaperUnwinder); o_CamIn(Execute := FALSE, Master := MachineEncoder, Slave := o_PaperUnwinderAxis); o_CamOut(Execute := FALSE, Slave := o_PaperUnwinderAxis); o_SetPosition(Execute := FALSE, Axis := o_PaperUnwinderAxis); IF ... THEN i_StateMachine := 10; END_IF; 10: o_Power( Enable := TRUE, bRegulatorOn := TRUE, bDriveStart := TRUE, Axis := o_PaperUnwinderAxis ); IF o_Power.Status THEN i_StateMachine := 20; END_IF; 20: (* Avanzamento carta *) o_MoveAbs( Execute := TRUE, Position := o_Somewhere, Velocity := 25.0, Acceleration := 3666.7, Deceleration := 3666.7, Jerk := 48000.0, Direction := MC_DIRECTION.positive, Axis := o_PaperUnwinderAxis ); IF o_MoveAbs.Done THEN o_MoveAbs(Execute := FALSE, Axis := o_PaperUnwinderAxis); i_StateMachine := 30; END_IF 30: d_HomingPosition := ...; o_SetPosition( Execute := TRUE, Position := d_HomingPosition, Mode := FALSE, Axis := o_PaperUnwinderAxis ); (* ... *) IF o_SetPosition.Done = TRUE THEN o_SetPosition(Execute := FALSE, Axis := o_PaperUnwinderAxis ); o_LogServer.Append(sMessage := '...', lscClass := LOGSERVER_CLASS.ALWAYS, sdt := o_CommonsMgrData.systime.sdtLocal); i_StateMachine := 40; END_IF; 50: ... The code above is a sketchy example of what I wanted to write. But it gives me a spot problem: in some, the state change results in a drive error, which is unrecoverable except with a reinitialization via SM3_ReinitDrive(). Things are improved a little if in the program I always run the call of all softmotion blocks in this way: o_Power(Axis := o_PaperUnwinderAxis); o_Jog(Axis := o_PaperUnwinderAxis); o_Halt(Axis := o_PaperUnwinderAxis); o_MoveAbs(Axis := o_PaperUnwinderAxis); o_MoveRel(Axis := o_PaperUnwinderAxis); o_CamIn(Master := MachineEncoder, Slave := o_PaperUnwinderAxis); o_CamOut(Slave := o_PaperUnwinderAxis); If I don't execute all the calls of all the motion FBs used, when exchanging machine state often (but not always), the axis goes into error with event id THE_FB_WASNT_CALL... Done a little diagnostics it seems that the FBs return the bDone, before they are completely terminated. I tried doing the machine state exchange not with the bDone bit of the FBs, but with the 'standstill' state of the axis. It didn't seem to change anything. Problem 2: During the use SM3_ReinitDrive() I get the erro in the log: "NetID 0: SDO read error for object 16#607C..." Assuming that the device involved it's one of the two servodrive, (no others device are present in the network), I don't found any object 0x607C in the 'possible object list in/out' of the two drive, and I don't understand where this object can be listed. So any ideas and suggestions regarding these two issues will be very, very welcome. If you need the source project, I am willing to send it.
Last updated: 2024-07-17
Post by mondinmr on COL.IMap2 and HashTableFactory cause frequent Access Violation
CODESYS Forge
talk
(Post)
Good morning, Iβve been using the Collection library for a long time, mostly with Stack, LinkedList, and List. From your examples I was able to manage the different factories, even for custom elements. Now I need a hashtable, but with this object Iβm running into a lot of random access violations. If I append something inside FB_Init after constructing the hashtable, it crashes, even though the list was already created. If I only create the hashtable in FB_Init and append afterwards, it usually works. I donβt understand the meaning of the dispose call in this code: pSlave := ADR(slave); uSlave := TO_ULINT(pSlave); iKey := fKey.Create(uSlave); IF hash.CountKeys() = 0 THEN Service.logger.appendLog('Filling hashtable', 'HashManager', AdvLogType.AdvDebugMsg); ok := FALSE; ELSE eError := hash.ContainsKey(iKey, xResult => ok); END_IF IF NOT ok THEN pI := __NEW(UINT); iVal := fKey.Create(TO_ULINT(pI)); Service.logger.appendLog(CONCAT('New slave', TO_STRING(uSlave)), 'HashManager', AdvLogType.AdvDebugMsg); hash.AddKeyValuePair(iKey, iVal); appendNewSlave := pI; ELSE eError := hash.GetElementByKey(iKey, itfValue => iElem); xResult := __QUERYINTERFACE(iKey, itfIInstance); IF xResult THEN itfIInstance.Dispose(); END_IF IF eError <> COL.COLLECTION_ERROR.NO_ERROR THEN Service.logger.appendLog(CONCAT('ERROR ', TO_STRING(eError)), 'HashManager', AdvLogType.AdvCriticalMsg); appendNewSlave := nullptr; RETURN; END_IF __QUERYINTERFACE(iElem, iVal); {warning disable C0033} pI := TO___UXINT(iVal.UlintValue); {warning restore C0033} appendNewSlave := pI; END_IF Without the dispose call, every second cold reset crashes immediately when I try to access iVal, even if eError doesnβt report any error. With the dispose call, the cold reset issue disappears, but I get other problems: a) If I start the runtime using systemctl start codesyscontrol, it crashes at IF hash.CountKeys() = 0 THEN b) If I delete the files in PlcLogic and download again, it works and survives multiple cold resets. But as soon as I run systemctl restart codesyscontrol, everything gets corrupted again and it starts crashing at that point. FUNCTION_BLOCK SlaveMapCounter VAR hash : COL.IMap2; eError : COL.COLLECTION_ERROR; END_VAR In its FB_Init I create it: METHOD FB_Init: BOOL VAR_INPUT bInitRetains: BOOL; // TRUE: retain variables are initialized (reset warm / reset cold) bInCopyCode: BOOL; // TRUE: the instance will be copied to the copy code afterward (online change) END_VAR VAR hF : COL.HashTableFactory; END_VAR hash := hF.Create(256); In another FB I instantiate it statically: FUNCTION_BLOCK ABSTRACT AbstractServoEthercatController EXTENDS AbstractServoController VAR_STAT hashSlaves : SlaveMapCounter; END_VAR VAR field : REFERENCE TO ADVAbstractFieldUnitEthercatCia402; initCnt : REFERENCE TO UINT; END_VAR The append method is the one shown above, and I call it after the runtime has started. The accesses are performed by a single task, and in any case Iβm working on an isolated single core. Iβve tried everything, moving the create, the instances, and all the rest several times, but nothing seems to work. Iβd like to point out that these FBs are part of our own library, which is used in many applications.
Last updated: 2025-09-11
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
To search for an exact phrase, put it in quotes. Example: "getting started docs"
To exclude a word or phrase, put a dash in front of it. Example: docs -help
To search on specific fields, use these field names instead of a general text search. You can group with AND or OR.