Tech Note 03c: Serial Communications

January 29, 2007

© NSB Corporation. All rights reserved.


There is additional documentation on Microsoft's website.

This TechNote describes Microsoft's Serial control for Windows CE. There is also a new third party control with additional features available from Franson. It includes support for Bluetooth and has many other improved features. There is some sample code using this control at the end of this Tech Note.


Serial communications are straightforward in NSBasic/CE. They make use of Microsoft's standard COMM control. Make sure it is installed on your Windows CE device and that it is properly set up in the Registry.

Communications are controlled completely by setting properties in the Comm object. These properties control port setting and are used to input and output characters.

If the Comm object needs to send information back to your program, it will call a subroutine in your program coalled Comm_onComm. This subroutine (which has no arguments) can then check the comm.commEvent property to see why there was a callback. The most common reason is to notify the program that there are characters in the input buffer.

Remember to turn off Communicate with PC in the Communication settings panel. Otherwise, you will be unable to open the port as Windows CE will already have it open.

To initialize the Comm object, put the following line in your program. If you do not supply the full list of arguments, onComm will not be called.

addObject "Comm","comm",0,0,0,0

 

Notes

From Kostas Bouzianas

In text mode In/Out buffers represented as strings. In binary mode they are represented as BYTE arrays This can be checked with VarType(Comm.Input or Output) when put Comm.InputMode=0/1 (I did not imagine how useful VarType was before). The problem is that due to VBScript's fuzzy declaration of variables, I could not strictly define a byte array (loss of As Byte), even in most obvious function like Array(cbyte(&HXX),....). Checking by VarType returns 8204 which is array with variant subscripts.

In such a way, Output does not run (OutBufferCount: 0, no OnComm events) while input usually gives a Type mismatch Error.

Finally, transmission/reception on Binary mode was affected by doing the following.:
InputMode=0 'Text
NullDiscard=False

Transmission: Conversion of bytes to transmit with CHR function Concatenation of bytes in a string variable (transmission of all bytes at once)

Reception: InputLen=1 (reception byte by byte) Conversion of received strings to numbers by using ASC function and storage in array.

For those developing for peripheral devices: Your application may run but low level signals of handheld may not trigger RS232 port of your peripheral. Make a respective application in desktop for testing.

From Juan Garlos Garrido

I read the note by Kostas Bouzianas, and he said that the only way of working with comm control in binary mode is setting inputlen by 1, and receive char by char, and this is not really true.

The ".input" comm Method returns a byte array, and the only thing you have to do is assign it to a variant and then use it as an array. I've been doing it with my old 2.10 version and works fine. (of course, inputlen is 0 in order to receive all characters avalaible)

Here is a sample that demonstrates it (extracted from one of my programs). It is a function that receives a packet. Constants for Start timeout, character timeout, and function result must be defined outside of the function. Com_port is the comm. Control created and opened outside of the function.

Function Receive(nr,s)
'Receives a packet, stopping when  nr characters are received or
timeout 
's contains the packet received, and  the function returns
'Result_err_TOUT or Result_OK constants
'Timeout for first character= st_tout* 20 ms
'Timeout betwen characters= c_tout* 20 ms
'st_tout and c_tout are global constants

    Dim B 'pointer to input buffer
    Dim ncr, i,Tim
    On Error Resume Next   
    Tim=1
    Do 
    'Waits until some characters are avalaible
        sleep (20) 
        ncr = com_port.InBufferCount
        Tim=Tim+1
    Loop  Until (ncr > 0) Or (tim>st_tout)
    s = ""
    If ncr = 0 Then 'time-out
        receive = Result_err_TOUT        
        Exit Function
    Else 'there are characters in the buffer
        B = com_port.Input
        For i = 0 To ncr - 1
            s = s & Chr(b(i))
        Next
    End If
    Tim=1
    Do Until (Len(s) >= nr) Or (Tim>c_tout)
    ' Receives full packet
        sleep(20)
        ncr = com_port.InBufferCount
        If ncr > 0 Then
            Tim=1 'Resets timeout timer
            B = com_port.Input
            For i = 0 To ncr  1 'get all characters from input buffer
                s = s & Chr(b(i))
            Next
        End If
        Tim = Tim + 1
    Loop 
    Erase B ' dispose memory of input buffer
    If  Len(s) >= nr then 'Reception completed	
      receive = Result_OK  ' Pck
    Else
       receive = Result_err_TOUT 'Tout
    End If
End Function

Properties

comm.commEvent

The integer code of the last event. Read only.

comm.commID

The handle of the comm device. Read only.

comm.commPort

The comm port (as in com1, com2...). Integer. For example, on a Casio PPC, set this value to 1.

comm.DSRHolding

State of the DSR line.

comm.DTREnable

State of DTR line. True or false.

comm.Handshaking

Handshaking protocol
0 - none
1 - XON/XOFF
2 - hardware
3 - hardware and XON/XOFF

comm.inBufferCount

Number of characters in input buffer. Read only.

comm.input

Returns characters from input buffer and clears it

comm.inputLen

Number of characters comm.input will return

comm.inputMode

Type of input
0 - text
1 - binary

comm.nullDiscard

Should null chars be discarded? true or false.

comm.output

Output string. Write only.

comm.OutBufferCount

Number of characters in output buffer. Read only.

comm.portOpen

Opens and closes port.
0 - close comm port
1 - open comm port

comm.RThreshold

Number of receive characters before onComm event triggered.
0 - do not trigger onComm

comm.Settings

A string of the format "BBBB,P,D,S", where BBBB is the baud, P is the parity, D is the number of data bits, and S is the number of stop bits. The default value is "9600,N,8,1"
Valid baud rates are 110, 300, 600, 1200, 2400, 9600, 14400, 28800, 38400, 56000, 128000, 256000
Valid parity values are E,M,N,O,S (Even, Mark, None, Odd, Space)
Valid data bit values are 4, 5, 6, 7, 8
Valid stop bit values are 1, 1.5, and 2.

comm.sThreshold

Number of send characters before onComm event triggered.
0 - do not trigger onComm

comm.RTSEnable

State of RTS line. True or False.

comm.settings

baud, parity, databits, stopbits in a string.

CommEvent Errors

Constant

Value

Description

comNoError

0

No Error.

comEventBreak

1001

A break signal was received.

comEventCTSTO

1002

Clear To Send Timeout. The Clear To Send line was lower than the system- specified amount of time used when transmitting a character.

comEventDSRTO

1003

Data Set Ready Timeout. The Data Set Ready line was lower than the system specified amount of time used when to transmitting a character.

comEventFrame

1004

Framing error. The hardware detected a framing error.

comEventOverrun

1006

Port overrun. A character was not read from the hardware before the next character arrived and was lost.

comEventCDTO

1007

Carrier detect timeout. The carrier detect line was low for the system specified amount of time while trying to transmit a character. Carrier detect is also known as the receive line signal detect.

comEventRxOver

1008

Receive buffer overflow. There is no room in the receive buffer.

comEventRxParity

1009

Parity error. The hardware detected a parity error.

comEventTxFull

1010

Transmit buffer full. The transmit buffer was full when trying to queue a character.

comEventDCB

1011

Unexpected error retrieving device control block for the port.

CommEvent Events

Constant

Value

Description

comEvSend

1

There are fewer than SThreshold number of characters in the transmit buffer.

comEvReceive

2

Received RThreshold number of characters. This event is generated continuously until you use the Input property to remove the data from the receive buffer.

comEvCTS

3

Change in Clear To Send line.

comEvDSR

4

Change in Data Set Ready line. This event is fired only when DSR changes from 1 to 0.

comEvCD

5

Change in carrier detect line.

comEvRing

6

Ring detected. Some universal asynchronous receiver-transmitters (UARTs) may not support this event.

comEvEOF

7

End Of File (ASCII character 26) character received.

 

Example

This program will talk to a terminal emulation program, such as HyperTerminal, running on a PC using the standard synch connnection. There are a few setup things to keep in mind so the program will work.

1. On your device, go into Settings...Communication Properties...PC Connection. Make sure the box "Allow connection with desktop computer when H/PC is attached is not checked.

2. On your PC, make sure ActiveSync is not enabled.

3. Set your terminal emulator for a local connection to the serial port your device is plugged into. Make sure baud, parity, databits and stop bits are all set the same as shown in Properties when running the following program. Also, make sure the handshaking is set the same way.

 

rem Demonstrate serial communications
'see Tech Note for complete details
Option Explicit
dim selection,myString
addObject "comm","comm",0,0,0,0
selection=0
myString=""

while selection<>9
  selection=inputbox("Choose Operation:" & chr(13) & "1. Open" & chr(13) & "2. Write" & chr(13) & "3. Properties " & chr(13) & "4. Read" & chr(13) & "5. Close" & chr(13) &  "9. End Program", "COMM Demo")
  select case selection
  case 1
    open_click
  case 2
    write_click
  case 3
    properties_click
  case 4
    read_click
  case 5
    close_click
  case else
    selection=9
    Comm.PortOpen = 0
  end select
wEnd

Private Sub Close_Click()
  Comm.PortOpen = 0
End Sub

Private Sub Comm_OnComm()
  Dim InString
  Select Case Comm.CommEvent
  Case 2 ' character In - collect until return is received
    InString = Comm.Input
    if asc(InString)=13 then
      msgBox myString
      myString=""
    else
      myString=myString & InString
    end if
  case else
    msgbox "Other CommEvent Received:" & comm.commEvent
  End Select
End Sub

Private Sub Read_click()
  dim sRead
  sRead=comm.input
  msgbox sRead
end Sub
 
Private Sub Open_Click()  
  Comm.Rthreshold = 1 'event on every character in
  Comm.InputMode = 0 'text mode
  Comm.handshaking=1 '0=none, 1=XON/XOFF, 2=HW
  Comm.RTSEnable=true
  comm.DTREnable=true
  Comm.PortOpen = True
  if err<>0 then
    msgbox "Open Comm: " & err.description
    err.clear
  end if 
End Sub

Private Sub Write_Click()
  Dim myString
  myString = "This is being sent from CommCtl Test."
  Comm.Output = myString
End Sub

Private Sub properties_click()
  dim sOut, tab, CR
  tab=chr(9)
  CR=chr(13)
  sOut="CommEvent:" & chr(9) & comm.commEvent & space(40) & CR
  sOut=sOut & "CommID:" & tab & comm.commID & tab & "InputLen:" & chr(9) & comm.inputLen & CR 
  sOut=sOut & "CommPort:" & tab & comm.commPort & tab & "InputMode:" & comm.inputMode &  CR
  sOut=sOut & "Handshaking:" & tab & comm.Handshaking & tab & "CTSHolding:" & CR
  sOut=sOut & "InBufferCount:" & tab & comm.inBufferCount & tab & "DSRHolding:" & comm.DSRHolding & CR
  sOut=sOut & "OutBufferCount:" & comm.OutBufferCount & tab & "DTREnable:" & comm.DTREnable & CR
  sOut=sOut & "PortOpen:" & tab & comm.portOpen & tab & "RTSEnable:" & comm.RTSEnable & CR
  sOut=sOut & "RThreshold:" & tab & comm.RThreshold & tab & "NullDiscard:" & comm.nullDiscard & CR
  sOut=sOut & "Settings:" & comm.settings
  msgbox sOut,0,"COMM Properties"
end Sub

Sample using Franson Serial Control

'Contributed by Michael Newett

'This example works for Pocket PC or Desktop devices, with any length 
'of file, any baudrate, serial or bluetooth.

'Note** The devices (PDA or desktop) Bluetooth must be turned ON 
'before running the code.

'For CE Device use the following
AddObject "serialce.port.1","objPort" 'For CE Device
AddObject "serialce.license","objlicense" 'For CE Device

'For WindowsXP Device use the following
AddObject "serialxp.port.1","objPort"
AddObject "serialxp.license","objlicense"

'For all devices
objLicense.LicenseKey = "xxx Enter license key here xxx"

Form1_Load

Sub StartCommandButton_Click
  objPort.BaudRate = 9600
  objPort.ComPort = 8 'enter bluetooth outbound COM port number here
  objPort.ByteSize = 8
  objPort.Parity = 0
  objPort.StopBits = 0 '0 means 1 stop bit
  objPort.Enabled = True 'enable comm. port
  objPort.NoEvents = True
  objPort.DTR = True
  objPort.RTS = True
  Sleep 100 'delay to enable comm port to initialise
End Sub

Sub StopCommandButton_Click
  objPort.Enabled = False 'disable comm port
End Sub

Sub WriteCommandButton_Click
  objPort.Write "Enter String to Write here"+vbCr 'Send command to device. Add vbCr or vbLf as applicable
  Finished=False
  Str=""
  Do until Finished=True
    Size=objPort.Buffersize 'get number of bytes received from device
    Newstr=objPort.Read(Size,1000) 'read response from device. Timeout if nothing received after 1000ms
    If IsNull(Newstr) Then
      Finished=True
    Else
      Str=Str&Newstr
    End If
  Loop
  If IsNull(Str) Then Str="Device Timed out"
  Msgbox Str
End Sub


Sub Form1_load
  AddObject "CommandButton", "StartCommandButton", 75, 125, 100, 25
  bStart.Caption = "Start Comms"
  bStart.FontSize = 8.25

  AddObject "CommandButton", "StopCommandButton", 75, 225, 100, 25
  bStop.Caption = "Stop Comms"
  bStop.FontSize = 8.25

  AddObject "CommandButton", "WriteCommandButton", 75, 175, 100, 25
  Write.Caption = "Write"
  Write.FontSize = 8.25
End Sub