tsc_Rs232Stream

Use this class to read and write to a serial device (COM port or Bluetooth serial profile) using Trimble Access' communication system.  Threading for the reading and writing of data is supplied internally and no threading management is required.  To asynchronously handle incoming data use a tsc_IRs232StreamMonitor instance (and see sample code below).

Note: that you are required to read or discard incoming data from the port.  You can discard data either manually or by specifying the WriteOnly port parameter as true.

To control access to a Windows Serial COM port resource use the static tsc_Rs232PortLocker class.

Constructors

tsc_Rs232Stream();
tsc_Rs232Stream(const tsc_Rs232Stream& from);
virtual ~tsc_Rs232Stream();

Methods

tsc_Rs232Stream& operator= (const tsc_Rs232Stream& stream);
Assignment operator makes a reference to the same object.

virtual bool Open (const tsc_Rs232PortParameters& parameters);
Opens the channel using the specified port and protocol settings, returns true if the open was successful. For Bluetoooth streams, there may be a delay of several seconds after this call returns, before the connection is properly established and reading or writing to the stream will succeed. Use the IsConnected() method to test for this.

virtual void Close ();
Closes the port.

tsc_Rs232PortParameters Parameters() const;
Returns which port is the current focus of the object (including parameters), this does not imply that the port is open or available.

virtual bool IsOpen() const;
Tests if this port instance is open. Note that "Open" does not necessarily mean connected. See IsConnected().

virtual long BytesAvailable() const;
Returns how many bytes are waiting to be read.  Will return -1 if the port is not open.

virtual long Read(unsigned char* data, long max);
Reads incoming data into the supplied buffer (which must have space for max bytes).  This function will read up to max bytes from the read buffer or less if that many are not available.  Returns immediately with the actual number of bytes read.  Will return -1 if the port is not open.  You can pass in a NULL buffer (data) to discard the data.

virtual long Write(unsigned char* data, long howMany);
Writes data to the port from the supplied buffer, which must contain howMany bytes of data.  This function will write up to howMany bytes from the buffer. Returns immediately with the actual number of bytes queued to be written.  Will return -1 if the port is not open.

virtual void DoBreak(const double& breakLength);
Issues a COM break on the open port of breakLength seconds.  The default length is 0.25s.  This call will block the calling thread for the specified period.

bool IsConnected ();
New in version 23.10
Returns true if the stream is fully connected. This differs from IsOpen and the OnConnection event, in that Bluetooth connections will not return true until the connection with the device is fully established. It may take some time to become true and occur several seconds after the Open() call has returned.

Enumerations

enum tsc_Rs232ComPorts
{
    tsc_Rs232_NoPort  // No port selected/NULL selection.
    tsc_Rs232_Com1    // COM 1
    tsc_Rs232_Com2    // COM 2
    tsc_Rs232_Com3    // COM 3
    tsc_Rs232_Com4    // COM 4
    tsc_Rs232_Com5    // COM 5
    tsc_Rs232_Com6    // COM 6
    tsc_Rs232_Com7    // COM 7
    tsc_Rs232_Com8    // COM 8

    // The com port represented by the serial port
    // adapter attached to a connected S Series instrument:
    tsc_Rs232_ComSSeriesFootConnector
}

Sample code

Here is a complete form which allows the user to start an interactive session with a bluetooth serial device, to send commands and display responses.

This is an example of asynchronous usage, with the interface being event-driven.

It is standalone, apart from requiring some translations for the PX_* values (x_Codes), and could be pasted into one module and the RunBluetoothTest() method called to display the form:


#include "stdafx.h"


// An EventArgs to return the response to the last command.

class BtResponse : public tsc_EventArgs

{

public:

    tsc_String  Response; 


    BtResponse (const tsc_String resp) : Response (resp)

    { }


    void OnInvokeComplete() override

    {

        delete this;

    }

};


// Our Bluetooth device.

class SomeBTDevice : tsc_IRs232StreamMonitor

{

    tsc_Rs232Stream btStream;

    tsc_Rs232PortParameters btStreamParams;

    tsc_String Response;


public:

    tsc_Event  CommandCompleted;

    tsc_Event  Connected;


    bool Open(const char* port, tsc_String result)

    {

        result = "";


        btStreamParams.Port = port;

        tsc_IRs232StreamMonitor::Start (btStream);


        if (!btStream.Open (btStreamParams))

        {

            result = tsc_String(">>> Failed to open port ", btStreamParams.Port.c_str());

            return false;

        }

        return true;

    }


    void SendCommand (const tsc_String& command)

    {

        Response = "";

        btStream.Write ((unsigned char*) command.Characters(), command.Length());

    }


    void Close()

    {

        if (btStream.IsOpen())

        {

            tsc_IRs232StreamMonitor::Stop (btStream);

            btStream.Close();

        }

    }



    // =================================== tsc_IRs232StreamMonitor overrides


    void OnDataReceived (long bytes) override

    {

        unsigned char* buff = new unsigned char[bytes + 1];

        long br = btStream.Read (buff, bytes);

        buff[br] = '\0';

        Response += (char*)buff;

        delete [] buff;


        if (true /* Or some condition that signifies a complete response in the received data...*/)

        {

            CommandCompleted.Invoke(this, new BtResponse(Response));

        }

    }


    void OnPortOpened () override

    {

        if (btStream.IsConnected())

        {

            Connected.Invoke (this, nullptr);

        }

    }

};




class BluetoothForm : public tsc_Form

{

public:


    tsc_DropDownPortListField* _portField = nullptr;

    tsc_IntegerField*   _lenField = nullptr;

    tsc_StringField*    _commandField = nullptr;

    tsc_StringField*    _responseField = nullptr;

    tsc_SoftkeyControl* _skConnect = new tsc_SoftkeyControl(X_SoftkeyConnect);

    tsc_SoftkeyControl* _skSend  = new tsc_SoftkeyControl(X_SoftkeySend);

    tsc_SoftkeyControl* _skClose = new tsc_SoftkeyControl(X_SoftkeyClose);


    SomeBTDevice   btDevice;


    tsc_EventDelegate (CommandCompleted, BluetoothForm);

    tsc_EventDelegate (Connected, BluetoothForm);


    BluetoothForm()

    {

        this->Text(PX_HelloWorld);        // Form title

        this->SetSizing(Size_Normal);


        tsc_StringList btThings {"BLUETOOTH*", ""}; 

        _portField = new tsc_DropDownPortListField (X_Port, btThings, tsc_String(""));

         this->Controls.Add(_portField);


         _commandField = new tsc_StringField(PX_Command, "");

         _commandField->AllowEmpty (true);

         this->Controls.Add(_commandField);


         this->Controls.Add(new tsc_LineBreakControl);


         _responseField = new tsc_StringField(PX_Response, "");

         _responseField->AllowEmpty (true);

         this->Controls.Add(_responseField);


        _lenField = new tsc_IntegerField (PX_BytesReceived, 0);

        _lenField->AllowEmpty (true);

         this->Controls.Add(_lenField);


        this->Controls.Add(_skConnect);

        this->Controls.Add(_skSend);

        this->Controls.Add(_skClose);


        _skSend->SetVisible (false);

        _skClose->SetVisible (false);


        CommandCompleted.Bind(this);

        Connected.Bind(this);

    }


    void OnLoad () override

    {

        // Wire up events to call `OnConnected` and `OnCommandCompleted`.

        btDevice.Connected += Connected;

        btDevice.CommandCompleted += CommandCompleted;  

    }


    virtual ~BluetoothForm()

    {

        btDevice.Close();

        btDevice.CommandCompleted -= CommandCompleted;

        btDevice.Connected -= Connected;

    }


    virtual bool OnSoftkeyClick (x_Code softkey) override

    {

        tsc_String result;


        switch (softkey)

        {

            case X_SoftkeyConnect:

            {

                tsc_SurveyCore::StatusMessage (X_OpeningConnection, 5);


                if (!btDevice.Open(_portField->SelectedItem(), result))

                {

                    _lenField->Value (0);

                    _responseField->Value (">> Open failed: " + result);

                    tsc_SurveyCore::StatusMessage (X_ConnectFailure, 5);

                }

                break;

            }


            case X_SoftkeySend:

            {

                if (_commandField->Value().IsEmpty())

                {

                    tsc_MessageBox::Show (

                        "Whoops",

                        "Enter something into the Command field before hitting Send (BTW, \\n works)");

                    break;

                }

                _responseField->Value("");

                _lenField->Value(0);

                btDevice.SendCommand (_commandField->Value().Replace("\\n", "\n", 0));

                _commandField->Value("");

                break;

            }


            case X_SoftkeyClose:

            {

                btDevice.Close ();

                _skConnect->SetVisible (true);

                _skSend->SetVisible (false);

                _skClose->SetVisible (false);

                break;

            }

            default:

                return false;

        }

        return true;

    }


    bool OnFormClosing (tsc_DialogResult result, bool formIsModified, tsc_FormClosingPermission& permission) override

    {

        return true;

    }


    // Read completion event from btDevice.

    void OnCommandCompleted (void*, tsc_EventArgs* args)

    {

        tsc_String response = (dynamic_cast<BtResponse*> (args))->Response;


        _responseField->Value (response);

        _lenField->Value (response.Length());

    }


    void OnConnected (void*, tsc_EventArgs* ) 

    {

        _skConnect->SetVisible (false);

        _skSend->SetVisible (true);

        _skClose->SetVisible (true);

    }


};


// This function could, for instance, be called from a tsc_UITask...

extern void RunBluetoothTest()

{

    BluetoothForm f;

    f.ShowDialog();

}