 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
aobrien
Joined: 14 Feb 2008 Posts: 31
|
Posted: Sat Feb 16, 2008 8:55 am Post subject: Serial ( COM ) Port Console Script |
|
|
[UPDATE]
The code posted here uses the port.dll file that can be found on the web for free. The problem with port.dll is that it will only send one byte of data every 15.8ms (translates to 633 baud rate) regardless of the intended baud rate. This is a limitation of the port.dll file.
I am leaving this port.dll code here as a reference and because it works, however, I don't recommend using port.dll.
The recommended method to send/receive on the COM port is in the next post
[/UPDATE]
Well, at the risk of embarasing myself, here is a serial port console script that I pieced together using code that I found here on the forum.
I took me quite some time to put it together. So, I am placing it here so others can benefit.
The real power of this script is the ease with which it can be modified to send data instead of ASCII characters - something HyperTerminal (and other terminal emulators) can't do.
| Code: | ;=================== Serial_Port_Console.ahk ===========================
; 2/15/08
; Assembled, tested (on WinXP), and debugged by aobrien with help from
; other AHK forum members and threads.
;
; Instructions:
; 1) Copy port.dll from the link below and put into windows
; system32 directory
; http://www.the-starbearer.de/Praxis/ElektronikamPC/RS232/portdll.htm
;
; 2) Modify the COM port settings (under the User Variables heading)
; to your needs and save the file.
;
; 3) Launch this script to connect to the COM Port
;
; 4) CTRL-F1 to close the COM port and exit the receive loop
;
; Script Behavior/Notes:
; * The script is designed to use a text editor (Notepad) to place the
; received COM port characters.
; * When you attempt to type into the designated text editor the script
; will capture the character and send it out the COM port. This is
; accomplished with the Hotkey Assignments section.
; * Currently the script is written to only send/receive ASCII characters,
; however, it would be REALLY EASY to modify the script so that it
; will output/input data - something that HyperTerminal can't do.
; * When you first launch the script it will open Notepad and save it
; using the Console_Path variable and a predetermined file name.
;
; !!!The Notepad text file MUST be saved so that the words
; "COM1_Console_(timestamp).txt - Notepad" appear as the window
; title, because the script will want to change to the window with
; that name when it receives a character on the COM port.
;
;========================================================================
#SingleInstance Force
SetTitleMatchMode, 2
;========================================================================
;====== User Variables ==================================================
;========================================================================
COM_Port = COM1
COM_Baud = 115200
COM_Parity = N
COM_Data = 8
COM_Stop = 1
Console_Path = C:\aobrien\_AutoHotKey_Scripts\COM_Port
;========================================================================
;====== Script Variables ================================================
;========================================================================
COM_Settings = %COM_Port%:%COM_Baud%,%COM_Parity%,%COM_Data%,%COM_Stop%
Console_File_Name= %COM_Port%_Console.txt
Console_Title = %Console_File_Name% - Notepad
;========================================================================
;====== Notepad Console Check ===========================================
;========================================================================
;Check for console, if there isn't already one, then open it.
IfWinNotExist, %Console_Title%
{
Run, Notepad
WinWait, Untitled - Notepad
Send, !fa ;file save as
WinWait, Save As
Clipboard = %Console_Path%\%Console_File_Name%
Send, ^v{ENTER}
}
;========================================================================
;====== Hotkey Assignments - Used for Serial Port Transmit ==============
;========================================================================
;If the Console window is the focus then typing any character on the
; keyboard will cause the script to send the character out the COM port.
Hotkey, IfWinActive, %Console_Title%,
;Direct Key Presses for a-z
Loop, 26
HotKey, % "$" chr(96+A_Index), HotkeySub
;Direct Key Presses for 0-9
Loop, 10
HotKey, % "$" chr(47+A_Index), HotkeySub
;Direct Key Presses for Other Keys
HotKey, -, HotkeySub
HotKey, =, HotkeySub
HotKey, [, HotkeySub
HotKey, ], HotkeySub
HotKey, `;, HotkeySub
HotKey, `', HotkeySub
HotKey, `,, HotkeySub
HotKey, `., HotkeySub
HotKey, `/, HotkeySub
HotKey, `\, HotkeySub
Hotkey, Space, HotkeySub
Hotkey, ENTER, HotkeySub
Hotkey, BS, HotkeySub
;Shift Modified Character Key Presses for a-z.
Loop, 26
HotKey, % "$+" chr(96+A_Index), HotkeySub_Char_Shift
;Shift Modified Character Key Presses for 0-9
Loop, 10
HotKey, % "$+" chr(47+A_Index), HotkeySub_Other_Shift
;Shift Modified Character Key Presses for Other Keys
HotKey, +-, HotkeySub_Other_Shift
HotKey, +=, HotkeySub_Other_Shift
HotKey, +[, HotkeySub_Other_Shift
HotKey, +], HotkeySub_Other_Shift
HotKey, +`;, HotkeySub_Other_Shift
HotKey, +`', HotkeySub_Other_Shift
HotKey, +`,, HotkeySub_Other_Shift
HotKey, +`., HotkeySub_Other_Shift
HotKey, +`/, HotkeySub_Other_Shift
HotKey, +`\, HotkeySub_Other_Shift
;========================================================================
;====== Serial Port Receive =============================================
;========================================================================
;Quit_var is used to exit the COM port receive loop
Quit_var = 0
hModule := DllCall("LoadLibrary", "str", "Port.dll")
result := DllCall("Port.dll\OPENCOM", "str", COM_Settings)
if result = 0
{
MsgBox, AHK could not open %COM_Port%
return
}
MsgBox, AHK is now connected to %COM_Port%
SetFormat, integer, data
;COM port receive loop
data = 0
Loop
{
data := DllCall("Port.dll\READBYTE")
;This will send every byte that is received on
; the COM port to the Notepad Console
If data <> -1
{
Critical, On
WinWait, %Console_Title%,
IfWinNotActive, %Console_Title%, , WinActivate, %Console_Title%,
WinWaitActive, %Console_Title%,
;If you want to see the decimal data (as received by the serial port,
; then uncomment the line below.
;Send, ^{END}data=%data%{ENTER}
ASCII := chr(data)
Send, ^{END}%ASCII%
Critical, Off
}
if Quit_var = 1
Break
}
result := DllCall("c:\temp\Port.dll\CLOSECOM")
DllCall("FreeLibrary", "UInt", hModule)
MsgBox, AHK is now disconnected from %COM_Port%
return
;========================================================================
;====== Serial Port Transmit ============================================
;========================================================================
HotkeySub:
var := Asc(SubStr(A_ThisHotkey,0)) ;Get the key that was pressed and convert it to its ASCII code
If A_ThisHotkey = Space
var=32
If A_ThisHotkey = BS
var=8
If A_ThisHotkey = ENTER
{
var=10 ;New Line
d := DllCall("Port\SENDBYTE", "UInt", var)
var=13 ;Carriage Return
}
d := DllCall("Port\SENDBYTE", "UInt", var)
return
HotkeySub_Char_Shift:
var := SubStr(A_ThisHotkey,0) ;Get the key that was pressed.
StringUpper, var, var ;Convert it to uppercase
var := Asc(var) ;Get the ASCII equivalent
d := DllCall("Port\SENDBYTE", "UInt", var) ;Send it out the COM port
return
HotkeySub_Other_Shift:
var := SubStr(A_ThisHotkey,0) ; Get the key that was pressed.
;Convert it to the shift version
; StringUpper won't work on the following.
If var = 1
var = !
If var = 2
var = @
If var = 3
var = #
If var = 4
var = $
If var = 5
var = `%
If var = 6
var = ^
If var = 7
var = &
If var = 8
var = *
If var = 9
var = (
If var = 0
var = )
If var = -
var = _
If var = =
var = +
If var = [
var = {
If var = ]
var = }
If var = \
var = |
If var = `;
var = :
If var = `'
var = "
If var = `,
var = <
If var = `.
var = >
If var = `/
var = ?
var := Asc(var) ;Get the ASCII equivalent
d := DllCall("Port\SENDBYTE", "UInt", var) ;Send it out the COM port
return
;========================================================================
;====== Save & Reload and Minimize AHK Script ===========================
;========================================================================
^!w::
Send, ^s
Sleep, 200
Reload
Sleep, 1000
return
;========================================================================
;====== Exit Console Receive Loop =======================================
;========================================================================
^F1::
Quit_var = 1
return
|
[EDIT] I was trying to be slick by putting a timestamp on the notepad file name - without testing it. Doing this broke the script. The code shown above works as advertised. Sorry for any confusion this may have caused.[/EDIT] |
|
| Back to top |
|
 |
aobrien
Joined: 14 Feb 2008 Posts: 31
|
Posted: Fri Mar 28, 2008 7:41 pm Post subject: Correct method for sending/receiving data on the Serial Port |
|
|
The following code uses built in Microsoft Windows dll/functions. This is the method that I recommend for reading/writing the serial ports.
[EDIT] 4/2/08 - Made corrections to "Create the SetCommTimeouts Structure" section as suggested by Lexikos[/EDIT]
[EDIT] 5/22/08 - Made corrrection to Read_from_COM() subroutine. Removed redundant line from COM port receive loop. Thanks Ron1 for reporting the bug. [/EDIT]
[EDIT] 7/23/08 - Fixed the following problems:
1. Reading NULL (0x00). Previously, if NULL (0x00) data was received then everything following the NULL was omitted. As a result Read_from_COM() now returns DATA instead of ASCII. This is how the function should have been written from the beginning.
Example: Read_Data := Read_from_COM("0xFF") ;if the RX buffer contained 0x11, 0x22, 0x00, 0x33, 0x44 then Read_Data will contain 1122003344. The conversion to ASCII routine can be found in the "Serial Port Receive" section of the script.
2. Using COM Ports larger than 9. The script can now handle COM ports > 9. Thanks krisky68 for reporting and finding the fix for this bug. I was able to reproduce this bug when I changed the internal COM port on my laptop (Dell 620) from COM1 to COM11. The fix supplied by krisky68 allows my internal COM port to work at COM11. However, I often use the "Prolific USB-to-Serial Comm Port" adaptors and when I set it to COM11 then I get a failure at the "BuildCommDCB" dll call -- I have no clue how to fix this and I suspect that it is a limitation of the adaptor.
The procedure on how to change the COM# for your device can be found on the first post in the second page of this topic.[/EDIT]
| Code: | ;################### Serial_Port_Console_ReadFile.ahk ###################
; 3/27/08
; Assembled, tested (on WinXP), and debugged by aobrien with help from
; other AHK forum members (especially Lexikos) and threads.
;
; This script is based upon dll structures that are built into the
; Microsoft Windows environment. This script is ugly (not very readable),
; because, it was written for demonstration purposes and I didn't want
; to complicate things by using #Include files.
;
; The most useful subroutines are listed below. Take them and write your
; application around them.
; Initialize_COM(COM_Settings)
; Close_COM(COM_FileHandle)
; Read_from_COM("0xFF") -- Size of receive buffer. This returns ASCII
; representation of the received HEX data.
; Example: Read_Data := Read_from_COM("0xFF") ;if the RX buffer contained
; 0x11, 0x22, 0x00, 0x33, 0x44 then Read_Data will contain 1122003344
; Write_to_COM(Hex_Data) -- Comma delimited hex data. If I wanted to
; send "Hello World" I would do the following:
; ;ASCII DATA= H e l l o SP W o r l d
; Hex_Data = 0x48,0x65,0x6C,0x6C,0x6F,0x20,0x57,0x6F,0x72,0x6C,0x64
; Write_to_COM(Hex_Data)
;
; Instructions:
; 1) Modify the COM port settings (under the User Variables heading)
; to your needs and save the file.
;
; 2) Launch this script to connect to the COM Port.
;
; 3) CTRL-F1 to close the COM port and exit the receive loop.
;
; Script Behavior/Notes:
; * The script is designed to use a text editor (Notepad) to place the
; received COM port characters.
; * When you attempt to type into the designated text editor the script
; will capture the character and send it out the COM port. This is
; accomplished with the Hotkey Assignments section.
; * Currently the script is written to only send/receive ASCII characters,
; however, it would be REALLY EASY to modify the script so that it
; will output/input data - something that HyperTerminal can't do.
; * When you first launch the script it will open Notepad and save it
; using the Console_Path variable and a predetermined file name.
;
; !!!The Notepad text file MUST be saved so that the words
; "COM1_Console.txt - Notepad" appear as the window
; title, because the script will want to change to the window with
; that name when it receives a character on the COM port.
;
;########################################################################
MsgBox, Begin COM Test
#SingleInstance Force
SetTitleMatchMode, 2
;########################################################################
;###### User Variables ##################################################
;########################################################################
COM_Port = COM4
COM_Baud = 115200
COM_Parity = N
COM_Data = 8
COM_Stop = 1
Console_Path =
;########################################################################
;###### Script Variables ################################################
;########################################################################
COM_Settings = %COM_Port%:baud=%COM_Baud% parity=%COM_Parity% data=%COM_Data% stop=%COM_Stop% dtr=Off
Console_File_Name= %COM_Port%_Console.txt
Console_Title = %Console_File_Name% - Notepad
;########################################################################
;###### Notepad Console Check ###########################################
;########################################################################
;Check for console, if there isn't already one, then open it.
IfWinNotExist, %Console_Title%
{
Run, Notepad
WinWait, Untitled - Notepad
Send, !fa ;file save as
WinWait, Save As
Clipboard = %Console_Path%\%Console_File_Name%
Send, ^v{ENTER}
}
;########################################################################
;###### Hotkey Assignments - Used for Serial Port Transmit ##############
;########################################################################
;If the Console window is the focus then typing any character on the
; keyboard will cause the script to send the character out the COM port.
Hotkey, IfWinActive, %Console_Title%,
;###### Direct Key Presses for a-z ######
Loop, 26
HotKey, % "$" chr(96+A_Index), HotkeySub
;###### Direct Key Presses for 0-9 ######
Loop, 10
HotKey, % "$" chr(47+A_Index), HotkeySub
;###### Direct Key Presses for Other Keys ######
HotKey, -, HotkeySub
HotKey, =, HotkeySub
HotKey, [, HotkeySub
HotKey, ], HotkeySub
HotKey, `;, HotkeySub
HotKey, `', HotkeySub
HotKey, `,, HotkeySub
HotKey, `., HotkeySub
HotKey, `/, HotkeySub
HotKey, `\, HotkeySub
Hotkey, Space, HotkeySub
Hotkey, ENTER, HotkeySub
Hotkey, BS, HotkeySub
;###### Shift Modified Character Key Presses for a-z. ######
Loop, 26
HotKey, % "$+" chr(96+A_Index), HotkeySub_Char_Shift
;###### Shift Modified Character Key Presses for 0-9 ######
Loop, 10
HotKey, % "$+" chr(47+A_Index), HotkeySub_Other_Shift
;###### Shift Modified Character Key Presses for Other Keys ######
HotKey, +-, HotkeySub_Other_Shift
HotKey, +=, HotkeySub_Other_Shift
HotKey, +[, HotkeySub_Other_Shift
HotKey, +], HotkeySub_Other_Shift
HotKey, +`;, HotkeySub_Other_Shift
HotKey, +`', HotkeySub_Other_Shift
HotKey, +`,, HotkeySub_Other_Shift
HotKey, +`., HotkeySub_Other_Shift
HotKey, +`/, HotkeySub_Other_Shift
HotKey, +`\, HotkeySub_Other_Shift
;########################################################################
;###### Serial Port Receive #############################################
;########################################################################
;Quit_var is used to exit the COM port receive loop
; 0=Don't Exit; 1=Exit; CTRL-F1 to set to 1 and exit script.
Quit_var = 0
Initialize_COM(COM_Settings)
;COM port receive loop
Loop
{
Read_Data := Read_from_COM("0xFF")
;msgbox, Bytes_Received=%Bytes_Received% ;Global variable that is set by Read_from_COM()
;0xFF in the above line basically sets the size of the read buffer.
; Use StringLeft to collect only the data received by the COM port.
; Bytes_Received is a global variable that is set during the Read_from_COM() routine.
;StringLeft, Read_Data, Read_Data, Bytes_Received ;5/22/08 This line was moved to Read_from_COM() subroutine.
;Process the data, if there is any.
If (Bytes_Received > 0)
{
;msgbox, Read_Data=%Read_Data%
;Prevent interruption during execution of this loop.
Critical, On
;If care is taken, you can comment out these WinActive lines for performance gains.
IfWinNotActive, %Console_Title%, , WinActivate, %Console_Title%,
WinWaitActive, %Console_Title%,
;7/23/08 Modified this IF statement because Read_from_COM() now returns data instead of ASCII
;Set to 0 if you want to see the decimal data as received by the serial port.
IF (1)
{
;Begin Data to ASCII conversion
ASCII =
Read_Data_Num_Bytes := StrLen(Read_Data) / 2 ;Read_from_COM() returns 2 characters for each byte
Loop %Read_Data_Num_Bytes%
{
StringLeft, Byte, Read_Data, 2
StringTrimLeft, Read_Data, Read_Data, 2
Byte = 0x%Byte%
Byte := Byte + 0 ;Convert to Decimal
ASCII_Chr := Chr(Byte)
ASCII = %ASCII%%ASCII_Chr%
}
Send, ^{END}%ASCII%
;End Data to ASCII conversion
}
Else ;Send the data that was received by the COM port-ASCII format
Send, ^{END}%Read_Data%
Critical, Off
}
;CTRL-F1 sets Quit_var=1
if Quit_var = 1
Break
}
Close_COM(COM_FileHandle)
MsgBox, AHK is now disconnected from %COM_Port%
;ExitApp ;Exit Script
Return
;########################################################################
;###### Serial Port Transmit ############################################
;########################################################################
;###### Normal Key Presses ######
HotkeySub:
var := Asc(SubStr(A_ThisHotkey,0)) ;Get the key that was pressed and convert it to its ASCII code
If A_ThisHotkey = Space
var=0x20
If A_ThisHotkey = BS
var=0x08
If A_ThisHotkey = ENTER
var=0x0D,0x0A ;New Line, Carriage Return ; 7/23/08 Changed 0x0A,0x0D to 0x0D,0x0A
Write_to_COM(var) ;Send it out the COM port
return
;###### Shift Key Presses ######
HotkeySub_Char_Shift:
var := SubStr(A_ThisHotkey,0) ;Get the key that was pressed.
StringUpper, var, var ;Convert it to uppercase
var := Asc(var) ;Get the ASCII equivalent
Write_to_COM(var) ;Send it out the COM port
return
;###### Other Shift Key Presses ######
HotkeySub_Other_Shift:
var := SubStr(A_ThisHotkey,0) ; Get the key that was pressed.
;Convert it to the shift version
; StringUpper won't work on the following.
If var = 1
var = !
If var = 2
var = @
If var = 3
var = #
If var = 4
var = $
If var = 5
var = `%
If var = 6
var = ^
If var = 7
var = &
If var = 8
var = *
If var = 9
var = (
If var = 0
var = )
If var = -
var = _
If var = =
var = +
If var = [
var = {
If var = ]
var = }
If var = \
var = |
If var = `;
var = :
If var = `'
var = "
If var = `,
var = <
If var = `.
var = >
If var = `/
var = ?
var := Asc(var) ;Get the ASCII equivalent
Write_to_COM(var) ;Send it out the COM port
return
;########################################################################
;###### Initialize COM Subroutine #######################################
;########################################################################
Initialize_COM(COM_Settings)
{
Global COM_FileHandle
;###### Build COM DCB ######
;Creates the structure that contains the COM Port number, baud rate,...
VarSetCapacity(DCB, 28)
BCD_Result := DllCall("BuildCommDCB"
,"str" , COM_Settings ;lpDef
,"UInt", &DCB) ;lpDCB
If (BCD_Result <> 1)
{
MsgBox, There is a problem with Serial Port communication. `nFailed Dll BuildCommDCB, BCD_Result=%BCD_Result% `nThe Script Will Now Exit.
Exit
}
;###### Extract/Format the COM Port Number ######
;7/23/08 Thanks krisky68 for finding/solving the bug in which COM Ports greater than 9 didn't work.
StringSplit, COM_Port_Temp, COM_Settings, `:
COM_Port_Temp1_Len := StrLen(COM_Port_Temp1) ;For COM Ports > 9 \\.\ needs to prepended to the COM Port name.
If (COM_Port_Temp1_Len > 4) ;So the valid names are
COM_Port = \\.\%COM_Port_Temp1% ; ... COM8 COM9 \\.\COM10 \\.\COM11 \\.\COM12 and so on...
Else ;
COM_Port = %COM_Port_Temp1%
;MsgBox, COM_Port=%COM_Port%
;###### Create COM File ######
;Creates the COM Port File Handle
;StringLeft, COM_Port, COM_Settings, 4 ; 7/23/08 This line is replaced by the "Extract/Format the COM Port Number" section above.
COM_FileHandle := DllCall("CreateFile"
,"Str" , COM_Port ;File Name
,"UInt", 0xC0000000 ;Desired Access
,"UInt", 3 ;Safe Mode
,"UInt", 0 ;Security Attributes
,"UInt", 3 ;Creation Disposition
,"UInt", 0 ;Flags And Attributes
,"UInt", 0 ;Template File
,"Cdecl Int")
If (COM_FileHandle < 1)
{
MsgBox, There is a problem with Serial Port communication. `nFailed Dll CreateFile, COM_FileHandle=%COM_FileHandle% `nThe Script Will Now Exit.
Exit
}
;###### Set COM State ######
;Sets the COM Port number, baud rate,...
SCS_Result := DllCall("SetCommState"
,"UInt", COM_FileHandle ;File Handle
,"UInt", &DCB) ;Pointer to DCB structure
If (SCS_Result <> 1)
{
MsgBox, There is a problem with Serial Port communication. `nFailed Dll SetCommState, SCS_Result=%SCS_Result% `nThe Script Will Now Exit.
Close_COM(COM_FileHandle)
Exit
}
;###### Create the SetCommTimeouts Structure ######
ReadIntervalTimeout = 0xffffffff
ReadTotalTimeoutMultiplier = 0x00000000
ReadTotalTimeoutConstant = 0x00000000
WriteTotalTimeoutMultiplier= 0x00000000
WriteTotalTimeoutConstant = 0x00000000
VarSetCapacity(Data, 20, 0) ; 5 * sizeof(DWORD)
NumPut(ReadIntervalTimeout, Data, 0, "UInt")
NumPut(ReadTotalTimeoutMultiplier, Data, 4, "UInt")
NumPut(ReadTotalTimeoutConstant, Data, 8, "UInt")
NumPut(WriteTotalTimeoutMultiplier, Data, 12, "UInt")
NumPut(WriteTotalTimeoutConstant, Data, 16, "UInt")
;###### Set the COM Timeouts ######
SCT_result := DllCall("SetCommTimeouts"
,"UInt", COM_FileHandle ;File Handle
,"UInt", &Data) ;Pointer to the data structure
If (SCT_result <> 1)
{
MsgBox, There is a problem with Serial Port communication. `nFailed Dll SetCommState, SCT_result=%SCT_result% `nThe Script Will Now Exit.
Close_COM(COM_FileHandle)
Exit
}
Return %COM_FileHandle%
}
;########################################################################
;###### Close COM Subroutine ############################################
;########################################################################
Close_COM(COM_FileHandle)
{
;###### Close the COM File ######
CH_result := DllCall("CloseHandle", "UInt", COM_FileHandle)
If (CH_result <> 1)
MsgBox, Failed Dll CloseHandle CH_result=%CH_result%
Return
}
;########################################################################
;###### Write to COM Subroutines ########################################
;########################################################################
Write_to_COM(Message)
{
Global COM_FileHandle
Global COM_Port
SetFormat, Integer, DEC
;Parse the Message. Byte0 is the number of bytes in the array.
StringSplit, Byte, Message, `,
Data_Length := Byte0
;msgbox, Data_Length=%Data_Length% b1=%Byte1% b2=%Byte2% b3=%Byte3% b4=%Byte4%
;Set the Data buffer size, prefill with 0xFF.
VarSetCapacity(Data, Byte0, 0xFF)
;Write the Message into the Data buffer
i=1
Loop %Byte0%
{
NumPut(Byte%i%, Data, (i-1) , "UChar")
;msgbox, %i%
i++
}
;msgbox, Data string=%Data%
;###### Write the data to the COM Port ######
WF_Result := DllCall("WriteFile"
,"UInt" , COM_FileHandle ;File Handle
,"UInt" , &Data ;Pointer to string to send
,"UInt" , Data_Length ;Data Length
,"UInt*", Bytes_Sent ;Returns pointer to num bytes sent
,"Int" , "NULL")
If (WF_Result <> 1 or Bytes_Sent <> Data_Length)
MsgBox, Failed Dll WriteFile to %COM_Port%, result=%WF_Result% `nData Length=%Data_Length% `nBytes_Sent=%Bytes_Sent%
}
;########################################################################
;###### Read from COM Subroutines #######################################
;########################################################################
Read_from_COM(Num_Bytes)
{
Global COM_FileHandle
Global COM_Port
Global Bytes_Received
SetFormat, Integer, HEX
;Set the Data buffer size, prefill with 0x55 = ASCII character "U"
;VarSetCapacity won't assign anything less than 3 bytes. Meaning: If you
; tell it you want 1 or 2 byte size variable it will give you 3.
Data_Length := VarSetCapacity(Data, Num_Bytes, 0x55)
;msgbox, Data_Length=%Data_Length%
;###### Read the data from the COM Port ######
;msgbox, COM_FileHandle=%COM_FileHandle% `nNum_Bytes=%Num_Bytes%
Read_Result := DllCall("ReadFile"
,"UInt" , COM_FileHandle ; hFile
,"Str" , Data ; lpBuffer
,"Int" , Num_Bytes ; nNumberOfBytesToRead
,"UInt*", Bytes_Received ; lpNumberOfBytesReceived
,"Int" , 0) ; lpOverlapped
;MsgBox, Read_Result=%Read_Result% `nBR=%Bytes_Received% ,`nData=%Data%
If (Read_Result <> 1)
{
MsgBox, There is a problem with Serial Port communication. `nFailed Dll ReadFile on %COM_Port%, result=%Read_Result% - The Script Will Now Exit.
Close_COM(COM_FileHandle)
Exit
}
;;;;;;;; 7/23/08 This section is replaced by the code below ;;;;;;;;;;;;;
; SetFormat, Integer, DEC
;
; ;###### Format the received data ######
; ;Return only the bytes that were received.
; If (Bytes_Received = 0)
; Return ""
; Else
; ;StringTrimRight, Data, Data, %Bytes_Received% ;5/22/08 This line is essentially useless and could potentially show up as a bug.
; StringLeft, Data, Data, Bytes_Received ;5/22/08 This is what the above line should have been
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;###### Format the received data ######
;This loop is necessary because AHK doesn't handle NULL (0x00) characters very nicely.
;Quote from AHK documentation under DllCall:
; "Any binary zero stored in a variable by a function will hide all data to the right
; of the zero; that is, such data cannot be accessed or changed by most commands and
; functions. However, such data can be manipulated by the address and dereference operators
; (& and *), as well as DllCall itself."
i = 0
Data_HEX =
Loop %Bytes_Received%
{
;First byte into the Rx FIFO ends up at position 0
Data_HEX_Temp := NumGet(Data, i, "UChar") ;Convert to HEX byte-by-byte
StringTrimLeft, Data_HEX_Temp, Data_HEX_Temp, 2 ;Remove the 0x (added by the above line) from the front
;If there is only 1 character then add the leading "0'
Length := StrLen(Data_HEX_Temp)
If (Length =1)
Data_HEX_Temp = 0%Data_HEX_Temp%
i++
;Put it all together
Data_HEX := Data_HEX . Data_HEX_Temp
}
;MsgBox, Read_Result=%Read_Result% `nBR=%Bytes_Received% ,`nData_HEX=%Data_HEX%
SetFormat, Integer, DEC
Data := Data_HEX
Return Data
}
;########################################################################
;###### Exit Console Receive Loop #######################################
;########################################################################
^F1::
Quit_var = 1
return
|
Last edited by aobrien on Sat Jul 26, 2008 5:53 am; edited 3 times in total |
|
| Back to top |
|
 |
bradchuck
Joined: 01 Apr 2008 Posts: 3
|
Posted: Tue Apr 01, 2008 12:50 pm Post subject: Thanks |
|
|
Thanks! This was usefill to me.
I am making it into an include file and using it to replace the Port.dll file. I also found that port.dll it did not work correctly. Your method does. |
|
| Back to top |
|
 |
aobrien
Joined: 14 Feb 2008 Posts: 31
|
Posted: Wed Apr 02, 2008 5:33 pm Post subject: |
|
|
Hi bradchuck,
I'm glad that you are finding it useful.
FYI, I made a correction just now - the only changs are in the "Initialize COM Subroutine" section of the code. Just update your library with that section and you should be good to go.
aobrien |
|
| Back to top |
|
 |
Guest
|
Posted: Thu May 15, 2008 4:55 pm Post subject: Thank you for Serial (COM) Port Console Script |
|
|
Thank you for this very useful script. I marvel at the level of knowledge that it takes to create such a script.
Until now I have not been able to get any terminal program that I have evaluated to behave exactly as needed in my application. But, with the building blocks that you have provided, I have realized a proper configuration at last.
The result will be incorporated in a computer-based system that provides magnification services to individuals with low vision. The script controls the the parameters of the display through the display's serial port.
Again, my appreciation for this most helpful contribution.
Ron1 |
|
| Back to top |
|
 |
aobrien
Joined: 14 Feb 2008 Posts: 31
|
Posted: Sun May 18, 2008 7:36 am Post subject: |
|
|
Hi Ron1,
Thanks for the compliment . I'm glad that you have found it useful and are putting it to such a noble cause.
Well, necesity is the mother of invention. It's funny that I was only about 26.4ms away from not developing this WinDLL version.
For my application, I am using AHK to communicate with my companies ICs. I first started using Port.dll and after several days of development I was finally at the point of where I should have been able to communicate with the ICs, however, I kept getting NACK (Not Acknowlege). I probed the Serial Port Tx line on the oscilloscope and noticed that there was only one byte of data being transmitted every 15.8ms - I was sending 8 bytes (8*15.8ms=126.4ms). It turned out that if our ICs didn't get all 8 bytes of data in 100ms then they timed-out and sent NACK.
It took me about another 2 weeks to develop the WinDLL version. But to be honest, I couldn't have done it without the help of Lexikos.
If I do say so myself, I've done some pretty amazing things with AHK. In one case, I wrote a test automation script (in one week), which would have taken a team of software developers several months with conventional methods, saving my companies ass in the process... and they don't even know it.
I particularly enjoy automating Windows based test equipment. I automated a (Big Name) pattern generator (took me about a month) they have a team of people working more than 6 months now, trying to accomplish the same thing and they come to me for help.
This is the first time that I have made any contribution to an Open Source community and I'm honored for the opportunity.
aobrien. |
|
| Back to top |
|
 |
Guest
|
Posted: Fri Jun 20, 2008 10:20 am Post subject: |
|
|
nice
could this be used to send hex commands to a plasma? I gave up on a script ~ a year ago that used port.dll, maybe this is the answer? |
|
| Back to top |
|
 |
aobrien
Joined: 14 Feb 2008 Posts: 31
|
Posted: Wed Jun 25, 2008 7:48 am Post subject: |
|
|
Yes, I use it to send binary data at 115200 baud rate every day. The instructions (at the top of the script) are pretty clear, I hope. Please let me know if it needs clarification.
Note-to-all: I have recently found a bug on receiving 0x00 (NULL) - it is a pretty nasty bug. I haven't had the time to post the fix yet. Just beware and if you need the fix urgently, then let me know and I'll do my best to put it up sooner. |
|
| Back to top |
|
 |
evandevon
Joined: 22 Apr 2008 Posts: 18
|
Posted: Sun Jun 29, 2008 7:18 pm Post subject: HELP PLEASE |
|
|
Please see
http://www.autohotkey.com/forum/viewtopic.php?p=204820#204820
for my post.
Can't seem to get your second script to work (first works fine) I think it may be because the first data value is null?
Thanks for these awesome scripts aobrien
Evs _________________ Inventing problems that need solutions... |
|
| Back to top |
|
 |
Raccoon
Joined: 02 Jan 2008 Posts: 70 Location: Freenode IRC
|
Posted: Sun Jul 13, 2008 4:46 pm Post subject: |
|
|
I slashed out over a hundred lines of code by removing all your hotkeys and using a Timer plus Input instead.
| Code: | ;########################################################################
;###### Serial Port Transmit ############################################
;########################################################################
GetUserInput:
{
WinGetActiveTitle, Active_Title
if (Active_Title != Console_Title)
Return
Input, var, IVL1T1, {Space}{Backspace}{Enter}{Escape}
if ErrorLevel = Timeout
Return
if (var := Asc(var))
Write_to_COM(var)
if ErrorLevel = EndKey:Space
Write_to_COM(0x20)
if ErrorLevel = EndKey:Backspace
Write_to_COM(0x08)
if ErrorLevel = EndKey:Enter
Write_to_COM(0x0D)
if ErrorLevel = EndKey:Escape
{
Quit_var = 1
SetTimer, GetUserInput, Off
}
} Return |
and put this line somewhere above the Serial Port Receive loop, and after Notepad has been initialized.
| Code: | | SetTimer, GetUserInput, 50 |
Note that for my purposes, I changed the value of Enter to 0x0D. Yours was 0x0A0D (which is pretty non-standard, I think you meant 0x0D0A, bug?). In any event, you should probably change this to a User Variable at the top section of the script.
| Code: | COM_Data = 8
COM_Stop = 1
COM_Return = 0x0D0A
Console_Path = |
Thank you so very much for this code. I've been trying to port it from SerialTerm with no clue how to bottle the functions for Read/Write. Hope my contribution appears in your next update!
PS. A side effect of this code is the Read Loop will pause for 1 second intervals while capturing input, causing any output from the COM Port to stutter. This wont be a problem with most uses that are usually "turn-based" communication, but it could be an issue for asynchronous data transmissions such as "chat". I think the trade-off is worth it, personally. There may be a similarly better solution as-well. _________________ Need help right away? Get live support on IRC.
Already have an IRC client installed? /join #autohotkey |
|
| Back to top |
|
 |
Raccoon
Joined: 02 Jan 2008 Posts: 70 Location: Freenode IRC
|
Posted: Sun Jul 13, 2008 5:07 pm Post subject: |
|
|
Oh, and you should also change this:
| Code: | ;Send the data that was received by the COM port-ASCII format
Send, ^{END}%Read_Data% |
to
| Code: | ;Send the data that was received by the COM port-ASCII format
Send, ^{END}
SendRaw, %Read_Data% |
I noticed that any output that contained "^V" was pasting the contents of my clipboard in its place. _________________ Need help right away? Get live support on IRC.
Already have an IRC client installed? /join #autohotkey |
|
| Back to top |
|
 |
krisky68 Guest
|
Posted: Sat Jul 19, 2008 10:23 am Post subject: Does this work for all com port numbers? |
|
|
Hi, trying to use this to talk to a modem on COM17. I noticed that the code assumes that the com port number is single digit (ie. four chars for the handle):
| Code: | ;Creates the COM Port File Handle
StringLeft, COM_Port, COM_Settings, 4 |
But even after I changed this, the script fails when attempting to create the file handle. Nothing else is connected to the port. Is there some limitation I don't know about? |
|
| Back to top |
|
 |
Raccoon
Joined: 02 Jan 2008 Posts: 70 Location: Freenode IRC
|
Posted: Sun Jul 20, 2008 10:15 pm Post subject: |
|
|
Assuming you changed StringLeft value to 5 making %COM_Port% == COM17, it should be right, but then again it may be bumping the predicted string length in some other portion of the script. I agree, this is poor coding.
Before going any further with AHK, I would suggest trying to connect using the command line tool called SerialTerm (you can find a link on these forums) or download the newest Putty and connect through it.
Once you've established a connection, having all your other variables in order (baud, parity, etc), then try again with AHK. Of course, make sure these are closed first (only one may connect at a time). _________________ Need help right away? Get live support on IRC.
Already have an IRC client installed? /join #autohotkey |
|
| Back to top |
|
 |
krisky68 Guest
|
Posted: Mon Jul 21, 2008 7:21 am Post subject: |
|
|
OK thanks, will try. Actually all I want for the time being is to send AT commands to the modem to dial phone numbers from the clipboard, I am already doing it via ahk and a hidden hyperterminal window, so I know the settings are fine. (and yes, I did make sure HT wasn't running when i tried the script ) But the HT approach becomes cumbersome if I ever want to read from the modem (eg. to get the ID of incoming calls). |
|
| Back to top |
|
 |
aobrien
Joined: 14 Feb 2008 Posts: 31
|
Posted: Tue Jul 22, 2008 7:50 am Post subject: |
|
|
Hi Raccoon,
Yes, I agree that it isn't the best coding in the world. I'm actually not happy with the whole flow of the script, but I wanted an easy way to demonstrate the script and I didn't know how to do it any other way.
Your way is much better. Thanks for the suggestions. I'll put them in soon.
Krisky, I'll also look into the single digit console problem, but when I test this script I actually test it in loop back mode -- 2 com ports on the same pc running 2 different copies of the same script. So I don't have any problem using different com port numbers.
I'll try to get the changes in by the end of the week.
aobrien |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|