Filtering receive data on UART echo

Go To Last Post
44 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello

I need help. I am looking for a solution how to write a code to receive data on avr attiny2313 after UART, specifically midi messages, comparison, receive bytes and send or not.

For example, if the UART receives a message consisting of 3 bytes, I need to compare them with those defined rigidly and if they are the same then do not send anything, and if they do not match, then send what I received.

Such a simple echo filtering program.

For now, I was able to start the echo function at the interruption but I don't know how to move on.

please help.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sounds like you need a simple state machine, look in the tutorial section for those key words.

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ki0bk wrote:
sounds like you need a simple state machine

+1

 

https://www.avrfreaks.net/commen...

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is some MIDI code in C.   This first section is in the main()  or  loop().  It tests for a newly arriving MIDI byte.  The Serial library uses the AVR's USART that has been set to MIDI baud (31250).
There is a software serial port that sends the ASCII of the received MIDI byte to the PC terminal (at 115200 baud).
Then the latest byte is processed by MIDIparse() to find its position in the current MIDI message: i.e is it the first, second, or third arriving byte of the message? Or maybe a sysEx string or even a "Running Status" compressed message.
When the full MIDI message is received, MIDIparse() sets the global boolean flag isMsgRdy to be true.   The code in the loop() then filters the new message.  In this case, all Active Sense 0xFE bytes are ignored and all Note-On's get a high fixed velocity.
  /*************************************************/  
  if ( Serial.available() ) {
    myNMB = Serial.read();
    if (myNMB != 0xfe) {  // ignore MIDI active-sense byte
       if (myNMB < 0x10) mySoftwareSerial.print(F("0"));
       mySoftwareSerial.print(myNMB, HEX); // sent at 115K baud
       mySoftwareSerial.print(F(" ")); // print 20 MIDI hex bytes on each line
       serialDisplayByteCounter += 1;
       if ( serialDisplayByteCounter > 20) {
         serialDisplayByteCounter = 0;
         mySoftwareSerial.println();
       }
       displayOneHexPair(myNMB);
    }

    //*  if (myNMB != MIDI_ACTIVE_SENSE )  {
    MIDIparse( myNMB);
    // seeMIDIparseResults();
    if ( isMsgRdy == true ) { // entire MIDI message buffered: no MIDIout sent yet
      msgSize = msgLen;
      isMsgRdy = false;
      isSysEx = false;
      msgLen = 0; // first copy MIDI message, then reset the parser

      // NOTE ON/OFF:  set velocity to 0x60 for any keypress, regardless of how lightly it is pressed.
      switch ( msgBufferPtr[0] & 0xf0 )  {
        case  0x80 :   // NOTE OFF  any velocity
          break;
        case  0x90 :   // NOTE OFF if velocity is zero.
          // if note number is above the range of the plastic keyboards...surpress rogue notes??
          if (msgBufferPtr[1] > 0x54) msgBufferPtr[2] = 0x00;
          /*    if (msgBufferPtr[1] > 0x3b){   // test of split keyboard
                   msgBufferPtr[0] = 0x91;    // notes Middle-C and above go to
                   msgBufferPtr[1] -= 12;    // MIDI channel 2 and drop an octave.
              } */
          //  surpress all velocity changes. Any keypress at any softness gets velocity = 96 (0x60)    
          if (msgBufferPtr[2] != 0)   msgBufferPtr[2] = 0x60;
          break;

        case  0xf0 :   // System Exclusive
          break;

        case  0xb0 :   // Continuous controller commands
          break;

        case  0xc0 :   // Program Change_Voice Change
        case  0xd0 :   // All programs on this channel heed this new aftertouch value
          break;

        case  0xa0 :   // aftertouch on voice number??? [rarely seen]
          break;

        case  0xe0 :   // pitch-change wheel; often uses Running_Status
          break;

        default :
          break;
      } // switch(msgBufferPtr[0])

      // send modified MIDI message to MIDI-OUT
      for (i = 0; i < msgSize; i++) Serial.write( msgBufferPtr[i] ); // send entire msg to MIDI-OUT

      // send modified MIDI message to PC terminal
      if (myNMB != 0xfe) {
        mySoftwareSerial.println();
        mySoftwareSerial.print(F("out: "));
        for (i = 0; i < msgSize; i++) {
          if (msgBuffer[i] < 0x10) mySoftwareSerial.print(F("0"));
          mySoftwareSerial.print( msgBufferPtr[i], HEX ); // send msg to PC
          mySoftwareSerial.print(F(" "));
        }

        mySoftwareSerial.println();
        mySoftwareSerial.print(F("in: "));
      }
    } // if (msgRdy == true)

  }        // if ( Serial.available() )  
 
 
 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   MIDIparse()  - update status flags on each arriving MIDI byte.
   Most MIDI messages are 3 bytes. Most sys-ex single_param_change messages are 10-15 bytes.
   Updates the following variables:
     [booleans]   isRunStatus ,isTwoByte, isThreeByte, isSysEx, isMsgRdy, isError
     [uint8_t]    msgBuffer[16]     standard and sys-ex data from MIDI IN
                  runCmdBuffer[4]   holds MIDI IN running status bytes. new RS data is sent as full MIDI msg
                  msgLen            number of bytes sent to MIDI-0UT
                    msgBufferPtr    will point to buffer used for sending data to MIDI-OUT

   updated boolean flags:
   isRunStatus  made true when the first byte of a new message is <0x8n. [n = MIDI channel 0x00-0x0f]
   isTwoByte    made true when the first byte of a new message is 0xcn, 0xdn, or 0xf2.
   isThreeByte  made true when the first byte of a new message is 0x8n, 0x9n, 0xan, 0xbn, 0xen, or 0xf3.
   isSysEx      made true when the first byte of a new message is 0xf0.
   isError      made true if first message byte is <0x80 and run_CmdBuffer[0] < 0x80.
*/
void MIDIparse(uint8_t myNMB) {     // NewMIDIbyte from mySoftwareSerial.read()
  isMsgRdy = false;  // re-initialized on each pass through MIDIparse
  isError  = false;

  if (myNMB & (1 << 7) )   //CMD  test whether NewMIDIbyte is a command byte; is bit 7 set?
  {
    uint8_t aNMB;

    aNMB = myNMB & 0xf0;

    if (aNMB == 0xf0) {
      switch (myNMB)  {
        case  0xf0 :
          isSysEx = true; msgBuffer[0] = myNMB; msgLen = 1;
          break;

        case  0xf7 :
          isRunStatus  = false; isTwoByte = false; isThreeByte = false; isSysEx = true;  // re-initialize booleans
          msgBuffer[msgLen] = myNMB; msgLen += 1; isMsgRdy = true;  msgBufferPtr = msgBuffer;
          break;

        case  0xf2 :
          isTwoByte = true; msgBuffer[0] = myNMB; msgLen = 1;
          break;

        case  0xf3 :
          isThreeByte  = true; msgBuffer[0] = myNMB; msgLen = 1;
          break;

        case  0xfe:   // Active-Sense
          isRunStatus  = false; isTwoByte = false; isThreeByte  = false; isSysEx = true;  // re-initialize booleans
          msgBuffer[0] = myNMB; msgLen = 1; isMsgRdy = true; msgBufferPtr = msgBuffer;
          break;
      }
      return;
    }   // if (aNMB == 0xf0)

    msgBuffer[0] = myNMB;
    msgLen = 1;

    if ( (aNMB == 0xc0) || (aNMB == 0xd0) ) {
      isTwoByte = true; runCmdBuffer[0] = myNMB;
      return;
    }

    if (   (aNMB == 0x80) || (aNMB == 0x90)
           ||  (aNMB == 0xa0) || (aNMB == 0xb0)
           ||  (aNMB == 0xe0)  )  {
      isThreeByte = true; runCmdBuffer[0] = myNMB;
      return;
    }
  }    //   if (myNMB & (1 << cmd) )

  else  // ----------  myNMB < 0x80  it is a data byte _____________________________________________________________________________
  { // test for running-status message
    if (msgLen == 0) {  // msgLen incremented by command byte handler

      // Error if a data byte is received with no previous MIDI message having established a command-byte value.
      //   Possibly the MIDImerge device was powered up in the middle of a MIDI message.
      if ( (runCmdBuffer[0] & (1 << 7)) == 0) { // MIDI command byte has bit 7 set
        isError = true;
        return;
      }

      //  If a data byte arrives with msgLen=0, then this is a Running-Status message.  First determine
      //  if this is a two byte or three byte message by examining runCmdBuffer[0]. If it is 0xcn or 0xdn,
      //  then this is the last byte of a rare two-byte RunStat message. If runCmdBuffer[0] is not 0xcn or 0xdn,
      //  then determine if myNMB is the middle or the last byte of the message by checking MsgLen value.
      uint8_t aRunCmd = runCmdBuffer[0] & 0xf0;
      if ( (aRunCmd == 0xc0) || (aRunCmd == 0xd0) ) {  // very rare, but possible
        isRunStatus  = false; isTwoByte = false; isThreeByte  = false; isSysEx = false; // re-initialize booleans
        runCmdBuffer[1] = myNMB; msgLen = 2; msgBufferPtr = runCmdBuffer; isMsgRdy = true;
        return;
      }
      else {  // this is the first byte of an ordinary two-data-byte Running-Status message
        isThreeByte = true; isRunStatus = true; runCmdBuffer[1] = myNMB; msgLen = 1;
        // Running-status msgs are expanded to cmd+data msgs. runCmdBuffer[0] is always a command byte.
        return;
      }
    }   //  if(msgLen == 0) [running-status message]
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    else  {   // Parse routine entered with msgLen != 0 and NMB < 0x80.  Mpt a running-status message.
      if (isSysEx == true) {      // another byte of a sys-ex message, but not last byte of msg.
        msgBuffer[msgLen] = myNMB; msgLen  += 1;
        return;  // the last byte of a sys-ex is handled by the command byte section above.
      }

      if (isTwoByte == true) {    // this is the single data (and final) byte of 0xCn or 0xDn msg
        isRunStatus  = false; isTwoByte = false; isThreeByte = false; isSysEx = false;
        msgBuffer[1] = myNMB;  msgLen = 2; msgBufferPtr = msgBuffer; isMsgRdy = true;
        return;
      }

      if (isThreeByte == true) {  // could be second or third byte of the msg
        if (msgLen == 1) {     // NMB is second byte of msg
          if (isRunStatus == true) {
            runCmdBuffer[2] = myNMB;
            isRunStatus  = false; isTwoByte = false; isThreeByte = false; isSysEx = false;
            msgLen = 3; msgBufferPtr = runCmdBuffer; isMsgRdy = true;
            return;
          }
          else  // 2nd byte (first data byte) of a standard message: not a running-status message
          {
            msgBuffer[msgLen] = myNMB; msgLen = 2;
            return;
          }
        }        //  if (msgLen == 1)

        if (msgLen == 2) {      // second and final data byte of a standard 3-byte message
          msgBuffer[msgLen] = myNMB;
          isRunStatus  = false; isTwoByte = false; isThreeByte = false; isSysEx = false;
          msgLen = 3; msgBufferPtr = msgBuffer; isMsgRdy  = true;
          return;
        }     // if (msgLen == 2)
      }          // if (isThreeByte == true)
    }               // msgLen != 0
  }                   // myNMB is a data byte
} //__________________________  end of MIDI_parse()  ______________________________________________________

// Use this function to test the MIDI monitor. When called, this function sends to the
// serial terminal the values of the monitor's flags and variables [ that were updated upon
// the last received MIDI byte].
//  MIDI bytes are arriving each 320 microSeconds. 3,125 per second.
//  This function sends about 34 chars to the UART: ~ 3mS @115K
void seeMIDIparseResults() {  // tested OK at 115200 baud
  if (myNMB < 0x10) { // @3mS full string:   MIDI bytes arrive @3 per mS.
    mySoftwareSerial.print(F("0"));  // should be able to handle 16 byte SysEx strings
    mySoftwareSerial.print( myNMB, HEX);
  }  // without a buffer overflow.
  else  mySoftwareSerial.print(myNMB, HEX);

  mySoftwareSerial.print(F("  Ln=")); mySoftwareSerial.print(msgLen);
  mySoftwareSerial.print(F("  Ry=")); isMsgRdy    ? mySoftwareSerial.print(F("T ")) : mySoftwareSerial.print(F("F "));
  mySoftwareSerial.print(F("RS="));   isRunStatus ? mySoftwareSerial.print(F("T ")) : mySoftwareSerial.print(F("F "));
  mySoftwareSerial.print(F("2="));    isTwoByte   ? mySoftwareSerial.print(F("T ")) : mySoftwareSerial.print(F("F "));
  mySoftwareSerial.print(F("3="));    isThreeByte ? mySoftwareSerial.print(F("T ")) : mySoftwareSerial.print(F("F "));
  mySoftwareSerial.print(F("SX="));   isSysEx     ? mySoftwareSerial.println(F("T")) : mySoftwareSerial.println(F("F"));
}
//__________________________  end of seeMIDI_parseResults()  __________________________________________________

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for te state machine info, I read this tut https://www.avrfreaks.net/forum/...

but still i dont now how this will help in my case :/

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Did you read the one I suggested in #3 ?

 

That is based on the specific example of decoding GPS messages - so the principle is very similar to what you want to do.

 

Note that this is quite a common application of state machines - so an internet search should find you plenty of other examples and explanations ...

 

eg,  https://www.google.com/search?q=state+machine+message+parsing

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm realy beginner programing in C and above example is too complicated to figure out.

and I still have the impression that we don't understand each other

 

here code, when I realise how I can simply ingnore byte define by me in code using condition in interrupt

but still dont now how to ignore more complex 2 or 3 byte data

 


#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "light_ws2812.h"

#define KEY_1_PIN (1<<PIND3)
#define KEY_2_PIN (1<<PIND2)
#define KEY_1_DOWN !(PIND & KEY_1_PIN)
#define KEY_2_DOWN !(PIND & KEY_2_PIN)
#define UART_BAUD 31250
#define __UBRR 8000000/16/UART_BAUD-1

unsigned char ProgramChange1 = 1;
unsigned char ProgramChange2 = 2;
unsigned char PCMidiChannel1 = 193;

uint8_t KEY_LOCK_1;
uint8_t KEY_LOCK_2;


void USART_Transmit( unsigned char data );

void USART_Init( uint16_t baud ) {
	UBRRH = (uint8_t) (baud>>8);
	UBRRL = (uint8_t)baud;
	UCSRB = (1<<RXEN) | (1<<TXEN);
	UCSRC = (1<<USBS) | (3<<UCSZ0);
}


int main(void)
{
	DDRD &= ~KEY_1_PIN;
	DDRD &= ~KEY_2_PIN;
	PORTD |= KEY_1_PIN;
	PORTD |= KEY_2_PIN;
	USART_Init(__UBRR );
	UCSRB |= (1 << RXCIE ); 
	sei (); 
	
_delay_ms(50);
	
	while (1) {
		

	if (!KEY_LOCK_1 && KEY_1_DOWN)
	{
		KEY_LOCK_1 = 1;
		USART_Transmit(PCMidiChannel1);
		USART_Transmit(ProgramChange1);
	} 
	else if ( KEY_LOCK_1 && (PIND & KEY_1_PIN)) KEY_LOCK_1 = 0;
	
	if (!KEY_LOCK_2 && KEY_2_DOWN)
	{
		KEY_LOCK_2 = 1;
		USART_Transmit(PCMidiChannel1);
		USART_Transmit(ProgramChange2);
	}
	else if ( KEY_LOCK_2 && (PIND & KEY_2_PIN)) KEY_LOCK_2 = 0;
	
	
}
	}

ISR ( USART_RX_vect )

{
	
	char ReceivedByte ;
	ReceivedByte = UDR ;
	if (ReceivedByte == PCMidiChannel1)
	{
		return;
	}
	else 
	{
		UDR = ReceivedByte;
	}
	
 
}



void USART_Transmit( unsigned char data ) {
	while ( !( UCSRA & (1<<UDRE)) );
	UDR = data;
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


drakston wrote:
I'm realy beginner programing in C and above example is too complicated to figure out

Then maybe you need to spend some time to build your 'C' skills ?

 

As often said, that can be a whole lot easier on PC than on a small microcontroller - where you have a whole load of added complications to contend with.

 

Or maybe start with a simpler project better suited to your current 'C' skills.

 

still dont now how to ignore more complex 2 or 3 byte data

That is fundamentally about state - ie, not just the byte you receive "now", but also what came before it.

 

That is why state machines are so often suggested - the clue is in the name!

 

Even if you don't call it a "state machine", or use standard "state machine" approaches, you can just approach it as any other programming task.

 

That is not jumping straight into code, but starting with a pencil and paper and drawing-out the process of receiving a certain specific byte first, and then some other particular byte, and then ...

 

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

C is the programming language - solving your problem happens before coding.

 

The first step is to define the problem:

From what I understand, you want to remove certain MIDI messages. This involves detecting a particular message byte and then ignoring the following 'n' bytes. Rinse and repeat.

 

given that the rx interrupt gives us 1 byte at a time, we need to remember what we got previously. This is the concept of 'state'. We exist in only one state at a time.

 

For this we would have two states - the first is looking for the message byte we want to ignore, the second state is to ignore following  'n' bytes. Once we've ignored the required number of bytes, we go back to the first state. And so on. Normally we'd draw a 'state diagram' to visualise this, but I'm lazy and I'd have to find an online tool to do this - usually I just use pen and paper. Nevertheless, for two states, we can skip this step.

 

To put this into simple words, we might do something like this:

 

given a rx byte 'byte':

 

STATE 1:

     IF byte is message to ignore THEN:

              following bytes to ignore = 2

              set next state to STATE 2

              END

    ELSE

             echo byte out

             END

 

STATE 2:

           following bytes to ignore -1

           IF following bytes to ignore is 0 THEN next state is STATE 1

           END

 

 

Now 

convert this to C code:


ISR (USART_RX_VECT)
{
    static uint8_t state = 0; //static because we want it to persist
    static uint8_t bytes_to_ignore = 0;
    
    uint8_t rx_byte = UDR;
    
    switch(state)
        {
            case 0:
                if (rx_byte == PCMidiChannel1)
                    {
                        bytes_to_ignore = 2; //I'm assuming a 3 byte message here
                        state = 1;
                    }
                else
                    {
                        UDR = rx_byte;  //echo
                    }
            break;
            
            case 1: //ignore 'n' bytes
                bytes_to_ignore--;
                if (bytes_to_ignore == 0)
                    {
                        state = 0;
                    }
            break;
        }
    
}

 

Job done. This should get you going.

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Andy snuck in before me!!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I know nothing about midi, but looks like you want to block 0xC1 messages (you do it instead). It seems that a status message has bit7 set, data does not. Set a flag any time you see a 0xC1, then block data until you see another status byte, and if it not another 0xC1 status then turn off blocking. This may not be enough for more complicated items, but you can start somewhere and take advantage of the difference between status and data bytes. Its a mini/micro state machine, but is one nonetheless.

 

The next problem you have, is keeping those transmit bytes 'together'. If your rx is also using the tx, then your 2 bytes could get split up and your message will be scrambled. Maybe there is not enough traffic, so you can just ignore for now and get by, but keep in mind. (In addition, your rx was using udr as tx when in fact it may have been filled up by your other tx- some things to think about)

 

ISR ( USART_RX_vect ){
    static uint8_t blocking_on; //when blocking 193/0xC1/PCMidiChannel1

    uint8_t ReceivedByte ; //!!! this should be unsigned !!!
    ReceivedByte = UDR ;

    //if blocking, and is a data byte (bit7 not set), do not tx
    if( (ReceivedByte < 0x80) && blocking_on ){
        return;
    }   

    //if status byte (bit7 set), and is PCMidiChannel1, turn blocking on
    if( ReceivedByte == PCMidiChannel1 ){
        blocking_on = 1;
        return;
    }

    //must be something wanted if we get here, turn off flag
    blocking_on = 0;
    //and echo (using USART_Transmit so all tx using same function- may be needed later)
    USART_Transmit( ReceivedByte );

}

edit- you may also want to verify midi channel numbers, they seem to be 1 based, so 193/0xC1 is channel2 not channel1. Like I said, I know nothing about midi, so take that into account.

 

edit again- corrected the char/unsigned error in the isr that has been propagating without correction

Last Edited: Sat. Nov 2, 2019 - 09:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think we have an assembler programmer here........

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
ISR ( USART_RX_vect )

{
	
	char ReceivedByte ;
	ReceivedByte = UDR ;
	if (ReceivedByte == PCMidiChannel1)
	{
		return;
	}
	else 
	{
		UDR = ReceivedByte;
	}
	
 
}

Don't write functions with multiple return points - it increases the cyclomatic complexity. This code would have the same behaviour with:

ISR ( USART_RX_vect )

{
	
	char ReceivedByte ;
	ReceivedByte = UDR ;
	if (ReceivedByte != PCMidiChannel1)
	{
		UDR = ReceivedByte;
	}
	
 
}

As shown subsequently, this is not the whole solution but don't get into bad habits like this early.

 

Of course, different programmers have different opinions as seen here: 

 

https://stackoverflow.com/questions/36707/should-a-function-have-only-one-return-statement

 

But ultimately I would tend to be guided by MISRA:

 

https://stackoverflow.com/questions/17177276/c-c-conditional-return-statements/17177315#17177315

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would use whatever method makes it easier to figure out the logic decisions. If an early return helps, ok with me. If inverting the logic eliminates an else, that is good. Using a continue to eliminate a nested if brace, I like it. The less indentation needed, the better. Early returns, continues, breaks, etc., can free up the mind to reason about the logic, as you can eliminate the need to mentally decode anything else beyond the statement you are looking at.

 

I would imagine logic decisions are where a lot of code goes wrong. Once you get past a few decisions in a function, it start to get harder to mentally figure out. See post #4- it may be perfect code, but there is no way to know until you spend a bit of time decoding it all and there still could be problems lurking inside if your mental state took a snooze in the process. Breaking up larger functions into smaller pieces/functions can also help (like in post #7- the key checking code could broken down in ways that do not require you to figure out what a pressed switch state happens to be).

 

I would concentrate on the things that have a real bite to them, like the mixing of signed/unsigned (which I missed, and I guess everyone else did too)-

https://godbolt.org/z/vLaih1

that is the isr as posted in #7

 

since PCMidiChannel1 is an unsigned char, and ReceivedByte is a char, the comparison promotes both to an int- the ReceivedByte is sign extended, the PCMidiChannel1 is 0 extended.

 

if ReceivedByte equals 193 (that's what you are looking for), then the comparison goes something like this-

ReceivedByte = char 193 (0xC1) = -63 = 0xFFC1 (sign extended, still -63)

PCMidiChannel1 = unsigned char 193 = 0xC1 = 0x00C1 (zero extended, still 193)

193 != -63, so will never be true, and the only reason the compiler is going through the motions is PCMidiChannel1 is a data byte, not a define or constant.

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First of all, thank you for your help so far, I will analyze and practice the above suggestions in the morning, but for further conversation, for sure I will be understood well, I will give what else I want to achieve.

defines that if I receive a midi message consisting of 3 bytes,

first byte 10110001, second byte 00000001, third byte 01111111

then I do not want to send it further, but if I receive the message

first byte 10110001, second byte 00000001, third byte 00000001
then forward it.

I hope this is clearer now. As you can see, messages can be from two bytes or three and can almost always be repeated by which individual bytes. Also, as I imagine now, it would have to be a mechanism that receives the first byte, I wait for the second, if it is waiting for the third but I wait for a certain time and if there is no third it compares and decides.

Last Edited: Sat. Nov 2, 2019 - 10:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have a 3 byte rx buffer- 2 buffer bytes + the shift register. Barely adequate, but maybe will work without creating a software buffer. The bytes that were blocked but not a match will have to go out in sequence (so they don't get split up), so tx needs exclusive use during that time. In the meantime, whatever bytes are coming in to rx have nowhere to go except stored in the hardware (3 bytes).

 

A simple example, blocking messages (compiles, may not be all correct)-

https://godbolt.org/z/2xHCIk

all the work is done in the isr since there is no software buffer in use (have to wait on tx in any case). If you start sending messages with your switch presses, then you will have to turn off interrupts while sending since those messages also need exclusive use of tx. Since your inserted messages are only 2 bytes, that should probably work ok.

 

There are problems to work out, and a software buffer may be needed, but you can start simple and work your way up. The above code may not be correct, but can use for ideas.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm:

 

I put the code into the project, removed the key control, I only check your code, the compilation has passed correctly, but unfortunately the code does not work, it practically blocks all messages, sends nothing further. I checked for 2 and 3 byte messages

 

anticipating questions, so electronics circuit is working fine

 

best regards

 

 


#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <stdint.h>	//nowe
#include <stdbool.h>	//nowe
#include <avr/interrupt.h>	//nowe

#define UART_BAUD 31250
#define __UBRR 8000000/16/UART_BAUD-1


//block message struct
typedef struct {
	uint8_t* dataPtr; //pointer to current byte in message
	uint8_t* message; //the message to block
} blockMsg_t;

//am assuming these bytes will never be seen (unused midi value)
#define END_MSG 0xFD  //end of message marker
#define ANY_DATA 0xF9 //any data match wildcard

//a message to block, END_MSG marks end
uint8_t msg1[] = {0xB1, 0x01, 0x07F, END_MSG};
uint8_t msg2[] = {0xC1, ANY_DATA, END_MSG};
//put in the struct that include a 'state' pointer
blockMsg_t Msg1 = { msg1, msg1 };
blockMsg_t Msg2 = { msg2, msg2 };
	
//tx
void USART_Transmit( uint8_t data ) {
	while ( !( UCSRA & (1<<UDRE)) );
	UDR = data;
}

//return value- true = send, false = do not send
//runs inside rx isr
//will take care of sending blocked bytes that were not a full match
bool checkMsg(uint8_t data, blockMsg_t* msg){
	if( *msg->dataPtr == END_MSG ){      //if at message end (done)
		msg->dataPtr = msg->message;     //set pointer to message start
	}
	if( *msg->dataPtr == ANY_DATA ||     //wildcard match
	*msg->dataPtr == data ){         //or byte match
		msg->dataPtr++;                  //advance to next data byte
		return false;                    //do not send
	}
	if( msg->dataPtr == msg->message ){  //no match and no partial match
		return true;                     //send
	}
	//was only partial match, now need to send out the
	//data blocked previously, start at the beginning of message,
	//tx until at current position
	for( uint8_t* p = msg->message; p < msg->dataPtr; USART_Transmit(*p++) );
	msg->dataPtr = msg->message;        //and reset pointer
	return true;                        //send
}

ISR ( USART_RX_vect ){
	uint8_t ReceivedByte ; //unsigned, not char
	ReceivedByte = UDR ;
	// && all messages, if any message blocks, will not get to xmit
	// (they all have to be non-blocking, before can xmit)
	if( checkMsg( ReceivedByte, &Msg1 ) &&
	checkMsg( ReceivedByte, &Msg2 ) ){
		USART_Transmit( ReceivedByte );
	}
}



void USART_Transmit( unsigned char data );

void USART_Init( uint16_t baud ) {
	UBRRH = (uint8_t) (baud>>8);
	UBRRL = (uint8_t)baud;
	UCSRB = (1<<RXEN) | (1<<TXEN);
	UCSRC = (1<<USBS) | (3<<UCSZ0);
}

int main(void)
{

	USART_Init(__UBRR );
	UCSRB |= (1 << RXCIE ); 
	sei (); 
	

	
	while (1) {
}
	}

 

Last Edited: Tue. Nov 5, 2019 - 08:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

>but unfortunately the code does not work

 

They never do work the first time.

 

I'll see what mistakes I made, but step 1 is to eliminate the checking in the rx isr, and just tx everything. If you can echo everything, then at least that is something, if you cannot, then that is something else. Profound wisdom, I know.

 

I also had a buffer version made up, but that is a little more code, and I'm sure could be more broken.

 

I ran this in the simulator-

https://godbolt.org/z/FQBB43

(results at bottom)

using just a buffer of made up midi messages, then 'tx' into another buffer (simulating rx/tx)

seems to be ok at first glance (blocked messages that were to be blocked), but is not using hardware tx/rx so only somewhat validates only the logic.

 

One problem that the ANY_DATA wildcard can cause, is if its used for anything other the the last data byte because otherwise it will be tx when there is no match, and its not actually the missing byte value. Using buffers would allow the ANY_DATA wildcard to be used anywhere as the actual byte would be saved. But you have to walk before you can run.

 

You can even switch over to a pc compiler-

https://godbolt.org/z/aMYwEh

and use printf to track whats going on, just need a web browser

not the hardware it ends up on, but you can get the logic correct that way

 

Last Edited: Wed. Nov 6, 2019 - 01:44 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm wrote:
step 1 is to eliminate the checking in the rx isr, and just tx everything.

Indeed.

 

Probably the single biggest mistake made by beginners is to try to do everything, all at once, in one huge leap - and then say, "it doesn't work".

 

See: https://www.avrfreaks.net/commen...

 

And: https://www.avrfreaks.net/commen...

and: https://www.avrfreaks.net/commen...

 

Key terms:

  • Modular
  • Step-by-Step
  • Design-in debug support
  • Test as you go

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Wed. Nov 6, 2019 - 10:46 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Everyone calm down, the code from my error didn't work, I had to clean up my messages first :)

curtvm: Your first sent code works very well and I am able to send additional messages from the level of the pressed key, so huge compliments and thanks to you for help, for now I am analyzing and understanding this code and playing with small modifications to learn

I will also test the second buffered version. I'll let you know

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

>I will also test the second buffered version

 

Those are tests only, using buffers/arrays as substitutes for rx/tx, so you can use them to test out code that blocks/allows messages (the pc version works better, as you can printf information along the way).

 

 

The actual 'buffered version' is this, I think-

https://godbolt.org/z/4qmdUM

the rx just puts data into its buffer, the main loop removes rx data and checks, if possibly need to block it goes into a midi buffer otherwise straight to the tx buffer. If the message was a complete match the checker code will clear the midi buffer, if a partial match it will move the blocked midi buffer bytes to the tx buffer.

Or something like that. I was just playing around.

 

 

 

 

 

Last Edited: Wed. Nov 6, 2019 - 07:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm :I'm still working on your first code and I don't think I'm still getting it up, I'm trying to add messages that I want to block.
being specific {0xB1, 0x0A, 0x0B} {0xB1, 0x01, 0x7F} {0xC1, 0x01}
what I would like to achieve is the ability to enter any message or several that I want to block. no matter if it has 2 or 3 bytes. It is possible?

Last Edited: Mon. Nov 11, 2019 - 12:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm: I'm still working on your first code and I don't think I'm still getting it up, I'm trying to add messages that I want to block.
being specific {0xB1, 0x0A, 0x0B} {0xB1, 0x01, 0x7F} {0xC1, 0x01}
what I would like to achieve is the ability to enter any message or several that I want to block. no matter if it has 2 or 3 bytes. It is possible?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

>no matter if it has 2 or 3 bytes. It is possible?

 

That code does not depend on the message length, but depends on there being a END_MSG marker.

 

So you just create a byte array with the bytes wanted, along with the END_MSG marker-

//a message to block, END_MSG marks end

uint8_t msg1[] = {0xB1, 0x0A, 0x0B, END_MSG};

uint8_t msg2[] = {0xB1, 0x01, 0x7F, END_MSG};

uint8_t msg3[] = {0xC1, 0x01, END_MSG};

 

create the corresponding blockMsg_t for each-

//put in the struct that include a 'state' pointer

blockMsg_t Msg1 = { msg1, msg1 };

blockMsg_t Msg2 = { msg2, msg2 };

blockMsg_t Msg3 = { msg3, msg3 };

 

and have all of them checked-

if( checkMsg( ReceivedByte, &Msg1 ) &&

    checkMsg( ReceivedByte, &Msg2 ) &&

    checkMsg( ReceivedByte, &Msg3 ) ) {

    USART_Transmit( ReceivedByte );

}

 

 

or, with a little change-

https://godbolt.org/z/PUnvcB

additions at lines 21,52,62

so you can just make one call to check all messages and can make the isr code a little nicer to use

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I check old code and a strange thing is happening. If the arrays are arranged this way

// a message to block, END_MSG marks end
uint8_t msg1 [] = {0xB1, 0x0A, 0x0B, END_MSG};
uint8_t msg2 [] = {0xB1, 0x01, 0x7F, END_MSG};
uint8_t msg3 [] = {0xC1, 0x01, END_MSG};

msg1 is blocked, msg2 is not, msg3 is blocked

if I swap msg1 and 2 as below

uint8_t msg1 [] = {0xB1, 0x01, 0x7F, END_MSG};
uint8_t msg2 [] = {0xB1, 0x0A, 0x0B, END_MSG};
uint8_t msg3 [] = {0xC1, 0x01, END_MSG};

msg1 is blocked, msg2 is not, msg3 is blocked

looks like msg2 was not taken into account at all.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think the code is fatally flawed. What happens to the incoming bytes when a deferred message is being transmitted? The rx interrupt is blocked for this time. I’d suggest an interrupt driven queue for transmit is implemented. Or run a three byte delay on the tx side and have a timer to tickle the machine if there’s a break in the receive.

I’d also suggest running the code on a PC and simulate the midi traffic. Much faster and easier to debug.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
//a message to block, END_MSG marks end
uint8_t msg1[] = {0xB1, 0x0A, 0x0B, END_MSG};
uint8_t msg2[] = {0xB1, 0x01, 0x7F, END_MSG};
uint8_t msg3[] = {0xC1, 0x01, END_MSG};
uint8_t msg4[] = {0xB1, 0x04, 0x7F, END_MSG};

//put in the struct that include a 'state' pointer
blockMsg_t Msg1 = { msg1, msg1};
blockMsg_t Msg2 = { msg2, msg2};
blockMsg_t Msg3 = { msg3, msg3};
blockMsg_t Msg4 = { msg4, msg4};






	if( checkMsg( ReceivedByte, &Msg1 ) &&
		checkMsg( ReceivedByte, &Msg2 ) &&
		checkMsg( ReceivedByte, &Msg3 ) &&
		checkMsg( ReceivedByte, &Msg4 )  ) {
		USART_Transmit( ReceivedByte );

}

 

msg1 and msg3 - block, the rest do not block

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So what happens when they block? Subsequent message(s) get lost. If you can control this, then there's not a problem.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

>msg1 and msg3 - block, the rest do not block

 

The simple example was to get you going with something. The messages are blocked in a way that did not consider overlapping bytes that can match. There is always a solution, it will just require some time and thought. Get out a notebook and a pencil, and figure out something, then apply it to code and test. Repeat until its solved.

 

>I think the code is fatally flawed. What happens to the incoming bytes when a deferred message is being transmitted?

 

that was known going in, but was in the interest of keeping it simple-

>You have a 3 byte rx buffer- 2 buffer bytes + the shift register. Barely adequate, but maybe will work without creating a software buffer.

 

There is later code given with a software buffer, and a version that can be used to troubleshoot the decoding via printf (compiled for pc, so can also printf to the web console output), but I'm not sure I want to be the one to explain all that also.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A modification-

https://godbolt.org/z/mMEdsb

 

and its pc testing counterpart-

https://godbolt.org/z/VMuUZZ

which can be used to test out, with printf's as needed to follow what is happening.

 

Still unbuffered, but any ideas will transfer, as the buffer is mostly to take care of a hardware limitation that depends on the max msg size you want to block . The isr now has its own temp buffer to store blocked bytes, and is in charge of tx any previously blocked bytes that now have to be transmitted.

 

I'm trying to keep code minimal, so it can be understood what is happening. Work your way through it, and reason it out until it makes sense to you. Then come up with something better. It does require time to think through, so if it doesn't work, figure out why, you have all the tools and info needed. Use the printf version, and figure out why/where things go wrong. Not trying to be discouraging, but there really is no easy way out for many things other than to put some work into it.

 

My ideas may be terribly wrong, but the printf version seems to produce the correct results. I probably wouldn't be happy with it if I had to use it, and I'm sure I would eventually settle on something better, but sometimes you just have to lay down some code to get started. Eventually over time it settles down to something good.

 

and this is the next step, add a tx buffer which uses the tx isr-

https://godbolt.org/z/Rc58qg

 

Last Edited: Tue. Nov 12, 2019 - 04:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My MIDI parser code in #4 works well.  Each MIDI-IN byte gets placed into an SRAM buffer.  This buffer has to be about 16 bytes in order to handle MIDI SysEx messages that are often 11 to 15 bytes long.  Most MIDI messages are three bytes: Note ON, Note OFF, Continuous Controller, Aftertouch, and PitchBend.  The parser code determines the size of the message and whether the latest byte is the last byte of the message.  If it is, then the global boolean flag "isMsgRdy" is made TRUE.

 

The main code checks isMsgRdy.  If true, then the main code checks what type of message that it is.  A three byte message will be in msgBufferPtr[0], [1], and [2].  Check these three bytes for being your specific message.  If it is, then retransmit it as is, modify it and retransmit, or block it as needed.  Then clear the various flags, including making isMsgRdy FALSE.  This sets everything up for the next MIDI message.

 

How are you testing this code?  With a MIDI keyboard or workstation?   Note that in MIDI literature, the channels are referred to as Channel One to Channel 16, while the channel number is encoded in the first byte's bits3:0 as 0x0 to 0xF.  So a Continuous Controller value of 0xB1 is considered Channel Two.    Also, most keyboards send a one-byte ActiveSense message (0xFE) every 300 milliseconds.  I've never seen a keyboard where this message can be turned off.   MIDI can also send valid messages where the first byte does not have bit 7 set.  For example, the keyboard can send {0xB1, 0x01, 0x7f  }  and then {0x02, 0x7f} followed by {0x02, 0x7e}.   These are "running status" messages that re-use 0xB1 as the control byte and send only the data bytes until the control byte gets changed again.

 

MIDI messages are complicated to work with, and MIDI files much more complicated than MIDI messages.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

curtvm: from what I can see, this before compilation without buffor on tx works very well and I even start to understand this mechanism more than in the previous example;)

I wonder, however, if i can somehow react to the fact that the program send an unblocked message? in short, if the message was sent, set the variable int to 1 and do something in the loop then.

Only from what I understand, message filtering works in interruption and I can't change the int to which the program will react in the loop?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can communicate between isr code and main code. Its done all the time. You just have to decide what you want to communicate- when a specific message is blocked? when any message is blocked? when a message was not blocked? In other words, what do you want the main loop to know, and what to want the main loop to do in response?

 

You may still end up letting the isr code handle it and still have no need for the main loop to get involved. It just depends on what you actually want to do, and I'm not understanding what that may be.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In addition to what is happening in the ISR, in addition, I have a simple operation of two keys, the active key lights up led but type ws2812. I have a library for handling LEDs which requires sending, for example, such an information frame as below to light specific colors

led [0] .r = 00; LED [0] .g = 00; LED [0] .b = 00;
led [1] .r = 100; LED [1] .g = 00; LED [1] .b = 00;
ws2812_setleds (LED, 2);
_delay_ms (10);

The question is whether it can be done in isr or in a loop. I tried to add a variable that issues "1" when I "allow" messages to be sent and in a loop to read if the variable has 0 or 1 but it doesn't work

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

volatile uint8_t somethingFlag;

 

ISR( SOMETHING ){

  //your code

 

  //something happened, so set flag

  somethingFlag = 1;

}

 

int main(){

  for(;;){

    if( somethingFlag ){

        //clear flag with irq's off, so we don't clear a flag just set again

        sreg = SREG; cli(); somethingFlag = 0; SREG = sreg;

        //now do something

    }

  }

}

 

You cannot do a _delay_ms inside the isr as the delay blocks, and when it blocks, its blocking everything (your rx bytes). 10ms is a long time to be blocking- that's like 30 some bytes of data that can be missed.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The WS2812 has very specific and exacting timing requirements.  Basically for each of the 24 bits (8 red, 8 blue, 8 green) the data line is logic high for 0.4 microseconds, then has either bit high or bit low for 0.4 uS, and ends with logic low for 0.4 microseconds: about 28-30 microseconds per LED for any selected RGB color.  The only way that I've seen AVRs do this reliably is with assembly code embedded in the C library.   If you are not using code specifically for the speed of your AVR, then the WS2812 library that you're using probably won't work.   I suggest that you substitute a normal LED for low-level development work, and then switch to the WS2812.

 

Don't do anything in an interrupt service routine except setting boolean flags and/or very short simple math operations for the main code.   Any IRQ longer than 10 microseconds in length should be reviewed.

 

In the real world, the only way to handle protocol-structured serial input messages of varying lengths like MIDI is to receive the whole message into a buffer, and then examine the components of the message. Edit the message as necessary and then re-transmit it.  The code that you have is convoluted and nearly incomprehensible.  It has no worthwhile comments that explain what exactly that code is doing without forcing the reader/editor/modifier to plow through the actual code line by line.  Code like this may/may not work for one specific MIDI message or sequence, but it is not maintainable or easily changed to meet the needs of another change in the specification.

 

To make the MIDIparse() routine, I first made an elaborate Warnier-Orr diagram using washable/erasable colored markers on a transparent clear plastic cover page sheet.  This diagram had an exact routine for every possible MIDI byte value arriving into the AVR: command, data, and running status.  You want to make code that you are assured will work by covering every possible way that it can fail.  Then simplify and simplify again.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm: thanks for the guidance, I was combining well but I did not know about the need to use volatile, I read why and everything works

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The volatile thing is such an important issue in the use of avr-gcc that they made it #1 in the FAQ in the user manual:

 

https://www.nongnu.org/avr-libc/user-manual/FAQ.html

 

(and also my signature here ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

>the only way to handle protocol-structured serial input messages of varying lengths like MIDI is to receive the whole message into a buffer

 

That is a way, but not sure why it would be the only way. I understood the goal here was to match a message or messages, then drop them from continuing to the next node. I would be more inclined to make the code as generic as possible. It really doesn't matter what protocol is being watched, if n number of bytes match a pattern, drop it, otherwise echo it. If you can pin down the messages of interest into a specific group of bytes, it hardly matters what the underlying protocol may be so no need to decipher it. The bytes go out faster as you do not need to wait till the end of a message to find out you will not be blocking it, and the bonus is you do not need to decipher any protocol.

 

The same code could block all incoming "Hello World"'s because it doesn't rely on anything but byte matching. The code is generic enough to do other things, and if there is protocol errors coming in, no need to handle them as we are not in the protocol business- send them out if no match, not our problem.

 

 

Last Edited: Thu. Nov 14, 2019 - 06:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You almost certainly need to actually identify the messages, because otherwise, the three bytes you're looking for could occur elsewhere in messages. (For instance, it's possible that some valid message which isn't related to what you're doing could contain those three bytes, but it's also possible that it could end with two of them and the next message could start with the third.)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

>You almost certainly need to actually identify the messages, because otherwise, the three bytes you're looking for could occur elsewhere in messages.

 

The data bytes do not have bit7 set, the status bytes do. Every message starts with a status byte followed by some data bytes. If you have a valid match rule, you cannot match anything other than a valid message since data and status bytes are in a separate range of values. So no, you do not have to identify incoming messages.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Huh, that's fascinating. Is that true even for sysex data dumps, etc?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm not a midi expert, but if they started to use status bytes as data bytes, all their previously crafted plans go out the window. That plan I assume was to keep status and data bytes separate so all bytes carried state information with them- if you get a little confused or lost or just joined the conversation, you just have to look for the next status byte and begin/start over.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0