Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix cancel knit, move first run from OpKnit::knit() to OpKnit::begin() #169

Draft
wants to merge 33 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
5f5fbed
non-blocking beep
t0mpr1c3 Sep 14, 2023
13749e3
Merge branch 'v1.0-dev' into beep
t0mpr1c3 Sep 14, 2023
6e2fd32
Update CHANGELOG.md
t0mpr1c3 Sep 14, 2023
4b8638d
Update CHANGELOG.md
t0mpr1c3 Sep 14, 2023
d1aecf2
configurable beeper
t0mpr1c3 Sep 16, 2023
7fa5d06
Fix type in beeper.h
t0mpr1c3 Sep 16, 2023
c69b3a0
ISR
t0mpr1c3 Sep 17, 2023
5268ebd
Merge branch 'v1.0-dev' into tasks
t0mpr1c3 Sep 18, 2023
0c79fe1
op
t0mpr1c3 Sep 21, 2023
857851a
isr
t0mpr1c3 Sep 23, 2023
98ad074
avr-libc
t0mpr1c3 Sep 24, 2023
54065cd
controller
t0mpr1c3 Sep 25, 2023
3f8d4ee
fixup
t0mpr1c3 Sep 25, 2023
4b15580
ready
t0mpr1c3 Sep 26, 2023
838dabd
finish
t0mpr1c3 Sep 26, 2023
9b9feef
Merge branch 'op' into ready
t0mpr1c3 Sep 26, 2023
2e584b9
redux
t0mpr1c3 Sep 26, 2023
5149ebe
AtomicBlock
t0mpr1c3 Sep 27, 2023
d7eebcc
routes to Test
t0mpr1c3 Sep 27, 2023
61c4d62
new
t0mpr1c3 Sep 28, 2023
743c79c
Merge branch 'ready' into op
t0mpr1c3 Sep 28, 2023
f62de23
Neither attach nor detach interrupts during testing
t0mpr1c3 Sep 28, 2023
ae91876
Add comment about ATOMIC_BLOCK macro
t0mpr1c3 Sep 28, 2023
1cd8726
knit test coverage
t0mpr1c3 Sep 28, 2023
1a8ce58
100%
t0mpr1c3 Sep 28, 2023
fd6c7ad
ignore beltshift for KH270
t0mpr1c3 Sep 28, 2023
55e9d34
async analog read
t0mpr1c3 Sep 29, 2023
e0eba2e
use ATOMIC_BLOCK
t0mpr1c3 Oct 1, 2023
c023174
Merge branch 'op' into async
t0mpr1c3 Oct 1, 2023
4748717
mock PacketSerial
t0mpr1c3 Oct 1, 2023
3807822
rescue little edits
t0mpr1c3 Oct 4, 2023
3c82e46
remove OpKnit::encodePosition()
t0mpr1c3 Oct 4, 2023
9936b06
move first run from knit() to begin()
t0mpr1c3 Oct 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
[submodule "libraries/PacketSerial"]
[submodule "lib/PacketSerial"]
active = true
path = lib/PacketSerial
url = https://github.com/bakercp/PacketSerial.git
[submodule "libraries/Adafruit_MCP23008"]
url = https://github.com/adafruit/Adafruit-MCP23008-library.git
[submodule "lib/Adafruit_MCP23008"]
active = true
path = lib/Adafruit_MCP23008
url = https://github.com/adafruit/Adafruit-MCP23008-library.git
[submodule "lib/avr-libc"]
active = true
path = lib/avr-libc
url = https://github.com/avrdudes/avr-libc.git
[submodule "lib/AnalogReadAsync"]
path = lib/AnalogReadAsync
url = https://github.com/boothinator/AnalogReadAsync
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
17 changes: 10 additions & 7 deletions doc/finite_state_machine.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
### Finite State Machine

The finite state machine is defined in the `Fsm` class.
The finite state machine is defined in the `Controller` class.

| State | Action |
--: | :--
`Idle` | Wait for information on machine type.
`Init` | Wait for carriage to be put in the correct location.
`Ready` | Wait to start operation.
`Knit` | Operate in knitting mode.
Expand All @@ -14,9 +15,11 @@ A tabular representation of state transitions follows.

| Transition | Function / condition |
--: | :--
`Init -> Test` | `Tester::startTest()`
`Ready -> Test` | `Tester::startTest()`
`Test -> Init` | `Tester::quitCmd()`
`Init -> Ready` | `Knitter::isReady()`
`Ready -> Knit` | `Knitter::startKnitting()`
`Knit -> Ready` | `m_workedOnLine && m_lastLineFlag`
`Idle -> Init` | `Com::h_reqInit()`
`Init -> Ready` | `OpInit::update()`
`Ready -> Knit` | `OpKnit::startKnitting()`
`Init -> Test` | `OpTest::startTest()`
`Ready -> Test` | `OpTest::startTest()`
`Knit -> Test` | `OpTest::startTest()`
`Knit -> Init` | `m_workedOnLine && m_lastLineFlag`
`Test -> Init` | `OpTest::end()`
125 changes: 125 additions & 0 deletions init
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
test/test_encoders.cpp: encoders->init(Machine_t::Kh910);
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: .WillOnce(Return(FILTER_L_MIN[static_cast<int8_t>(encoders->getMachineType())]));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getDirection(), Direction_t::Right);
test/test_encoders.cpp: ASSERT_EQ(encoders->getPosition(), 0x01);
test/test_encoders.cpp: ASSERT_EQ(encoders->getCarriage(), Carriage_t::NoCarriage);
test/test_encoders.cpp: .WillOnce(Return(FILTER_R_MIN[static_cast<int8_t>(encoders->getMachineType())] - 1));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getDirection(), Direction_t::Right);
test/test_encoders.cpp: ASSERT_EQ(encoders->getPosition(), END_RIGHT_MINUS_OFFSET[static_cast<int8_t>(encoders->getMachineType())]);
test/test_encoders.cpp: ASSERT_EQ(encoders->getCarriage(), Carriage_t::Knit);
test/test_encoders.cpp: .WillOnce(Return(FILTER_L_MAX[static_cast<int8_t>(encoders->getMachineType())] + 1));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getDirection(), Direction_t::Right);
test/test_encoders.cpp: ASSERT_EQ(encoders->getPosition(), END_LEFT_PLUS_OFFSET[static_cast<int8_t>(encoders->getMachineType())]);
test/test_encoders.cpp: ASSERT_EQ(encoders->getCarriage(), Carriage_t::Knit);
test/test_encoders.cpp: ASSERT_FALSE(encoders->getMachineType() == Machine_t::Kh270);
test/test_encoders.cpp: ASSERT_EQ(encoders->getCarriage(), Carriage_t::NoCarriage);
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: .WillOnce(Return(FILTER_L_MIN[static_cast<int8_t>(encoders->getMachineType())] - 1));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getDirection(), Direction_t::Right);
test/test_encoders.cpp: ASSERT_EQ(encoders->getHallActive(), Direction_t::Left);
test/test_encoders.cpp: ASSERT_EQ(encoders->getPosition(), END_LEFT_PLUS_OFFSET[static_cast<int8_t>(encoders->getMachineType())]);
test/test_encoders.cpp: ASSERT_EQ(encoders->getCarriage(), Carriage_t::Lace);
test/test_encoders.cpp: ASSERT_EQ(encoders->getBeltShift(), BeltShift::Regular);
test/test_encoders.cpp: .WillOnce(Return(FILTER_R_MIN[static_cast<int8_t>(encoders->getMachineType())]));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: encoders->m_position = 0;
test/test_encoders.cpp: .WillOnce(Return(FILTER_L_MAX[static_cast<int8_t>(encoders->getMachineType())] + 1));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getDirection(), Direction_t::Right);
test/test_encoders.cpp: ASSERT_EQ(encoders->getPosition(), END_LEFT_PLUS_OFFSET[static_cast<int8_t>(encoders->getMachineType())]);
test/test_encoders.cpp: ASSERT_EQ(encoders->getCarriage(), Carriage_t::Knit);
test/test_encoders.cpp: encoders->init(Machine_t::Kh270);
test/test_encoders.cpp: ASSERT_TRUE(encoders->getMachineType() == Machine_t::Kh270);
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getDirection(), Direction_t::Right);
test/test_encoders.cpp: ASSERT_EQ(encoders->getHallActive(), Direction_t::Left);
test/test_encoders.cpp: ASSERT_EQ(encoders->getPosition(), END_LEFT_PLUS_OFFSET[static_cast<int8_t>(Machine_t::Kh270)]);
test/test_encoders.cpp: ASSERT_EQ(encoders->getCarriage(), Carriage_t::Knit);
test/test_encoders.cpp: ASSERT_EQ(encoders->getBeltShift(), BeltShift::Regular);
test/test_encoders.cpp: .WillOnce(Return(FILTER_R_MIN[static_cast<int8_t>(encoders->getMachineType())]));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: encoders->init(Machine_t::Kh270);
test/test_encoders.cpp: ASSERT_TRUE(encoders->getMachineType() == Machine_t::Kh270);
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: .WillOnce(Return(FILTER_L_MAX[static_cast<int8_t>(encoders->getMachineType())] + 1));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getDirection(), Direction_t::Right);
test/test_encoders.cpp: ASSERT_EQ(encoders->getHallActive(), Direction_t::Left);
test/test_encoders.cpp: ASSERT_EQ(encoders->getPosition(), END_LEFT_PLUS_OFFSET[static_cast<int8_t>(Machine_t::Kh270)] + MAGNET_DISTANCE_270);
test/test_encoders.cpp: ASSERT_EQ(encoders->getCarriage(), Carriage_t::Knit);
test/test_encoders.cpp: ASSERT_EQ(encoders->getBeltShift(), BeltShift::Regular);
test/test_encoders.cpp: .WillOnce(Return(FILTER_L_MAX[static_cast<int8_t>(encoders->getMachineType())] + 1));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getCarriage(), Carriage_t::Knit);
test/test_encoders.cpp: .WillOnce(Return(FILTER_R_MAX[static_cast<int8_t>(encoders->getMachineType())] + 1));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: .WillOnce(Return(FILTER_L_MIN[static_cast<int8_t>(encoders->getMachineType())] - 1));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getCarriage(), Carriage_t::Garter);
test/test_encoders.cpp: .WillOnce(Return(FILTER_R_MIN[static_cast<int8_t>(encoders->getMachineType())]));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: .WillOnce(Return(FILTER_R_MIN[static_cast<int8_t>(encoders->getMachineType())] - 1));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: .WillOnce(Return(FILTER_L_MIN[static_cast<int8_t>(encoders->getMachineType())]));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: encoders->m_position = END_LEFT[static_cast<uint8_t>(encoders->getMachineType())] + 1;
test/test_encoders.cpp: .WillOnce(Return(FILTER_R_MIN[static_cast<int8_t>(encoders->getMachineType())]));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: .WillOnce(Return(FILTER_L_MIN[static_cast<int8_t>(encoders->getMachineType())]));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: .WillOnce(Return(FILTER_R_MAX[static_cast<int8_t>(encoders->getMachineType())] + 1));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getDirection(), Direction_t::Right);
test/test_encoders.cpp: ASSERT_EQ(encoders->getHallActive(), Direction_t::Right);
test/test_encoders.cpp: ASSERT_EQ(encoders->getPosition(), END_RIGHT_MINUS_OFFSET[static_cast<int8_t>(encoders->getMachineType())]);
test/test_encoders.cpp: ASSERT_EQ(encoders->getCarriage(), Carriage_t::NoCarriage);
test/test_encoders.cpp: ASSERT_EQ(encoders->getBeltShift(), BeltShift::Shifted);
test/test_encoders.cpp: .WillOnce(Return(FILTER_L_MAX[static_cast<int8_t>(encoders->getMachineType())]));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: .WillOnce(Return(FILTER_R_MAX[static_cast<int8_t>(encoders->getMachineType())] + 1));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getPosition(), END_RIGHT_MINUS_OFFSET[static_cast<int8_t>(encoders->getMachineType())]);
test/test_encoders.cpp: uint16_t pos = END_RIGHT_MINUS_OFFSET[static_cast<int8_t>(encoders->getMachineType())];
test/test_encoders.cpp: while (pos < END_RIGHT[static_cast<int8_t>(encoders->getMachineType())]) {
test/test_encoders.cpp: .WillOnce(Return(FILTER_L_MAX[static_cast<int8_t>(encoders->getMachineType())]));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getPosition(), ++pos);
test/test_encoders.cpp: .WillOnce(Return(FILTER_R_MAX[static_cast<int8_t>(encoders->getMachineType())]));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getPosition(), pos);
test/test_encoders.cpp: ASSERT_EQ(encoders->getPosition(), pos);
test/test_encoders.cpp: .WillOnce(Return(FILTER_L_MAX[static_cast<int8_t>(encoders->getMachineType())]));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getPosition(), pos);
test/test_encoders.cpp: ASSERT_TRUE(encoders->getMachineType() == Machine_t::Kh910);
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: .WillOnce(Return(FILTER_R_MIN[static_cast<int8_t>(encoders->getMachineType())] - 1));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getCarriage(), Carriage_t::Knit);
test/test_encoders.cpp: .WillOnce(Return(FILTER_R_MAX[static_cast<int8_t>(encoders->getMachineType())] + 1));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getPosition(), END_LEFT_PLUS_OFFSET[static_cast<int8_t>(encoders->getMachineType())]);
test/test_encoders.cpp: .WillOnce(Return(FILTER_R_MAX[static_cast<int8_t>(encoders->getMachineType())]));
test/test_encoders.cpp: encoders->isr();
test/test_encoders.cpp: ASSERT_EQ(encoders->getPosition(), END_LEFT_PLUS_OFFSET[static_cast<int8_t>(encoders->getMachineType())]);
test/test_encoders.cpp: uint8_t p = encoders->getPosition();
test/test_encoders.cpp: BeltShift_t b = encoders->getBeltShift();
test/test_encoders.cpp: Direction_t d = encoders->getDirection();
test/test_encoders.cpp: Direction_t d = encoders->getHallActive();
test/test_encoders.cpp: Carriage_t c = encoders->getCarriage();
test/test_encoders.cpp: Machine_t m = encoders->getMachineType();
test/test_encoders.cpp: encoders->init(Machine_t::Kh270);
test/test_encoders.cpp: Machine_t m = encoders->getMachineType();
test/test_encoders.cpp: uint16_t v = encoders->getHallValue(Direction_t::NoDirection);
test/test_encoders.cpp: v = encoders->getHallValue(Direction_t::Left);
test/test_encoders.cpp: v = encoders->getHallValue(Direction_t::Right);
test/test_encoders.cpp: v = encoders->getHallValue(Direction_t::Right);
1 change: 1 addition & 0 deletions lib/AnalogReadAsync
Submodule AnalogReadAsync added at b97e43
4 changes: 2 additions & 2 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ default_envs = uno

[env]
framework = arduino
extra_scripts =
pre:scripts/preBuild.py
extra_scripts =
pre:scripts/preBuild.py

[env:uno]
platform = atmelavr
Expand Down
2 changes: 1 addition & 1 deletion scripts/preBuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Import("env")
print("Pre build script")

# Reads the current git tag of the repo and returns the version number
# Reads the current git tag of the repo and returns the version number
# elements
# In case there are changes since the last tag, the dirty flag is set
# In case the git tag does not match the x.y.z format, 0.0.0 is used as fallback
Expand Down
37 changes: 37 additions & 0 deletions src/ayab/analogReadAsyncWrapper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*!
* \file analogReadAsyncWrapper.cpp
*
* This file is part of AYAB.
*
* AYAB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AYAB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AYAB. If not, see <http://www.gnu.org/licenses/>.
*
* Original Work Copyright 2013 Christian Obersteiner, Andreas Müller
* Modified Work Copyright 2020-3 Sturla Lange, Tom Price
* http://ayab-knitting.com
*/

#include "analogReadAsyncWrapper.h"

/*!
* \brief Wrapper for analogReadAsync
*/
void AnalogReadAsyncWrapper::analogReadAsyncWrapped(uint8_t pin, analogReadCompleteCallback_t cb, const void *data) {
#ifndef AYAB_TESTS
analogReadAsync(pin, cb, data);
#else
(void) pin;
(void) cb;
(void) data;
#endif
}
64 changes: 64 additions & 0 deletions src/ayab/analogReadAsyncWrapper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*!
* \file analogReadAsyncWrapper.h
*
* This file is part of AYAB.
*
* AYAB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AYAB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AYAB. If not, see <http://www.gnu.org/licenses/>.
*
* Original Work Copyright 2013 Christian Obersteiner, Andreas Müller
* Modified Work Copyright 2020-3 Sturla Lange, Tom Price
* http://ayab-knitting.com
*/

#ifndef ANALOGREADASYNCWRAPPER_H_
#define ANALOGREADASYNCWRAPPER_H_

#include <Arduino.h>
#include <analogReadAsync.h>

class AnalogReadAsyncWrapperInterface {
public:
virtual ~AnalogReadAsyncWrapperInterface() = default;

// any methods that need to be mocked should go here
virtual void analogReadAsyncWrapped(uint8_t pin, analogReadCompleteCallback_t cb, const void *data) = 0;
};

// Container class for the static method analogReadAsync.
// Dependency injection is enabled using a pointer to a global instance of
// either `AnalogReadAsyncWrapper` or `AnalogReadAsyncWrapperMock`,
// both of which classes implement the
// pure virtual methods of `AnalogReadAsyncWrapperInterface`.

class GlobalAnalogReadAsyncWrapper final {
private:
// singleton class so private constructor is appropriate
GlobalAnalogReadAsyncWrapper() = default;

public:
// pointer to global instance whose methods are implemented
static AnalogReadAsyncWrapperInterface *m_instance;

static void analogReadAsyncWrapped(uint8_t pin, analogReadCompleteCallback_t cb = nullptr, const void *data = nullptr);
};

/*!
* \brief Wrapper for analogReadAsync method
*/
class AnalogReadAsyncWrapper : public AnalogReadAsyncWrapperInterface {
public:
void analogReadAsyncWrapped(uint8_t pin, analogReadCompleteCallback_t cb = nullptr, const void *data = nullptr) final;
};

#endif // ANALOGREADASYNCWRAPPER_H_
Loading