Skip to content

Commit

Permalink
Non-blocking, configurable beep (#143)
Browse files Browse the repository at this point in the history
* non-blocking beep

* Update CHANGELOG.md

* Update CHANGELOG.md

* configurable beeper

* Fix type in beeper.h
  • Loading branch information
t0mpr1c3 authored Oct 17, 2023
1 parent 0253467 commit df5c27c
Show file tree
Hide file tree
Showing 23 changed files with 243 additions and 92 deletions.
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## 1.0.0 / Unreleased

* Migrate to AYAB API v6
* Remove dependency on SerialCommand library
* Add informative error codes
* Add support for garter carriage
* Add support for KH270
* Allow carriage to start on the right-hand side moving left
* Add run-time hardware tests
* Fix intermittent patterning errors
* Change end-of-line beep to be non-blocking so that knitting can continue during beep
* Migrate to generic firmware from machine-specific versions
* Migrate to semantic versioning
* Change libraries to submodules
* Remove dependency on SerialCommand library
* Add unit tests that can run in the absence of the hardware
* Add GPLv3 license
* Add informative error codes
* Add development environment documentation to README
* Add firmware update instructions to README
* Add CHANGELOG.md
Expand Down
88 changes: 72 additions & 16 deletions src/ayab/beeper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,44 +28,100 @@
#include "beeper.h"
#include "board.h"

/*!
* Initialize beeper
*/
void Beeper::init(bool enabled) {
m_currentState = BeepState::Idle;
m_enabled = enabled;
}

/*!
* Get beeper enabled flag
*/
bool Beeper::enabled() {
return m_enabled;
}

/*!
* Get beeper state
*/
BeepState Beeper::getState() {
return m_currentState;
}

/*!
* Beep to indicate readiness
*/
void Beeper::ready() {
beep(BEEP_NUM_READY);
if (m_enabled) {
beep(BEEP_NUM_READY);
}
}

/*!
* Beep to indicate the end of a line
*/
void Beeper::finishedLine() {
beep(BEEP_NUM_FINISHEDLINE);
if (m_enabled) {
beep(BEEP_NUM_FINISHEDLINE);
}
}

/*!
* Beep to indicate the end the knitting pattern
*/
void Beeper::endWork() {
beep(BEEP_NUM_ENDWORK);
if (m_enabled) {
beep(BEEP_NUM_ENDWORK);
}
}

/* Private Methods */

/*!
* Generic beep function.
*
* /param length number of beeps
* Beep handler scheduled from main loop
*/
void Beeper::beep(uint8_t length) const {

for (uint8_t i = 0U; i < length; ++i) {

void Beeper::schedule() {
long unsigned int now = millis();
switch (m_currentState) {
case BeepState::On:
analogWrite(PIEZO_PIN, BEEP_ON_DUTY);
delay(BEEP_DELAY);

m_currentState = BeepState::Wait;
m_nextState = BeepState::Off;
m_nextTime = now + BEEP_DELAY;
break;
case BeepState::Off:
analogWrite(PIEZO_PIN, BEEP_OFF_DUTY);
delay(BEEP_DELAY);
m_currentState = BeepState::Wait;
m_nextState = BeepState::On;
m_nextTime = now + BEEP_DELAY;
m_repeat--;
break;
case BeepState::Wait:
if (now >= m_nextTime) {
if (m_repeat == 0) {
analogWrite(PIEZO_PIN, BEEP_NO_DUTY);
m_currentState = BeepState::Idle;
} else {
m_currentState = m_nextState;
}
}
break;
case BeepState::Idle:
default:
break;
}
}

/* Private Methods */

analogWrite(PIEZO_PIN, BEEP_NO_DUTY);
/*!
* Generic beep function.
*
* /param repeats number of beeps
*/
void Beeper::beep(uint8_t repeats) {
m_repeat = repeats;
m_currentState = BeepState::Wait;
m_nextState = BeepState::On;
m_nextTime = millis();
}
24 changes: 22 additions & 2 deletions src/ayab/beeper.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@

#include <Arduino.h>

constexpr uint8_t BEEP_DELAY = 50U; // ms
enum class BeepState : unsigned char {Idle, Wait, On, Off};

constexpr unsigned int BEEP_DELAY = 50U; // ms

constexpr uint8_t BEEP_NUM_READY = 5U;
constexpr uint8_t BEEP_NUM_FINISHEDLINE = 3U;
Expand All @@ -41,9 +43,13 @@ class BeeperInterface {
virtual ~BeeperInterface() = default;

// any methods that need to be mocked should go here
virtual void init(bool enabled) = 0;
virtual bool enabled() = 0;
virtual BeepState getState() = 0;
virtual void ready() = 0;
virtual void finishedLine() = 0;
virtual void endWork() = 0;
virtual void schedule() = 0;
};

// Container class for the static methods that control the beeper.
Expand All @@ -60,22 +66,36 @@ class GlobalBeeper final {
// pointer to global instance whose methods are implemented
static BeeperInterface *m_instance;

static void init(bool enabled);
static bool enabled();
static BeepState getState();
static void ready();
static void finishedLine();
static void endWork();
static void schedule();
};

/*!
* \brief Class to actuate a beeper connected to PIEZO_PIN
*/
class Beeper : public BeeperInterface {
public:
void init(bool enabled) final;
bool enabled() final;
BeepState getState() final;
void ready() final;
void finishedLine() final;
void endWork() final;
void schedule() final;

private:
void beep(uint8_t length) const;
void beep(uint8_t repeats);

BeepState m_currentState;
BeepState m_nextState;
unsigned long m_nextTime;
uint8_t m_repeat;
bool m_enabled;
};

#endif // BEEPER_H_
2 changes: 1 addition & 1 deletion src/ayab/board.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ constexpr uint8_t I2Caddr_sol1_8 = 0x0U; ///< I2C Address of solenoids 1 - 8
constexpr uint8_t I2Caddr_sol9_16 = 0x1U; ///< I2C Address of solenoids 9 - 16

// TODO(Who?): Optimize Delay for various Arduino Models
constexpr uint16_t START_KNITTING_DELAY = 2000U;
constexpr uint16_t START_KNITTING_DELAY = 2000U; // ms

// Determine board type
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
Expand Down
5 changes: 3 additions & 2 deletions src/ayab/com.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ void Com::h_reqStart(const uint8_t *buffer, size_t size) {

uint8_t startNeedle = buffer[1];
uint8_t stopNeedle = buffer[2];
auto continuousReportingEnabled = static_cast<bool>(buffer[3]);
auto continuousReportingEnabled = static_cast<bool>(buffer[3] & 1);
auto beeperEnabled = static_cast<bool>(buffer[3] & 2);

uint8_t crc8 = buffer[4];
// Check crc on bytes 0-4 of buffer.
Expand All @@ -245,7 +246,7 @@ void Com::h_reqStart(const uint8_t *buffer, size_t size) {
return;
}

// TODO(who?): verify operation
GlobalBeeper::init(beeperEnabled);
memset(lineBuffer, 0xFF, MAX_LINE_BUFFER_LEN);

// Note (August 2020): the return value of this function has changed.
Expand Down
7 changes: 4 additions & 3 deletions src/ayab/encoders.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@

// Enumerated constants

enum class Direction : unsigned char {
NoDirection = 0xFF,
Left = 0,

enum class Direction : unsigned char {
NoDirection = 0xFF,
Left = 0,
Right = 1
};
constexpr int NUM_DIRECTIONS = 2;
Expand Down
2 changes: 1 addition & 1 deletion src/ayab/fsm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ void Fsm::state_error() {
// every 500ms
// send `indState` and flash LEDs
unsigned long now = millis();
if (now - m_flashTime >= 500) {
if (now - m_flashTime >= FLASH_DELAY) {
digitalWrite(LED_PIN_A, m_flash); // green LED
digitalWrite(LED_PIN_B, !m_flash); // yellow LED
m_flash = !m_flash;
Expand Down
2 changes: 2 additions & 0 deletions src/ayab/fsm.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ enum class ErrorCode : unsigned char {
};
using Err_t = enum ErrorCode;

constexpr unsigned int FLASH_DELAY = 500; // ms

class FsmInterface {
public:
virtual ~FsmInterface() = default;
Expand Down
12 changes: 12 additions & 0 deletions src/ayab/global_beeper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@

// static member functions

void GlobalBeeper::init(bool enabled) {
m_instance->init(enabled);
}

bool GlobalBeeper::enabled() {
return m_instance->enabled();
}

void GlobalBeeper::ready() {
m_instance->ready();
}
Expand All @@ -38,3 +46,7 @@ void GlobalBeeper::finishedLine() {
void GlobalBeeper::endWork() {
m_instance->endWork();
}

void GlobalBeeper::schedule() {
m_instance->schedule();
}
6 changes: 1 addition & 5 deletions src/ayab/knitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,11 +345,7 @@ bool Knitter::setNextLine(uint8_t lineNumber) {
// Is there even a need for a new line?
if (lineNumber == m_currentLineNumber) {
m_lineRequested = false;

// FIXME: Beeper is causing problems with flanking needles on the 270
if (m_machineType != Machine_t::Kh270) {
GlobalBeeper::finishedLine();
}
GlobalBeeper::finishedLine();
return true;
} else {
// line numbers didn't match -> request again
Expand Down
4 changes: 4 additions & 0 deletions src/ayab/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ TesterInterface *GlobalTester::m_instance = new Tester();
* Setup - do once before going to the main loop.
*/
void setup() {
GlobalBeeper::init(false);
GlobalCom::init();
GlobalFsm::init();
GlobalKnitter::init();
Expand All @@ -70,4 +71,7 @@ void setup() {
*/
void loop() {
GlobalFsm::dispatch();
if (GlobalBeeper::enabled()) {
GlobalBeeper::schedule();
}
}
2 changes: 1 addition & 1 deletion src/ayab/tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ Err_t Tester::startTest(Machine_t machineType) {
*/
void Tester::loop() {
unsigned long now = millis();
if (now - m_lastTime >= 500) {
if (now - m_lastTime >= TEST_LOOP_DELAY) {
m_lastTime = now;
handleTimerEvent();
}
Expand Down
1 change: 1 addition & 0 deletions src/ayab/tester.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "encoders.h"

constexpr uint8_t BUFFER_LEN = 40;
constexpr unsigned int TEST_LOOP_DELAY = 500; // ms

class TesterInterface {
public:
Expand Down
20 changes: 20 additions & 0 deletions test/mocks/beeper_mock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,21 @@ void releaseBeeperMock() {
}
}

void Beeper::init(bool enabled) {
assert(gBeeperMock != nullptr);
gBeeperMock->init(enabled);
}

bool Beeper::enabled() {
assert(gBeeperMock != nullptr);
return gBeeperMock->enabled();
}

BeepState Beeper::getState() {
assert(gBeeperMock != nullptr);
return gBeeperMock->getState();
}

void Beeper::ready() {
assert(gBeeperMock != nullptr);
gBeeperMock->ready();
Expand All @@ -52,3 +67,8 @@ void Beeper::endWork() {
assert(gBeeperMock != nullptr);
gBeeperMock->endWork();
}

void Beeper::schedule() {
assert(gBeeperMock != nullptr);
gBeeperMock->schedule();
}
4 changes: 4 additions & 0 deletions test/mocks/beeper_mock.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@

class BeeperMock : public BeeperInterface {
public:
MOCK_METHOD1(init, void(bool));
MOCK_METHOD0(enabled, bool());
MOCK_METHOD0(getState, BeepState());
MOCK_METHOD0(ready, void());
MOCK_METHOD0(finishedLine, void());
MOCK_METHOD0(endWork, void());
MOCK_METHOD0(schedule, void());
};

BeeperMock *beeperMockInstance();
Expand Down
Loading

0 comments on commit df5c27c

Please sign in to comment.