mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2026-10-31 13:52:15 +01:00
refactor: name radio jobs as GLOSSARY.md does
The repeater-frame flag was called raw and the ticket was seq, jobSeq, stopSeq or mySeq depending on the file. They are now repeater and ticket (stopTicket, myTicket, lastTicket) throughout, matching the glossary. Renames only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
29d642b6f4
commit
bb6c929bf8
10 changed files with 92 additions and 92 deletions
|
|
@ -12,7 +12,7 @@ static bool admits(uint32_t spaces, bool priority) {
|
|||
return spaces > (priority ? 0u : (uint32_t)TX_RESERVED_SLOTS);
|
||||
}
|
||||
uint32_t RadioScheduler::submit(somfy_tx_job_t &job, bool priority, uint16_t delayMs, uint32_t now) {
|
||||
job.seq = 0;
|
||||
job.ticket = 0;
|
||||
if(this->suspendMask) {
|
||||
ESP_LOGW(TAG, "Radio TX suspended, dropping transmission");
|
||||
return 0;
|
||||
|
|
@ -26,10 +26,10 @@ uint32_t RadioScheduler::submit(somfy_tx_job_t &job, bool priority, uint16_t del
|
|||
return 0;
|
||||
}
|
||||
// 0 means no job so it is skipped on wrap.
|
||||
if(++this->lastSeq == 0) ++this->lastSeq;
|
||||
job.seq = this->lastSeq;
|
||||
if(++this->lastTicket == 0) ++this->lastTicket;
|
||||
job.ticket = this->lastTicket;
|
||||
job.priority = priority;
|
||||
job.front = priority && !job.raw && !this->waitingFor(job.frame.remoteAddress);
|
||||
job.front = priority && !job.repeater && !this->waitingFor(job.frame.remoteAddress);
|
||||
job.queuedAt = now;
|
||||
job.delayMs = delayMs;
|
||||
// Front jobs go out in the order they came, ahead of the back.
|
||||
|
|
@ -41,7 +41,7 @@ uint32_t RadioScheduler::submit(somfy_tx_job_t &job, bool priority, uint16_t del
|
|||
for(uint8_t i = this->count; i > at; i--) this->jobs[i] = this->jobs[i - 1];
|
||||
this->jobs[at] = job;
|
||||
this->count++;
|
||||
return job.seq;
|
||||
return job.ticket;
|
||||
}
|
||||
bool RadioScheduler::hasRoom() const {
|
||||
return !this->suspendMask && admits(TX_JOB_QUEUE_SIZE - this->count, false) && this->outcomesFit();
|
||||
|
|
@ -54,7 +54,7 @@ bool RadioScheduler::outcomesFit() const {
|
|||
}
|
||||
bool RadioScheduler::waitingFor(uint32_t remoteAddress) const {
|
||||
for(uint8_t i = 0; i < this->count; i++) {
|
||||
if(!this->jobs[i].raw && this->jobs[i].frame.remoteAddress == remoteAddress) return true;
|
||||
if(!this->jobs[i].repeater && this->jobs[i].frame.remoteAddress == remoteAddress) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -81,7 +81,7 @@ bool RadioScheduler::next(uint32_t now, somfy_tx_job_t &job, uint32_t &waitMs) {
|
|||
}
|
||||
job = head;
|
||||
this->remove(0);
|
||||
this->taken = job.seq;
|
||||
this->taken = job.ticket;
|
||||
this->takenFlushed = false;
|
||||
this->takenJob = job;
|
||||
return true;
|
||||
|
|
@ -120,7 +120,7 @@ void RadioScheduler::suspend(uint8_t reason, uint32_t now) {
|
|||
void RadioScheduler::resume(uint8_t reason) { this->suspendMask &= ~reason; }
|
||||
void RadioScheduler::post(tx_event_t type, const somfy_tx_job_t &job, uint32_t at) {
|
||||
// Repeater frames don't belong to any of our remotes.
|
||||
if(job.raw) return;
|
||||
if(job.repeater) return;
|
||||
if(this->eventCount >= TX_EVENT_QUEUE_SIZE) {
|
||||
// submit() leaves room for every outcome so this can't happen short of a bug.
|
||||
ESP_LOGE(TAG, "Radio TX event queue full, outcome lost");
|
||||
|
|
@ -130,7 +130,7 @@ void RadioScheduler::post(tx_event_t type, const somfy_tx_job_t &job, uint32_t a
|
|||
evt.type = type;
|
||||
evt.cmd = job.frame.cmd;
|
||||
evt.remoteAddress = job.frame.remoteAddress;
|
||||
evt.seq = job.seq;
|
||||
evt.ticket = job.ticket;
|
||||
evt.at = at;
|
||||
this->eventCount++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
// Not thread safe. The caller serializes every call and passes the time in.
|
||||
class RadioScheduler {
|
||||
public:
|
||||
// Queues a job. Its ticket comes back and is also set in job.seq, 0 when
|
||||
// Queues a job. Its ticket comes back and is also set in job.ticket, 0 when
|
||||
// the queue is full or suspended, or when outcomes aren't collected with
|
||||
// popEvent() fast enough to leave room for its own. A priority job (a stop) may use the
|
||||
// reserved slots and goes ahead of every job queued at the back, unless a
|
||||
|
|
@ -54,7 +54,7 @@ class RadioScheduler {
|
|||
private:
|
||||
somfy_tx_job_t jobs[TX_JOB_QUEUE_SIZE];
|
||||
uint8_t count = 0;
|
||||
uint32_t lastSeq = 0;
|
||||
uint32_t lastTicket = 0;
|
||||
uint8_t suspendMask = 0;
|
||||
// The job taken by next() and not yet ended (0 for none), kept for its
|
||||
// events.
|
||||
|
|
|
|||
|
|
@ -36,14 +36,14 @@ bool stepPosition(float pos, int8_t dir, uint32_t travelMs, uint16_t stepSize, u
|
|||
out = dir > 0 ? std::min(100.0f, pos + step) : std::max(0.0f, pos - step);
|
||||
return true;
|
||||
}
|
||||
void TxHold::mark(uint32_t jobSeq, bool moving, uint32_t now) {
|
||||
if(jobSeq == 0 || this->seq != 0 || moving) return;
|
||||
this->seq = jobSeq;
|
||||
void TxHold::mark(uint32_t ticket, bool moving, uint32_t now) {
|
||||
if(ticket == 0 || this->ticket != 0 || moving) return;
|
||||
this->ticket = ticket;
|
||||
this->since = now;
|
||||
}
|
||||
bool TxHold::release(uint32_t jobSeq) {
|
||||
if(jobSeq == 0 || jobSeq != this->seq) return false;
|
||||
this->seq = 0;
|
||||
bool TxHold::release(uint32_t ticket) {
|
||||
if(ticket == 0 || ticket != this->ticket) return false;
|
||||
this->ticket = 0;
|
||||
return true;
|
||||
}
|
||||
TxHoldCheck TxHold::check(bool moving, uint32_t now, uint32_t timeoutMs) {
|
||||
|
|
@ -57,29 +57,29 @@ TxHoldCheck TxHold::check(bool moving, uint32_t now, uint32_t timeoutMs) {
|
|||
this->clear();
|
||||
return TxHoldCheck::expired;
|
||||
}
|
||||
void ShadeTxState::stopSent(uint32_t seq, uint32_t now, int8_t dir, bool tilt) {
|
||||
this->stopSeq = seq;
|
||||
void ShadeTxState::stopSent(uint32_t ticket, uint32_t now, int8_t dir, bool tilt) {
|
||||
this->stopTicket = ticket;
|
||||
this->stopAt = now;
|
||||
this->stopDir = dir;
|
||||
this->stopTilt = tilt;
|
||||
}
|
||||
void ShadeTxState::setMySent(uint32_t seq, float oldPos, float oldTiltPos) {
|
||||
this->mySeq = seq;
|
||||
void ShadeTxState::setMySent(uint32_t ticket, float oldPos, float oldTiltPos) {
|
||||
this->myTicket = ticket;
|
||||
this->myOldPos = oldPos;
|
||||
this->myOldTiltPos = oldTiltPos;
|
||||
}
|
||||
ShadeTxActions ShadeTxState::onEvent(const somfy_tx_event_t &evt, bool moving) {
|
||||
ShadeTxActions act;
|
||||
if(evt.seq == 0) return act;
|
||||
if(this->hold.release(evt.seq)) {
|
||||
if(evt.ticket == 0) return act;
|
||||
if(this->hold.release(evt.ticket)) {
|
||||
if(evt.type == tx_event_t::started) {
|
||||
act.startMovement = true;
|
||||
act.startAt = evt.at;
|
||||
}
|
||||
else act.cancelMovement = true;
|
||||
}
|
||||
if(this->mySeq == evt.seq && evt.type != tx_event_t::started) {
|
||||
this->mySeq = 0;
|
||||
if(this->myTicket == evt.ticket && evt.type != tx_event_t::started) {
|
||||
this->myTicket = 0;
|
||||
// The motor only stores the favorite when it gets the whole long press.
|
||||
if(evt.type == tx_event_t::finished) act.commitMy = true;
|
||||
else {
|
||||
|
|
@ -88,8 +88,8 @@ ShadeTxActions ShadeTxState::onEvent(const somfy_tx_event_t &evt, bool moving) {
|
|||
act.myOldTiltPos = this->myOldTiltPos;
|
||||
}
|
||||
}
|
||||
if(this->stopSeq == evt.seq) {
|
||||
this->stopSeq = 0;
|
||||
if(this->stopTicket == evt.ticket) {
|
||||
this->stopTicket = 0;
|
||||
// Unless something has moved the shade since, the motor never got the stop
|
||||
// and is still running.
|
||||
if(evt.type == tx_event_t::dropped && !moving) {
|
||||
|
|
|
|||
|
|
@ -30,20 +30,20 @@ enum class TxHoldCheck {
|
|||
// The radio job that set an idle shade moving. Its simulated movement is held
|
||||
// until the job goes on air, since that is when the motor starts.
|
||||
struct TxHold {
|
||||
uint32_t seq = 0; // 0 when nothing is held.
|
||||
uint32_t ticket = 0; // 0 when nothing is held.
|
||||
uint32_t since = 0; // millis() when the hold started.
|
||||
// Holds for job seq unless the shade was already moving (its motor carries on
|
||||
// Holds for job ticket unless the shade was already moving (its motor carries on
|
||||
// with the earlier command) or a job is already held. The first job held is
|
||||
// the one that starts the motor. A command sent while processing another
|
||||
// registers before it: for a simMy shade My/Favorite queues its Up/Down from
|
||||
// moveToMyPosition() first, and that Up/Down is what starts a motor with no
|
||||
// favorite of its own, so the outer My/Favorite is ignored on purpose.
|
||||
void mark(uint32_t jobSeq, bool moving, uint32_t now);
|
||||
// Ends the hold when jobSeq is the held job. True when it was.
|
||||
bool release(uint32_t jobSeq);
|
||||
bool held() const { return this->seq != 0; }
|
||||
void mark(uint32_t ticket, bool moving, uint32_t now);
|
||||
// Ends the hold when ticket is the held job. True when it was.
|
||||
bool release(uint32_t ticket);
|
||||
bool held() const { return this->ticket != 0; }
|
||||
bool timedOut(uint32_t now, uint32_t timeoutMs) const { return now - this->since >= timeoutMs; }
|
||||
void clear() { this->seq = 0; }
|
||||
void clear() { this->ticket = 0; }
|
||||
// Drops a hold on a shade the command didn't set moving, or one that has
|
||||
// waited timeoutMs for the radio.
|
||||
TxHoldCheck check(bool moving, uint32_t now, uint32_t timeoutMs);
|
||||
|
|
@ -77,17 +77,17 @@ struct ShadeTxState {
|
|||
TxHold hold;
|
||||
// Stop sent when the simulated target was reached. If it never goes on
|
||||
// air the motor runs on to its end limit. 0 once an event for it arrived.
|
||||
uint32_t stopSeq = 0;
|
||||
uint32_t stopTicket = 0;
|
||||
uint32_t stopAt = 0;
|
||||
int8_t stopDir = 0;
|
||||
bool stopTilt = false;
|
||||
// Command telling the motor to store the favorite. The favorite is only
|
||||
// committed once all of it is on air and restored if it never is.
|
||||
uint32_t mySeq = 0;
|
||||
uint32_t myTicket = 0;
|
||||
float myOldPos = -1.0f;
|
||||
float myOldTiltPos = -1.0f;
|
||||
void stopSent(uint32_t seq, uint32_t now, int8_t dir, bool tilt);
|
||||
void setMySent(uint32_t seq, float oldPos, float oldTiltPos);
|
||||
void stopSent(uint32_t ticket, uint32_t now, int8_t dir, bool tilt);
|
||||
void setMySent(uint32_t ticket, float oldPos, float oldTiltPos);
|
||||
// What to do about evt. moving is whether the shade is moving now.
|
||||
ShadeTxActions onEvent(const somfy_tx_event_t &evt, bool moving);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2295,12 +2295,12 @@ void SomfyShade::setTiltMovement(int8_t dir) {
|
|||
this->emitState();
|
||||
}
|
||||
}
|
||||
void SomfyShade::markTxPending(uint32_t seq) {
|
||||
void SomfyShade::markTxPending(uint32_t ticket) {
|
||||
// This runs before the caller sets the new target so direction still says
|
||||
// whether the shade was moving. A reversal is simulated as soon as it is
|
||||
// queued even though the motor turns once it is on air. See TxHold::mark
|
||||
// for which of several queued commands is held.
|
||||
this->tx.hold.mark(seq, this->direction != 0 || this->tiltDirection != 0, millis());
|
||||
this->tx.hold.mark(ticket, this->direction != 0 || this->tiltDirection != 0, millis());
|
||||
}
|
||||
void SomfyShade::processTxEvent(const somfy_tx_event_t &evt) {
|
||||
const ShadeTxActions act = this->tx.onEvent(evt, this->direction != 0 || this->tiltDirection != 0);
|
||||
|
|
@ -3078,10 +3078,10 @@ void SomfyShadeController::processFrame(somfy_frame_t &frame, bool internal) {
|
|||
if(this->shades[i].getShadeId() != 255) this->shades[i].processFrame(frame, internal);
|
||||
}
|
||||
}
|
||||
void SomfyShadeController::markTxPending(uint32_t remoteAddress, uint32_t seq) {
|
||||
void SomfyShadeController::markTxPending(uint32_t remoteAddress, uint32_t ticket) {
|
||||
for(uint8_t i = 0; i < SOMFY_MAX_SHADES; i++) {
|
||||
SomfyShade *shade = &this->shades[i];
|
||||
if(shade->getShadeId() != 255 && shade->findRemote(remoteAddress)) shade->markTxPending(seq);
|
||||
if(shade->getShadeId() != 255 && shade->findRemote(remoteAddress)) shade->markTxPending(ticket);
|
||||
}
|
||||
// Group commands move their member shades through processInternalCommand.
|
||||
for(uint8_t i = 0; i < SOMFY_MAX_GROUPS; i++) {
|
||||
|
|
@ -3090,7 +3090,7 @@ void SomfyShadeController::markTxPending(uint32_t remoteAddress, uint32_t seq) {
|
|||
for(uint8_t j = 0; j < SOMFY_MAX_GROUPED_SHADES; j++) {
|
||||
if(group->linkedShades[j] == 0) continue;
|
||||
SomfyShade *shade = this->getShadeById(group->linkedShades[j]);
|
||||
if(shade) shade->markTxPending(seq);
|
||||
if(shade) shade->markTxPending(ticket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4618,7 +4618,7 @@ void Transceiver::loop() {
|
|||
if(tx_queue.length > 0 && millis() > tx_queue.delay_time && somfy_rx.cpt_synchro_hw == 0 &&
|
||||
(this->txSuspended() || this->txHasRoom())) {
|
||||
somfy_tx_job_t job;
|
||||
job.raw = true;
|
||||
job.repeater = true;
|
||||
tx_queue.peek(&job.tx);
|
||||
{
|
||||
somfy_tx_t &tx = job.tx;
|
||||
|
|
@ -4685,7 +4685,7 @@ bool Transceiver::transmitJob(somfy_tx_job_t &job) {
|
|||
bool keep;
|
||||
{
|
||||
TxQueueLock lock;
|
||||
keep = this->sched.keepSending(job.seq);
|
||||
keep = this->sched.keepSending(job.ticket);
|
||||
}
|
||||
// Stop early when flushed or when someone is waiting to reconfigure the
|
||||
// radio so they get it within a frame.
|
||||
|
|
@ -4702,7 +4702,7 @@ bool Transceiver::transmitJob(somfy_tx_job_t &job) {
|
|||
return complete;
|
||||
}
|
||||
void Transceiver::runJob(somfy_tx_job_t &job) {
|
||||
if(job.raw) {
|
||||
if(job.repeater) {
|
||||
// Don't step on a remote that is transmitting right now.
|
||||
for(uint32_t waited = 0; rxInProgress() && waited < TX_RX_IDLE_WAIT; waited += 5)
|
||||
vTaskDelay(pdMS_TO_TICKS(5));
|
||||
|
|
@ -4713,12 +4713,12 @@ void Transceiver::runJob(somfy_tx_job_t &job) {
|
|||
{
|
||||
// The queue may have been flushed while we waited.
|
||||
TxQueueLock qlock;
|
||||
start = this->sched.start(job.seq, millis());
|
||||
start = this->sched.start(job.ticket, millis());
|
||||
}
|
||||
if(!start) return;
|
||||
const bool complete = this->transmitJob(job);
|
||||
TxQueueLock qlock;
|
||||
this->sched.ended(job.seq, complete, millis());
|
||||
this->sched.ended(job.ticket, complete, millis());
|
||||
}
|
||||
// Give the motors a full frame beat between separate transmissions.
|
||||
vTaskDelay(pdMS_TO_TICKS(TX_QUEUE_DELAY));
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ class SomfyShade : public SomfyRemote {
|
|||
// The shade itself or the linked remote with this address, else nullptr.
|
||||
SomfyRemote *findRemote(uint32_t address);
|
||||
void processInternalCommand(somfy_commands cmd, uint8_t repeat = 1);
|
||||
void markTxPending(uint32_t seq);
|
||||
void markTxPending(uint32_t ticket);
|
||||
void processTxEvent(const somfy_tx_event_t &evt);
|
||||
void setTiltMovement(int8_t dir);
|
||||
void setMovement(int8_t dir);
|
||||
|
|
@ -524,7 +524,7 @@ class SomfyShadeController {
|
|||
// Returns the radio job's ticket, 0 when the radio can't take it.
|
||||
uint32_t sendFrame(somfy_frame_t &frame, uint8_t repeats = 0, uint16_t delayMs = 0, bool priority = false);
|
||||
void processFrame(somfy_frame_t &frame, bool internal = false);
|
||||
void markTxPending(uint32_t remoteAddress, uint32_t seq);
|
||||
void markTxPending(uint32_t remoteAddress, uint32_t ticket);
|
||||
void processTxEvent(const somfy_tx_event_t &evt);
|
||||
void emitState(uint8_t num = 255);
|
||||
void publish();
|
||||
|
|
|
|||
|
|
@ -57,11 +57,11 @@ struct somfy_tx_job_t {
|
|||
somfy_frame_t frame;
|
||||
uint8_t repeats = 0; // Number of repeat frames after the first frame.
|
||||
uint8_t firstRepeat = 1; // 80-bit repeat counter used for the first repeat frame.
|
||||
bool raw = false; // Repeater frame. Waits for the receiver to be idle.
|
||||
bool repeater = false; // Repeater frame. Waits for the receiver to be idle.
|
||||
// Set by RadioScheduler::submit().
|
||||
bool priority = false; // May use the reserved slots.
|
||||
bool front = false; // Queued ahead of the back. Only for priority jobs.
|
||||
uint32_t seq = 0; // Ticket the job's events are matched up by.
|
||||
uint32_t ticket = 0; // Matches the job's events up with it.
|
||||
uint32_t queuedAt = 0; // millis() when it was submitted.
|
||||
uint16_t delayMs = 0; // How long it waits after it was queued and after the job ahead of it ended.
|
||||
};
|
||||
|
|
@ -76,7 +76,7 @@ struct somfy_tx_event_t {
|
|||
tx_event_t type = tx_event_t::started;
|
||||
somfy_commands cmd = somfy_commands::My;
|
||||
uint32_t remoteAddress = 0;
|
||||
uint32_t seq = 0;
|
||||
uint32_t ticket = 0;
|
||||
uint32_t at = 0; // millis() when the job started or was dropped.
|
||||
};
|
||||
// Encodes the first frame of a transmission into the job. Encoding here keeps
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ static void test_txhold_idle_shade_is_held() {
|
|||
TxHold hold;
|
||||
hold.mark(7, false, 1000);
|
||||
TEST_ASSERT_TRUE(hold.held());
|
||||
TEST_ASSERT_EQUAL_UINT32(7, hold.seq);
|
||||
TEST_ASSERT_EQUAL_UINT32(7, hold.ticket);
|
||||
TEST_ASSERT_EQUAL_UINT32(1000, hold.since);
|
||||
}
|
||||
static void test_txhold_moving_shade_is_not_held() {
|
||||
|
|
@ -171,7 +171,7 @@ static void test_txhold_first_job_wins() {
|
|||
TxHold hold;
|
||||
hold.mark(11, false, 1000);
|
||||
hold.mark(10, false, 1005);
|
||||
TEST_ASSERT_EQUAL_UINT32(11, hold.seq);
|
||||
TEST_ASSERT_EQUAL_UINT32(11, hold.ticket);
|
||||
TEST_ASSERT_EQUAL_UINT32(1000, hold.since);
|
||||
TEST_ASSERT_FALSE(hold.release(10));
|
||||
TEST_ASSERT_TRUE(hold.held());
|
||||
|
|
@ -192,7 +192,7 @@ static void test_txhold_new_hold_after_release() {
|
|||
hold.mark(5, false, 0);
|
||||
hold.release(5);
|
||||
hold.mark(6, false, 200);
|
||||
TEST_ASSERT_EQUAL_UINT32(6, hold.seq);
|
||||
TEST_ASSERT_EQUAL_UINT32(6, hold.ticket);
|
||||
TEST_ASSERT_EQUAL_UINT32(200, hold.since);
|
||||
}
|
||||
static void test_txhold_times_out() {
|
||||
|
|
|
|||
|
|
@ -24,15 +24,15 @@ static uint32_t runNext(RadioScheduler &s, uint32_t now = 0) {
|
|||
somfy_tx_job_t job;
|
||||
uint32_t waitMs;
|
||||
if(!s.next(now, job, waitMs)) return 0;
|
||||
if(!s.start(job.seq, now)) return job.seq;
|
||||
s.ended(job.seq, true, now);
|
||||
return job.seq;
|
||||
if(!s.start(job.ticket, now)) return job.ticket;
|
||||
s.ended(job.ticket, true, now);
|
||||
return job.ticket;
|
||||
}
|
||||
static void assertEvent(RadioScheduler &s, tx_event_t type, uint32_t ticket) {
|
||||
somfy_tx_event_t evt;
|
||||
TEST_ASSERT_TRUE_MESSAGE(s.popEvent(evt), "expected another event");
|
||||
TEST_ASSERT_EQUAL_UINT8((uint8_t)type, (uint8_t)evt.type);
|
||||
TEST_ASSERT_EQUAL_UINT32(ticket, evt.seq);
|
||||
TEST_ASSERT_EQUAL_UINT32(ticket, evt.ticket);
|
||||
}
|
||||
static void assertNoEvents(RadioScheduler &s) {
|
||||
somfy_tx_event_t evt;
|
||||
|
|
@ -61,7 +61,7 @@ static void test_tickets_are_distinct_and_set_in_the_job() {
|
|||
RadioScheduler s;
|
||||
somfy_tx_job_t job = makeJob(REMOTE_A);
|
||||
const uint32_t a = s.submit(job, false, 0, 0);
|
||||
TEST_ASSERT_EQUAL_UINT32(a, job.seq);
|
||||
TEST_ASSERT_EQUAL_UINT32(a, job.ticket);
|
||||
TEST_ASSERT_NOT_EQUAL(a, submit(s, REMOTE_A));
|
||||
}
|
||||
static void test_nothing_waiting_sleeps_until_woken() {
|
||||
|
|
@ -102,7 +102,7 @@ static void test_stop_goes_ahead_once_its_remote_is_on_air() {
|
|||
somfy_tx_job_t job;
|
||||
uint32_t waitMs;
|
||||
TEST_ASSERT_TRUE(s.next(0, job, waitMs));
|
||||
TEST_ASSERT_EQUAL_UINT32(up, job.seq);
|
||||
TEST_ASSERT_EQUAL_UINT32(up, job.ticket);
|
||||
// The remote's frame is already going out so the stop can't overtake it.
|
||||
const uint32_t stop = submit(s, REMOTE_A, 0, true);
|
||||
s.start(up, 0);
|
||||
|
|
@ -151,9 +151,9 @@ static void test_a_refused_job_has_no_ticket() {
|
|||
RadioScheduler s;
|
||||
for(uint8_t i = 0; i < TX_JOB_QUEUE_SIZE - TX_RESERVED_SLOTS; i++) submit(s, REMOTE_B);
|
||||
somfy_tx_job_t job = makeJob(REMOTE_A);
|
||||
job.seq = 99;
|
||||
job.ticket = 99;
|
||||
TEST_ASSERT_EQUAL_UINT32(0, s.submit(job, false, 0, 0));
|
||||
TEST_ASSERT_EQUAL_UINT32(0, job.seq);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, job.ticket);
|
||||
}
|
||||
static void test_taking_a_job_frees_its_slot() {
|
||||
RadioScheduler s;
|
||||
|
|
@ -175,7 +175,7 @@ static void test_delayed_job_waits_until_due() {
|
|||
TEST_ASSERT_FALSE(s.next(1400, job, waitMs));
|
||||
TEST_ASSERT_EQUAL_UINT32(100, waitMs);
|
||||
TEST_ASSERT_TRUE(s.next(1500, job, waitMs));
|
||||
TEST_ASSERT_EQUAL_UINT32(a, job.seq);
|
||||
TEST_ASSERT_EQUAL_UINT32(a, job.ticket);
|
||||
}
|
||||
static void test_delayed_job_holds_up_the_jobs_behind_it() {
|
||||
RadioScheduler s;
|
||||
|
|
@ -208,7 +208,7 @@ static void test_delay_counts_from_the_job_ahead_going_off_air() {
|
|||
TEST_ASSERT_FALSE(s.next(350, job, waitMs));
|
||||
TEST_ASSERT_EQUAL_UINT32(100, waitMs);
|
||||
TEST_ASSERT_TRUE(s.next(450, job, waitMs));
|
||||
TEST_ASSERT_EQUAL_UINT32(setMy, job.seq);
|
||||
TEST_ASSERT_EQUAL_UINT32(setMy, job.ticket);
|
||||
}
|
||||
static void test_delay_ignores_a_job_that_ended_before_it_was_queued() {
|
||||
RadioScheduler s;
|
||||
|
|
@ -220,7 +220,7 @@ static void test_delay_ignores_a_job_that_ended_before_it_was_queued() {
|
|||
TEST_ASSERT_FALSE(s.next(100, job, waitMs));
|
||||
TEST_ASSERT_EQUAL_UINT32(200, waitMs);
|
||||
TEST_ASSERT_TRUE(s.next(300, job, waitMs));
|
||||
TEST_ASSERT_EQUAL_UINT32(a, job.seq);
|
||||
TEST_ASSERT_EQUAL_UINT32(a, job.ticket);
|
||||
}
|
||||
static void test_delay_after_a_job_ended_across_millis_wrap() {
|
||||
RadioScheduler s;
|
||||
|
|
@ -234,7 +234,7 @@ static void test_delay_after_a_job_ended_across_millis_wrap() {
|
|||
TEST_ASSERT_FALSE(s.next(0x100, job, waitMs));
|
||||
TEST_ASSERT_EQUAL_UINT32(0x80, waitMs);
|
||||
TEST_ASSERT_TRUE(s.next(0x180, job, waitMs));
|
||||
TEST_ASSERT_EQUAL_UINT32(setMy, job.seq);
|
||||
TEST_ASSERT_EQUAL_UINT32(setMy, job.ticket);
|
||||
}
|
||||
static void test_stop_waits_behind_its_remotes_delayed_job() {
|
||||
// The favorite's long press holds a rolling code, so the stop can't go first.
|
||||
|
|
@ -255,7 +255,7 @@ static void test_delay_across_millis_wrap() {
|
|||
TEST_ASSERT_FALSE(s.next(0x50, job, waitMs));
|
||||
TEST_ASSERT_EQUAL_UINT32(0xB0, waitMs);
|
||||
TEST_ASSERT_TRUE(s.next(0x100, job, waitMs));
|
||||
TEST_ASSERT_EQUAL_UINT32(a, job.seq);
|
||||
TEST_ASSERT_EQUAL_UINT32(a, job.ticket);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
|
|
@ -273,7 +273,7 @@ static void test_job_reports_started_then_finished() {
|
|||
somfy_tx_event_t evt;
|
||||
TEST_ASSERT_TRUE(s.popEvent(evt));
|
||||
TEST_ASSERT_EQUAL_UINT8((uint8_t)tx_event_t::started, (uint8_t)evt.type);
|
||||
TEST_ASSERT_EQUAL_UINT32(a, evt.seq);
|
||||
TEST_ASSERT_EQUAL_UINT32(a, evt.ticket);
|
||||
TEST_ASSERT_EQUAL_UINT32(20, evt.at);
|
||||
TEST_ASSERT_EQUAL_UINT32(REMOTE_A, evt.remoteAddress);
|
||||
TEST_ASSERT_EQUAL_UINT8((uint8_t)somfy_commands::Up, (uint8_t)evt.cmd);
|
||||
|
|
@ -340,18 +340,18 @@ static void test_every_job_gets_one_outcome_across_a_flush() {
|
|||
somfy_tx_job_t job;
|
||||
uint32_t waitMs;
|
||||
s.next(0, job, waitMs);
|
||||
s.start(job.seq, 0);
|
||||
s.start(job.ticket, 0);
|
||||
s.flush(0);
|
||||
// Jobs queued after the flush are unaffected by it.
|
||||
for(uint8_t i = 3; i < 6; i++) tickets[i] = submit(s, REMOTE_B + i);
|
||||
s.ended(job.seq, s.keepSending(job.seq), 0);
|
||||
s.ended(job.ticket, s.keepSending(job.ticket), 0);
|
||||
while(runNext(s)) {}
|
||||
uint8_t outcomes[6] = {};
|
||||
somfy_tx_event_t evt;
|
||||
while(s.popEvent(evt)) {
|
||||
if(evt.type == tx_event_t::started) continue;
|
||||
for(uint8_t i = 0; i < 6; i++)
|
||||
if(tickets[i] == evt.seq) outcomes[i]++;
|
||||
if(tickets[i] == evt.ticket) outcomes[i]++;
|
||||
}
|
||||
for(uint8_t i = 0; i < 6; i++) TEST_ASSERT_EQUAL_UINT8(1, outcomes[i]);
|
||||
}
|
||||
|
|
@ -399,7 +399,7 @@ static void test_flush_reports_every_drop_when_events_arent_collected() {
|
|||
while(s.popEvent(evt)) {
|
||||
if(evt.type == tx_event_t::started) continue;
|
||||
for(uint8_t i = 0; i < n; i++)
|
||||
if(tickets[i] == evt.seq) outcomes[i]++;
|
||||
if(tickets[i] == evt.ticket) outcomes[i]++;
|
||||
}
|
||||
for(uint8_t i = 0; i < n; i++) TEST_ASSERT_EQUAL_UINT8(1, outcomes[i]);
|
||||
}
|
||||
|
|
@ -444,13 +444,13 @@ static void test_resume_needs_every_reason_cleared() {
|
|||
static void test_repeater_frames_report_nothing() {
|
||||
RadioScheduler s;
|
||||
somfy_tx_job_t job = makeJob(REMOTE_A);
|
||||
job.raw = true;
|
||||
job.repeater = true;
|
||||
const uint32_t r = s.submit(job, false, 0, 0);
|
||||
TEST_ASSERT_NOT_EQUAL(0, r);
|
||||
TEST_ASSERT_EQUAL_UINT32(r, runNext(s));
|
||||
submit(s, REMOTE_B);
|
||||
job = makeJob(REMOTE_A);
|
||||
job.raw = true;
|
||||
job.repeater = true;
|
||||
s.submit(job, false, 0, 0);
|
||||
s.flush(0);
|
||||
somfy_tx_event_t evt;
|
||||
|
|
@ -463,7 +463,7 @@ static void test_repeater_frame_doesnt_hold_back_a_stop() {
|
|||
// order.
|
||||
RadioScheduler s;
|
||||
somfy_tx_job_t job = makeJob(REMOTE_A);
|
||||
job.raw = true;
|
||||
job.repeater = true;
|
||||
const uint32_t r = s.submit(job, false, 0, 0);
|
||||
const uint32_t stop = submit(s, REMOTE_A, 0, true);
|
||||
TEST_ASSERT_EQUAL_UINT32(stop, runNext(s));
|
||||
|
|
|
|||
|
|
@ -8,17 +8,17 @@ static const int8_t UP = -1;
|
|||
static const bool IDLE = false;
|
||||
static const bool MOVING = true;
|
||||
|
||||
static somfy_tx_event_t evt(tx_event_t type, uint32_t seq, uint32_t at = 0) {
|
||||
static somfy_tx_event_t evt(tx_event_t type, uint32_t ticket, uint32_t at = 0) {
|
||||
somfy_tx_event_t e;
|
||||
e.type = type;
|
||||
e.seq = seq;
|
||||
e.ticket = ticket;
|
||||
e.at = at;
|
||||
return e;
|
||||
}
|
||||
// A shade whose idle motor was set moving by radio job seq.
|
||||
static ShadeTxState heldBy(uint32_t seq) {
|
||||
// A shade whose idle motor was set moving by radio job ticket.
|
||||
static ShadeTxState heldBy(uint32_t ticket) {
|
||||
ShadeTxState tx;
|
||||
tx.hold.mark(seq, false, 0);
|
||||
tx.hold.mark(ticket, false, 0);
|
||||
return tx;
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ static void test_favorite_started_waits_for_the_end() {
|
|||
tx.setMySent(9, 40.0f, 10.0f);
|
||||
ShadeTxActions act = tx.onEvent(evt(tx_event_t::started, 9), IDLE);
|
||||
TEST_ASSERT_FALSE(act.any());
|
||||
TEST_ASSERT_EQUAL_UINT32(9, tx.mySeq);
|
||||
TEST_ASSERT_EQUAL_UINT32(9, tx.myTicket);
|
||||
}
|
||||
static void test_favorite_finished_is_committed() {
|
||||
ShadeTxState tx;
|
||||
|
|
@ -72,7 +72,7 @@ static void test_favorite_finished_is_committed() {
|
|||
ShadeTxActions act = tx.onEvent(evt(tx_event_t::finished, 9), IDLE);
|
||||
TEST_ASSERT_TRUE(act.commitMy);
|
||||
TEST_ASSERT_FALSE(act.restoreMy);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, tx.mySeq);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, tx.myTicket);
|
||||
}
|
||||
static void test_favorite_aborted_restores_the_previous_one() {
|
||||
// The motor only stores the favorite when it gets the whole long press.
|
||||
|
|
@ -84,7 +84,7 @@ static void test_favorite_aborted_restores_the_previous_one() {
|
|||
TEST_ASSERT_FALSE(act.commitMy);
|
||||
ASSERT_POS(40.0f, act.myOldPos);
|
||||
ASSERT_POS(10.0f, act.myOldTiltPos);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, tx.mySeq);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, tx.myTicket);
|
||||
}
|
||||
static void test_favorite_dropped_restores_the_previous_one() {
|
||||
ShadeTxState tx;
|
||||
|
|
@ -107,7 +107,7 @@ static void test_stop_dropped_runs_on_to_the_limit() {
|
|||
TEST_ASSERT_FALSE(act.limitTilt);
|
||||
// From when the motor should have stopped, not when the drop was reported.
|
||||
TEST_ASSERT_EQUAL_UINT32(5000, act.limitSince);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, tx.stopSeq);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, tx.stopTicket);
|
||||
}
|
||||
static void test_tilt_stop_dropped_runs_the_tilt_on() {
|
||||
ShadeTxState tx;
|
||||
|
|
@ -124,13 +124,13 @@ static void test_stop_dropped_after_moving_again_does_nothing() {
|
|||
tx.stopSent(12, 5000, DOWN, false);
|
||||
ShadeTxActions act = tx.onEvent(evt(tx_event_t::dropped, 12), MOVING);
|
||||
TEST_ASSERT_FALSE(act.any());
|
||||
TEST_ASSERT_EQUAL_UINT32(0, tx.stopSeq);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, tx.stopTicket);
|
||||
}
|
||||
static void test_stop_on_air_does_nothing() {
|
||||
ShadeTxState tx;
|
||||
tx.stopSent(12, 5000, DOWN, false);
|
||||
TEST_ASSERT_FALSE(tx.onEvent(evt(tx_event_t::started, 12), IDLE).any());
|
||||
TEST_ASSERT_EQUAL_UINT32(0, tx.stopSeq);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, tx.stopTicket);
|
||||
// Nothing is waiting on it any more.
|
||||
TEST_ASSERT_FALSE(tx.onEvent(evt(tx_event_t::dropped, 12), IDLE).any());
|
||||
}
|
||||
|
|
@ -153,7 +153,7 @@ static void test_one_event_for_the_held_job_and_the_favorite() {
|
|||
TEST_ASSERT_TRUE(act.cancelMovement);
|
||||
TEST_ASSERT_TRUE(act.restoreMy);
|
||||
TEST_ASSERT_FALSE(tx.hold.held());
|
||||
TEST_ASSERT_EQUAL_UINT32(0, tx.mySeq);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, tx.myTicket);
|
||||
}
|
||||
static void test_seq_zero_is_ignored() {
|
||||
ShadeTxState tx;
|
||||
|
|
@ -168,9 +168,9 @@ static void test_other_jobs_are_ignored() {
|
|||
tx.stopSent(12, 5000, DOWN, false);
|
||||
TEST_ASSERT_FALSE(tx.onEvent(evt(tx_event_t::dropped, 8), IDLE).any());
|
||||
TEST_ASSERT_FALSE(tx.onEvent(evt(tx_event_t::finished, 13), IDLE).any());
|
||||
TEST_ASSERT_EQUAL_UINT32(7, tx.hold.seq);
|
||||
TEST_ASSERT_EQUAL_UINT32(9, tx.mySeq);
|
||||
TEST_ASSERT_EQUAL_UINT32(12, tx.stopSeq);
|
||||
TEST_ASSERT_EQUAL_UINT32(7, tx.hold.ticket);
|
||||
TEST_ASSERT_EQUAL_UINT32(9, tx.myTicket);
|
||||
TEST_ASSERT_EQUAL_UINT32(12, tx.stopTicket);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue