Hey,

I have x64 bit OS running on one of the builds you have on the bleeding edge.

I am not sure if my setup is fully functional.... but I get it to work most often and sometimes have to kill the java process manually to get it to release the serial port....

I'm having fun with this and learning a little more each day.

My question is how can I talk to the Arduino with a direct serial connection via  realterm or equivalent terminal when running the arduinoserialbare.pde on the microcontroller.  

I am trying to test the interface without the myrobotlab application to halfsplit my problems, as often as they occur...

If I shut everything down, open task manager, kill process, restart mrl, then I can usually get it to resync and talk to the arduino, but I'd like to just test a command without having to do all that by sending it manually...

Any ideas?

TY

 

DancesWithRobots

12 years ago

The real action occurs at the bottom of the bleeding edge files.  There's been a lot of work going on there lately.  Especially with Arduino.

When you start an Arduino service, it should display an editor with some code.  That code is mrlcomm.ino, which replaces arduinobareserial.  Mrlcomm.ino also reconfigures itself for any supported Arduino shield.  (So far, only Adafruit Motor Shield is supported in this way.)

After setting your board and serial port, hit the compile button, and then the upload button to install mrlcomm.ino in your Arduino.  Then you should be able to go to the various Arduino services, connect them and control them via the gui.

At this point, I'm not sure if the serial console can be used to control an Arduino, but that's the sort of thing that can be added if it's not already there.

There should be a new Arduino service page that goes into more detail, and some new tutorials and demos posted soon.

Thanks for your advice.  I have updated to latest bleeding edge.  Seems to not hang the com port when closing mrl.  

Selfishly, I would like to use this sketch protocol to talk serially to another system as well.  I wouldn't have to reflash to be able to switch between my existing system......

So I played around a little....

usbsnoopy shows mrl sending

54    out down    0x04    26.779    BULK_OR_INTERRUPT_TRANSFER    aa    
55    out down    0x04    26.780    BULK_OR_INTERRUPT_TRANSFER    06    
56    out down    0x04    26.781    BULK_OR_INTERRUPT_TRANSFER    00    
57    out down    0x04    26.782    BULK_OR_INTERRUPT_TRANSFER    09    
58    out down    0x04    26.787    BULK_OR_INTERRUPT_TRANSFER    aa    
59    out down    0x04    26.788    BULK_OR_INTERRUPT_TRANSFER    07    
60    out down    0x04    26.791    BULK_OR_INTERRUPT_TRANSFER    00    
61    out down    0x04    26.805    BULK_OR_INTERRUPT_TRANSFER    00   

This is just what the mrlcomm.ino shows it should be to set up a servo and then move to 0.

Seems that I better understand, which I think means that aa (10 10 bin) will be transmitted by a terminal as 61 61 hex(ascii) or 97 97 decimal

I don't think that it is possible to send the aa in a 'text' terminal window. 

my test was typing AA0609 with hex display mode resulting in usb transfer of:

66    ??? down    n/a    9.596    BULK_OR_INTERRUPT_TRANSFER    41    Hex for Ascii A
67    ??? down    n/a    9.978    BULK_OR_INTERRUPT_TRANSFER    41    
68    ??? down    n/a    12.759    BULK_OR_INTERRUPT_TRANSFER    30    
69    ??? down    n/a    13.297    BULK_OR_INTERRUPT_TRANSFER    36    
70    ??? down    n/a    14.067    BULK_OR_INTERRUPT_TRANSFER    30    
71    ??? down    n/a    14.641    BULK_OR_INTERRUPT_TRANSFER    39    

There is no way to type a character that equates to value aa in 1 keypress of a  terminal window...

So sadly I will have to find some other way to switch the protocol handler in my sketch to translate for my other software.  I cannot change the source of the other, only the scripting for control, not how it communicates...

I feel good that I'm starting to figure out whats happening under the hood! Really cool app, still I'm not sure of all mrl can do yet!

Thanks again!
 

I can tell you what the protocol is if that would help you.

MRL speaks a 4 byte command protocol to Arduino and
Arduino speaks to MRL with a 5 byte command response

MRL -> Arduino Message
byte 1 byte 2 byte 3 byte 4
MAGIC NUMBER  = 170 METHOD # PARAMETER 1 PARAMATER 2
Arduino -> MRL Message
byte 1 byte 2 byte 3 byte 4 byte 5
MAGIC NUMBER  = 170 TYPE IDENTIFIER MSB VALUE
 
LSB VALUE

 

If you have 2 Arduinos do you have to communicate from one to the other via serial ?
MRL has the capability of taking data from one Arduino and sending it to another MRL instance running somewhere on the internet to another Arduino (thousands of miles away ;)

If you showed us what your goal is, with big pretty pictures we might be able to assist.

Hi Grog,

Thanks for the breakdown. 

I am a technician that works for a software company.  I would like to be able to utilize my arduino to enhance my hardware interfacing capacity for my test bench.  I can write scripts for and receive input from hardware and send output to meters , etc...  The interface is reasonably flexible but it is serial only.  I can develop variables and pass them out of the system serially, through tcp or udp, or even can bus.  I have the ability to create fabulous gui's from toolkits etc... but the problem is I don't have access to the source so I can't develop the interface beyond what it is.  MRLcomm.ino is way more advanced than anything I've been able to come up with (only 2 weeks with my new uno).  I think that I could have used it to allow me to develop in house with my own hardware instead of having to have the production hardware exposed on my bench and risk damage.  Beyond that I tinker at home and I want to set up a camera for my wife to use when I'm traveling for security outside.  That's how I found your site, looking for arduino examples for servo's. I already have the camera up, serves to manycam, and splits to my motion detecting software for recording, and when I enable it to the net for outside access.  I was thinking that I could use the cam stuff you've got to take the xy coordinates triggered by my existing software and move the cam to follow the target.... or allow her to move it with the tv remote....

I think you can see that I am in the learning/dreaming stage with my new arduino.

I want to thank you for what you have done with this project, its very very cool.

 

Glad you having fun and dreaming up stuff.  DWR & I are trying to get some helpful videos out to show some of the basics of MRL (arduino to arduino communication - remote interfacing - remote data logging - scripting Python in MRL - how to generated Python from GUI actions - and a bunch of other things I've forgotten)

Currently the Arduino service in MRL uses MRLComm.ino as a structure protocol to communicate -  I've kicked around the idea of creating a more general Serial Service - which would effectively be like a serial terminal, but there has been more interest recently in getting Arduino Shields, OpenNI & OpenCV working more robustly..

Feel free to bring up any idea - MRL will assimilate !

Hey Grog,

I have been overseas working, and due to go back tomorrow.  I haven't had much time to work on this.

I have been working on the arduino mrlcomm.ino to read a standard ascii sentence that my hope is will be translated on the arduino side to equivalent MRL data structure and be transparent to your code's operation.  I have the input statement, and a checksum parameter implemented.  Now I have to develop a matrix of equivalent statements, ie...

 

* e.g. digitalWrite (13, 1)     = DIGITAL_WRITE|13|1 = 170|0|13|1
* structure....  $MRCMD,xxx,xxx*FF
$MRMRL,000,013,001*53
So when the data appears without a magic number, if it begins with $MR and the checksum is correct, continue and parse out the data to return your original byte code data so the original code is still unchanged.  Reply statements will be converted back to ascii if that is the originally triggered input. In this way I can talk to the arduino directly or via your java app without ever changing the arduino.
.... I am slowly translating my thoughts into C code.... not so bad, but its going slow for me....
I'm learning that you really need to watch the variable declarations in this language!
I'll get back to you soon.
 

So your wrapping the MRL protocol in your own..  and you'll have a parser/router method in your Arduino code..  Is that correct?

When your talking to the arduino "directly" .. is it through the same serial port connected to the computer?  Or a different serial port on the Arduino card?

What does your code do which MRLComm.ino can not?  Just curious ;D

I thought in the past that it might be nice if I wrap MRLComm into a library, but have not found a good reason to at the moment.

You have an interesting project, I'd like to hear more about it...  like what will the Arduino be doing... expecially when your talking to it directly?

P.S. - nice avatar Schlick   .. I think your beyond grasshoppar too :D, but it looks cool

Schlick

11 years 12 months ago

In reply to by GroG

 

Hey Grog,

So I am trying to talk to my arduino with regular ascii characters.

Your method is wonderful because it is no frills, and fast.  There is no fat in your code that takes up any extra time to communicate and has a measure of data validity.

I want something that I can direct the arduino to respond when talked to serially.  either I am talking to it through a terminal window or an app I write in autoit.  

Your code has two problems with this.

1. untypeable characters are used to build the magic number.

2. the code is byte dependent upon position.  Also not typeable.

Selfishly I want to use my arduino as a analog to digital converter when at work dealing with 'proprietary' systems.  I want to use it at home as well.  I only have one board right now, and I would like it to be able to just work for both without haveing to reflash. I am currently testing it with the same comm port you would use via usb.  either mine direct comms or yours via MRL, just one at a time.

I can write my own programs to talk to it using your protocol because it is very fast and robust.  I can program the output easily.  No changes needed.

But to use it at work, I don't have access to change the source code to build an interface.  But I can easily script the in/out serially to accomplish the same as my 'commercial' interfaces that are considerably more expensive and I never get to keep them for very long.  So I have to rebuild my test bench constantly.  If I can use the arduino, they can not tell me to build it into a customer's project.....

Also you discussed certain issues with the comm port not working.... is there problems on the host pc because of OS or Java problems.  Why not just open a terminal window and tap out a sentence....

$MRTST,013,0 (\n\r)

$MRTST,013,1 (\n\r)

$MR (similar to your magic number)

TST - test ( if  TST is used, checksum requirement can be ommitted)

,013 - pin assigment

,1 / ,0 - on/ off....

further, I figured to use CMD or MRL or something to indicate your code basis. and basically deliver the same format as you would use just comma seperated values.

If I decide to develop commands I could customize just by adding it into the script. just like the TST example.

Normally all input would be checksum based with is all the characters between a $ and the * to be XOR with each other.  if it doesn't match its discarded....

This is all very common to serial interfaces in use for a couple decades now, GPS's use this same protocol.

(maybe I haven't used all the right words here, but the idea is there)

pretty simple....

I am not a programmer, I am interested in learning cool things, and this gives me focus on a project that helps me learn by doing.....

So I'm doing it like this....

you like?

chirp.

 

This is not the first time someone has asked for an ASCII interface.  
I like your idea very much.
 
I also like your XOR idea too, its fast and not complicated.  
 
Are you using the MRL Arduino Service Oscope ?
Would a sensor monitor be of use for you?
 
"is there problems on the host pc because of OS or Java problems.  Why not just open a terminal window and tap out a sentence"
 
You have a very good point, One of the mantras of my design is to allow access at different levels, and not try to dictate "how" MRL will be used.  I think it is possible to type in Alt-codes to your terminal window now to MRLComm.ino ,  admittedly, its a bit of a hassle..  I would be interested in making it easier.
 
If there was an ASCII inteface for MRLComm.ino would that be sufficient for you, or are there other things which need to be in the Arduino ?  I'm wondering about MRLComm becoming a library again.
 
Have you looked at Firmata ?  http://www.firmata.org/wiki/Protocol
Or thought about a REST / URL protocol  -> e.g.  /pin/3/0   
So many things to try ... so little time ;)
 
 

 

Schlick

11 years 10 months ago

In reply to by GroG

Hey Grog,

Rest ful ish looks very interesting...

I can't hardly digest all that is here already. I am very pleased with the DirectSerial progress so far.

But I think that your suggestion with the rest interface looks cool.  I have no idea what would be required.

http code/java is a foreign language to me.

Sadly I have done no other programming projects since I took up the directserial work.  Also, I want to manufacture a teensy-ish pcb smd board....

what to do now?

 

 

Congrats on your progress Schlick,

Does it now meet all the requirements of your project?

Was curious too if you've ever used the rest of MRL (e.g. the Java part) ?

Patrick M - made a teensy smd Arduino board - he published the eagle / art  I think if thats what your after..

Hey,

I will make an output checksum function for replies, but for now I need a break from it.  too little time to work on this kind of stuff and its all I've done since I found mrl.

I have used the java interface a bit, but only for the whats this do or how does that work part of it.

I have an old laptop in the garage that is vista x64 and super slow.  but I don't do much with my w7 laptop as I use that for work.  so I loose patience quick on this dead slow box.

I have been super excited with the arduino because it just jumps to life....

So most of my attention is towards this end, and usually the hardware side of things.  I have been playing learning a little sketchup, autoit code projects, pcb design, etc....

Initially all of this was only for the effort of making 1 camera move.  I decided I needed to learn how to program a microcontroller.  My prototype board was so horrible that I decided to learn how to make a pcb...

more time passes.  I started working with eagle, and then sketchup(so cool).  Made my first couple boards and learned how incredibly easy it was to make every rookie mistake there is...

So eventually I bought this uno, and that night I was completely amazed. two years of planning, learning, dabbling, done in one night with an arduino.  Oh and then in ten minutes I found MyRobotLab and was controlling my servo with GUI. WOW. And I did'nt have to program it myself! cool.

I still cant admit defeat and must manufacture one of these little things myself just to follow through.

and I'm so damn cheap that I need to make some little boards for the little projects around the house... like the camera i wanted to move two years ago! I can't just bury this uno in a conduit box on the side of the house!

So thats my story.

oh, I can use Direct Serial just as it is for the interface I want to setup for my testbench at work.

I can directly type or program any command that MRL can do with java... and see its responce too.

This means that I can program it to my 'proprietary' interface at work for general interfacing for testing my work scripts too without having to use hardware off the 'sales' shelf.  Damn salesman always sell everything, and I end up having to tear our test/production bench up all the time.  with a duino, they can't sell that, its not in the pricebook and I'll be set.

I do alot of programming in autoit, mostly because its fully selfcontained once compiled.  On our production environment we use mostly winxp and now having to use win7.  Both out of the box with only dotnet runtimes added.  I have never attempted java, mostly because I don't have the ability to update the platforms I would want to run my apps on.  We need them to be dumb and bend to our will, we cannot have the environment change....

So mrl is helping me to be interested in other things, thanks for that.

-Jeff

 

 

GroG

12 years ago

DWR is very wise !

Use the bleeding edge - If it's using ArduinoSerialBare it is ancient ! 

MRLComm.ino uses a protocol which recovers from noise on the line and other interference.  It's much more robust.

Grab the Edge !

GroG

12 years ago

Oh, change your avatar picture too - you've graduated beyond scared gopher !

Schlick

11 years 11 months ago

/**

 * from 992 MRLcomm version... using an uno...
 *I think we are working now.......
 * upload this to your arduino, open terminal(hyperterminal) and tap out the below.          

$MRTST,6,0,6,

$MRTST,6,1,9,

$MRTST,7,0,0,

$MRTST,7,0,180,

$MRTST,7,1,0,

$MRTST,7,1,180,

two servos 1 on pin6, 1 on pin7

 * Edited to allow Direct Serial, MRL still works normal, Direct Serial resonds to proper
 * ascii input with checksum
 * paste $MRCMD,000,011,001*48 or $MRTST,0,11,1, (needs no checksum)
 * TST Requires following comma to register last bit...
 *
* @author greg (at) myrobotlab.org
*
* This file is part of MyRobotLab.
*
* MyRobotLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version (subject to the "Classpath" exception
* as provided in the LICENSE.txt file that accompanied this code).
*
* MyRobotLab is distributed in the hope that it will be useful or fun,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* All libraries in thirdParty bundle are subject to their own license
* requirements - please refer to http://myrobotlab.org/libraries for
* details.
*
* Enjoy !
*
* arduinoSerial
* -----------------
* Purpose: translate serial commands into Arduino language commands,
* mostly relating to IO.  This would allow a computer to easily take
* advantage of Arduino's great IO capabilities, while cpu number crunching
* could be done on the computer (e.g. Video processing)
*
* Created 2 Februrary 2009
*
* http://myrobotlab.org
*
* TODO - create analogSensitivity (delta) & analogGain (scalar)
* References :
*      http://www.arduino.cc/en/Reference/Constants
*
*/

#include <Servo.h>

#define DIGITAL_WRITE        0
#define DIGITAL_VALUE        1
#define ANALOG_WRITE         2
#define ANALOG_VALUE         3
#define PINMODE              4
#define PULSE_IN             5
#define SERVO_ATTACH         6
#define SERVO_WRITE          7
#define SERVO_SET_MAX_PULSE  8
#define SERVO_DETACH         9
#define SET_PWM_FREQUENCY    11
#define SET_SERVO_SPEED           12
#define ANALOG_READ_POLLING_START  13
#define ANALOG_READ_POLLING_STOP  14
#define DIGITAL_READ_POLLING_START  15
#define DIGITAL_READ_POLLING_STOP  16
#define SET_ANALOG_TRIGGER               17
#define REMOVE_ANALOG_TRIGGER            18
#define SET_DIGITAL_TRIGGER              19
#define REMOVE_DIGITAL_TRIGGER           20
#define DIGITAL_DEBOUNCE_ON              21
#define DIGITAL_DEBOUNCE_OFF             22
#define DIGITAL_TRIGGER_ONLY_ON          23
#define DIGITAL_TRIGGER_ONLY_OFF         24
#define SET_SERIAL_RATE            25

#define COMMUNICATION_RESET    252
#define SOFT_RESET      253
#define SERIAL_ERROR           254
#define NOP  255

#define MAGIC_NUMBER    170 // 10101010

// pin services
#define POLLING_MASK 1
#define TRIGGER_MASK 2
// TODO #define SERVO_SWEEP

// --VENDOR DEFINE SECTION BEGIN--
// --VENDOR DEFINE SECTION END--

// -- FIXME - modified by board type BEGIN --
#define ANALOG_PIN_COUNT 4
#define DIGITAL_PIN_COUNT 13
// -- FIXME - modified by board type END --

long debounceDelay = 50; // in ms
long lastDebounceTime[DIGITAL_PIN_COUNT];

Servo servos[MAX_SERVOS];
int servoSpeed[MAX_SERVOS];    // 0 - 100 corresponding to the 0.0 - 1.0 Servo.setSpeed - not a float at this point
int servoTargetPosition[MAX_SERVOS];  // when using a fractional speed - servo's must remember their end destination
int servoCurrentPosition[MAX_SERVOS]; // when using a fractional speed - servo's must remember their end destination
int movingServos[MAX_SERVOS];    // array of servos currently moving at some fractional speed
int movingServosCount = 0;            // number of servo's currently moving at fractional speed

unsigned long loopCount     = 0;
int byteCount               = 0;
unsigned char newByte   = 0;
unsigned char ioCommand[4];  // most io fns can cleanly be done with a 4 byte code
int readValue;

int digitalReadPin[DIGITAL_PIN_COUNT];        // array of pins to read from
int digitalReadPollingPinCount = 0;           // number of pins currently reading
int lastDigitalInputValue[DIGITAL_PIN_COUNT]; // array of last input values
int digitalPinService[DIGITAL_PIN_COUNT];     // the services this pin is involved in
bool digitalTriggerOnly = false;      // send data back only if its different

int analogReadPin[ANALOG_PIN_COUNT];          // array of pins to read from
int analogReadPollingPinCount = 0;            // number of pins currently reading
int lastAnalogInputValue[ANALOG_PIN_COUNT];   // array of last input values
int analogPinService[ANALOG_PIN_COUNT];       // the services this pin is involved in
bool analogTriggerOnly = false;         // send data back only if its different

unsigned long retULValue;

unsigned int errorCount = 0;

// MRL DirectSerial Protocol
//int newByte = 0;

int inputgroup[10] = {
  0,0,0};
char inputData[300] = "";
char Checksum[3] = "  ";
char Cmd[4] = "   ";
int group = 0;
int group1 =0;
int stat = 0;
int cnt = 0;
int subSection[45];
char iochar[] ="";
int byteMode = 0;
const char MrlID[4] = "$MR";
int calcChecksum ;
int XOR;
int check = 0;
int ChkMatch= 0;
int stopXOR = 0;
int ValidateChecksum = 0;
char hx[5] = "0x00";
char buffer[5] = "0x00";
char ipdatabuff[5] = "0000";
unsigned char nmeaChk;
int PrintVariables = 0;
int ProceedAllowed =0;
int tstMode=0;
int Nogood = 0;
long int li1= 0;
long int li2= 0;
char *pEnd;
int ReturnMode = 0; // when return is required, use to return true or false
int Reset = 0; // when return is required, use to reset variables.
// End MRL DirectSerial definitions

void PrintVariablesList () {

  if (PrintVariables == 1){ //reset variables
    // variables
    Serial.println("============================Variables=================================");
    Serial.print("cnt");
    Serial.println(cnt);
    Serial.print("inputData[i]=");
    Serial.println(inputData);
    Serial.print("group = ");
    Serial.println(group);
    Serial.print("group1 =");
    Serial.println(group1);
    Serial.print("stat=");
    Serial.println(stat);
    Serial.print("check=");
    Serial.println(check);
    Serial.print("calcChecksum=");
    Serial.println(calcChecksum);
    Serial.print("Checksum[] = ");
    Serial.println(Checksum);
    Serial.print("hx[] = ");
    Serial.println(hx);
    Serial.print("nmeaChk =");
    Serial.println(nmeaChk);
    Serial.print("stopXOR = ");
    Serial.println(stopXOR);
    Serial.print("byteCount=");
    Serial.println(byteCount);
    Serial.print("ChkMatch= ");
    Serial.println(ChkMatch);
    Serial.print("ValidateChecksum = ");
    Serial.println(ValidateChecksum);
    Serial.print("inputgroup[]=");
    Serial.println(*inputgroup);
    Serial.print("byteMode =");
    Serial.println(byteMode);
    Serial.print("Reset = ");
    Serial.println(Reset);
    Serial.print("XOR= ");
    Serial.println(XOR);
    Serial.print("buffer[] = ");
    Serial.println(buffer);
    Serial.println(" Variables Print");
    Serial.println("==============================================================================");

    PrintVariables = 0; 
  }
  return;
} //PrintVariables
void ResetVariables(){ //reset variables
  PrintVariablesList ();
  // variables
  cnt=0;                    // Reset the buffer
  for (int i=0;i<300;i++){    // 
    inputData[i]=' ';
  }
  group = 0;               // Reset the group bit for next time sentence is received
  group1 =0;
  stat =0;               // Reset the status bit for next time sentence is received
  check=0;
  //char hx[5] = "0x00";
  //hx[5] = 0x00;
  hx[0] = '\0';
  hx[1] = 'x';
  hx[2] = '\0';
  hx[3] = '\0';
  hx[4] = '\0';

  char buffer[5] = "0x00";
  nmeaChk = 0;
  calcChecksum=0;
  stopXOR = 0;
  byteCount=0;
  ChkMatch= 0;
  ValidateChecksum = 0;
  inputgroup[10]=0;
  cnt=0;
  //byteMode =0;
  Reset = 0;
  XOR= 0;
  ProceedAllowed =0;
  tstMode=0;
  Nogood=0;
  li1= 0;
  li2= 0;
  char MrlID[4] = "$MR";
  byteCount=0;
  ReturnMode=0;
  Serial.println("Variables are Reset");
  //softReset();
  return;
}  //reset variables

void setup() {
 Serial.begin(57600);        // connect to the serial port

 softReset();

 // --VENDOR SETUP BEGIN--
 // --VENDOR SETUP END--
}

//
void softReset()
{

 for (int i = 0; i < MAX_SERVOS - 1; ++i)
 {
  servoSpeed[i] = 100;
  servos[i].detach();
 }

 for (int j = 0; j < DIGITAL_PIN_COUNT - 1; ++j)
 {
  pinMode(j, OUTPUT);
 }

 digitalReadPollingPinCount = 0;
 analogReadPollingPinCount = 0;
 loopCount = 0;

}

void setPWMFrequency (int address, int prescalar)
{
 int clearBits = 0x07;
 if (address == 0x25)
 {
  TCCR0B &= ~clearBits;
  TCCR0B |= prescalar;
 } else if (address == 0x2E)
 {
  TCCR1B &= ~clearBits;
  TCCR1B |= prescalar;
 } else if (address == 0xA1)
 {
  TCCR2B &= ~clearBits;
  TCCR2B |= prescalar;
 }

}

void removeAndShift (int array [], int& len, int removeValue)
{
 int pos = -1;

 if (len == 0)
 {
  return;
 }

 // find position of value
 for (int i = 0; i < len; ++i)
 {
  if (removeValue == array[i])
  {
   pos = i;
   break;
  }
 }
 // if at the end just decrement size
 if (pos == len - 1)
 {
  --len;
  return;
 }

 // if found somewhere else shift left
 if (pos < len && pos > -1)
 {
  for (int j = pos; j < len - 1; ++j)
  {
   array[j] = array[j+1];
  }
  --len;
 }
}

/*
* getCommand - retrieves a command message
 * input messages are in the following format
 *
 * command message - (4 byte protocol) MAGICNUMBER|FUNCTION|DATA0|DATA1
 * e.g. digitalWrite (13, 1)     = DIGITAL_WRITE|13|1 = 170|0|13|1
 *
 * return message  - (5 byte protocol) MAGICNUMBER|FUNCTION|DATA0|MSB|LSB
 * e.g. results of analogRead = ANALOG_READ|3|1|1  = 170|3|3|257
 *
 * $MRCMD,xxx,xxx*FF
 * $MRCMD,000,013,001*4A
 * checksum ref http://www.hhhh.org/wiml/proj/nmeaxor.html
 *
 */
           /*
$MRCMD,000,013,001*4A
$MRCMD,000,013,000*4B
$MRTST,000,013,000,1,2,3,4
$MRTST,6,11,0,
$MRTST,7,11,50,100,
$MRTST,0,12,0,
$MRTST,0,12,1,
 */

boolean getCommand ()
{
  // handle serial data begin
  if (Serial.available() > 0)
  {
    // read the incoming byte:
    newByte = Serial.read();

    if (byteCount == 0 && newByte != MAGIC_NUMBER)
    {
      // ERROR !!!!!
      // TODO - call modulus error method - notify sender

      //++errorCount;
      //return false;
      byteMode=1;
      //++byteCount;
    }
    if (byteCount == 0 && newByte == MAGIC_NUMBER)
    {
      byteMode=0; //Ensure MRL Natural protocol
    }
    if (byteMode==0){ //MRL Natural
      ioCommand[byteCount] = newByte;
      ++byteCount;

      if (byteCount > 3)
      {
        return true;
      }
      else{
        return false;
      }

    } //MRL Natural
    if (byteMode==1){ //MRL Direct Serial
      //

      inputData[cnt] = newByte;        // If there is serial port data, it is put in the buffer
      cnt++;
      if (newByte==13)            // If the received byte is = to 13, end of transmission
      {

        //PrintVariables = 0;
        //PrintVariablesList();
        Serial.println("----------------------");
        Serial.println(inputData); 
        Serial.println("----------------------");
        //for (int ij=0;ij<3;ij++){     // Verifies if the received command starts with $MR
        if (inputData[0] == MrlID[0]&& inputData[1] == MrlID[1]&&inputData[2] == MrlID[2]){
          stat=3;
          Serial.println("---Good------");
          // Serial.println(stat);
        }
        else{
          Nogood = 1;
          Serial.println("---No Good-----");
          //Serial.println(stat);
        }
        //}
      }
      //Serial.println("stat=");Serial.println(stat);
      //if (Nogood = 1 && stat <3){//$MR not found
      //  ReturnMode = 2;
      //  Reset =1;
      //}
      if(newByte==13 && stat==3){               // If $MR, continue and process the data
        //Serial.println("status stat==3");
        for (int i=0;i<cnt;i++){
          if (i==5){
            //Serial.print("status i=="); Serial.println(i);
            //Serial.print("cnt="); Serial.println(cnt);
            // since $MR assume valid command incoming
            Cmd[0] = inputData[i-2]; 
            Cmd[1] = inputData[i-1]; 
            Cmd[2] = inputData[i];  
            //Serial.print("Cmd:"); Serial.println(Cmd);
            // sets Cmd = to buffer data position 3-5
            if (Cmd[0]=='t'|Cmd[0]=='T'&&Cmd[1]=='s'|Cmd[1]=='S'&&Cmd[2]=='t'|Cmd[2]=='T'){
              ValidateChecksum = 1;
              stopXOR = 1;
              ProceedAllowed =1;
              tstMode=1;
              Serial.println("No Checksum Required for Test cmd");
            }//tst mode, no checksum required
            else{
              ValidateChecksum = 0; // checksum required
              stopXOR = 0;
              ProceedAllowed =0;
              Serial.println("Checksum Required for CMD");
            }

          }
          if (inputData[i]==','){    // check for the "," separator and set a group relationship to it.
            //Serial.println("inputData[i]==','");
            subSection[group]=i;
            group++;
          }

          if (inputData[i]=='*'){    // check for the "*"
            //Serial.println("inputData[i]=='*'");
            stopXOR = 1;
            subSection[group]=i;   // no more commas so set last group bounds
            inputgroup[group] += inputData[i];
            group++;
            Checksum[0] = inputData[i+1];
            Checksum[1] = inputData[i+2];
            Checksum[2] = 0x00;
            //Serial.println("Found *");
            //String BufferChecksum = char(Checksum[1]) & char(Checksum[2])

            //calcChecksum ^=  check;
            //-----------------

            //-----------------
            //Serial.print("BufferChecksum=");
            //Serial.print(BufferChecksum);
            // Serial.print("Calculated checksum=:");
            // Serial.println(calcChecksum);
          }
          if (inputData[i] !='*'){
            //Serial.println("inputData[i] !='*'");
            // still getting data
            //-----------------
            if (( inputData[i] != '$') && stopXOR == 0){
              check ^= (inputData[i]);
              //Serial.print("check=");
              //Serial.print(inputData[i]);
              //Serial.print("<-in : check = ");
              //Serial.println(check);

              //-----------------
              //Reset=1;
              //byteCount=0;
            }
          } //!='*'
          //Serial.println(inputData[i]);
        }  // i==5 cmd group

        if (ValidateChecksum == 0 && stopXOR == 1){
          //Checksum compare the check (decimal) to Checksum[1] and Checksum[2]
          // below structure of serial port received checksome data

          //hx[1] = 0x00;
          hx[2] = Checksum[0];
          hx[3] = Checksum[1];
          hx[1] = 'x';
          hx[0] = '0';
          nmeaChk = atoi(hx); //hx[2] + hx[3];
          //below structure of calculated checksum xor data
          sprintf(buffer,"0x%2X",check);
          //Serial.print(buffer);Serial.println(hx);
          //Serial.print(buffer);
          //Serial.print("<- Hex calc. checksum : Serial checksum ->");
          //Serial.println(hx);
          PrintVariables = 1;
          PrintVariablesList();
          if (strcmp(buffer,hx)) { // false match
            Serial.println("No Checksum Match");
            ValidateChecksum = 1;
            ChkMatch= 0; // 1=match 0 = no match/abort
            ProceedAllowed =0;
            ReturnMode = 2;
            ResetVariables();
          }
          else{  // true match
            Serial.println("Checksum's Match");
            //Serial.print(buffer);
            //Serial.print("<- Hex calc. checksum: Serial checksum ->");
            //Serial.println(hx);
            ValidateChecksum = 1;
            ChkMatch= 1; // 1=match 0 = no match/abort
            ProceedAllowed =1;
          }
        }//end checksum check required
        //Serial.print("group=");Serial.println(group);
        if (ValidateChecksum == 1 && ProceedAllowed ==1){ //display output
          for (int ii=0;ii<10;ii++){    //  Clear ioCommand[]
            ioCommand[ii]=0;
            iochar[ii]=0;
          }
          //Serial.println("--ioCommand--");
          //Serial.println(ioCommand[0]);
          //Serial.println(ioCommand[1]);
          //Serial.println(ioCommand[2]);
          //Serial.println(ioCommand[3]);

          for (int i=0;i<group+1;i++){  //good data return
            switch(i){
            case 0 :
              Serial.print("Group 1: ");
              break;
            case 1 :
              Serial.print("Group 2: ");
              break;
            case 2 :
              Serial.print("Group 3: ");
              break;
            case 3 :
              Serial.print("Group 4: ");
              break;
            case 4 :
              Serial.print("Group 5: ");
              break;
            case 5 :
              Serial.print("Group 6: ");
              break;
            case 6 :
              Serial.print("Group 7: ");
              break;
            case 7 :
              Serial.print("Group 8: ");
              break;
            case 8 :
              Serial.print("Group 9: ");
              break;
            case 9 :
              Serial.print("Group 10: ");
              break;
            case 10 :
              Serial.print("Group 11: ");
              break;
            case 11 :
              Serial.print("Group 12: ");
              break;
            }
            int q =0;
            //*iochar=0x48;
            li1=0;
            li2=0;
            //*pEnd=-1;
            for (int m=subSection[i];m<(subSection[i+1]-1);m++){
              //if (inputData[m+1] == '/0'){inputData[m+1] =' ';}             
              iochar[q]=inputData[m+1];
              //Serial.print("m=");Serial.println(m);
              Serial.print(inputData[m+1]);

              q++;
              //-----------------------------------
              // How to format what I have to be useable in MRL format?....

            }
            iochar[q]=' ';
            Serial.println("");
            //-------Set ioCommand[]--------------

            //long int li1;
            li1='      ';
            li1 =strtol (iochar,&pEnd,10);
            char buffera [10]="         ";
            char buffers [10]="         ";
            sprintf (buffera, "%X", li1);
            sprintf (buffers, "%s", buffera);
            unsigned char li3 =strtol (buffera,&pEnd,16);
            if (q==1&&*iochar=='0'){
              li3=0;
              }
            if (q==0){
              li3=-1;
              }
            ioCommand[i+1] =li3;
            //Serial.print("li1=");Serial.println(li1);
            //Serial.print("li3=");Serial.println(li3);
          }//good data return

          ReturnMode = 1;
          ioCommand[0] = MAGIC_NUMBER;
        } //display output
      }  //stat==3 

      if (Nogood == 1 && stat !=3){
        Serial.println("Nogood ==1 and stat!=3");
        ReturnMode = 2;
        Reset =1;
      }

      if (tstMode=1 && byteCount > 300){
        ReturnMode = 0;
        ResetVariables();
      }
      if (byteMode ==1  && stat>=25){
        Serial.println("byteMode ==0 && newByte ==13 && stat>=5");
        ++errorCount;
        byteMode =0;
        ReturnMode = 2;
        Reset =1;
      }
      if (ReturnMode == 1){
        // ReturnMode =0;
        Serial.println("");
        PrintVariables = 0;
        // Serial.println("---------------");

        //for (int n = 0 ;n<10;n++){
        //  Serial.println(inputgroup[n]);
        //}

        Serial.println("--ioCommand--");
        Serial.println(ioCommand[0]);
        Serial.println(ioCommand[1]);
        Serial.println(ioCommand[2]);
        Serial.println(ioCommand[3]);
        Serial.println(ioCommand[4]);
        Serial.println(ioCommand[5]);
        Serial.println(ioCommand[6]);
        ResetVariables();
        Serial.println("----------------------");
        return true;
      }
      if (ReturnMode == 2){
        ReturnMode =0;
        ResetVariables();
        Serial.println("Return false requested!");

        return false;
      }

    }//byteMode ==1

  } // if Serial.available

    //return false;
}

/*
set pollingRead = true if any of the pins are commanded to read
default behavior should be to poll read
*/

void loop () {

 ++loopCount;

 if (getCommand())
 {
  /*
  must comment out debugging - if serial control is used
  all Serial, debugging assumes no
  interference will occur due to serial
  processing
  */

  /*
  Serial.print("c[");
  Serial.print(ioCommand[0],HEX);
  Serial.print("|");
  Serial.print(ioCommand[1],HEX);
  Serial.print("|");
  Serial.print(ioCommand[2],HEX);
  Serial.print("]\n");
  */

  switch (ioCommand[1])
  {
  case DIGITAL_WRITE:
   digitalWrite(ioCommand[2], ioCommand[3]);
   break;
  case ANALOG_WRITE:
   analogWrite(ioCommand[2], ioCommand[3]);
   break;
  case PINMODE:
   pinMode(ioCommand[2], ioCommand[3]);
   break;
  case PULSE_IN:
   retULValue = pulseIn(ioCommand[2], ioCommand[3]);
   break;
  case SERVO_ATTACH:
   servos[ioCommand[2]].attach(ioCommand[3]);
                        break;                               
  case SERVO_WRITE:

   if (servoSpeed[ioCommand[2]] == 100) // move at regular/full 100% speed
   {  
    // move at regular/full 100% speed
    // although not completely accurate
    // target position & current position are
    // updated immediately
     servos[ioCommand[2]].write(ioCommand[3]);
                                servoTargetPosition[ioCommand[2]] = ioCommand[3];
    servoCurrentPosition[ioCommand[2]] = ioCommand[3];
   } else if (servoSpeed[ioCommand[2]] < 100 && servoSpeed[ioCommand[2]] > 0) {
    // start moving a servo at fractional speed
    servoTargetPosition[ioCommand[2]] = ioCommand[3];
    movingServos[movingServosCount]=ioCommand[2];
    ++movingServosCount;
   } else {
    // NOP - 0 speed - don't move
   }
   break;
  case SET_SERVO_SPEED:
   // setting the speed of a servo
   servoSpeed[ioCommand[2]]=ioCommand[3];
   break;
  case SERVO_SET_MAX_PULSE:
   //servos[ioCommand[2]].setMaximumPulse(ioCommand[3]);    TODO - lame fix hardware
   break;
  case SERVO_DETACH:
   servos[ioCommand[2]].detach();
   break;
  case SET_PWM_FREQUENCY:
   setPWMFrequency (ioCommand[2], ioCommand[3]);
   break;
  case ANALOG_READ_POLLING_START:
   analogReadPin[analogReadPollingPinCount] = ioCommand[2]; // put on polling read list
   analogPinService[ioCommand[2]] |= POLLING_MASK;
   // TODO - if POLLING ALREADY DON'T RE-ADD - MAKE RE-ENTRANT - if already set don't increment
   ++analogReadPollingPinCount;
   break;
  case ANALOG_READ_POLLING_STOP:
   // TODO - MAKE RE-ENRANT
   removeAndShift(analogReadPin, analogReadPollingPinCount, ioCommand[2]);
   analogPinService[ioCommand[2]] &= ~POLLING_MASK;
   break;
  case DIGITAL_READ_POLLING_START:
   // TODO - MAKE RE-ENRANT
   digitalReadPin[digitalReadPollingPinCount] = ioCommand[2]; // put on polling read list
   ++digitalReadPollingPinCount;
   break;
  case DIGITAL_READ_POLLING_STOP:
   // TODO - MAKE RE-ENRANT
   removeAndShift(digitalReadPin, digitalReadPollingPinCount, ioCommand[2]);
   digitalPinService[ioCommand[2]] &= ~POLLING_MASK;
   break;
  case SET_ANALOG_TRIGGER:
   // TODO - if POLLING ALREADY DON'T RE-ADD - MAKE RE-ENTRANT
   analogReadPin[analogReadPollingPinCount] = ioCommand[2]; // put on polling read list
   analogPinService[ioCommand[2]] |= TRIGGER_MASK;
   ++analogReadPollingPinCount;
   break;
  case DIGITAL_DEBOUNCE_ON:
   debounceDelay = 50;
   break;
  case DIGITAL_DEBOUNCE_OFF:
   debounceDelay = 0;
   break;
  case DIGITAL_TRIGGER_ONLY_ON:
   digitalTriggerOnly = true;
   break;
  case DIGITAL_TRIGGER_ONLY_OFF:
   digitalTriggerOnly = false;
   break;
  case SET_SERIAL_RATE:
   Serial.end();
   delay(500);
   Serial.begin(ioCommand[2]);
   break;
   
  case SOFT_RESET:
   softReset();
   break;

   // --VENDOR CODE BEGIN--
   // --VENDOR CODE END--

  case NOP:
   // No Operation
   break;
  default:
   //             Serial.print("unknown command!\n");
   break;
  }

  // reset buffer
  ioCommand[0] = -1; // MAGIC_NUMBER
  ioCommand[1] = -1; // FUNCTION
  ioCommand[2] = -1; // PARAM 1
  ioCommand[3] = -1; // PARAM 2
  byteCount = 0;

 } // if getCommand()

 // digital polling read - send data for pins which are currently in INPUT mode only AND whose state has changed
 for (int i  = 0; i < digitalReadPollingPinCount; ++i)
 {
  if (debounceDelay)
  {
    if (millis() - lastDebounceTime[digitalReadPin[i]] < debounceDelay)
    {
      continue;
    }
  }
 
  // read the pin
  readValue = digitalRead(digitalReadPin[i]);

  // if my value is different from last time  && config - send it
  if (lastDigitalInputValue[digitalReadPin[i]] != readValue  || !digitalTriggerOnly)
      if (lastDigitalInputValue[digitalReadPin[i]] != readValue  || !digitalTriggerOnly)
    {if (byteMode==0){ //MRL protocol
      Serial.write(MAGIC_NUMBER);
      Serial.write(DIGITAL_VALUE);
      Serial.write(digitalReadPin[i]);// Pin#
      Serial.write(readValue >> 8);   // MSB
      Serial.write(readValue);  // LSB
      }else{ //DirectSerial
      Serial.print(MAGIC_NUMBER);
      Serial.print("|");
      Serial.print(DIGITAL_VALUE);
      Serial.print("|");
      Serial.print(digitalReadPin[i]);// Pin#
      Serial.print("|");
      Serial.print(readValue >> 8);   // MSB
      Serial.print("_");
      Serial.println(readValue);  // LSB
      }
      lastDebounceTime[digitalReadPin[i]] = millis();
     
    }

  // set the last input value of this pin
  lastDigitalInputValue[digitalReadPin[i]] = readValue;
 }

 // analog polling read - send data for pins which are currently in INPUT mode only AND whose state has changed
 for (int i  = 0; i < analogReadPollingPinCount; ++i)
 {
  // read the pin
  readValue = analogRead(analogReadPin[i]);

  // if my value is different from last time - send it
      if (lastAnalogInputValue[analogReadPin[i]] != readValue   || !analogTriggerOnly) //TODO - SEND_DELTA_MIN_DIFF
    {if (byteMode==0){ //MRL protocol
      Serial.write(MAGIC_NUMBER);
      Serial.write(ANALOG_VALUE);
      Serial.write(analogReadPin[i]);
      Serial.write(readValue >> 8);   // MSB
      Serial.write(readValue & 0xFF); // LSB
      }else{ //DirectSerial
      Serial.print(MAGIC_NUMBER);
      Serial.print("|");
      Serial.print(ANALOG_VALUE);
      Serial.print("|");
      Serial.print(analogReadPin[i]);
      Serial.print("|");
      Serial.print(readValue >> 8);   // MSB
      Serial.print("_");
      Serial.println(readValue & 0xFF); // LSB
      }
    }
  // set the last input value of this pin
  lastAnalogInputValue[analogReadPin[i]] = readValue;
 }

 // handle the servos going at fractional speed
 for (int i = 0; i < movingServosCount; ++i)
 {
  int servoIndex = movingServos[i];
  int speed = servoSpeed[servoIndex];
  if (servoCurrentPosition[servoIndex] != servoTargetPosition[servoIndex])
  {
   // caclulate the appropriate modulus to drive
   // the servo to the next position
   // TODO - check for speed > 0 && speed < 100 - send ERROR back?
   int speedModulus = (100 - speed) * 10;
   if (loopCount % speedModulus == 0)
   {
    int increment = (servoCurrentPosition[servoIndex]<servoTargetPosition[servoIndex])?1:-1;
    // move the servo an increment
    servos[servoIndex].write(servoCurrentPosition[servoIndex] + increment);
    servoCurrentPosition[servoIndex] = servoCurrentPosition[servoIndex] + increment;
   }
  } else {
   removeAndShift(movingServos, movingServosCount, servoIndex);
  }
 }

 

} // loop

GroG

11 years 11 months ago

Hi Schlick,

Nice to see ya again.

I looked at your update a litte.  Your out of sync, MRLComm.ino has changed - (we move fast here :)

I think a XOR checksum is a good idea...

Would a RESTful (ish) protocol work for your requirements?

to write pin 13 LOW

/pin/13/0   

to write pin 13 HIGH

/pin/13/1

to read pin 13

/pin/13

If a protocol adapter like this was put into place - would it satisfy your problems?

Hey Grog,

I was able to checksum match, thats now  working today! yay!

I am closer with my concept.  Here is what I like about what I am trying to do.

I am presenting another alternative to your natural input.  either is sufficient, and either all the time.

Your protocol is faster, no doubt, don't remove it, it's perfect....

Ascii based input is slower by nature because it requires more bytes to be transmitted to accomplish the same.

I am (in progress/attempting) to convert to the native code inside the arduino so your original MRLcomm is still intact. 

the matrix that you are using is all that is needed, and if txt names are desired, they can easily be declared for use. 

$MR   start of valid cmd sentence... consider it magicnumber 170

         XXX,   command also iocommand[1]. if cmd is TST then checksum requirement  will be disabled.

                  XXX,XXX parameters , iocommand[2] &[3]

                                 , XXX,XXX,XXX,XXX  so far extra parameters are available, not yet defined

                                                                    *XX  Checksum (Hex XOR everything between $ and *)

I will pursue this, because it is a standard type serial interface....

... not saying what you are suggesting is not better......

Still learning, slowly...

Thanks for the help yesterday

Jeff