perl to C question- GTI limiter - 5000mtu

hi there I hacked a TED 1001 some time a go and it was writen in perl. I was planning to hack the ted MTU 5000 module and connect it to arduino connected to serial pins i want to use it to monitor house hold voltage and usage with the arduino instead

anyways i was wonder if someone could help me converting this bit of code to C from perl – ive tried but i can not seam to get it to work… wondering if if any would be kind enough to help

@data = ();
$buf = "";
# $cnt = 0;
$started = 0;
sub processPacket($);

while (read(INFILE, $buf, 1)) {
  $d = ord($buf) ^ 0xff;
  if ($d == 0x55 && $started == 0) {
    $started = 1;
    $a = 0;
  }
  if ($started == 1) {
    $data[$a] = $d;
    $sum += $data[$a];
    # printf("0x%02X ", $data[$a]);
    $a++;
    if ($a >= 11) {
      $sum -= $data[9];
      $sum &= 0xff;
      if ($sum == 0) { processPacket($data); }
      $started=1;
      $a = 0;
    }
  }
}

  # Working sub process packet stuff
  sub processPacket($) {
  local($data) = @_;
  #  If the power reading is way off, uncomment the other power line
  $power = (($data[5]^0xff)<<8) + ($data[4]^0xff);
  # $power = ($data[5]<<8) + $data[4];
  $voltage = ($data[8] << 8) | $data[7];
  $voltage = sprintf("%.3f",123.6 + ($voltage - 27620) / 85 * 0.2);
  $power = sprintf("%.3f",(1.19 + 0.84 * (($power - 288.0) / 204.0)));

ve tried but i can not seam to get it to work..

Please post the Arduino code you tried and describe the problems that you encountered.

yes but the sketch i wrote would pretty useless, as I do not know C and me hacking away at it to create a usable code from a perl script translated into C .. as perl has alot of commands not found in c such as "ord", I just do not know what to do for it..C....

one would expect to get a easier cleaner code fromthe original working perl script then something I tried to hack together..

the usable part I gotfor a sketch is

void setup() { Serial.begin(1200);

}

void loop() {

{ if (Serial.available() > 0) { int INFILE = Serial.read();

and i just can not figure out how to translat the that perl script into something usable on arduino.

thank you for your time..

P.S once i got this section figured out then i will post my full sketch from my GTi limiter and whole house energy monitor, for everyone to use if they want.

if you expect an integer streamed over serial try parseInt().

if(Serial.available())
{
  int myInt = Serial.parseInt();
}

thanks BulldogLowell

what it suppose to do is process the hex invert it once it finds 0x55 that is the start bit. then it translate the it into a 11 bit ie something like this" 0x55 0x0C 0xF4 0xE2 0xBD 0x02 0x4D 0x7F 0x6A 0xFB 0xD4"

then the bottom portion converts it into it into volts and kw output from the the 11 bit …

here what i originally did.

here let me explain what happening it the perl script ( i never wrote the original perl script )

i will edit portions to c but I have no clue what to do for the hex processing portions of the perl code

@data = ();  
$buf = "";     # the buffer of the captured hex

 int started = 0;                  # process starts 
sub processPacket($);      # sub routine starts 

while (read(INFILE, $buf, 1)) {     #reads the sent hex  bit from the serial communications
  $d = ord($buf) ^ 0xff;             #  here it inverts the hex value
  if ($d == 0x55 && $started == 0) {   # here if the inverted hex equall 0x55 that the start bit 
    started = 1;                              # start bit verified
     int a = 0;                                 # the bit counter 
  }
  if (started == 1) {                   # this next section  keeps adding bit unit the 11 bit  key is made
    $data[$a] = $d;
    $sum += $data[$a];
    
    a++;
    if (a >= 11) {                    # then once the 11 bit  key is created  it starts over
      $sum -= $data[9];
      $sum &= 0xff;
      if ($sum == 0) { processPacket($data); }  #process the end packet to pass the 11 bit to the next sub routine
      started=1;
      a = 0;
    }
  }
}

  # Working sub process packet stuff
  sub processPacket($) {                                   #   sub routine to convert to  usable data
  local($data) = @_;
  #  If the power reading is way off, uncomment the other power line
  int power = (($data[5]^0xff)<<8) + ($data[4]^0xff);    # takes bit 5 and 4  converts to decimial
  # $power = ($data[5]<<8) + $data[4];
  int voltage = ($data[8] << 8) | $data[7];                    # takes  bit 8 and 7  and covert to decimal
  voltage = sprintf("%.3f",123.6 + (voltage - 27620) / 85 * 0.2);    #formulal  to get  voltage 
  power = sprintf("%.3f",(1.19 + 0.84 * ((power - 288.0) / 204.0)));   # formula to get  power

basically I do not know what to do here for these line

@data = (); ?

sub processPacket($); #what do you do for sub routines

while (read(INFILE, $buf, 1)) ?
$d = ord($buf) ^ 0xff; # what to do for ord and and inverting hex bit
$sum &= 0xff; ?
if ($sum == 0) { processPacket($data); ??? sub routine call

sub processPacket($) ?
local($data) = @_; ?
$power = (($data[5]^0xff)<<8) + ($data[4]^0xff); ?
$voltage = ($data[8] << 8) | $data[7]; ?

Have you tried a Perl to C translator? http://search.cpan.org/~nwclark/perl-5.8.9/utils/perlcc.PL

this ARRAY:

@data = ();

Appears to be a regular array of bytes, not bits. The script appears to be parsing the stream of bytes and creating values from that stream.

the leading byte is 0x55, you got that right. It then puts 10 bytes into the array and does what looks like a checksum on the array values.

You can write a C++ (Arduino) program to capture the stream using Robin2's excellent examples Serial Input Basics.

Once you capture your array of bytes, you can then manipulate it like the author of your code does in his processPacket($) function, passing the array of bytes to the function and assembling some values from certain array values.

So, in short, start with gathering the stream of data into an array. Once you have that you will be able to do the rest kind-of easily.

thank you very BulldogLowell

okay some head way I used this code from your the suggested thread: and i can capture the hex and print it , but it is the inverted so instead of the required 0x55 I used 0xAA

so I can work with that i guess just have to figure out how to invert the bytes before I use them

// adapted from Serial Input Basics
// char data type replaced by byte
const byte numBytes = 32;
byte receivedBytes[numBytes];
byte numReceived = 0;

boolean newData = false;

void setup() {
    Serial.begin(1200);
    Serial.println("<Arduino is ready>");
    Serial.begin(1200);
}

void loop() {
    recvBytesWithStartEndMarkers();
    showNewData();
}

void recvBytesWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    byte startMarker = 0xAA;
    byte endMarker = 0xAA;
    byte rb;


    while (Serial.available() > 0 && newData == false) {
        rb = Serial.read();

        if (recvInProgress == true) {
          
            if (rb != endMarker) {
                receivedBytes[ndx] = rb;
                ndx++;
                if (ndx >= numBytes) {
                    ndx = numBytes - 1;
              
                }
            }
            else {
                receivedBytes[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                numReceived = ndx;  // save the number for use when printing
                ndx = 0;
                newData = true;
            }
        }

        else if (rb == startMarker) {
            recvInProgress = true;
       
        }
    }
}

void showNewData() {
    if (newData == true) {
        Serial.print("This just in ... ");
        for (byte n = 0; n < numReceived; n++) {
            Serial.print(receivedBytes[n], HEX);
            Serial.print(' ');
        }
        Serial.println();
        showGroupsOfBytes();
        newData = false;
    }
}

void showGroupsOfBytes() {
    for (byte n = 0; n < numReceived; n++) {
        Serial.print(receivedBytes[n], HEX);
        Serial.print(' ');
        if ((n + 1) % 5 == 0) {
   //         Serial.println();
        }
    }
   // Serial.println();
}

as this is what it out puts

4E 2E FF FF FF 30 5E 94 3 B1 This just in ... 4E 2C FF FF FF 30 5E 94 3 B3 
4E 2C FF FF FF 30 5E 94 3 B3 This just in ... 4E 2A FF FF FF 89 74 94 3 46 
4E 2A FF FF FF 89 74 94 3 46 This just in ... 4E 28 FF FF FF 89 74 94 3 48 
4E 28 FF FF FF 89 74 94 3 48 This just in ... 4E 26 FF FF FF 89 74 94 3 4A 
4E 26 FF FF FF 89 74 94 3 4A This just in ... 4E 24 FF FF FF 30 5E 94 3 BB 
4E 24 FF FF FF 30 5E 94 3 BB This just in ... 4E 22 FF FF FF 30 5E 94 3 BD 
4E 22 FF FF FF 30 5E 94 3 BD This just in ... 4E 20 FF FF FF 30 5E 94 3 BF 
4E 20 FF FF FF 30 5E 94 3 BF This just in ... 4E 1E FF FF FF 30 5E 94 3 C1 
4E 1E FF FF FF 30 5E 94 3 C1 This just in ... 4E 1C FF FF FF 89 74 94 3 54 
4E 1C FF FF FF 89 74 94 3 54 This just in ... 4E 1A FF FF FF 30 5E 94 3 C5 
4E 1A FF FF FF 30 5E 94 3 C5 This just in ... 4E 18 FF FF FF 89 74 94 3 58 
4E 18 FF FF FF 89 74 94 3 58 This just in ... 4E 16 FF FF FF 89 74 94 3 5A 
4E 16 FF FF FF 89 74 94 3 5A This just in ... 4E 14 FF FF FF 89 74 94 3 5C 
4E 14 FF FF FF 89 74 94 3 5C This just in ... 4E 12 FF FF FF D7 47 94 3 3D 
4E 12 FF FF FF D7 47 94 3 3D This just in ... 4E 10 FF FF FF D7 47 94 3 3F 
4E 10 FF FF FF D7 47 94 3 3F This just in ... 4E E FF FF FF 30 5E 94 3 D1 
4E E FF FF FF 30 5E 94 3 D1 This just in ... 4E C FF FF FF 89 74 94 3 64

they are correct as i can verify with MTU number which is 177 or hex of B1 and the inverter hex of B1 is 4E

can you point me in the direction or if you know how to pull the 7th and 8th and invert it or I guess now it would be the 6th and 7th as the first 0x55 is lost
say for this as an example from the original perl code

voltage = ($data[8] << 8) | $data[7];                    
  voltage = ("%.3f",123.6 + (voltage - 27620) / 85 * 0.2);

sorry if I am a pain I just do so little programing and it never the same language when i do…

okay question why is it when i use a bit calculator

http://calc.penjee.com/

4E and NOT gives me a value of B1 and a decimal value of 177

but the bitwise not on the arduino gives me 64 and a decimal vaule of 100

why is it different???

voltage = ($data[8] << 8) | $data[7];

the author isn’t “inverting” the two bytes, rather he is combining them into a 16bit number. First shifting the eighth element of the array and the using the bitwise “OR” to combine.

In C++ you would do that as follows:

int voltage = 0;  // initialize a 16 bit integer as zero (on an Uno, ints are 16 bits)
voltage = (data[8] << 8) | data[7];  // moves the eighth element to the Most Significant Byte position and copies the value of the 7th element into the Least Significant Byte's position.

thank you for your reply BulldogLowell

but yes it is inverting it at this code location

$d = ord($buf) ^ 0xff;

that is why the hex " keys" are different the original program gives this ;

the "^ " denotes key markers

0x55 0xB1 0x2A 0x20 0x45 0xFF 0xD4 0x9F 0x69 0xFB 0x90
^ ^ ^ ^ ^

the arduino this; ( minus the start key of 0xAA or invert of 0X55

4E D6 DF BA 0 2B 60 96 4 6E

I wrote a debug program that shows this:
here a sampling at the same time:
the original software:
0x55 0xB1 0x2A 0x20 0x45 0xFF 0xD4 0x9F 0x69 0xFB 0x90 is the Hex key
69,255,159,105------------- the decimal val of $data 4,5,7and 8
65349,27039 --------------> pre math equation value for power and voltage
269.088235294118,120.865882352941 → value after equation of power and voltage

this is the arduino debug:
This just in … 4E D6 DF BA 0 2B 60 96 4 6E

MTU B1 --------------------------> inverted 4E
Voltage
hex pre invert 60 96
hex inverted 9F 69
Dec 159 105 ----------------> the same as $data[7] and data[8]
voltage prequ 159 -----------> prequ wrong 27039 something goes wrong here voltage = ( k<< 8) | j;
voltage 59 ------------------> suppose to be 120.865882352941
Power
hex pre invert BA 0
hex inverted 45 FF
Dec 69 255 --------------------> the same values of $data[4] and $data [5]
Power prequ 69 ---------------> prequ is wrong 65349 somethig goes wrong here power = (r<<8) + m;
power out 0 ------------------> suppose to be 269.088235294118

that is what i do not get the equations are the same but the out puts are differnt

/ adapted from Serial Input Basics
// char data type replaced by byte
const byte numBytes = 32;
byte receivedBytes[numBytes];
byte numReceived = 0;

boolean newData = false;

void setup() {
    Serial.begin(1200);
    Serial.println("<Arduino is ready>");
    Serial.begin(1200);
}

void loop() {
    recvBytesWithStartEndMarkers();
    showNewData();
}

void recvBytesWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    byte startMarker = 0xAA;
    byte endMarker = 0xAA;
    byte rb;


    while (Serial.available() > 0 && newData == false) {
        rb = Serial.read();

        if (recvInProgress == true) {
          
            if (rb != endMarker) {
                receivedBytes[ndx] = rb;
                ndx++;
                if (ndx >= numBytes) {
                    ndx = numBytes - 1;
              
                }
            }
            else {
                receivedBytes[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                numReceived = ndx;  // save the number for use when printing
                ndx = 0;
                newData = true;
            }
        }

        else if (rb == startMarker) {
            recvInProgress = true;
       
        }
    }
}

void showNewData() {
    if (newData == true) {
        Serial.print("This just in ... ");
        for (byte n = 0; n < numReceived; n++) {
            Serial.print(receivedBytes[n], HEX);
            Serial.print(' ');
        }
        Serial.println();
        showGroupsOfBytes();
        newData = false;

    }
}

void showGroupsOfBytes() {
    
    byte j = 0;
    byte k = 0;
    byte m = 0;
    byte r = 0;
    byte h = 0x4E;
      byte n = (0);
      
      h = receivedBytes[0];
      h = ~h;
      Serial.print("MTU ");
        Serial.println(h, HEX);
        Serial.print(' ');
       
             Serial.println ("Voltage");
                   j = receivedBytes[6] ;
                   k = receivedBytes[7];
             Serial.print("hex  pre invert ");      
            Serial.print(j, HEX);
             Serial.print(" ");
            Serial.println(k, HEX);
            j= ~j;
            k= ~k;
            Serial.print("hex inverted "); 
            Serial.print(j, HEX);
             Serial.print(" ");
            Serial.println(k, HEX);
Serial.print("Dec ");
 Serial.print(j);
   Serial.print(" ");
 Serial.println(k); 
            

byte voltage = 0;
byte power = 0;
voltage = ( k<< 8) | j;
Serial.print("voltage prequ ");
      Serial.println(voltage);  
         
  voltage= (123.6 + (voltage - 27620) / 85 * 0.2);
   Serial.print("voltage ");
       Serial.println(voltage);  
   
 
 Serial.println ("Power");
                  m = receivedBytes[3] ;
                  r = receivedBytes[4];
             Serial.print("hex  pre invert ");      
            Serial.print(m, HEX);
             Serial.print(" ");
            Serial.println(r, HEX);
            m= ~m;
            r= ~r;
            Serial.print("hex inverted "); 
            Serial.print(m, HEX);
             Serial.print(" ");
            Serial.println(r, HEX);
 Serial.print("Dec ");
 Serial.print(m); 
  Serial.print(" ");
 Serial.println(r); 
            
 
 power = (r<<8) + m;
 
       Serial.print("Power prequ  "); 
            Serial.println(power);  
           
            
           power = 1.19 + 0.84 * ((power - 288.0) / 204.0);
        
       Serial.print("power out  ");     
       Serial.println(power); 

    Serial.println();
}

does anyone see what the problem is, the data inputs are identical and so are the equations but the the arduino outputs vastly different numbers

original software equations:

$power = ($data[5]<<8) + $data[4];
$power = 1.19 + 0.84 * (($power - 288.0) / 204.0);
$voltage = ($data[8]<<8) | $data[7];
$voltage = 123.6 + ($voltage - 27620) / 85 * 0.2;

the arduino’s
r = $data[5] m=$data[4] j=$data[7] k=$data[8]

power = (r<<8) + m;
power = 1.19 + 0.84 * ((power - 288.0) / 204.0);
voltage = ( k<< 8) | j;
voltage= (123.6 + (voltage - 27620) / 85 * 0.2);

I even made a testpl.pl from perl with the know data

0x55 0xB1 0x4A 0x12 0x47 0xFF 0x67 0x03 0x69 0xFC 0x85
71,255,3,105
65351,26883
269.096470588235,120.131764705882

perl gives a correct answer

#!/usr/bin/perl -w -s
{

  $test1 = 0x47;
  $test2 = 0xFF;
  $test3 = 0x03;
  $test4 = 0x69;
  print "\n";
  print "$test1,$test2,$test3,$test4\n";
  
  $power = ($test2<<8) + $test1;
  
  $voltage = ($test4<<8) |$test3 ;
   print "$power,$voltage\n";
  $voltage = 123.6 + ($voltage - 27620) / 85 * 0.4;
  $power = 1.19 + 0.84 * (($power - 288.0) / 204.0);

  print "$power,$voltage\n";
  }

outputs this

71,255,3,105
65351,26883
269.096470588235,120.131764705882

when i write the same thing for arduino not even close

void setup() {
  // put your setup code here, to run once:
 Serial.begin(1200);
    Serial.println("<Arduino is ready>");
    
    byte j = 0x03;
    byte k = 0x69;
    byte r = 0xFF;
    byte m = 0x47;
    

byte voltage = 0;
byte power = 0;
voltage = ( k<< 8) | j;
Serial.print("voltage prequ ");
      Serial.println(voltage);  
//byte volt = voltage;
         //Serial.println(volt);         
  voltage= (123.6 + (voltage - 27620) / 85 * 0.2);
   Serial.print("voltage ");
       Serial.println(voltage);  
      // Serial.println (" ");

  power = (r<<8) + m;
 
       Serial.print("Power prequ  "); 
            Serial.println(power);  
            //volt = voltage;
            
           power = 1.19 + 0.84 * ((power - 288) / 204);
        
       Serial.print("power out  ");     
       Serial.println(power); 



    
}

void loop() {


}

outputs this

voltage prequ 25 voltage 58 Power prequ 255 power out 1

something wrong in how the arduino does the math equation, there has to be something different in the format.

does anyone know what wrong

byte voltage = 0;
  voltage= (123.6 + (voltage - 27620) / 85 * 0.2);

voltage is declared as a byte so its value will never be greater than 255 and will alsways be an integer not a float.

thanks UKHeliBob

it turns out I had to use double, as every thing esle still gives bad data,

if anyone curious this is the end data running a I2C LCD displaying the data

#include <stdio.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 16, 2);

const byte numBytes = 32;
byte receivedBytes[numBytes];
byte numReceived = 0;
int cnt = 0;

boolean newData = false;

void setup() {
    Serial.begin(1200);
    Serial.println("<Arduino is ready>");
   // Serial.begin(1200);
    lcd.begin();
}

void loop() {
    recvBytesWithStartEndMarkers();
    showNewData();
}

void recvBytesWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    byte startMarker = 0xAA;
    byte endMarker = 0xAA;
    byte rb;


    while (Serial.available() > 0 && newData == false) {
        rb = Serial.read();

        if (recvInProgress == true) {
          
            if (rb != endMarker) {
                receivedBytes[ndx] = rb;
                ndx++;
                cnt++;
                if (ndx >= numBytes) {
                    ndx = numBytes - 1;
                    
              
                }
            }
            else {
                receivedBytes[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                numReceived = ndx;  // save the number for use when printing
                ndx = 0;
                newData = true;
            }
        }

        else if (rb == startMarker) {
            recvInProgress = true;
       
        }
    }
}

void showNewData() {
    if (newData == true) {
        Serial.print("This just in ... ");
        for (byte n = 0; n < numReceived; n++) {
            Serial.print(receivedBytes[n], HEX);
            Serial.print(' ');
        }
        Serial.println();
        showGroupsOfBytes();
        newData = false;

    }
}

void showGroupsOfBytes() {
    if ( receivedBytes[0]==0x4E )  {
    // if (cnt == 9) {
    byte j = ~receivedBytes[6];
    byte k = ~receivedBytes[7];
    byte m = ~receivedBytes[3];
    byte r = ~receivedBytes[4];


double voltage = 0;
double power = 0;

voltage = ( k<< 8) | j;
voltage= (123.6 + (voltage - 27620) / 85 * 0.4);
  // Serial.print("voltage ");
   //    Serial.println(voltage);  

 
 power = (r<<8) + m;
 power = 1.19 + 0.84 * ((power - 288) / 204);
        
      // Serial.print("power out KW ");
     //  printf("power out %.4f",power);     
      // Serial.println(power); 
          
    lcd.setCursor(0,0);
    lcd.print("volts ");
    lcd.print(voltage);
    lcd.setCursor(1,1);
    lcd.print("kw ");
    lcd.print(power);
       
       }

// Serial.println();
    
    cnt = 0;
 
}

and a picture of it funtioning properly