|
|
Previous Section: Variable Scope |
|
|
OVM Streams Introduction |
|
|
OVM provides special commands, and functions (of the form STREAM) which are intended for serial communication applications. To make use of OVM’s stream keywords your application must actually support them. This section will describe the expected generic behaviour of the stream commands, and functions. If your application does support OVM streams you should refer to your application’s documentation in preference to this document. For the purposes of illustration we will assume that the application is PC based and that an RS232 serial port stream is supported by the application. |
|
Creating, and Destroying OVM Streams |
|
|
OVM supports three keywords for creating, and destroying streams. These are streamcreate, streamdestroy, and streamdestroyall. The streamcreate keyword is implemented externally by the application. The type of streams you can create depends entirely on your application. @integer handle = streamcreate("RS232","COM2", \ The above example would create a stream that comunicates via the COM2 serial port of the PC with a baud rate of 9600 bps, with 8 bits of data, no parity, and 1 stop bit. The supports a 50 line history buffer. Also, the stream should log all data to the file "logfile.txt", and OVM will not filter out ASCII 0 characters. On success the value in handle will be > 0. This handle is then used by the other stream keywords as the first parameter (except streamdestroyall) to specify an individual stream. Internally, OVM can support up to 100 concurrent streams. For the application above we will assume we can only create a single RS232 connection. To destroy an individual stream you use the streamdestroy command. @streamdestroy(handle) Note that the streamdestroy command does not change the value of handle to indicate the stream has been destroyed. You must do this yourself. When you create multiple streams you can destroy them all with the streamdestroyall command. @streamdestroyall Once again this does not change any handle values for you. All created OVM streams are automatically destroyed when the application exits. |
|
Sending Data to an OVM Stream |
|
|
OVM provides four keywords for sending information to an OVM stream. The application must provide support for these keywords before you can make use of them. The streamputbyte command is used to send 1 or more individual byte values to a stream. Each value is passed as an integer and should be in the range 0 to 255. Any values outside of this range will cause the error flag to be set. @streamputbyte(handle,13,10) ! send a CRLF pair The streamput command is used to send strings or byte data to a stream. @streamput(handle,"mary had a little lamb",13,10) The above example would send the string "mary had a little lamb" plus a carriage return and line feed to the stream. Note that the integer values 13, and 10 are sent as their ASCII equivalent character as was the case for streamputbyte. You cannot send a boolean value using streamput. The streambreak command is used to send a break signal to the stream. For some streams this command is meaningless. @streambreak(handle) The streamflushout command is used to ensure that any data pending to be sent is actually transmitted. This is useful if your application’s streamput, and streamputbyte commands do not block (ie they return before all data has been sent). @streamflushout(handle) Typically you only need to use the streamflushout command with streams that have non blocking output before taking some action (such as destroying the stream). |
|
Reading Data from an OVM Stream |
|
|
OVM provides a number of keywords for reading data from streams. These keywords require application support. The streamavail function returns how many characters / bytes are currently waiting to be read. @if streamavail(handle) > 0 then Since most streams will have some sort of input buffer this does not necessarily reflect all potentially available data. It is useful however for taking other action while there is no data waiting. Note that when a stream is created with the ASCII 0 filtering option turned on streamavail can not be used as a reliable guide to how many characters will actually be returned when the stream is read. To read a single byte from a stream use the streamgetbyte function. @integer byteval On success streamgetbyte will return 1, and byteval will contain a value from 0 to 255 inclusive. Note that if ASCII 0 filtering is enabled streamgetbyte will return 0 if the next character due to be read was an ASCII 0. Therefore, with ASCII 0 filtering enabled the streamgetbyte return value cannot be used to indicate if no more characters are currently waiting to be read. To read a buffer full of bytes from a stream use the streamreadbuff function. @string buffer The above example will read up to 100 characters / bytes from the stream (if less characters are available it is up to the application to decide if to wait for more characters to arrive) returning > 0 if characters were stored in buffer. If no characters were available streamgetbuff returns 0. This can also occur when ASCII 0 filtering is enabled, and only ASCII 0 characters were available. A variation of streamgetbuff is streamgetline which works much like streamgetbuff except that it also stops reading if a specified character is encountered. @string buffer Use streamgetline when you know you need to stop reading data when a
particular character is encountered but you don’t want implement
your own streamgetbyte loop. Internally streamgetline uses the same application
calls as streamavail, and streamgetbyte. To discard any data currently waiting to be read use the streamflushin command. @streamflushin(handle) This command is useful when you want to ensure no extraneous data is waiting to be read before waiting for a particular response. The streamwaitforany function is used to wait for 1 or more given strings (with support for the wildcards supported by @patterncreate) to appear in the stream input data within a specified timeout period. For example, assume that a RS232 stream is being used to connect to a Unix host that we wish to login into automatically. @boolean loggedin = false The second parameter is a timeout in milliseconds for how long to wait for any of the given strings to appear. The third parameter is whether the search is case sensitive. True means the case of the data must exactly match the case of the search string. False, means the case of the data is not important. The fourth (fifth, ) parameters are the string(s) to wait for. When matching data is found streamwaitforany returns the number (counting from 1) of the string that was matched. If no matching string is found then streamwaitforany returns 0 when it times out. If given an empty string, or an error occurs on the stream streamwaitforany will return < 0. Note that streamwaitforany consumes the characters as it checks them. Streamwaitforany requires that streamavail, and streamgetbyte are also supported, as it internally uses the same application calls that these functions use.
|
|
|
Using the OVM Stream Line Buffer (The streamlb keywords) |
|
|
When you create a stream with streamcreate the fourth parameter is the length in lines of the stream’s history line buffer. When you specify a value > 0 an internally managed line buffer is associated with the stream. This history buffer keeps a sliding window of all the data that was read with streamgetbyte, streamgetbuff, streamgetline, and streamwaitforany. If you specify you want a line buffer (by setting the 4th parameter of streamcreate to > 0) the value you specify may not be the actual number of lines you get. Internally, OVM will create a line buffer of between 10, and 10000 lines. So, if you specify a 1 line buffer you will actuall get a 10 line buffer. If you specify a 20000 line buffer you will actual get a 10000 line buffer. To make use of data in the stream’s line buffer OVM provides five line buffer commands. These all start with streamlb. The streamlbflush command is used to clear the line buffer of all data. This restores the line buffer to the state it was in when the stream was first created. @streamlbflush(handle) ! discard all data in the buffer The streamlbget command returns a copy of the data from the line specified provided that the specified line of data is actually available. As data is read into a previously empty line buffer the characters are placed into line 1. Whenever a line feed, form feed, or vertical tab character is stored (or when 255 characters are read) the next line of the line buffer is used. Once the line buffer becomes full the oldest line of data is discarded – however, the line numbering continues to increase. For example if 11 lines of data are read into a 10 line buffer the available lines of data will be numbered from 2 to 11 (not 1 to 10). @string buffer = streamlbget(handle,5) The above example returns the 5th line of data received since the stream was created (or since the last streamlbflush) but only if at least 4 complete lines of data have been received, and only if the 5th line is still present in the buffer. The typical use of streamlbflush, and streamlbget is as follows. Just before sending data to a stream that will generate a response use the streamlbflush command. Then send your data to the stream. When sufficient data has been read you can then use the streamlbget function to retrieve individual lines of the returned data. This ability is useful when you need to analyse data further after a command has failed for example especially in conjunction with streamwaitforany. The streamlbstart function returns the line number of the oldest line of data still available in the line buffer. For example to retreive the oldest line of data still in the buffer. @string buffer = streamlbget(handle,streamlbstart(handle)) For an empty line buffer streamlbstart will always return 1. The streamlbend function returns the line number of the newest line of data available in the line buffer. This is the line that the next character received will be stored on. For an empty line buffer this will always be line 1. For a 10 line buffer that is about to become full this will be line 10. Once the buffer is full this will be line 11 (and so on). It is worth noting that an internal limitation of OVM means that after approximately 2 billion lines of data the line buffer will be automatically flushed (all data will be lost at this point, and streamlbstart and streamlbend will return 1 until further data is received. To get a copy of the newest data in the line buffer. @string buffer = streamlbget(handle,streamlbend(handle)) The streamlbscan function allows you to search for a particular string in the line buffer. The search can be case sensitive or case insensitive. You can search the entire buffer or just certain lines (both forwards or backwards by line). You can also limit the search to start just within particular columns (although the search always proceeds left to right in each line). @integer online=streamlbscan(handle,false,"incorrect",1,50,100,90) The above example does a case insensitive seach for the string "incorrect" starting in the first 50 columns per line searching from line 100 back to line 90. On success online will be > 0 indicating the line the string was found on. If the string was not found online will contain 0. The same search but for the entire buffer could have been written as : @integer online = streamlbscan(handle,false,"incorrect") If an empty string is passed to streamlbscan, or some other error occurs streamlbscan will return < 0, and the errorflag will be set. If you specify lines that are out of range (either too old or too new) streamlbscan will do its best to search any remaining available lines that still fall within the bounding lines given. The column values must always be between 1, and 255 and the final column must always be greater than or equal to the starting column. The default value for the starting column is 1. The default value for the end column is 255. The default value for the start line is the oldest line in the buffer. If you pass a value less than 1 then the oldest line in the buffer is used as the start line. The default value for the end line in the newest line in the buffer. If you pass a value less than 1 then the newest line in the buffer is used as the end line. The string to search for in streamlbscan supports the same wildcards as streamwaitforany (see @patterncreate for details) but the search is applied individually to each line in turn. This means you cannot search for data that has crossed a line boundary. |
|
Miscalleneous OVM Stream Keywords |
|
|
The streamgetstatus function returns an integer that reflects the status of the stream. Values below 0 are taken to mean the stream is in an error condition. All values >= 0 have application dependent meanings but should never indicate an error condition. @if streamgetstatus(handle) < 0 then streamdestroy(handle) All streams support the streamgetstatus function. The streamsetstatus command is used to change the value returned by streamgetstatus. This command is most useful when you need to recover the stream from a non fatal error. @if streamgetstatus(handle) = -10 then streamsetstatus(0) The streamlog command is used change logfiles, and is also used to stop logging (when the logfile name is the empty string). @integer handle = streamcreate("RS232","COM2",\ Note that stream logging must be supported by the application. The streamevent function is generally used to handle cases such as out of band data. For example in a telnet stream the streamevent function could be used to notify the remote end of a change in the size of the window being used to display the data. The streamsetparam command is used to change a stream specific parameter after the stream has been created. For example to change the baud rate of an RS232 stream. @streamsetparam(handle,"BAUD","38400") The streamgetparam function returns the current value of a specified parameter. @if streamgetparam(handle,"BAUD") = "38400" then Once again your application must support the streamgetparam, and streamsetparam functions before you can use them. |
|
|
|
Previous Section: Variable Scope |
|
|
|
This publication has been prepared and written by Telstra Corporation Limited (ACN 051 775 556), and is copyright. Other than for the purposes of and subject to the conditions prescribed under the Copyright Act, no part of it may in any form or by any means (electronic, mechanical, microcopying, photocopying, recording or otherwise) be reproduced, stored in a retrieval system or transmitted without prior written permission from the document controller. Product or company names are trademarks or registered trademarks of their respective holders. Note for non-Telstra readers: The contents of this publication are subject to change without notice. All efforts have been made to ensure the accuracy of this publication. Notwithstanding, Telstra Corporation Limited does not assume responsibility for any errors nor for any consequences arising from any errors in this publication. |