Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Serial ( COM ) Port Console Script


  • Please log in to reply
136 replies to this topic
aobrien
  • Members
  • 77 posts
  • Last active: Mar 06 2014 04:42 AM
  • Joined: 14 Feb 2008
Krisky,

I have reproduced your problem (script doesn't work with COM Port > 9). The section of the code that is causing the error is shown below.


;######################################################################## 
;###### 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"   ;<--- Problem
       ,"str" , COM_Settings ;lpDef      ;<---   is 
       ,"UInt", &DCB)        ;lpDCB      ;<---  here
  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 
  } 

The DllCall("BuildCommDCB"... is not happy with that extra character.

I don't believe that there is any way to fix this problem. However, there may be a work around. I am able to change the COM port number for my devices with the following procedure:
1. Right click "My Computer" -> select "Properties"
2. Click the "Hardware" tab
3. Click "Device Manager"
4. Expand "Ports (COM & LPT)"
5. Double click your device that has COM Port > 9.
6. Click the "Port Settings" tab
7. Click the "Advanced" button
8. Choose a different port number from the "COM Port Number" drop down menu. Just ignore all of the other settings (bits per second, parity, ...) they don't effect anything.
9. Click, OK, OK to finalize your new setting.

I'm using WinXP, but there should be something similar for Vista as well.

This should suffice for 98% of the population, which sucks because I'm probably one the 2% that will need more than 9 COM ports. :(

If anyone has any suggestions on how to fix this bug, I'm all ears.

aobrien

krisky68
  • Guests
  • Last active:
  • Joined: --
It relates to COM port numbers over 9, from the MS website CreateFile help:

To specify a COM port number greater than 9, use the following syntax: "\\.\COM10". This syntax works for all port numbers and hardware that allows COM port numbers to be specified.


So for the CreateFile dll call, need to prepend the COM_Port var with "\\.\" if more than 4 chars. I tried it by just placing the string into the function, seems to work.

:)

krisky68
  • Guests
  • Last active:
  • Joined: --
I didn't see your last reply before I posted mine. I'm running XP, but the problem I was getting related to CreateFile, not the DBC

COM_Port 	= COM17
COM_Baud     = 115200
COM_Parity   = N
COM_Data     = 8
COM_Stop     = 1
Console_Path =

And

COM_FileHandle := DllCall("CreateFile"
       ,"Str" , "\\.\COM17"     ;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")

I haven't changed anything else, and it seems to work...

aobrien
  • Members
  • 77 posts
  • Last active: Mar 06 2014 04:42 AM
  • Joined: 14 Feb 2008
Krisky68, thanks for finding/fixing that bug! It is likely to not have been resolved otherwise.

I also put the fix in for the NULL (0x00) data.

Everyone (receiving email notifications) should update their functions to include these two important fixes. See the notes dated 7/23/08 on the second post for more information.

  • Guests
  • Last active:
  • Joined: --
How can the script be modified to send data instead of ASCII characters?

aobrien
  • Members
  • 77 posts
  • Last active: Mar 06 2014 04:42 AM
  • Joined: 14 Feb 2008
The script, by default, sends and receives only data. Look at the second post... in the header of the code you will find this following...

; 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)

The Write_to_COM() and Read_from_COM() functions, by default, send/receive only data. What you want to do with the data is up to you.

The rest of the script was set up to send/receive ascii into a standard Notepad just for illustration purposes.

Simply copy the functions listed above and start writing your script around them.

  • Guests
  • Last active:
  • Joined: --
I need to send this:
-without the (begin) & (end) of course

(begin)
%

O8()

%
(end)

If could someone could show me how, I should be able to manage from here.
(thanks in advance)

twhyman
  • Members
  • 348 posts
  • Last active: Sep 17 2014 01:55 AM
  • Joined: 07 Dec 2005
Hi,

Can someone upload the dll because the developer site is gone :roll:

Thanks
Twhyman
(\__/) This is Bunny.
(='.'=) Cut, copy, and paste bunny onto your sig.
(")_(") Help Bunny gain World Domination.

Rabiator
  • Members
  • 292 posts
  • Last active: Aug 29 2016 09:29 PM
  • Joined: 17 Apr 2005
http://www.elektroni...de/Port_dll.zip

twhyman
  • Members
  • 348 posts
  • Last active: Sep 17 2014 01:55 AM
  • Joined: 07 Dec 2005

http://www.elektroni...de/Port_dll.zip


Thank you :D
(\__/) This is Bunny.
(='.'=) Cut, copy, and paste bunny onto your sig.
(")_(") Help Bunny gain World Domination.

aobrien
  • Members
  • 77 posts
  • Last active: Mar 06 2014 04:42 AM
  • Joined: 14 Feb 2008
Guest,

Here is the code that will perform what you are asking. I don't have ability to test this at home, but it should work (famous last words).

0. Install ahk on your pc.
1. copy the entire code below and paste it into a text file
2. save it as .ahk
3. double click the file name
4. press the F4 key to send the characters on the serial port.

This is a good ASCII table that will tell you how to translate the ASCII characters to Decimal or Hex code which is what the script needs.
http://www.asciitable.com/

There are 2 different codes that can be used to send a {RETURN} 0x0A (New Line) and 0x0D (Carriage Return). Some text editors use one or the other or both. I'm not sure what your application requires so it might not be correct.

Good luck.


F4::

MsgBox, Begin COM Test

;########################################################################
;###### User Variables (Change these to match you needs) ################
;########################################################################
COM_Port     = COM4
COM_Baud     = 115200
COM_Parity   = N
COM_Data     = 8
COM_Stop     = 1

;########################################################################
;###### Script Variables (Don't touch these) ############################
;########################################################################
COM_Settings = %COM_Port%:baud=%COM_Baud% parity=%COM_Parity% data=%COM_Data% stop=%COM_Stop% dtr=Off

;########################################################################
;###### Main Routine ####################################################
;########################################################################
Initialize_COM(COM_Settings) 

;NL = New Line
;            %   NL   NL    O    8    (    )   NL   NL    %
Message = 0x25,0x0A,0x0A,0x4F,0x38,0x28,0x29,0x0A,0x0A,0x25
Write_to_COM(Message)


Close_COM(COM_FileHandle) 
Return


;########################################################################
;###### Subroutines (You don't really need to look below this line) #####
;########################################################################

;########################################################################
;###### Initialize COM Subroutine (Don't touch this routine) ############
;########################################################################
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 (Don't touch this routine) #################
;########################################################################
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 (Don't touch this routine) #############
;########################################################################
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 (Don't touch this routine) ############
;########################################################################
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
  }

  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

}




Max_Foster
  • Guests
  • Last active:
  • Joined: --
I'm wondering if this script can be used for my needs, but unfortunatelly my AHK skills are still very basic...
So, this is the thing: I'm using this program (SuperLab) to perform some experiments on visual perception. So far, I've been using AHK to send the mouse cursor to the center of the screen after any mouse click (so to allow the mouse cursor to appear always at that position at the beginning of each trial). But for some stimuli I would need the mouse cursor to be send for specific coordinates on the screen. Since the stimuli appear in a random order, the only way I could manage this would be to have SuperLab sending an instruction to AHK to perform that positioning of the mouse cursor. Luckily, SuperLab has the option to send a Serial Output (Including sending a String or ASCII values). Also, and since both programs would be run in the same machine, I can use a virtual serial port.
My question is simply out to "translate" a given serial output from SuperLab into an action within the AHK script (specifically, move the mouse cursor to x,y)? Would this script allow me to do that?
I can antecipate that I would have to do something around this logic: IF serial output = X THEN [instruction for mouse cursor]. But I can't figure out where and how in the script I can do such...
Thanks in advance.

aobrien
  • Members
  • 77 posts
  • Last active: Mar 06 2014 04:42 AM
  • Joined: 14 Feb 2008
Hi Max,

The following script probably won't work straight out of the box, but is a good start.

Read and understand the script until you get to the subroutines (don't go any further than that) then begin testing.

Good luck!

[EDIT]Updated code snip[\EDIT]


F6::  ;Push F6 key to start script

;########################################################################
;###### User Variables ##################################################
;########################################################################
;COM Port Settings
COM_Port     = COM9
COM_Baud     = 115200
COM_Parity   = N
COM_Data     = 8
COM_Stop     = 1

;########################################################################
;###### Script Variables ################################################
;########################################################################
COM_Settings = %COM_Port%:baud=%COM_Baud% parity=%COM_Parity% data=%COM_Data% stop=%COM_Stop% dtr=Off



;########################################################################
;###### Main Routine ################################################
;########################################################################

;READ THIS!!! -- This script assums that:
;   the first byte of data received on the serial port is the X coordinate and
;   the second byte of data received on the serial port is the Y coordinate.
;Have your Superlab send 2 bytes of data over the serial port and you should see the mouse move.
;Use the MsgBox lines to help you debug. Remove the MsgBoxes when the script is working.


COM_FileHandle := Initialize_COM(COM_Settings) ;Initialize the COM port with the above settings
Data =
Loop   ;This is an infinite loop. To stop the script you will have to right click on the Green "H" icon and reload or exit.
{
    New_Data := Read_from_COM("0xFF") ;Get some data from the serial port - store it in New_Data - each byte of data will be represented by 2 characters which will make one hex byte
    New_Data_Length := StrLen(New_Data) ;Find out how many characters are in New_Data
    If (New_Data_Length > 1)
    {
        Data := Data + New_Data
        MsgBox, Data = %Data%      New_Data %New_Data% ;pop-up a message box to show what your data strings.
    }

    Data_Length := StrLen(New_Data)
    If (Data_Length > 3)
    {
        StringLeft, X, Data, 2  ;get the first hex byte - 2 characters
        StringTrimLeft, Data, Data, 2  ;remove the first hex byte from "Data" the second byte is now the shifted into the first byte position

        StringLeft, Y, Data, 2  ;get the Y hex byte
        StringTrimLeft, Data, Data, 2 ;remove it from the string.

;MouseMove will require a decimal number. You will need to have some sort of routine to convert the Hex X and Y values Decimal. I will leave this to you :)

        MouseMove, %X%, %Y%  ; move the mouse
        MsgBox, X = %X%    Y = %Y% ;pop-up a message box showing what your retrieved X,Y data is.
       
    }
}

;########################################################################
;###### Subroutines (You don't really need to look below this line) #####
;########################################################################

;######################################################################## 
;###### 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 

}




Max Foster
  • Guests
  • Last active:
  • Joined: --
Hi aobrien!
First of all, thank you very much for the prompt reply along with the script.
However, I can't run the code. Everytime I try to it gives me an error message on a nonexistent function, namely Close_COM(COM_FileHandle). Moreover, it reports the error to be happening at the line 122.
Since this location is well below your comment "Don't touch this", I thought it would be better to ask you about this...
In the meanwhile, I've been looking through the rest of the code, and I'm pretty confident that it would work properly for my purposes. :)
Anyway, if you can give me a tip on this error, I would appreciate.
Thanks again!

A_Guest
  • Guests
  • Last active:
  • Joined: --
hi

thanks for sharing this!

i got my plasma connected to my pc and use a software to switch it on/off. The software i use is kinda bloated/slow and i would like to try this script. Im a novis coder so i dont understand it fully. I want to send this:

"COM Settings","9600","O","8","1"
"C","Power On","9F 80 60 4E 00 CD","5"
"C","Power Off","9F 80 60 4F 00 CE","5"

*the 5 is some kind of delay i think 5ms ..?

Would it work to insert this data to your User Variables/Message section? If not could oyu please give me some help..?