Small TCP client library?


#1

hi

I’m looking for a small wip library (.dwl) to create a TCP client using AT commands for the GPRS connection, and then the DATA-MODE to transfer the data.
I have already tried the WIPSoft library, but I’m experiencing a lot of trouble using it. It seems I have encountered the most part of the problems described in this forum without any working result.

Does anyone can send me a piece of working code to build a TCP client connection ?

BR
Alan


#2

By using Open AT Lua to write additional AT commands, you can run something like that:

-------------------------------------------------------------------------
-- AT+TCPCONNECT=<address>,<port>,<nbytes> will:
-- * read <nbytes> bytes of data from the UART port where the AT command is typed
-- * connect a TCP socket to address:port
-- * send the data read from UART to the TCP socket
-- * shutdown the TCP connection.
-------------------------------------------------------------------------
at.commands['AT+TCPCONNECT='] = function (cmd, address, port, nbytes)
   local data = read_n_bytes_from_uart (nbytes, cmd.port)
   local socket = wip.tcp_client (address, port)
   socket:write(data)
   socket:close()
   return "\r\nOK"
end

function read_n_bytes_from_uart(bytes_to_read, uart)
   local ch = wip.fcm (uart)
   local buffer = { }
   while true do
      local segment = internal.wip_read(ch, bytes_to_read)
      if segment then
         table.insert(buffer, segment)
         bytes_to_read = bytes_to_read - #segment
      end
      if bytes_to_read == 0 then break end
      ch:_wait_read()
   end
   ch:close()
   return table.concat (buffer)
end

Notice that the the big ugly function read_n_bytes_from_uart() is a work around a known bug in the current release (blocking to read a specified number of bytes from a channel sometimes incorrectly waits for an extra byte). In the upcoming version of Open AT Lua, the program will simply be:

at.commands['AT+TCPCONNECT='] = function (cmd, address, port, nbytes)
   local uart = wip.fcm(cmd.port)       -- reserve the UART port and switch it to DATA mode
   local data = uart:read(nbytes..'*')  -- block to read `nbytes' bytes of data from uart in DATA mode
   uart:close()                         -- switch UART back to AT mode and release it
   local socket = wip.tcp_client (address, port) -- create & connect the socket
   socket:write(data)                   -- send data
   socket:close()                       -- close and release socket
   return "\r\nOK"
end

#3

Oops, I forgot the grps config part. Here’s to start GPRS:

----------------------------------------------------
-- AT+TCPSTARTGPRS=<login>,<password>,<apn>
-- starts the GPRS connection with the specified config
----------------------------------------------------
at.commands['AT+TCPSTARTGPRS='] = function (cmd, login, password, apn)
   if proc.bearers.GPRS then return { "GPRS already up\r\n", "OK\r\n" } end
   local b = wip.bearer_client( 'GPRS', { login=login; password=password; apn=apn })
   if not b then error() end
   return "OK\r\n"
end

and here’s to shut it down:

----------------------------------------------------
-- AT+TCPSTOPGPRS stops the GPRS bearer
----------------------------------------------------
at.commands['AT+TCPSTOPGPRS'] = function (cmd)
   local b = proc.bearers.GPRS
   if b then  b:close(); return "OK\r\n"
   else return { "GPRS already down\r\n", "OK\r\n" } end
end

#4

hey

Thanks fft for your answer!

In fact, I have already tryed to manage a Open AT C code having the same behaviour you have described above.
My problem is that I am transmitting data via AT command, not in DATA_MODE.
That results in a datasize problem (multi AT commands are possible, but modem’s storage is limited).

I’m currently using this to send data:

wip_write( c, httpTx, strlen(httpTx));

And to receive:

nread = wip_read( c, buffer, SIZE_RECEIVE_BUFFER);

(in a loop)

Any idea to translate it using the DATA_MODE?
I can send you my more detailed code if you want/need.

I’m still looking for a simple TCP client library using DATA_MODE switching.

Thanks


#5

if you want to do it in C, you’ll need to figure out and use the adl_fcmSubscribe() API. Be warned that it’s not very intuitive, and it’s cumbersome to bufferize data with it. I heard that Wavecom wants to provide a better, direct interface to UART-like ports, but don’t hold your breadth.

However, for your problem, I can’t think of any added value provided by C, that would match the additional development and maintenance costs it induces (you’re not realtime-bound, you don’t have resource issues, you don’t need to do anything close to the metal).


#6

yeah

Thanks for your advice.

I have never tried OpenAT Lua before but I will try it. It looks easyier than “c” OpenAT. I hope so!

Question:

local data = uart:read(nbytes..'*')  -- block to read `nbytes' bytes of data from uart in DATA mode
uart:close()                         -- switch UART back to AT mode and release it

-> I guess there is no DATA_Mode like the one escaped by “+++”?
(That does not really matter.)

Let’s try Lua. I keep you informed.

Thanks


#7

Ooops

Just one more question:

When using this

local data = uart:read(nbytes..'*')  -- block to read `nbytes' bytes of data from uart in DATA mode
uart:close()                         -- switch UART back to AT mode and release it

-> Is ‘nbytes’ limited ? (I mean: is the data stored in the modem’s memory or is it directly dispatched to the V24?)

Thanks again!


#8

The command “uart=wip.fcm(port)” switches the port to DATA mode, and it stays that way until “uart:close()” is called or “+++” is entered. If you want to read everything until the user types “+++”, replace the call to read_n_bytes_from_uart() by uart:read(“a"). (“a” is for “all”, and "” is for “block until reading is finished”).

Unfortunately there’s an other a pending bug (in the WIP/FCM library this time, not in Lua) that forbids a second wip.fcm() after the uart has been closed. It can be fixed either by waiting for next delivery of WIP, or with a C-based workaround (PM me for details if you need it and you’re in a hurry).

‘data’ is stored as a string in RAM, so that’s your limitation. You can also use A&D or flash objects API to store your data but the program will be slightly more complex. You can also flush data more regularly if you prefer:

at.commands['AT+TCPCONNECT='] = function (cmd, address, port)
   local uart = wip.fcm(cmd.port)
   local tcp = wip.tcp_client(address, port)
   while(true) do
      repeat
         local buf = uart:read() -- read whatever's available on uart
         tcp:write(buf)          -- flush it on tcp
      until buf==""              -- do it again until there's nothing left to read
      uart:wait("read")          -- wait for a "more data to read" signal on uart
   end
end

Yet another solution would be to separate TCP connection establishment and data emission: AT+TCPCONNECT=, opens connection, AT+TCPSEND= reads ans sends bytes of data then returns to AT mode without shutting donw the TCP connection; that way, AT+TCPSEND can be called several times. Finally, AT+TCPCLOSE shuts it down:

-- Warning: untested, no error handling.
TCP_SOCKET = nil

at.commands['AT+TCPCONNECT='] = function (cmd, address, port)
   TCP_SOCKET = wip.tcp_client (address, port)
   return "OK\r\n"
end

at.commands['AT+TCPSEND='] = function (cmd, nbytes)
   local data = read_n_bytes_from_uart (nbytes, cmd.port)
   TCP_SOCKET:write (data)
   return "OK\r\n"
end

at.commands['AT+TCPCLOSE'] = function(cmd)
   TCP_SOCKET:close()
   TCP_SOCKET = nil
   return "OK\r\n"
end

#9

Where have you hear this? Any more rumors you want to share? I’d love to have a direct interface to the UARTs! :smiley:


#10

Me too - or at least a proper way to send a BREAK signal: viewtopic.php?f=15&t=2226&p=8220&hilit=uart+break#p8220