Sign in to follow this  
Followers 0
Akshay07

Help needed with Martin's "Serial port (COM port) udf " to communicate with a modem

10 posts in this topic

#1 ·  Posted (edited)

Hi all,

First of all, I know that the title of this thread is not really describing a specific problem, but I have the feeling that I will have more than one question on Martin's UDF. I believe this should be the right place to ask question, but I am not 100% sure taking into account the number of questions that have been asked on the original thread.

Let me know it if is easier to keep on posting the questions in the "Example scripts" section.

I am trying to communicate with a modem. So far, with a minor change, I am able to do that. I am sending a "AT" string to the modem, and I would like to get the answer from the modem. But with what I have used so far, I only get a repetition of what I sent ($instr = "AT"). I used a MsBox to check that.

Here is the script (I am just testing it so far so I did not try to make it "clean".

Local $sportSetError

;$setport = StringReplace(GUICtrlRead($CmboPortsAvailable), 'COM', '')
$setport = "22"
;_CommSetPort($setport, $sportSetError, GUICtrlRead($CmBoBaud), GUICtrlRead($CmboDataBits), GUICtrlRead($CmBoParity), GUICtrlRead($CmBoStop), $setflow)
_CommSetPort($setport, $sportSetError, 115200, 8, 0, 1, 2)

if $sportSetError <> '' Then   ; if $sportSetError = '' then connection to COMPORT is established
    MsgBox(262144, 'Setport error = ', $sportSetError)  ; cannot connect to COMPORT
EndIf

Call ("_CommSendString", "AT")   ; sent AT command to the modem

While 1
        ;gets characters received returning when one of these conditions is met:
        ;receive @CR, received 20 characters or 200ms has elapsed
        $instr = _CommGetString()

    If $instr <> '' Then;if we got something
        MsgBox(0,"", $instr)
        ExitLoop
    EndIf

WEnd

Exit

Martin's example file shows:

While 1

    ;gets characters received returning when one of these conditions is met:
    ;receive @CR, received 20 characters or 200ms has elapsed
    $instr = _CommGetString()

    If $instr <> '' Then;if we got something

        If GUICtrlRead($Checkbox1) = $GUI_CHECKED Then $instr = StringReplace($instr,@CR,@CRLF)
        GUICtrlSetData($Edit1, $instr,1)

    EndIf

WEnd

I introduced a MsgBox in his example:

While 1

    ;gets characters received returning when one of these conditions is met:
    ;receive @CR, received 20 characters or 200ms has elapsed
    $instr = _CommGetString()

    If $instr <> '' Then;if we got something
        MsgBox( 0, "", $instr )
        If GUICtrlRead($Checkbox1) = $GUI_CHECKED Then $instr = StringReplace($instr,@CR,@CRLF)
        GUICtrlSetData($Edit1, $instr,1)

    EndIf

WEnd

And while running his example, I get two messages in the message box: the "AT" command and the answer. So these two data are available in $instr in Martin's example.

I can't figure out why I don't get the same in my script.

Any hint?

Thanks

Edited by Akshay07

Share this post


Link to post
Share on other sites



Hi,

Your example does ExitLoop as soon as a string has been received, BUT your modem has echo enabled. Moral: what your read is an echo to your own AT command string, no more no less, then you exit the read loop before getting the modem's actual answer.

Make yourself a favor: open HyperTerminal, the relevant COMx port and establish the communication.

Then play with your modem and its AT command set. Almost all modems share the same basic AT commands, with only little variants for esoteric or marginal functions. All this by heart, may be bugged:

ATe0 sets echo OFF

ATe1 sets echo ON

AT&v displays the overall configuration

ATz reset modem to default profile

ATx* set modem response style *

...

Lookup either the modem docs or generic AT commands, experiment what you really need to achieve your goal. Keep in mind that other applications may run outside yours and leave the modem in a different configuration than yours, so don't rely on what you discover now, force things into known state.

Basic Init string can be ATze0x4 and probably much more complex for specialized needs.

Once you know precisely how to dialog with your modem and which answers you can expect in various normal or error situations, only then write your code accordingly.

Hope this can help you.


This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Thanks for your answer.

The exit loop statement should not have been there, it's just something I tried. It should have been commented out.

I actually know about hyperterminal, ATE0, and ATE1, as well as some other AT commands. I also tried to send ATE0 first, then wait for 1 second, then send AT and use the "gets characters" loop, but then I get as the answer "ATE0AT", which is just a repetition of what I sent despite the echo set to OFF.

I was expecting a "OK" as an answer in the above script, just like in hyperterminal.

AT -> not visible in HyperTerm in case ATE0 was sent previously

OK -> always received

Here is what was tried:

_CommSetPort($setport, $sportSetError, 115200, 8, 0, 1, 2)

if $sportSetError <> '' Then   ; if $sportSetError = '' then connection to COMPORT is established
    MsgBox(262144, 'Setport error = ', $sportSetError)  ; cannot connect to COMPORT
EndIf

Call ("_CommSendString", "ATE0")   ; sent AT command to the modem
Sleep(1000)

Call ("_CommSendString", "AT")   ; sent AT command to the modem

While 1
        ;gets characters received returning when one of these conditions is met:
        ;receive @CR, received 20 characters or 200ms has elapsed
        $instr = _CommGetString()

    If $instr <> '' Then;if we got something
        MsgBox(0,"",$instr)
        ;ExitLoop
    EndIf

WEnd

Basically, I am simply trying to achieve this:

1/ Send AT and check that I receive "OK" (I know I might receive something else but I know what else I might receive so this part is not an issue)

2/ send AT+CGMI and get the answer to this command.

Edited by Akshay07

Share this post


Link to post
Share on other sites

Please don't believe I was being condescending by giving you advices you didn't really need. Many people have little experience with modems and serial ports in general nowadays.

I just looked at a program I've made to handle our shipping scale connected through a standard (not USB) serial port. Beside the ugly processing I need to do with the scale data (averaging, various tare compensations and the like) there are clear differences: I use a direct call to output my command string and I use CommGetLine with parameters to override defaults in the receive call. In fact, it is very simplistic!

It goes something like this:

#include "..\include\commMG.au3"

Global $done = False
HotKeySet("^!q", "Finish")

main()

Func Finish()
    $done = True
EndFunc

Func main()
    Local $old, $s, $st, $Com, $err, $poids, $valmin, $valmax, $memoire[8], $nbr = 0, $valeur, $mesure, $tare = 0

    If _CommSetPort(1, $err, 9600, 7, 1, 1, 0) <> 1 Then        ; COM1, 9600, 7, O, 1, hardware
        ConsoleWrite($err & @LF)
        Return
    EndIf
    While (Not $done)
        _CommSendString(@CR, 1)
        If @error Then ExitLoop
        $s = _CommGetLine(Chr(0x04), 18, 400)
        If StringLen($s) = 18 Then
            If StringMid($s, 9, 1) = 'l' Then
                ConsoleWrite('@@@ La balance est en mode "livre anglaise" et non "kilogramme" !' & @LF)
            EndIf
            $st = StringRegExp($s, "\A([ |-])([ 0-9]{2}\d)\.(\d{2}) k [g|G] \x0D\x0A\x04\z", 1)
            If @error = 0 Then
                $st = StringStripWS(_ArrayToString($st, "") & '0', 7)
                $valeur = Number($st)
                _ArrayPush($memoire, $valeur)
                $valmin = _ArrayMin($memoire)
                $valmax = _ArrayMax($memoire)
                $mesure = ($valmax + $valmin) / 2
                If Abs($valmax - $valmin) <= 20 Then
                    $poids = Abs($mesure - $tare)
                    Switch $nbr
                        Case 3
                            If $mesure = 0 Then
                                $tare = 0
                            Else
                                If $poids > 40 Then
                                    ConsoleWrite("*** Poids = " & $poids & " g")
                                    If $tare <> 0 Then
                                        ConsoleWrite(" (tare = " & $tare & " g)")
                                    EndIf
                                    ConsoleWrite(@LF)
                                EndIf
                            EndIf
                        Case 100, 200, 300, 400, 500, 600, 700, 800, 900
                            If Abs($valeur) <= 40 And $poids <= 40 And $valeur <> $tare Then
                                $tare = $valeur
                                ConsoleWrite("--- Tare = " & $tare & " g" & @LF)
                            EndIf
                        Case 1000
                            If $tare <> 0 Then
                                ConsoleWrite("Remettre la tare de la balance à zéro !" & Chr(0x09) & @LF)
                            EndIf
                            $nbr = 100
                    EndSwitch
                    $nbr += 1
                Else
                    $nbr = 0
                EndIf
                Sleep(50)
            Else
                ConsoleWrite('?')
                Sleep(60)
                _CommClearOutputBuffer()
                _CommClearInputBuffer()
            EndIf
        EndIf
    WEnd
    _CommClosePort()
EndFunc

I'm going to write a simple terminal app and use another PC here which has a modem on a serial port. I need to TS into it since it's in use currently (and escaladate privileges...). I keep you informed shortly. But there is no reason that it works in HyperTerminal and not with AutoIt and Martin's wrapper. Just an idea: when you succeeded in using Hyperterminal, what handshake protocol did you use? [Emulated] hardware should work, but who knows?


This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

Please don't believe I was being condescending by giving you advices you didn't really need. Many people have little experience with modems and serial ports in general nowadays.

No worries, I didn't take it in the wrong way, you could not guess that :huggles: And I am no expert in AT commands, I just know a little more than the average person, but that's it. I really appreciate that you're trying to help me.

Just an idea: when you succeeded in using Hyperterminal, what handshake protocol did you use? [Emulated] hardware should work, but who knows?

Well, Emulation is set to "autodetect". I don't know how to find more information about the handshake protocol. But if it helps, the USB modems I want to communicate with are all mobile phones.

I just tried to introduce _CommClearOutputBuffer after sending ATE0, and now, the output is only AT (instead of AT0AT previously)

_CommSetPort($setport, $sportSetError, 115200, 8, 0, 1, 2)

if $sportSetError <> '' Then   ; if $sportSetError = '' then connection to COMPORT is established
    MsgBox(262144, 'Setport error = ', $sportSetError)  ; cannot connect to COMPORT
EndIf

Call ("_CommSendString", "ATE0")   ; sent AT command to the modem
Sleep(1000)
Call ("_CommClearOutputBuffer")
Call ("_CommSendString", "AT")   ; sent AT command to the modem

While 1
        ;gets characters received returning when one of these conditions is met:
        ;receive @CR, received 20 characters or 200ms has elapsed
        $instr = _CommGetString()

    If $instr <> '' Then;if we got something
        MsgBox(0,"",$instr)
        ;ExitLoop
    EndIf

WEnd

Just out of curiosity, I also tried to introduce _CommClearOutputBuffer after sending AT, but the MsgBox still shows "AT".

Edit: I tried to use _CommGetLine after Call ("_CommSendString", "AT") but the answer is still "AT" :D

Edited by Akshay07

Share this post


Link to post
Share on other sites

I just tried to introduce _CommClearOutputBuffer after sending ATE0, and now, the output is only AT (instead of AT0AT previously)

Don't do that without reason. Once before closing to keep clean if plenty.

Got it! You don't send @CR after your command(s)

_CommSetPort($setport, $sportSetError, 115200, 8, 0, 1, 2)

if $sportSetError <> '' Then ; if $sportSetError = '' then connection to COMPORT is established
 MsgBox(262144, 'Setport error = ', $sportSetError) ; cannot connect to COMPORT
EndIf

Call ("_CommSendString", "ATE0" & @CR) ; sent AT command to the modem

While 1
;;********* add an input box to entr successive command lines here
;;********* append @CR to the command line and send it
 ;gets characters received returning when one of these conditions is met:
 ;receive @CR, received 20 characters or 200ms has elapsed
;; beware that many commands can generate a reply longer than 20 chars. E.g. AT&V
 $instr = _CommGetString()

 If $instr <> '' Then;if we got something
 MsgBox(0,"",$instr)
 ;ExitLoop
 EndIf

WEnd

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Thanks a LOT :D:huggles::

I do get the "OK" now, that is a huge step :D

There is still one thing I don't understand.

Here is the script now, modified according to your comments

_CommSetPort($setport, $sportSetError, 115200, 8, 0, 1, 2)

if $sportSetError <> '' Then   ; if $sportSetError = '' then connection to COMPORT is established
    MsgBox(262144, 'Setport error = ', $sportSetError)  ; cannot connect to COMPORT
EndIf

_CommSendString("ATE0"&@CR, 1)

Call ("_CommClearInputBuffer")
Call ("_CommClearOutputBuffer")

_CommSendString("AT"&@CR, 1)

While 1
        ;gets characters received returning when one of these conditions is met:
        ;receive @CR, received 20 characters or 200ms has elapsed
        ;$instr = _CommGetString()
        $instr = _CommGetLine(@CR,0,0)

    If $instr <> '' Then;if we got something
        MsgBox(0,"",$instr)
    EndIf

WEnd

I get two MsgBox's.

First one is empty, so it looks like it is still "echo-ing" the AT command sent, it simply does not show it.

Second one is showing the "OK" I wanted so much to get :) (I need to find out how to capture only the "OK" without the first empty line, but that should not be too complicated).

Any idea why I get this first empty MsgBox?

Edit: although I still don't understand why I get this empty MsgBox, I can get rid of it using this:

While 1
        ;gets characters received returning when one of these conditions is met:
        ;receive @CR, received 20 characters or 200ms has elapsed
        ;$instr = _CommGetString()
    $instr = _CommGetLine(@CR,0,0)

    If $instr <> '' Then;if we got something
        If $instr <> @CR Then
            MsgBox(0,"",$instr)
        EndIf
    EndIf

WEnd

post-54217-12647937843584_thumb.jpg

post-54217-12647939900278_thumb.jpg

Edited by Akshay07

Share this post


Link to post
Share on other sites

Please try this (not tested)

#include "commMG.au3"

HotKeySet("^!q", "Finish")      ; CTRL-ALT-Q to exit

Func Finish()
    _Commcloseport()
    Exit
EndFunc

Local $setport = 1      ;; adapt to the actual port number!
Local $sportSetError

If _CommSetPort($setport, $sportSetError, 115200, 8, 0, 1, 2) <> 1 Then
    ConsoleWrite($sportSetError & @LF)
    Return
EndIf

if $sportSetError <> '' Then ; if $sportSetError = '' then connection to COMPORT is established
    MsgBox(262144, 'Setport error = ', $sportSetError) ; cannot connect to COMPORT
EndIf

Local $command, $instr

While 1
    $command = InputBox("Toy modem example", "Enter the command you wish to send:")
    If @error = 1 Then Finish()     ; Click Cancel to exit (or hotkey)

    _CommSendString($command & @CR) ; sent command line to the modem (don't wait)
    Sleep(50)       ; don't rush, the modem need some time to proceed

    ; receive multi-line answer until time-out
    $instr = ''
    Do
        ; receive a line or time-out
        ; since many answers are multi-line we need to loop there until we don't receive anymore
        Do
            $instr &= _CommGetline(@cr, 32384, 250)
        Until @error = -2       ; timeout
    Until $instr <> ''      ; here we should really wait for the final status answer (OK or else)

    MsgBox(0, "Modem answer was:", $instr)
WEnd

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites

I had to change this

If _CommSetPort($setport, $sportSetError, 115200, 8, 0, 1, 2) <> 1 Then
    ConsoleWrite($sportSetError & @LF)
    Return
EndIf

Into

_CommSetPort($setport, $sportSetError, 115200, 8, 0, 1, 2)

Otherwise, it works like a charm!

I really really appreciate your help. Thank you very much!

Share this post


Link to post
Share on other sites

Quite possible there's a problem with nesting like this. Sorry, I didn' have the opportunity to try it before hitting "Add Reply".

You can test for error anyway, this way:

_CommSetPort($setport, $sportSetError, 115200, 8, 0, 1, 0)  ; <-- last parameter changed to 0 = hardware handshake is better
If @error Then ...

Glad to hear it helped you.

You may still have to tune the timeout or handle things differently in case of multi-line answer or dial that can take some time to receive, for instance. Apart from that, you get the idea.

Good luck!


This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0