Go Down

Topic: Unions+Functions+serialWrite = Error (Read 1 time) previous topic - next topic

billroy

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: [Select]

#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);
}

adnalok

#6
Mar 21, 2013, 11:11 pm Last Edit: Mar 21, 2013, 11:17 pm by adnalok Reason: 1

Code: [Select]

#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: [Select]
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: [Select]

#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);
}

lloyddean

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

adnalok


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?

michinyon

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

Go Up