Attachment 'COM.v1.0.txt'
Download 1 :Class COM
2 ⍝ Class for Asynchronous Serial Communication
3
4 ⍝ List of methods:
5 ⍝ Open = Open the serial port
6 ⍝ SendReceive = Send the bytes and return the bytes received
7 ⍝ Close = Close the serial port
8
9 ⍝ Version 1.0 January 2016
10
11 ⍝ .Net assemblies:
12 :Using
13 :Using System,mscorlib.dll
14 :Using System.Net,System.dll
15 :Using System.Net.Sockets,System.dll
16 :Using System.IO.Ports,System.dll
17
18 (⎕IO ⎕ML ⎕WX)←1 3 3 ⍝ System variables
19
20 :Field Public spObj ⍝ SerialPort object
21 :Field Public Type←'COM'
22
23 ⍝ Used internally
24 :Field _buffer ⍝ empty Byte[] array same size as _BufferSize
25 :Field _stream ⍝ spObj.BaseStream
26
27 ⍝ YOU CAN CHANGE THE VALUE OF THE FOLLOWING 5 FIELDS AFTER
28 ⍝ INTANTIATING THE CLASS BUT BEFORE CALLING THE 'Open' METHOD.
29
30 ⍝ Size of the Input and Output Buffers in Bytes. Should be
31 ⍝ as Big as the Largest Number of Bytes to Send or Receive.
32 :Field Public _BufferSize←100
33
34 ⍝ Time in milliseconds to Wait for a port that is not Active (Receiving Nothing).
35 ⍝ If exceeded Windows Stop Waiting and returns the Control to the Calling Application.
36 :Field Public _PortTimeOut←250
37
38 ⍝ Time in milliseconds that Windows Waits between two Bytes to Arrive.
39 ⍝ If exceeded Windows Stop Waiting and Returns the Control to the Calling Application.
40 :Field Public _LastByteTimeOut←15
41
42 ⍝ When used for serial half duplex communication you will need a small delay
43 ⍝ between sending and receiving to let the serial port switch from receiving to sending.
44 ⍝ Rule of thumb for the delay in millisec: 1E6÷(Baud Rate of serial device)
45 :Field Public _SwitchingDelay←50
46
47 ⍝ Default Flow Control
48 ⍝ (0=None, 1=XOn/XOff Software, 2=RequestToSend, 3=RequestToSendXOnXOff)
49 :Field Public _FlowControl←0
50
51 ∇ Init0
52 :Access Public
53 :Implements Constructor
54 spObj←⎕NULL
55 ∇
56
57 ∇ r←Open(PortNo BaudRate DataBits Parity StopBits);BaudRateOK
58 :Access Public
59 ⍝ Open a Serial Communication Port and Obtain a .Net Serial Port Object (spObj)
60 ⍝
61 ⍝ PortNo = Communication Port Number (ex.: 1, 2, 3, 4, etc.)
62 ⍝ BaudRate = Baud Rate (300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200)
63 ⍝ DataBits = Number of Data Bits (4, 5, 6, 7, 8)
64 ⍝ Parity = Number for Parity (0 = None, 1 = Odd, 2 = Even, 3 = Mark, 4 = Space)
65 ⍝ StopBits = Number of Stop Bits (1, 1.5, 2)
66 ⍝
67 ⍝ r[1] = 1 for Success, 0 for Failure
68 ⍝ r[2] = Literal Error if Failure
69
70 ⍝ Check if the port is already opened
71 :If ⎕NULL≢spObj
72 :AndIf spObj.IsOpen
73 r←0 'Error Opening: Port already open' ⋄ →0
74 :EndIf
75
76 BaudRateOK←300 600 1200 2400 4800 9600 19200 38400 57600 76800 115200
77
78 ⍝ Verify that there is some Serial Port(s) available on the computer
79 :If 0=⍴SerialPort.GetPortNames
80 r←0 'COM Error Opening: No Serial Port Available' ⋄ →0
81 :EndIf
82
83 ⍝ Check if the PortNo is available on the computer
84 :If ~PortNo∊{⍎(⍵∊⎕D)/⍵}¨SerialPort.GetPortNames
85 r←0 'COM Error Opening: The Comm Port Number is Not Valid' ⋄ →0
86 :EndIf
87
88 ⍝ Validate the rest
89 :If ~BaudRate∊BaudRateOK ⋄ r←0 'Error Opening: The Baud Rate is Not Valid' ⋄ →0 ⋄ :EndIf
90 :If ~DataBits∊4 5 6 7 8 ⋄ r←0 'Error Opening: The Data Bits are Not Valid' ⋄ →0 ⋄ :EndIf
91 :If ~Parity∊0 1 2 3 4 ⋄ r←0 'Error Opening: The Parity is Not Valid' ⋄ →0 ⋄ :EndIf
92 :If ~StopBits∊1 1.5 2 ⋄ r←0 'Error Opening: The Stop Bits are Not Valid' ⋄ →0 ⋄ :EndIf
93 :If ~_FlowControl∊0 1 2 3 ⋄ r←0 'Error Opening: The Flow Control is Not Valid' ⋄ →0 ⋄ :EndIf
94
95 :Trap 0
96 ⍝ Construct a SerialPort Object
97 spObj←⎕NEW SerialPort(⊂'COM',⍕PortNo)
98 spObj.(ReadBufferSize WriteBufferSize)←_BufferSize ⍝ Set the Sizes of the Input and Output Buffers
99 spObj.(ReadTimeout WriteTimeout)←_PortTimeOut ⍝ Set the Time-Outs of the communication
100 spObj.BaudRate←BaudRate ⍝ Set the Baud Rate
101 spObj.DataBits←DataBits ⍝ Set the DataBits
102 spObj.Parity←Parity ⍝ Set the Parity
103 spObj.StopBits←(-⎕IO)+(0 1 2 1.5)⍳StopBits ⍝ Set the StopBits
104 spObj.Handshake←_FlowControl ⍝ Set the FlowControl
105
106 ⍝ Open the Port and empty the buffers
107 spObj.Open
108 spObj.DiscardInBuffer
109 spObj.DiscardOutBuffer
110
111 ⍝ Success
112 _buffer←Array.CreateInstance(Byte _BufferSize) ⍝ empty Byte[] array same size as _BufferSize
113 _stream←spObj.BaseStream
114 r←1
115
116 :Else
117 {}Close
118 ⍝ Show the error.
119 :If 90=⎕EN
120 ⍝ .Net Error
121 r←0('COM Error Opening: ',⎕EXCEPTION.GetBaseException.Message)
122 :Else
123 ⍝ APL Error
124 r←0(1⊃⎕DM),': ',{(' '=1↑⍵)↓((1↓a,0)∨a←' '≠⍵)/⍵}(2⊃⎕DM)
125 :EndIf
126 :EndTrap
127 ∇
128
129 ∇ r←{option}SendReceive bytes;count;data;lastByte;qtyBytes;task;taskResult
130 :Access Public
131 ⍝ Write Bytes Asynchronously to a Serial Port.
132 ⍝ Normally the last bytes received will be the one that has time-out on _PortTimeOut.
133 ⍝ Optionnally you can specified the value of the last byte (lastByte) or the quantity
134 ⍝ of bytes to be received (qtyBytes) so the communication will be faster.
135
136 ⍝ bytes = Bytes (as Numbers 0 to 255) to be Written to the Communication Port
137 ⍝ option = positive number -> lastByte to be received
138 ⍝ = negative number -> qtyBytes to be received
139 ⍝ = absent -> will time-out on _PortTimeOut
140
141 ⍝ r[1] = 1 for Success, 0 for Failure
142 ⍝ r[2] = Response if Success, Literal Error if Failure
143
144 ⍝ Check if the port is already opened
145 :If ⎕NULL≡spObj
146 :OrIf ~spObj.IsOpen
147 r←0 'COM Error Sending: Port not open' ⋄ →0
148 :EndIf
149
150 ⍝ Parse the option
151 :If 0≠⎕NC'option'
152 :If option<0
153 qtyBytes←|option
154 :Else
155 lastByte←option
156 :EndIf
157 :EndIf
158
159 :Trap 0
160 ⍝ Write the data:
161 :If _stream.CanWrite
162 :AndIf spObj.IsOpen
163
164 ⍝ Purge the Input and Output Buffers
165 spObj.DiscardInBuffer
166 spObj.DiscardOutBuffer
167
168 ⍝ Write the bytes to serial port
169 task←_stream.WriteAsync(bytes 0(⍬⍴⍴,bytes))
170
171 ⍝ Wait asynchronously for the task to complete
172 :If 0=⎕TSYNC{task.Wait ⍵}&(_PortTimeOut)
173 r←0 'COM Error Sending: Task did not complete sending the bytes' ⋄ →0
174 :Else
175 ⍝ Success
176 task.Dispose
177 :EndIf
178 :Else
179 r←0 'COM Error Sending: Serial Port no longer available to send data' ⋄ →0
180 :EndIf
181
182 ⍝ Read the data received:
183 data←⍳0 ⋄ taskResult←1
184
185 ⍝ Switching delay
186 ⎕TSYNC ⎕DL&_SwitchingDelay÷1000
187
188 :If _stream.CanRead
189 :AndIf spObj.IsOpen
190
191 :While taskResult
192 task←_stream.ReadAsync(_buffer 0 _BufferSize) ⍝ _buffer will be filled with the bytes received
193 ⍝ Waiting asynchronously for the task to complete
194 :If taskResult←⎕TSYNC{task.Wait ⍵}&(_PortTimeOut) ⍝ taskResult=0 when no data is received
195 count←task.Result ⍝ count = number of byte(s) received
196 data,←count↑⌷_buffer ⍝ cumul the bytes
197
198 :If 0≠⎕NC'lastByte'
199 :AndIf lastByte=¯1↑data ⍝ Check if lastByte has been received
200 →END
201 :EndIf
202
203 :If 0≠⎕NC'qtyBytes'
204 :AndIf qtyBytes=⍴,data ⍝ Check if the total number of bytes has been received
205 →END
206 :EndIf
207
208 task.Dispose
209 ⎕TSYNC ⎕DL&_LastByteTimeOut÷1000 ⍝ Wait for last byte to time-out and loop again
210 :EndIf
211 :EndWhile
212 :Else
213 r←0 'COM Error Sending: Serial port no longer available to receive data' ⋄ →0
214 :EndIf
215
216 END: ⍝ Prepare the result
217 :If 0≠⍴,data
218 r←1 data
219 :Else
220 r←0 'COM: No data received'
221 :End
222
223 :Else
224 ⍝ Show the error.
225 :If 90=⎕EN
226 ⍝ .Net Error
227 r←0('COM Error Sending: ',⎕EXCEPTION.GetBaseException.Message)
228 :Else
229 ⍝ APL Error
230 r←0(1⊃⎕DM),': ',{(' '=1↑⍵)↓((1↓a,0)∨a←' '≠⍵)/⍵}(2⊃⎕DM)
231 :EndIf
232 :EndTrap
233 ∇
234
235 ∇ r←Close
236 :Access Public
237 ⍝ Close the Serial Port
238 ⍝ The best practice for any application is to wait for some amount of time after calling the Close method
239 ⍝ before attempting to call the Open method, as the port may not be closed instantly.
240 ⍝
241 ⍝ r[1] = 1 for Success, 0 for Failure
242 ⍝ r[2] = Literal Error if Failure
243
244 :If ⎕NULL≡spObj ⋄ r←0 'Error Closing: Already Closed' ⋄ →0 ⋄ :EndIf
245
246 :Trap 0
247 spObj.Close
248 spObj.Dispose
249 r←1
250 :Else
251 ⍝ Show the error.
252 :If 90=⎕EN
253 ⍝ .Net Error
254 r←0('COM Error Closing: ',⎕EXCEPTION.GetBaseException.Message)
255 :Else
256 ⍝ APL Error
257 r←0(1⊃⎕DM),': ',{(' '=1↑⍵)↓((1↓a,0)∨a←' '≠⍵)/⍵}(2⊃⎕DM)
258 :EndIf
259 :EndTrap
260
261 spObj←⎕NULL
262 ∇
263
264 :EndClass
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.