Tuesday, December 31, 2019

Digest for comp.lang.c++@googlegroups.com - 25 updates in 3 topics

Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 30 11:59PM

On Mon, 30 Dec 2019 19:58:52 +0000
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
[snip]
> std::holds_alternative() are not constexpr unless the variant is
> constexpr.
 
> At some point I must take the time to work out how it is done.
 
On reflection, impressive but perhaps not super-impressive. At the
conceptual level, std::visit (if it had access to std::variant's
privates) could static_cast the address of the start of the variant's
storage to the appropriate type conditional upon the variant's index
variable (or whatever tag variable the variant keeps), and pass that
(dereferenced) to the visitor function. This would be resolved at run
time, after which ordinary function overload resolution would kick in
for the visitor function.
Bonita Montero <Bonita.Montero@gmail.com>: Dec 31 03:13AM +0100

> fall foul of the type-based access rules of C and C++.  You can only
> access data via an lvalue of appropriate type (a compatible type, or a
> char type).  Anything else is not defined by the standards.
 
There is no compiler and there won't be any compiler that behaves
different here.
You're not a practical programmer but a theorist.
Bonita Montero <Bonita.Montero@gmail.com>: Dec 31 03:29AM +0100

> will be occasions where the compiler can generate tighter code on
> the assumption that types like "int" and "float" never share the
> same address. ...
 
No, that won't happen. The compiler sees in my case that I alias
a float as an unsigned and doesn't do any optimization around that.
James Kuyper <jameskuyper@alumni.caltech.edu>: Dec 30 10:16PM -0500

> Paavo Helde <myfirstname@osa.pri.ee> wrote:
>> On 29.12.2019 20:30, boltar@nowhere.org wrote:
>>> On Sun, 29 Dec 2019 12:21:33 +0200
...
> int ifru_media;
> int ifru_intval;
> caddr_t ifru_data;
 
How does that declaration prove your point? It doesn't involve any
examples of "write as one type and read as another'.
Also,on Unix platforms, the C compiler is part of the same
implementation that provides those headers. The reason why portable code
should avoid "write as one type and read as another' is that the
behavior of such code is undefined (except in C2011). The implementors
KNOW what form the undefined behavior of such code takes on their
platform, and therefore can write code which relies upon that behavior.
Code intended to be portable can't do that.
 
Also, don't you find it a bit odd that what you consider to be "the
whole point of a union" has always had undefined behavior in C++, and
had undefined behavior in C all the way up until C2011? If the C and C++
committees had considered that "write as one type and read as another"
to be the whole point of unions, or even just the main point, or even
just a commonplace usage, you would think they would have explicitly
defined what the behavior of such usage was. In fact, the main point of
unions was originally the ability to store objects of multiple different
types in the same piece of memory, so long as the storage periods didn't
overlap.
 
It wasn't until C2011 that a footnote was added to the C standard
identifying that the behavior of "write as one type and read as another"
is to reinterpret the associated memory as having the type of the lvalue
used to read it. This still makes it completely dependent upon the
implementation-defined representation of the two types involved, so it
still can't be used in code that's intended to be portable, but the new
wording does allow it be used in code that doesn't need to be portable.
 
Footnotes are non-normative, and I've been unable to locate any
corresponding normative text in the C standard. People who should know
claim that this can be derived from other things the standard says about
obect representations, but when I asked for the details of that
derivation, all I got in response was silence. However, I haven't
bothered complaining much about it, because that's what most people have
always expected, what most C and C++ compilers have actually done, and
the footnote makes it clear that this is the C committee's intent - so
the absence of supporting normative text isn't a particularly important
problem.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Dec 30 07:37PM -0800

On 12/30/2019 9:12 AM, David Brown wrote:
[...]
 
> behaviour and many compilers (including gcc, clang and msvc) /will/ make
> you suffer for such language abuse.
 
>> But that's pure theory.
 
I must be missing your main point, however there is a nice case where
casting is "okay"?:
________________________
#include <iostream>
 
struct foo
{
int a;
};
 
 
struct bar
{
foo f;
int b;
};
 
 
int main() {
bar b = { { 0 }, 1};
foo* f = (struct foo*)&b;
 
f->a += 1;
b.b += 1;
 
std::cout << "b.f.a = " << b.f.a << "\n";
std::cout << "b.b = " << b.b << "\n";
 
return 0;
}
________________________
 
All pod, and perfectly fine to cast a pointer to a struct bar into a
pointer to a struct foo.
 
struct foo is the _first_ member of struct bar.
Siri Cruise <chine.bleu@yahoo.com>: Dec 30 08:07PM -0800

In article <qucif8$1oa0$1@gioia.aioe.org>, boltar@nowhere.org
wrote:
 
 
> Oh dear, someone better tell the authors of the standard unix networking
> libraries then. Clearly they have no clue, I mean look at this horror from
> net/if.h:
 
If your contract for C source code demands it conform to ANS C,
if.h violates the contract. If the contract has some different
requirement, like compatiable with gcc -lplugh2.77.1, then maybe
if.h is okay. If the contract requires Ada, you ain't even close.
 
There's no international treaty of C Standard Compliance. You
choose what you and the customers agree to.
 
--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
'I desire mercy, not sacrifice.' /|\
The first law of discordiamism: The more energy This post / \
to make order is nore energy made into entropy. insults Islam. Mohammed
Siri Cruise <chine.bleu@yahoo.com>: Dec 30 08:30PM -0800

In article <queeiv$iqr$1@dont-email.me>,
 
> implementation-defined representation of the two types involved, so it
> still can't be used in code that's intended to be portable, but the new
> wording does allow it be used in code that doesn't need to be portable.
 
typedef enum {
BigEndian = 0,
HoneywellEndian = 1,
PDPEndian = 2,
LittleEndian = 3
};
#define nativeByteOrder ( \
((union{char b[4]; uint32_t n;}){.b={
LittleEndian, HoneywellEndian, \
PDP11Endian, BigEndian}}).n & 0xFF)
#define bigEndian (nativeByteOrder==BigEndian)
#define honeywellEndian (nativeByteOrder==HoneywellEndian)
#define pdpEndian (nativeByteOrder==PDPEndian)
#define littleEndian (nativeByteOrder==LittleEndian)
 
--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
'I desire mercy, not sacrifice.' /|\
The first law of discordiamism: The more energy This post / \
to make order is nore energy made into entropy. insults Islam. Mohammed
boltar@nowhere.org: Dec 31 09:23AM

On Mon, 30 Dec 2019 14:57:25 +0100
 
>So this is C code (not C++) for a specific compiler on a specific
>operating system. As gcc has always defined the behavior, it "just
>works" there.
 
Its from MacOS so its compiled with Clang.
boltar@nowhere.org: Dec 31 09:25AM

On Mon, 30 Dec 2019 16:39:03 +0100
>type-punning in C.
 
>But when you claim that this is the /only/ use, outside tiny embedded
>systems, you are talking drivel.
 
So other than the VERY occasional uses of saving memory or reducing the amount
pushed onto a stack in a function call/return, what would you say is the main
use for a union then?
 
>Type-punning through unions is defined in C standards, but referencing
>examples from its use in C says nothing about unions in C++.
 
Many C header files and source code will be included into a C++ project. In
any sane world C++ *will* support the same union rules as C because it has
to regardless of whatever the standards committee in their ivory tower say.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 31 11:19AM

On Mon, 30 Dec 2019 19:37:05 -0800
 
> All pod, and perfectly fine to cast a pointer to a struct bar into a
> pointer to a struct foo.
 
> struct foo is the _first_ member of struct bar.
 
The point being made was I think about type punning, which leads to
trouble with C and C++'s strict aliasing rules.
 
There is no type punning in your code. It so happens that the address
of a standard-layout struct has two dynamic types (in C, effective
types): that of the struct and that of its first member, and so on
recursively if the first member is also a standard-layout struct. You
can freely cast between these and freely dereference the result, without
breaking strict aliasing, because a constructed object of the
dereferenced type will actually exist at the address in question: this
has always been the case in C++, but C++17 introduced a new term
"pointer-interconvertible"[1] to cover this.
 
Chris
 
[1] According to C++17 "If two objects are pointer-interconvertible,
then they have the same address, and it is possible to obtain a pointer
to one from a pointer to the other via a reinterpret_cast".
Melzzzzz <Melzzzzz@zzzzz.com>: Dec 31 12:00PM


> So other than the VERY occasional uses of saving memory or reducing the amount
> pushed onto a stack in a function call/return, what would you say is the main
> use for a union then?
 
In C++11 you can use objects in union....
 
 
> Many C header files and source code will be included into a C++ project. In
> any sane world C++ *will* support the same union rules as C because it has
> to regardless of whatever the standards committee in their ivory tower say.
 
Depends on compiler...
 
--
press any key to continue or any other to quit...
U ničemu ja ne uživam kao u svom statusu INVALIDA -- Zli Zec
Svi smo svedoci - oko 3 godine intenzivne propagande je dovoljno da jedan narod poludi -- Zli Zec
Na divljem zapadu i nije bilo tako puno nasilja, upravo zato jer su svi
bili naoruzani. -- Mladen Gogala
David Brown <david.brown@hesbynett.no>: Dec 31 01:01PM +0100

On 31/12/2019 03:13, Bonita Montero wrote:
 
> There is no compiler and there won't be any compiler that behaves
> different here.
> You're not a practical programmer but a theorist.
 
Again, you are wrong. Type-based alias optimisations are used on many
compilers, and they can give unexpected results from code that uses
inappropriate conversions like this. As I said, in simple test code you
often get the results that you'd expect if you did not know about the
effective type rules. But I have seen contrary results from MSVC, gcc
and clang - /all/ of these have type-based alias analysis optimisations
that can give you unexpected results when you don't understand (or
ignore) the rules of the language. This is not "just theory" - it is
practice. (It is not easy to get this effect on MSVC, but it does happen.)
 
It is so much "real world practice" that the Linux kernel is complied
with "-fno-strict-aliasing" to turn off type-based alias analysis -
because their code abuses types and accesses in a way that conflicts
with the standards.
 
It is incomprehensible to me how some people react with denial of
reality to things like this. It is fair enough to say "I wish C and C++
allowed casts like this" or "my code will only work on compilers like
gcc -fno-strict-aliasing because it messes with pointer types". But to
blindly say "I know this is against the rules of the language, but I'll
do it anyway because I think it should be allowed" takes a special kind
of stubborn stupidity.
 
 
If you want to write knowingly incorrect code, that's up to you. But
please do not recommend it to others.
 
 
Let's demonstrate with a simple example of type-based alias
optimisation. It's a little different from your example, because it's
simpler to demonstrate the issue without a lot of extra surrounding
code, and it can be handled simply in <https://godbolt.org>. And it
applies equally to C and C++.
 
 
int foo(int * px, float * py) {
int x = *px;
*py = 0;
return x + *px;
}
 
gcc -O2 -fno-strict-aliasing gives:
 
foo:
mov eax, DWORD PTR [rdi]
mov DWORD PTR [rsi], 0x00000000
add eax, DWORD PTR [rdi]
ret
 
With that flag, the compiler adds semantics to the C (or C++) language
to allow accessing data via non-compatible pointers or references. That
means it has to re-read via px, just in case py pointed to the same address.
 
Without the special flag, you get:
 
foo:
mov eax, DWORD PTR [rdi]
mov DWORD PTR [rsi], 0x00000000
add eax, eax
ret
 
It is more efficient code, based on the (valid) assumption that a
pointer to int and pointer to float can't refer to the same object.
 
 
MSVC /O2 gives:
 
int foo(int * __ptr64,float * __ptr64) PROC
; foo, COMDAT
mov r8d, DWORD PTR [rcx]
mov DWORD PTR [rdx], 0
mov eax, DWORD PTR [rcx]
add eax, r8d
ret 0
 
MSVC does not do this kind of type-based optimisation in this case, and
reads through px twice. Maybe I haven't used powerful enough
optimisation flags here.
 
 
ICC -O2 gives:
 
foo(int*, float*):
mov eax, DWORD PTR [rdi] #3.14
add eax, DWORD PTR [rdi] #5.17
mov DWORD PTR [rsi], 0 #4.6
ret
 
Bizarrely, icc re-reads via px, but does so out of order - giving code
that is less efficient than gcc but still dependent on type-based alias
analysis (and more efficient than gcc -fno-strict-aliasing).
Paavo Helde <myfirstname@osa.pri.ee>: Dec 31 02:06PM +0200


> So other than the VERY occasional uses of saving memory or reducing the amount
> pushed onto a stack in a function call/return, what would you say is the main
> use for a union then?
 
There is no other use, at least not according to the C++ standard. Its
usefulness can be "VERY occasional" or "sometimes useful", which
basically mean the same if you remove the emotional dressing. I think
nobody claims union is the most important construct in C++.
 
This is also related to the zero overhead principle. If there is no
reason to allocate any extra bytes for the object, the C++ language must
provide means to avoid that, in order to maintain zero overhead.
Bonita Montero <Bonita.Montero@gmail.com>: Dec 31 01:13PM +0100

> Again, you are wrong.
 
No, there isn't any compiler and there wont be ever any compiler
where what I wrote doesn't work.
.
 
> Type-based alias optimisations are used on many compilers, and
> they can give unexpected results from code that uses inappropriate
> conversions like this.
 
Not what I wrote: in this case the compiler does see the aliasing.
 
> *py = 0;
> return x + *px;
> }
 
That's a totally different issue.
David Brown <david.brown@hesbynett.no>: Dec 31 01:14PM +0100

On 31/12/2019 04:37, Chris M. Thomasson wrote:
 
> All pod, and perfectly fine to cast a pointer to a struct bar into a
> pointer to a struct foo.
 
> struct foo is the _first_ member of struct bar.
 
The cast is fine - often when dealing with these things, the cast itself
is perfectly valid. It is accessing data through the cast result that
is in question.
 
And in this case, I believe it is perfectly valid - the address of a
struct is guaranteed (in C, and I think also in C++ for POD with no
virtual stuff) to be the address of its first member.
David Brown <david.brown@hesbynett.no>: Dec 31 01:38PM +0100


> So other than the VERY occasional uses of saving memory or reducing the amount
> pushed onto a stack in a function call/return, what would you say is the main
> use for a union then?
 
I'd say it is used for three things:
 
1. To avoid pointlessly wasting memory. PC's may have oodles of ram,
but they have small caches. Small unions don't even need to go into
memory - compilers optimise them like any other data.
 
2. To express "sum types" - a type that can be one of several other
types. (structs are "product types" in the same sense.)
 
3. For type punning.
 
 
If you know you need either an A or a B, but not both, it simply doesn't
make sense to have a type holding both (like a struct). You have
something like a union. In C++, a std::variant makes this safer, and
makes it easier to keep track of the construction and destruction of the
objects. With a union, you have to do the tracking manually. Either
way, you avoid having objects that you don't need or want - and thus
avoid the responsibility of creating, tracking and destroying them.
 
 
> Many C header files and source code will be included into a C++ project. In
> any sane world C++ *will* support the same union rules as C because it has
> to regardless of whatever the standards committee in their ivory tower say.
 
No, that is not an issue.
 
Header files will often have declarations of union types - either as
independent types, or specifically for parameters to functions or APIs.
But they will rarely contain code that /uses/ the union, and does any
type-punning. You can use the union for non-type-punning access in the
C++ code that includes the header, and for type-punning access in the C
code that implements the functions declared in the header. That's all
fine and standards-compliant.
 
 
Many C++ compilers /do/ support type-punning for POD unions, just
because it is simple to support and occasionally useful to programmers.
But they would not have to do so.
David Brown <david.brown@hesbynett.no>: Dec 31 02:09PM +0100

On 31/12/2019 13:13, Bonita Montero wrote:
>> Again, you are wrong.
 
> No, there isn't any compiler and there wont be ever any compiler
> where what I wrote doesn't work.
 
This is not guaranteed. It won't work with the compiler/flag
combination I use, since it will be rejected as a fatal error when you
try to compile the code.
 
>> they can give unexpected results from code that uses inappropriate
>> conversions like this.
 
> Not what I wrote: in this case the compiler does see the aliasing.
 
It might - and it might not, depending on how code is re-arranged,
broken up, transferred around. And even if the compiler /does/ see the
aliasing, there is no guarantee it will honour it.
 
I fully agree that it is highly unlikely for a compiler to interpret the
exact code you wrote in any way other than the way you intended it. But
for serious programming, "highly unlikely" is not good enough.
 
Similar code, with the same fundamental error you made, could easily end
up interpreted differently.
 
And I totally fail to understand how you could think it's okay to break
the rules because you think "no one will notice if I break them just a
little bit".
 
Your code is wrong. Broken. A good compiler can see that and warn
about it.
 
>>      return x + *px;
>> }
 
> That's a totally different issue.
 
No, it is the same issue. It is a different bit of code, because it is
easier to show the trouble it can cause, but it is the same underlying
issue - the same paragraph in the standards.
Bonita Montero <Bonita.Montero@gmail.com>: Dec 31 02:12PM +0100

>> No, there isn't any compiler and there wont be ever any compiler
>> where what I wrote doesn't work.
 
> This is not guaranteed.
 
This de-facto guaranteed.
 
> It won't work with the compiler/flag combination I use, ..
 
This absolutely hasn't anything to do with the aliasing-options
of the compiler; at least with the code I showed.
 
> It might - and it might not, ...
 
It will definitely, you compulsive pettifogging idiot.
 
> I fully agree that it is highly unlikely for a compiler to interpret
> the exact code you wrote in any way other than the way you intended it.
 
Theres for sure a lot of code that is like what I showed so that no
compiler-vendor can ignore this.
 
>> That's a totally different issue.
 
> No, it is the same issue.
 
No, that's a different issue because of the lack of the opportunity
to detect the aliasing.
Ned Latham <nedlatham@woden.valhalla.oz>: Dec 30 05:29PM -0600

Keith Thompson wrote:
 
----snip----
 
> Is that the whole point of showing us that code, that it depends
> on a null pointer being represented as all-bits-zero because it
> uses calloc()?
 
No. Try reading with your eyes open.
 
Idiot.
 
> sending us on a wild goose chase digging through some online code.
 
> I'll probably never know, because I won't waste my time talking to
> someone who calls people idiots.
 
Do you waste time talking to people who misrepresent what they've been
given and then sneer at it?
 
----snip----
James Kuyper <jameskuyper@alumni.caltech.edu>: Dec 30 09:42PM -0500

On 12/30/19 6:01 PM, Ned Latham wrote:
> James Kuyper wrote:
>> Ned Latham wrote:
...
>> to. Can you give me the exact location in that body of code of at least
>> one such construct? Better yet, could you quote that line of code?
 
> No. get off your arese and look.
 
Why? It shouldn't take you more than a few seconds to honor my request,
while it might take me hours to honor yours.
The fundamental problem is that I won't even necessarily recognize what
you're referring to, even if it's staring me in the face. There's a
pretty good chance that what you think is code that depends upon the
representation of null pointers is, in fact, not so dependent.
Alternatively, it might be code that I incorrectly think has no such
dependence - either way, I won't recognize it when I see it. However, if
you would just identify the particular code you're talking about, which
should only take you a few seconds, it might save me hours of possibly
fruitless searching, and we can move on to the discussion of whether or
not you're correct, and whether or not it was actually necessary to
write such code.
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Dec 30 09:48PM -0800

>> uses calloc()?
 
> No. Try reading with your eyes open.
 
> Idiot.
 
It's not worth my time to read your code to try (and quite possibly
fail) to figure out what you're talking about. And it's no longer
worth my time to interact with you at all.
 
*Plonk*
 
[...]
 
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
[Note updated email address]
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */
Ned Latham <nedlatham@woden.valhalla.oz>: Dec 31 06:03AM -0600

James Kuyper wrote:
 
----snip----
 
> you're referring to, even if it's staring me in the face. There's a
> pretty good chance that what you think is code that depends upon the
> representation of null pointers is, in fact, not so dependent.
 
I don't know why you haven't already got it. If NULL == 0 the same
logic can be used with pointers as with integers and all their bitwidth
lookalikes and all the functions that require or return those types.
Tests like
 
if (!(array=calloc(hemeny,sizeof(arrayrcrd)))) // then deal with OOM.
 
wouldn't work correctly otherwise.
 
Knowing the way NULL is represented can be useful.
 
----snip----
David Brown <david.brown@hesbynett.no>: Dec 31 01:57PM +0100

On 31/12/2019 00:22, Ned Latham wrote:
 
>> because it is written in a sort-of C, sort-of C++, sort-of something
>> else mix using your own macros.
 
> That's noi reason for saying "incomplete".,
 
That is not why I said it was incomplete. I said it was incomplete
because you linked to some source code that relied on non-standard
headers that were not included in your links.
 
 
>>> The documentation tells you that. And why.
 
>> No, it does not.
 
> Don't lie to me about what I wrote, you fuck.
 
Throwing your toys out the pram does not help your argument.
 
 
>>> Don't be stupider than you have to be, David.
 
>> They are not defined in the source code you linked.
 
> So? The statement is dead stupid.
 
It is /correct/. You said "look at the source code in this link", and I
did. I saw it was incomplete, and said so. I could certainly make a
reasonable guess about how you defined macros like "WHILE", but I could
not be sure what else might be missing. And there is a limit to how
much effort I'll put in deciphering spaghetti that mixes includes and
conditional compilation like your code.
 
>> the file "mcdef.h", which was not in the links (it is in the tarball
>> that can be found by a little digging from your links).
 
> There's a link to it in the documentation.
 
That would be the documentation that was not included in the original
links, but which I found by digging around?
 
Perhaps you sent the wrong links, or have not looked at the links for
some time.
 
>> Macros to try to make your C or C++ code like BASIC are /not/ a good
>> idea, and never have been.
 
> "BASIC"? You're a moron.
 
IF no tail THEN return NULL;
 
It's not quite BASIC, but it's C code with macros to make it look like
BASIC.
 
Maybe you had another language in mind, rather than BASIC - but not C or
C++.
 
 
 
>> Had you linked to the documentation, it would have told me that.
 
> Hmph. All you had to do to see the whole site is use BS and ENTER in
> the location bar.
 
It didn't take me much digging - I did not suggest it was difficult to
find. But if you had intended for people to read the documentation it
would have made sense to link to it.
 
 
>> It says nothing about /why/ that might be a useful idea.
 
> You're insane. Why would type-indepedence *not* be useful?
 
When it leads to inefficient and unsafe code, like yours?
 
>>> Exceptions are evil, especially in low-level code.
 
>> RAII is orthogonal to exceptions.
 
> It's bloat.
 
Please explain.
 
>> enough for code from 1995 - but hardly examples of how to write C++ in
>> this generation.
 
> Mclib's not about C++.
 
So you agree it is not written in normal C++ ?
 
 
>> Yes, you mentioned that in your documentation. It was one of many
>> incorrect statements.
 
> Dream on, Bozo.
 
No, thanks, I will try to leave it at that - I have no plans to try to
list your mistakes. People can read your posts in this thread and guess.
Andrew Z <formisc@gmail.com>: Dec 30 08:01PM -0800

hello,
im attempting to simplify the C code for arduino/idf framework.
the setup_task function worked well until i introduced the Zap class. And now it is failing with :
[code]
 
rc/main.cpp: In function 'void setup()':
src/main.cpp:112:115: error: invalid use of non-static member function
setup_task(outlet.OutletToggleTask, (char*)"Outlet Task", eventGroup, outlet.OutletCallback, outlet.GetCycleTicks);
^
In file included from src/main.cpp:19:0:
 
[/code]
 
I appreciate the guidance and any help since I clearly don't understand what is wrong. I found a similar thread here (https://forum.arduino.cc/index.php?topic=524167.0). But im not sure why there is a need to create such a complex hierarchy...
 
simplified code:
[code]
main.cpp
#include <Arduino.h>
...
#include <zap.h>
#define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( xTimeInMs ) * ( configTICK_RATE_HZ / ( TickType_t ) 1000 ) )
const int TIME_BIT = BIT0 ;
#define DATA_PIN 4
#define CHANNEL 1
 
 
EventGroupHandle_t eventGroup;
 
void setup_task( void (*DeviceTask)(void*), char* TaskName, EventGroupHandle_t eventGroup,
void (*Callback_Fn)(TimerHandle_t), TickType_t cycle_ticks ) {};
 
void setup(){
 
eventGroup = xEventGroupCreate(); //check if NULL NOT returned.
Zap outlet(DATA_PIN, CHANNEL , 20000); // make a new outlet instance with
setup_task(outlet.OutletToggleTask, (char*)"Outlet Task", eventGroup, outlet.OutletCallback, outlet.GetCycleTicks); // <-- Failure here
 
....
}
 
zap.h
#ifndef _ZAP_H
#define _ZAP_H
#include <Outlet.h>
 
class Zap : public Outlet {
private:
int channel ; //= 1 ; //CHANNEL 1
const TickType_t t_outlet_cycle ;
const TickType_t t_outlet_cycle_ticks = 10000;
public:
Zap( int pin , int ch=1, TickType_t cycle_ms = 10000 ): Outlet(pin), channel {ch} , t_outlet_cycle {cycle_ms}
{
assert( cycle_ms >= 10000) ;
 
} ;
 
void OutletCallback(TimerHandle_t handle) ;
void OutletToggleTask( void *Params) ;
int GetChannel() { return channel ; } ;
TickType_t GetCycle () { return t_outlet_cycle ;} ;
TickType_t GetCycleTicks () { return t_outlet_cycle_ticks ;} ;
};
 

No comments: