Shop OBEX P1 Docs P2 Docs Learn Events
RN-42 Bluetooth mldule and Java — Parallax Forums

RN-42 Bluetooth mldule and Java

ValeTValeT Posts: 308
edited 2014-09-28 05:30 in General Discussion
I am going to try to get the RN-42 - I still got to get the RN-42 Bluetooth module :), but it's coming - to talk to my Windows PC over Bluetooth. I will be using one of Java's many Bluetooth libraries to communicate to the ActivityBoard using the built in Bluetooth module in my computer, but am new to this and would like some help.

Since this is my first time going to be using the RN-42 module, does anyone have any tips or pointers? I am new to using Java with Bluetooth as well, so if someone could give me a link to a great Java Bluetooth tutorial they have found in the past, that would be much appreciated!
«1

Comments

  • RS_JimRS_Jim Posts: 1,766
    edited 2014-08-18 05:49
    Vale,
    Check out the forum at propellar powered, I think Jeff has done some stuff with Bluetooth.
    Jim
  • Martin_HMartin_H Posts: 4,051
    edited 2014-08-18 06:12
    One possible gotcha. If the RN-42 module is like the other Bluetooth modules I've used, it appears as a serial port on the host computer. Java doesn't have built in support for serial ports and requires a module called libRxTx. This module has the required native method calls to the host OS's serial API's. It works fine on Linux, Mac OS, and Windows 32 bit, but I've never gotten it to work on 64 bit Windows. I've tried several different builds of the library and all of them can enumerate the serial ports, but none can read from the port. So for my serial port work on 64 bit Windows I switched to C# which has built in support for COM ports on Windows.

    If you are a 64 bit Windows user and you get libRxTx working I'd love to know what you did.
  • ValeTValeT Posts: 308
    edited 2014-08-18 08:11
    RS_Jim,

    thanks. I will check it out and see what I can find out.


    Martin_H,

    I think I have miscommunicated my message. I would like to have the ActivityBoard as a standalone device and have Java use my computer's built in Bluetooth module. I would like to use Java to force pair with the ActivityBoard and send some simple characters such as 'A', 'B', etc.

    Have either of you completed a project dealing with Bluetooth?
  • Martin_HMartin_H Posts: 4,051
    edited 2014-08-18 09:34
    ValeT wrote: »
    Martin_H,

    I think I have miscommunicated my message. I would like to have the ActivityBoard as a standalone device and have Java use my computer's built in Bluetooth module. I would like to use Java to force pair with the ActivityBoard and send some simple characters such as 'A', 'B', etc.

    Have either of you completed a project dealing with Bluetooth?

    Yes I have. I used an eBay Bluetooth module with my BS2 and paired it with my PC's Bluetooth adapter. When I did that the Bluetooth module appeared as a COM port on my PC. I then opened the COM port with my PC program to read/wrote data to it. On the BS2 side I used two pins with the SERIN and SEROUT commands. The actual program was a remote control which used single letter commands to start/stop the drive wheels.

    The pairing of a Bluetooth module and the PC is handled by the underlying OS, not Java. How that module is presented to the rest of the OS depends upon the capabilities of the Bluetooth device paired. Most of these Bluetooth modules used with microcontrollers are designed to appear as serial ports. That's why I mentioned libRxTx, Java, and a potential gotcha on 64 bit Windows.
  • ValeTValeT Posts: 308
    edited 2014-08-18 10:07
    Martin_H wrote: »
    Yes I have. I used an eBay Bluetooth module with my BS2 and paired it with my PC's Bluetooth adapter. When I did that the Bluetooth module appeared as a COM port on my PC. I then opened the COM port with my PC program to read/wrote data to it. On the BS2 side I used two pins with the SERIN and SEROUT commands. The actual program was a remote control which used single letter commands to start/stop the drive wheels.

    The pairing of a Bluetooth module and the PC is handled by the underlying OS, not Java. How that module is presented to the rest of the OS depends upon the capabilities of the Bluetooth device paired. Most of these Bluetooth modules used with microcontrollers are designed to appear as serial ports. That's why I mentioned libRxTx, Java, and a potential gotcha on 64 bit Windows.

    Oh, ok. I see what you are saying.

    Do you think then that it would be better to try to write C code to do this then?

    I would not run into any problems because C supports this, right?
  • Martin_HMartin_H Posts: 4,051
    edited 2014-08-18 10:26
    ValeT wrote: »
    Oh, ok. I see what you are saying.

    Do you think then that it would be better to try to write C code to do this then?

    I would not run into any problems because C supports this, right?

    There would be no problems in C because that can call the host OS directly and use the Windows API's directly. Although you might have better luck getting Java to work than me.

    BTW Here's a debugging tip. It will be a pain to debug your PC program and your Activity Board client at the same time. So do them separately. Use the Parallax serial terminal to open the COM port and send commands directly to the Activity Board. Once you get that working completely write the PC program which sends those commands. That way you can debug each part of the system in isolation.
  • ValeTValeT Posts: 308
    edited 2014-08-18 17:30
    Martin_H,

    Thanks for the tip! I will work on this tomorrow, and keep you all posted.

    I am going to have to learn C++ then........Does anyone have any good tutorials/example programs I can learn from :)?
  • Martin_HMartin_H Posts: 4,051
    edited 2014-08-18 18:42
    I don't have a C++ serial port example, but here's a C# example:
    /*
     * Native Windows GUI for Arduino EEPROM programmer
     *
     * Initial author mario, C# port by Martin Heermance. While Mario didn't
     * state a specific license, his text makes clear he was writing OSS, so
     * I'm making if official by using the MIT license.
     * 
     * The MIT License (MIT)
     * Copyright (c) 2014 Mario and Martin Heermance
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy
     * of this software and associated documentation files (the "Software"), to deal
     * in the Software without restriction, including without limitation the rights
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     * The above copyright notice and this permission notice shall be included in
     * all copies or substantial portions of the Software.
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     * THE SOFTWARE.
     */
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.IO.Ports;
    
    namespace JBurn
    {
        public class MySerial
        {
            // Set of serial port properties kept as data members
            private SerialPort _serialPort = new SerialPort();
            private int _dataBits = 8;
            private Handshake _handshake = Handshake.None;
            private Parity _parity = Parity.None;
            private StopBits _stopBits = StopBits.One;
    
            /// <summary>
            /// This class is an argument block used to marshall context from the callback thread to the UI.
            /// </summary>
            public class AsyncContext
            {
                // Set of properties used to marshall anyc context back to the caller.
                public byte[] Data { get; set; }
                public int Offset { get; set; }
                public int Count { get; set; }
                public char Terminator { get; set; }
                public String ResponseText { get; set; }
                public List<byte> ResponseRaw { get; set; }
                public int ResponseSize { get; set; }
                public OnDataRecievedDelegate CallerCallback { get; set; }
            }
    
            // I hate doing this, but the serial API doesn't allow a way to marshall this.
            // So I have to use this to marshall across thread. It should work because
            // a serial port is inherently FIFO and we manage writes by turning off buttons.
            AsyncContext _context;
    
            /// <summary> 
            /// Holds data received until we get a terminator. 
            /// </summary> 
            private string tString = string.Empty;
    
            /// <summary>
            /// static which allows the consumer to populate a dropdown with a list of serial ports.
            /// </summary>
            /// <returns>a string array of serial port names</returns>
            public static string[] getAvailableSerialPorts()
            {
                return System.IO.Ports.SerialPort.GetPortNames();
            }
    
            /// <summary>
            /// A constructor with nothing special about it, but it captures the UI thread
            /// callback context since this object is constructed by the UI thread.
            /// </summary>
            public MySerial()
            {
                syncContext = System.Windows.Threading.DispatcherSynchronizationContext.Current;
            }
    
            /// <summary>
            /// Connects to the named port at the desired baud rate.
            /// </summary>
            /// <param name="portName">the serial port name (e.g. COM4)</param>
            /// <param name="speed">the baud rate</param>
            public void connect(String portName, int speed)
            {
                _serialPort.BaudRate = speed;
                _serialPort.DataBits = _dataBits;
                _serialPort.Handshake = _handshake;
                _serialPort.Parity = _parity;
                _serialPort.PortName = portName;
                _serialPort.StopBits = _stopBits;
                _serialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived);
                _serialPort.Open();
            }
    
            /// <summary>
            /// closes the serial port
            /// </summary>
            public void disconnect()
            {
                if (_serialPort != null)
                {
                    _serialPort.Close(); // close the port
                }
            }
    
            /// <summary>
            /// useful state accessor
            /// </summary>
            /// <returns>true if connected</returns>
            public bool isConnected()
            {
                return (_serialPort != null) && _serialPort.IsOpen;
            }
    
            /// <summary>
            /// Drops any leftover data in order to get a clean read from the port.
            /// </summary>
            public void DiscardInBuffer()
            {
                tString = string.Empty;
                _serialPort.DiscardInBuffer();
            }
    
            /// <summary>
            /// Write accepts text and callsback when a response is received. This is useful
            /// for one shot writing of small blocks of text data.
            /// </summary>
            /// <param name="text">the data to send to the serial port</param>
            /// <param name="terminator">the character which signifies the end of the response</param>
            /// <param name="callback">called when a line of response is recieved</param>
            public void Write(String text, char terminator, OnDataRecievedDelegate callback)
            {
                byte[] data = Encoding.ASCII.GetBytes(text);
                Write(data, 0, data.Length, terminator, 0, callback);
            }
    
            /// <summary>
            /// Write accepts text and callsback when a response is received. It differs from the
            /// above in that there's no terminator to the response. It is fixed length.
            /// </summary>
            /// <param name="text">the data to send to the serial port</param>
            /// <param name="responseSize">the number of bytes in the response</param>
            /// <param name="callback">called when a line of response is recieved</param>
            public void Write(String text, int responseSize, OnDataRecievedDelegate callback)
            {
                byte[] data = Encoding.ASCII.GetBytes(text);
                Write(data, 0, data.Length, '\0', responseSize, callback);
            }
    
            /// <summary>
            /// Write accepts data and calls back when a response is received. This is useful for
            /// writing a large block in chuncks. The user can specify an ofset and count and write
            /// ranges of the data.
            /// </summary>
            /// <param name="data">the data to send to the serial port</param>
            /// <param name="offset">the offset within the buffer to start writing from</param>
            /// <param name="count">the number of bytes to write</param>
            /// <param name="terminator">the character which signifies the end of the response.</param>
            /// <param name="responseSize">the expected size of the response in bytes if there's no terminator.</param>
            /// <param name="callback">called when a line of response is recieved</param>
            public void Write(Byte[] data, int offset, int count, char terminator,
                int responseSize, OnDataRecievedDelegate callback)
            {
                // If the user expects a response, then save all the context parameters.
                if (callback != null)
                {
                    _context = new AsyncContext();
                    _context.Data = data;
                    _context.Offset = offset;
                    _context.Count = count;
                    _context.Terminator = terminator;
                    _context.ResponseText = null;
                    _context.ResponseRaw = new List<byte>();
                    _context.ResponseSize = responseSize;
                    _context.CallerCallback = callback;
                }
    
                _serialPort.Write(data, offset, count);
            }
    
            // Everything below this is gritty Windows async callback stuff.
            // Basically I/O is non-blocking and calls back on a worker thread
            // But it's up to the programmer to marshall the data back to the caller.
    
            /// <summary>
            /// This holds the UI context to enable post message back to the UI thread
            /// </summary>
            private static SynchronizationContext syncContext;
            private static SynchronizationContext Sync
            {
                get { return syncContext; }
            }
    
            /// <summary>
            /// Consumers implement this delegate to be called when their response is available.
            /// Their initial arguments are reflected back to them to allow them to callback with
            /// the next block. This allows chaining a sequence of calls to together to write
            /// large payloads.
            /// </summary>
            public delegate void OnDataRecievedDelegate(AsyncContext context);
    
            /// <summary>
            /// I could use a lambda function to handle this thread break, but I find the
            /// syntax a bear to get correct.
            /// </summary>
            /// <param name="postPayload">the caller's callback method and response</param>
            private static void SimpleDelegateMethod(object postPayload)
            {
                System.Diagnostics.Debug.Assert(postPayload is AsyncContext);
                AsyncContext context = (AsyncContext)postPayload;
                context.CallerCallback(context);
            }
    
            /// <summary>
            /// Called in response to the data write.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                // Initialize a buffer to hold the received data 
                byte[] buffer = new byte[_serialPort.BytesToRead];
    
                // There is no accurate method for checking how many bytes are read 
                // unless you check the return from the Read method 
                int bytesRead = _serialPort.Read(buffer, 0, buffer.Length);
    
                // if the user passed a terminator, then convert to a string.
                if (_context.Terminator != '\0')
                {
                    // Assume the data we are received is ASCII data. 
                    tString += Encoding.ASCII.GetString(buffer, 0, bytesRead);
    
                    if (tString.IndexOf(_context.Terminator) > -1)
                    {
                        // Split the string at the terminator.
                        string[] fields = tString.Split(_context.Terminator);
    
                        // The payload is before the terminator.
                        _context.ResponseText = fields[0];
    
                        // The rest of the string is after the terminator.
                        tString = fields[1];
    
                        // If desired Post the message back to this object to break to the UI thread.
                        if (_context.CallerCallback != null)
                        {
                            Sync.Post(SimpleDelegateMethod, _context);
                        }
                    }
                }
                else
                {
                    _context.ResponseRaw.AddRange(buffer);
                    if (_context.ResponseRaw.Count >= _context.ResponseSize)
                    {
                        Sync.Post(SimpleDelegateMethod, _context);
                    }
                }
            }
        }
    }
    
  • NWCCTVNWCCTV Posts: 3,629
    edited 2014-08-18 18:45
    Does anyone have any good tutorials/example programs I can learn from
    If you are using the free MS version, there are built in tutorials that I find very resourceful.
  • Bob Lawrence (VE1RLL)Bob Lawrence (VE1RLL) Posts: 1,720
    edited 2014-08-18 22:30
    @Martin_H
    user-offline.png
    ]If you are a 64 bit Windows user and you get libRxTx working I'd love to know what you did. /QUOTE

    Are you saying that this library(below) doesn't work on 64 Bit Win? "
    [h=3]win-x86, win-x64, ia64[/h]Fork of the Java RXTX project to primarily provide a compiled native 64-bit package for Windows and Linux. RXTX is a Java native library providing serial and parallel communication for the Java Development Toolkit (JDK). RXTX is licensed under the GNU LGPL license as well as these binary distributions. RXTX is a great package, but it was lacking pre-built binaries for x64 (64-bit) versions of Windows. This project distributes binary builds of RXTX for Windows x64, x86, ia64 and Linux x86, x86_64.

    http://mfizz.com/oss/rxtx-for-java

    Built using Microsoft Visual C++ 2008 - not MinGW. The x86 and x64 versions are native and do not rely on any other non-standard windows libraries. Just drop in the compiled .dlls that are specific to the version of Java you run. If you installed the 64-bit version of the JDK, then install the x64 build. Tested the x86 and x64 versions with Windows 2008, 2003, and Vista SP1.
  • Martin_HMartin_H Posts: 4,051
    edited 2014-08-19 03:36
    Bob, I don't recall if I tried that specific version of libRxTx. I do know I spent two evenings trying both 32 bit and 64 bit versions of Java with their respective versions of libRxTx. I couldn't get any combination to work, but someone else might have better luck than me. All versions could enumerate the serial port, but could not open it. To figure out what was going on I would have had to debug into the native method calls within libRxTx, and for me the path of least resistance was to re-write the Java in C# which I know equally well.
  • mindrobotsmindrobots Posts: 6,506
    edited 2014-08-19 05:19
    There is also JSSC (Java Simple Serial Adapter) - I was playing with this for a short time when I was in my Java phase. I recall having it working with some simple serial comms to a Propeller.
  • ValeTValeT Posts: 308
    edited 2014-08-19 10:19
    Martin_H, thanks for the code. That really helped me get going.

    Mr. Lawerence, I have tried to get that to work, but I am having a lot of trouble controlling the settings for the USB Rx_P30 pin. I have attached a piece of example code that I have been using in NetBeans 8.0. I can receive stuff from my ActivityBoard, but when I send stuff, it comes out as rectangles and circles. Do you know how to fix this? I suspect it is the settings that I am using on the ActivityBoard, but I don't know how to change that.

    mindrobots, thanks for the link with the library. As you can see I am currently working with the other one, but I looked at the code.

    Here is my Java code:
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import gnu.io.*;
    /**
     *
     * @author Vale
     */
    public class SerialApplication {
     
        public void connect( String portName ) throws Exception {
        System.out.println( "IN CONNECT" );
        
        CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier( portName );
        if( portIdentifier.isCurrentlyOwned() ) {
          System.out.println( "Error: Port is currently in use" );
        } else {
          int timeout = 2000;
          CommPort commPort = portIdentifier.open( this.getClass().getName(), timeout );
     
          if( commPort instanceof SerialPort ) {
            System.out.println( "IN ANOTHER PART OF CONNECT" );
            
            SerialPort serialPort = ( SerialPort )commPort;
            serialPort.setSerialPortParams( 115200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE );
     
            InputStream in = serialPort.getInputStream();
            OutputStream out = serialPort.getOutputStream();
     
            ( new Thread( new SerialReader( in ) ) ).start();
            ( new Thread( new SerialWriter( out ) ) ).start();
     
          } else {
            System.out.println( "Error: Only serial ports are handled by this example." );
          }
        }
      }
     
      public static class SerialReader implements Runnable {
     
        InputStream in;
     
        public SerialReader( InputStream in ) {
          System.out.println( "IN SERIALREADER" );
          
          this.in = in;
        }
     
        public void run() {
          System.out.println( "IN ANOTHER PART OF SERIALREADER" );
          
          byte[] buffer = new byte[ 1024 ];
          int len = -1;
          try {
            while( ( len = this.in.read( buffer ) ) != -1 ) {
              System.out.print( new String( buffer, 0, len ) );
            }
          } catch( IOException e ) {
            e.printStackTrace();
          }
        }
      }
     
      public static class SerialWriter implements Runnable {
     
        OutputStream out;
     
        public SerialWriter( OutputStream out ) {      
          this.out = out;
          try {
             out.write( 10 ); 
          }
          catch ( Exception ex ) {
              
          }
        }
     
        public void run() {
          System.out.println( "IN ANOTHER PART OF SERIALWRITER" );
          
          try {
            System.out.println( "IN WRITE METHOD " );
            //this.out.write( 5 );
            //this.out.flush();
            while( true ) {
              System.out.println( "SENDING" );
              this.out.write( 10 );
              this.out.flush();
              Thread.sleep( 1000 );
            }
          } catch( Exception e ) {
            e.printStackTrace();
          }
        }
      }
     
      public static void main( String[] args ) {
        try {
          ( new SerialApplication() ).connect( "COM3" );
        } catch( Exception e ) {
          e.printStackTrace();
        }
      }
    }
    

    Here is my SimpleIDE code:
    #include "simpletools.h"                      // Include simpletools #include "FdSerial.h"
     
    
     int main()                                    // main function
     {
       int button = 0;
       
       print( "MESSAGE SENT FROM ACTIVITYBOARD" );
       
       while(1)                                    // Endless loop
       {
         button = 0;
         button = input(30);              // P3 input -> button variable
         print( input(30) );
         print("button = %d\n", 0);                // Display button state
         pause(1000);                              // Wait 0.1 second before repeat
         print("button = %d\n", 1);
         
         if ( button == 5 )
         {
           exit( 0 );
         }
         
         if ( button == 10 )
         {
           print( "MESSAGE RECIEVED!" );
           high( 8 );
           low( 9 );
         }            
         
         if ( button == 0 )
         {
           print( "BUTTON IS NOT REGISTERING" );
         }    
       }
     }
     
    
     /*#include <stdio.h>
     #include "propeller.h"
     #include "fdSerial.h"
     
    
     //ATTEMPTING TO USE FdSerial.h library; doesn't work :(
     
    
     /* Turn off default serial port driver just for this demo so we can see output on P30
      */
     /*_Driver *_driverlist[] = {
       NULL
     };*/
     
    
     /*
      * putchar must be defined for printf to work
      */
     /*int send(char ch)
     {
         if(ch == '\n') FdSerial_tx('\r');
         FdSerial_tx(ch);
         return ch;
     }
     
    
     /*
      * Using main without args for embedded use.
      * defining FDS_DISABLE_OUTS saves ~500 bytes
      * FdSerial_bin FdSerial_dec FdSerial_hex FdSerial_str etc...
      * are not necessary because we have printf.
      */
     /*int  main(void)
     {
         int ii = 0;
         int hex = 0x1deadbee;
     
    
         FdSerial_start(31,30,0,115200);
         FdSerial_str("\nHello World!\n");
         FdSerial_hex(hex,8);
         for(ii = 0; ii <= 1000; ii++) {
             FdSerial_tx(' ');
             FdSerial_dec(ii);
             if(ii % 10 == 0) {
                 FdSerial_tx('\r');
                 FdSerial_tx('\n');
             }
         }
         while(1) {
             ii = FdSerial_rxcheck();
             if(ii >= 0)
                 FdSerial_tx(ii);
         }
         return 0;
     } */
    

    Some of the statements are debug statements. Just an FYI
  • ValeTValeT Posts: 308
    edited 2014-08-20 05:55
    I feel like I may have confused some people with my past reply. Right now, I am working on testing the serial connection over USB because
    a) I need to get the RN-42 Bluetooth module
    b) I have done some research on how to use the RN-42, and it seems that it appears as a serial port on the computer.

    Does help clear things up?
  • Martin_HMartin_H Posts: 4,051
    edited 2014-08-20 06:24
    ValeT wrote: »
    I feel like I may have confused some people with my past reply. Right now, I am working on testing the serial connection over USB because
    a) I need to get the RN-42 Bluetooth module
    b) I have done some research on how to use the RN-42, and it seems that it appears as a serial port on the computer.

    That's how I do my wireless serial protocol development as well. Basically get the serial protocol working, then make it wireless. That way you only debug one thing at a time.
  • ValeTValeT Posts: 308
    edited 2014-08-20 06:33
    Exactly, that really helps debug errors.

    Do you have any ideas on how to edit the protocols on the ActivityBoard?
  • Bob Lawrence (VE1RLL)Bob Lawrence (VE1RLL) Posts: 1,720
    edited 2014-08-20 07:07
    ValeT wrote: »
    Exactly, that really helps debug errors.

    Do you have any ideas on how to edit the protocols on the ActivityBoard?

    First you need to work on one end at a time and get them working without errors and then combine them.

    For testing you can make a loop back tester. RS-232 Loopback: Connect the TXD pin to the RXD pin
    Then on the PC you can use a serial terminal program such as Putty for testing. Once you get that end working without errors you can start on the other end.

    http://www.ni.com/white-paper/3450/en/

    On you PC go to the device drivers >> serial Ports and check the serial port properties(ensure the baud rate is set high enough)

    Also, in your PC code I didn't see any flow control. . I always add it even if it's not used.(just a good habit so you don't forget when it's needed)

    try { serialPort.setFlowControlMode( // SerialPort.FLOWCONTROL_NONE);
    For the activity board side >> I use SPIN and Asm for the Propeller so I'm not setup to test the C code . Jazzed can help you out if he pop's by.
  • Martin_HMartin_H Posts: 4,051
    edited 2014-08-20 07:36
    For both the BS2 and the Propeller I often set up two serial ports from my microcontroller to the host PC. One is the debug serial port where I output debug statements. The other is the command serial port that I'll use to send and receive commands for the protocol I'm developing. On the PC side I'll have a PuTTY window and Parallax Serial terminal up side by side. It's a bit akward, but it seems to work.

    An interactive language (e.g. Forth) simplifies this process because the built in read eval print loop (REPL) is the protocol your PC side program will invoke when the protocol is complete.
  • ValeTValeT Posts: 308
    edited 2014-08-20 08:13
    Thanks for all of the help!

    I am testing your theories and will post my results within the next day. BTW, the FlowControl statement didn't do anything when I added that into my code. I also changed the port Baud rates, but that didn't do anything.

    Attached are pictures of my current results when I run the Java code in NetBeans and when I use Putty. Neither of them have changed.
    347 x 174 - 4K
    162 x 329 - 6K
  • ValeTValeT Posts: 308
    edited 2014-08-22 07:17
    So, after debugging this for a couple of days, I have solved one of the issues. It turns out, the circle and squares problem happened because when I was reading in information, I was reading in bytes. When I got rid of the buffer variable in my java code, I saw the ASCII value of the data. I have changed from inputting data with the input( PIN ) command to using the fdserial_rxChar( PIN ) command.

    Currently, when I run the program, I get random numbers back. I can't figure out why this is happening. Does anyone have any idea?

    Would someone mind debugging my program and testing it? I have attached my current code below.
    package serialapplication; //setting package program belongs to
    import java.io.IOException; //importing libraries
    import java.io.InputStream;
    import java.io.OutputStream;
    import gnu.io.*;
    /**
     *
     * @author Vale
     */
    public class SerialApplication {
        private String inputvalue = ""; //variable that WILL hold data that comes in from activityboard
     
        public String getIncomingMessage() { //returning the info that the activityboard has sent
            return inputvalue;
        }
        public void connect( String portName ) throws Exception { //method to connect to the activityboard
        System.out.println( "Connecting...." );
        
        CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier( portName ); //getting actual port name
        if( portIdentifier.isCurrentlyOwned() ) { //if some other process is using the port
          System.out.println( "Error: Port is currently in use" ); //cancel connecting and exit programs
          System.exit( 0 );
        } else { //if port is not in use
          int timeout = 2000;
          CommPort commPort = portIdentifier.open( this.getClass().getName(), timeout ); //open the port
     
          if( commPort instanceof SerialPort ) { //if commPort is successfully opened
            System.out.println( "Connected!" );
              
            SerialPort serialPort = ( SerialPort )commPort;
            serialPort.setSerialPortParams( 115200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE ); //setting port parameters
            
            try { //setting flow control
                serialPort.setFlowControlMode( SerialPort.FLOWCONTROL_NONE );
            }
            catch( Exception ex ) {
            }
     
            InputStream in = serialPort.getInputStream(); //creating input and output streams for info coming in and leaving through port
            OutputStream out = serialPort.getOutputStream();
     
            ( new Thread( new SerialReader( in ) ) ).start(); //creating new thread to read in info from activityboard
            ( new Thread( new SerialWriter( out ) ) ).start(); //creating new thread to write out info to activityboard
     
          } else { //commPort was not successfully opened
            System.out.println( "Error: Only serial ports are handled by this example." );
          }
        }
      }
     
      public static class SerialReader implements Runnable {
        InputStream in; //creating inputstream
     
        public SerialReader( InputStream in ) { //constructor     
          this.in = in;
        }
     
        public void run() {
          int len = -1; //setting input to -1
          try {
            while( true ) {
              len = this.in.read(); //reading in info from activityboard
              if ( len > 0 ) { //while info came in over serial port
                  if ( len != 95 ) { //if character inputed doesn't equal _ ( which means new line )
                    System.out.print( returnstringvalue( len ) );
                  } else { //if inputed is _
                    System.out.println();
                  }
                  
                  //System.out.println( len );
              }
            }
          } catch( IOException e ) {
            e.printStackTrace();
          }
        }
      }
     
      public static class SerialWriter implements Runnable {
     
        OutputStream out; //creating outputstream
     
        public SerialWriter( OutputStream out ) { //contructor    
          this.out = out;
        }
     
        public void run() {     
          try {
            byte[] values = new byte[1024];
            values[0] = 'C';
            while( true ) {
              this.out.write( values[0] ); //currently, only writing 10 to the ActivityBoard
              //Thread.sleep( 1000 );
            }
          } catch( Exception e ) {
            e.printStackTrace();
          }
        }
      }
      
      public static char returnstringvalue( int len ) {
         char[] ASCIIStringValue = { ' ', '!', '"', '#', '$', '%', '&', '-', '-', '-', '*', '+', '-', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '-', ']', '^', '_', '-', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|' };
         char value = '|';
         
         for ( int i = 0; i <= 92; i++ ) {
             if ( i + 32 == len ) {
                 value = ASCIIStringValue[i];
             }
         }
         
         return value;
      }
     
      public static void main( String[] args ) {
        try {
          ( new SerialApplication() ).connect( "COM3" );
        } catch( Exception e ) {
          e.printStackTrace();
        }
      }
    }
    
    #include "simpletools.h" //Importing/Including libraries 
    #include "fdserial.h"
     
    
    
    
     
    
    fdserial *comp1; //Creating serial port variable
     
    
    
    
     
    
    int main() //Main method declaration
     
    
    {
     
    
      comp1 = fdserial_open(31, 30, 0, 115200);
     
    
      
     
    
      //pause(5000); //Pausing for 5 seconds
     
    
      //dprint(comp1, "_Hi_Talking to you from the activityboard!"); //Sending data over the serial port to the computer
     
    
      //pause(1000); //Pausing for another second
     
    
      //dprint(comp1, "_How is it going?"); //Sending data over the serial port to the computer
     
    
      
     
    
      char c[1000];
     
    
      
     
    
      //dprint( comp1, fdserial_rxChar( comp1 ) );
     
    
      
     
    
      for ( int i = 0; i < 1000; i++ ) {
     
    
        c[i] = fdserial_rxChar( comp1 );
     
    
        
     
    
        pause( 100 );
     
    
        
     
    
        if ( c[i] == "16" ) {
     
    
          exit( 0 );
     
    
          dprint( comp1, "_INFO RECIEVED" );
     
    
        }   
     
    
        
     
    
        dprint( comp1, c[i] );   
     
    
      }    
     
    
    }
    
  • Martin_HMartin_H Posts: 4,051
    edited 2014-08-22 08:42
    I don't have time to debug this, but I can spot one problem right away in this code:
        if ( c[i] == "16" ) {
     
          exit( 0 );
     
          dprint( comp1, "_INFO RECIEVED" );
        }
    

    c is a char array and you are comparing a single character to the string "16". That will never be true. I'm also not sure about the definition of dprint, but you need to ensure it's expecting a character because that's what you are giving it.
  • ValeTValeT Posts: 308
    edited 2014-08-22 09:53
    Martin_H,

    Thanks, but it didn't fix the problem. Do you think anything could be wrong on the Java side of the code?
  • Martin_HMartin_H Posts: 4,051
    edited 2014-08-23 05:23
    I read through the Java but nothing jumped out at me. I think you're trying to solve too many problems at once. What I would do is write a propeller program that wrote data to the serial port. I would then focus on getting the Java program to read it. I would then have a propeller program try to read data and echo it back. I would debug it using Parallax serial terminal. Finally I would focus on Java writing to the serial port, the prop echos, then Java reads.

    The sort of problems are way to difficult to debug if you try to do everything at once.
  • ValeTValeT Posts: 308
    edited 2014-08-23 07:10
    I have, with that program, successfully read info from the ActivityBoard. I have also built and used a loopback tester to make sure that my Java program can read what it is sending.

    The problem that I am specifically dealing with is using the ActivityBoard to read in info from the Java program. Everything else works. I was having a problem with squares and circles, but since I got rid of the buffer variable, the Java program can read stuff in fine. I suspect the problem stems from the serial protocols the propeller is using, but I don't fully understand how the propeller communicates with the serial ports on the computer so I am having trouble narrowing down the problem.

    Right now, when I communicate to the ActivityBoard and have it echo back whatever info it is receiving, I get random numbers. I know it is not a problem with the Java program, so it must be with the ActivityBoard. Since I also know that the ActivityBoard can send info without issue, I can assume that the problem occurs when the ActivityBoard is reading information from the serial connection.

    If I could figure out how the ActivityBoard communicates with the SimpleIDE terminal, maybe I could figure out what is causing the problem, and hopefully come up with a solution. But if I could do this, I wouldn't need any help :). Do you know if 1) this could be the problem and 2) if this could be the solution?
  • Martin_HMartin_H Posts: 4,051
    edited 2014-08-23 09:04
    OK, here's another thing that doesn't look right to me.

    In one place in the code you call dprint with a null terminated string:
          dprint( comp1, "_INFO RECIEVED" );
    

    But later you call it with a single character:
        dprint( comp1, c[i] );
    

    Unless dprint is overloaded to take both data types that's not going to work. Given its name, my guess is that dprint expects a null terminated string and the dprint of c is going to print random junk until it bumps into a null.
  • twm47099twm47099 Posts: 867
    edited 2014-08-23 10:42
    Martin_H wrote: »
    OK, here's another thing that doesn't look right to me.

    In one place in the code you call dprint with a null terminated string:
          dprint( comp1, "_INFO RECIEVED" );
    

    But later you call it with a single character:
        dprint( comp1, c[i] );
    

    Unless dprint is overloaded to take both data types that's not going to work. Given its name, my guess is that dprint expects a null terminated string and the dprint of c is going to print random junk until it bumps into a null.

    I think in the second example you need a format specifier. I'm not sure if it will work, but try:
        dprint( comp1, "%c",c[i] );
    

    Tom
  • ValeTValeT Posts: 308
    edited 2014-09-01 08:10
    Hey everyone,

    Sorry for the big delay! My school just started, so it is hard finding time to work on everything.

    I have been trying to make some progress, but I can't figure out my problem :(. It appears that whatever I send to the ActivityBoard over USB from a Java program doesn't get "read in" by the program. When I try to make an echo loop with the ActivityBoard and the computer, it doesn't work. I can receive info from the ActivityBoard fine, and that part of my program/circuit works. The issue is when I send the character 'A', for example, and have the ActivityBoard echo what it receives, in this case an 'A', back to the computer, I get random numbers including 252, 128, and 16. Do these specific numbers matter; is there something that specifically causes these numbers to be returned?

    I have tried a loop tester with connecting the Rx an Tx pins directly together over an FTDI chip, and it works fine.
  • ValeTValeT Posts: 308
    edited 2014-09-02 14:52
    Hmmm.......It appears that this isn't going anywhere :(. Let me rephrase what I am saying.

    Has anyone successfully communicated with the ActivityBoard over USB from a program other than the Parallax supported IDEs in Java ( well....at this point, I guess I am willing to go for any language :) )?
  • ChrisL8ChrisL8 Posts: 129
    edited 2014-09-03 10:25
    ValeT wrote: »
    Has anyone successfully communicated with the ActivityBoard over USB from a program other than the Parallax supported IDEs in Java ( well....at this point, I guess I am willing to go for any language :) )?

    You can "communicate" with the Activity Board over USB with serial data. You can do that with any programming language. I've done it in Java, Python and I routinely just send commands over TTY to the Activity Board to test my basic code.

    What operating system are you using? If you are on Linux try running "miniterm.py /dev/ttyUSB0 115200", and see if you can send/recieve data to the Activity Board. If that works, you probably are just having trouble with your string conversion.

    Here is some test code I wrote a while back just to prove that I could talk over serial to an Activity Board from a Raspberry Pi:
    It uses jSSC: https://code.google.com/p/java-simple-serial-connector/
    package jssc_test;
    
    
    import jssc.SerialPort;
    import jssc.SerialPortEvent;
    import jssc.SerialPortEventListener;
    import jssc.SerialPortException;
    
    
    public class Test1 {
    
    
    static SerialPort serialPort;
    
    
    public static void main(String[] args) {
        if (args.length != 1) {
            System.out.println("You must include the COM port!");
            System.out.println("Like this:");
            System.out.println("Test1 COM4");
            System.out.println("Test1 /dev/ttyUSB0");
            System.out.println("Test1 /dev/ttyAMA0");
            System.out.println("etc.");
            System.exit(1);
        }
        serialPort = new SerialPort(args[0]); 
        try {
            System.out.print("Opening " + args[0] + " at");
            serialPort.openPort();
            System.out.print(" 115200, 8, 1, 0 and ");
            serialPort.setParams(115200, 8, 1, 0);
            //Preparing a mask. In a mask, we need to specify the types of events that we want to track.
            //Well, for example, we need to know what came some data, thus in the mask must have the
            //following value: MASK_RXCHAR. If we, for example, still need to know about changes in states 
            //of lines CTS and DSR, the mask has to look like this: SerialPort.MASK_RXCHAR + SerialPort.MASK_CTS + SerialPort.MASK_DSR
            int mask = SerialPort.MASK_RXCHAR;
            //Set the prepared mask
            serialPort.setEventsMask(mask);
            //Add an interface through which we will receive information about events
            System.out.println("waiting for data . . .");
            serialPort.addEventListener(new SerialPortReader());
    
    
            //serialPort.writeString("HelloWorld");
        }
        catch (SerialPortException ex) {
            System.out.println("Serial Port Opening Exception: " + ex);
        }
    }
    
    
    static class SerialPortReader implements SerialPortEventListener {
    
    
        public void serialEvent(SerialPortEvent event) {
            //Object type SerialPortEvent carries information about which event occurred and a value.
            //For example, if the data came a method event.getEventValue() returns us the number of bytes in the input buffer.
            /* For debugging, this should always be 1 unless we are
             * waiting for more than one byte, otherwise it just junks up the output :)
             */
            //System.out.println("Bytes: " + event.getEventType());
            if(event.isRXCHAR()){
                /* See original code,
                 * it waited for a certain number of bytes,
                 * but if I want the characters, why do that?
                 */
                //if(event.getEventValue() == 10){
                    try {
                        String data= serialPort.readString();
                        //System.out.println("Data: " + data); // For debugging
                        System.out.print(data);
                    }
                    catch (SerialPortException ex) {
                        System.out.println("Serial Port Reading Exception: " + ex);
                    }
                //}
            }
            //If the CTS line status has changed, then the method event.getEventValue() returns 1 if the line is ON and 0 if it is OFF.
            else if(event.isCTS()){
                if(event.getEventValue() == 1){
                    System.out.println("CTS - ON");
                }
                else {
                    System.out.println("CTS - OFF");
                }
            }
            else if(event.isDSR()){
                if(event.getEventValue() == 1){
                    System.out.println("DSR - ON");
                }
                else {
                    System.out.println("DSR - OFF");
                }
            }
        }
    }
    }
    

    It has been a few months since I threw that together, mostly from examples, so I don't remember all of the details. :)
  • ValeTValeT Posts: 308
    edited 2014-09-03 11:07
    I am using Windows 8.1.

    I can communicate to the computer from the ActivityBoard fine, it is just when I attempt to send data to the ActivityBoard from my computer that my communication breaks down :(. I have tried to debug the issue, but the issue seems that the ActivityBoard doesn't receive any information when I send information from the computer to it.

    Do you see what issue I am having?
Sign In or Register to comment.