so do you only want to process any input when both pump operations are complete and the pumps are off?
It should again wait for the inputs to be pushed from serial and run according to the new inputs.
with both pumps off
a cmd line for pump1 should be processed, presumably turning on the pump
with only one pump on, another cmd line should be read if available. if it is for pump2, i assume it should be processed, presumably turning pump 2 on. what should happen if it is for pump1 before pump1 has been turned off?
It should print 'pump1 busy'.
...after you press a button?
This is like pulling teeth. Please try to describe this top to bottom.
Can pump one be off and running because you pressed a button meanwhile more "commandlines" (yes, in one line ? about exactly 4 values) are yet to come in?
Can both pimps be on at the same time? Are new commandlines discarded if they arrive when the system is busy?
I know. A thousand questions. But first, the Tranya...
Maybe try to draw a time line diagram of commandlines coming in from wherever, when amongst those you might press one button or another, what should happen if, if, if.
The programming is easy. As you may be slowly realizing, describing what you want the program to do, so it makes total and unambiguous sense, is hard.
If you just start throwing out code at this, any questions you don't/can't answer will be answered by what the code does.
It must be specified exactly, as ultimate when the program runs it will do only and exactly what you said (coded).
a7
consider following simulation that queues cmd strings for specific pumps when busy and which are dequeued when the pump operation completes
ready
pumpRun: pump1 On
queue: 1,2,3,4000
pumpRun: pump1 Off
dequeue: 1,2,3,4000
pumpRun: pump1 On
pumpRun: pump1 Off
char buf [40];
char s [40];
unsigned long msec;
enum { Off = HIGH, On = LOW };
// -----------------------------------------------------------------------------
#define MaxTok 10
char *toks [MaxTok];
int vals [MaxTok];
int
tokenize (
char *s,
const char *sep )
{
unsigned n = 0;
toks [n] = strtok (s, sep);
vals [n] = atoi (toks [n]);
for (n = 1; (toks [n] = strtok (NULL, sep)); n++)
vals [n] = atoi (toks [n]);
return n;
}
// -----------------------------------------------------------------------------
#define NcmdQ 10
struct Q {
char cmdQ [NcmdQ][40];
int head;
int tail;
int cnt;
};
// -------------------------------------
void
queue (
const char *buf,
struct Q *q )
{
sprintf (s, "queue: %s", buf);
Serial.println (s);
if (NcmdQ <= q->cnt) {
sprintf (s, "queue: full");
Serial.println (s);
}
memcpy (q->cmdQ [q->head++], buf, strlen(buf));
if (NcmdQ <= q->head)
q->head = 0;
q->cnt++;
};
// -------------------------------------
char *
dequeue (
Q *q)
{
if (0 == q->cnt)
return NULL;
char *buf = q->cmdQ [q->tail++];
if (NcmdQ <= q->tail)
q->tail = 0;
q->cnt--;
sprintf (s, "dequeue: %s", buf);
Serial.println (s);
return buf;
}
// -------------------------------------
struct Pump {
byte pin;
const char *label;
Q q;
bool active;
int solenoid0;
int solenoid1;
unsigned long msecLst;
unsigned long period;
};
Pump pumps [] = {
{ 10, "pump0" },
{ 11, "pump1" },
};
#define Npump (sizeof(pumps)/sizeof(Pump))
// -------------------------------------
void
pumpRun (
char *s )
{
if (4 > tokenize (s, ",")) {
sprintf (s, "Error: wrong # of values - %s", s);
Serial.println (s);
return;
}
unsigned idx = vals [0];
Pump *p = & pumps [idx];
p->solenoid0 = vals [1];
p->solenoid1 = vals [2];
p->period = vals [3];
p->msecLst = msec;
p->active = true;
digitalWrite (p->pin, On);
sprintf (s, "pumpRun: %s On", p->label);
Serial.println (s);
}
// -------------------------------------
void
pumpMonitor (void)
{
Pump *p = pumps;
for (unsigned n = 0; n < Npump; n++, p++) {
if (p->active && (msec - p->msecLst) >= p->period) {
digitalWrite (p->pin, Off);
p->active = false;
sprintf (s, "pumpRun: %s Off", p->label);
Serial.println (s);
char *buf = dequeue (& p->q);
if (NULL != buf)
pumpRun (buf);
}
}
}
// -------------------------------------
void
pumpReq (
char *s )
{
unsigned idx = atoi(s);
if (Npump <= idx) {
sprintf (s, "Error: invalid pump idx - %d", idx);
Serial.println (s);
return;
}
if (! pumps [idx].active)
pumpRun (s);
else {
queue (buf, & pumps [idx].q);
}
}
// -----------------------------------------------------------------------------
void
loop (void)
{
msec = millis ();
pumpMonitor ();
if (Serial.available ()) {
int n = Serial.readBytesUntil ('\n', buf, sizeof(buf)-1);
buf [n] = '\0';
pumpReq (buf);
}
}
// -----------------------------------------------------------------------------
void
setup (void)
{
Serial.begin (9600);
Serial.println ("ready");
}
What line ending setting in the serial monitor did you test this code with?
a7
newline
empty
LOL. I saw the line of code you quoted at me. That informs the setting, but does not control it.
Thank you for ( assume) verifying with one precious word that you had your serial monitor set up correctly for the code you posted.
Which I will "consider" only when it becomes part of @Prominent_being's solution to her problem - the simulation you shared in your response #26 did nothing to answer my questions about exactly how the OP sees this working.
Perhaps you are able to divine the specification somehow, or maybe you just can't resist writing code.
I have little motive to wade through code to reverse engineer a specification of function, even less when it is obvious at a glance that you are not reading the OP the same way I have done so far.
I did play with your code a bit. On an UNO, IDE 1.8.7 input lines
1,2,3
and
1,2,3,4,5
both further took wind out of my sails.
The errors in your code will no doubt be found and fixed before it is exploited, if indeed it ever is.
a7
sometimes you have to demonstrate a solution and ask "is this what you want"?
the following statement seem inconsistent
what errors? a min of 4 arguments are expected
since it's just intended as a demonstration of what could be done, it's neither a complete implementation nor completely tested. waiting on a response from the OP
Agree. Progress can be made offering an incomplete and lightly tested program and asking "is this what you want". I like to stay in the (usually) more familiar territory noobs inhabit, words.
I will cheerfully admit to being too lazy to write code in the absence of a good understanding of what is wanted. For myself. And admit to being not of any mind to write code, complete or tested as it may or not be, for anyone here trying to learn up on this stuff.
So yeah, waiting on the OP.
a7
Thank you for the code "gcjr".I am sorry to be a little bit busy with my exams and haven't had a chance to try it out yet. It might take a few days before I'm able to test it out.
First things first, importanter things firster. I'm at the beach, so.
But I am sure we will be all over your latest efforts to 'splain what you are trying to do, so THX.
a7
1, 255, 3, 6, 10
1, 100, 1, 2, 20
...
1, 10, 8, 1, 40
it appears that there will be 2 "lists"of "programs" (previously referred to as "lines") separate lists for each of the 2 pumps.
and presumably when the program for a pump completes, the next program is processed, as i suggested in my last post
it wasn't at all obvious that these "programs" are sent, need to be stored and not processes until a "start" signal is received
one question is it looks like the time period for each operation listed in the examples are greater than the previous. in the image, the time for program 1 is 10 sec, program 2 is 20 sec and the last program is 40 sec. are these times the duration that the pump is on for each program or could they be an absolute time since the start signal that the pump is turned off at?
without separating the values in "program" strings, the first values of 1 and 2 identify the pump and which set the program is appended to.
what is the string for the start signal? ("3")?
what is the string for the done signal for each pump? (e.g "1 done")?
The OP has mentioned buttons that would initiate program lists that had been (fully?) received and stored. One per pump line.
The program list of 4 or 5 items comes to an end, that pump line is then idle.
But…
If the pump line start button is pressed while a program list is in progress?
If the pump line start button is pressed after that pump line has become idle?
If one pump line start button is pressed whilst the other is running?
If new program lists start coming in during a pump line run?
Is there a way to pause, interrupt or restart a program list?
I think the answers are all like we won't do that or that can't happen or similar ways of making questions moot at the expense of a fool proof system.
Guess we'll find out.
a7
here's another attempted simulation that reads a sequence of "programs" from an internal array as if read from the serial buffer, queues them and then starts processing and reports when each pump is done
ready
queue: pump-1 - 1,255,3,6,10
queue: pump-1 - 1,100,1,2,20
queue: pump-1 - 1,10,8,1,40
queue: pump-2 - 2,255,8,1,80
queue: pump-2 - 2,50,1,1,40
queue: pump-2 - 2,2,2,2,50
dequeue: 1,255,3,6,10
pumpRun: pump-1 On (1000 ms)
dequeue: 2,255,8,1,80
pumpRun: pump-2 On (8000 ms)
pumpRun: pump-1 Off
dequeue: 1,100,1,2,20
pumpRun: pump-1 On (2000 ms)
pumpRun: pump-1 Off
dequeue: 1,10,8,1,40
pumpRun: pump-1 On (4000 ms)
pumpRun: pump-1 Off
pumpRun: pump-1 is done
pumpRun: pump-2 Off
dequeue: 2,50,1,1,40
pumpRun: pump-2 On (4000 ms)
pumpRun: pump-2 Off
dequeue: 2,2,2,2,50
pumpRun: pump-2 On (5000 ms)
pumpRun: pump-2 Off
pumpRun: pump-2 is done
char s [40];
const char *programs [] = {
"1,255,3,6,10",
"1,100,1,2,20",
"1,10,8,1,40",
"2,255,8,1,80",
"2,50,1,1,40",
"2,2,2,2,50",
"3",
0
};
int progIdx;
// -------------------------------------
int
getProgram (
char *buf,
int size )
{
#if 0
sprintf (s, "getProgram: %d", progIdx);
Serial.println (s);
#endif
if (programs [progIdx]) {
strcpy (buf, programs [progIdx++]);
return strlen(buf);
}
return 0;
}
// ---------------------------------------------------------
char buf [40];
unsigned long msec;
enum { Off = HIGH, On = LOW };
// -----------------------------------------------------------------------------
#define MaxTok 10
char *toks [MaxTok];
int vals [MaxTok];
int
tokenize (
char *s,
const char *sep )
{
unsigned n = 0;
toks [n] = strtok (s, sep);
vals [n] = atoi (toks [n]);
for (n = 1; (toks [n] = strtok (NULL, sep)); n++)
vals [n] = atoi (toks [n]);
return n;
}
// -----------------------------------------------------------------------------
#define NcmdQ 10
struct Q {
char cmdQ [NcmdQ][20];
int head;
int tail;
int cnt;
};
// -------------------------------------
void
queue (
const char *buf,
struct Q *q,
const char *label )
{
sprintf (s, "queue: %s - %s", label, buf);
Serial.println (s);
if (NcmdQ <= q->cnt) {
sprintf (s, "queue: full");
Serial.println (s);
}
memcpy (q->cmdQ [q->head++], buf, strlen(buf));
if (NcmdQ <= q->head)
q->head = 0;
q->cnt++;
};
// -------------------------------------
char *
dequeue (
Q *q)
{
if (0 == q->cnt)
return NULL;
char *buf = q->cmdQ [q->tail++];
if (NcmdQ <= q->tail)
q->tail = 0;
q->cnt--;
sprintf (s, " dequeue: %s", buf);
Serial.println (s);
return buf;
}
// -------------------------------------
struct Pump {
byte pin;
const char *label;
bool active;
Q q;
int pwm;
int solenoid0;
int solenoid1;
unsigned long msecLst;
unsigned long period;
};
Pump pumps [] = {
{ 10, "pump-0" }, // no pump ID 0
{ 11, "pump-1" },
{ 12, "pump-2" },
};
#define Npump (sizeof(pumps)/sizeof(Pump))
// -------------------------------------
void
pumpRun (
char *buf )
{
if (4 > tokenize (buf, ",")) {
sprintf (s, "Error: wrong # of values - %s", s);
Serial.println (s);
return;
}
unsigned idx = vals [0];
Pump *p = & pumps [idx];
p->pwm = vals [1];
p->solenoid0 = vals [2];
p->solenoid1 = vals [3];
p->period = vals [4] * 100L;
p->msecLst = msec;
p->active = true;
digitalWrite (p->pin, On);
sprintf (s, " pumpRun: %s On (%lu ms)", p->label, p->period);
Serial.println (s);
}
// -------------------------------------
void
pumpMonitor (void)
{
Pump *p = pumps;
for (unsigned n = 0; n < Npump; n++, p++) {
if (p->active && (msec - p->msecLst) >= p->period) {
digitalWrite (p->pin, Off);
p->active = false;
sprintf (s, " pumpRun: %s Off", p->label);
Serial.println (s);
char *buf = dequeue (& p->q);
if (NULL != buf)
pumpRun (buf);
else {
sprintf (s, " pumpRun: %s is done", p->label);
Serial.println (s);
}
}
}
}
// -------------------------------------
void
pumpStart (void)
{
Pump *p = pumps;
for (unsigned n = 0; n < Npump; n++, p++) {
if (! p->active) {
char *buf = dequeue (& p->q);
if (NULL != buf)
pumpRun (buf);
}
else {
sprintf (s, "%s: pump %d active", __func__, n);
Serial.println (s);
}
}
}
// -----------------------------------------------------------------------------
void
loop (void)
{
msec = millis ();
pumpMonitor ();
#if 0
if (Serial.available ()) {
int n = Serial.readBytesUntil ('\n', buf, sizeof(buf)-1);
buf [n] = '\0';
pumpReq (buf);
}
#else
if (getProgram (buf, sizeof(buf)-1)) {
unsigned idx = atoi (buf);
if (3 == idx)
pumpStart ();
else
queue (buf, & pumps [idx].q, pumps [idx].label);
}
#endif
}
// -----------------------------------------------------------------------------
void
setup (void)
{
Serial.begin (9600);
Serial.println ("ready");
}
pumpRun ????
don't understand
a characteristic of good programmers is being able to clearly articulate what they are trying to do and what they are doing, both to themselves and others.