What is the difference between ... (a few things)

I apologize in advance because I feel this is going to be a long one. @profezzorn , if you only feel like replying to one a day (or even less/more days), it’s fine. I am not going anywhere and I would like to learn so I can create (hopefully) some fun prop files.

I have a few “What is the difference” questions:

  1. The first one is about error reporting.
    I assume these all send some “text” to the serial monitor? Do some send errors to OLED?
    I also assume that ln is for “line new” or “next line” but what is the difference between print("some_text\n") & println("some_text"), I am thinking flash memory usage ? Or when do I choose one over the other ?
    I believe that some of them will only show/hide the “text” depending on wether #define DISABLE_DIAGNOSTIC_COMMANDS and/or #define ENABLE_DEBUG is defined or not, but which one for which define ?
Serial.println("Dual Push Detected");
PVLOG_NORMAL.print("Maximum Volume \n");
PVLOG_NORMAL << "** Entering ProffieOS Menu System\n";
PVLOG_DEBUG << "** STOPPING timer.\n";
PVLOG_VERBOSE << "The Force will be with you...always.\n";
PVLOG_STATUS << "Blade Detected\n";
STDOUT << "Turning off " << location << "\n";
STDOUT.print("Minimum Volume \n");
STDOUT.println(battery_monitor.battery_percent())
STDERR << "Unknown variable source: " << variable_source << "\n";

Are there other error reporting ways that I should/could know about?

  1. Some error messages in @NoSloppy 's props start with "**", "***", "****", "*****" Do the different multiple of “*” mean something ?

That is it for errors reporting, but the following have been brewing in my mind for some time.

  1. What is the difference between these:
hybrid_font.PlayPolyphonic(&SFX_sound_name);
hybrid_font.PlayPolyphonic(SFX_sound_name);
//but no "&" before SFX, I can't find where I saw it anymore, but I know it was in official ProffieOS files, or did I dream it? What is "&" for ?
hybrid_font.PlayCommon(&SFX_sound_name); // this one I only noticed today as I was writing 1) above.
  1. Event & Event2 most props have all of the “action” happening in Event2. I only found 2 that have something in Event (SaberBlasterProp from dual_prop.h & micom.h - of course multi_prop.h as well, since it was based on SaberBlasterProp). I was under the impression that the bulk of the “action” would be under Event, Event2 would be for the “exception”, I guess it is just the opposite?

  2. Last one is about effect location. I understand that location is whether or not the effect will show on the blade(s), but what are the different values that location can have and what does those values mean ?

As always, thank you for reading so far & thank you for you time and dedication.

    • None of these print anything to the OLED. Only calls in common/error.h do that.
    • Generally speaking print / println the Arduino api for printing things, it’s well supported in all arduino code, but usually requires many lines of code to print something.
    • println() is just print, with an newline printed afterwards. The actual effect of print(“foo\n”) and println(“foo”) is the same. println(“foo”) saves one byte. For non-constant strings, picking the right one makes the code shorter.
    • SOME_OUTPUT << THING_YOU_WANT_TO_PRINT << “\n” is ProffieOS style, and it’s also similar to how you normally print things in C++ (Although it’s not based on cout, so it’s not exactly the same.) Using << this way generally ends up calling print eventually, the only advantage is that it’s simple to put multiple things to print on one line, like: PVLOG_NORMAL << "Milliseconds: " << millis_ << " some_variable=" << some_variable << "\n";
    • PVLOG_STATUS/NORMAL/DEBUG/VERBOSE correspond to different debug levels. You can use PVLOG_DEBUG_LEVEL to control how much information proffieOS will print out. You can also change this define for some section of the code if you want to debug that code more. ENABLE_DEBUG and DISABLE_DIAGNOSTIC_COMMANDS have no effect on PVLOG_DEBUG_LEVEL. The default debug level is 300. You can see the actual limits here: ProffieOS/common/stdout.h at ed595f7a419388277e54eea942d78c9c424e58c9 · profezzorn/ProffieOS · GitHub
    • If you use ENABLE_SERIAL, it will get output that used STDOUT, but not anything that uses STDERR. STDERR are meant for async messages, STDOUT is meant for messages which are in respons to a command.
  1. no

  2. hybrid_font.PlayPolyphonic(SFX_sound_name); This is not valid code. PlayCommon is used for sounds that share a filename in monophonic and polyphonic fonts. PlayCommon will decide how to play it based on whether the rest of the font seems to be monophonic or polyphonic.

  3. Event is meant for sound. Event2 is meant for other actions. By making sure that the sound is started before the action, the action can use the length of the sound to determine what kind of effect to play, and for how long.

  4. The intent was to have some piece of code determine the location where the event happened. Particularly for a clash this would be where on the blade the clash occurred. (0=at the hilt, 1=tip of blade) However, this has never come to fruition, and since most people use “reactive” effects nowadays which ignores the location, it is not likely to ever happen. In OS8 location was extended to specify which blade something happened on, which turns out to be more useful. (If you have more than one actual blade.) In particular, it allows you to turn on and off blades individually, as seen in Phantom Meanace.

1 Like

This is just for me so I can see more easily messages that come from my prop as opposed to standard system messages. When there’s a lot of printouts things can get lost so that helps.

1 Like

What you’ve seen is this with and without the ampersand. Like


If (SFX_sound_name) {
hybrid_font.PlayPolyphonic(&SFX_sound_name);
}
``
The if checks if the pointer is nullptr or not (meaning whether such sound exists) 
The second instance with an ampersand means get the specific address of the sound and play it with PlayPolyphonic().
1 Like

Ok, I only have one word: WAW! I am in total admiration of your knowledge.
That made me speechless, which is a rare occurrence.
It took me “a minute” to compose my thoughts.
You guys are so great. I know I have more questions but it will take me more than “a minute” to put them in written words and even longer to fully “digest” all that information. Now it’s bed time so I speak me tomorrow.

Have a great end of day & a good night.

Just one before I sleep: what is “cout” ?

std::cout is for “character out” and is the c++stdlib’s response to printing characters to (almost always) the console.

A quick google search for that should give you a wealth of hits :slight_smile:

1 Like

Look up “Taking memory address of variable” for C++.

Basically, it creates a pointer from a variable which points to the variable’s memory.

References are cooler since they can’t be null and mean the & isn’t needed, but you can’t null them which is sometimes desirable, which I assume is why profezzorn is using pointers here.

1 Like

References are pointers, but hidden.
That doesn’t make them cooler, it makes the code harder to read.
They have their uses, but in general I prefer const references and pointers for just about everything else.

Yes, but they’re non-nullable (without trying), and with a bit of help from an LSP to indicate mutability (I personally have my stuff setup so that variables are italicized when they’re passed to a function which can mutate them, pointer or reference), they’re much more convenient in my opinion.

A matter of taste I suppose, but when they can be used I prefer them.

It’s never not clear when a reference is in use when I’m programming, so I feel the idea of them being “hidden” and harder to read a bit disingenuous.

If everywhere that C++ code is displayed worked like that, I might change my mind.

… maybe

Everywhere C++ is displayed that I handle it works like that :crazy_face:

  1. a) So is Serial.println(“some_text”), the one that uses the least amount of flash memory for a constant string ?
    1b) ENABLE_DEBUG and DISABLE_DIAGNOSTIC_COMMANDS, sorry I meant ENABLE_DEVELOPER_COMMANDS, do what exactly ?

  2. ok

  3. So PlayCommon is more versatile but does it take more memory ?

  4. I guess, I can change everything around since I got it reversed. :upside_down_face:

  5. What do you use when there is no location like a “talking” menu or a “mode” change or you just want nothing to happen on a blade when a sound is played or is that when you put the effect in Event instead of in Event2 ? Edit: Sorry, I am getting confused, I was mixing Event & Effect. But the question still remains, how to program an effect that won’t have a location on the blade ?

Yes that must what I saw. And hybrid_font.PlayCommon also uses (&sound_name)
with an ampersand, correct ?

And I thought it was a typing error! :roll_eyes:

Thank you all for all this information.

Just use 0.

Yes.

1 Like

Yes, but you shouldn’t print to Serial, because that won’t work with actual serial ports. Using PVLOG is potentially even more memory-efficient, because PVLOG outputs that fall below the PVLOG_DEBUG_LEVEL use no memory at all.

This define is primarily for me. It enables additional code that checks the integrity of linked lists and other similar things.

No.
PlayCommon applies a set of rules that are specific to sounds that exists in mophononic and polyphonic fonts. If you want those rules, you use PlayCommon. There is no difference in the amount of memory. The memory cost has already been paid by other things that call this function. Only by removing all calls to PlayCommon could you get that memory back.

Just set the location to 0.

1 Like

The “fall below” I do not understand what that means or which level to choose.
I will give you an example from multi_prop:

//some code here
// Check if both buttons are pressed simultaneously or near-simultaneously
if (powerPressed_ && auxPressed_ && holdStartTime == 0) {
holdStartTime = millis();    // Start the hold timer when both buttons are pressed
STDOUT.println("Dual Long Push Initiated."); //lets call it "message1"
}
// more code here
if (!powerPressed_ || !auxPressed_) {
holdStartTime = 0;
STDOUT.println("One of the two (or both) button(s) was (were) released too early!"); //lets call it "message2"
}
// a bit more code here
if (powerPressed_ && auxPressed_ && (millis() - holdStartTime) >= TWO_BUTTONS_X_LONG_PUSH) {
switchModes(this); // Pass "this" MultiProp instance to switchModes & switch the prop mode
STDOUT.println("Both buttons were held long enough for MultiProp to switch to the next Prop_Mode."); // & "message3"
return true;

When I will be testing multi_prop.h, I want to see in serial monitor message 1&2 if both buttons where not held long enough, message 1&3 if both buttons where held long enough & and no messages if only one or no button was pushed. So will these:

PVLOG_DEBUG << "Dual Long Push Initiated." << "\n";
PVLOG_DEBUG << "One of the two (or both) button(s) was (were) released too early!" << "\n";
PVLOG_DEBUG << "Both buttons were held long enough for MultiProp to switch to the next Prop_Mode." << "\n";

achieve this ?
Once I know it is working the way I intended, I can comment them out to save more memory.

“By default, some commands which are only useful for developers are normally not compiled into the final binary to save memory, if you want them, add this define to enable them” Yes I have read that, but it is a bit “thin” to understand what would be “gained” if it was defined. Or is it another one of those

I converted my PlayPolyphonic to PlayCommon in jetpack_prop.h and got errors like this:

C:\ProffieOS\props\jetpack_prop.h: In member function 'void Jetpack::VolumeUp()':
C:\ProffieOS\props\jetpack_prop.h:155:36: error: could not convert 'hybrid_font.HybridFont::PlayCommon((& SFX_volup))' from 'void' to 'bool'
  155 |         if (!hybrid_font.PlayCommon(&SFX_volup)) beeper.Beep(0.5, 2000);
      |              ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
      |                                    |
      |                                    void
C:\ProffieOS\props\jetpack_prop.h:155:47: error: in argument to unary !
  155 |         if (!hybrid_font.PlayCommon(&SFX_volup)) beeper.Beep(0.5, 2000);
      |                                               ^

I reverted back to PlayPolyphonic and the problem went away. Which is not exactly a fix but rather a workaround. Is there any “right way” I can do to use PlayCommon when using the commonly (in many props but not in “main POS” ../sound/effect.h) used effects:

EFFECT(dim);        // for EFFECT_POWERSAVE
EFFECT(volup);      // for increase volume
EFFECT(voldown);    // for decrease volume
EFFECT(volmin);     // for minimum volume reached
EFFECT(volmax);     // for maximum volume reached
EFFECT(vmbegin);    // for Begin Volume Menu
EFFECT(vmend);      // for End Volume Menu
EFFECT(battery);    // for EFFECT_BATTERY_LEVEL

And not wanting to add the kitchen sink to the mix, but is there a less convoluted way to avoid “double declaration” of effects than what I came up with:

 // == sounds for system ==
#ifndef PROPS_SABER_FETT263_BUTTONS_H
EFFECT(dim);      // for EFFECT_POWERSAVE
#endif
#ifndef PROPS_SABER_SA22C_BUTTONS_H
  #ifndef PROPS_SABER_BC_BUTTONS_H
    #ifndef PROPS_BLASTER_BC_BUTTONS_H
    EFFECT(volup);      // for increase volume
    EFFECT(voldown);    // for decrease volume
    EFFECT(volmin);     // for minimum volume reached
    EFFECT(volmax);     // for maximum volume reached
    #endif
    #ifndef PROPS_SABER_FETT263_BUTTONS_H
      EFFECT(vmbegin);    // for Begin Volume Menu
      EFFECT(vmend);      // for End Volume Menu
      #if !defined(PROPS_SABER_SHTOK_BUTTONS_H) && !defined(PROPS_BLASTER_BC_BUTTONS_H)
        EFFECT(battery);    // for EFFECT_BATTERY_LEVEL
      #endif
    #endif
  #endif
#endif

I am hoping there is something equivalent to #ifndef ... #endif for EFFECT(sound_name), because I would like to be able to add even more props to the mix (like saber_sabersense_buttons.h for example) that also use the same effects but it is becoming very complicated real fast.

As always, thank you for ready so far. MTFBWYA

The link I posted to earlier leads to this this:

#define PVLOG_ERROR   PVLOG(100)
#define PVLOG_STATUS  PVLOG(200)
#define PVLOG_NORMAL  PVLOG(300)
#define PVLOG_DEBUG   PVLOG(400)
#define PVLOG_VERBOSE PVLOG(500)

These numbers here are the actual levels compared to PVLOG_DEBUG_LEVEL. So if PVLOG_DEBUG_LEVEL is 200, then only PVLOG_ERROR and PLOG_STATUS will be shown, the others will be ignored.

Yes.

The point of PVLOG is that you don’t have to comment them out. You can just change the log level instead.

Yes.

I guess PlayCommon doesn’t return a bool like PlayPolyphonic does.

I’m afraid I don’t have a good way to do this.

1 Like

@olivierflying747-8 This is what I leave in all my config files and adjust per/upload depending on if I’m testing or whatever:

   // PVLOG_ERROR 100 = errors
   // PVLOG_STATUS 200 = things you should probably know, like blade ID
   // PVLOG_NORMAL 300 = normal information about what is happening (default level)
   // PVLOG_DEBUG 400 = information helpful for debugging
   // PVLOG_VERBOSE 500 = repeated, spammy information you don't normally want
 #define PROFFIEOS_LOG_LEVEL 400

Here I have debugging level set.

1 Like

Ok, now I understand how it works. You define a level and everything at or below that level will show.

That’s too bad (for me :cry:). I know how it can be done on “my” ProffieOS:

  • Add them all to my `…/sound/effect.h"
  • Remove them all from the other props

And voilà, no more double defined to worry about. I guess it is not done in the official ProffieOS due to adding to memory usage, even though they are used in official props?

How about adding a new define in/for sound/effect.h:

// in our config:
#define ADD_ADDITIONAL_EFFECTS //would be off by default
// in sound/effect.h
#ifdef  ADD_ADDITIONAL_EFFECTS
EFFECT(dim);      // for EFFECT_POWERSAVE
EFFECT(battery);  // for EFFECT_BATTERY_LEVEL
EFFECT(bmbegin);  // for Begin Battle Mode
EFFECT(bmend);    // for End Battle Mode
EFFECT(vmbegin);  // for Begin Volume Menu
EFFECT(vmend);    // for End Volume Menu
EFFECT(volup);    // for increse volume
EFFECT(voldown);  // for decrease volume
EFFECT(volmin);   // for minimum volume reached
EFFECT(volmax);   // for maximum volume reached
EFFECT(faston);   // for EFFECT_FAST_ON
EFFECT(blstbgn);  // for Begin Multi-Blast
EFFECT(blstend);  // for End Multi-Blast
EFFECT(push);     // for Force Push gesture in Battle Mode
#endif
// and in the props:
#ifdnef  ADD_ADDITIONAL_EFFECTS
// only add the ones needed in the prop
#endif

This would allow for backward compatibility: users that only use one prop don’t need to change anything in their config(s), users that already use dual_prop.h also don’t need to change anything, and users who want to “adopt” multi_prop.h would already need to change their CONFIG_PROP, they would also need to add in their CONFIG_TOP #define ADD_ADDITIONAL_EFFECTS

Off course, I would need prop makers and obviously also you @profezzorn, to be on board with that change ?

I’m not a big fan of this approach, hopefully we can think of a better way to do it.

For now, I would probably just change it like this:

#ifdef PROPS_SABER_SA22C_BUTTONS_H
#define HAVE_VOLUP
#define HAVE_VOLDOWN
#define HAVE_VOLMIN
#define HAVE_VOLMAX
#endif

#ifdef PROPS_SABER_FETT263_BUTTONS_H
#define HAVE_VOLUP
#define HAVE_VOLDOWN
#define HAVE_VOLMIN
#define HAVE_VOLMAX
#define HAVE_VMBEGIN
#define HAVE_VMEND
#endif

#ifndef HAVE_VOLUP
EFFECT(volup);
#endif

#ifndef HAVE_VOLDOWN
EFFECT(voldown);
#endif

The idea is that each section lists exactly which effects already exists in that prop and should be relatively quick and easy to check and update. It’s actually longer than what you have currently, but it should be a lot easier to maintain.

1 Like