This is a read-only archive of the old Scratch 1.x Forums.
Try searching the current Scratch discussion forums.

#1 2013-04-09 09:54:44

DigiTechs
Scratcher
Registered: 2011-04-30
Posts: 500+

Getting Lua and Scratch to communicate...

Okay, so I have found out how to get Lua and Scratch to communicate (finally :I)

Lua and Scratch like to communicate over a UDP network. I've tried it using TCP, but I kept getting errors with my communication.

(Mainly 'message too big; bad size field?' errors.)

If any of the more intelligent with Squeak (I'm dumbfounded by it, I'm more of a Lua person  tongue ) know how to fix this, please tell me.

First, you want to host a mesh session on the Scratch window. I'm expecting you to know how to do this, and so won't provide tutorials.

Second, open up any of your favoured text editors, and paste this in.
Before we do that, you need to have Luaforwindows installed, as that's how I have most of this code.

Here's the code you want to paste in:

Code:

local socket = require("socket")
host = host or "localhost"
port = port or 42001
if arg then
    host = arg[1] or host
    port = arg[2] or port
end
host = socket.dns.toip(host)
udp = assert(socket.udp())
assert(udp:setpeername(host, port))
print("Using remote host '" ..host.. "' and port " .. port .. "...")
while 1 do
    line = io.read()
    if not line or line == "" then os.exit() end
    assert(udp:send('broadcast "'..line..'"'))
end

Save the file as a .lua for later.
In Scratch, make a chunk of code similar to this:

when I receive [Hello v]
say [Hello!]
Okay, done? Good.
Run the .lua file you saved earlier. If you did it properly, you should get this message:

Using remove host '[yourlocalIP]' and port 42001...

Then, in the window, type 'Hello'

You should see the sprite say 'Hello!'

Tell me what you think  smile  I'm currently working on getting Scratch to communicate with Lua, which seems to not work as simple.


I'm back.
Maybe.

Offline

 

#2 2013-04-09 10:12:57

DigiTechs
Scratcher
Registered: 2011-04-30
Posts: 500+

Re: Getting Lua and Scratch to communicate...

Although, I have one question.

What format does Scratch send broadcasts in?


I'm back.
Maybe.

Offline

 

#3 2013-04-09 13:50:21

blob8108
Scratcher
Registered: 2007-06-25
Posts: 1000+

Re: Getting Lua and Scratch to communicate...

See the wiki


Things I've made: kurt | scratchblocks2 | this cake

Offline

 

#4 2013-04-09 15:53:03

DigiTechs
Scratcher
Registered: 2011-04-30
Posts: 500+

Re: Getting Lua and Scratch to communicate...

I meant, once I have received it in Lua, what does it LOOK like?

I mean something like

broadcast "message"

That's how Lua sends a broadcast to Scratch. I want to know how Scratch sends the same broadcast to Lua.


I'm back.
Maybe.

Offline

 

#5 2013-04-09 16:22:30

blob8108
Scratcher
Registered: 2007-06-25
Posts: 1000+

Re: Getting Lua and Scratch to communicate...

I was under the impression it was a TCP connection, not UDP -- though the article doesn't actually mention that anywhere...


Things I've made: kurt | scratchblocks2 | this cake

Offline

 

#6 2013-04-09 16:25:38

blob8108
Scratcher
Registered: 2007-06-25
Posts: 1000+

Re: Getting Lua and Scratch to communicate...

Yup, think it's TCP


Things I've made: kurt | scratchblocks2 | this cake

Offline

 

#7 2013-04-09 16:44:22

DigiTechs
Scratcher
Registered: 2011-04-30
Posts: 500+

Re: Getting Lua and Scratch to communicate...

Actually, going through the code, I get this as a comment:

"Process incoming UDP commands."

That's in Scratch-Networking>ScratchServer>private-server>processUDPCommands

And anything I see about networking has 'UDP' in it.

It's weird how Scratch uses an UDP connection, while other things (Going to use Magnie's Little Server That Can as an example) use TCP connections.

Quite odd, isn't it?

EDIT: Here's the code for 'startHosting', which makes me certain that Scratch uses UDP and not TCP.

Code:

startHosting
"Open a socket on my port and start accepting connections."

Socket initializeNetwork.
self shutdownServer.

serverSocket _ Socket new.
serverSocket listenOn: self class portNumber backlogSize: 20.

incomingUDPSocket _ Socket newUDP setPort: self class portNumber.

Interesting, isn't it?

Last edited by DigiTechs (2013-04-09 16:47:18)


I'm back.
Maybe.

Offline

 

#8 2013-04-09 16:50:33

DigiTechs
Scratcher
Registered: 2011-04-30
Posts: 500+

Re: Getting Lua and Scratch to communicate...

Although, in:

Network-Message Socket>MessageSocket>connection>connectTo:port:

it defines 'socket' as Socket newTCP.

How ODD.


I'm back.
Maybe.

Offline

 

#9 2013-04-09 17:17:18

blob8108
Scratcher
Registered: 2007-06-25
Posts: 1000+

Re: Getting Lua and Scratch to communicate...

Well, the Python example is using TCP.


Things I've made: kurt | scratchblocks2 | this cake

Offline

 

#10 2013-04-09 17:18:22

DigiTechs
Scratcher
Registered: 2011-04-30
Posts: 500+

Re: Getting Lua and Scratch to communicate...

I have a question for those who have worked with Scratch Networking:

How do you receive a message from Scratch? I tried using:

udp:receive()

in my Lua code to receive my message, but I seem to not get any message out of it.

EDIT: If I use TCP, I get the error mentioned in the top. Also, I seem to get an error when joining a Lua UDP server saying 'unable to connect to [ip]', with no error message. But Lua says I get a timeout error.

Last edited by DigiTechs (2013-04-09 17:22:11)


I'm back.
Maybe.

Offline

 

#11 2013-04-09 17:29:45

blob8108
Scratcher
Registered: 2007-06-25
Posts: 1000+

Re: Getting Lua and Scratch to communicate...

DigiTechs wrote:

If I use TCP, I get the error mentioned in the top.

Sounds like you're sending a malformed message  tongue  It's definitely TCP.


Things I've made: kurt | scratchblocks2 | this cake

Offline

 

#12 2013-04-09 17:31:19

DigiTechs
Scratcher
Registered: 2011-04-30
Posts: 500+

Re: Getting Lua and Scratch to communicate...

I'm confused.

Scratch is odd.

Hosting server in Scratch and using UDP client to connect works, but using TCP gives me this malformed message thing.


I'm back.
Maybe.

Offline

 

#13 2013-04-10 06:14:18

blob8108
Scratcher
Registered: 2007-06-25
Posts: 1000+

Re: Getting Lua and Scratch to communicate...

DigiTechs wrote:

using TCP gives me this malformed message thing.

Check your message!


Things I've made: kurt | scratchblocks2 | this cake

Offline

 

#14 2013-04-10 06:49:18

DigiTechs
Scratcher
Registered: 2011-04-30
Posts: 500+

Re: Getting Lua and Scratch to communicate...

I don't get WHY I'm getting the error using TCP, I'm sending exactly the same message.


I'm back.
Maybe.

Offline

 

#15 2013-04-10 07:24:12

DigiTechs
Scratcher
Registered: 2011-04-30
Posts: 500+

Re: Getting Lua and Scratch to communicate...

I think I have encountered a problem using my TCP server.

I've found it can't receive from the port. I'll have to use a different client to do it.


I'm back.
Maybe.

Offline

 

#16 2013-04-10 08:14:07

DigiTechs
Scratcher
Registered: 2011-04-30
Posts: 500+

Re: Getting Lua and Scratch to communicate...

Okay, an update on the TCP client/server bundle:

I've got Scratch to be able to CONNECT to the TCP client, but I am unable to send messages to the other connected clients from one Scratch instance.

Here's my code. It's a little unorganised and everything's in funny places, so it'll be good if you have a vague understanding of Lua, or anything similar to it (Python is a little similar, but not the same definitely.)

Code:

--Local variables
local socket = require("socket")
local newline = "\n"
--Create server
local server = assert(socket.bind("127.0.0.1", 42001, 100))
server:settimeout(1)
server:setoption('tcp-nodelay', true)
local client = assert(socket.tcp())
local currsel

io.write("Created servers."..newline)

--Newset code
function newset()
    local reverse = {}
    local set = {}
    return setmetatable(set, {__index = {
        insert = function(set, value)
            if not reverse[value] then
                table.insert(set, value)
                reverse[value] = table.getn(set)
            end
        end,
        remove = function(set, value)
            local index = reverse[value]
            if index then
                reverse[value] = nil
                local top = table.remove(set)
                if top ~= value then
                    reverse[top] = index
                    set[index] = top
                end
            end
        end
    }})
end

set = newset()

--Insert servers in set
io.write("Inserting servers in set."..newline)
set:insert(server)

--Connect code
local conn = coroutine.create(function()
while true do
    local readable, _, errk = socket.select(set, nil)
    for _, input in ipairs(readable) do
        currsel = input
        if input == server then
            io.write("Waiting for clients..."..newline)
            local new = input:accept()
            if new then
                new:settimeout(1)
                io.write("Inserting client in set."..newline)
                set:insert(new)
            end
        else
            local line, err = client:receive()
            if err then
                io.write(tostring(err)..newline)
                input:close()
                io.write("Removing client from set."..newline)
            else
                io.write("Echoing line '"..line.."'."..newline)
                client:send(line)
            end
        end
    end
end
end)

--Create echo client
server:accept()
client:connect("127.0.0.1", 42001)
client:setoption('tcp-nodelay', true)

--Start the connection code
coroutine.resume(conn)

I'm back.
Maybe.

Offline

 

#17 2013-04-10 10:37:39

DigiTechs
Scratcher
Registered: 2011-04-30
Posts: 500+

Re: Getting Lua and Scratch to communicate...

OKAY, I think I have sending.. buggy but working to a small extent. Here's an error message (YAY, THE SAME.) of what I get when I send messages to scratch. Maybe the people who are better than me at Squeak can tell me what I'm doing wrong.

Code:

message too big; bad size field?

MessageSocket(Object)>>error:
[] in PasteUpMorph>>runStepMethods
[] in BlockContext>>ifError:
MessageSocket(Object)>>error:
MessageSocket>>nextMessage
ScratchServer>>processCommandFrom:
[] in ScratchServer>>processIncomingCommands
OrderedCollection>>do:
ScratchServer>>processIncomingCommands
ScratchServer>>stepServer

That's my error message. What I'm thinking is 'OH COME ON, DO I NEED TO ENCODE YOU IN MD5 OR SOMETHING?!'


I'm back.
Maybe.

Offline

 

#18 2013-04-11 19:43:51

Magnie
Scratcher
Registered: 2007-12-12
Posts: 1000+

Re: Getting Lua and Scratch to communicate...

The message field error (if you are getting it in Scratch) is relating to the fact you probably aren't adding the length of the message to the beginning. http://wiki.scratch.mit.edu/wiki/Remote_Sensor_Protocol

Scratch is thinking the length of the message is 'broa' (or 1634693730 characters) long.  tongue  So what you want to do is change the message so it's <4 byte size><message>. So 'broadcast "message"' is 19 characters long, so you want to send this:

Code:

\0\0\0\19broadcast "message"

I think, at least it's something along those lines. But basically the length of the message is stored in 4 bytes, and the message size is in base-256 or 255.

That is also the same format Scratch sends the messages in. Also, if anything, it's probably better to stick with TCP rather than UDP until you know what you are doing (I don't really use UDP just because it has a risk of sending the packets in the wrong order). Comment on my profile on the Beta website for any additional help (since I don't visit here very often anymore).

Offline

 

#19 2013-04-12 12:15:15

DigiTechs
Scratcher
Registered: 2011-04-30
Posts: 500+

Re: Getting Lua and Scratch to communicate...

UDP seems to be communicating with scratch easier.

But thanks for the info.

EDIT: Okay, so I did that but I'm still getting the error.

Here's what I send:

'\\0\\0\\0\\'..string.len('broadcast "TESTMSG"')..'broadcast "TESTMSG"'

Since \ is Lua's Escape Character, I have to double it up for it to work. But this time I'll try and just use one single one.

EDIT 2: When I use the single one I get an error... :I

EDIT 3: Okay, now this is the format of my begin code: \0\0\0\\ which DOESN'T give me the message to big error. I think another way I'll do it will be better.

EDIT 4: In fact, what I tried didn't work. I'm kinda still confused.

Last edited by DigiTechs (2013-04-12 12:23:21)


I'm back.
Maybe.

Offline

 

#20 2013-04-12 12:43:03

DigiTechs
Scratcher
Registered: 2011-04-30
Posts: 500+

Re: Getting Lua and Scratch to communicate...

Okay...

I need something like 'call' from BYOB in Lua...

Mabye loadstring()()?


I'm back.
Maybe.

Offline

 

#21 2013-04-12 14:32:44

Magnie
Scratcher
Registered: 2007-12-12
Posts: 1000+

Re: Getting Lua and Scratch to communicate...

\ is usually the escape character, which is why I said '\0\0\0\0' instead of '\\0\\0\\0\\0' since it is necessary to escape the character.

\0\0\0\0 means the message is '0' characters long and basically tells Scratch that it's closing the session. Send this message exactly as it is:

Code:

\0\0\0\19broadcast "message"

And with the same code (without the double-escape) send:

Code:

'\0\0\0\'....string.len('broadcast "TESTMSG"')..'broadcast "TESTMSG"'

I don't know exactly how the length is generated, I just use this (in Python):

Code:

def add_length(cmd):
    # Defines the length of each message.
    n = len(cmd)
    a = array('c')
    a.append(chr((n >> 24) & 0xFF))
    a.append(chr((n >> 16) & 0xFF))
    a.append(chr((n >>  8) & 0xFF))
    a.append(chr(n & 0xFF))
    return (a.tostring() + cmd)

If you understand bit shifting and stuff, you should be able to recreate the function in Lua. chr() is a function that changes a character from an integer (0-255) to the character equivalent. If Lua has a built-in function like that, use this instead (Lua code):

Code:

'\0\0\0'..chr(string.len('broadcast "TESTMSG"'))..'broadcast "TESTMSG"'

since it is more likely to work correctly (since I don't know exactly how to use escape characters to get the equivalent character.

Does that make sense?

Offline

 

#22 2013-04-12 15:01:06

DigiTechs
Scratcher
Registered: 2011-04-30
Posts: 500+

Re: Getting Lua and Scratch to communicate...

Okay, I've got it working. I've managed to send a message to scratch from Lua using my TCP server!

Here's what I had to do to fix it:

Code:

num = 19
result = loadstring("local s = '\\"..num.."' return s")()

Basically, the \ character is Lua's Escape character, and I needed a way to turn "\19" into what the Lua Command Line said was !! (one character, just two in one). I asked some friends and this is what they came up with. And it works!

EDIT: Magnie, this might be what you're looking for to turn the backslash into it's escape character.

Last edited by DigiTechs (2013-04-12 15:03:01)


I'm back.
Maybe.

Offline

 

#23 2013-04-12 15:28:23

Magnie
Scratcher
Registered: 2007-12-12
Posts: 1000+

Re: Getting Lua and Scratch to communicate...

It might be. I've never even touched Lua, so I wouldn't know.  tongue

I actually think it's supposed to be '\x13' (not sure how you get 19 into that, but that's what I have from Python). I hope it fixed your problem. The next step is decoding the string that you receive.  tongue

Offline

 

#24 2013-04-12 15:49:40

DigiTechs
Scratcher
Registered: 2011-04-30
Posts: 500+

Re: Getting Lua and Scratch to communicate...

Hmm.

I hate it that the Lua TCP server can't receive like you can in the Python TCP server.


I'm back.
Maybe.

Offline

 

Board footer