duino to SPIN. Memcpy, Pointer, Struct Containing Many Types Including Float
Keith Young
Posts: 569
in Propeller 1
I need to take a struct containing floats and other types, measure the size of the incoming (serial) struct, do a bitwise and with a pointer, and then memcpy. In addition in the duino code they can grab for example VData.AP. I need to be able to get data from serial, store it, and call it. This really has me stuck. The particular things I think I'm having trouble with are commented in the code below as a problem.
I really prefer to do this project with a Prop instead of a duino.
How do I store the incoming serial data in a place I can call it, and how do I call it?
Thanks for any help.
I really prefer to do this project with a Prop instead of a duino.
How do I store the incoming serial data in a place I can call it, and how do I call it?
Thanks for any help.
uint16_t * address; //-----------------------------PROBLEM byte buffer[256]; //address for temporary storage and parsing buffer uint8_t structSize; struct VesselData //------------------------------PROBLEM { byte id; //1 float AP; //2 float PE; //3 float SemiMajorAxis; //4 float SemiMinorAxis; //5 float VVI; //6 float e; //7 float inc; //8 float G; //9 long TAp; //10 long TPe; //11 float TrueAnomaly; //12 float Density; //13 long period; //14 float RAlt; //15 float Alt; //16 float Vsurf; //17 float Lat; //18 float Lon; //19 float LiquidFuelTot; //20 float LiquidFuel; //21 float OxidizerTot; //22 float Oxidizer; //23 float EChargeTot; //24 float ECharge; //25 float MonoPropTot; //26 float MonoProp; //27 float IntakeAirTot; //28 float IntakeAir; //29 float SolidFuelTot; //30 float SolidFuel; //31 float XenonGasTot; //32 float XenonGas; //33 float LiquidFuelTotS; //34 float LiquidFuelS; //35 float OxidizerTotS; //36 float OxidizerS; //37 uint32_t MissionTime; //38 float deltaTime; //39 float VOrbit; //40 uint32_t MNTime; //41 float MNDeltaV; //42 float Pitch; //43 float Roll; //44 float Heading; //45 uint16_t ActionGroups; //46 status bit order:SAS, RCS, Light, Gear, Brakes, Abort, Custom01 - 10 byte SOINumber; //47 SOI Number (decimal format: sun-planet-moon e.g. 130 = kerbin, 131 = mun) byte MaxOverHeat; //48 Max part overheat (% percent) float MachNumber; //49 float IAS; //50 Indicated Air Speed }; VesselData VData; boolean KSPBoardReceiveData() { if ((rx_len == 0)&&(Serial.available()>3)){ while(Serial.read()!= 0xBE) { if (Serial.available() == 0) return false; } if (Serial.read() == 0xEF){ rx_len = Serial.read(); id = Serial.read(); rx_array_inx = 1; switch(id) { case 0: structSize = sizeof(HPacket); address = (uint16_t*)&HPacket; break; case 1: structSize = sizeof(VData); //----------------------------PROBLEM address = (uint16_t*)&VData; //--------------------------PROBLEM break; } } //make sure the binary structs on both Arduinos are the same size. if(rx_len != structSize){ rx_len = 0; return false; } } if(rx_len != 0){ while(Serial.available() && rx_array_inx <= rx_len){ buffer[rx_array_inx++] = Serial.read(); } buffer[0] = id; if(rx_len == (rx_array_inx-1)){ //seem to have got whole message //last uint8_t is CS calc_CS = rx_len; for (int i = 0; i<rx_len; i++){ calc_CS^=buffer[i]; } if(calc_CS == buffer[rx_array_inx-1]){//CS good memcpy(address,buffer,structSize); //---------------------PROBLEM rx_len = 0; rx_array_inx = 1; return true; } else{ //failed checksum, need to clear this out anyway rx_len = 0; rx_array_inx = 1; return false; } } } return false; } void loop() { KSPBoardReceiveData() //The loop is abbreviated. This is the function I'm stuck on. }
Comments
In your particular case, only the first variable (id) is not aligned properly. You could declare it as a "byte id[4];" and do a memcpy of the serial data starting with the last byte of the variable ("&id[3]"). If your serial data is not "little endian" with the least significant byte first in the data stream, you'll also have to rearrange the bytes of each value.
Your description of how to align the data is helpful.
I've got a question. I don't know of a way to do a memcpy in SPIN. What am I missing here?
Thanks again.
Is my pseudo code in the ball park?
repeat i from 0 to totalbytes
buffer = serial-in
if checksum = sentchecksum
bytemove( storage, buffer, totalbytes)
id = buffer 0
somehow make AP = buffer 1 through 5
loop through and put together variables from their region of the buffer
Is there a routine for taking 4 bytes and turning them into a float?
Thanks Mike. I would have been fumbling around forever trying to find BYTEMOVE.
When trying to grab the easiest of them all, the first byte which is actually a byte I personally know the value of, it doesn't work.
How would I grab a float from this, assuming I know for example that it exists starting at buffer[1]?
The floating point routines for the Propeller use the standard IEEE floating point format. If your serial data is also in IEEE format, you don't have to do any conversion (other than byte order if it's not least significant byte first).
The most important thing for you is to document the format of the serial data which you haven't done here (including the formats of each data item ... "little endian" or "big endian")
Why don't you write your program in C? Then you won't have to convert everything to Spin. Do you have a link for the spec on the transmission protocol? It appear to consist of a 16-bit sync word, $BEEF, followed by an 8-bit length value, and a checksum at the end. What is the length value that you are receiving? It should match the size of the struct plus one checksum byte.
I do have ID working now. So I need to try to put together the float, and if it doesn't come out right I know there might be an endian issue.
I don't see anywhere in the Arduino code that seems to be converting endian types, so my guess and hope is that it's being sent with little endian, and that's what the Prop is expecting.
My main reason for doing this in SPIN is because I suspect it will be useful to read all my buttons in PASM, and the vast majority of drivers in OBEX are in SPIN. So for example TV is in SPIN, not C. My Joystick Driver is in SPIN and PASM.
I don't know exactly how many features I'm going to want in this but it seems to have the most possibility I'm going to want SPIN. Could be wrong, it's just my current thinking.
Thanks for the help so far guys.
Thanks!
Spin doesn't have types. Just store floats in longs, and make sure you use FP ops on them (from F32.spin or something).
It's getting me the right value for id, so I must be doing something wrong somewhere else. The value it gives for AP is clearly wrong, at least after I send it via serial as a dec (it's a float).
Hopefully I can figure out where my problem is, because if so that's likely the last piece of the puzzle before I can start checking altitudes etc.
You can't send a float as a dec like that. As Spin doesn't have proper types and assumes everything is a signed integer, the dec function thinks your float is just an int, and prints out an invalid number. Try FloatString.spin for printing floats as strings.
I'm doing something wrong somewhere.
No matter what I always get 121765XXXX with XXX often being 4000.
I'm correctly polling address[0] for the id.
Another interesting thing is I can grab address[1] and address[3] (checking for padding) and they get the same result.
LONGMOVE (and other statements that expect to get the address of a 32-bit long word) will ignore the least significant two bits of the address provided.
I don't yet know if I can do comparisons or use these values to display on 7 segment etc, but I got it to go through to PST correctly.
One interesting thing is I could pull a longmove from @buffer[1] through @buffer[4] with a size 1 and still get the same value.
bytemove with length of 4 also worked great.
Thanks a ton for the help guys. I couldn't have gotten this far without you.
Now to see if I can turn on an LED when my altitude gets too low. Awesome!
if apogee > desired and perigee > desired
turn on LED
say "achieved orbit"
Thanks guys. This is amazing.