Pages: [1]   Go Down
Author Topic: Unions+Functions+serialWrite = Error  (Read 749 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 18
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello Everybody,

I'm working on a project, wich is kind of a midi controller, and i've ran into an error wich i can't solve, somebody please help me out smiley-sad

This is part of the code, i'm currently starting using pointers for giving variables to functions, but this gives me an error:

Code:
#define _C4 0x30
#define _Cs4 0x31
#define _D4 0x32
#define _Ds4 0x33
#define _E4 0x34
#define _F4 0x35
#define _Fs4 0x36
#define _G4 0x37
#define _Gs4 0x38
#define _A4 0x39
#define _As4 0x3A
#define _B4 0x3B
#define _C5 0x3C
#define NoteOn 0x7B
#define MaxVel 0xFF

typedef union {
  struct {
    uint8_t Command;
    uint8_t Channel;
    uint8_t Data1;
    uint8_t Data2;
  } Msg;
  uint8_t Raw[4];
} MidiMsg;

void setup() {
Serial.begin(31250);
}

void SendMsgSerial (MidiMsg* Message){
Serial.write(*Message.Raw, sizeof(*Message));
}

void SendNoteOn (uint8_t Note, uint8_t Velocity, uint8_t Channel){
MidiMsg Message;
Message.Msg.Command=NoteOn;
Message.Msg.Channel=Channel;
Message.Msg.Data1=Note;
Message.Msg.Data2=Velocity;
SendMsgSerial(&Message);
}

void SendScale (int ValveState){
uint8_t Vel=MaxVel;
uint8_t Ch=0x00;
switch (ValveState) {
case 0: SendNoteOn(_C4,Vel,Ch); break;
case 1: SendNoteOn(_D4,Vel,Ch); break;
case 2: SendNoteOn(_F4,Vel,Ch); break;
case 3: SendNoteOn(_E4,Vel,Ch); break;
case 4: SendNoteOn(_A4,Vel,Ch); break;
case 5: SendNoteOn(_B4,Vel,Ch); break;
case 6: SendNoteOn(_G4,Vel,Ch); break;
case 7: SendNoteOn(_C5,Vel,Ch); break;
}
}
void loop(){
SendScale(0);
}

the error is : "sketch_mar21a:36: error: request for member 'Raw' in 'Message', which is of non-class type 'MidiMsg*'"


SendMsgSerial is a must have function, and I would like to give the data to it with a pointer to a "MidiMsg" union, wich consists of 4 bytes (later it will be only 3) , because 3 serialWrite commands / midi message is a bit too much in my case, and i would like to send the 3 byte command in one "serialWrite" command...


 Anybody could help me out?
Thanks a lot
« Last Edit: March 21, 2013, 04:29:39 pm by adnalok » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 549
Posts: 46063
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What happens if you define the struct outside of the union?
Logged

0
Offline Offline
God Member
*****
Karma: 39
Posts: 986
Get Bitlash: http://bitlash.net
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Also, what happens if you change:
Code:
Serial.write(*Message.Raw, sizeof(*Message));
to:
Code:
Serial.write(Message->Raw, sizeof(*Message));

-br
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 18
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Also, what happens if you change:
Code:
Serial.write(*Message.Raw, sizeof(*Message));
to:
Code:
Serial.write(Message->Raw, sizeof(*Message));

-br


I've done both recomenndations

Code:
#define _C4 0x30
#define _Cs4 0x31
#define _D4 0x32
#define _Ds4 0x33
#define _E4 0x34
#define _F4 0x35
#define _Fs4 0x36
#define _G4 0x37
#define _Gs4 0x38
#define _A4 0x39
#define _As4 0x3A
#define _B4 0x3B
#define _C5 0x3C
#define NoteOn 0x7B
#define MaxVel 0xFF

struct Msg{
    uint8_t Command;
    uint8_t Channel;
    uint8_t Data1;
    uint8_t Data2;
  };
 
typedef union {
  Msg Msg1;
  uint8_t Raw[4];
} MidiMsg;

void setup() {
Serial.begin(31250);
}

void SendMidiMsg (MidiMsg* Message){
Serial.write(Message->Raw, sizeof(*Message));
}

void SendNoteOn (uint8_t Note, uint8_t Velocity, uint8_t Channel){
MidiMsg Message;
Message.Msg1.Command=NoteOn;
Message.Msg1.Channel=Channel;
Message.Msg1.Data1=Note;
Message.Msg1.Data2=Velocity;
SendMidiMsg(&Message);
}

void SendScale (int ValveState){
uint8_t Vel=MaxVel;
uint8_t Ch=0x00;
switch (ValveState) {
case 0: SendNoteOn(_C4,Vel,Ch); break;
case 1: SendNoteOn(_D4,Vel,Ch); break;
case 2: SendNoteOn(_F4,Vel,Ch); break;
case 3: SendNoteOn(_E4,Vel,Ch); break;
case 4: SendNoteOn(_A4,Vel,Ch); break;
case 5: SendNoteOn(_B4,Vel,Ch); break;
case 6: SendNoteOn(_G4,Vel,Ch); break;
case 7: SendNoteOn(_C5,Vel,Ch); break;
}
}
void loop(){
SendScale(0);
}

Now i only have 3 errors

sketch_mar21a:19: error: variable or field 'SendMidiMsg' declared void
sketch_mar21a:19: error: 'MidiMsg' was not declared in this scope
sketch_mar21a:19: error: 'Message' was not declared in this scope

I think the original problem is solved, but im missing out something
Logged

Des Moines, WA - USA
Offline Offline
God Member
*****
Karma: 25
Posts: 779
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
#define ENTRIES(ARRAY) (sizeof(ARRAY) / sizeof(ARRAY[0]))

#define _C4             0x30
#define _Cs4            0x31
#define _D4             0x32
#define _Ds4            0x33
#define _E4             0x34
#define _F4             0x35
#define _Fs4            0x36
#define _G4             0x37
#define _Gs4            0x38
#define _A4             0x39
#define _As4            0x3A
#define _B4             0x3B
#define _C5             0x3C
#define NoteOn          0x7B
#define MaxVel          0xFF

struct MidiMsg
{
    union
    {
        struct { uint8_t    Command, Channel, Data1, Data2; };
                 uint8_t    Raw[4];
    };
} ;

void setup()
{
    Serial.begin(31250);
}

void SendMsgSerial(struct MidiMsg* Message)
{
    Serial.write(Message->Raw,  ENTRIES(Message->Raw));
}

void SendNoteOn(uint8_t Note, uint8_t Velocity, uint8_t Channel)
{
    MidiMsg     Message;
    Message.Command = NoteOn;
    Message.Channel = Channel;
    Message.Data1   = Note;
    Message.Data2   = Velocity;
    SendMsgSerial(&Message);
}

void SendScale(int ValveState)
{
    uint8_t Vel = MaxVel;
    uint8_t Ch  = 0x00;
    switch ( ValveState )
    {
        case 0: SendNoteOn(_C4, Vel, Ch);   break;
        case 1: SendNoteOn(_D4, Vel, Ch);   break;
        case 2: SendNoteOn(_F4, Vel, Ch);   break;
        case 3: SendNoteOn(_E4, Vel, Ch);   break;
        case 4: SendNoteOn(_A4, Vel, Ch);   break;
        case 5: SendNoteOn(_B4, Vel, Ch);   break;
        case 6: SendNoteOn(_G4, Vel, Ch);   break;
        case 7: SendNoteOn(_C5, Vel, Ch);   break;
    }
}

void loop()
{
    SendScale(0);
}
Logged

0
Offline Offline
God Member
*****
Karma: 39
Posts: 986
Get Bitlash: http://bitlash.net
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think you were being bit by some variant of the "precompiler rearranges your sketch" bug. 

I got your last code to compile by adding a line defining SendMidiMsg(); see below. 

I got there by looking at the .cpp that is actually compiled for the project, which you can get from rummaging around in the build folder, which you can identify by turning on verbose builds in Preferences.  The precompiler phase moved the definition of SendMidiMsg above the definition of the union, which made the compiler unhappy.  It seems better here with the patch.

-br

Code:
#include "arduino.h"

#define _C4 0x30
#define _Cs4 0x31
#define _D4 0x32
#define _Ds4 0x33
#define _E4 0x34
#define _F4 0x35
#define _Fs4 0x36
#define _G4 0x37
#define _Gs4 0x38
#define _A4 0x39
#define _As4 0x3A
#define _B4 0x3B
#define _C5 0x3C
#define NoteOn 0x7B
#define MaxVel 0xFF

typedef union {
struct {
    uint8_t Command;
    uint8_t Channel;
    uint8_t Data1;
    uint8_t Data2;
  } Msg;
  uint8_t Raw[4];
} MidiMsg;
void SendMidiMsg (MidiMsg* Message);  // this is the magic line


void setup() {
Serial.begin(31250);
}

void SendMidiMsg (MidiMsg* Message){
Serial.write(Message->Raw, sizeof(*Message));
}

void SendNoteOn (uint8_t Note, uint8_t Velocity, uint8_t Channel){
MidiMsg Message;
Message.Msg.Command=NoteOn;
Message.Msg.Channel=Channel;
Message.Msg.Data1=Note;
Message.Msg.Data2=Velocity;
SendMidiMsg(&Message);
}

void SendScale (int ValveState){
uint8_t Vel=MaxVel;
uint8_t Ch=0x00;
switch (ValveState) {
case 0: SendNoteOn(_C4,Vel,Ch); break;
case 1: SendNoteOn(_D4,Vel,Ch); break;
case 2: SendNoteOn(_F4,Vel,Ch); break;
case 3: SendNoteOn(_E4,Vel,Ch); break;
case 4: SendNoteOn(_A4,Vel,Ch); break;
case 5: SendNoteOn(_B4,Vel,Ch); break;
case 6: SendNoteOn(_G4,Vel,Ch); break;
case 7: SendNoteOn(_C5,Vel,Ch); break;
}
}
void loop(){
SendScale(0);
}
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 18
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
#define ENTRIES(ARRAY) (sizeof(ARRAY) / sizeof(ARRAY[0]))

#define _C4             0x30
#define _Cs4            0x31
#define _D4             0x32
#define _Ds4            0x33
#define _E4             0x34
#define _F4             0x35
#define _Fs4            0x36
#define _G4             0x37
#define _Gs4            0x38
#define _A4             0x39
#define _As4            0x3A
#define _B4             0x3B
#define _C5             0x3C
#define NoteOn          0x7B
#define MaxVel          0xFF

struct MidiMsg
{
    union
    {
        struct { uint8_t    Command, Channel, Data1, Data2; };
                 uint8_t    Raw[4];
    };
} ;

void setup()
{
    Serial.begin(31250);
}

void SendMsgSerial(struct MidiMsg* Message)
{
    Serial.write(Message->Raw,  ENTRIES(Message->Raw));
}

void SendNoteOn(uint8_t Note, uint8_t Velocity, uint8_t Channel)
{
    MidiMsg     Message;
    Message.Command = NoteOn;
    Message.Channel = Channel;
    Message.Data1   = Note;
    Message.Data2   = Velocity;
    SendMsgSerial(&Message);
}

void SendScale(int ValveState)
{
    uint8_t Vel = MaxVel;
    uint8_t Ch  = 0x00;
    switch ( ValveState )
    {
        case 0: SendNoteOn(_C4, Vel, Ch);   break;
        case 1: SendNoteOn(_D4, Vel, Ch);   break;
        case 2: SendNoteOn(_F4, Vel, Ch);   break;
        case 3: SendNoteOn(_E4, Vel, Ch);   break;
        case 4: SendNoteOn(_A4, Vel, Ch);   break;
        case 5: SendNoteOn(_B4, Vel, Ch);   break;
        case 6: SendNoteOn(_G4, Vel, Ch);   break;
        case 7: SendNoteOn(_C5, Vel, Ch);   break;
    }
}

void loop()
{
    SendScale(0);
}


That works like a charm, but i don't really understand the magic of that ENTRIES(ARRAY). Thank You very much for the help this forum is a really helpful place!

EDIT: Also, the second solution is working, but with a differend method and ths gets me more confused... Thanks a lot anyway!

Also while i have some pro coders attention, is there any advise about these functions, to make them more simple/efficent / ?

Since i have a ton more functions sending notes depending on input,

Example:

Code:
void Send2_5Octave (int ValveState){
switch (ValveState) {
case 0:
SendMidiMsg(NoteOn,_C4,MaxVel);
SendMidiMsg(NoteOn,_G4,MaxVel);
SendMidiMsg(NoteOn,_C5,MaxVel);
SendMidiMsg(NoteOn,_E5,MaxVel);
SendMidiMsg(NoteOn,_G5,MaxVel);
SendMidiMsg(NoteOn,_C6,MaxVel);
break;
case 2:
SendMidiMsg(NoteOn,_B3,MaxVel);
SendMidiMsg(NoteOn,_Fs4,MaxVel);
SendMidiMsg(NoteOn,_B4,MaxVel);
SendMidiMsg(NoteOn,_Ds5,MaxVel);
SendMidiMsg(NoteOn,_Fs5,MaxVel);
SendMidiMsg(NoteOn,_B5,MaxVel);
break;
case 3:
SendMidiMsg(NoteOn,_Gs3,MaxVel);
SendMidiMsg(NoteOn,_Ds4,MaxVel);
SendMidiMsg(NoteOn,_Gs4,MaxVel);
SendMidiMsg(NoteOn,_Gs5,MaxVel);
break;
case 4:
SendMidiMsg(NoteOn,_As3,MaxVel);
SendMidiMsg(NoteOn,_F4,MaxVel);
SendMidiMsg(NoteOn,_As4,MaxVel);
SendMidiMsg(NoteOn,_D5,MaxVel);
SendMidiMsg(NoteOn,_F5,MaxVel);
SendMidiMsg(NoteOn,_As5,MaxVel);
break;
case 5:
SendMidiMsg(NoteOn,_G3,MaxVel);
SendMidiMsg(NoteOn,_D4,MaxVel);
break;
case 7:
SendMidiMsg(NoteOn,_Fs3,MaxVel);
SendMidiMsg(NoteOn,_Cs4,MaxVel);
break;
default:
SendMidiMsg(NoteOn,_A3,MaxVel);
SendMidiMsg(NoteOn,_E4,MaxVel);
SendMidiMsg(NoteOn,_A4,MaxVel);
SendMidiMsg(NoteOn,_Cs5,MaxVel);
SendMidiMsg(NoteOn,_A5,MaxVel);
}
}

 I would also like to make the "SendNoteOn" function to handle a dynamic number(max 10) of notes in the input parameter list. Any advise on that?

Code:
#define ENTRIES(ARRAY) (sizeof(ARRAY) / sizeof(ARRAY[0]))

#define _C4             0x30
#define _Cs4            0x31
#define _D4             0x32
#define _Ds4            0x33
#define _E4             0x34
#define _F4             0x35
#define _Fs4            0x36
#define _G4             0x37
#define _Gs4            0x38
#define _A4             0x39
#define _As4            0x3A
#define _B4             0x3B
#define _C5             0x3C
#define NoteOn          0x7B
#define MaxVel          0xFF

struct MidiMsg
{
    union
    {
        struct { uint8_t    Data1, Data2, Data3; };
                 uint8_t    Raw[3];
    };
} ;

void setup()
{
    Serial.begin(31250);
}

void SendMsgSerial(struct MidiMsg* Message)
{
    Serial.write(Message->Raw,  ENTRIES(Message->Raw));
}

void SendNoteOn(uint8_t Note, uint8_t Velocity, uint8_t Channel)
{
    uint8_t Sum;
    Sum=NoteOn<<4;
    Sum=(Sum|Channel);
    MidiMsg     Message;
    Message.Data1   = Sum;
    Message.Data2   = Note;
    Message.Data3   = Velocity;
    SendMsgSerial(&Message);
}

void SendScale(int ValveState)
{
    uint8_t Vel = MaxVel;
    uint8_t Ch  = 0x00;
    switch ( ValveState )
    {
        case 0: SendNoteOn(_C4, Vel, Ch);   break;
        case 1: SendNoteOn(_D4, Vel, Ch);   break;
        case 2: SendNoteOn(_F4, Vel, Ch);   break;
        case 3: SendNoteOn(_E4, Vel, Ch);   break;
        case 4: SendNoteOn(_A4, Vel, Ch);   break;
        case 5: SendNoteOn(_B4, Vel, Ch);   break;
        case 6: SendNoteOn(_G4, Vel, Ch);   break;
        case 7: SendNoteOn(_C5, Vel, Ch);   break;
    }
}

void loop()
{
    SendScale(0);
}
« Last Edit: March 21, 2013, 05:17:07 pm by adnalok » Logged

Des Moines, WA - USA
Offline Offline
God Member
*****
Karma: 25
Posts: 779
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes but I'm out for the next 5 to 6 hours.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 18
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes but I'm out for the next 5 to 6 hours.

Now i'm going to do some work with the current code, if You willing to take a look, i will send it when done, and You could take a look on it, OK?
Logged

Offline Offline
Edison Member
*
Karma: 28
Posts: 2036
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I would define the struct,   and then define the union,   and then define the typedef separately.
Logged

Offline Offline
Edison Member
*
Karma: 28
Posts: 2036
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
void SendMsgSerial (MidiMsg* Message){
Serial.write(*Message.Raw, sizeof(*Message));
}

In this code,  Raw is the name of an array,  and therefore a pointer.   It isn't the values of the array,  or even the
value of the first element of the array.

As far as I know,  Serial.write() does not have a version to print the values in the array.

If I wanted to write the elements of the array,  I'd write this:
Code:
for (int i=0 ; i<4 ; i++)
{
    Serial.write( Message->Raw[i], sizeof(uint_8));
}
Logged

Des Moines, WA - USA
Offline Offline
God Member
*****
Karma: 25
Posts: 779
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
#define ENTRIES(ARRAY) (sizeof(ARRAY) / sizeof(ARRAY[0]))

'ENTRIES' is a preprocessor macro.  The preprocessor runs before the 'compiler' doing "smart" text substitution on our code before handing it off to the compiler.  Here 'ENTRIES' has one parameter 'ARRAY'.

'sizeof' give us the number of bytes a data object occupies.

'sizeof(ARRAY)' give us the byte count of the entire array.

'sizeof(ARRAY[0])' give us the byte count of the first element of the array.  An array can't have zero elements so there must be at least 1 element at index 0.

So the macro gets the byte count of the entire array and divides it by the number of bytes in an element of the array giving us the number of elements in the array.

Never hard code a value if you can get it compile time.

Anyway go ahead when ready and we'll help you get something working.
« Last Edit: March 21, 2013, 08:34:48 pm by lloyddean » Logged

Des Moines, WA - USA
Offline Offline
God Member
*****
Karma: 25
Posts: 779
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In this code,  Raw is the name of an array,  and therefore a pointer.   It isn't the values of the array,  or even the  of the first element of the array.

Actually the array 'name' is the ADDRESS of the array it is not a pointer.

A pointer a named memory location large enough to HOLD THE ADDRESS OF data of a known type.
« Last Edit: March 21, 2013, 08:41:32 pm by lloyddean » Logged

Pages: [1]   Go Up
Jump to: