/// <summary>
        /// Primary function used to query the belt configuration
        /// </summary>
        /// <param name="typeMsg">Type of query: 
        /// "QRY ALL\r" | "QRY RHY\r" | "QRY MAG\r" | "QRY MTR\r" | "QRY SPT\r" 
        /// | "QRY VER\r"</param>
        /// <param name="timeout">Time allowed to recieve data on incoming 
        /// serial COM port before processing buffer</param>
        /// <returns>error code resulting from Query command</returns>
        private error_t Query(string typeMsg, int timeout)
        {
            error_t return_error = error_t.EMAX;

            clearBuffer(qry_resp);

            //Send the QRY command if ports are setup
            try {
                return_error = change_acmd_mode(acmd_mode_t.ACM_LRN);

                if (return_error == error_t.ESUCCESS) {
                    // Send command with wait time for belt to respond back.
                    return_error = SerialPortWriteData(typeMsg, timeout);

                    //read responses from Serial_Port and place RSP lines into string array
                    if (return_error == error_t.ESUCCESS) {
                        string[] buffer;

                        //Removes the '\r\n' characters
                        char[] delimiters = new char[] { '\r', '\n' }; //, ' '
                        //CANNOT USE REGEX in CF 2.0
                        //buffer = Regex.Split(serialIn.MsgInBuffer, "\r\n");
                        buffer = ByteToAscii(serialIn.DataRecvBuffer()).Split(delimiters);
                        int rsp_index = 1;

                        // Formats buffer into string array so each RSP line is an element and removes "\r"
                        for (int i = 0; i < buffer.Length; i++) {
                            //Ignore non RSP lines
                            if (buffer[i].Length >= 3) {
                                if (buffer[i].Substring(0, 3).Equals("RSP")) {
                                    qry_resp[rsp_index] = buffer[i];
                                    rsp_index++;
                                }
                                else if (buffer[i].Substring(0, 3).Equals("DBG")) {
                                    // Not yet implemented
                                    //string[] split = buffer[i].Split(' ');
                                    //sys_error = (error_t)split[1][0]; // get char at index 0
                                }
                            }
                        }
                        rsp_index--; // decrement from last increment to give count of elements
                        qry_resp[0] = rsp_index.ToString(); //count of elements
                    }
                }
            }
            catch (Exception e) {
                qry_resp[0] = "0";
                return_error = error_t.EXCQRYCMD;
            }
            _dll_error = return_error;
            return return_error;
        }
        /*
         * Method switches the global mode
         */
        private error_t change_glbl_mode(mode_t mode)
        {
            error_t return_error = error_t.EMAX;

            if (_glbl_mode == mode) {
                // already in requested mode, do nothing and no loss of performance
                _belt_error = error_t.ESUCCESS; // already in requested mode
                return_error = _belt_error;
            }
            else if (mode == mode_t.M_ACTIVE) {
                //switch to activate command mode
                return_error = SerialPortWriteData("BGN\n", MAX_RESPONSE_TIMEOUT);

                if (return_error == error_t.ESUCCESS)
                    _glbl_mode = mode_t.M_ACTIVE;
            }
            else { //if (_glbl_mode == mode_t.M_ACTIVE)
                // back to learning mode
                byte[] returnState = { 0x30, 0x30 }; //should send Hex 0x30 0x30 = mode 0
                return_error = SerialPortWriteData(returnState, MAX_RESPONSE_TIMEOUT);

                if (return_error == error_t.ESUCCESS)
                    _glbl_mode = mode_t.M_LEARN;
            }
            _dll_error = return_error;
            return return_error;
        }
        /*
         * Function is used to get status from belt after each send or receive
         */
        private void checkBeltStatus(acmd_mode_t acmd_mode)
        {
            error_t error = error_t.EMAX;

            // .NET SerialPort.ReadLine() results in \r\n
            // BUT YOU CAN ONLY SEE "\n" WHEN DIRECTLY LISTENING TO PORT
            //if (serialIn.MsgInBuffer.Equals("STS 0\r\n") || serialIn.MsgInBuffer.Equals("53 54 53 20 30 0D 0A "))

            if (acmd_mode == acmd_mode_t.ACM_LRN) {
                char[] delimiters = new char[] { '\r', '\n', ' ' };
                string[] split = ByteToAscii(serialIn.DataRecvBuffer()).Split(delimiters);
                for (int i = 0; i < split.Length; i++) {
                    if (String.Equals(split[i], "STS")) {
                        byte[] errors = IntegerStrToByte(split[i + 1]); // gets first error code
                        error = (error_t)(errors[0]);
                    }
                }
            }
            // Otherwise the error code is returned as a hex digit without '\n'
            else if (acmd_mode == acmd_mode_t.ACM_VIB) {
                error = (error_t)(serialIn.DataRecvBuffer()[0]);
            }
            else { ; }//do nothing
            _belt_error = error;
        }
        /// <summary>
        /// Function is used to STOP vibration of all motors on the haptic belt
        /// </summary>
        /// <returns>error code resulting from Stop Vibrate command</returns>
        public error_t StopAll()
        {
            error_t return_error = error_t.EMAX;
            int motorCount = this.getMotors(QueryType.PREVIOUS);

            // Assumes that QRY has already occured in order to activate motors
            if (motorCount != 0) {
                for (byte i = 0; i < motorCount; i++) {
                    // sending rhythm_cycles = 0 stops motor
                    return_error = Vibrate_Motor(i, 0x0, 0x0, 0x0);
                }
            }
            else {
                return_error = _belt_error;
            }
            _dll_error = return_error;
            return return_error;
        }
        /*
         * This method is used to change the mode of the application
         * as the firmware mode is changed.  The application and the
         * firmware modes must stay synchronized.
         */
        private error_t change_acmd_mode(acmd_mode_t mode)
        {
            error_t return_error = error_t.EMAX;

            if (_acmd_mode == mode) {
                _belt_error = error_t.ESUCCESS; // already in requested mode
                return_error = _belt_error;
            }
            else if (mode == acmd_mode_t.ACM_LRN) {
                //return to learning mode
                return_error = change_glbl_mode(mode_t.M_LEARN);
                if (return_error == error_t.ESUCCESS) {
                    _acmd_mode = mode;
                }
            }
            else { //(mode == acmd_mode_t.ACM_VIB || acmd_mode_t.ACM_SPT || acmd_mode_t.ACM_GCL)
                return_error = change_glbl_mode(mode_t.M_ACTIVE);
                if (return_error == error_t.ESUCCESS) {
                    _acmd_mode = mode;
                }
            }
            _dll_error = return_error;
            return return_error;
        }
        /// <summary>
        /// Closes all COM ports in use for the wireless haptic belt.
        /// </summary>
        public error_t ClosePorts()
        {
            error_t error = error_t.COMPRTOPEN;

            if (serialIn != null && serialOut != null) {
                error = serialIn.ClosePort();
                if (_portInName != _portOutName)
                    error = serialOut.ClosePort();
            }
            // Reset mode variables & state machine
            _glbl_mode = mode_t.M_LEARN;
            _acmd_mode = acmd_mode_t.ACM_LRN;

            _dll_error = error;
            return error;
        }
        /// <summary>
        /// Function is used to STOP vibration of a specific motor on the haptic belt
        /// </summary>
        /// <param name="motor_number"></param>
        /// <returns>error code resulting from Stop Vibrate command</returns>
        public error_t Stop(byte motor_number)
        {
            error_t return_error = error_t.EMAX;

            if (motor_number < 0) {
                return_error = error_t.ENOMOTOR;
            }
            else {
                // sending rhythm_cycles = 0 stops motor
                return_error = Vibrate_Motor(motor_number, 0x0, 0x0, 0x0);
            }
            _dll_error = return_error;
            return return_error;
        }
        /// <summary>
        /// Reset haptic belt and driver to the default states if any erroneous 
        /// states occur in DLL or belt.  This is an attempt to regain control
        /// to a known state.
        /// </summary>
        /// <param name="resetComPorts">Set if you want to reset the connection</param>
        /// <returns>error code resulting from the reset</returns>
        public error_t ResetHapticBelt(bool resetComPorts)
        {
            //Reset Com Ports
            if (resetComPorts) {
                _dll_error = ClosePorts();
                System.Threading.Thread.Sleep(1000); //must use Sleep for Windows
                _dll_error = OpenPorts();
            }

            //Reset Belt's mode
            _dll_error = change_acmd_mode(acmd_mode_t.ACM_LRN);

            return _dll_error;
        }
        /// <summary>
        /// Send binary data (byte array) to the outgoing serial COM port
        /// </summary>
        /// <param name="data"></param>
        /// /// <param name="responseTimeout">Time allowed to recieve data on incoming 
        /// serial COM port before processing buffer</param>
        /// <returns>error code resulting from sending the binary data</returns>
        public error_t SerialPortWriteData(byte[] data, int responseTimeout)
        {
            error_t error = error_t.COMPRTWRITE;

            if (!port_setup)
                error = error_t.COMPRTSETUP;
            else if (!serialOut.IsOpen())
                error = error_t.COMPRTNOTOPEN;
            else {
                error = serialOut.WriteData(data);
                if (error == error_t.ESUCCESS) {
                    //get response from belt
                    error = serialIn.ReceiveData(SerialPortManager.DataType.Hex, responseTimeout);
                    if (error == error_t.ESUCCESS) {
                        checkBeltStatus();
                        error = _belt_error;
                    }
                }
            }
            _dll_error = error;
            return error;
        }
        /// <summary>
        /// This function returns the firmware version from the specified QRY operation
        /// </summary>
        public string getVersion(QueryType query_type)
        {
            string return_value = "";
            error_t return_error = error_t.NOTFOUND;

            // Query configuration data from belt
            return_error = QuerySelect("QRY VER\r", query_type);

            // Search and process data
            if (return_error == error_t.ESUCCESS) {

                return_error = error_t.NOTFOUND;
                try {
                    for (int index = 1; index < qry_resp.Length; index++) {
                        if (qry_resp[index] != null) {
                            string[] split = qry_resp[index].Split(' ');

                            //put the values from the response into the return string
                            if (split[1].Equals("VER")) {
                                return_value = split[2];
                                return_error = error_t.ESUCCESS;
                                break; // exit loop
                            }
                        }
                    }
                }
                catch {
                    return_error = error_t.EXCDATASEARCH;
                }
            }
            _dll_error = return_error;
            return return_value;
        }
        /// <summary>
        /// Opens the COM ports if they have already been setup using SetupPorts().
        /// </summary>
        public error_t OpenPorts()
        {
            error_t error = error_t.COMPRTNOTOPEN;

            if (port_setup) {
                // this.DataRecievedFxn is already Method = {Void MethodName()} from parent class
                if (DataReceivedFxn != null) {
                    // serialIn.DataRecievedFxn becomes Method = {Void Invoke()}
                    serialIn.DataReceivedFxn += new SerialPortManager.DataRecievedHandler(DataReceivedFxn);
                }
                error = serialIn.OpenPort();
                if (_portInName != _portOutName)
                    error = serialOut.OpenPort();

                // Send  Use HEX 0x0A for newline to signal to belt "End of Transmission"
                // In case the belt is in an unknown byte count or state
                // expect COM port read timeout since nothing should be returned
                byte[] test = { 0x0A }; // == '\n'
                error_t status = SerialPortWriteData(test, 10);
            }
            _dll_error = error;
            return error;
        }
        /// <summary>
        /// This function returns the motor count from the specified QRY operation
        /// </summary>
        public byte getMotors(QueryType query_type)
        {
            byte return_values = 0;

            error_t return_error = error_t.NOTFOUND;

            // Query configuration data from belt
            return_error = QuerySelect("QRY MTR\r", query_type);

            // Search and process data
            if (return_error == error_t.ESUCCESS) {

                return_error = error_t.NOTFOUND;
                try { //Convert.ToInt16 can cause exception
                    for (int index = 1; index < qry_resp.Length; index++) {
                        if (qry_resp[index] != null) {
                            string[] split = qry_resp[index].Split(' ');

                            //put the values from the response into the return array
                            if (split[1].Equals("MTR")) {
                                string motor_count = split[2]; // gets motor number string
                                return_values = (byte)Convert.ToByte(motor_count);
                                return_error = error_t.ESUCCESS;
                                break; // exit loop
                            }
                        }
                    }
                }
                catch {
                    return_error = error_t.EXCDATASEARCH;
                }
            }
            _dll_error = return_error;
            return return_values;
        }
 /// <summary>
 /// Accessor method that returns the error code message for a particular error code.
 /// </summary>
 public string getErrorMsg(error_t error_code)
 {
     return "Code: " + (int)error_code + " " + Constants.error_t_names[(int)error_code];
 }
        /// <summary>
        /// 
        /// </summary>
        /// <returns>error code resulting from Erase All command</returns>
        public error_t Erase_All()
        {
            error_t return_error = error_t.EMAX;

            try {
                return_error = change_acmd_mode(acmd_mode_t.ACM_LRN);

                if (return_error == error_t.ESUCCESS) {
                    // Send command with wait time for belt to respond back.
                    return_error = SerialPortWriteData("ZAP 1 2 3\n", MAX_RESPONSE_TIMEOUT); // requires 3 arguments
                }
            }
            catch {
                qry_resp[0] = "0";
                return_error = error_t.EXCZAPCMD;
            }
            _dll_error = return_error;
            return return_error;
        }
        private error_t QuerySelect(string msg, QueryType query_type)
        {
            error_t return_error = error_t.NOTFOUND;

            // Query configuration data from belt
            if (query_type == QueryType.SINGLE)
                return_error = Query(msg, MAX_RESPONSE_TIMEOUT);
            else if (query_type == QueryType.ALL)
                return_error = Query("QRY ALL\r", MAX_RESPONSE_TIMEOUT);
            else // No query - DLL data structure already populated from recent QRY
                return_error = error_t.ESUCCESS;

            _dll_error = return_error;
            return return_error;
        }
        /// <summary>
        /// Initializes the Serial COM ports
        /// </summary>
        /// <param name="portInName">COM port number used for recieving data, ie "COM8"</param>
        /// <param name="portOutName">COM port number used for sending data, ie "COM8"</param>
        /// <param name="baud">baud rate of connection</param>
        /// <param name="dBits">number of data bits to be sent at a time </param>
        /// <param name="sBits">stop bits to be used (0, 1, 1.5, 2)</param>
        /// <param name="par">parity bits to be used (None, Odd, Even, Mark, Space)</param>
        /// <param name="timeout">specifies the default timeout for sending/recieving data</param>
        /// <returns>error code resulting from COM port setup</returns>
        public error_t SetupPorts(string portInName, string portOutName, string baud, string dBits, string sBits, string par, int timeout)
        {
            error_t error = error_t.COMPRTSETUP;

            // validate parameters
            if (portInName == null || portOutName == null || baud == null || dBits == null
                || sBits == null || par == null || timeout == 0) {

                error = error_t.COMPRTINVALID;
            }
            _portInName = portInName;
            _portOutName = portOutName;

            try {
                // Set default Port Manager parameters
                serialIn = new SerialPortManager(portInName, baud, dBits, sBits, par, timeout);
                serialIn.EchoBack = true;

                if (portInName != portOutName) {
                    serialOut = new SerialPortManager(portOutName, baud, dBits, sBits, par, timeout);
                }
                else serialOut = serialIn;

                port_setup = true;
                error = error_t.ESUCCESS;
            }
            catch {
                //error = error_t.COMPRTSETUP; // already default
            }
            _dll_error = error;
            return error;
        }
        /// <summary>
        /// Primary function used to vibrate motors - send a bit string command
        /// </summary>
        /// <returns>error code resulting from Vibrat Motor command</returns>
        private error_t Vibrate_Motor(acmd_mode_t cmd_mode, byte motor, byte rhythm, byte magnitude, byte rhythm_cycles)
        {
            byte[] command_byte = { 0x00, 0x00 };
            error_t return_error = error_t.EMAX;

            // Validate parameters
            if (motor < 0 || rhythm < 0 || rhythm > 8
                || magnitude < 0 || magnitude > 8
                || rhythm_cycles < 0 || rhythm_cycles > 7) {

                return_error = error_t.EARG;
            }
            else {
                byte mode = 0x0;
                //byte motor = 0x0; // this is the first valid motor
                //byte rhythm = 0x7; //rhy H =7
                //byte magnitude = 0x0; //mag A = 0
                //byte rhythm_cycles = 0x6;
                // This equates to hex command < 01 36 >

                try {
                    return_error = change_acmd_mode(cmd_mode);

                    if (return_error == error_t.ESUCCESS) {
                        mode = (byte)cmd_mode;

                        // Send mode first, it is the LSB of the first byte in firmware struct active_command_t
                        command_byte[0] = (byte)((mode << 4) | (motor & 0xf));
                        // Send rhythm first, it is the LSB of the firmware struct vibration_t
                        command_byte[1] = (byte)(((rhythm & 0x7) << 5)
                            | ((magnitude & 0x3) << 3)
                            | (rhythm_cycles & 0x7));

                        return_error = SerialPortWriteData(command_byte, MAX_RESPONSE_TIMEOUT);

                        // BROWN OUT HANDLING - Error from sending msg can return odd
                        // error code if belt is currently in ACM.LRN.  Reasonable risk that
                        // this will not occur when main controller is running on battery.
                        // error = 0xFC = 252 is from brown out condition
                        if (return_error > error_t.NOTFOUND) {

                            return_error = ResetHapticBelt();//error_t.ELOWPOWER;

                            // proceed for expected behavior of readtimeout
                            if (return_error == error_t.ESUCCESS)
                                //Try again with recursive call
                                return_error = Vibrate_Motor(cmd_mode, motor, rhythm, magnitude, rhythm_cycles);
                        }
                    }
                }
                catch (Exception e) {
                    return_error = error_t.EXCVIBCMD;
                }
            }
            _dll_error = return_error;
            return return_error;
        }
Пример #18
0
 public string getErrorMsg(error_t status)
 {
     return wirelessBelt.getErrorMsg(status);
 }