I'm trying to control a robotic arm with a leap motion controller. Right now I'm just controlling two servos. I'm using java to read data from the leap motion, process and format it, and send it to the Arduino. The Arduino just receives the data, translates it, and sends it to the servos.
The format that I send the data to the Arduino in is, in string form:
z-rotation:shoulderPos:elbowAngle:wristAngle:clawPos
with each of these variables formatted with leading zeroes so that exactly 19 bytes are always sent to the Arduino at a time.
The issue is that data seems to be being lost in communication between the java on my laptop and the Arduino. If I send one command string, "000:180:000:000:000"
for example, the Arduino tells me that it's received "000:180:000:000:000"
and it correctly sends "000" to one servo and "180" to the second servo.
If I send a string of nine commands:
000:000:000:000:000180:000:000:000:000000:000:000:000:000180:000:000:000:000000:000:000:000:000180:000:000:000:000000:000:000:000:000180:000:000:000:000
The Arduino tells me that it's received all of the commands individually and it correctly sends all of the commands to the servos (evident by the twitching of the servos) and ends with sending "000" to both servos.
However, when I run my code with the leap motion, which effectively constantly transmits strings of 19 bytes to the Arduino, the servos just begin to twitch, moving between 0, 180, and the position that I'm sending to them. When I move my hand closer to the 100 position, the twitching servos have a net movement towards the 100 position, but never actually reaches it. The Arduino tells me that it's receiving the commands correctly for a few seconds before beginning to receive distorted messages like "0:180:0000:0018:00". I can only assume that the transmission and reception of commands are getting out of sync, but I'm not sure.
Here's my Java code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.text.DecimalFormat;
import java.util.ArrayList;
import com.leapmotion.leap.*;
import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
class SampleListenerMain extends Listener {
//define position lock booleans
public boolean leftLock = false;
public boolean rightLock = false;
String data = "";
static DecimalFormat df = new DecimalFormat("000");
//Displacement variables
double deltaX, deltaY, deltaZ, angle;
public void onInit(Controller controller) {
System.out.println("Initialized");
}
public void onConnect(Controller controller) {
System.out.println("Connected");
controller.enableGesture(Gesture.Type.TYPE_CIRCLE);
controller.enableGesture(Gesture.Type.TYPE_KEY_TAP);
}
public void onDisconnect(Controller controller) {
System.out.println("Disconnected");
}
public void onExit(Controller controller) {
System.out.println("Exited");
}
public void onFrame(Controller controller) {
//Define position variables
double shoulderAngle, elbowAngle, wristPos, clawPos, zRotationPos, wristAngle;
//Define object variables
//Frame
Frame frame = controller.frame();
//Hands
Hand leftHand = frame.hands().leftmost();
Hand rightHand = frame.hands().rightmost();
//Arms
Arm leftArm = leftHand.arm();
Arm rightArm = rightHand.arm();
/* Control of robotic arm with Z-rotation based on the left hand, arm 'wrist' position based on the wrist,
* arm 'elbow position based on the elbow, and claw based on the fingers. 'Shoulder' is based on the left elbow
*/
//Control position locks for left hand controls and right hand controls
//Gesture gesture = new Gesture(gesture);
for(Gesture gesture : frame.gestures()) {
HandList handsForGesture = gesture.hands();
switch(gesture.type()) {
case TYPE_KEY_TAP:
System.out.println("Key tap from" + handsForGesture + " Hand");
try {
wait(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
leftLock = !leftLock;
break;
default:
System.out.println("Unrecognized gesture");
break;
}
}
//'Shoulder' control
//find angle between the left elbow and the left wrist center
Vector leftElbow = leftArm.elbowPosition();
Vector leftWrist = leftArm.wristPosition();
deltaZ = leftElbow.getZ() - leftWrist.getZ();
deltaY = leftElbow.getY() - leftWrist.getY();
angle = Math.atan(deltaY/deltaZ);
//map angle so servo can understand it
shoulderAngle = leapArm.map(angle, 0, 90, 0, 180);
//System.out.println("ShoulderPos: " + shoulderAngle);
//Write position to 'shoulder'
//Z-rotation control
Vector leftHandPos = leftHand.palmPosition();
//rotate z-axis with speed proportional to left hand X position
//map X position to motor power
zRotationPos = leapArm.map(leftHandPos.getX(), -230, 230, 0, 180);
//System.out.println("zRotationPos: " + zRotationPos);
data += df.format(zRotationPos);
data += ":" + df.format(shoulderAngle);
//write power to rotational servo
//'elbow' control
//find angle between the right elbow and right wrist center
Vector rightElbow = rightArm.elbowPosition();
Vector rightWrist = rightArm.wristPosition();
//refresh deltas and angle
deltaZ = rightElbow.getZ() - rightWrist.getZ();
deltaY = rightElbow.getY() - rightWrist.getY();
angle = Math.atan(deltaY/deltaZ);
//map angle so the servo can understand it
elbowAngle = leapArm.map(angle, -1.25, 0, 0, 180);
data+= ":" + df.format(elbowAngle);
//System.out.println("ElbowPos: " + elbowAngle);
//'wrist' control
//update vectors
rightWrist = rightArm.wristPosition();
Vector rightHandPos = rightHand.palmPosition();
//update deltas
deltaZ = rightWrist.getZ() - rightHandPos.getZ();
deltaY = rightWrist.getY() - rightHandPos.getY();
System.out.println("Wrist pos: " + rightWrist.getX() + ", " + rightWrist.getY() + ", " + rightWrist.getZ());
System.out.println("Right hand pos: " + rightHandPos.getX() + ", " + rightHandPos.getY() + ", " + rightHandPos.getZ());
angle = Math.atan(deltaY/deltaZ);
wristAngle = leapArm.map(angle, -0.5, 0.5, 0, 180);
data += ":" + df.format(wristAngle);
//System.out.println("wristAngle: " + wristAngle + " degrees");
//pinch control
//define fingers
FingerList fingerList = rightHand.fingers().fingerType(Finger.Type.TYPE_INDEX);
Finger rightIndexFinger = fingerList.get(0);
fingerList = rightHand.fingers().fingerType(Finger.Type.TYPE_THUMB);
Finger rightThumb = fingerList.get(0);
//find the distance between the bones to detect pinch
Vector rightIndexDistal = rightIndexFinger.bone(Bone.Type.TYPE_DISTAL).center();
Vector rightThumbDistal = rightThumb.bone(Bone.Type.TYPE_DISTAL).center();
//Calculate distance between joints
double distalDistance = Math.sqrt(Math.pow((rightIndexDistal.getX()-rightThumbDistal.getX()),2) + Math.pow((rightIndexDistal.getY()-rightThumbDistal.getY()),2) + Math.pow((rightIndexDistal.getZ()-rightThumbDistal.getZ()),2));
if(distalDistance <= 10) {
clawPos = 180;
} else {
clawPos = 0;
}
data += ":" + df.format(clawPos);
System.out.println("ClawPos: " + clawPos);
/* Write data to arduino
* FORMAT: z-rotation:shoulderPos:elbowAngle:wristAngle:clawPos
*/
System.out.println("Data: " + data);
/* wait for arduino to catch up ~30 packets/sec
* basically see how long the arduino takes to process one packet and flush the receiving arrays to prevent 'pollution'.
*/
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//send to arduino
leapArm.writeToArduino(data);
System.out.println("Sent");
}
}
public class leapArm implements SerialPortEventListener {
public static double map(double input, double in_min, double in_max, double out_min, double out_max) {
return ((input - in_min) * (out_max - out_min) / (in_max - in_min)) + out_min;
}
static OutputStream out = null;
static BufferedReader input;
public static void main(String[] args) {
//Connect to COM port
try
{
//Device
(new leapArm()).connect("/dev/cu.usbmodem14101");
Thread.sleep(3000);
//leapArm.writeToArduino("000:000:000:000:000180:000:000:000:000000:000:000:000:000180:000:000:000:000000:000:000:000:000180:000:000:000:000000:000:000:000:000180:000:000:000:000");
//System.out.println("sent");
}
catch ( Exception e )
{
e.printStackTrace();
System.exit(0);
}
// Create a sample listener and controller
SampleListenerMain listener = new SampleListenerMain();
Controller controller = new Controller();
// Have the sample listener receive events from the controller
controller.addListener(listener);
// Keep this process running until Enter is pressed
System.out.println("Press Enter to quit...");
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
// Remove the sample listener when done
controller.removeListener(listener);
}
void connect ( String portName ) throws Exception {
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
if ( portIdentifier.isCurrentlyOwned() )
{
System.out.println("Error: Port is currently in use");
}
else
{
CommPort commPort = portIdentifier.open(this.getClass().getName(),2000);
if ( commPort instanceof SerialPort )
{
SerialPort serialPort = (SerialPort) commPort;
serialPort.setSerialPortParams(4800,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
out = serialPort.getOutputStream();
//input = new BufferedReader(new InputStreamReader(serialPort.getInputStream()));
// add event listeners
try {
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
} catch (Exception e) {
System.err.println(e.toString());
}
}
else
{
System.out.println("Selected port is not a Serial Port");
}
}
}
public static void writeToArduino(String data)
{
String tmpStr = data;
byte bytes[] = tmpStr.getBytes();
try {
/*System.out.println("Sending Bytes: ");
for(int i = 0; i<bytes.length; i++) {
System.out.println(bytes[i]);
}*/
out.write(bytes);
} catch (IOException e) { }
}
public synchronized void serialEvent(SerialPortEvent oEvent) {
if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
try {
String inputLine=input.readLine();
System.out.println("Received: " + inputLine);
} catch (Exception e) {
System.err.println(e.toString());
}
}
// Ignore all the other eventTypes, but you should consider the other ones.
}
}
And here's my Arduino code:
#include <SoftwareSerial.h>
#include <Servo.h>
Servo shoulder1, shoulder2;
SoftwareSerial mySerial(5,3); //RX, TX
char *strings[19];
char chars[19];
int loopno = 0;
byte index = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(4800);
mySerial.begin(9600);
mySerial.println("Started");
shoulder1.attach(2);
shoulder2.attach(4);
chars[19] = NULL;
}
void loop() {
// put your main code here, to run repeatedly:
if(Serial.available()>18) {
loopno++;
Serial.readBytes(chars, 19);
/*for(int i = 0; i< sizeof(chars); i++) {
mySerial.print("Character ");
mySerial.print(i);
mySerial.print(": ");
mySerial.println(chars[i]);
}*/
String str(chars);
/*mySerial.print("In string form: ");
mySerial.println(str);*/
char* ptr = NULL;
index = 0;
ptr = strtok(chars, ":");
while(ptr != NULL) {
/* mySerial.print("Pointer: ");
mySerial.println(ptr);*/
strings[index] = ptr;
index++;
ptr = strtok(NULL, ":");
}
//mySerial.print("shoulder1: ");
mySerial.println(atoi(strings[0]));
/*mySerial.print("shoulder2: ");
mySerial.println(atoi(strings[0]));
mySerial.print("Loop no: ");*/
mySerial.println(loopno);
shoulder1.write(atoi(strings[0]));
shoulder2.write(atoi(strings[1]));
}
flush();
}
void flush() {
for(int i = 0; i<19; i++) {
chars[i] = NULL;
strings[i] = NULL;
}
}
And here's the circuit that I'm using (The top Arduino is used for serial readout and debugging)
I'm very confused as to why this is happening. I've tried:
Decreasing the baud rate (115200 to 4800).
Sending commands one at a time or in small groups as described earlier.
Commenting out all debugging and unnecessary print statements to decrease processing time and reduce the amount of Serial calls in the Arduino program.
Commenting out all print statements in the Java code as well as rewriting my formatting and transmission code with an eye for effifiency to increase data collection -> transmission speed.
I'd appreciate it if anyone has experience with this or knows what the probelem could be!
Thanks,
Gabe
Edit:
I messed around with it when I got home and I think I might have isolated (one of) the issue(s). When I have all my debugging print statements uncommented and I send the arduino `
Tests.writeToArduino("000:000:000:000:000000:000:000:000:000180:000:000:000:000"); Tests.writeToArduino("180:000:000:000:000000:000:000:000:000000:000:000:000:000");
Tests.writeToArduino("000:000:000:000:000000:000:000:000:000000:000:000:000:000");
Tests.writeToArduino("180:000:000:000:000000:000:000:000:000000:000:000:000:000");, it starts to give me weird feedback starting at loop 7:
However, when I run my code with all the debugging statements commented out except for the first data value and the loop number, it is able to successfully keep track of 51 loops worth of data:
Tests.writeToArduino("000:000:000:000:000000:000:000:000:000180:000:000:000:000");
Tests.writeToArduino("180:000:000:000:000000:000:000:000:000000:000:000:000:000");
Tests.writeToArduino("000:000:000:000:000000:000:000:000:000000:000:000:000:000");
Tests.writeToArduino("180:000:000:000:000000:000:000:000:000000:000:000:000:000");
Tests.writeToArduino("000:000:000:000:000000:000:000:000:000000:000:000:000:000");
Tests.writeToArduino("180:000:000:000:000000:000:000:000:000000:000:000:000:000");
Tests.writeToArduino("000:000:000:000:000000:000:000:000:000000:000:000:000:000");
Tests.writeToArduino("180:000:000:000:000000:000:000:000:000000:000:000:000:000");
Tests.writeToArduino("000:000:000:000:000000:000:000:000:000000:000:000:000:000");
Tests.writeToArduino("180:000:000:000:000000:000:000:000:000000:000:000:000:000");
Tests.writeToArduino("000:000:000:000:000000:000:000:000:000180:000:000:000:000");
Tests.writeToArduino("000:000:000:000:000000:000:000:000:000180:000:000:000:000");
Tests.writeToArduino("000:000:000:000:000000:000:000:000:000180:000:000:000:000");
Tests.writeToArduino("000:000:000:000:000000:000:000:000:000180:000:000:000:000");
Tests.writeToArduino("000:000:000:000:000000:000:000:000:000180:000:000:000:000");
Tests.writeToArduino("000:000:000:000:000000:000:000:000:000180:000:000:000:000");
Tests.writeToArduino("000:000:000:000:000000:000:000:000:000777:000:000:000:000");
gives me:
This leads me to believe that either data is being lost in serial communication, as softwareserial is known to have this issue (which would make sense because less readout -> less jumbled data), or that I might be running into memory issues on the Arduino. Could either of these be the case? I'm still having the original issue, just thought these insights might help.
I found the solution: my arduino code was taking ~30ms to go through one loop but my java-side code was looping faster than that. The 64 byte arduino serial buffer was getting filled up after a few loops, and, since 64 is not a multiple of the 19 bytes I was sending, the dropped bytes would mean that the number:number format would get messed up.
If it helps anyone, I just tracked the time of the arduino loop and added a 50ms delay to the java-side code so that the arduino-side can catch up.
Related
I have a Moog Theremini that outputs two sets of continuous controller data. The "pitch" antenna outputs on CC 20 and the "volume" antenna outputs on CC2.
I have no problem pulling up the track data for CC20, but after a day of reading MIDI docs and articles, can't seem to find any way to grab this other CC data on the same track. Is anyone familiar enough with this to help me out?
The output code below is what I'm trying to figure out. My intention with it is
Convert the last (or second to last) message on the track (there's only 1 track) to a Short Message
Print out the Command, Status, Controller # and Controller value
This is done in a loop so it continues indefinitely printing out the latest part of the track.
The below code successfully achieves the above for CC 20, but I can't seem to figure out how to grab the data for CC 2. I'm not even sure why it's printing CC20 to be honest.
try {
ShortMessage sm = (ShortMessage) sequencePass.getTracks()[0].get(sequencePass.getTracks()[0].size()-2).getMessage();
System.out.println("| comm " + sm.getCommand() + "| status " + sm.getStatus() + "| d1 (Controller#) " + sm.getData1() + "| d2 (Controller value) " + sm.getData2());
} catch (Exception e) {
System.out.println("blah blah" + e);
}
**Edit 1 here is the MIDI class: **
public MidiJunk() {
try {
MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo(); //looking through all of my MIDI devices
for(int i=0;i<infos.length;i++)
{
System.out.println(infos[i].getName() + " - " + infos[i].getDescription());
}
System.out.println();
MidiDevice INSTRUMENTO = MidiSystem.getMidiDevice(infos[5]); //the plugged in Theremini is here, so assigning it as a MidiDevice
INSTRUMENTO.open(); //opening midi device
Sequencer sequencero = MidiSystem.getSequencer(); //default sequencer transmitter and receiver
sequencero.open(); //open sequencer
Transmitter transmittero = INSTRUMENTO.getTransmitter(); //linking transmitter to instrument?
Receiver receivero = sequencero.getReceiver(); //get reciever from sequencer
transmittero.setReceiver(receivero);
Sequence testseq; //test sequence
try {
testseq = new Sequence(Sequence.PPQ,24);
sequencero.setSequence(testseq);
sequencero.recordEnable(testseq.createTrack(),0);
sequencero.setTickPosition(0);
sequencero.startRecording();
Timer timeo = new Timer();
TimerTask timeoTaskeo = new displayMidiEventsOnTimer(testseq);
timeo.schedule(timeoTaskeo,400,400);
Scanno.nextLine();
sequencero.stopRecording();
MidiSystem.write(testseq,1,new File("miditest.mid"));
System.out.println("it's done");
} catch (Exception ene) {
System.out.println(ene);
}
} catch (Exception E) {
System.out.println(E);
}
}
And here is the display events class
public class displayMidiEventsOnTimer extends TimerTask {
Sequence sequencePass;
public displayMidiEventsOnTimer(Sequence thisguy) {
sequencePass = thisguy;
}
#Override
public void run() {
try {
ShortMessage sm = (ShortMessage) sequencePass.getTracks()[0].get(sequencePass.getTracks()[0].size()-2).getMessage();
System.out.println("| comm " + sm.getCommand() + "| status " + sm.getStatus() + "| d1 (Controller#) " + sm.getData1() + "| d2 (Controller value) " + sm.getData2());
} catch (Exception e) {
System.out.println(e);
}
}
}
You don't need a sequencer here, unless you want to record the relative timings between the received events.
Here is an example how to display all incoming CC messages directly in a custom Receiver.
...
Transmitter transmittero = INSTRUMENTO.getTransmitter();
Receiver receivero = new MyReceiver(); // Connect to your custom receiver
transmittero.setReceiver(receivero);
...
class MyReceiver implements Receiver
{
#Override
public void send(MidiMessage mm, long timeStamp)
{
if (mm instanceof ShortMessage)
{
ShortMessage sm = (ShortMessage) mm;
if (sm.getCommand() == ShortMessage.CONTROL_CHANGE)
{
int cc = sm.getData1();
// Do something quick, filter ignored CCs etc.
System.out.println("cc=" + cc);
}
}
}
#Override
public void close()
{
}
}
I'm new here so please excuse me if I make a mistake with the question asking process. I have researched my question for the last week and a half and haven't found what I'm looking for (although I feel like the answer is very close). I'm a student and have been working on an assignment using Eclipse for my Java class. I have written a code that takes information from one file, uses it in a calculation and now I need to output it into another file. This is where I am having difficulty. This is my code so far:
import java.util.Scanner;
import java.nio.file.Paths;
import java.io.IOException;
import java.util.NoSuchElementException;
import java.util.ArrayList;
public class Program6 {
private Scanner input;
private ArrayList<Double> payRoll = new ArrayList<>();
public static void main(String[] args) {
Program6 myObject = new Program6();
myObject.openFile();
myObject.readFile();
myObject.calculateRecords();
myObject.closeFile();
}
public void openFile() {
try {
input = new Scanner(Paths.get("Program6.txt"));
} catch (IOException ioException) {
System.err.println("Error opening file. Terminating.");
System.exit(1);
}
}
public void readFile() {
try {
while (input.hasNext()) {
payRoll.add(input.nextDouble());
}
} catch (NoSuchElementException elementException) {
System.err.println("File improperly formed. Terminating.");
} catch (IllegalStateException stateException) {
System.err.println("Error reading from file. Terminating.");
}
}
public void calculateRecords() {
System.out.printf("%10s%25s%15s%19s", "Before Payroll",
"Raise Percent",
"Raise Amount",
"After Payroll\n");
double raisePercent;
double raiseAmount;
double totalBeforePayroll = 0;
double totalAfterPayroll = 0;
for (int i = 0; i < payRoll.size(); i++) {
if (payRoll.get(i) > 70000) {
raisePercent = 4;
} else if (payRoll.get(i) > 50000) {
raisePercent = 7;
} else {
raisePercent = 5.5;
}
raiseAmount = payRoll.get(i) * raisePercent / 100;
System.out.printf("%12.2f%21.1f%18.2f%17.2f%n",
payRoll.get(i), raisePercent, raiseAmount, payRoll.get(i) + raiseAmount);
totalBeforePayroll += payRoll.get(i);
totalAfterPayroll += payRoll.get(i) + raiseAmount;
}
System.out.printf("%nTotal amount of raises: $%,.2f%n",
totalAfterPayroll - totalBeforePayroll);
System.out.printf("Average raise percent : %.0f%%",
(totalAfterPayroll - totalBeforePayroll) * 100.0 / totalBeforePayroll);
System.out.printf("%nAverage raise amount : $%,.2f%n",
(totalAfterPayroll - totalBeforePayroll) / payRoll.size());
}
public void closeFile() {
if (input != null)
input.close();
}
}
Assuming you want to output just the payroll amount after adding the raise amount.
You can write a void method writeFile() in which you loop through your list and append every entry to an empty file.
For this I'm going to be using the BufferedWriter class, but you are free to chose whatever class you like. I'm going to proceed with the BufferedWriter example though.
So what we need to do in our writeFile method is setting up the bufferedwriter. This is done like this:
BufferedWriter b = new BufferedWriter(new FileWriter("path here" + System.getProperty("file.separator") + "filename.txt"));
Replacing "path here" by wherever you want to save your file. One example would be to replace it by System.getProperty("user.dir") which is the users working directory.
System.getProperty("file.seperator") would be a \ in Windows. But using System.getProperty("file.separator") will make it work on different systems as well.
So:
BufferedWriter bw = new BufferedWriter(new FileWriter(System.getProperty("user.dir") + System.getProperty("file.separator") + "filename.txt"));
Now you can loop through your list and append every entry to the writer:
for (int i = 0; i < payRoll.size(); i++){
bw.append(payRoll.get(i));
}
After that you can and should "close" the bufferedwriter using:
bw.close();
The method would look something like this:
BufferedWriter b = new BufferedWriter(new FileWriter("path here" + System.getProperty("file.separator") + "filename.txt"));
for (int i = 0; i < payRoll.size(); i++){
bw.append(payRoll.get(i));
}
bw.close();
I am trying to send text messages from Java/Netbeans using a cell modem based on the SIM900. Using TeraTerm, I verify that I can send messages using the modem with basic AT commands. The following code attempts to use jssc to send messages.
I do not get errors and the data appears to be written to the modem, but I never receive a text message. For the phone number, I have tried both with an +, and without.
In TeraTerm, the number must be without the + to work. Many variations have been tried, and many .println's used. Still not making progress.
I hope someone can see the error of my ways.
Thanks in advance. Doug
package jssc_test;
import jssc.SerialPort;
import jssc.SerialPortException;
import jssc.SerialPortList;
public class Jssc_test {
public static SerialPort serialPort=null;
public static void main(String[] args) throws InterruptedException {
try {
String[] portNames = SerialPortList.getPortNames();
for(int i = 0; i < portNames.length; i++){
System.out.println(portNames[i]);
}
if(portNames.length < 1){
System.out.println("No ports available");
System.exit(0);
}
else{
serialPort = new SerialPort(portNames[0]);
}
System.out.println("Port opened: " + serialPort.openPort());
System.out.println("Params set: " + serialPort.setParams(9600, 8, 1, 0));
System.out.println("\"Hello World!!!\" successfully writen to port: " + serialPort.writeBytes("Hello World!!!".getBytes()));
serialPort.writeBytes(" AT+CMGF=1".getBytes());
Thread.sleep(1000);
System.out.println("bytes back = " + serialPort.readString());
serialPort.writeBytes(" AT+CMGS=\"585*******\"".getBytes()); // \r = <CR>. Tried both with and without '+'. In TeraTerm, only works without +. error if use: \r\n
//Thread.sleep(1000);
//System.out.println("bytes back = " + serialPort.readString());
//serialPort.writeBytes("0x0D".getBytes()); // send <CR>
Thread.sleep(1000);
System.out.println("bytes back = " + serialPort.readString());
serialPort.writeBytes("THIS IS A TEST from DS.".getBytes()); // placing Cntr-Z string in text did not work: \u001A
//serialPort.writeBytes("0x0D".getBytes()); // send <CR>
serialPort.writeBytes("0x1A".getBytes()); // send <ctrl>Z
Thread.sleep(1000);
System.out.println("bytes back = " + serialPort.readString());
System.out.println("Port closed: " + serialPort.closePort());
}
catch (SerialPortException ex){
System.out.println(ex);
}
} // ******************* end main ***************
} // *********************** end main class ***********************
I was able to answer the question I posed above. Below code works. The event listener does not need to be in there. The major changes that helped are defining the new line and end of file as bytes "public static final Byte eof = 0x1A, nl=0x0D;" then writing the bytes to the serialPort separately from the commands "serialPort.writeByte(nl);". I hope this helps others.
Doug
PS: I wrote a java class that may simplify sending code to the SIM900 using jssc, if anyone is interested.
package jssc_test;
//import jssc.SerialPort;
//import jssc.SerialPortException;
//import jssc.SerialPortList;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import jssc.*;
import static jssc.SerialPort.PURGE_RXCLEAR;
import static jssc.SerialPort.PURGE_TXCLEAR;
import static jssc_test.Jssc_test.serialPort;
/**
*
* #author DStockman
*/
public class Jssc_test {
public static SerialPort serialPort=null;
public static final Byte eof = 0x1A, nl=0x0D;
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws InterruptedException {
//SerialPort serialPort = null;
try {
String[] portNames = SerialPortList.getPortNames();
for(int i = 0; i < portNames.length; i++){
System.out.println(portNames[i]);
}
if(portNames.length < 1){
System.out.println("No ports available");
System.exit(0);
}
else{
serialPort = new SerialPort(portNames[0]);
}
System.out.println("Port opened: " + serialPort.openPort());
System.out.println("Params set: " + serialPort.setParams(9600, 8, 1, 0));
serialPort.writeBytes("ATI".getBytes()); // get modem ID
serialPort.writeByte(nl);
Thread.sleep(1000);
System.out.println("modem ID = " + serialPort.getEventsMask());
/*
int mask = SerialPort.MASK_RXCHAR + SerialPort.MASK_CTS + SerialPort.MASK_DSR;//Prepare mask
serialPort.setEventsMask(mask);//Set mask
try{
serialPort.addEventListener(new SerialPortReader());//Add SerialPortEventListener
}
catch (SerialPortException ex) {
System.out.println(ex);
}
*/
// just looking up settings
System.out.println("events mask = " + serialPort.getEventsMask());
System.out.println("flow control mode = " + serialPort.getFlowControlMode());
System.out.println("output buffer bytes = " + serialPort.getOutputBufferBytesCount());
//serialPort.purgePort(PURGE_RXCLEAR | PURGE_TXCLEAR);
serialPort.writeBytes(" AT+CMGF=1".getBytes());
serialPort.writeByte(nl);
Thread.sleep(1000);
System.out.println("bytes back set modem to text mode = " + serialPort.readString());
System.out.println("Success entering number: " + serialPort.writeBytes(" AT+CMGS=\"5857738696\";".getBytes())); // \r = <CR>. Tried both with and without '+'. In TeraTerm, only works without +. error if use: \r\n
serialPort.writeByte(nl);
Thread.sleep(1000);
System.out.println("bytes back after number entered = " + serialPort.readString());
serialPort.writeBytes("THIS IS A third TEST from DS 09/29/16.2.".getBytes());
serialPort.writeByte(nl);
Thread.sleep(1000);
serialPort.writeByte(eof);
Thread.sleep(1000);
System.out.println("bytes back = " + serialPort.readString());
Thread.sleep(10000);
//serialPort.purgePort(SerialPort.PURGE_TXCLEAR);
//attempt to get msgs received by modem
serialPort.writeBytes("AT+CMGL=\"ALL\"".getBytes());
serialPort.writeByte(nl);
Thread.sleep(1000);
System.out.println("bytes back = " + serialPort.readString());
System.out.println("Port closed: " + serialPort.closePort());
}
catch (SerialPortException ex){
System.out.println(ex);
}
} // ******************* end main ***************
} // *********************** end main class ***********************
class SerialPortReader implements SerialPortEventListener {
public void serialEvent(SerialPortEvent event) {
if(event.isRXCHAR()){//If data is available
if(event.getEventValue() == 1){//Check bytes count in the input buffer
//Read data, if 10 bytes available
try {
System.out.println("bytes back inside listener = " + serialPort.readString());
byte buffer[] = Jssc_test.serialPort.readBytes(10);
System.out.println("listener text:");
System.out.print(Arrays.toString(buffer));
System.out.println("End listener text:");
}
catch (SerialPortException ex) {
System.out.println(ex);
}
}
}
else if(event.isCTS()){//If CTS line has changed state
if(event.getEventValue() == 1){//If line is ON
System.out.println("CTS - ON");
}
else {
System.out.println("CTS - OFF");
}
}
else if(event.isDSR()){///If DSR line has changed state
if(event.getEventValue() == 1){//If line is ON
System.out.println("DSR - ON");
}
else {
System.out.println("DSR - OFF");
}
}
}
}
I made an application that would show me Max, Minimum, and Average ping when I click "start" in my JFrame application. I made a white box so I could fit a dynamically changing line graph that will be in the same window as my stats, and will update at the same rate as my stats (1 second).
No matter how much I google, everybody seems to understand the JFreeChart sample code. I do not understand how to implement that at all. Other tutorials show just the graph as a standalone in its own window.
I hope somebody can help me. Here is my code for the JFrame as of now:
private void startButtonMouseClicked(java.awt.event.MouseEvent evt) {
String host = hostName.getText();
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(new Runnable(){
#Override
public void run(){
try {
NetworkAnalyzer.pingCheck(host);
} catch (IOException ex) {
Logger.getLogger(NetworkAnalyzerwindow.class.getName()).log(Level.SEVERE, null, ex);
}
}
}, 0, 1, TimeUnit.SECONDS);
And here is my pingCheck:
public class NetworkAnalyzer {
static int count=0;
static long max_time = 0;
static long min_time = 0;
static long avg_time = 0;
public static void pingCheck(String host) throws IOException{
String time = "";
//command to execute
String pingCmd = "ping " + host + " -t " + "-n 1";
//gets runtime to execute command
Runtime runtime = Runtime.getRuntime();
try {
Process process = runtime.exec(pingCmd);
//gets inputstream to read the output of the cocmmand
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
//read outputs
String inputLine = in.readLine();
while((inputLine != null)) {
if (inputLine.length() > 0 && inputLine.contains("time")){
time = inputLine.substring(inputLine.indexOf("time"));
break;
}
inputLine = in.readLine();
}
/* if(inputLine.contains("timed")){
System.out.print("Request timed out. Try another domain:");
pingCheck(time);
}*/
time = time.replaceAll("[^0-9]+", " ");
time = time.substring(0, Math.min(time.length(), 3));
time = time.replaceAll(" ", "");
System.out.println("ping:" + time);
//ping calcs
count++;
Long ping;
ping = Long.parseLong(time);
//for avg
//max ping
if( count == 1 || ping >= max_time)
max_time = ping;
//min ping
if(count == 1 || ping <= min_time)
min_time = ping;
//avg ping
if (count > 0)
avg_time = (avg_time*(count-1)+ping)/count;
NetworkAnalyzerwindow.maxPing.setText("Max: " + max_time + "ms");
NetworkAnalyzerwindow.minPing.setText("Min: " + min_time + "ms");
NetworkAnalyzerwindow.avgPing.setText("Avg: " + avg_time + "ms");
} catch(IOException | NumberFormatException ex){
JOptionPane.showMessageDialog(null, ex);
}
}
I just want to add a dynamically changing graph that would take the ping values and graph them. Can somebody actually help me and not link me to one of the tutorials that only shows how to make a graph by itself.
Here is what the app looks like when running(I would like the graph in the white box. I could make the box bigger):
http://imgur.com/kgYCoW2
Using ProcessBuilder, shown here, execute the ping command in your doInBackground() implementation of a SwingWorker. Parse the output, and publish() the results. Update the dataset in your process() implementation, and the chart will update itself in response. An example using JFreeChart is shown here.
Can you explain a bit more?
Starting with the first example, replace
ProcessBuilder pb = new ProcessBuilder("ls", "-lR", "/");
with
ProcessBuilder pb = new ProcessBuilder("ping", "-c", "3", "example.com");
to get a convenient display of the standard output of ping. In outline, your process() in the second example might look like this:
#Override
protected void process(java.util.List<String> messages) {
for (String message : messages) {
textArea.append(message + "\n");
// parse x, y from message
series.add(x, y);
}
}
I need to communicate a Java application and a C process via POSIX message queue, and I would like to do it using JNA.
After some research, reading and your help, I started with a simple Java application which tries to create a message queue.
/** Simple example of JNA interface mapping and usage. */
public class HelloJNAWorld {
// This is the standard, stable way of mapping, which supports extensive
// customization and mapping of Java to native types.
public interface IPCLibrary extends Library {
IPCLibrary INSTANCE = (IPCLibrary)
Native.loadLibrary("c",IPCLibrary.class);
int msgget(NativeLong key, int msgflg);
}
public static void main(String[] args) {
int id = IPCLibrary.INSTANCE.msgget(new NativeLong(12500), 0600|1);
if(id<0){
System.out.println("Error creating message queue. Id:"+id);
System.out.println(Native.getLastError());
}else{
System.out.println("Message queue id:" + idCola);
}
}
}
I thought msgctl was the simplest method to map because it's just int msgget(key_t key, int msgflag);. I have assumed that I could map key_t as a NativeLong but msget is returning -1. So I've checked lastError and the value returned is 2, which means "No such file or
directory" according to errno codes.
Could you help me with this? Maybe key_t should be mapped in another way? Maybe I need more libraries or something like that?
Since no one answer this question, and some could need the help I needed those days, I'm posting my test class code here. :-)
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Platform;
import com.sun.jna.Structure;
/** Simple example of JNA interface mapping and usage. */
public class HelloJNAWorld {
// This is the standard, stable way of mapping, which supports extensive
// customization and mapping of Java to native types.
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)
Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),CLibrary.class);
void printf(String format, Object... args);
}
public interface IPCLibrary extends Library {
IPCLibrary INSTANCE = (IPCLibrary)
Native.loadLibrary("c",IPCLibrary.class);
class WaitQueue extends Structure{
}
// mapping msqid_ds structure
class MsqidDs extends Structure{
long msg_stime; /* last msgsnd time */
long msg_rtime; /* last msgrcv time */
long msg_ctime; /* last change time */
short msg_cbytes;
short msg_qnum;
short msg_qbytes; /* max number of bytes on queue */
short msg_lspid; /* pid of last msgsnd */
short msg_lrpid; /* last receive pid */
}
// END mapping msqid_ds structure
class MsgBuf extends Structure{
NativeLong mtype; /* type of message */
byte mtext[] = new byte[1];
}
class MyMsgBuf extends MsgBuf{
public NativeLong messageKind;
public byte[] contenido = new byte[1024];
}
// Initialize queue, or if it exists, get it
int msgget(NativeLong key, int msgflg);
// Send messages to queue
// int msgsnd(int msqid, struct msgbuf *ptrkey, int length, int flag);
int msgsnd(int msqid, MsgBuf ptrkey, int msgsz, int msgflg);
// Receive messages from queue
// int msgrcv(int msqid, struct msgbuf *ptrkey, int length, long msgtype, int flag);
int msgrcv(int msqid, MsgBuf ptrkey, int length, long msgtype, int flag);
}
public static void main(String[] args) {
int idCola = IPCLibrary.INSTANCE.msgget(new NativeLong(12500), 0);
if(idCola<0){
System.out.println("The queue can't be created. IdCola:"+idCola);
System.out.println("Error msgget: " + Native.getLastError());
}else{
System.out.println("Queue with id:" + idCola + "has been recovered");
// Send message
IPCLibrary.MyMsgBuf mensaje = new IPCLibrary.MyMsgBuf();
mensaje.tipoMensaje = new NativeLong(1);
mensaje.contenido = "Sending message".getBytes();
int devSend = IPCLibrary.INSTANCE.msgsnd(idCola, mensaje, mensaje.contenido.length, 1);
if(devSend != 0){
System.out.println("Send response: "+devSend);
System.out.println("Error value: " + Native.getLastError());
}
}
// Receiving message
IPCLibrary.MyMsgBuf mensajeRecibido = new IPCLibrary.MyMsgBuf();
int bytesRecibidos = IPCLibrary.INSTANCE.msgrcv(idCola, mensajeRecibido, mensajeRecibido.contenido.length, 1234, 0);
if(bytesRecibidos > 0){
System.out.println("C message has been received: " + new String(mensajeRecibido.contenido));
}else{
System.out.println("msgrcv error: " + Native.getLastError());
}
// Send closing message
IPCLibrary.MyMsgBuf mensajeCierre = new IPCLibrary.MyMsgBuf();
mensajeCierre.tipoMensaje = new NativeLong(2);
mensajeCierre.contenido = "Closing queue".getBytes();
int devSend = IPCLibrary.INSTANCE.msgsnd(idCola, mensajeCierre, mensajeCierre.contenido.length, 1);
if(devSend != 0){
System.out.println("Send response: "+devSend);
System.out.println("Error value: " + Native.getLastError());
}
}
}
I really hope this can help someone else.
I cleaned up your code and got it running.
You need two tasks . one to send and one to receive.
just replace the main() in your previous post with the main()'s below. It worked for me. Thanks for posting your efforts for me to start with.
Also see kirk.c and spock.c for a good c example http://beej.us/guide/bgipc/output/html/multipage/mq.html
public static void main(String[] args) {
double SLEEP_MINUTES = 0.1;
int IPC_CREAT = 01000; // starts with 0 so its octal or 512
int IPC_EXCL = 02000;
int IPC_NOWAIT = 04000;
int MSG_EXCEPT = 020000;
int MSG_NOERROR = 010000; // truncate the message if its to big
int msgflg_msgrcv = MSG_NOERROR; // truncate the message if its to big
int msgflg_msgget = 0666 | IPC_CREAT;
int msgflg_msgsnd = 0;
int msgtype_msgrcv = 0; // read them all
NativeLong msgtype_msgsnd = new NativeLong(1); // just needs to be a positive number
NativeLong msgkey = new NativeLong(12500);
int msqid = IPCLibrary.INSTANCE.msgget(msgkey, msgflg_msgget);
if(msqid<0)
{
System.out.println("The queue can't be created. msqid:"+msqid);
System.out.println("Error msgget: " + Native.getLastError());
System.exit(0);
}
System.out.println("Queue with id:" + msqid + "has been found or created");
for(int i=0;i<100;i++)
{
// Send message
IPCLibrary.MyMsgBuf message = new IPCLibrary.MyMsgBuf();
message.messagetype = msgtype_msgsnd;
message.content = ("Sending message"+i+'\0').getBytes(); // add 1 for the '\0'
int devSend = IPCLibrary.INSTANCE.msgsnd(msqid, message, message.content.length+1,
msgflg_msgsnd);
if(devSend != 0)
{
System.out.println("Send response: "+devSend);
System.out.println("Error value: " + Native.getLastError());
System.exit(0);
}
System.out.println("Sent "+i);
try
{
Thread.sleep((long)(SLEEP_MINUTES*60.0*1000.0));
}
catch (InterruptedException e)
{
System.out.println("InterruptedException while writing");
System.out.println(e.getMessage());
}
}
}
public static void main(String[] args) {
// found these in /usr/include/bits/*.h
int IPC_CREAT = 01000; // remember if it starts with a '0' its octal or 512
int IPC_EXCL = 02000;
int IPC_NOWAIT = 04000;
int MSG_EXCEPT = 020000;
int MSG_NOERROR = 010000; // truncate the message if its to big
int msgflg_msgrcv = MSG_NOERROR; // truncate the message if its to big
int msgflg_msgget = 0666 | IPC_CREAT; // create the queue if its not there , let everybody read and write
int msgtype_msgrcv = 0; // read them all
NativeLong msgtype_msgsnd = new NativeLong(1); // just needs to be a positive number
NativeLong msgkey = new NativeLong(12500);
int msqid = IPCLibrary.INSTANCE.msgget(msgkey, msgflg_msgget);
if(msqid<0)
{
System.out.println("The queue can't be created. msqid:"+msqid);
System.out.println("Error msgget: " + Native.getLastError());
System.exit(0);
}
System.out.println("Queue with id:" + msqid + "has been found or was created");
for(int i=0;i<100;i++)
{
IPCLibrary.MyMsgBuf message = new IPCLibrary.MyMsgBuf();
int ret = IPCLibrary.INSTANCE.msgrcv(msqid, message, message.content.length,
msgtype_msgrcv,msgflg_msgrcv);
if(ret > 0)
{
System.out.println("message has been received: " + ret);
System.out.println(new String(message.content));
}
else
{
System.out.println("msgrcv error: " + Native.getLastError());
}
}
}
}