How to generate port id


#1

Hi, I have a node that does an analog read, and I’d like to be able to modify the input port programmatically. i.e. I’d like to have a loop that reads 8 analog inputs (A0 to A7) with an analog read in it. Something like

for (int 1 = 0; i < 8; i++) {
    myArray[i] = analogRead("A" + i);
}

but I can’t figure out how to generate the port id. I’ve tried concat, but I can’t connect a string to a port. I made a node with an input string and an output port, and tried to emit the input, but that didn’t work either. Apparently some sort of conversion is needed to make a string into a port id.
How can I do this?
Thanks,
Ian


#2

Analog ports are just byte constants (macrodefinitions), not strings. And they are enumerated sequentially. So:

for (int i = 0; i < 8; i++) {
    myArray[i] = analogRead(A0 + i);
}

And if you take a look on how analogRead is implemented inside the Arduino core, you will see that it expects a zero-based channel, not port. And if one passed an Ax port to it, the function converts it to a channel first. Long story short, the following is equivalent:

for (int i = 0; i < 8; i++) {
    myArray[i] = analogRead(i); // yeah, just i
}

#3

Sorry Victor, I’ve confused the issue with my example.

My problem is that I want to use the “analog-sensor” node in my patch rather than write a piece of bespoke code, and I want to use the “count” node as input to it to provide the sensor pin id. The intention of the example was only to indicate what I want to do, i.e. continuously loop around reading each analog input and store the results in an array. (That array will then be used to drive my PPM generator (which you helped me sort out way back), which will feed a 2.4GHz RF module and control my R/C model plane).

Count gives me an integer (I’ve added some other nodes around it so it just counts to 8 then restarts at zero), and “concat” lets me concatenate the “A” before it, so I can generate the pin name (i.e. A0) as a string, but I cannot pass that to the “analog-sensor”. I get a type mismatch.

So my question is, how do I emit a port in a custom node? An example would be great!

Thanks, Ian


#4

Judging from what has already been said, you can probably create a node with number input and port output. Assuming input is called index, write (A0 + index) to the output. This node would only work for Analog ports.


#5

Thanks gweimer, that worked!. Lateral thinking at its best!
:wink:


#6

With a bit of mucking around I reduced it to one line of code! Now it looks like this.

void evaluate(Context ctx) {
    emitValue<output_OUT>(ctx, A0 + getValue<input_IN>(ctx));
}

Brilliant!

Well, maybe I spoke too soon. The program compiled and produced expected (sort of) results with no pots connected. However when I connected up three pots (actually a three-axis stick) to A0, A1 and A2, I got some odd results. A0 seems to work fine but A1 and A2 are equal to A0.
I’ve tried swapping the pots around the analog inputs, and even disconnecting A0 and connecting that pot to A3, but still the same thing happens. A0 reads something, and then all other analog pins read the same value.
I’ve put in watches (and run the clock at 1 second) to display the values read. I’ve also run it with the clock at 0.02 (50 times / second) and looked at the output with a software oscilloscope (xoscope) and the pulses are definitely all the same width.
I put the same code into an Arduino program, same hardware, same stick, and it worked fine.
My next desperate attempt was this.

struct State {
};

{{ GENERATED_CODE }}

void evaluate(Context ctx) {
   auto inValue = getValue<input_IN>(ctx);
   if (inValue = 0) emitValue<output_OUT>(ctx, A0);
   else if (inValue = 1) emitValue<output_OUT>(ctx, A1);
   else if (inValue = 2) emitValue<output_OUT>(ctx, A2);
   else if (inValue = 3) emitValue<output_OUT>(ctx, A3);
   else if (inValue = 4) emitValue<output_OUT>(ctx, A4);
   else if (inValue = 5) emitValue<output_OUT>(ctx, A5);
   else if (inValue = 6) emitValue<output_OUT>(ctx, A6);
   else if (inValue = 7) emitValue<output_OUT>(ctx, A7);
}

But still the same result. All values returned are the same, and they all track A0. i.e. they all return the same value as the pot connected to A0.

What am I doing wrong?


#7

In further developments, it seems that all the analog ids (A0, A1, A2 etc) are all equal to 15. So passing any of them to analog-sensor will always read A0.


#8

That’s weird. Are you sure you actually have a non-zero value on IN? To me it looks like the input value is stuck.

Could you attach a xodball of your project so that I can try to reproduce?


#9

proj1.xodball (35.0 KB)

Here ya go.

:wink: Ian


#10

Any reason why type PORT doesn’t cast to a STRING so we can watch it? Did you avoid auto-casting to number just so it doesn’t get tied to numeric input accidentally?

This port2num node seems to work:

struct State {
};

{{ GENERATED_CODE }}

void evaluate(Context ctx) {
    emitValue<output_NUM>(ctx, getValue<input_IN>(ctx));
}

#11

Your update-pulse-widths is using a channel array (channel[chanValue]), but it I don’t see where it is declared, and it is not saved as part of state, so there is no reason to have an array to save multiple values.

I think I found your problem. You connect counttomax-TRG to analog-sensor-UPD, so analog sensor only updates when counttomax-TRG sends a pulse. That pin is tied to “count<max” node, so it only triggers when count BECOMES <max, i.e. only when count is reset, so it only reads 1st analog port. You need counttomax-TRG to send a pulse every time input TRG gets a pulse if count<max.


#12

Thanks for having a look at this for me @gweimer.
The channel array is defined in the myinitialisation node, which is where the hardware timer is set up to output the PPM stream. It is in global scope so I assume it is available to any node that references it.
From your second point, my understanding is that the “less” node only triggers when the condition changes, not when the input changes.
In the Execution Model page under Program Life Cycle it says:
“A signal causes the program to enter a new transaction. The updated values flow downstream along links and cause the nodes they hit to update. The process of updating a node is called evaluation in XOD.”
That’s why I thought that a node will be evaluated when any of its inputs change. But the inputs changing does not necessarily mean that the output will be generated and passed to connecting nodes. That’s a bit of a shift for me to wrap my brain around!
So I tried your suggestion and you are right. I added a pulse-on-change node in count2max and connected the input to the count output. And that seems to have solved the problem. At least the numbers are changing. But it seems my pots are not being read. No idea why not, they were before. Seems I’ve changed something I shouldn’t have…

Thanks again for your help. I’ll keep experimenting!
:wink: Ian


#13

@gweimer Sorry, just read your previous post. Have to confess I don’t understand it. I did notice that I couldn’t attach out output port to a watch as the types were incompatible, but I don’t know how to cast a port to a string. Is that what your port2num node is for?
I didn’t avoid auto-casting to a number, I don’t know what that means or how to do it.
Did I mention I’m not a C++ programmer? I’ve done a bit of simple C (Arduino) but I have no idea about C++. All I can do is copy/paste and follow simple instructions…
:-\ Ian


#14

Not really. We did not get an idea how could it be used. And now I see. Will add the cast.

@mogplus8, the example @gweimer provided is a new C++ node (port2num) which takes a port as an input and outputs NUM with its numerical representation. You can create one for yourself and place it between an output of type port and an input of type string (e.g., watch).


#15

Sorry. I should have been more clear. The auto-casting comment was directed at the developers, not the originator of the post. A number will auto-cast to a string, so it can be tied to a watch node. A port will not auto-cast, so I had to convert it to a number before connecting it to a watch node.

nkrkv, a variable declared in one node is not available to other nodes, is it? A variable declared within a node isn’t even available to the same node on the next call unless it is stored in State. Does {{#global}} construct get around that limitation?

The less node will update every time its input changes, but it will not “pulse” unless it is changing from false to true. An update from true -> true will not be seen as a pulse. I’m guessing it won’t even be seen as a “change” so down-stream nodes would not update, but developers would need to confirm that.