FAQ
I know it's a bit of a stretch for my first go at Golang ;-) but I want to
decode a string of decimals sent by my an Arduino that has been created
from a struct like this:

type heatingData struct {

     tankIn int // temp going into the tank

     tankBottom int // temperature bottom of tank

     tankTop int // temperature top of tank

     xchangeIn int // temperature going in the tank / back from floor

     xchangeOut int // temperature coming out of the tank

     afterHeater int // temperature coming out of the tank

     floorIn int // temperature going in the floor

     floorFlow int // The water flow speed.

     panelOut int // temperature panel out

     panelAmb int // temperature outside

     panelIn int

     flowIn int // cold water flow into floor

     errorCode int // error code

     solarPump bool // pump on or off

     spPwm byte // solar pump pwm

     floorPump bool // pump on or off

     fpPwm byte // pump pwm;

     heaterPump bool //auxilary heater pump

}


the data received from the serial port is:

31 52 1 0 0 163 1 0 0 122 1 50 1 97 1 0 0 103 0 106 0


I am curious if there is an easy way to 'map' this sequence back to a struct?

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Search Discussions

  • Michael Jones at Dec 3, 2013 at 2:03 am
    no magic way. easily done the standard way, field by field. not to mention
    that only you know how many bytes per field.

    Michael

    P.S. Yes, there is a magic way but you should skip it for now.

    On Mon, Dec 2, 2013 at 12:29 PM, wrote:

    I know it's a bit of a stretch for my first go at Golang ;-) but I want to
    decode a string of decimals sent by my an Arduino that has been created
    from a struct like this:

    type heatingData struct {

    tankIn int // temp going into the tank

    tankBottom int // temperature bottom of tank

    tankTop int // temperature top of tank

    xchangeIn int // temperature going in the tank / back from floor

    xchangeOut int // temperature coming out of the tank

    afterHeater int // temperature coming out of the tank

    floorIn int // temperature going in the floor

    floorFlow int // The water flow speed.

    panelOut int // temperature panel out

    panelAmb int // temperature outside

    panelIn int

    flowIn int // cold water flow into floor

    errorCode int // error code

    solarPump bool // pump on or off

    spPwm byte // solar pump pwm

    floorPump bool // pump on or off

    fpPwm byte // pump pwm;

    heaterPump bool //auxilary heater pump

    }


    the data received from the serial port is:

    31 52 1 0 0 163 1 0 0 122 1 50 1 97 1 0 0 103 0 106 0



    I am curious if there is an easy way to 'map' this sequence back to a struct?

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.


    --
    Michael T. Jones | Chief Technology Advocate | mtj@google.com | +1
    650-335-5765

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Minux at Dec 3, 2013 at 2:07 am

    On Mon, Dec 2, 2013 at 3:29 PM, wrote:

    I know it's a bit of a stretch for my first go at Golang ;-) but I want to
    decode a string of decimals sent by my an Arduino that has been created
    from a struct like this:

    type heatingData struct {

    tankIn int // temp going into the tank

    tankBottom int // temperature bottom of tank

    tankTop int // temperature top of tank

    xchangeIn int // temperature going in the tank / back from floor

    xchangeOut int // temperature coming out of the tank

    afterHeater int // temperature coming out of the tank

    floorIn int // temperature going in the floor

    floorFlow int // The water flow speed.

    panelOut int // temperature panel out

    panelAmb int // temperature outside

    panelIn int

    flowIn int // cold water flow into floor

    errorCode int // error code

    solarPump bool // pump on or off

    spPwm byte // solar pump pwm

    floorPump bool // pump on or off

    fpPwm byte // pump pwm;

    heaterPump bool //auxilary heater pump

    }


    the data received from the serial port is:

    31 52 1 0 0 163 1 0 0 122 1 50 1 97 1 0 0 103 0 106 0

    assuming that each field has an integral number of bytes, and have exact
    Go type,
    encoding/binary package could help you with this once you have a Go
    definition of
    the struct (e.g. same order, correct type according to the length of each
    field,
    and the most important, export every field)
    http://golang.org/pkg/encoding/binary/#Read

    depending on where you get your data from, you might need to use the bytes
    package
    (http://golang.org/pkg/bytes/#Reader) to make the []byte you get from
    serial port into
    a io.Reader for encoding/binary.Read

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Michael Jones at Dec 3, 2013 at 2:14 am
    OK, I'll come clean, but you REALLY don't need to be doing this.

    1. You can tag each field in your struct with a name. Read this and look
    for "tag":
    http://golang.org/ref/spec#Struct_types

    2. You can define a mapping from name to byte count, order, encoding,
    offset, etc. as a form of formatting "program.

    3. You can pair the tag name and the formatting program in a map:
    http://golang.org/ref/spec#Map_types

    4. You can iterate through the struct using the reflection API, examine
    each field for its tag, look up the formatting program in the map, and then
    apply that to the input data stream and update the corresponding field.


    Unless you have some extraordinary reason to do all of this, it seems an
    absurd hurdle for your *first* program in the Go language. It is not the
    clearest way, it is not the fastest way, it is not the easiest way, and it
    will befuddle everyone who tries to understand your program. ;-)



    On Mon, Dec 2, 2013 at 6:07 PM, minux wrote:

    On Mon, Dec 2, 2013 at 3:29 PM, wrote:

    I know it's a bit of a stretch for my first go at Golang ;-) but I want
    to decode a string of decimals sent by my an Arduino that has been created
    from a struct like this:

    type heatingData struct {

    tankIn int // temp going into the tank

    tankBottom int // temperature bottom of tank

    tankTop int // temperature top of tank

    xchangeIn int // temperature going in the tank / back from floor

    xchangeOut int // temperature coming out of the tank

    afterHeater int // temperature coming out of the tank

    floorIn int // temperature going in the floor

    floorFlow int // The water flow speed.

    panelOut int // temperature panel out

    panelAmb int // temperature outside

    panelIn int

    flowIn int // cold water flow into floor

    errorCode int // error code

    solarPump bool // pump on or off

    spPwm byte // solar pump pwm

    floorPump bool // pump on or off

    fpPwm byte // pump pwm;

    heaterPump bool //auxilary heater pump

    }


    the data received from the serial port is:

    31 52 1 0 0 163 1 0 0 122 1 50 1 97 1 0 0 103 0 106 0


    assuming that each field has an integral number of bytes, and have exact
    Go type,
    encoding/binary package could help you with this once you have a Go
    definition of
    the struct (e.g. same order, correct type according to the length of each
    field,
    and the most important, export every field)
    http://golang.org/pkg/encoding/binary/#Read

    depending on where you get your data from, you might need to use the bytes
    package
    (http://golang.org/pkg/bytes/#Reader) to make the []byte you get from
    serial port into
    a io.Reader for encoding/binary.Read

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.


    --
    Michael T. Jones | Chief Technology Advocate | mtj@google.com | +1
    650-335-5765

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Minux at Dec 3, 2013 at 2:44 am

    On Mon, Dec 2, 2013 at 9:13 PM, Michael Jones wrote:

    OK, I'll come clean, but you REALLY don't need to be doing this.
    to be clear, I didn't suggest that. I suggest using encoding/binary to do
    this, and no struct tag is involved.

    for example,
    http://play.golang.org/p/dRpbCwHCgT
    1. You can tag each field in your struct with a name. Read this and look
    for "tag":
    http://golang.org/ref/spec#Struct_types

    2. You can define a mapping from name to byte count, order, encoding,
    offset, etc. as a form of formatting "program.

    3. You can pair the tag name and the formatting program in a map:
    http://golang.org/ref/spec#Map_types

    4. You can iterate through the struct using the reflection API, examine
    each field for its tag, look up the formatting program in the map, and then
    apply that to the input data stream and update the corresponding field.


    Unless you have some extraordinary reason to do all of this, it seems an
    absurd hurdle for your *first* program in the Go language. It is not the
    clearest way, it is not the fastest way, it is not the easiest way, and it
    will befuddle everyone who tries to understand your program. ;-)
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Michael Jones at Dec 3, 2013 at 2:48 am
    Oh, I don't mean your idea. I meant the elaborate thing I proposed. Note
    that he has some ints and some bools so there will need to be come
    case-by-case magic. I was thinking that field name driven pack/unpack would
    make him happy but bewildered.

    On Mon, Dec 2, 2013 at 6:44 PM, minux wrote:

    On Mon, Dec 2, 2013 at 9:13 PM, Michael Jones wrote:

    OK, I'll come clean, but you REALLY don't need to be doing this.
    to be clear, I didn't suggest that. I suggest using encoding/binary to do
    this, and no struct tag is involved.

    for example,
    http://play.golang.org/p/dRpbCwHCgT
    1. You can tag each field in your struct with a name. Read this and look
    for "tag":
    http://golang.org/ref/spec#Struct_types

    2. You can define a mapping from name to byte count, order, encoding,
    offset, etc. as a form of formatting "program.

    3. You can pair the tag name and the formatting program in a map:
    http://golang.org/ref/spec#Map_types

    4. You can iterate through the struct using the reflection API, examine
    each field for its tag, look up the formatting program in the map, and then
    apply that to the input data stream and update the corresponding field.


    Unless you have some extraordinary reason to do all of this, it seems an
    absurd hurdle for your *first* program in the Go language. It is not the
    clearest way, it is not the fastest way, it is not the easiest way, and it
    will befuddle everyone who tries to understand your program. ;-)

    --
    Michael T. Jones | Chief Technology Advocate | mtj@google.com | +1
    650-335-5765

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Alex knol at Dec 3, 2013 at 8:07 am
    Thanks guys!

    Apart from the great help, I really appreciate the overwhelming support!

    As easy as it is in C (arduino) to go from a received msg to the struct is
    the ultimate goal:
    typedef struct {
         boolean pump; // pump on or off
         boolean needPump; //we need the pump
    boolean water; // is there water detected
         int tempIn; // temperature panel in
         int tempOut; // temperature panel out
         int tempAmb; // temperature outside
    // int panelFlow; // The water flow speed.
    } panelData;

    void receive () {
       if (rf12_recvDone() && rf12_crc == 0) {
         if ((RF12_HDR_MASK & rf12_hdr) == panelsID) { // from the panels
           panelData* buf = (panelData*) rf12_data;
         }
       }
    }

    BUT My goal is to learn Go by example and I'll start of going the more
    'manual' way. I have a working poc in Node that I'll replicate first using
    http://golang.org/pkg/encoding/binary/#Read and then move on to the bytes.
    I am at liberty to change my arduino output, so using only int16 is not a
    problem (+ the values min/max will fit too), but I'll learn less I guess.

    function returnInt(element){
    return parseInt(element,10);
    }

       if (words.shift() === 'OK') {
         var ints = words.map(returnInt);
         var head = ints.shift();
         var data = new Buffer(ints);
         var i, _i;
         var values = []
         for (i = _i = 0; _i <= 13; i = ++_i) {
           values.push(data.readUInt16LE(2 * i));
         }
         values.push(data.readUInt8(26));
         values.push(data.readUInt8(28));
         values.push(data.readUInt8(30));
       }

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Konstantin Khomoutov at Dec 3, 2013 at 1:52 pm

    On Tue, 3 Dec 2013 00:07:08 -0800 (PST) alex knol wrote:

    As easy as it is in C (arduino) to go from a received msg to the
    struct is the ultimate goal:
    typedef struct {
    boolean pump; // pump on or off
    boolean needPump; //we need the pump
    boolean water; // is there water detected
    int tempIn; // temperature panel in
    int tempOut; // temperature panel out
    int tempAmb; // temperature outside
    // int panelFlow; // The water flow speed.
    } panelData;

    void receive () {
    if (rf12_recvDone() && rf12_crc == 0) {
    if ((RF12_HDR_MASK & rf12_hdr) == panelsID) { // from the panels
    panelData* buf = (panelData*) rf12_data;
    }
    }
    }
    One obvious problem with your code is that it assumes the same
    endianness [1] of the integers sent "on the wire" by your hardware and
    the machine which reads them off the wire. That is, your C program is
    not portable. What's worse, it will build just OK on a box with
    different endianness but will silently produce different results.

    The second, less obvious, problem with your C program is that the C
    standard does not specify any way to define a "packed" struct, and by
    default the compiler is free to lay out your struct members in any way
    it wishes, save for reordering them, which means that typically any
    struct member will be laid out using a boundary which is some factor of
    sizeof (int) (on Intel platforms it's typically 8 bytes, IIRC) [2].
    This means it's futile to cast a byte array of length
    2*sizeof(int)+sizeof (char) to something like

    struct {
       int a;
       char b;
       int c;
    }

    because its length will most probably be more than that due to the
    "c" field being aligned (typically) to a 4 or 8 byte boundary, not
    right after the "b" member.

    Any serious compiler does have a way to explicitly control packing of
    structs, but it a) should be employed in your case; b) is not portable
    across compilers of different families.

    That's why there's an encoding/binary package: while it's not a
    pinnacle of effectiveness (for some reason Go does not include
    platform-optimized versions of certain functions in this package) it
    allows you to do serialization/deserialization right by explicitly
    using a specific endianness to read/write your data.

    1. http://en.wikipedia.org/wiki/Endianness
    2. http://en.wikipedia.org/wiki/Data_structure_alignment

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Alex knol at Dec 3, 2013 at 4:08 pm
    So the reason this has always worked for me on Arduino is that i've been
    using the same platform and compiler....
    Learnt something there ;-) tnx

    So it seems writing "unwrappers" per message type (sender struct) is the
    safest option, like i started in my nodejs poc.

    Thanks for your detailed answer.
    On Tuesday, December 3, 2013 2:52:44 PM UTC+1, Konstantin Khomoutov wrote:

    On Tue, 3 Dec 2013 00:07:08 -0800 (PST)
    alex knol <alex...@gmail.com <javascript:>> wrote:
    As easy as it is in C (arduino) to go from a received msg to the
    struct is the ultimate goal:
    typedef struct {
    boolean pump; // pump on or off
    boolean needPump; //we need the pump
    boolean water; // is there water detected
    int tempIn; // temperature panel in
    int tempOut; // temperature panel out
    int tempAmb; // temperature outside
    // int panelFlow; // The water flow speed.
    } panelData;

    void receive () {
    if (rf12_recvDone() && rf12_crc == 0) {
    if ((RF12_HDR_MASK & rf12_hdr) == panelsID) { // from the panels
    panelData* buf = (panelData*) rf12_data;
    }
    }
    }
    One obvious problem with your code is that it assumes the same
    endianness [1] of the integers sent "on the wire" by your hardware and
    the machine which reads them off the wire. That is, your C program is
    not portable. What's worse, it will build just OK on a box with
    different endianness but will silently produce different results.

    The second, less obvious, problem with your C program is that the C
    standard does not specify any way to define a "packed" struct, and by
    default the compiler is free to lay out your struct members in any way
    it wishes, save for reordering them, which means that typically any
    struct member will be laid out using a boundary which is some factor of
    sizeof (int) (on Intel platforms it's typically 8 bytes, IIRC) [2].
    This means it's futile to cast a byte array of length
    2*sizeof(int)+sizeof (char) to something like

    struct {
    int a;
    char b;
    int c;
    }

    because its length will most probably be more than that due to the
    "c" field being aligned (typically) to a 4 or 8 byte boundary, not
    right after the "b" member.

    Any serious compiler does have a way to explicitly control packing of
    structs, but it a) should be employed in your case; b) is not portable
    across compilers of different families.

    That's why there's an encoding/binary package: while it's not a
    pinnacle of effectiveness (for some reason Go does not include
    platform-optimized versions of certain functions in this package) it
    allows you to do serialization/deserialization right by explicitly
    using a specific endianness to read/write your data.

    1. http://en.wikipedia.org/wiki/Endianness
    2. http://en.wikipedia.org/wiki/Data_structure_alignment
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Michael Jones at Dec 3, 2013 at 4:18 pm
    Precisely. Not only are byte order and struct layout presumed in the C
    original, so is int size. If you moved between 32-bit and 64-bit hosts, you
    could need to change your firmware (or change 'int' to 'long' or whatever).

    Doing it by hand in Go is perfect. Doing it using library tools as Minux
    shows is perfect and simpler. Both of these work in every case, on every
    platform, etc. so long as your data really does map one-to-one on both
    sides of the wire.

    If, as is often the case in heterogeneous systems with products from
    multiple vendors, the data from devices is encoded in some way, you have to
    make a stylistic choice about when and where to decode. For example, maybe
    the packet has variable length depending on observations or maybe certain
    data values are reserved to indicate power or probe failure, out of range
    or unreliable data, and so on. In such cases you can either structure your
    code to read a raw packet and then decode it or to read the items one at a
    time and decode them. Both ways are good.

    On Tue, Dec 3, 2013 at 8:08 AM, alex knol wrote:

    So the reason this has always worked for me on Arduino is that i've been
    using the same platform and compiler....
    Learnt something there ;-) tnx

    So it seems writing "unwrappers" per message type (sender struct) is the
    safest option, like i started in my nodejs poc.

    Thanks for your detailed answer.

    On Tuesday, December 3, 2013 2:52:44 PM UTC+1, Konstantin Khomoutov wrote:

    On Tue, 3 Dec 2013 00:07:08 -0800 (PST)
    alex knol wrote:
    As easy as it is in C (arduino) to go from a received msg to the
    struct is the ultimate goal:
    typedef struct {
    boolean pump; // pump on or off
    boolean needPump; //we need the pump
    boolean water; // is there water detected
    int tempIn; // temperature panel in
    int tempOut; // temperature panel out
    int tempAmb; // temperature outside
    // int panelFlow; // The water flow speed.
    } panelData;

    void receive () {
    if (rf12_recvDone() && rf12_crc == 0) {
    if ((RF12_HDR_MASK & rf12_hdr) == panelsID) { // from the panels
    panelData* buf = (panelData*) rf12_data;
    }
    }
    }
    One obvious problem with your code is that it assumes the same
    endianness [1] of the integers sent "on the wire" by your hardware and
    the machine which reads them off the wire. That is, your C program is
    not portable. What's worse, it will build just OK on a box with
    different endianness but will silently produce different results.

    The second, less obvious, problem with your C program is that the C
    standard does not specify any way to define a "packed" struct, and by
    default the compiler is free to lay out your struct members in any way
    it wishes, save for reordering them, which means that typically any
    struct member will be laid out using a boundary which is some factor of
    sizeof (int) (on Intel platforms it's typically 8 bytes, IIRC) [2].
    This means it's futile to cast a byte array of length
    2*sizeof(int)+sizeof (char) to something like

    struct {
    int a;
    char b;
    int c;
    }

    because its length will most probably be more than that due to the
    "c" field being aligned (typically) to a 4 or 8 byte boundary, not
    right after the "b" member.

    Any serious compiler does have a way to explicitly control packing of
    structs, but it a) should be employed in your case; b) is not portable
    across compilers of different families.

    That's why there's an encoding/binary package: while it's not a
    pinnacle of effectiveness (for some reason Go does not include
    platform-optimized versions of certain functions in this package) it
    allows you to do serialization/deserialization right by explicitly
    using a specific endianness to read/write your data.

    1. http://en.wikipedia.org/wiki/Endianness
    2. http://en.wikipedia.org/wiki/Data_structure_alignment
    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.


    --
    Michael T. Jones | Chief Technology Advocate | mtj@google.com | +1
    650-335-5765

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Brian at Dec 4, 2013 at 6:34 pm
    Great post on why you shouldn't use a C struct copy to define your wire
    protocol.

    Does the Go library:
    1) only do one memory allocation (no realloc()) ?
    2) As easy to read as Python str.format(), which uses c-style printf to
    define a buffer format ?

    IMHO, the problem with these "serializers" (most of 'em) is they present a
    picture-perfect API that does a LOT of malloc() underneath.
    On Wednesday, December 4, 2013 1:18:08 AM UTC+9, Michael Jones wrote:

    Precisely. Not only are byte order and struct layout presumed in the C
    original, so is int size. If you moved between 32-bit and 64-bit hosts, you
    could need to change your firmware (or change 'int' to 'long' or whatever).

    Doing it by hand in Go is perfect. Doing it using library tools as Minux
    shows is perfect and simpler. Both of these work in every case, on every
    platform, etc. so long as your data really does map one-to-one on both
    sides of the wire.

    If, as is often the case in heterogeneous systems with products from
    multiple vendors, the data from devices is encoded in some way, you have to
    make a stylistic choice about when and where to decode. For example, maybe
    the packet has variable length depending on observations or maybe certain
    data values are reserved to indicate power or probe failure, out of range
    or unreliable data, and so on. In such cases you can either structure your
    code to read a raw packet and then decode it or to read the items one at a
    time and decode them. Both ways are good.


    On Tue, Dec 3, 2013 at 8:08 AM, alex knol <alex...@gmail.com <javascript:>
    wrote:
    So the reason this has always worked for me on Arduino is that i've been
    using the same platform and compiler....
    Learnt something there ;-) tnx

    So it seems writing "unwrappers" per message type (sender struct) is the
    safest option, like i started in my nodejs poc.

    Thanks for your detailed answer.

    On Tuesday, December 3, 2013 2:52:44 PM UTC+1, Konstantin Khomoutov wrote:

    On Tue, 3 Dec 2013 00:07:08 -0800 (PST)
    alex knol wrote:
    As easy as it is in C (arduino) to go from a received msg to the
    struct is the ultimate goal:
    typedef struct {
    boolean pump; // pump on or off
    boolean needPump; //we need the pump
    boolean water; // is there water detected
    int tempIn; // temperature panel in
    int tempOut; // temperature panel out
    int tempAmb; // temperature outside
    // int panelFlow; // The water flow speed.
    } panelData;

    void receive () {
    if (rf12_recvDone() && rf12_crc == 0) {
    if ((RF12_HDR_MASK & rf12_hdr) == panelsID) { // from the panels
    panelData* buf = (panelData*) rf12_data;
    }
    }
    }
    One obvious problem with your code is that it assumes the same
    endianness [1] of the integers sent "on the wire" by your hardware and
    the machine which reads them off the wire. That is, your C program is
    not portable. What's worse, it will build just OK on a box with
    different endianness but will silently produce different results.

    The second, less obvious, problem with your C program is that the C
    standard does not specify any way to define a "packed" struct, and by
    default the compiler is free to lay out your struct members in any way
    it wishes, save for reordering them, which means that typically any
    struct member will be laid out using a boundary which is some factor of
    sizeof (int) (on Intel platforms it's typically 8 bytes, IIRC) [2].
    This means it's futile to cast a byte array of length
    2*sizeof(int)+sizeof (char) to something like

    struct {
    int a;
    char b;
    int c;
    }

    because its length will most probably be more than that due to the
    "c" field being aligned (typically) to a 4 or 8 byte boundary, not
    right after the "b" member.

    Any serious compiler does have a way to explicitly control packing of
    structs, but it a) should be employed in your case; b) is not portable
    across compilers of different families.

    That's why there's an encoding/binary package: while it's not a
    pinnacle of effectiveness (for some reason Go does not include
    platform-optimized versions of certain functions in this package) it
    allows you to do serialization/deserialization right by explicitly
    using a specific endianness to read/write your data.

    1. http://en.wikipedia.org/wiki/Endianness
    2. http://en.wikipedia.org/wiki/Data_structure_alignment
    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts...@googlegroups.com <javascript:>.
    For more options, visit https://groups.google.com/groups/opt_out.


    --
    Michael T. Jones | Chief Technology Advocate | m...@google.com<javascript:>
    +1 650-335-5765
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Michael Jones at Dec 4, 2013 at 8:26 pm
    ...which is why I like to do my own work. ;-)

    On Wed, Dec 4, 2013 at 6:28 AM, wrote:

    Great post on why you shouldn't use a C struct copy to define your wire
    protocol.

    Does the Go library:
    1) only do one memory allocation (no realloc()) ?
    2) As easy to read as Python str.format(), which uses c-style printf to
    define a buffer format ?

    IMHO, the problem with these "serializers" (most of 'em) is they present a
    picture-perfect API that does a LOT of malloc() underneath.

    On Wednesday, December 4, 2013 1:18:08 AM UTC+9, Michael Jones wrote:

    Precisely. Not only are byte order and struct layout presumed in the C
    original, so is int size. If you moved between 32-bit and 64-bit hosts, you
    could need to change your firmware (or change 'int' to 'long' or whatever).

    Doing it by hand in Go is perfect. Doing it using library tools as Minux
    shows is perfect and simpler. Both of these work in every case, on every
    platform, etc. so long as your data really does map one-to-one on both
    sides of the wire.

    If, as is often the case in heterogeneous systems with products from
    multiple vendors, the data from devices is encoded in some way, you have to
    make a stylistic choice about when and where to decode. For example, maybe
    the packet has variable length depending on observations or maybe certain
    data values are reserved to indicate power or probe failure, out of range
    or unreliable data, and so on. In such cases you can either structure your
    code to read a raw packet and then decode it or to read the items one at a
    time and decode them. Both ways are good.

    On Tue, Dec 3, 2013 at 8:08 AM, alex knol wrote:

    So the reason this has always worked for me on Arduino is that i've been
    using the same platform and compiler....
    Learnt something there ;-) tnx

    So it seems writing "unwrappers" per message type (sender struct) is the
    safest option, like i started in my nodejs poc.

    Thanks for your detailed answer.


    On Tuesday, December 3, 2013 2:52:44 PM UTC+1, Konstantin Khomoutov
    wrote:
    On Tue, 3 Dec 2013 00:07:08 -0800 (PST)
    alex knol wrote:
    As easy as it is in C (arduino) to go from a received msg to the
    struct is the ultimate goal:
    typedef struct {
    boolean pump; // pump on or off
    boolean needPump; //we need the pump
    boolean water; // is there water detected
    int tempIn; // temperature panel in
    int tempOut; // temperature panel out
    int tempAmb; // temperature outside
    // int panelFlow; // The water flow speed.
    } panelData;

    void receive () {
    if (rf12_recvDone() && rf12_crc == 0) {
    if ((RF12_HDR_MASK & rf12_hdr) == panelsID) { // from the panels
    panelData* buf = (panelData*) rf12_data;
    }
    }
    }
    One obvious problem with your code is that it assumes the same
    endianness [1] of the integers sent "on the wire" by your hardware and
    the machine which reads them off the wire. That is, your C program is
    not portable. What's worse, it will build just OK on a box with
    different endianness but will silently produce different results.

    The second, less obvious, problem with your C program is that the C
    standard does not specify any way to define a "packed" struct, and by
    default the compiler is free to lay out your struct members in any way
    it wishes, save for reordering them, which means that typically any
    struct member will be laid out using a boundary which is some factor of
    sizeof (int) (on Intel platforms it's typically 8 bytes, IIRC) [2].
    This means it's futile to cast a byte array of length
    2*sizeof(int)+sizeof (char) to something like

    struct {
    int a;
    char b;
    int c;
    }

    because its length will most probably be more than that due to the
    "c" field being aligned (typically) to a 4 or 8 byte boundary, not
    right after the "b" member.

    Any serious compiler does have a way to explicitly control packing of
    structs, but it a) should be employed in your case; b) is not portable
    across compilers of different families.

    That's why there's an encoding/binary package: while it's not a
    pinnacle of effectiveness (for some reason Go does not include
    platform-optimized versions of certain functions in this package) it
    allows you to do serialization/deserialization right by explicitly
    using a specific endianness to read/write your data.

    1. http://en.wikipedia.org/wiki/Endianness
    2. http://en.wikipedia.org/wiki/Data_structure_alignment
    --
    You received this message because you are subscribed to the Google
    Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send
    an email to golang-nuts...@googlegroups.com.

    For more options, visit https://groups.google.com/groups/opt_out.


    --
    Michael T. Jones | Chief Technology Advocate | m...@google.com | +1
    650-335-5765
    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.


    --
    Michael T. Jones | Chief Technology Advocate | mtj@google.com | +1
    650-335-5765

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Matt Harden at Dec 4, 2013 at 10:29 pm
    If the Go library being discussed is encoding/binary, it does satisfy #1,
    although it does use reflection extensively, which is considered slow. It
    looks like reflection doesn't allocate unnecessarily either. As for item
    #2, there is no support for printf-style format strings. The type of each
    item combined with the specified endianness determines the binary format.
    Padding can be added by using struct fields named _.

    On Wed, Dec 4, 2013 at 8:28 AM, wrote:

    Great post on why you shouldn't use a C struct copy to define your wire
    protocol.

    Does the Go library:
    1) only do one memory allocation (no realloc()) ?
    2) As easy to read as Python str.format(), which uses c-style printf to
    define a buffer format ?

    IMHO, the problem with these "serializers" (most of 'em) is they present a
    picture-perfect API that does a LOT of malloc() underneath.

    On Wednesday, December 4, 2013 1:18:08 AM UTC+9, Michael Jones wrote:

    Precisely. Not only are byte order and struct layout presumed in the C
    original, so is int size. If you moved between 32-bit and 64-bit hosts, you
    could need to change your firmware (or change 'int' to 'long' or whatever).

    Doing it by hand in Go is perfect. Doing it using library tools as Minux
    shows is perfect and simpler. Both of these work in every case, on every
    platform, etc. so long as your data really does map one-to-one on both
    sides of the wire.

    If, as is often the case in heterogeneous systems with products from
    multiple vendors, the data from devices is encoded in some way, you have to
    make a stylistic choice about when and where to decode. For example, maybe
    the packet has variable length depending on observations or maybe certain
    data values are reserved to indicate power or probe failure, out of range
    or unreliable data, and so on. In such cases you can either structure your
    code to read a raw packet and then decode it or to read the items one at a
    time and decode them. Both ways are good.

    On Tue, Dec 3, 2013 at 8:08 AM, alex knol wrote:

    So the reason this has always worked for me on Arduino is that i've been
    using the same platform and compiler....
    Learnt something there ;-) tnx

    So it seems writing "unwrappers" per message type (sender struct) is the
    safest option, like i started in my nodejs poc.

    Thanks for your detailed answer.


    On Tuesday, December 3, 2013 2:52:44 PM UTC+1, Konstantin Khomoutov
    wrote:
    On Tue, 3 Dec 2013 00:07:08 -0800 (PST)
    alex knol wrote:
    As easy as it is in C (arduino) to go from a received msg to the
    struct is the ultimate goal:
    typedef struct {
    boolean pump; // pump on or off
    boolean needPump; //we need the pump
    boolean water; // is there water detected
    int tempIn; // temperature panel in
    int tempOut; // temperature panel out
    int tempAmb; // temperature outside
    // int panelFlow; // The water flow speed.
    } panelData;

    void receive () {
    if (rf12_recvDone() && rf12_crc == 0) {
    if ((RF12_HDR_MASK & rf12_hdr) == panelsID) { // from the panels
    panelData* buf = (panelData*) rf12_data;
    }
    }
    }
    One obvious problem with your code is that it assumes the same
    endianness [1] of the integers sent "on the wire" by your hardware and
    the machine which reads them off the wire. That is, your C program is
    not portable. What's worse, it will build just OK on a box with
    different endianness but will silently produce different results.

    The second, less obvious, problem with your C program is that the C
    standard does not specify any way to define a "packed" struct, and by
    default the compiler is free to lay out your struct members in any way
    it wishes, save for reordering them, which means that typically any
    struct member will be laid out using a boundary which is some factor of
    sizeof (int) (on Intel platforms it's typically 8 bytes, IIRC) [2].
    This means it's futile to cast a byte array of length
    2*sizeof(int)+sizeof (char) to something like

    struct {
    int a;
    char b;
    int c;
    }

    because its length will most probably be more than that due to the
    "c" field being aligned (typically) to a 4 or 8 byte boundary, not
    right after the "b" member.

    Any serious compiler does have a way to explicitly control packing of
    structs, but it a) should be employed in your case; b) is not portable
    across compilers of different families.

    That's why there's an encoding/binary package: while it's not a
    pinnacle of effectiveness (for some reason Go does not include
    platform-optimized versions of certain functions in this package) it
    allows you to do serialization/deserialization right by explicitly
    using a specific endianness to read/write your data.

    1. http://en.wikipedia.org/wiki/Endianness
    2. http://en.wikipedia.org/wiki/Data_structure_alignment
    --
    You received this message because you are subscribed to the Google
    Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send
    an email to golang-nuts...@googlegroups.com.

    For more options, visit https://groups.google.com/groups/opt_out.


    --
    Michael T. Jones | Chief Technology Advocate | m...@google.com | +1
    650-335-5765
    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • C Banning at Dec 3, 2013 at 6:59 pm
    http://play.golang.org/p/8s9I2jZDs0
    On Monday, December 2, 2013 2:29:17 PM UTC-6, alex knol wrote:

    I know it's a bit of a stretch for my first go at Golang ;-) but I want to
    decode a string of decimals sent by my an Arduino that has been created
    from a struct like this:

    type heatingData struct {

    tankIn int // temp going into the tank

    tankBottom int // temperature bottom of tank

    tankTop int // temperature top of tank

    xchangeIn int // temperature going in the tank / back from floor

    xchangeOut int // temperature coming out of the tank

    afterHeater int // temperature coming out of the tank

    floorIn int // temperature going in the floor

    floorFlow int // The water flow speed.

    panelOut int // temperature panel out

    panelAmb int // temperature outside

    panelIn int

    flowIn int // cold water flow into floor

    errorCode int // error code

    solarPump bool // pump on or off

    spPwm byte // solar pump pwm

    floorPump bool // pump on or off

    fpPwm byte // pump pwm;

    heaterPump bool //auxilary heater pump

    }


    the data received from the serial port is:

    31 52 1 0 0 163 1 0 0 122 1 50 1 97 1 0 0 103 0 106 0


    I am curious if there is an easy way to 'map' this sequence back to a struct?
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Alex knol at Dec 3, 2013 at 11:54 pm
    First things first:

    How do I read variable length messages from my serial port into something
    like a buffer?
    I've looked at the examples in these libraries
    http://godoc.org/?q=serial+port but they all seem to define a MSG length
    before the read.

    I have tried the example from sio here: http://play.golang.org/p/OvvdWmL56N
    According to the arduino (jeenode) spec the messages can be at the most 66
    bytes long (why i chose 66 bytes).

    But the output is garbled:

    Read: "OK 30 34 1 0 0 164 1 0 0 130 1 87 1 114 1 0 0 82 0 101 0 68 0 0 0 "

    Read: "0 0 0 100 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0 130 1 86 1 114 1 0 0 8"

    Read: "2 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0 130"

    Read: " 1 85 1 114 1 0 0 82 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30 34 "

    Read: "1 0 0 164 1 0 0 130 1 85 1 114 1 0 0 82 0 101 0 68 0 0 0 0 0 0 100"

    Read: " 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0 130 1 84 1 114 1 0 0 82 0 101 0"

    Read: " 68 0 0 0 0 0 0 100 1 100 0\r\n ? 137 143 157 242 196 143 27 46 71 1"

    Read: "48 7 220 7 131 25 181 219 240 8 55 71\r\nOK 30 34 1 0 0 164 1 0 0 13"

    Read: "0 1 84 1 114 1 0 0 82 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\n ? 1 0 0"

    Read: " 0 64 0 0 128 50 128\r\nOK 30 34 1 0 0 164 1 0 0 130 1 84 1 114 1 0 "

    Read: "0 81 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0 "

    Read: "130 1 82 1 114 1 0 0 81 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30 "

    Read: "34 1 0 0 164 1 0 0 130 1 82 1 114 1 0 0 81 0 101 0 68 0 0 0 0 0 0 "

    ....

    Read: "0 0 0 "

    Read: "0 0 10"

    Read: "0 1 1"

    Read: "00 1\r\n"


    Can i not read until the \r\n in some way?

    A buffer seems the type to use for variable length stuff right, or am I
    wrong?

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Minux at Dec 4, 2013 at 3:16 am

    On Tue, Dec 3, 2013 at 6:54 PM, alex knol wrote:

    First things first:

    How do I read variable length messages from my serial port into something
    like a buffer?
    I've looked at the examples in these libraries
    http://godoc.org/?q=serial+port but they all seem to define a MSG length
    before the read.

    I have tried the example from sio here:
    http://play.golang.org/p/OvvdWmL56N
    According to the arduino (jeenode) spec the messages can be at the most 66
    bytes long (why i chose 66 bytes).

    But the output is garbled:

    Read: "OK 30 34 1 0 0 164 1 0 0 130 1 87 1 114 1 0 0 82 0 101 0 68 0 0 0 "

    Read: "0 0 0 100 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0 130 1 86 1 114 1 0 0
    8"

    Read: "2 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0
    130"

    Read: " 1 85 1 114 1 0 0 82 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30 34
    "

    Read: "1 0 0 164 1 0 0 130 1 85 1 114 1 0 0 82 0 101 0 68 0 0 0 0 0 0 100"

    Read: " 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0 130 1 84 1 114 1 0 0 82 0 101
    0"

    Read: " 68 0 0 0 0 0 0 100 1 100 0\r\n ? 137 143 157 242 196 143 27 46 71
    1"

    Read: "48 7 220 7 131 25 181 219 240 8 55 71\r\nOK 30 34 1 0 0 164 1 0 0
    13"

    Read: "0 1 84 1 114 1 0 0 82 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\n ? 1 0
    0"

    Read: " 0 64 0 0 128 50 128\r\nOK 30 34 1 0 0 164 1 0 0 130 1 84 1 114 1 0
    "

    Read: "0 81 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0
    "

    Read: "130 1 82 1 114 1 0 0 81 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30
    "

    Read: "34 1 0 0 164 1 0 0 130 1 82 1 114 1 0 0 81 0 101 0 68 0 0 0 0 0 0 "

    ....

    Read: "0 0 0 "

    Read: "0 0 10"

    Read: "0 1 1"

    Read: "00 1\r\n"


    Can i not read until the \r\n in some way?
    You can use bufio.Scanner for this.
    http://golang.org/pkg/bufio/#Scanner
    A buffer seems the type to use for variable length stuff right, or am I
    wrong?
    Have you gone through the go tour? tour.golang.org.
    If not, you might want to go through that first.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Andy Balholm at Dec 4, 2013 at 11:23 pm

    On Tuesday, December 3, 2013 3:54:27 PM UTC-8, alex knol wrote:
    First things first:

    How do I read variable length messages from my serial port into something
    like a buffer?
    I've looked at the examples in these libraries
    http://godoc.org/?q=serial+port but they all seem to define a MSG length
    before the read.

    I have tried the example from sio here:
    http://play.golang.org/p/OvvdWmL56N
    According to the arduino (jeenode) spec the messages can be at the most 66
    bytes long (why i chose 66 bytes).

    But the output is garbled:

    Read: "OK 30 34 1 0 0 164 1 0 0 130 1 87 1 114 1 0 0 82 0 101 0 68 0 0 0 "

    Read: "0 0 0 100 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0 130 1 86 1 114 1 0 0
    8"

    Read: "2 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0
    130"

    Read: " 1 85 1 114 1 0 0 82 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30 34
    "

    Read: "1 0 0 164 1 0 0 130 1 85 1 114 1 0 0 82 0 101 0 68 0 0 0 0 0 0 100"

    Read: " 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0 130 1 84 1 114 1 0 0 82 0 101
    0"

    Read: " 68 0 0 0 0 0 0 100 1 100 0\r\n ? 137 143 157 242 196 143 27 46 71
    1"

    Read: "48 7 220 7 131 25 181 219 240 8 55 71\r\nOK 30 34 1 0 0 164 1 0 0
    13"

    Read: "0 1 84 1 114 1 0 0 82 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\n ? 1 0
    0"

    Read: " 0 64 0 0 128 50 128\r\nOK 30 34 1 0 0 164 1 0 0 130 1 84 1 114 1 0
    "

    Read: "0 81 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0
    "

    Read: "130 1 82 1 114 1 0 0 81 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30
    "

    Read: "34 1 0 0 164 1 0 0 130 1 82 1 114 1 0 0 81 0 101 0 68 0 0 0 0 0 0 "
    For a text format like that, I think you need to use fmt.Fscanf:

    var data heatingData
    _, err := fmt.Fscanf(serialPort, "OK %d %d %d\r\n", &data.tankIn,
    &data.tankBottom, &data.tankTop)

    but with more items, of course.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Michael Jones at Dec 5, 2013 at 12:33 am
    general pontification:

    These types of variable width text formats have a certain character to
    them. The reader sees...

    [body] [end of line]

    ...over and over. As you plug in the device, or power cycling starts the
    reader and writer out of synchronization. you'll get something between a
    perfect record and just (in this case) the '\n' after having missed the
    body and the '\r'.

    So, a reliable mechanism will do something like:

    read up to the first '\n' discarding everything.
    retry = 0
    while not done {
       if retry > limit { complain }
       read up to the next '\n'
       try to parse all the fields
       if that failed {retry++; continue}
       do testing, conversion, encode/decode of values
       compare checksums if applicable
       handle valid data
       retry = 0
    }

    If you do something very different, you will have problems. This scenario
    would make me inclined to read line-by-line (as has been suggested) then
    parse the result.

    On Wed, Dec 4, 2013 at 3:23 PM, Andy Balholm wrote:
    On Tuesday, December 3, 2013 3:54:27 PM UTC-8, alex knol wrote:

    First things first:

    How do I read variable length messages from my serial port into something
    like a buffer?
    I've looked at the examples in these libraries http://godoc.org/?q=
    serial+port but they all seem to define a MSG length before the read.

    I have tried the example from sio here: http://play.golang.org/
    p/OvvdWmL56N
    According to the arduino (jeenode) spec the messages can be at the most
    66 bytes long (why i chose 66 bytes).

    But the output is garbled:

    Read: "OK 30 34 1 0 0 164 1 0 0 130 1 87 1 114 1 0 0 82 0 101 0 68 0 0 0 "

    Read: "0 0 0 100 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0 130 1 86 1 114 1 0 0
    8"

    Read: "2 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0
    130"

    Read: " 1 85 1 114 1 0 0 82 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30
    34 "

    Read: "1 0 0 164 1 0 0 130 1 85 1 114 1 0 0 82 0 101 0 68 0 0 0 0 0 0 100"

    Read: " 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0 130 1 84 1 114 1 0 0 82 0 101
    0"

    Read: " 68 0 0 0 0 0 0 100 1 100 0\r\n ? 137 143 157 242 196 143 27 46 71
    1"

    Read: "48 7 220 7 131 25 181 219 240 8 55 71\r\nOK 30 34 1 0 0 164 1 0 0
    13"

    Read: "0 1 84 1 114 1 0 0 82 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\n ? 1 0
    0"

    Read: " 0 64 0 0 128 50 128\r\nOK 30 34 1 0 0 164 1 0 0 130 1 84 1 114 1
    0 "

    Read: "0 81 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30 34 1 0 0 164 1 0
    0 "

    Read: "130 1 82 1 114 1 0 0 81 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK
    30 "

    Read: "34 1 0 0 164 1 0 0 130 1 82 1 114 1 0 0 81 0 101 0 68 0 0 0 0 0 0 "
    For a text format like that, I think you need to use fmt.Fscanf:

    var data heatingData
    _, err := fmt.Fscanf(serialPort, "OK %d %d %d\r\n", &data.tankIn,
    &data.tankBottom, &data.tankTop)

    but with more items, of course.

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.


    --
    Michael T. Jones | Chief Technology Advocate | mtj@google.com | +1
    650-335-5765

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Matt Harden at Dec 5, 2013 at 2:17 am
    I think that, as a newbie to Go, Alex may be missing the fact that any type
    with a Read() method satisfies the io.Reader interface, and can therefore
    be used with any function that expects a reader, such as the fmt.Fscanf()
    function suggested by Andy. In Alex's example
    http://play.golang.org/p/OvvdWmL56N, the port variable can be passed to
    fmt.Fscanf(). There is no need to manage the buffers yourself. Unless you
    want to.

    To read line-by-line as Michael suggested, one way is to use
    bufio.NewScanner() as in http://golang.org/pkg/bufio/#example_Scanner_lines.
    You could run an extra scanner.Scan() at the beginning to toss out the
    first, potentially garbled, line. The string returned by scanner.Text() can
    be used with fmt.Sscan() or Sscanf() to parse out the numbers.

    On Wed, Dec 4, 2013 at 6:33 PM, Michael Jones wrote:

    general pontification:

    These types of variable width text formats have a certain character to
    them. The reader sees...

    [body] [end of line]

    ...over and over. As you plug in the device, or power cycling starts the
    reader and writer out of synchronization. you'll get something between a
    perfect record and just (in this case) the '\n' after having missed the
    body and the '\r'.

    So, a reliable mechanism will do something like:

    read up to the first '\n' discarding everything.
    retry = 0
    while not done {
    if retry > limit { complain }
    read up to the next '\n'
    try to parse all the fields
    if that failed {retry++; continue}
    do testing, conversion, encode/decode of values
    compare checksums if applicable
    handle valid data
    retry = 0
    }

    If you do something very different, you will have problems. This scenario
    would make me inclined to read line-by-line (as has been suggested) then
    parse the result.

    On Wed, Dec 4, 2013 at 3:23 PM, Andy Balholm wrote:
    On Tuesday, December 3, 2013 3:54:27 PM UTC-8, alex knol wrote:

    First things first:

    How do I read variable length messages from my serial port into
    something like a buffer?
    I've looked at the examples in these libraries http://godoc.org/?q=
    serial+port but they all seem to define a MSG length before the read.

    I have tried the example from sio here: http://play.golang.org/
    p/OvvdWmL56N
    According to the arduino (jeenode) spec the messages can be at the most
    66 bytes long (why i chose 66 bytes).

    But the output is garbled:

    Read: "OK 30 34 1 0 0 164 1 0 0 130 1 87 1 114 1 0 0 82 0 101 0 68 0 0 0
    "

    Read: "0 0 0 100 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0 130 1 86 1 114 1 0
    0 8"

    Read: "2 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0
    130"

    Read: " 1 85 1 114 1 0 0 82 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30
    34 "

    Read: "1 0 0 164 1 0 0 130 1 85 1 114 1 0 0 82 0 101 0 68 0 0 0 0 0 0
    100"

    Read: " 1 100 0\r\nOK 30 34 1 0 0 164 1 0 0 130 1 84 1 114 1 0 0 82 0
    101 0"

    Read: " 68 0 0 0 0 0 0 100 1 100 0\r\n ? 137 143 157 242 196 143 27 46
    71 1"

    Read: "48 7 220 7 131 25 181 219 240 8 55 71\r\nOK 30 34 1 0 0 164 1 0 0
    13"

    Read: "0 1 84 1 114 1 0 0 82 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\n ? 1
    0 0"

    Read: " 0 64 0 0 128 50 128\r\nOK 30 34 1 0 0 164 1 0 0 130 1 84 1 114 1
    0 "

    Read: "0 81 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK 30 34 1 0 0 164 1 0
    0 "

    Read: "130 1 82 1 114 1 0 0 81 0 101 0 68 0 0 0 0 0 0 100 1 100 0\r\nOK
    30 "

    Read: "34 1 0 0 164 1 0 0 130 1 82 1 114 1 0 0 81 0 101 0 68 0 0 0 0 0 0
    "
    For a text format like that, I think you need to use fmt.Fscanf:

    var data heatingData
    _, err := fmt.Fscanf(serialPort, "OK %d %d %d\r\n", &data.tankIn,
    &data.tankBottom, &data.tankTop)

    but with more items, of course.

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.


    --
    Michael T. Jones | Chief Technology Advocate | mtj@google.com | +1
    650-335-5765

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedDec 3, '13 at 1:57a
activeDec 5, '13 at 2:17a
posts19
users8
websitegolang.org

People

Translate

site design / logo © 2022 Grokbase