Hello Guest it is March 28, 2024, 11:03:09 AM

Author Topic: Making a connection through rs232 in Mach4  (Read 8198 times)

0 Members and 1 Guest are viewing this topic.

Re: Making a connection through rs232 in Mach4
« Reply #20 on: November 25, 2019, 10:09:06 PM »
I am not an expert in programming by any stretch so this is likely a super butchered explanation...

When you call the line to open the port, you assign a pointer or address of the port to the variable "p"

From then on, your functions will use the name of the port "p" (which you can set to anything you want BTW) and call functions from the luars232 library.

As I understand... p:write() is shorthand for p.luars232.write() or something like that. It is an abbreviated form of a function call.

Once I got all my serial code working, I wrapped it up and put it in a module. I found this helpful to help keep my code organized and keep the screen load script from getting filled up with too much junk.

Signing off for the night. Check in tomorrow to see where you got.

Nice Work.

-Mike
Re: Making a connection through rs232 in Mach4
« Reply #21 on: November 26, 2019, 12:10:53 PM »
Lets see if I can give you some examples. I'm not familiar with labels, but I can use the error bar. I'm typing this straight into the forum so please excuse and correct any syntax errors.

Example 1: Read exactly 10 characters from the serial port and print them to the error bar on screen. This assumes the port is open.

Code: [Select]
inst = mc.mcCntlGetInstance()
local string = ""  --Empty string
local len = 0

e, string, len = p:read(10,5) --Read 10 characters, save to "string", 5ms timeout, string length saved in "len"
if (e~= 0) then
    mc.mcCntlSetLastError(inst, "Read Failed, Error: "..tostring(e))
else
    mc.mcCntlSetLastError(inst, tostring(len).." characters read. Data is: "..string)
end

In this example, we want to read 10 characters. If this happens without error, we print the string length (returned from the function call) and the actual data received (not that termination characters count to the length but are not visible). If an error occurs, we print an error message with the error code.
Re: Making a connection through rs232 in Mach4
« Reply #22 on: November 26, 2019, 12:19:04 PM »
Example 2: Read the entire buffer character by character, stop when empty. Data is concatenated into a string at the end of each loop.

Code: [Select]
inst = mc.mcCntlGetInstance()
local string = ""
local dat = ""
local len = 0

for i=0,4095,1 do
    e, dat = p:read(1,5) --1 character, 5ms timeout
    if  (e ~= 0 and e~=9) then
        mc.mcCntlSetLastError(inst, "Read Failed, Error: "..tostring(e))
    elseif (e==9) then
        mc.mcCntlSetLastError(inst, "Buffer Empty")
        break --Exit the for loop
    else
        string = string..dat
    end
end
mc.mcCntlSetLastError(inst, string.len(string).." characters received. Data is: "..string)

Here we read until getting an error 9 (Timeout) which indicates that data was not found before the timeout value expired. Timeout is a great way to handle real world latencies in network traffic.
Re: Making a connection through rs232 in Mach4
« Reply #23 on: November 26, 2019, 12:27:31 PM »
Pretty sure I know where your error is in this code:

Code: [Select]
scr.SetProperty("testLabel","Label",p:read(12, 5))
LUA allows you to do multiple returns from a function. This means when the function exits, it can have a statement like:

Code: [Select]
myfunction()
...
return a,b,c
end

When you call this function you might do something like this:

Code: [Select]
x, y, z = myfunction()
Where x gets the value returned by "a", y the value for "b", and z the value for "c". You don't need to use all 3, however they always return in this order.

The LUA serial function read() returns 3 variables as shown below:

Code: [Select]
e, data_read, size = p:read(length, timeout)
"e" is the error code, "data_read" is the data, and "size" is the length of the returned string.

When you called this function inside another function, you only grabbed the first returned value, in this case the error code not the data you wanted.

To make this work, you'll need to do something like this:

Code: [Select]
e, string = p:read(12, 5)
scr.SetProperty("testLabel","Label",string)

Note that in this case I captured the first return "e" but did nothing with it and I didn't even bother to capture the 3rd return "size".
Re: Making a connection through rs232 in Mach4
« Reply #24 on: November 26, 2019, 12:35:45 PM »
I think I can better phrase the answer I gave earlier about the use of the colon in the serial library.

The serial library defines the "port" as a class (as in a datatype in an object oriented programming language). When we open the port, we are also declaring that "p" is a member of the class "port". This class has methods (actions) which it can do. In our case, these are:

-close
-flush
-read
-write

To call a method (action) of a class, you can use the colon. So p:write() is the way to tell "p", member of class "port", that it should write(). This is shorthand and you could still call it normally like a function.

This is explained here in the LUA reference: https://www.lua.org/pil/16.html
Re: Making a connection through rs232 in Mach4
« Reply #25 on: November 26, 2019, 12:42:26 PM »
Example 3: Flushing the buffer

Flushing the buffer is super simple and all it does is delete the contents of the buffer without reading them.

Lets say you open your serial port and sit for a few minutes. The whole time your Arduino has been writing "Hello World" once per second. Obviously your buffer will be very full. Lets say we want to read one line of "Hello World" and we want it to be the most recent one.

Code: [Select]
inst = mc.mcCntlGetInstance()
string = ""

p:flush()
e, string(12, 1200) --Read all 12 characters of "Hello World\r" waiting just over 1 second for them to arrive
mc.mcCntlSetLastError(inst, string)

In this code, we make sure the buffer is completely empty before we read. We allow 1.2 seconds for the data to arrive since this will capture one and only one packet from the Arduino.
Re: Making a connection through rs232 in Mach4
« Reply #26 on: November 26, 2019, 08:20:16 PM »
YYYYYESSSS!!!!!
So this works awesome!
I was able to read from the Arduino using the examples. I'll start setting things up to Read / Write and see how things behave. I want to also do some testing with speeds and error correction but, for now, I'm just getting the basics going.

Thank you again Mike, I really think once this gets out a little more, people will start to see just how simple / powerful this is.

More to come
-Tim
Re: Making a connection through rs232 in Mach4
« Reply #27 on: November 26, 2019, 08:47:49 PM »
Glad it is working. Awesome job!

Sounds perfect. Something you might want to consider is adding a checksum to the end of each transmission. Something quick to calculate but unlikely to be generated by bad input data.

If you're controlling both ends of the transmission then this is great. My servo drives require this with their transmissions so I was forced to develop it. Here is that code which does some math to create a two character checksum to be appended onto the end of a string you want to transmit. On the receiving end, you take the received string, remove the last 3 characters (checksum plus carriage return), and run the same checksum code. If the string matches the string you received, then you know it is highly likely that the transmission came through correctly.

Code: [Select]

function AppendChecksum(str)
local ccSum = 0
local len = string.len(str)

for i=1,len,1 do
ccSum = ccSum + str:byte(i)
end

local output = string.format("%X", bit32.band(256-ccSum))
local checksum =  string.sub(output,-2,-1)

return str..checksum.."\r"
end


This is just one example of accomplishing this.

Feel free to keep asking questions and please share any tips that you come across for other who might want to try serial.

You've made it over the hill! Now is the fun part!
Re: Making a connection through rs232 in Mach4
« Reply #28 on: November 30, 2019, 04:08:47 PM »
Well done guys.

I am trying to accomplish the same. It seems that you aren't using the Serial Plugin that ships with Mach4, are you? Have anybody tried using it? I cannot find any documentation about it and I could imagine using the official plugin might be more future proof(?)

Best regards

Brandon
Re: Making a connection through rs232 in Mach4
« Reply #29 on: November 30, 2019, 07:35:28 PM »
@brandon. Hey Brandon. That is an old module that is there for other things. I read about it here somewhere. I shut it off all together. It's not what you need.

FYI, I have been able to build out a solid communications channel using an Arduino Uno. This has two way coms and I currently have a Jogging encoder connected which is updating a DRO. Step two is to send the DRO value back to the Arduino so that I see it on a screen.

I still need to flush this all out and then post here so that -real- developers might be able to take what I have and make it better / more bullet proof. I am going to completely document the whole process to build a serial Pendant using an Arduino.

Mike Cardoso, here in this thread, has been a tremendous help I really need to give most of the credit to him (I definitely will when I publish) but I'm trying not to bother him until I'm ready.