Notifications
Clear all

[Solved] Need a tiny bit of C++ help

Page 1 / 2

Ron
 Ron
(@zander)
Noble Member
Joined: 1 year ago
Posts: 1824
Topic starter  

I never learned C++ as it wasn't a compiler on my hardware platform.

I have a sketch that reads a button press. I then want to programmatically (NO GUI) manipulate an Arduino Cloud Schedule object (.h file below) to perform a 'OneShot'(found that in the .h) timer/timeout/alarm of upto 60 minutes. ALL my use cases are minutes no more than 60, I might even limit it to 59 so I only need to mess with the minutes field/property/method.

There will be a total of 4 CloudSchedule widgets/objects and I want to re-use them if possible hence the oneshot property/method/attribute.

I am aware there may be an issue after 2300 but ignore that case, I will sort that out if it becomes an issue.

The code to be executed when the schedule event/alarm fires is prvided via a callback auto generated by the cloud and inserted in my code ready for me to add a single bool to indicate the alarm went off.

The .h file is big, so the entire file is included as an attachment but what I think (I do read C) is relevant is inline below here. 


#include <Arduino.h>
#include "../Property.h"
#include "../../AIoTC_Const.h"
#include "utility/time/TimeService.h"
#include <time.h>

#define SCHEDULE_UNIT_MASK    0xC0000000
#define SCHEDULE_UNIT_SHIFT   30

#define SCHEDULE_TYPE_MASK    0x3C000000
#define SCHEDULE_TYPE_SHIFT   26

#define SCHEDULE_MONTH_MASK   0x0000FF00
#define SCHEDULE_MONTH_SHIFT  8

#define SCHEDULE_REP_MASK     0x03FFFFFF
#define SCHEDULE_WEEK_MASK    0x000000FF
#define SCHEDULE_DAY_MASK     0x000000FF

#define SCHEDULE_ONE_SHOT     0xFFFFFFFF

enum class ScheduleUnit : int {
  Seconds      = 0,
  Minutes      = 1,
  Hours        = 2,
  Days         = 3
};

enum class ScheduleType : int {
  OneShot      = 0,
  FixedDelta   = 1,
  Weekly       = 2,
  Monthly      = 3,
  Yearly       = 4
};

enum class ScheduleMonth : int {
  Jan          = 0,
  Feb          = 1,
  Mar          = 2,
  Apr          = 3,
  May          = 4,
  Jun          = 5,
  Jul          = 6,
  Aug          = 7,
  Sep          = 8,
  Oct          = 9,
  Nov          = 10,
  Dec          = 11
};

enum class ScheduleWeekDay : int {
  Sun          = 0,
  Mon          = 1,
  Tue          = 2,
  Wed          = 3,
  Thu          = 4,
  Fri          = 5,
  Sat          = 6
};

enum class ScheduleState : int {
  Inactive     = 0,
  Active       = 1
};

/******************************************************************************
 * TYPEDEF
 ***************************************************************************/
typedef struct ScheduleWeeklyMask {
  ScheduleStateoperator[](ScheduleWeekDay i) { return day[static_cast<int>(i)];}
  ScheduleState day[7];
}ScheduleWeeklyMask;

typedef unsigned int ScheduleTimeType;
typedef unsigned int ScheduleConfigurationType;

/************************************************************************
   CLASS DECLARATION
 ***************************************************************************/
class Schedule {
  public:
    ScheduleTimeType frmtolenmsk;
    Schedule(ScheduleTimeType sScheduleTimeType eScheduleTimeType dScheduleConfigurationType m): frm(s), to(e), len(d), msk(m) {}

    bool isActive() {

      ScheduleTimeType now = _schedule_time_service.getLocalTime();

      if(checkTimeValid(now)) {
        /* We have to wait RTC configuration and Timezone setting from the cloud */

        if(checkSchedulePeriod(nowfrmto)) {
          /* We are in the schedule range */

          if(checkScheduleMask(nowmsk)) {

            /* We can assume now that the schedule is always repeating with fixed delta */
            ScheduleTimeType delta = getScheduleDelta(msk);
            if ( ( (std::max(now , frm) - std::min(now , frm)) % delta ) <= len ) {
              return true;
            }
          }
        }
      }
      return false;
    }

    static ScheduleConfigurationType createOneShotScheduleConfiguration() {
      return 0;
    }

    static ScheduleConfigurationType createFixedDeltaScheduleConfiguration(ScheduleUnit unitunsigned int delta) {
      int temp_unit = static_cast<int>(unit);
      int temp_type = static_cast<int>(ScheduleType::FixedDelta);
      unsigned int temp_delta = delta;

      if (temp_delta > SCHEDULE_REP_MASK) {
        temp_delta = SCHEDULE_REP_MASK;
      }
      return (temp_unit << SCHEDULE_UNIT_SHIFT) | (temp_type << SCHEDULE_TYPE_SHIFT) | temp_delta;
    }

    static ScheduleConfigurationType createWeeklyScheduleConfiguration(ScheduleWeeklyMask weekMask) {
      unsigned int temp_week = 0;
      int temp_type = static_cast<int>(ScheduleType::Weekly);

      for(int i = 0i<7i++) {
        if(weekMask[static_cast<ScheduleWeekDay>(i)] == ScheduleState::Active) {
          temp_week |= 1 << i;
        }
      }
      return (temp_type << SCHEDULE_TYPE_SHIFT) | temp_week;
    }

    static ScheduleConfigurationType createMonthlyScheduleConfiguration(int dayOfTheMonth) {
      int temp_day = dayOfTheMonth;
      int temp_type = static_cast<int>(ScheduleType::Monthly);

      if(temp_day < 1) {
        temp_day = 1;
      }

      if(temp_day > 31) {
        temp_day = 31;
      }
      return (temp_type << SCHEDULE_TYPE_SHIFT) | temp_day;
    }

    static ScheduleConfigurationType createYearlyScheduleConfiguration(ScheduleMonth monthint dayOfTheMonth) {
      unsigned int temp_day = createMonthlyScheduleConfiguration(dayOfTheMonth);
      int temp_month = static_cast<int>(month);
      int temp_type = static_cast<int>(ScheduleType::Yearly);

      return (temp_type << SCHEDULE_TYPE_SHIFT) | (temp_month << SCHEDULE_MONTH_SHIFT)| temp_day;
    }

    Scheduleoperator=(Schedule & aSchedule) {
      frm = aSchedule.frm;
      to  = aSchedule.to;
      len = aSchedule.len;
      msk = aSchedule.msk;
      return *this;
    }

    bool operator==(Schedule & aSchedule) {
      return frm == aSchedule.frm && to == aSchedule.to && len == aSchedule.len && msk == aSchedule.msk;
    }

    bool operator!=(Schedule & aSchedule) {
      return !(operator==(aSchedule));
    }

 The entire .h file is attached below

 

It is considered poor judgement to traverse a chasm in 2 leaps.


Quote
Eliza
(@eliza)
Eminent Member
Joined: 3 months ago
Posts: 36
 

Hi Ron, I see the class. What problem are you trying to solve? There's no main. (or loop if this will run in an Arduino)


ReplyQuote
Ron
 Ron
(@zander)
Noble Member
Joined: 1 year ago
Posts: 1824
Topic starter  

@eliza As I said,

I have a sketch that reads a button press. I then want to programmatically (NO GUI) manipulate an Arduino Cloud Schedule object to perform a 'OneShot'(found that in the .h) timer/timeout/alarm of up to 60 minutes. ALL my use cases are minutes no more than 60, I might even limit it to 59 so I only need to mess with the minutes field/property/method.

There is no main/loop because I don't know how to do it hence the question. 

In pseudo code I suspect it will be 

scedobj1.oneshot = true

scedobj1.min = 60

start ???

 

It is considered poor judgement to traverse a chasm in 2 leaps.


ReplyQuote
Eliza
(@eliza)
Eminent Member
Joined: 3 months ago
Posts: 36
 

You have to declare an object of the Schedule type in the global scope of your sketch (outside and before setup and loop) using the parameters shown in the prototype of the constructor:

myScheduleNewScheduleObject = Schedule( timeTypeThingHere, anotherTimeTypeThingHere .... )

Once you have that object declared/instantiated you can use any of the methods in the object. So your call would apparently be something like:

if( buttonPressed) {

  mySchedule.createOneShotScheduleConfiguration();

}

but the method shown here is clearly a do nothing method. It just returns zero. Are you supposed to override this method? Are we trying to figure out how to program the createOneShotScheduleConfiguration code?

From the typedef statement, a one shot type is indeed a zero. The enum typedef statement means nothing more than "What I'm calling a ScheduleType is what you call an integer" 

Is any of this helpful?


ReplyQuote
Ron
 Ron
(@zander)
Noble Member
Joined: 1 year ago
Posts: 1824
Topic starter  

@eliza Not helpful. I have a rough idea how to do a constructor, what I need to understand is how to set up the one shot. I see it in several different places including a #define mask. I also have to figure out what method will substitute for a device press. The common use case (NOT ME) is to spin a dial or whatever to dial in a alarm time and then 'start' the timer. I don't want to use a gui, just a button press. I am going to grab another board and set up a sketch with only the CloudSchedule object and start poking around. Thanks for looking.

It is considered poor judgement to traverse a chasm in 2 leaps.


ReplyQuote
frogandtoad
(@frogandtoad)
Noble Member
Joined: 3 years ago
Posts: 1133
 

@zander

Posted by: @zander

@eliza Not helpful. I have a rough idea how to do a constructor, what I need to understand is how to set up the one shot. I see it in several different places including a #define mask. I also have to figure out what method will substitute for a device press. The common use case (NOT ME) is to spin a dial or whatever to dial in a alarm time and then 'start' the timer. I don't want to use a gui, just a button press. I am going to grab another board and set up a sketch with only the CloudSchedule object and start poking around. Thanks for looking.

Hi Ron,

I think the information @eliza provided is helpful, but it does require some knowledge of classes.  The only thing I would add to his response at this time, is that I think he has chosen the wrong class to instantiate, as looking through the code in the file you provided, the 'Schedule' class is declared inside of the 'CloudSchedule' class, so it appears that you have to instantiate a 'CloudSchedule' type, and then invoke any methods of the 'Schedule' object through that 'CloudSchedule' object instead.

Here is the code to show the relevant part for initialization:

class CloudSchedule : public Property {
  private:
    Schedule _value,
             _cloud_value;
  public:
    CloudSchedule() : _value(0, 0, 0, 0), _cloud_value(0, 0, 0, 0) {}
    
    CloudSchedule(unsigned int frm, unsigned int to, unsigned int len, unsigned int msk) 
      : _value(frm, to, len, msk), _cloud_value(frm, to, len, msk) {}

 [snip]

So, to create a variable of 'CloudSchedule', it can be performed in a couple of different ways.

1) - Using the default constructor (where all variables internally are initialized to zero's):

 CloudSchedule mySchedule();

 2) - Using the overloaded (custom) constructor (where all variables internally are initialized to the values we enter as desired):

 CloudSchedule mySchedule(from, to, duration, one_shot_mask);

Hopefully this makes it a little more clear on how to go about it... please ask further questions if still not clear.

I have to run as having some visitors over soon, but I'll check back latter tonight.  In the mean time, my suggestion is to actually create a schedule via the GUI first, and then take a look at any generated code from there to see if there is something similar.

Cheers


Ron and Inst-Tech liked
ReplyQuote
Ron
 Ron
(@zander)
Noble Member
Joined: 1 year ago
Posts: 1824
Topic starter  

@frogandtoad I will be creating a new 'Thing' today with just one widget of the class CloudSchedule. I will be pleasantly surprised if the generated code is ay more than the normal On[object name]Change procedure with NO code is generated.

 

Here is what got generated. I will try google again today to see if there is any documentation available, maybe I missed it the first time I looked.

/*
Since TestSched is READ_WRITE variable, onTestSchedChange() is
executed every time a new value is received from IoT Cloud.
*/
void onTestSchedChange() {
// Add your code here to act upon TestSched change
}

It is considered poor judgement to traverse a chasm in 2 leaps.


ReplyQuote
byron
(@byron)
Prominent Member
Joined: 3 years ago
Posts: 855
 

@zander

The sun is out and its getting quite toasty outside so its time for a cuppa, check the emails et al, and to see what Ron is up to. 😎    

Too much reading to really understand what your issues are, but I think its all to do with schedule events generated by the Arduino cloud and there are not enough of them so you wish to reassign the code to run once a particular scheduler alarm event is received.

I which case, in your local code, just let the scheduler callback set a flag when triggered.  Have another set of flags to indicate the currently assign procedure to run, and poll the flags to see when its changed, run the currently assigned procedure, reassigning the currently assigned procedure as necessary.

The heat of the afternoon is making me soporific and no need to reply with gory details.  Maybe your 'oneshots' are the answer you seek but .... Zzzzzzz


ReplyQuote
Ron
 Ron
(@zander)
Noble Member
Joined: 1 year ago
Posts: 1824
Topic starter  

@byron Thanks Byron, but the event handling is the easy part, what I am looking for is how to programmatically create a oneshot event of x mins.

Since I don't know C++ and I suspect the syntax is important I am looking for the C++ equivalent of

create an even of type oneshot

set the event to timeout in 30 minutes

 

It is considered poor judgement to traverse a chasm in 2 leaps.


ReplyQuote
Ron
 Ron
(@zander)
Noble Member
Joined: 1 year ago
Posts: 1824
Topic starter  

I figured it out myself. 

It is considered poor judgement to traverse a chasm in 2 leaps.


frogandtoad and Will liked
ReplyQuote
frogandtoad
(@frogandtoad)
Noble Member
Joined: 3 years ago
Posts: 1133
 

@zander

Posted by: @zander

I figured it out myself. 

Great to hear!

I just created an account, installed the agent, and started screwing around with it.

I created a variable named: "mySchedule" of type "Schedule" from the drop down list, and it did actually create a variable in the "thingProperties.h" file called: "CloudSchedule mySchedule", just as expected.

Can you please let us know how you resolved your issue?

I'd be interested to know if you used this variable or if you used something else entirely.

Cheers


ReplyQuote
Ron
 Ron
(@zander)
Noble Member
Joined: 1 year ago
Posts: 1824
Topic starter  

@frogandtoad Actually I am a little embarrassed I asked the question before I checked but all I did was look at the header file I had posted to see class variables that sounded pertinent then I found an example sketch to do with Schedules. It didn't take long to see what I wanted could likely be done so I 'borrowed' the sample code, stripped it down to the bare essentials and set up another board to test on. The biggest challenge was discovering what function to use to get the current time. It looks like it changes depending on if you are in the cloud environment or not. Until I put the code into the cloud properly the time started at 0, once I fixed that it worked sortof. The callback fires once sometimes during initialization but does not fire when the timeout ends so I just poll the isActive property. It's inelegant, but gets the job done and those boards are going to loop anyway so I am slowly coming to grips with code that loops instead of interrupt driven as I am used to.

I probably won't get a chance to work on it today and not sure about the rest of the week, between visitors, Dentist, and Doctor I have a busy week but this problem is solved as far as I am concerned.

Thanks for asking.

It is considered poor judgement to traverse a chasm in 2 leaps.


ReplyQuote
frogandtoad
(@frogandtoad)
Noble Member
Joined: 3 years ago
Posts: 1133
 

@zander

Posted by: @zander

@frogandtoad Actually I am a little embarrassed I asked the question before I checked but all I did was look at the header file I had posted to see class variables that sounded pertinent then I found an example sketch to do with Schedules. It didn't take long to see what I wanted could likely be done so I 'borrowed' the sample code, stripped it down to the bare essentials and set up another board to test on. The biggest challenge was discovering what function to use to get the current time. It looks like it changes depending on if you are in the cloud environment or not. Until I put the code into the cloud properly the time started at 0, once I fixed that it worked sortof. The callback fires once sometimes during initialization but does not fire when the timeout ends so I just poll the isActive property. It's inelegant, but gets the job done and those boards are going to loop anyway so I am slowly coming to grips with code that loops instead of interrupt driven as I am used to.

I probably won't get a chance to work on it today and not sure about the rest of the week, between visitors, Dentist, and Doctor I have a busy week but this problem is solved as far as I am concerned.

Thanks for asking.

No worries.

One question I have however, is where did you get the "CloudSchedule.h" file to begin with?

It is not included with any schedule variable I created, nor have I seen any documentation regarding it?

Cheers


ReplyQuote
Ron
 Ron
(@zander)
Noble Member
Joined: 1 year ago
Posts: 1824
Topic starter  

@frogandtoad I often use the Mac search tool to look for files (may be more powerful than windows, but try terminal then find on Win. Use man find for reams of doc'n. Yup, Win does *nix now, for a while) and found it.

Documentation is a sore point. I asked here, and on the arduino forum with almost no responses, I actually got more here. I am currently trying to get API info for the Alexa features but no response from the arduino forum.

As you likely know the arduino IDE and even the CLI 'hide' a lot of what is happening under the covers AND modern compilers no longer exact a price for including unneeded 'stuff'. When I first saw that the compiler actually compiled the library source almost every time I was more than a little surprised. Even back in the early days of DOS and make we knew how to check if the source had been modified so did or didn't need to be recompiled. It does sometimes NOT recompile 'core' elements, but it more often than not does re-compile. 

Anyway because I 'knew' that I made the rash assumption that a relevant clue yielding header file was likely on my drive so I hauled out my handy dandy file searcher and text matcher tool and started chasing the clues. See screen shots for results of a search.

Screen Shot 2022 05 15 at 07.49.08
Screen Shot 2022 05 15 at 08.05.38
Screen Shot 2022 05 15 at 08.05.15

 

It is considered poor judgement to traverse a chasm in 2 leaps.


ReplyQuote
Ron
 Ron
(@zander)
Noble Member
Joined: 1 year ago
Posts: 1824
Topic starter  

@frogandtoad I do come by my sleuthing ability genetically, one of my ancestors on my male side was Inspector Alexander of Scotland Yard. He solved a very famous serial murder case by going undercover (a first). For this reason he was sent a letter and several gifts from Queen Victoria. Sadly the letter and gifts have disappeared (family issues) and it was OLD Scotland yard which I think was bombed in WWII so I have not been able to find any records online. I have another area of research but since I appear to be the last living Alexander remotely interested in this it simply isn't worth what little time I have left to pursue it. Now you know my secret.

That other area of investigation? Even before copiers, important correspondence was copied, by hand! So there may be Queen Victoria archives somewhere with the document but finding it is beyond my finances and energy level.

It is considered poor judgement to traverse a chasm in 2 leaps.


ReplyQuote
Page 1 / 2