Need help to understand a function

The code below is written by my C programming tutor. I have to use this function in my following assignment, however i can not get the output pointer parameter to return time for how long the button is being pressed.

Function :

int readSwitchEventTimes(SwitchPtr sw,
unsigned int *pClickDurationMs,
unsigned int *pTimeSincePrevClickMs) {
boolean debouncedValueChanged;
int switchEvent;
unsigned int timeNowMs;

timeNowMs = (unsigned int) millis();
debouncedValueChanged = debounce(sw, timeNowMs);

// if (timeNowMs == TIME_NOT_SET) // ensure we don't use the not set value
// timeNowMs -= 1;

if (sw->debouncedSwitchValue == SW_ACTIVE) { // is debounced switch pressed?
// if it has just changed, then we've just pressed, otherwise the switch is
// being held down
if (debouncedValueChanged) {
switchEvent = SW_PRESS;

sw->prevDebouncedPressTimeMs = timeNowMs;
} else
switchEvent = SW_KEEP_PRESSED;

} else { // no, switch is not currently being pressed
if (debouncedValueChanged) { // just released?
switchEvent = SW_RELEASE_CLICK;

if (pClickDurationMs)
*pClickDurationMs = timeNowMs - sw->prevDebouncedPressTimeMs;

if (pTimeSincePrevClickMs) {
*pTimeSincePrevClickMs = timeNowMs - sw->prevDebouncedReleaseTimeMs;
}

sw->prevDebouncedReleaseTimeMs = timeNowMs;

} else { // not-pressed for a while
switchEvent = SW_OFF;
}
}

return switchEvent;
}

=========================================================================
I called it like this in my code:
=========================================================================

void loop() {
static int array1[ARRAY_LEN] = { 1, 27, 44 };
int sw1Event;
unsigned int clickDuration;

sw1Event = readSwitchEventTimes(sw1, clickDuration, NULL);

if (sw1Event == SW_RELEASE_CLICK) {
Serial.println("SW1 clicked");
printArray("array1", array1, ARRAY_LEN);
Serial.println(clickDuration); // only printing it so i can see if it works
}


delay(SUPERLOOP_DELAY_MS);
}
what, exactly, is the parameter supposed to be to
serial.println(???)

I see this:

Serial.println("SW1 clicked"); //it takes a string or char array construct?

Serial.println(clickDuration); // or does it take an integer, or is it overloaded??

just to test it, try this...

char tst[100];
sprintf(tst, "%i", clickDuration);
Serial.println(tst);

closed account (48T7M4Gy)
@OP It's pretty lousy (Arduino?) function programming you have been given for a simple problem, but here are a few thoughts.

1. What output if any do you get?

2. Where have you declared sw1? Is this somehow meant to be related to array?

3. I would also suggest you add an else section to your if control so all event bases are covered not just if sw1Event == SW_RELEASE_CLICK.
This is what is given in the assignment brief :

==========================================================

There is a function in the EE108 library, readSwitchEventTimes, which is very like the readSwitchEvent function that you have already used. (Refer to the ee108_switches.h header file.) The main differences are as follows:
 readSwitchEventTimes does not distinguish between click types (normal, long, very long) and instead returns SW_RELEASE_CLICK in the case that any click is detected.
 readSwitchEventTimes has two optional output (pointer) parameters. Both are pointers to unsigned int types.
○ The first output parameter, pClickDurationMs, receives the click duration in ms. (You can use this value to differentiate between normal, long, very long clicks etc. as you wish.)
○ You can ignore the second output parameter, pTimeSincePrevClickMs, (and should just pass in NULL) as it is not very useful in the current implementation.

==========================================================

sw1 is declared in the header file which i have included already in the code.
sw1 - is just a simple switch button on the arduino daughter board.

I am asked to pass in pointer to an unsigned int that receives the click duration from this function but eventually when the function is called nothing points to that variable that i am passing in. it is just 0.

This part of the function :

if (pClickDurationMs)
*pClickDurationMs = timeNowMs - sw->prevDebouncedPressTimeMs;

Does this mean that if some argument is passed in the function it will obtain the time the button was pressed and point to it?

closed account (48T7M4Gy)
Please post all your code so I can see the structure of what makes up a switch and how you have declared it. Without 'full disclosure' it's not possible to help you.

If you can't or won't do that, and it's your call, the best I can comment is the function you have been given updates a variable you must define, and that variable would be attached to an individual switch. A struct is an ideal way of doing that.

(Interestingly your tutor treats the two relevant pointers as outputs but that is not what is happening. A function has only one output and this one is no exception. But that doesn't help you too much.)

BTW you should use code tags using the <> button on the right. Just select your code and click the <> button. You can go back to your previous posts and do that via the edit button at the bottom of your posts.

========================
ee108_switches.h
========================
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/**
 * Header file for switch reading functionality
 * used with Arduino Uno.
 */
 
#include <ee108.h>

#ifdef __cplusplus
extern "C" {
#endif

#define SW_ACTIVE LOW
#define SW_INACTIVE HIGH

const int SW_OFF = 0x0;
const int SW_PRESS = 0x02;
const int SW_KEEP_PRESSED = 0x06;
const int SW_RELEASE_CLICK = 0x08;
const int SW_LONG_MODIFIER = 0x10;
const int SW_VERY_LONG_MODIFIER = 0x20;
const int SW_LONG_CLICK = 0x18; // SW_RELEASE_CLICK | SW_LONG_MODIFIER;
const int SW_VERY_LONG_CLICK = 0x38; // SW_LONG_CLICK | SW_VERY_LONG_MODIFIER;


const unsigned int TIME_NOT_SET = 0;

typedef struct SwitchInfo * SwitchPtr;

extern SwitchPtr sw1;
extern SwitchPtr sw2;


void setSwitchDebounce(unsigned int debounceMs);
void setSwitchClickDurations(unsigned int longClickMs, unsigned int veryLongClickMs);

/**
 * read the (debounced) switch value and optionally output the
 * click duration and time since previous click
 *
 * Typically this function should be called once per superloop.
 * In any case, the function must be called relatively frequently (at least
 * every 100ms or so) in order to correctly detect the button being
 * held down and the difference between long and normal click. 
 * 
 */
int readSwitchEventTimes(SwitchPtr sw, 
                          unsigned int *pClickDurationMs,
                          unsigned int *pTimeSincePrevClickMs);

/**
 * read the current switch event as simply as possible
 *
 * Usually this function or readSwitchEventTimes should be called
 * once per superloop.
 *
 * @param sw    a SwitchPtr referring to valid switch state information
 *              (usually sw1 or sw2)
 * @returns the current switch event which is one of:
 *            SW_OFF         the button is not pressed
 *            SW_PRESS        the button has just transitioned from not
 *                            pressed to pressed
 *            SW_KEEP_PRESSED the button was already pressed and has
 *                            been held down continuously since
 *            SW_RELEASE_CLICK the button has just been released. A press
 *                            followed by a release is called a click.
 */
int readSwitchEvent(SwitchPtr sw);


#ifdef __cplusplus
}
#endif 



=================================
ee108_switches.c
=================================
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include <ee108_switches.h>

typedef struct SwitchInfo {
  int switchPin;  
  int prevSwitchValue; // raw switch value the last time the switch was checked
  int debouncedSwitchValue;
  unsigned int switchChangeTimeMs; // last time switch value changed or 0 if not yet set
  unsigned int prevDebouncedPressTimeMs;
  unsigned int prevDebouncedReleaseTimeMs;
} SwitchInfo;


unsigned int debounceMs = 20;
unsigned int longClickMs = 1000;
unsigned int veryLongClickMs = 2000;

static SwitchInfo sw1Info = { SW1, 1, 1, 0, 0, 0 };
SwitchPtr sw1 = &sw1Info; // point at information for switch1

static SwitchInfo sw2Info = { SW2, 1, 1, 0, 0, 0 };
SwitchPtr sw2 = &sw2Info; // point at information for switch1


void setSwitchDebounce(unsigned int debounceMs_) {
	debounceMs = debounceMs_;
}

void setSwitchClickDurations(unsigned int longClickMs_, unsigned int veryLongClickMs_) {
	longClickMs = longClickMs_;
	veryLongClickMs = veryLongClickMs_;
}

 /**
 * debounces the specified switch (updating the switch info by side effect)
 * 
 * NOTE: this function does *not* change any debounced time values. This is
 * to allow the caller to calculate click durations etc.
 * 
 * @param sw    a SwitchPtr referring to valid switch state information
 * @param timeNowMs the time at which this read is occurring
 * @returns true if the debounced value has changed, false otherwise
 */
static boolean debounce(SwitchPtr sw, unsigned int timeNowMs) {
  int currentSwitchValue = digitalRead(sw->switchPin);
  boolean changed = false;

  if (currentSwitchValue != sw->prevSwitchValue) { // has raw switch value changed?
    sw->switchChangeTimeMs = timeNowMs;
    sw->prevSwitchValue = currentSwitchValue;
  } else { // no - raw switch value is unchanged
    // is raw switch value different to debounced value, and if so
    // has the raw switch value been stable for long enough to be stable/debounced?
    if (currentSwitchValue != sw->debouncedSwitchValue) {
      if ((timeNowMs - sw->switchChangeTimeMs) > debounceMs) {          
        sw->debouncedSwitchValue = currentSwitchValue;
        changed = true; // debounced value has changed
      }
    }
  }
  return changed;
}

/**
 * read the current switch event and optionally output times also
 */
int readSwitchEventTimes(SwitchPtr sw, 
                          unsigned int *pClickDurationMs,
                          unsigned int *pTimeSincePrevClickMs) {
  boolean debouncedValueChanged;
  int switchEvent;
  unsigned int timeNowMs;

  timeNowMs = (unsigned int) millis();
  debouncedValueChanged = debounce(sw, timeNowMs);

//  if (timeNowMs == TIME_NOT_SET) // ensure we don't use the not set value
//    timeNowMs -= 1;

  if (sw->debouncedSwitchValue == SW_ACTIVE) { // is debounced switch pressed?
    // if it has just changed, then we've just pressed, otherwise the switch is
    // being held down
    if (debouncedValueChanged) {
      switchEvent = SW_PRESS;

      sw->prevDebouncedPressTimeMs = timeNowMs;
    } else
      switchEvent = SW_KEEP_PRESSED;
      
  } else { // no, switch is not currently being pressed    
    if (debouncedValueChanged) { // just released?
      switchEvent = SW_RELEASE_CLICK;

      if (pClickDurationMs)
        *pClickDurationMs = timeNowMs - sw->prevDebouncedPressTimeMs;

      if (pTimeSincePrevClickMs) {
        *pTimeSincePrevClickMs = timeNowMs - sw->prevDebouncedReleaseTimeMs;
      }

      sw->prevDebouncedReleaseTimeMs = timeNowMs;
      
    } else { // not-pressed for a while
      switchEvent = SW_OFF;
    }
  }

  return switchEvent;
}


int readSwitchEvent(SwitchPtr sw) {
  unsigned int clickDurationMs = 0;
  int ret = readSwitchEventTimes(sw, &clickDurationMs, NULL);
  
  if (ret == SW_RELEASE_CLICK) {
	if (clickDurationMs >= longClickMs) {
	  if (clickDurationMs >= veryLongClickMs)
		ret = SW_VERY_LONG_CLICK;
	  else
		ret = SW_LONG_CLICK;
	}		
  }
  
  return ret;
}


====================================
this code is provide and needs to be edited:
however you can see that i already declared unsigned int variable called clickDuration
and passed it in the function.
====================================

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
   Starter sketch for assignment 3.

   The starter code includes functionality to print an array
   (featuring an array pointer + pointer arithmetic implementation)
   and demonstrates part of how to call the readSwitchEventTimes function.
*/

#include <ee108.h>
#include <ee108_switches.h>

// constants

#define ARRAY_LEN 3
const int SUPERLOOP_DELAY_MS = 20;

// function declarations
void printArray(int *slice, int len);

// ==============================================================
// top level functions
// ==============================================================

void setup() {
  // set up serial
  Serial.begin(9600);
  Serial.println("\n\nA3_ClickArraysStarter starting...");
}

void loop() {
  static int array1[ARRAY_LEN] = { 1, 27, 44 };
  int sw1Event;
  unsigned int clickDuration;

  // WARNING: this function only returns one type of click,
  // namely SW_RELEASE_CLICK. It's up to you to figure out
  // if it should be interpreted as a long click or very-long
  // click depending on the optional pClickDurationMs output parameter
  // (which has not been supplied on the following line).

  sw1Event = readSwitchEventTimes(sw1, clickDuration, NULL);

  if (sw1Event == SW_RELEASE_CLICK) {
    Serial.println("SW1 clicked");
    printArray("array1", array1, ARRAY_LEN);
    Serial.println(clickDuration);
  }
  

  delay(SUPERLOOP_DELAY_MS);
}

// ==============================================================
// helper functions
// ==============================================================

/**
   print all the values in the specified array (or array slice)

   @param arrayName the name to print before the array elements
   @param slice    a pointer to the first element of the array
                   or array slice to be printed
   @param len      the number of elements to be printed
*/
void printArray(const char * arrayName, int *slice, int len) {
  int *pValue;

  Serial.print(arrayName);
  Serial.print(" { ");

  // print first value without comma before
  if (len > 0)
    Serial.print(*slice);

  // now print remaining values
  for (pValue = slice + 1; pValue < slice + len; pValue++) {
    Serial.print(", ");
    Serial.print(*pValue);
  }
  Serial.println(" }");
}



=================================
The first output parameter, pClickDurationMs, receives the click duration in ms. (You can use this value to differentiate between normal, long, very long clicks etc. as you wish.)

However, it doesn't return anytime and i can not see the click duration...
=================================
closed account (48T7M4Gy)
Thanks for the extra information which confirms what I thought about a struct being involved.

i.e
1
2
3
4
5
6
7
8
typedef struct SwitchInfo {
  int switchPin;  
  int prevSwitchValue; // raw switch value the last time the switch was checked
  int debouncedSwitchValue;
  unsigned int switchChangeTimeMs; // last time switch value changed or 0 if not yet set
  unsigned int prevDebouncedPressTimeMs;
  unsigned int prevDebouncedReleaseTimeMs;
} SwitchInfo;


So, if you declare a switch SW_xyz, all references to members of that switch will be by dot notation eg SW_xyz.prevSwitchValue

And, if pSW-xyz is a pointer to the same switch ie &SW_xyz then the member will be referred to as pSW_xyz -> prevSwitchValue.

All of this you know.

The way I read it you use the function in the following way:

in loop()
1
2
int clickDuration = 0;
int sw1Event = readSwitchEventTimes(&sw1, &clickDuration, NULL);


clickDuration will be updated, and you will have a value for sw1Event you can use, update prevSwitchValue, and compare with the constants SW_OFF etc

From the time values you can update the timing properties within the struct
eg pSW_xyz->prevDebouncedPressTimeMs = some_function_of(prevSwitchValue, clickDuration);

Those same values can be printed out and processed within the loop as required.

This part of the function :

if (pClickDurationMs)
*pClickDurationMs = timeNowMs - sw->prevDebouncedPressTimeMs;

Does this mean that if some argument is passed in the function it will obtain the time the button was pressed and point to it?


You have used clickDuration, but essentially what this snippet is doing is updating that value in loop() (note that sw->prevDebouncedPressTimeMS is read from the SwitchInfo properties for the particular switch passed as a pointer to the function).

Hope this helps :)







kemort, so you are telling me that all i needed to do is just pass in an address of clickDuration..

It works... Thank you so much! You are very helpful!
closed account (48T7M4Gy)
Cheers, you!re right, most of it is shuffling pointers around to drive and make use of the properties within SwitcInfo.
Topic archived. No new replies allowed.