decrypt numbers in processing.

Hey.
A whole day and this has me beat.

All i want to do is send a number from 0-4095 (multiple actually, but within that range) through to processing.

i have been copying ways to do it from posts.

the way i have it setup now, is an array method (hah just took me 20 secs to get array into my head), which is not what i want to end up with. but still i want to know why its not working.

the method i want to end up with is to have an identifier, and a value eg…(T2, 4095), and have what ever is recieving process based on the identifier.

i have used the serial monitor to print out the numbers from arduino and they add up. So as far as i can figure, actually i cant. Im getting accurate numbers up to a point on the processing side but then gobbledygoop.

arduino code

#include "SPI.h" 
#include "SBS_Time.h"

unsigned int TPS_Output = 0;
 int TPS1_Value = 0;          // a word is a 16-bit number
byte TPS1data = 0;            // and a byte is an 8-bit number
 int TPS2_Value = 0;          // a word is a 16-bit number
byte TPS2data = 0;            // and a byte is an 8-bit number

int inByte = 0;               // incoming serial byte

SBS::Timer upButton(1, 'm');  // initialise timers
SBS::Timer downButton(1, 'm');
SBS::Timer timerSerial(50, 'm');

int upButtonPressed = 0;
int downButtonPressed = 0;
int upPin2 = 2;
int downPin3 = 3;

unsigned int buttons = 0;

void setup()
{
// set up serial  
  Serial.begin(115200);
// set up pins
  pinMode(7, OUTPUT);   // CS TPS2
  pinMode(10, OUTPUT);  // CS TPS1
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(upPin2, INPUT);
  pinMode(downPin3, INPUT);


// set up SBS::Timers
  timerSerial.start();				// start serial timer
// Initiate the SPI bus  
  SPI.begin();					// wake up the SPI bus.
  SPI.setBitOrder(MSBFIRST);	// send top register SPI data first

  establishContact();
}


void establishContact() 
{
  while (Serial.available() <= 0) 
  {
    Serial.print('A'); // send a capital A
    delay(300);
  }
}

void updateTPS1()
{
  TPS1_Value = TPS_Output;
//  TPS1_Value = map(TPS1_Value, 0, 4095, 3000, 850);
  digitalWrite(10, LOW);
  TPS1data = highByte(TPS1_Value);
  TPS1data = 0b00001111 & TPS1data;
  TPS1data = 0b00110000 | TPS1data;
  SPI.transfer(TPS1data);
  TPS1data = lowByte(TPS1_Value);
  SPI.transfer(TPS1data);   // SPI.transfer(TPS1data);
  digitalWrite(10, HIGH); 
}

void updateTPS2()
{
  TPS2_Value = TPS_Output;
  digitalWrite(7, LOW);
  TPS2data = highByte(TPS2_Value);
  TPS2data = 0b00001111 & TPS2data;
  TPS2data = 0b00110000 | TPS2data;
  SPI.transfer(TPS2data);
  TPS2data = lowByte(TPS1_Value);
  SPI.transfer(TPS2data);
  digitalWrite(7, HIGH); 
}


void updateButtons()
{
   if(digitalRead(upPin2))
  {
    if(upButton.justFinished())  // 
    {
      if(buttons < 4095)
      {
        buttons = buttons + 1; 
      }
	  buttons = buttons <= 4095 ? buttons: 4095;
    }
    TPS_Output = buttons;
    upButton.Continue();
  }  

  if(digitalRead(downPin3))
  {
    if(downButton.justFinished())
    {    
      if(buttons >= 1)
      {
      buttons = buttons - 1; 
      }
	  buttons = buttons >= 0 ? buttons: 0;
    TPS_Output = buttons;
    }
    downButton.Continue();
  } 
}

 void updateTimerSerial() {
    if(timerSerial.justFinished()) {      
      if (Serial.available() > 0) 
      {
        inByte = Serial.read();
        Serial.print(TPS1_Value / 256);   // (((TPS1_Value / 256)*256) + (TPS1_Value % 256));
        Serial.print(TPS1_Value % 256);        
        Serial.print(TPS2_Value / 256);
        Serial.print(TPS2_Value % 256);
//        Serial.print('A');
//        inByte = 0;
      }   
    }
    timerSerial.Continue();      
 }




void loop()
{ 
  updateButtons(); 
  updateTPS1();
  updateTPS2();
  updateTimerSerial(); 
}

processing code

import processing.serial.*;

Serial port;  // Create object from Serial class
int[] serialInArray = new int[4]; // Where we'll put what we receive
int serialCount = 0;     // A count of how many bytes we receive
boolean firstContact = false;
int TPS1high;
int TPS1low;
int TPS2high;
int TPS2low;
float TPS1;
float TPS2;

void setup() {
   size(750, 250);  // Set the font and its size (in units of pixels)
   stroke(255);
   smooth();
  
    //println(Serial.list());
    port = new Serial(this, "COM5", 115200); 
    //port.bufferUntil('\n');
 }


void draw() {

  float n = TPS1;  
  int x = 125;
  int y = 125;  
  PFont fontA;
  fontA = loadFont("Latha-32.vlw");
  background(0);                      // black background
  fill(0);                           // circle colour
  strokeWeight(1);                   // thickness of circle outline
  stroke(255);                        // colour of circle
  ellipse(x, y, 160, 160);        // position of circle
   
  int rn = round(n);                    // convert float to int
  //int s = rn;  
  float ratio = map(rn, 0, 4095, 0, PI);
  stroke(255);
  strokeWeight(4);
  line(x, y,  x - (cos(ratio)*69), y - (sin(ratio)*69));  // draw needle
   
  fill(100);                        // text colour  
  textFont(fontA, 25);              // font
  textAlign(CENTER, CENTER);        // position   
  text(100 * rn / 4095, x, y + 30);   // text
 
  stroke(255, 0, 0);    // Draw the minute ticks
  fill(255, 0, 0);
  strokeWeight(4);
  PFont fontb;
  fontb = loadFont("Latha-32.vlw");
  for (int a = 180; a <= 360; a+=18)
   {
     float i = x + ( cos(radians(a)) * 90 );
     float j = y + ( sin(radians(a)) * 90 );
     textFont(fontb, 12);
     text(ceil((a - 180)/1.8), i, j);
   }
 
  for (int a = 180; a <= 360; a+=10) 
   {
     float i = x + ( cos(radians(a)) * 74 );
     float j = y + ( sin(radians(a)) * 74 );
     point(i, j);
   }
  
}

void serialEvent (Serial port) 
{
  int inByte = port.read();
  if (firstContact == false) 
  {
    if (inByte == 'A') 
    {
      port.clear();   // clear the serial port buffer
      firstContact = true;  // you've had first contact from the microcontroller
      port.write('A');  // ask for more
    }
  }
  else 
  {
    //println(serialInArray[0]);
    //println(serialInArray[1]);
    //println(serialInArray[2]);
    //println(serialInArray[3]);
    
    
    serialInArray[serialCount] = inByte;
    serialCount++;
    if (serialCount > 3 ) 
    {
      //int x = (((serialInArray[0]-48)*256) + (serialInArray[1]-48));
      TPS1 = (((serialInArray[0]-48)*256) + (serialInArray[1]-48));
      //TPS2 = (serialInArray[2]) + serialInArray[3];
      
      println(TPS1);
      //println(serialInArray[1]-48);
      port.write('A');
      serialCount = 0;
      //port.clear(); 
    }
  }
}

any help appreciated

Another question which may or may not be slightly off topic.

the arduino code runs 2x DACs through SPI, every time the processing connects up the DACs get reset to there starting position. Anyone know why?

Cheers

No idea about the corrupted data; maybe you must indicate what 'gobbledygoop' exactly means.

Most Arduinos reset when you make a connection via the 'serial port'; that might be the explanation for your second problem. Workarounds have been described; do a search.

numbers fluctuating, i might get readings up to about 1200, and then they start fluctuating.

Is the method of converting a number back in processing correct.

so in establishContact you flood the receiver side by sending tons of ‘A’ until you get something back which you don’t read

On the Processing side, you wait for a firstContact by expecting JUST ONE A - if you got multiple A you don’t ignore them

I guess that’s fine if you launch your processing software before the arduino but not in the other case (unless your arduino, like most, reset when getting the serial connection)

and then you send an ‘A’ with port.write('A');  // ask for more

that ‘A’ is captured (although you don’t check if that was really an ‘A’) in the updateTimerSerial that you call at each end of the main loop.

in updateTimerSerial you do

        Serial.print(TPS1_Value / 256);   // (((TPS1_Value / 256)*256) + (TPS1_Value % 256));
        Serial.print(TPS1_Value % 256);        
        Serial.print(TPS2_Value / 256);
        Serial.print(TPS2_Value % 256);

TPS1_Value in an int - you shift it by 8 bits to the right (would be faster with >>8 rather than dividing by 256), so Serial.print has a parameter of type int, which means it will send the ASCII representation of those 2 bytes on the Serial line and then you send the modulo in ASCII as well

On the processing side you are actually waiting for 4 bytes

    serialInArray[serialCount] = inByte;
    serialCount++;
    if (serialCount > 3 ) {...

and once you have received 4 bytes, you do the ASCII conversation back to numbers math operation on the values:

      TPS1 = (((serialInArray[0]-48)*256) + (serialInArray[1]-48));

(note: would be faster to use <<8 to multiply by 256)

Here is your challenge:

You said you are 100% sure that your values are between 0 and 4095, so when you divided by 256 for the first Serial.print, you get a value between 0 and 16 to send and as you did not specify any formatter to Serial.print, you send the decimal representation in ASCII BUT you don’t actually know how many bytes will be sent.

if you are lucky and the value is larger than or equal to 10 then you do get two bytes, but if it’s lower than 10 only 1 ASCII byte will be written but you will be waiting for 2 bytes on the Processing side… and that’s where your trouble begins… then your values are getting out of sync, you confuse the sending of the modulo (which will have the same issue if the ASCII representation of the modulo is less than 9 - only 1 digit sent) for the second byte and… long story short, you are toast :slight_smile:

I’m a bit confused why you do this. You should explore sending bytes not ASCII. just use Serial.write(TPS1_Value,2); which will send your int’s 2 bytes to Processing starting with Most significant byte first.

You need to check the endianness of your computer on the processing side and if integers would be on 2 or 4 bytes to rebuild a value there

makes sense?

makes sense?

not really, ithought by doing a serial print i was sending bytes, serial write was asc11.

i tried your method

Serial.write (TPS1_Value, 2);

and i get error messages

generator_MCP4921_DACx2_parse_copy:120: error: call of overloaded 'write(int&, int)' is ambiguous

Serial.write (TPS1_Value, 2);

error message attached

i dont think the way im trying is very elegant at all, but had to start somewhere. Finding good, current info on serial hasnt been all that easy.

i understand the bit shifting, but one thing at a time.

error.txt (8.88 KB)

ive tried this also

int x = TPS1_Value;
//        inByte = Serial.read();
        byte TPS1_MSB = ((x) >> 8);
        byte TPS1_LSB = ((x) & 0xFF);
        Serial.write (TPS1_MSB);
        Serial.print(" ; ");
        Serial.write (TPS1_LSB);
        Serial.println();

and this is what i get for my troubles from the serial monitor - see attached.

Capture.JPG

and the result attached using serial print

int x = TPS1_Value;
//        inByte = Serial.read();
        byte TPS1_MSB = ((x) >> 8);
        byte TPS1_LSB = ((x) & 0xFF);
        Serial.print (TPS1_MSB);
        Serial.print(" ; ");
        Serial.print (TPS1_LSB);
        Serial.println();

super confused

Capture.JPG

@joeblogs

try this code with your arduino

int TPS1_Value = 3873; // 15 * 256 + 33
int TPS1_MSB = TPS1_Value >> 8;
int TPS1_LSB = TPS1_Value & 0xFF;

int TPS2_Value = 1289; // 5 * 256 + 9
int TPS2_MSB = TPS2_Value >> 8;
int TPS2_LSB = TPS2_Value & 0xFF;


void setup() {
  Serial.begin(115200);
  Serial.print("TPS1_Value = [");
  Serial.print(TPS1_MSB);
  Serial.print("] x 256 + [");
  Serial.print(TPS1_LSB);
    Serial.print("]");
  
  Serial.println("");
  
  Serial.print("TPS2_Value = [");
  Serial.print(TPS2_MSB);
  Serial.print("] x 256 + [");
  Serial.print(TPS2_LSB);
  Serial.print("]");
}

void loop() {
}

you will see that the console output is

TPS1_Value = [[b]15[/b]] x 256 + [[b]33[/b]]
TPS2_Value = [[b]5[/b]] x 256 + [[b]9[/b]]

what you see between the brackets is what your

        Serial.print(TPS1_Value / 256);   // (((TPS1_Value / 256)*256) + (TPS1_Value % 256));
        Serial.print(TPS1_Value % 256);

would really send across, in ASCII.

so for the first one it would send '1' '5' '3' '3' which is 4 ASCII chars
but for the second one '5' '9', only 2 ASCII chars

Notice that depending on the value of TPSx_value, you have a different number of characters being sent.
That is my point.

By sending your data in ASCII, you can get 2, 3, 4 or 5 characters sent to Processing to interpret and you statically expect 4 only.

Yes when you use write, you send binary data, not ASCII so they don't print nicely

does this help?

in the "super confused" message you do

int x = TPS1_Value;

byte TPS1_MSB = ((x) >> 8);
byte TPS1_LSB = ((x) & 0xFF);

TPS1_Value is 2 bytes and TPS1_MSB is 1 byte.

if i you want to be sure of what you will be getting in the byte, you need to make sure you know when the truncating from 2 bytes to 1 byte will happen i.e. before or after you shifted right.

if it happens before and then you shift, you have basically emptied your byte and end up with zero)

joeblogs:
not really, ithought by doing a serial print i was sending bytes, serial write was asc11.

i tried your method and i get error messages
error message attached

i dont think the way im trying is very elegant at all, but had to start somewhere. Finding good, current info on serial hasnt been all that easy.

i understand the bit shifting, but one thing at a time.

Yes sorry, I typed this too fast, you need to pass the address of your memory location you want to send across the serial line and how many bytes, so it should be written

Serial.write ([b](const char *) &[/b]TPS1_Value, 2);

post # 7 - this is the cause of a lot of my confusion, i was assuming the serial monitor would print out what serial write was doing. yes this does help, i didnt (should have), realise it was sending binary. doing the bit shifts i was getting no output, or garbage.

Yes when you use write, you send binary data, not ASCII so they don't print nicely

try this one in the morning

Serial.write ((const char *) &TPS1_Value, 2);

thanks so much for your help,

Why so complicated?

Send lines with both values printed and seperated by ','.

Make Processing receive whole lines, tokenize and convert.

Forget about that 'A' stuff.

The Arduino sends data, Processing works with the data.
Use producer/consumer, not master/slave pingpong.

Edit:
My answer to the thread titel 'decrypt numbers in processing' is: 'don't encrypt them on the Arduino'.

@whandall

I agree with you that there is no need for the ping pong game.

While ASCII makes debugging easy, it's very verbose, requires additional text for delimiting tokens and thus

  • creates timing constraints (small serial buffers)
  • memory pressure
  • computation (parsing) demand on the Arduino side to build or decode those strings

(PC usually are fine with GB of RAM and fast USB bus and CPUs)

that's why I prefer binary communication.

@J-M-L

Framing is easy when using ASCII, there are no delimiters in the payload.

Using ASCII does not create the time constrain, it only moves it to a different level.
A compressed hexadecimal representation with fixed lengths and no delimiters could be used, if really necessary

Conversion from and to ASCII is quite fast, to hexadecimal even faster.

Nevermind, I only wanted to give hints, go ahead with you binary-way.

processing is just a way to visualize some sensor data, i only got me wee uno a couple of weeks ago so i am fumbling my way through the coding.

lets say for example that i have 2 different functions that are sending different serial data at different times to their target.

func1 sends 2 bytes of data to target,
func2 sends 2 bytes of data to target,

without some sort of pingpong how does the target know which func's send data (binary)

@whandall

I think we overall agree - partly personal preference

(on the time constraint thing it's you need to be quick to empty small serial buffers if you use Software Serial)

But in this case SoftwareSerial is the bottleneck and cpu hog, regardless of the transmission format.

joeblogs:
func1 sends 2 bytes of data to target,
func2 sends 2 bytes of data to target,
without some sort of pingpong how does the target know which func’s send data (binary)

This information could be embedded in the needed framing information (if using binary).
In my primitive and easy ASCII representation I would just add an identifying first character to the line.

1,1234,5678 messages from func1
2,1234,5678 messages from func2

Whandall:
But in this case SoftwareSerial is the bottleneck and cpu hog, regardless of the transmission format.

well hence the need to optimize what goes on the wire, each byte counts. binary is less verbose than ASCII

In hex ASCII uses twice as much bandwidth for the data, but the framing is much simpler (one LF is enough).
With binary it's hard to construct a message that can be decoded without errors regardless of the data content.

Whandall:
In hex ASCII uses twice as much bandwidth for the data, but the framing is much simpler (one LF is enough).

true but can't be open ended. you need to craft & send the frame then read the frame, decode the frame, go to the next frame. so you are frame based.

Whandall:
With binary it's hard to construct a message that can be decoded without errors regardless of the data content.

unless you know what you do :slight_smile: and you can stream away without being annoyed

I see that a bit like a GET request versus POST :slight_smile: to some extent in level of flexibly