''''''''''''''''''''''''''''''''''''''''''''''''''''' ' UBW_Play.bas ' ' Written by Brian Schmalz ' as part of the UBW Project ' http://www.greta.dhs.org/UBW ' Free for all to use and improve ' 4/06/06 ' ' DESCRIPTION: ' As an application, this Liberty Basic program allows ' the user to play with the 19 digial I/O pins on their ' UBW board with Firmware D on it. Firmware D allows ' for each I/O pin to be read, written to, and set ' as either an input or an output. The UBW Play ' application allows the user to read the status ' of each I/O pin (the green LEDs), change the pin to ' and input or an output (In/Out button) and if the ' pin is an output, set it high or low (Off/On button). ' ' As Liberty Basic source code, this code shows a ' developer how to use some simple interfaces to a ' chunk of utility code that can talk to a UBW FW D. ' There are functions for setting I/O bits state, ' reading their states, setting direction, etc. This ' UBW Utility Code also supports easy detection of ' the presense of a UBW board using an automatically ' updated COM port pull down list. There is no ' 'connect' button on this application because the ' code can find a UBW board on whichever COM port ' is currently selected in the pulldown list. ' ' 'NOMAINWIN ' Take care of some constants so that our code is more readable Global TRUE TRUE = 1 Global FALSE FALSE = 0 Global MAXCOMPORTS ' How many com ports can we hold in our drop down list? MAXCOMPORTS = 10 Global HIGHESTCOMPORT ' Highest numerical com port to check for HIGHESTCOMPORT = 20 Global TICKRATE ' In ms how often do we do call the tick timer routine TICKRATE = 10 Global GETCOMPORTRATE ' How many ticks between checking for new COM ports GETCOMPORTRATE = 100 ' Call out global variables GLOBAL PortA ' Port bytes store the values we write for output bytes PortA = 0 GLOBAL PortB PortB = 0 GLOBAL PortC PortC = 0 GLOBAL DirA ' Dir bytes hold the direction bits for each port pin DirA = 255 GLOBAL DirB DirB = 255 GLOBAL DirC DirC = 255 GLOBAL StatusA ' Status bytes hold the current value read in on the pins StatusA = 0 GLOBAL StatusB StatusB = 0 GLOBAL StatusC StatusC = 0 Global OpenedCOMPort$ ' Holds the name of the com port we currently have opened, if any OpenedCOMPort$ = "" ' Dim all of the arrays DIM COMPort$(MAXCOMPORTS) ' Holds strings for COM port numbers (COM1, COM2, etc.) DIM NewCOMPort$(MAXCOMPORTS) ' Holds strings for COM port numbers (COM1, COM2, etc.) inside GetCOMPort routine 'Form created with the help of Freeform 3 v03-27-03 'Generated on Apr 08, 2006 at 00:06:51 [setup.main.Window] '-----Begin code for #main WindowWidth = 550 WindowHeight = 780 UpperLeftX=int((DisplayWidth-WindowWidth)/2) UpperLeftY=int((DisplayHeight-WindowHeight)/2) '-----Begin GUI objects code bmpbutton #main.bmpbutton1, ".\28DIPv5Basic.bmp", [bmpbutton1Click], UL, 185, 32 statictext #main.statictext2, "B7", 365, 102, 16, 20 statictext #main.statictext3, "B6", 365, 122, 16, 20 statictext #main.statictext4, "B5", 365, 142, 16, 20 statictext #main.statictext5, "B4", 365, 162, 16, 20 statictext #main.statictext6, "B3", 365, 182, 16, 20 statictext #main.statictext7, "B2", 365, 202, 16, 20 statictext #main.statictext8, "B1", 365, 222, 16, 20 statictext #main.statictext9, "B0", 365, 242, 16, 20 statictext #main.statictext10, "+5", 365, 267, 16, 20 statictext #main.statictext11, "GND", 365, 287, 35, 20 statictext #main.statictext12, "C7", 365, 307, 16, 20 statictext #main.statictext13, "C6", 365, 327, 16, 20 statictext #main.statictext14, "MCLR", 140, 97, 45, 20 statictext #main.statictext15, "A0", 160, 117, 16, 20 statictext #main.statictext16, "A1", 160, 137, 16, 20 statictext #main.statictext17, "A2", 160, 157, 16, 20 statictext #main.statictext18, "A3", 160, 177, 16, 20 statictext #main.statictext19, "A4", 160, 197, 16, 20 statictext #main.statictext20, "A5", 160, 217, 16, 20 statictext #main.statictext21, "C0", 160, 307, 16, 20 statictext #main.statictext22, "C1", 160, 327, 16, 20 statictext #main.statictext23, "C2", 160, 347, 16, 20 statictext #main.statictext24, "Reset", 135, 57, 45, 20 statictext #main.statictext25, "Program", 120, 507, 55, 20 bmpbutton #main.bmpbuttonB7Status, ".\LEDOff.bmp", [bmpbuttonB7StatusClick], UL, 395, 102 bmpbutton #main.bmpbuttonB6Status, ".\LEDOff.bmp", [bmpbuttonB6StatusClick], UL, 395, 122 bmpbutton #main.bmpbuttonB5Status, ".\LEDOff.bmp", [bmpbuttonB5StatusClick], UL, 395, 142 bmpbutton #main.bmpbuttonB4Status, ".\LEDOff.bmp", [bmpbuttonB4StatusClick], UL, 395, 162 bmpbutton #main.bmpbuttonB3Status, ".\LEDOff.bmp", [bmpbuttonB3StatusClick], UL, 395, 182 bmpbutton #main.bmpbuttonB2Status, ".\LEDOff.bmp", [bmpbuttonB2StatusClick], UL, 395, 202 bmpbutton #main.bmpbuttonB1Status, ".\LEDOff.bmp", [bmpbuttonB1StatusClick], UL, 395, 222 bmpbutton #main.bmpbuttonB0Status, ".\LEDOff.bmp", [bmpbuttonB0StatusClick], UL, 395, 242 bmpbutton #main.bmpbuttonC7Status, ".\LEDOff.bmp", [bmpbuttonC7StatusClick], UL, 395, 307 bmpbutton #main.bmpbuttonC6Status, ".\LEDOff.bmp", [bmpbuttonC6StatusClick], UL, 395, 327 bmpbutton #main.bmpbuttonA0Status, ".\LEDOff.bmp", [bmpbuttonA0StatusClick], UL, 135, 115 bmpbutton #main.bmpbuttonA1Status, ".\LEDOff.bmp", [bmpbuttonA1StatusClick], UL, 135, 135 bmpbutton #main.bmpbuttonA2Status, ".\LEDOff.bmp", [bmpbuttonA2StatusClick], UL, 135, 155 bmpbutton #main.bmpbuttonA3Status, ".\LEDOff.bmp", [bmpbuttonA3StatusClick], UL, 135, 175 bmpbutton #main.bmpbuttonA4Status, ".\LEDOff.bmp", [bmpbuttonA4StatusClick], UL, 135, 195 bmpbutton #main.bmpbuttonA5Status, ".\LEDOff.bmp", [bmpbuttonA5StatusClick], UL, 135, 215 bmpbutton #main.bmpbuttonC0Status, ".\LEDOff.bmp", [bmpbuttonC0StatusClick], UL, 135, 305 bmpbutton #main.bmpbuttonC1Status, ".\LEDOff.bmp", [bmpbuttonC1StatusClick], UL, 135, 325 bmpbutton #main.bmpbuttonC2Status, ".\LEDOff.bmp", [bmpbuttonC2StatusClick], UL, 135, 345 button #main.buttonA0Dir,"In",DirClick, UL, 85, 112, 35, 20 button #main.buttonA1Dir,"In",DirClick, UL, 85, 132, 35, 20 button #main.buttonA2Dir,"In",DirClick, UL, 85, 152, 35, 20 button #main.buttonA3Dir,"In",DirClick, UL, 85, 172, 35, 20 button #main.buttonA4Dir,"In",DirClick, UL, 85, 192, 35, 20 button #main.buttonA5Dir,"In",DirClick, UL, 85, 212, 35, 20 button #main.buttonC0Dir,"In",DirClick, UL, 85, 302, 35, 20 button #main.buttonC1Dir,"In",DirClick, UL, 85, 322, 35, 20 button #main.buttonC2Dir,"In",DirClick, UL, 85, 342, 35, 20 button #main.buttonB7Dir,"In",DirClick, UL, 425, 100, 35, 20 button #main.buttonB6Dir,"In",DirClick, UL, 425, 120, 35, 20 button #main.buttonB5Dir,"In",DirClick, UL, 425, 140, 35, 20 button #main.buttonB4Dir,"In",DirClick, UL, 425, 160, 35, 20 button #main.buttonB3Dir,"In",DirClick, UL, 425, 180, 35, 20 button #main.buttonB2Dir,"In",DirClick, UL, 425, 200, 35, 20 button #main.buttonB1Dir,"In",DirClick, UL, 425, 220, 35, 20 button #main.buttonB0Dir,"In",DirClick, UL, 425, 240, 35, 20 button #main.buttonC7Dir,"In",DirClick, UL, 425, 305, 35, 20 button #main.buttonC6Dir,"In",DirClick, UL, 425, 325, 35, 20 button #main.buttonA0Port,"Off",PortClick, UL, 45, 112, 30, 20 button #main.buttonA1Port,"Off",PortClick, UL, 45, 132, 30, 20 button #main.buttonA2Port,"Off",PortClick, UL, 45, 152, 30, 20 button #main.buttonA3Port,"Off",PortClick, UL, 45, 172, 30, 20 button #main.buttonA4Port,"Off",PortClick, UL, 45, 192, 30, 20 button #main.buttonA5Port,"Off",PortClick, UL, 45, 212, 30, 20 button #main.buttonC0Port,"Off",PortClick, UL, 45, 302, 30, 20 button #main.buttonC1Port,"Off",PortClick, UL, 45, 322, 30, 20 button #main.buttonC2Port,"Off",PortClick, UL, 45, 342, 30, 20 button #main.buttonB7Port,"Off",PortClick, UL, 470, 100, 30, 20 button #main.buttonB6Port,"Off",PortClick, UL, 470, 120, 30, 20 button #main.buttonB5Port,"Off",PortClick, UL, 470, 140, 30, 20 button #main.buttonB4Port,"Off",PortClick, UL, 470, 160, 30, 20 button #main.buttonB3Port,"Off",PortClick, UL, 470, 180, 30, 20 button #main.buttonB2Port,"Off",PortClick, UL, 470, 200, 30, 20 button #main.buttonB1Port,"Off",PortClick, UL, 470, 220, 30, 20 button #main.buttonB0Port,"Off",PortClick, UL, 470, 240, 30, 20 button #main.buttonC7Port,"Off",PortClick, UL, 470, 305, 30, 20 button #main.buttonC6Port,"Off",PortClick, UL, 470, 325, 30, 20 ComboboxColor$ = "white" combobox #main.COMPort, COMPort$(), [comboboxCOMPortDoubleClick], 375, 417, 100, 100 statictext #main.statictext88, "COM Port", 375, 392, 57, 20 '-----End GUI objects code '-----Begin menu code menu #main, "File",_ "Quit", [quit.main] '-----End menu code open "UBW Play v1.0" for window as #main print #main, "font ms_sans_serif 10" ' ' END OF FREEFORM GENERATED CODE. DO NOT COPY-PASTE FROM FREEFORM ' loadbmp "ON", ".\LEDOn.bmp" loadbmp "OFF", ".\LEDOff.bmp" print #main, "trapclose [quit.main]" ' Populate the drop down list of available COM ports gosub [GetCOMPorts] ' Go do TimerTick every 50ms timer TICKRATE, [TimerTick] [main.inputLoop] 'wait here for input event wait [bmpbutton1Click] 'Perform action for the bmpbutton named 'bmpbutton1' [bmpbuttonB7StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonB7Status' [bmpbuttonB6StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonB6Status' [bmpbuttonB5StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonB5Status' [bmpbuttonB4StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonB4Status' [bmpbuttonB3StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonB3Status' [bmpbuttonB2StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonB2Status' [bmpbuttonB1StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonB1Status' [bmpbuttonB0StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonB0Status' [bmpbuttonC7StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonC7Status' [bmpbuttonC6StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonC6Status' [bmpbuttonA0StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonA0Status' [bmpbuttonA1StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonA1Status' [bmpbuttonA2StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonA2Status' [bmpbuttonA3StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonA3Status' [bmpbuttonA4StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonA4Status' [bmpbuttonA5StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonA5Status' [bmpbuttonC0StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonC0Status' [bmpbuttonC1StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonC1Status' [bmpbuttonC2StatusClick] 'Perform action for the bmpbutton named 'bmpbuttonC2Status' wait ' The user has clicked on a PORT bit, meaning they want to flip the bit from ' a 1 to a 0 or vise versa. sub PortClick handle$ ' First, get the name of the Port and the Bit that we're working with ' #main.buttonA0Port Port$ = mid$(handle$, 13, 1) Pin = val(mid$(handle$, 14, 1)) if Port$ = "A" then PortA = BitFlip(PortA, Pin) if TstBit(PortA, Pin) then #handle$ "On" else #handle$ "Off" end if end if if Port$ = "B" then PortB = BitFlip(PortB, Pin) if TstBit(PortB, Pin) then #handle$ "On" else #handle$ "Off" end if end if if Port$ = "C" then PortC = BitFlip(PortC, Pin) if TstBit(PortC, Pin) then #handle$ "On" else #handle$ "Off" end if end if call SendOCommand PortA, PortB, PortC end sub ' So the user has clicked on a direction button ' We need to flip the bit in the direction byte, and we need ' to toggle the direction button's text (In/Out) sub DirClick handle$ ' First, get the name of the Port and the Bit that we're working with ' #main.buttonA0Dir Port$ = mid$(handle$, 13, 1) Pin = val(mid$(handle$, 14, 1)) if Port$ = "A" then DirA = BitFlip(DirA, Pin) if TstBit(DirA, Pin) then #handle$ "In" else #handle$ "Out" end if end if if Port$ = "B" then DirB = BitFlip(DirB, Pin) if TstBit(DirB, Pin) then #handle$ "In" else #handle$ "Out" end if end if if Port$ = "C" then DirC = BitFlip(DirC, Pin) if TstBit(DirC, Pin) then #handle$ "In" else #handle$ "Out" end if end if call SendCCommand DirA, DirB, DirC, 0 end sub ' Each time the user selects a new COM port, close the old one (if any) and open the new one [comboboxCOMPortDoubleClick] gosub [CloseSerialPort] gosub [OpenSerialPort] ' Also send out the status of our Direction registers and data registers call SendCCommand DirA, DirB, DirC, 0 call SendOCommand PortA, PortB, PortC wait ' Go through the current values of the Status bytes and update the LEDs to On/Off ' based upon each stats byte's value [UpdateLEDs] ' Do PortA for Bit = 0 to 5 if TstBit(OldStatusA, Bit) <> TstBit(StatusA, Bit) then hndl$ = "#main.bmpbuttonA";Bit;"Status" if TstBit(StatusA, Bit) = 1 then print #hndl$, "bitmap ON" else print #hndl$, "bitmap OFF" end if end if next Bit ' Do PortB for Bit = 0 to 7 if TstBit(OldStatusB, Bit) <> TstBit(StatusB, Bit) then hndl$ = "#main.bmpbuttonB";Bit;"Status" if TstBit(StatusB, Bit) = 1 then print #hndl$, "bitmap ON" else print #hndl$, "bitmap OFF" end if end if next Bit ' Do PortC for Bit = 0 to 7 if _ (TstBit(OldStatusC, Bit) <> TstBit(StatusC, Bit)) _ AND _ (Bit <> 3) _ AND _ (Bit <> 4) _ AND _ (Bit <> 5) _ then hndl$ = "#main.bmpbuttonC";Bit;"Status" if TstBit(StatusC, Bit) = 1 then print #hndl$, "bitmap ON" else print #hndl$, "bitmap OFF" end if end if next Bit ' Copy over the last known state OldStatusA = StatusA OldStatusB = StatusB OldStatusC = StatusC return ' Go through all of the direction port bits, and disable the buttons that correspond ' to I/O bits that are set as inputs [UpdatePorts] ' Do PortA for Bit = 0 to 5 if TstBit(OldDirA, Bit) <> TstBit(DirA, Bit) then hndl$ = "#main.buttonA";Bit;"Port" if TstBit(DirA, Bit) = 1 then print #hndl$, "!disable" else print #hndl$, "!enable" end if end if next Bit ' Do PortB for Bit = 0 to 7 if TstBit(OldDirB, Bit) <> TstBit(DirB, Bit) then hndl$ = "#main.buttonB";Bit;"Port" if TstBit(DirB, Bit) = 1 then print #hndl$, "!disable" else print #hndl$, "!enable" end if end if next Bit ' Do PortC for Bit = 0 to 7 if _ (TstBit(OldDirC, Bit) <> TstBit(DirC, Bit)) _ AND _ (Bit <> 3) _ AND _ (Bit <> 4) _ AND _ (Bit <> 5) _ then hndl$ = "#main.buttonC";Bit;"Port" if TstBit(DirC, Bit) = 1 then print #hndl$, "!disable" else print #hndl$, "!enable" end if end if next Bit ' Copy over the last known state OldDirA = DirA OldDirB = DirB OldDirC = DirC return ' Application wide tick routine - called every TICKRATE ms. [TimerTick] ' Always shut off the timer in case things take longer than we anticipate timer 0 ' Check to see if it's time to check for new com ports if GetCOMPortCount = 0 then gosub [GetCOMPorts] ' If we go do it, then reload the counter GetCOMPortCount = GETCOMPORTRATE else ' Otherwise just decriment it every tick GetCOMPortCount = GetCOMPortCount - 1 end if ' Go check to see if there's any new data for us on our COM port gosub [CheckForNewData] ' Also, constantly query the unit to read the state of its bits call SendICommand ' And update our LEDs with any new data we just receieved gosub [UpdateLEDs] ' Now make sure to disable any port buttons who's dir bit is an input gosub [UpdatePorts] ' Now re-arm our timer timer TICKRATE, [TimerTick] wait ' Here we look at if there's any data that's come from the COM port ' since the last time we checked. We look for the result of ' I commands, and errors. [CheckForNewData] if OpenedCOMPort$ <> "" then NumBytes = lof(#commHandle) DataIn$ = input$(#commHandle, NumBytes) if DataIn$ <> "" then 'Now see if we got the response to an "I" command if left$(DataIn$,2) = "I," then ' "I,AAA,BBB,CCC" StatusA = val(mid$(DataIn$, 3, 3)) StatusB = val(mid$(DataIn$, 7, 3)) StatusC = val(mid$(DataIn$, 11, 3)) ' We're looking at port C, bit 0 to watch the LED flash ' and counting packets inbetween flashes. FlashCounter = FlashCounter + 1 if TstBit(StatusC,0) <> OldValue then NewTime = time$("ms") print "Got " + str$(FlashCounter) + " packets and " + str$(NewTime - OldTime) + "ms between flashes. Now " + str$(TstBit(StatusC,0)) OldTime = NewTime FlashCounter = 0 OldValue = TstBit(StatusC,0) end if end if end if end if return [quit.main] 'End the program gosub [CloseSerialPort] close #main end ''''''''''''''''''''''''''''''''''''' ' UBW SEND/RECEIVE UTILITY ROUTINES ' ''''''''''''''''''''''''''''''''''''' ' This subroutine sends an O command to the UBW, which outputs ' the bits that are contained in the three port values. Note that ' not all of the bits in three registers actually come out of the ' board as I/O pins, and you have to have set the pin as an output ' with the C command before you can output anything on that pin. sub SendOCommand PortAOut, PortBOut, PortCOut if OpenedCOMPort$ <> "" then OutStr$ = "O," + str$(PortAOut) + "," + str$(PortBOut) + "," + str$(PortCOut) + chr$(13) print #commHandle, OutStr$; end if end sub ' This subroutine sets the direction of the bits on the UBW board ' Normally you'll call this once at the beginning of your application ' to set the direction of the bits, and then just use the O and I ' commands to read and write the bits. sub SendCCommand DirAOut, DirBOut, DirCOut, AnalogOut if OpenedCOMPort$ <> "" then OutStr$ = "C," + str$(DirAOut) + "," + str$(DirBOut) + "," + str$(DirCOut) + "," + str$(AnalogOut) + chr$(13) print #commHandle, OutStr$; end if end sub ' This subroutine reads the values of all bits. Note that this ' routine will read the actual state of each port pin, not the ' value that may have been written to the corresponding port ' register (they may not be the same). Also, you do not have ' to have a pin set to an input to use this command - the ' states of all pins are read every time this command is executed. ' Note that the result of this command will be a packet back from ' the UBW board of the format "I,021,121,200" where each ' number is the current value of the port. This packet will be ' received during the TimerTick routine when it checks for any ' new data back from the UBW. sub SendICommand if OpenedCOMPort$ <> "" then OutStr$ = "I," + chr$(13) print #commHandle, OutStr$; end if end sub ''''''''''''''''''''''''''''''' ' BIT/BYTE UTILITY ROUTINES ' ''''''''''''''''''''''''''''''' ' Flip the bit 'Bit' in byte 'Byte' and return the new byte. function BitFlip(Byte, Bit) if TstBit(Byte, Bit) = 1 then BitFlip = (Byte AND (255 XOR (2^Bit))) else BitFlip = (Byte OR (2^Bit)) end if end function ' Test bit "Bit" in variable "Byte" and return it's value (1 or 0) function TstBit(Byte, Bit) TestBit = 0 if ((Byte AND (2^Bit)) > 0) then TstBit = 1 end if end function ''''''''''''''''''''''''''''''' ' COM PORT UTILITY ROUTINES ' ''''''''''''''''''''''''''''''' ' ' GetCOMPorts ' ' This subroutine will populate the drop-down list called #main.CombComPort ' with all of the currently available COM ports. You can change #main.COMPort ' to whatever you use in your program. ' [GetCOMPorts] ' First clear out our 'new' COM Ports array for Port = 0 to MAXCOMPORTS NewCOMPort$(Port) = "" next Port ' We start with index 1, since that's where the combo box starts CurrentComboIndex = 1 ' We're going to loop from 1 to 254 and see if any of those COM ports are available for TestPort = 1 to HIGHESTCOMPORT ' If we hit upon our currently opened COM port, we add that to our list too to keep things simple if IsCOMPortAvailable(TestPort) = 1 OR "COM" + str$(TestPort) = OpenedCOMPort$ then ' Add this port into 'new' COM port array NewCOMPort$(CurrentComboIndex) = "COM" + str$(TestPort) CurrentComboIndex = CurrentComboIndex + 1 end if next TestPort ' Now compare to see if there are any differences between the two lists ' of COM ports (old vs new) bAreTheSame = TRUE for Port = 1 to MAXCOMPORTS ' Now, if the COM port strings at this index are not the same, then something's changed ' and we need to remember that fact and exit the loop if NewCOMPort$(Port) <> COMPort$(Port) then bAreTheSame = FALSE exit for end if next Port ' If they are not the same, then copy over new to old and update combobox if (bAreTheSame = FALSE) then for Port = 1 to MAXCOMPORTS COMPort$(Port) = NewCOMPort$(Port) next Port ' Now reload the combbox to get the new array values print #main.COMPort, "reload" end if ' If the currently selected COM port is empty, and we have some COM port in our list, then ' set our currently selected COM port to the first one. print #main.COMPort, "contents? CurComPort$" if CurComPort$ = "" and CurrentComboIndex > 1 then print #main.COMPort, "selectindex 1" gosub [CloseSerialPort] gosub [OpenSerialPort] end if return ' Helper function for [GetCOMPorts] ' Returns 0 if the Port is not available on this system (either already opened or doesn't ' exist) and 1 if the port is available. function IsCOMPortAvailable(Port) struct lpSecurityAttributes, _ nLength as long, _ lpSecurityDescriptor as long, _ bInheritHandle as long lpFileName$ = "\\.\COM" + str$(Port) dwDesiredAccess = 0 dwShareMode = 1 + 2 dwCreationDisposition = 3 dwFlagsAndAttributes = 128 hTemplateFile = 0 calldll #kernel32, "CreateFileA", _ lpFileName$ as ptr, _ dwDesiredAccess as long, _ dwShareMode as long, _ lpSecurityAttributes as struct, _ dwCreationDisposition as long, _ dwFlagsAndAttributes as long, _ hTemplateFile as long, _ retcode as long hObject = retcode ' Test the return code to see if the port is available and free if retcode = -1 then IsCOMPortAvailable = 0 else ' If we were able to open it, then close it and return TRUE calldll #kernel32, "CloseHandle", _ hObject as long, _ retcode as long IsCOMPortAvailable = 1 end if ' The other reason we could have an available com end function ' Handle opening the serial port [OpenSerialPort] oncomerror [ComErrorHandler] print #main.COMPort, "contents? ComPort$" if ComPort$ <> "" and OpenedCOMPort$ <> ComPort$ then print #main.COMPort, "contents? ComPort$" OpenedCOMPort$ = ComPort$ open ComPort$;":9600,8,N,1,RS,DS0,CS0" for random as #commHandle end if return ' Handle closing the serial port [CloseSerialPort] if OpenedCOMPort$ <> "" then close #commHandle OpenedCOMPort$ = "" end if return ' We get here if there is a com error at some point. [ComErrorHandler] ' Display the com error box notice "Com Error"; chr$(13); "Some type of com port error has occured. Your computer may not have a valid com port at COM"; str$(ComPortNumber); " or there might be another error. "; chr$(13); "Error: "; ComError$; " Port: "; str$(ComPortNumber); " ErrorNo: "; str$(ComErrorNumber) gosub [CloseSerialPort] wait