Merge remote-tracking branch 'github/master'

This commit is contained in:
Midgard 2021-02-01 18:10:09 +01:00
commit dc3299f5f8
Signed by: midgard
GPG key ID: 511C112F1331BBB4
43 changed files with 6933 additions and 308 deletions

View file

@ -2,17 +2,26 @@
You see an armed time bomb but don't know how to disarm it. Your friends found a manual to defuse the bomb and you have them on call. This is the premise of the game OBUS, a hardware project by [Zeus WPI](https://zeus.ugent.be). Inspired by the amazing software game [Keep Talking and Nobody Explodes](https://www.keeptalkinggame.com/).
# Get started writing a module
## Get started writing a module
These are the instructions for building your own OBUS module with an Arduino Nano v3 and the custom PCB. If
you're using other hardware, you might need to do some things differently.
0. Read the "[Getting started guide](docs/GETTING_STARTED.md)" to get a general idea of how OBUS works.
1. [Install](https://www.arduino.cc/en/Guide/#install-the-arduino-desktop-ide) the Arduino IDE.
2. Clone this repository with Git in a permanent location on your drive.
3. Symlink the library: `ln -s /ABSOLUTE/PATH/TO/REPO/lib /PATH/TO/Arduino/libraries/obus`
(on most Linux distro's, this the Arduino folder is in `$HOME/Arduino`)
4. Follow [these steps](https://github.com/autowp/arduino-mcp2515/#software-usage) to install the CAN library
5. Execute `./src/new_module.sh` to create a new module
5. Execute `./src/new_module.sh` to create a new module. When asked for a type, you'll probably want to choose 'puzzle'.
6. Edit the newly generated .ino file, either in the Arduino IDE or in your own editor.
7. In the Arduino IDE, select the correct board (Arduino Nano) and processor (ATmega328P (Old Bootloader)). After that,
flash your code to the Arduino and test it out.
# Background
## Game
TODO insert picture here
## Background
### Game
The game is played by at least two players. The goal is to defuse a bomb,
this is accomplished by defusing every module on that bomb before the bomb
@ -25,49 +34,15 @@ There are two roles:
These two roles can communicate with each other. To successfully defuse the bomb, they must
communicate efficiently and clearly. If a mistake is made, the team gets a strike.
If they get too many strikes, the bomb explodes, even if the timer hasn't run out yet.
If they get too many strikes or the timer runs out, the bomb explodes.
## Implementation details
### Implementation goals
Now we want to implement this game in hardware. As in the computer version, we want this game to be modular:
it should be easy to 1) make new modules and 2) attach them to a bomb. To do this, we need to settle on
a protocol, both in hardware and in software.
- It should be easy to add new modules, both hardware- and software-wise
- It should be easy to build your own module and get it working with the rest of the game
- Every run of the game should be different
- It should be possible for multiple people at the same time to develop a new module
The idea is to have one bomb controller that keeps track of the timer, the amount of strikes and of whether
the bomb has been successfully disarmed, and to have multiple modules that have one or more challenges on them
that need to be solved.
### Hardware
The bomb controller and modules have to be able to communicate with each other. Ideally, we would like a hardware bus where it is easy to add more modules. We would also like to minimise the amount of wires that are needed.
Multiple protocols were considered:
- I2C: very standard, most microcontrollers have this built in; unfortunately, limited in the amount of nodes that can connect to the same network (255), limited in distance between nodes (about 1 meter), and the bus needs 4 wires (GND, VCC and two data lines)
- SPI: needs even more wires, and requires a separate wire per module
- Serial: this is not a bus architecture, so a lot of wires will need to be used
But eventually, CAN was picked. CAN is widely used in vehicles and has several desired properties:
- We only need two wires (CAN uses a differential pair)
- Distance can be up to 500m
- There is built-in packet collision avoidance and per-node priorities
- CAN modules are very cheap
- There are existing Arduino libraries for the CAN module we'll be using
The payload of a CAN packet is 8 bytes long, this should be enough.
## Software
We needed to decide on a protocol to communicate between the bomb controller and the modules (and possibly also between modules?).
Some things we had to consider:
- payload is 8 bytes per packet
- packets can be delayed or not received on every node, so detection of this and retransmission might be needed: if the bomb interactor solves a module and the packet that communicates this with the bomb does not get delivered to the controller, the bomb will still go off, even if all modules have been solved
- we can't send an infinite amount of packets; the higher our bitrate is, the shorter our wires need to be
## Development setup
In the Arduino IDE, select the correct board (Arduino Nano) and processor (ATmega328P (Old Bootloader)).
We use [this](https://github.com/autowp/arduino-mcp2515/) library for CAN communications. See [this](https://github.com/autowp/arduino-mcp2515/#software-usage) header for 3 simple steps on how to use it in the arduino IDE

View file

@ -42,15 +42,17 @@ class Message:
def sender_id(self):
return (self.received_from >> 0) & 0b1111_1111
def human_readable_type(self):
return [('controller' if self.sender_id() == 0 else 'info'), 'puzzle', 'needy', 'RESERVED TYPE'][self.sender_type()]
@staticmethod
def human_readable_type(sender_type, sender_id):
return [('controller' if sender_id == 0 else 'info'), 'puzzle', 'needy', 'RESERVED TYPE'][sender_type]
def _parse_state_update(self):
timeleft = self.payload[1] << 0x18 | self.payload[2] << 0x10 | self.payload[3] << 0x08 | self.payload[4]
strikes = self.payload[5]
max_strikes = self.payload[6]
solved_puzzle_modules = self.payload[7]
return f'{timeleft/1000:3.2f} {strikes:02}/{max_strikes:02}'
return f'{timeleft/1000:3.2f} {strikes:02}/{max_strikes:02} [{solved_puzzle_modules:02}]'
def parse_message(self):
sender_type = self.sender_type()
@ -58,7 +60,7 @@ class Message:
try:
if sender_type == 0b00 and self.sender_id() == 0: # controller
if message_type == 0:
return "ACK"
return f"ACK {Message.human_readable_type(self.payload[1], self.payload[2])} {self.payload[2]}"
elif message_type == 1:
return "HELLO"
elif message_type == 2:
@ -99,7 +101,7 @@ class Message:
'parsed': self.parse_message(),
'pretty_raw_sender_id': f'{self.priority_bit():01b} {self.sender_type():02b} {self.sender_id():08b}',
'raw_message': f"{self.payload.hex(' ')}",
'human_readable_type': self.human_readable_type(),
'human_readable_type': Message.human_readable_type(self.sender_type(), self.sender_id()),
'sender_id': self.sender_id(),
'internal_id': self.internal_id
}

123
docs/GETTING_STARTED.md Normal file
View file

@ -0,0 +1,123 @@
# Getting started
This is a guide for writing your own puzzle module. We'll first start by
describing an OBUS game, then describe the minimum things you need to implement
to get a working puzzle module. We'll then finish by explaining some nice-to-haves
(like using info modules or game state in a puzzle module).
## OBUS game
### Parts of the game
The goal of OBUS is to defuse a bomb by communicating clearly. There are (at least) two players: the defuser and the expert.
The defuser can see and interact with the bomb, the expert can read the manual that describes how to defuse the bomb.
You win the game by defusing the bomb, you lose if the bomb explodes. The bomb is defused when all puzzle modules are
solved; the bomb explodes if the time runs out or too much mistakes ("strikes") have been made.
The bomb consists of a controller and multiple modules: the controller shows the time left, the amount of mistakes made
while defusing the bomb (strikes) and the amount of strikes left. It's responsible for starting games, enumerating modules,
keeping track of game state, ...
The modules on the other hand are the parts of the bomb that can be interacted with by the defuser. There are several kinds of
modules: puzzle modules, needy modules and info modules.
Puzzle modules are the most common kind of modules. The bomb is defused as soon as all puzzle modules are solved.
Puzzle modules are generally solved by having the defuser observe some kind of state of the game, then having them
communicate that information to the expert. The expert then uses this information and the manual to communicate a set of
instructions to the defuser. If the instructions are correct and the defuser executes them correctly, the module is solved.
If one of the two players makes an error and the defuser executes an incorrect action, the module generates a "strike".
An example of a puzzle module is an RGB led with a red and a green button under it. The defuser looks at the module and
sees that the RGB led is colored blue. They then tell that to the expert, who then looks up this module in the manual.
The manual instructs to press the green button if the color starts with the letter "b" or "o". The expert then asks the
defuser to press the green button. When the defuser does this, the module is solved.
There are also needy modules. These can't be "solved", but they can generate strikes: they require periodic action
from the defuser to prevent them from generating a strike.
An example of a needy module is a buzzer with a red button. If the buzzer goes off, the defuser has to press the button within 5 seconds
or a strike is generated. Needy modules can also have the expert look something up in the manual (if you do this, make sure
to balance the time needed by the defuser against the time between the signal that action is needed and the strike).
Finally, there are also info modules. These don't serve a purpose on their own, they are only useful in combination with
puzzle or needy modules. They provide extra information to those modules. These modules were added to the game
to make it possible to make puzzle/needy modules with less hardware: puzzle modules generally consist of two "parts":
a part that shows information to the defuser that needs to be communicated to the expert and a part that the defuser
can interact with to solve the module. With info modules, this first part can be moved to a dedicated module that can
be shared between multiple puzzle modules.
An example of an info module is an LCD display that displays a serial number. There can then be a puzzle module with
just two buttons on it. When the defuser is solving that module, the expert reads in the manual "press the second button
if the last digit of the serial number is even, otherwise press the first". The expert then asks for the serial number
and after that has the defuser press the correct button, solving the puzzle module.
### Hardware
In our OBUS implementation, every module has its own microcontroller and CAN module. CAN is a hardware protocol
that allows the modules to communicate with the controller (and each other). To write your own module, you don't
have to know how CAN works, this is all abstracted away with the OBUS framework. The only thing you need to do
is to set the type (puzzle/needy/info) of the module and it's ID. The combination type/ID needs to be unique across
the OBUS game, so in order to avoid collisions, you can register your module in TODO LINK MOANA and get an ID.
In addition to a CAN module, every module also has an RGB LED. This LED is used to show both the
state of the module and to indicate if the module has an error.
If the module is solved, the LED is green, if a module generates a strike, the module blinks red. There are also several blinking
patterns for errors. In order to save pins on the microcontroller for implementing the puzzle, only the red and green
parts of the RGB led are connected. You CANNOT use the RGB LED for the puzzle itself: this would be confusing for the player
and when debugging a game.
### A sample game
This is a description of a sample game with only one module: the `puzzle_testmodule_buttons`. When reading this part, it's useful to have the `puzzle_testmodule_buttons.ino` file next to you as well.
We'll start this story from the start: the puzzle module boots up.
It calls the `obus_module::setup` function to register it's module type and ID. It then keeps calling the `obus_module::loopPuzzle` in a loop.
It's important that the `loopPuzzle` function is executed very frequently without delays: if this doesn't happen enough, important CAN messages can get dropped.
Then after a while, a button gets pressed on the controller and the controller starts preparing to start the game. It first asks all info modules to broadcast their information. After some time, it then asks all puzzle/needy module to register themselves. The controller then confirms that that module will be active in the next round. After some time, the controller broadcasts that the game has started and starts counting down.
This broadcasts is received on the puzzle module and results in the `callback_game_start` function getting called the next time the
`obus::loopPuzzle` is called. The `callback_game_start` function is responsible for setting up the module for a new game. Here, we
randomly turn the blue LED on or off, and enable the main loop to start checking button presses.
After the `callback_game_start` function returns, the microcontroller stays inside the `loop` function, and keeps executing the `obus_module::loopPuzzle`
frequently. If the correct button is pressed, it calls the `obus_module::solve` function and turns off input checking. Turning off imput checking is
important: that way it's impossible for the puzzle module to generate strikes after it has been solved. If an incorrect button is pressed, it calls the
`obus_module::strike` function. That function will send a strike to the controller.
When `obus_module::solve` is called, the module sends an "I'm solved" CAN packet to the controller. The controller then sees that all modules have been solved,
and broadcasts a "solved" packet to every module. The next time the `obus_module::loopPuzzle` function gets called, the
`callback_game_stop` will be called. This function is responsible for tearing down the puzzle state. This should have the
same effect as just resetting the microcontroller, so if your state is too hard to clean up, you can just reboot the microcontroller.
## What you need to implement for your own puzzle module
- The setup code, initializing your microcontroller and setting the type and id of the module with `obus_module::setup`
- The main loop code. This should call the `loopPuzzle` function frequently so that all CAN packets can be handled.
If you are using calls to `delay()`, try to replace them with a timer (a variable that keeps track of when something should happen). That way the loop can continue executing, without being stuck in the `delay()` function.
- A call to the `obus_module::solve` function
- A description for the expert of how to defuse the module in `doc/index.md` of your module folder
- The `callback_game_start`, `callback_game_stop` and `callback_info` functions. These can be empty.
## More advanced puzzle modules
### Receiving game updates
It's possible to use the current state of the game in your module: the amount of
strikes (in microseconds), amount of allowed strikes and time left regularly get
broadcast to all modules. That way, you can spice up your puzzle, for example by
making the defuser press a button when the timer has a `1` in it, or by
having the instructions in the manual vary based on the amount of strikes.
TODO how will we do this?
### Using info modules in your puzzle/needy modules
Using info modules is a great way to reduce the amount of hardware components needed in a puzzle:
you can then still have puzzles that change every game, without having to add components that show information
to the defuser. Info modules broadcast their information to all modules in the phase before the game starts.
Every module can listen to these info messages with the `callback_info` callback. This callback will get
the ID of the info module and 7 bytes, as specified by the specific module. The `callback_info` function is
responsible for filtering out the info messages the module is interested in, and saving that info for the upcoming game.
For example, the serial number module has ID 1 and sends in its message 7 random character, chosen randomly from numbers
and the uppercase letters.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 KiB

After

Width:  |  Height:  |  Size: 293 KiB

View file

@ -38,8 +38,10 @@ Types for controller:
- 0 acknowledge valid message
[ X B B B B B B B ]
--------------
reserved
- - ----------
| ↓ reserved
↓ module ID
type
- 1 hello
[ X B B B B B B B ]
@ -49,25 +51,25 @@ Types for controller:
- 2 game start
[ X B B B B B B B ]
-------- - - -
time left ↓ ↓ reserved
time left ↓ ↓ #puzzle modules
#strikes #max strikes
- 3 state (every x ms e.g. in the middle of each second)
[ X B B B B B B B ]
-------- - - -
time left ↓ ↓ reserved
time left ↓ ↓ #solved puzzle modules
#strikes #max strikes
- 4-6 solved, timeout, strikeout
[ X B B B B B B B ]
-------- - - -
end time ↓ ↓ reserved
end time ↓ ↓ #solved puzzle modules
#strikes #max strikes
- 7 info start
- 7 info start
[ X B B B B B B B ]
--------------
reserved
reserved
- 8-255 reserved

View file

@ -37,6 +37,7 @@ uint8_t payload_type(uint8_t module_type, uint8_t module_id, uint8_t msg_type) {
if (module_type == OBUS_TYPE_CONTROLLER && module_id == OBUS_CONTROLLER_ID) {
switch (msg_type) {
case OBUS_MSGTYPE_C_ACK:
return OBUS_PAYLDTYPE_MODULEADDR;
case OBUS_MSGTYPE_C_HELLO:
return OBUS_PAYLDTYPE_EMPTY;
@ -113,13 +114,14 @@ bool receive(struct message *msg) {
break;
case OBUS_PAYLDTYPE_GAMESTATUS:
if (receive_frame.can_dlc < 7) {
Serial.println(F("W Received illegal gamestatus msg: payload <7"));
if (receive_frame.can_dlc < 8) {
Serial.println(F("W Received illegal gamestatus msg: payload <8"));
return false;
}
msg->gamestatus.time_left = unpack_4b_into_u32(&(receive_frame.data[1]));
msg->gamestatus.strikes = receive_frame.data[5];
msg->gamestatus.max_strikes = receive_frame.data[6];
msg->gamestatus.time_left = unpack_4b_into_u32(&(receive_frame.data[1]));
msg->gamestatus.strikes = receive_frame.data[5];
msg->gamestatus.max_strikes = receive_frame.data[6];
msg->gamestatus.puzzle_modules_solved = receive_frame.data[7];
break;
case OBUS_PAYLDTYPE_COUNT:
@ -137,6 +139,16 @@ bool receive(struct message *msg) {
msg->infomessage.len = data_len;
}
break;
case OBUS_PAYLDTYPE_MODULEADDR:
{
if (receive_frame.can_dlc < 3) {
Serial.println(F("W Received illegal count msg: payload <3"));
return false;
}
msg->payload_address.type = receive_frame.data[1];
msg->payload_address.id = receive_frame.data[2];
}
break;
default:
Serial.println(F("W Couldn't determine payload type"));
return false;
@ -175,7 +187,8 @@ void send(struct message *msg) {
pack_u32_into_4b(&(send_frame.data[1]), msg->gamestatus.time_left);
send_frame.data[5] = msg->gamestatus.strikes;
send_frame.data[6] = msg->gamestatus.max_strikes;
length = 7;
send_frame.data[7] = msg->gamestatus.puzzle_modules_solved;
length = 8;
break;
case OBUS_PAYLDTYPE_COUNT:
@ -188,6 +201,11 @@ void send(struct message *msg) {
length = msg->infomessage.len + 1;
break;
case OBUS_PAYLDTYPE_MODULEADDR:
send_frame.data[1] = msg->payload_address.type;
send_frame.data[2] = msg->payload_address.id;
break;
default:
Serial.print(F("E Unknown payload type "));
Serial.println(pyld_type);

View file

@ -35,6 +35,7 @@
#define OBUS_PAYLDTYPE_GAMESTATUS 1
#define OBUS_PAYLDTYPE_COUNT 2
#define OBUS_PAYLDTYPE_INFO 3
#define OBUS_PAYLDTYPE_MODULEADDR 4
#define OBUS_PAYLD_INFO_MAXLEN (OBUS_MSG_LENGTH - 1)
@ -50,6 +51,7 @@ struct payld_gamestatus {
uint32_t time_left;
uint8_t strikes;
uint8_t max_strikes;
uint8_t puzzle_modules_solved;
};
struct payld_infomessage {
uint8_t len;
@ -66,6 +68,7 @@ struct message {
struct payld_gamestatus gamestatus;
uint8_t count;
struct payld_infomessage infomessage;
struct module payload_address;
};
};
@ -126,12 +129,13 @@ inline struct message _msg(struct module from, bool priority, uint8_t msg_type)
*/
inline void _send_payld_gamestatus(
struct module from, bool priority, uint8_t msg_type,
uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_solved) {
struct message msg = _msg(from, priority, msg_type);
msg.gamestatus.time_left = time_left;
msg.gamestatus.strikes = strikes;
msg.gamestatus.max_strikes = max_strikes;
msg.gamestatus.puzzle_modules_solved = puzzle_modules_solved;
send(&msg);
}
@ -140,9 +144,10 @@ inline void _send_payld_gamestatus(
/**
* Send a controller "ACK" OBUS message
*/
inline void send_c_ack(struct module from) {
inline void send_c_ack(struct module from, struct module payload_address) {
assert(from.type == OBUS_TYPE_CONTROLLER);
struct message msg = _msg(from, false, OBUS_MSGTYPE_C_ACK);
msg.payload_address = payload_address;
send(&msg);
}
@ -160,44 +165,44 @@ inline void send_c_hello(struct module from) {
* Send a controller "game start" OBUS message
*/
inline void send_c_gamestart(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_solved) {
assert(from.type == OBUS_TYPE_CONTROLLER);
_send_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_GAMESTART, time_left, strikes, max_strikes);
from, false, OBUS_MSGTYPE_C_GAMESTART, time_left, strikes, max_strikes, puzzle_modules_solved);
}
/**
* Send a controller "state" OBUS message
*/
inline void send_c_state(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_solved) {
assert(from.type == OBUS_TYPE_CONTROLLER);
_send_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_STATE, time_left, strikes, max_strikes);
from, false, OBUS_MSGTYPE_C_STATE, time_left, strikes, max_strikes, puzzle_modules_solved);
}
/**
* Send a controller "solved" OBUS message
*/
inline void send_c_solved(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_solved) {
assert(from.type == OBUS_TYPE_CONTROLLER);
_send_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_SOLVED, time_left, strikes, max_strikes);
from, false, OBUS_MSGTYPE_C_SOLVED, time_left, strikes, max_strikes, puzzle_modules_solved);
}
/**
* Send a controller "timeout" OBUS message
*/
inline void send_c_timeout(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_solved) {
assert(from.type == OBUS_TYPE_CONTROLLER);
_send_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_TIMEOUT, time_left, strikes, max_strikes);
from, false, OBUS_MSGTYPE_C_TIMEOUT, time_left, strikes, max_strikes, puzzle_modules_solved);
}
/**
@ -213,11 +218,11 @@ inline void send_c_infostart(struct module from) {
* Send a controller "strikeout" OBUS message
*/
inline void send_c_strikeout(
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes) {
struct module from, uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_solved) {
assert(from.type == OBUS_TYPE_CONTROLLER);
_send_payld_gamestatus(
from, false, OBUS_MSGTYPE_C_STRIKEOUT, time_left, strikes, max_strikes);
from, false, OBUS_MSGTYPE_C_STRIKEOUT, time_left, strikes, max_strikes, puzzle_modules_solved);
}
@ -267,6 +272,10 @@ inline void send_i_infomessage(struct module from, uint8_t *data, uint8_t data_l
send(&msg);
}
inline bool is_from_controller(struct module from) {
return from.type == OBUS_TYPE_CONTROLLER && from.id == OBUS_CONTROLLER_ID;
}
}
#endif /* end of include guard: OBUS_CAN_H */

View file

@ -1,12 +1,15 @@
#include "obus_can.h"
#include "obus_module.h"
#define RED_LED A4
#define GREEN_LED A5
#define RED_LED 4
#define GREEN_LED 7
#define BLINK_DELAY_SLOW 1000
#define BLINK_DELAY_FAST 300
#define MAX_TIME_BETWEEN_CALLS 100
// Not used normally
#define MCP_INT 2
#define COLOR_OFF ((struct color) {false, false})
@ -19,6 +22,7 @@ namespace obus_module {
struct obus_can::module this_module;
uint8_t strike_count;
bool active;
uint32_t next_loop_call_deadline;
// Current LED status
struct color { bool red; bool green; };
@ -79,6 +83,7 @@ void _setLedBlink(struct color color, uint16_t delay) {
void _resetState() {
strike_count = 0;
active = false;
next_loop_call_deadline = 0;
if (this_module.type == OBUS_TYPE_PUZZLE || this_module.type == OBUS_TYPE_NEEDY) {
pinMode(RED_LED, OUTPUT);
@ -97,29 +102,55 @@ void setup(uint8_t type, uint8_t id) {
_resetState();
}
bool loopPuzzle(obus_can::message* message, void (*callback_game_start)(), void (*callback_game_stop)()) {
void empty_callback_info(uint8_t info_id, uint8_t infomessage[7]) {
// Mark arguments as not used
(void)info_id;
(void)infomessage;
}
void empty_callback_state(uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_solved) {
// Mark arguments as not used
(void)time_left;
(void)strikes;
(void)max_strikes;
(void)puzzle_modules_solved;
}
void blink_error(String message) {
bool blink = false;
while (true) {
digitalWrite(RED_LED, blink);
digitalWrite(GREEN_LED, blink);
blink = !blink;
delay(blink ? BLINK_DELAY_SLOW : BLINK_DELAY_FAST);
Serial.println(message);
}
}
bool loopPuzzle(obus_can::message* message, void (*callback_game_start)(uint8_t puzzle_modules), void (*callback_game_stop)(), void (*callback_info)(uint8_t info_id, uint8_t infomessage[7]), void (*callback_state)(uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_solved)) {
// TODO this can be more efficient by only enabling error interrupts and
// reacting to the interrupt instead of checking if the flag is set in a loop
// We will need to fork our CAN library for this, because the needed functions
// are private
// We will need to fork our CAN library for this, because the needed functions are private.
// Also, we can't do this by default, because the INT pin is normally not connected to the board
if (obus_can::is_error_condition()) {
bool blink = false;
while (true) {
digitalWrite(RED_LED, blink);
digitalWrite(GREEN_LED, blink);
delay(blink ? BLINK_DELAY_SLOW : BLINK_DELAY_FAST);
blink = !blink;
}
blink_error(F("E CAN error"));
}
bool interesting_message = false;
if (next_loop_call_deadline != 0 && millis() > next_loop_call_deadline) {
blink_error(F("E missed deadline"));
}
next_loop_call_deadline = millis() + MAX_TIME_BETWEEN_CALLS;
bool received_message = false;
if (obus_can::receive(message)) {
if (message->from.type == OBUS_TYPE_CONTROLLER && message->from.id == 0) {
received_message = true;
if (is_from_controller(message->from)) {
switch (message->msg_type) {
case OBUS_MSGTYPE_C_GAMESTART:
active = true;
_setLed(COLOR_YELLOW);
callback_game_start();
// The field is named puzzle_modules_solved, but it actually contains the amount of puzzle modules
callback_game_start(message->gamestatus.puzzle_modules_solved);
break;
case OBUS_MSGTYPE_C_HELLO:
_resetState();
@ -135,28 +166,32 @@ bool loopPuzzle(obus_can::message* message, void (*callback_game_start)(), void
case OBUS_MSGTYPE_C_ACK:
break;
case OBUS_MSGTYPE_C_STATE:
interesting_message = true;
callback_state(message->gamestatus.time_left, message->gamestatus.strikes, message->gamestatus.max_strikes, message->gamestatus.puzzle_modules_solved);
break;
default:
break;
}
} else if (message->from.type == OBUS_TYPE_INFO) {
uint8_t infobuffer[7] = {0};
memcpy(infobuffer, message->infomessage.data, message->infomessage.len);
callback_info(message->from.id, infobuffer);
}
}
_ledLoop();
return interesting_message;
return received_message;
}
bool loopNeedy(obus_can::message* message, void (*callback_game_start)(), void (*callback_game_stop)()) {
bool loopNeedy(obus_can::message* message, void (*callback_game_start)(uint8_t puzzle_modules), void (*callback_game_stop)(), void (*callback_info)(uint8_t info_id, uint8_t infomessage[7]), void (*callback_state)(uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_solved)) {
// For now this is the same function
return loopPuzzle(message, callback_game_start, callback_game_stop);
return loopPuzzle(message, callback_game_start, callback_game_stop, callback_info, callback_state);
}
bool loopInfo(obus_can::message* message, int (*info_generator)(uint8_t*)) {
bool interesting_message = false;
if (obus_can::receive(message)) {
if (message->from.type == OBUS_TYPE_CONTROLLER && message->from.id == 0) {
if (is_from_controller(message->from)) {
switch (message->msg_type) {
case OBUS_MSGTYPE_C_INFOSTART:
{

View file

@ -12,9 +12,12 @@ namespace obus_module {
void setup(uint8_t type, uint8_t id);
bool loopPuzzle(obus_can::message* message, void (*callback_game_start)(), void (*callback_game_stop)());
void empty_callback_info(uint8_t info_id, uint8_t infomessage[7]);
void empty_callback_state(uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_solved);
bool loopNeedy(obus_can::message* message, void (*callback_game_start)(), void (*callback_game_stop)());
bool loopPuzzle(obus_can::message* message, void (*callback_game_start)(uint8_t puzzle_modules), void (*callback_game_stop)(), void (*callback_info)(uint8_t info_id, uint8_t infomessage[7]) = empty_callback_info, void (*callback_state)(uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_solved) = empty_callback_state);
bool loopNeedy(obus_can::message* message, void (*callback_game_start)(uint8_t puzzle_modules), void (*callback_game_stop)(), void (*callback_info)(uint8_t info_id, uint8_t infomessage[7]) = empty_callback_info, void (*callback_state)(uint32_t time_left, uint8_t strikes, uint8_t max_strikes, uint8_t puzzle_modules_solved) = empty_callback_state);
bool loopInfo(obus_can::message* message, int (*info_generator)(uint8_t*));

View file

@ -18,7 +18,7 @@ uint8_t shiftInFixed(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
else
value |= digitalRead(dataPin) << (7 - i);
digitalWrite(clockPin, HIGH);
delay(1);
delayMicroseconds(3);
digitalWrite(clockPin, LOW);
}
return value;
@ -50,7 +50,7 @@ void loop() // run over and over
{
// read data in
digitalWrite(READ_PIN, HIGH);
delay(200);
delayMicroseconds(3);
digitalWrite(READ_PIN, LOW);
// shift data bit by bit

41
pcb/README.md Normal file
View file

@ -0,0 +1,41 @@
# OBUS PCB
![The panelized OBUS PCB](./pcb_kicad.png)
In order to make it easier for our members to get started creating their own OBUS module,
we designed and ordered PCBs they can use instead of having to wire up the basics
on a breadboard. The PCB accomodates an Arduino Nano V3 (and clones), an MCP2515 CAN-bus module
and an RGB LED. The LED and CAN bus module are connected to pins on the
Arduino Nano. All pins on the Arduino Nano are connected to the ajacent pin socket so
they can easily be accessed when breadboarding.
The pins already used by the OBUS framework are marked with exclamation marks. This does
not mean they can't be used for other purposes anymore, just that you need to pay
attention when using them: for example the SPI pins can be used for other devices, but
the LED pins can't. While picking the pins, we made sure to use the least useful pins
for the OBUS framework: we tried to pick as few PWM pins as possible, didn't pick any I2C
pins, ...
## Connecting the parts on the socket.
We tried our best to make the board as self-explanatory as possible. When pushing the
Arduino into its socket, make sure it's in the correct orientation. When connecting the
CAN bus module, you'll need to flip it on its back, then look at the silk screen on both
the OBUS PCB and the CAN module so that the INT pin is connected in the INT socket hole.
By default, the INT pin on the CAN module is not connected to the Arduino in order to
save pins. If you want to connect the INT pin to pin D2 on the Arduino, you can bridge
the jumper on the top right of the board with some solder.
## Getting this board manufactured
I order to get this board manufactured cheaper, we panelized it (by putting two OBUS PCBs per ordered "board"). If you want to manufacture this board, there's a file `panel/can_arduino_mini_pcb_panel/fabricate/handin.zip` containing all the
Gerber files needed for production. If you modify the original PCB, you can generate
the panel with `panel/build.sh`, then use KiCAD to plot the Gerber files.
### Component list per board
- 2 1x15 2.54mm pin sockets, we recommend 4 sockets so you can socket the Arduino as well
- 1 1x07 2.54mm pin socket
- 1 1x02 2.54mm pin socket
- 1 common cathode 5mm RGB LED, pin order RCGB
- 2 330 ohm through hole resistors

28
pcb/can_arduino_mini_pcb/.gitignore vendored Normal file
View file

@ -0,0 +1,28 @@
# For PCBs designed using KiCad: http://www.kicad-pcb.org/
# Format documentation: http://kicad-pcb.org/help/file-formats/
# Temporary files
*.000
*.bak
*.bck
*.kicad_pcb-bak
*.kicad_sch-bak
*.kicad_prl
*.sch-bak
*~
_autosave-*
*.tmp
*-save.pro
*-save.kicad_pcb
fp-info-cache
# Netlist files (exported from Eeschema)
*.net
# Autorouter files (exported from Pcbnew)
*.dsn
*.ses
# Exported BOM files
*.xml
*.csv

View file

@ -0,0 +1,331 @@
EESchema-LIBRARY Version 2.4
#encoding utf-8
#
# Connector_Conn_01x02_Female
#
DEF Connector_Conn_01x02_Female J 0 40 Y N 1 F N
F0 "J" 0 100 50 H V C CNN
F1 "Connector_Conn_01x02_Female" 0 -200 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_1x??_*
$ENDFPLIST
DRAW
A 0 -100 20 901 -901 1 1 6 N 0 -80 0 -120
A 0 0 20 901 -901 1 1 6 N 0 20 0 -20
P 2 1 1 6 -50 -100 -20 -100 N
P 2 1 1 6 -50 0 -20 0 N
X Pin_1 1 -200 0 150 R 50 50 1 1 P
X Pin_2 2 -200 -100 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Connector_Conn_01x07_Female
#
DEF Connector_Conn_01x07_Female J 0 40 Y N 1 F N
F0 "J" 0 400 50 H V C CNN
F1 "Connector_Conn_01x07_Female" 0 -400 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_1x??_*
$ENDFPLIST
DRAW
A 0 -300 20 901 -901 1 1 6 N 0 -280 0 -320
A 0 -200 20 901 -901 1 1 6 N 0 -180 0 -220
A 0 -100 20 901 -901 1 1 6 N 0 -80 0 -120
A 0 0 20 901 -901 1 1 6 N 0 20 0 -20
A 0 100 20 901 -901 1 1 6 N 0 120 0 80
A 0 200 20 901 -901 1 1 6 N 0 220 0 180
A 0 300 20 901 -901 1 1 6 N 0 320 0 280
P 2 1 1 6 -50 -300 -20 -300 N
P 2 1 1 6 -50 -200 -20 -200 N
P 2 1 1 6 -50 -100 -20 -100 N
P 2 1 1 6 -50 0 -20 0 N
P 2 1 1 6 -50 100 -20 100 N
P 2 1 1 6 -50 200 -20 200 N
P 2 1 1 6 -50 300 -20 300 N
X Pin_1 1 -200 300 150 R 50 50 1 1 P
X Pin_2 2 -200 200 150 R 50 50 1 1 P
X Pin_3 3 -200 100 150 R 50 50 1 1 P
X Pin_4 4 -200 0 150 R 50 50 1 1 P
X Pin_5 5 -200 -100 150 R 50 50 1 1 P
X Pin_6 6 -200 -200 150 R 50 50 1 1 P
X Pin_7 7 -200 -300 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Connector_Conn_01x15_Female
#
DEF Connector_Conn_01x15_Female J 0 40 Y N 1 F N
F0 "J" 0 800 50 H V C CNN
F1 "Connector_Conn_01x15_Female" 0 -800 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
Connector*:*_1x??_*
$ENDFPLIST
DRAW
A 0 -700 20 901 -901 1 1 6 N 0 -680 0 -720
A 0 -600 20 901 -901 1 1 6 N 0 -580 0 -620
A 0 -500 20 901 -901 1 1 6 N 0 -480 0 -520
A 0 -400 20 901 -901 1 1 6 N 0 -380 0 -420
A 0 -300 20 901 -901 1 1 6 N 0 -280 0 -320
A 0 -200 20 901 -901 1 1 6 N 0 -180 0 -220
A 0 -100 20 901 -901 1 1 6 N 0 -80 0 -120
A 0 0 20 901 -901 1 1 6 N 0 20 0 -20
A 0 100 20 901 -901 1 1 6 N 0 120 0 80
A 0 200 20 901 -901 1 1 6 N 0 220 0 180
A 0 300 20 901 -901 1 1 6 N 0 320 0 280
A 0 400 20 901 -901 1 1 6 N 0 420 0 380
A 0 500 20 901 -901 1 1 6 N 0 520 0 480
A 0 600 20 901 -901 1 1 6 N 0 620 0 580
A 0 700 20 901 -901 1 1 6 N 0 720 0 680
P 2 1 1 6 -50 -700 -20 -700 N
P 2 1 1 6 -50 -600 -20 -600 N
P 2 1 1 6 -50 -500 -20 -500 N
P 2 1 1 6 -50 -400 -20 -400 N
P 2 1 1 6 -50 -300 -20 -300 N
P 2 1 1 6 -50 -200 -20 -200 N
P 2 1 1 6 -50 -100 -20 -100 N
P 2 1 1 6 -50 0 -20 0 N
P 2 1 1 6 -50 100 -20 100 N
P 2 1 1 6 -50 200 -20 200 N
P 2 1 1 6 -50 300 -20 300 N
P 2 1 1 6 -50 400 -20 400 N
P 2 1 1 6 -50 500 -20 500 N
P 2 1 1 6 -50 600 -20 600 N
P 2 1 1 6 -50 700 -20 700 N
X Pin_1 1 -200 700 150 R 50 50 1 1 P
X Pin_10 10 -200 -200 150 R 50 50 1 1 P
X Pin_11 11 -200 -300 150 R 50 50 1 1 P
X Pin_12 12 -200 -400 150 R 50 50 1 1 P
X Pin_13 13 -200 -500 150 R 50 50 1 1 P
X Pin_14 14 -200 -600 150 R 50 50 1 1 P
X Pin_15 15 -200 -700 150 R 50 50 1 1 P
X Pin_2 2 -200 600 150 R 50 50 1 1 P
X Pin_3 3 -200 500 150 R 50 50 1 1 P
X Pin_4 4 -200 400 150 R 50 50 1 1 P
X Pin_5 5 -200 300 150 R 50 50 1 1 P
X Pin_6 6 -200 200 150 R 50 50 1 1 P
X Pin_7 7 -200 100 150 R 50 50 1 1 P
X Pin_8 8 -200 0 150 R 50 50 1 1 P
X Pin_9 9 -200 -100 150 R 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Device_Jumper_NO_Small
#
DEF Device_Jumper_NO_Small JP 0 30 N N 1 F N
F0 "JP" 0 80 50 H V C CNN
F1 "Device_Jumper_NO_Small" 10 -60 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
SolderJumper*Open*
Jumper*
TestPoint*2Pads*
TestPoint*Bridge*
$ENDFPLIST
DRAW
C -40 0 20 0 1 0 N
C 40 0 20 0 1 0 N
X 1 1 -100 0 40 R 50 50 0 1 P
X 2 2 100 0 40 L 50 50 0 1 P
ENDDRAW
ENDDEF
#
# Device_LED_RCGB
#
DEF Device_LED_RCGB D 0 0 Y N 1 F N
F0 "D" 0 370 50 H V C CNN
F1 "Device_LED_RCGB" 0 -350 50 H V C CNN
F2 "" 0 -50 50 H I C CNN
F3 "" 0 -50 50 H I C CNN
$FPLIST
LED*
LED_SMD:*
LED_THT:*
$ENDFPLIST
DRAW
C -80 0 10 0 1 0 F
T 0 75 -250 50 0 0 0 B Normal 0 C C
T 0 75 -50 50 0 0 0 G Normal 0 C C
T 0 75 150 50 0 0 0 R Normal 0 C C
S 50 -50 50 50 0 1 0 N
S 50 50 50 50 0 1 0 N
S 50 150 50 250 0 1 0 N
S 50 250 50 250 0 1 0 N
S 110 330 -110 -300 0 1 10 f
P 2 0 1 0 -50 -200 50 -200 N
P 2 0 1 10 -50 -150 -50 -250 N
P 2 0 1 0 -50 0 -100 0 N
P 2 0 1 10 -50 50 -50 -50 N
P 2 0 1 0 -50 200 50 200 N
P 2 0 1 10 -50 250 -50 150 N
P 2 0 1 0 50 -200 100 -200 N
P 2 0 1 0 50 0 -50 0 N
P 2 0 1 0 50 0 100 0 N
P 2 0 1 0 50 200 100 200 N
P 3 0 1 0 -50 50 -50 -50 -50 -50 N
P 3 0 1 0 -50 250 -50 150 -50 150 N
P 4 0 1 0 -50 200 -80 200 -80 -200 -40 -200 N
P 4 0 1 10 50 -150 50 -250 -50 -200 50 -150 N
P 4 0 1 10 50 50 50 -50 -50 0 50 50 N
P 4 0 1 10 50 250 50 150 -50 200 50 250 N
P 5 0 1 0 -40 -150 20 -90 -10 -90 20 -90 20 -120 N
P 5 0 1 0 -40 50 20 110 -10 110 20 110 20 80 N
P 5 0 1 0 -40 250 20 310 -10 310 20 310 20 280 N
P 5 0 1 0 0 -150 60 -90 30 -90 60 -90 60 -120 N
P 5 0 1 0 0 50 60 110 30 110 60 110 60 80 N
P 5 0 1 0 0 250 60 310 30 310 60 310 60 280 N
X RA 1 200 200 100 L 50 50 1 1 P
X K 2 -200 0 100 R 50 50 1 1 P
X GA 3 200 0 100 L 50 50 1 1 P
X BA 4 200 -200 100 L 50 50 1 1 P
ENDDRAW
ENDDEF
#
# Device_R
#
DEF Device_R R 0 0 N Y 1 F N
F0 "R" 80 0 50 V V C CNN
F1 "Device_R" 0 0 50 V V C CNN
F2 "" -70 0 50 V I C CNN
F3 "" 0 0 50 H I C CNN
$FPLIST
R_*
$ENDFPLIST
DRAW
S -40 -100 40 100 0 1 10 N
X ~ 1 0 150 50 D 50 50 1 1 P
X ~ 2 0 -150 50 U 50 50 1 1 P
ENDDRAW
ENDDEF
#
# MCU_Module_Arduino_Nano_v3.x
#
DEF MCU_Module_Arduino_Nano_v3.x A 0 20 Y Y 1 F N
F0 "A" -400 925 50 H V L BNN
F1 "MCU_Module_Arduino_Nano_v3.x" 200 -950 50 H V L TNN
F2 "Module:Arduino_Nano" 0 0 50 H I C CIN
F3 "" 0 0 50 H I C CNN
ALIAS Arduino_Nano_v3.x
$FPLIST
Arduino*Nano*
$ENDFPLIST
DRAW
S -400 900 400 -900 0 1 10 f
X D1/TX 1 -500 500 100 R 50 50 1 1 B
X D7 10 -500 -100 100 R 50 50 1 1 B
X D8 11 -500 -200 100 R 50 50 1 1 B
X D9 12 -500 -300 100 R 50 50 1 1 B
X D10 13 -500 -400 100 R 50 50 1 1 B
X D11 14 -500 -500 100 R 50 50 1 1 B
X D12 15 -500 -600 100 R 50 50 1 1 B
X D13 16 -500 -700 100 R 50 50 1 1 B
X 3V3 17 100 1000 100 D 50 50 1 1 w
X AREF 18 500 200 100 L 50 50 1 1 I
X A0 19 500 0 100 L 50 50 1 1 B
X D0/RX 2 -500 600 100 R 50 50 1 1 B
X A1 20 500 -100 100 L 50 50 1 1 B
X A2 21 500 -200 100 L 50 50 1 1 B
X A3 22 500 -300 100 L 50 50 1 1 B
X A4 23 500 -400 100 L 50 50 1 1 B
X A5 24 500 -500 100 L 50 50 1 1 B
X A6 25 500 -600 100 L 50 50 1 1 B
X A7 26 500 -700 100 L 50 50 1 1 B
X +5V 27 200 1000 100 D 50 50 1 1 w
X ~RESET 28 500 600 100 L 50 50 1 1 I
X GND 29 100 -1000 100 U 50 50 1 1 W
X ~RESET 3 500 500 100 L 50 50 1 1 I
X VIN 30 -100 1000 100 D 50 50 1 1 W
X GND 4 0 -1000 100 U 50 50 1 1 W
X D2 5 -500 400 100 R 50 50 1 1 B
X D3 6 -500 300 100 R 50 50 1 1 B
X D4 7 -500 200 100 R 50 50 1 1 B
X D5 8 -500 100 100 R 50 50 1 1 B
X D6 9 -500 0 100 R 50 50 1 1 B
ENDDRAW
ENDDEF
#
# custom_components_CAN_MODULE
#
DEF custom_components_CAN_MODULE U 0 40 Y Y 1 F N
F0 "U" -250 -400 50 H V C CNN
F1 "custom_components_CAN_MODULE" -50 400 50 H V C CNN
F2 "" -500 50 50 H I C CNN
F3 "" -500 50 50 H I C CNN
DRAW
P 5 0 1 0 -300 350 -300 -350 200 -350 200 350 -300 350 f
X CS ~ -400 -100 100 R 50 50 1 1 I
X GND ~ -400 -200 100 R 50 50 1 1 W
X INT ~ -400 300 100 R 50 50 1 1 O
X SCK ~ -400 200 100 R 50 50 1 1 I
X SI ~ -400 100 100 R 50 50 1 1 I
X SO ~ -400 0 100 R 50 50 1 1 O
X VCC ~ -400 -300 100 R 50 50 1 1 W
ENDDRAW
ENDDEF
#
# power_+3.3V
#
DEF power_+3.3V #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 -150 50 H I C CNN
F1 "power_+3.3V" 0 140 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
ALIAS +3.3V
DRAW
P 2 0 1 0 -30 50 0 100 N
P 2 0 1 0 0 0 0 100 N
P 2 0 1 0 0 100 30 50 N
X +3V3 1 0 0 0 U 50 50 1 1 W N
ENDDRAW
ENDDEF
#
# power_+5V
#
DEF power_+5V #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 -150 50 H I C CNN
F1 "power_+5V" 0 140 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
DRAW
P 2 0 1 0 -30 50 0 100 N
P 2 0 1 0 0 0 0 100 N
P 2 0 1 0 0 100 30 50 N
X +5V 1 0 0 0 U 50 50 1 1 W N
ENDDRAW
ENDDEF
#
# power_GND
#
DEF power_GND #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 -250 50 H I C CNN
F1 "power_GND" 0 -150 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
DRAW
P 6 0 1 0 0 0 0 -50 50 -50 0 -100 -50 -50 0 -50 N
X GND 1 0 0 0 D 50 50 1 1 W N
ENDDRAW
ENDDEF
#
# power_VCC
#
DEF power_VCC #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 -150 50 H I C CNN
F1 "power_VCC" 0 150 50 H V C CNN
F2 "" 0 0 50 H I C CNN
F3 "" 0 0 50 H I C CNN
DRAW
P 2 0 1 0 -30 50 0 100 N
P 2 0 1 0 0 0 0 100 N
P 2 0 1 0 0 100 30 50 N
X VCC 1 0 0 0 U 50 50 1 1 W N
ENDDRAW
ENDDEF
#
#End Library

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,106 @@
(module Zeusbadge:logo_small (layer F.Cu) (tedit 0)
(fp_text reference Ref** (at 0 0) (layer F.SilkS) hide
(effects (font (size 1.27 1.27) (thickness 0.15)))
)
(fp_text value Val** (at 0 0) (layer F.SilkS) hide
(effects (font (size 1.27 1.27) (thickness 0.15)))
)
(fp_poly (pts (xy -1.016 -3.288689) (xy -1.142003 -3.138997) (xy -1.268007 -2.989305) (xy -1.182104 -3.030809)
(xy -1.025377 -3.087386) (xy -0.846598 -3.120172) (xy -0.657547 -3.129238) (xy -0.470004 -3.114655)
(xy -0.295752 -3.076497) (xy -0.164929 -3.024586) (xy -0.067915 -2.961689) (xy 0.032277 -2.874577)
(xy 0.12265 -2.776208) (xy 0.190203 -2.679541) (xy 0.200396 -2.660424) (xy 0.254 -2.552855)
(xy 0.254 -3.069167) (xy 0.881518 -3.069167) (xy 0.880072 -2.450042) (xy 0.879921 -2.267152)
(xy 0.880578 -2.121569) (xy 0.882289 -2.008269) (xy 0.885296 -1.922228) (xy 0.889844 -1.858422)
(xy 0.896176 -1.811829) (xy 0.904535 -1.777425) (xy 0.913896 -1.752948) (xy 0.971152 -1.672643)
(xy 1.054138 -1.625167) (xy 1.16035 -1.611805) (xy 1.185619 -1.613478) (xy 1.28122 -1.634538)
(xy 1.357754 -1.681383) (xy 1.424353 -1.760687) (xy 1.45408 -1.80975) (xy 1.513417 -1.915583)
(xy 1.527029 -3.069167) (xy 2.137833 -3.069167) (xy 2.137833 -2.72153) (xy 2.185458 -2.815669)
(xy 2.258964 -2.9177) (xy 2.365182 -3.005012) (xy 2.495233 -3.070792) (xy 2.536114 -3.084859)
(xy 2.623269 -3.102769) (xy 2.742311 -3.114551) (xy 2.883255 -3.120301) (xy 3.036115 -3.120112)
(xy 3.190905 -3.114079) (xy 3.337639 -3.102295) (xy 3.46633 -3.084856) (xy 3.513667 -3.075635)
(xy 3.693583 -3.036259) (xy 3.705475 -2.544021) (xy 3.550865 -2.604056) (xy 3.326485 -2.672813)
(xy 3.104529 -2.705117) (xy 2.963429 -2.705744) (xy 2.877009 -2.697913) (xy 2.819472 -2.683696)
(xy 2.777438 -2.659152) (xy 2.763281 -2.646802) (xy 2.719319 -2.584497) (xy 2.711743 -2.519641)
(xy 2.726274 -2.482613) (xy 2.766383 -2.450155) (xy 2.838853 -2.419933) (xy 2.933728 -2.395388)
(xy 3.01625 -2.382466) (xy 3.156457 -2.361403) (xy 3.299459 -2.331076) (xy 3.433035 -2.294693)
(xy 3.544964 -2.255458) (xy 3.60293 -2.228539) (xy 3.704631 -2.153435) (xy 3.758668 -2.084122)
(xy 3.781923 -2.040048) (xy 3.796927 -1.996041) (xy 3.805436 -1.941265) (xy 3.809206 -1.864882)
(xy 3.81 -1.767417) (xy 3.809025 -1.662024) (xy 3.804921 -1.588087) (xy 3.795919 -1.534747)
(xy 3.780252 -1.491148) (xy 3.758318 -1.450115) (xy 3.674898 -1.349053) (xy 3.556203 -1.268239)
(xy 3.404468 -1.208296) (xy 3.221927 -1.169846) (xy 3.010815 -1.153512) (xy 2.773365 -1.159916)
(xy 2.729504 -1.163401) (xy 2.612096 -1.17531) (xy 2.49223 -1.190343) (xy 2.386424 -1.206294)
(xy 2.329159 -1.21691) (xy 2.254258 -1.23242) (xy 2.19722 -1.243771) (xy 2.169123 -1.248766)
(xy 2.168199 -1.248833) (xy 2.164593 -1.268613) (xy 2.16165 -1.322407) (xy 2.159682 -1.401899)
(xy 2.159 -1.494515) (xy 2.159483 -1.59945) (xy 2.161637 -1.668627) (xy 2.166519 -1.708619)
(xy 2.175187 -1.725996) (xy 2.188698 -1.727331) (xy 2.196042 -1.7247) (xy 2.366911 -1.663036)
(xy 2.546916 -1.615359) (xy 2.72448 -1.583779) (xy 2.888025 -1.570405) (xy 3.013854 -1.575702)
(xy 3.11662 -1.599827) (xy 3.193226 -1.6406) (xy 3.239488 -1.693512) (xy 3.251217 -1.754055)
(xy 3.230422 -1.808898) (xy 3.205257 -1.838257) (xy 3.168347 -1.862212) (xy 3.113195 -1.882828)
(xy 3.0333 -1.902173) (xy 2.922163 -1.922312) (xy 2.826401 -1.937369) (xy 2.636219 -1.972919)
(xy 2.483188 -2.017374) (xy 2.362634 -2.073083) (xy 2.269885 -2.142399) (xy 2.200269 -2.227675)
(xy 2.179975 -2.262724) (xy 2.139704 -2.338917) (xy 2.138769 -1.762125) (xy 2.137833 -1.185333)
(xy 1.524 -1.185333) (xy 1.524 -1.453244) (xy 1.425698 -1.359054) (xy 1.292809 -1.254409)
(xy 1.150557 -1.18894) (xy 0.99134 -1.159524) (xy 0.93419 -1.157201) (xy 0.761957 -1.169408)
(xy 0.618339 -1.21056) (xy 0.500057 -1.281763) (xy 0.460985 -1.317015) (xy 0.386955 -1.405718)
(xy 0.332771 -1.507635) (xy 0.294623 -1.632148) (xy 0.268702 -1.788638) (xy 0.268388 -1.791268)
(xy 0.2448 -1.989667) (xy -0.41735 -1.989667) (xy -0.608043 -1.989812) (xy -0.760238 -1.989585)
(xy -0.877765 -1.987996) (xy -0.964456 -1.984052) (xy -1.024141 -1.976762) (xy -1.060652 -1.965135)
(xy -1.077818 -1.948179) (xy -1.079471 -1.924903) (xy -1.069441 -1.894314) (xy -1.051559 -1.855422)
(xy -1.039127 -1.828731) (xy -0.969825 -1.719242) (xy -0.873815 -1.640901) (xy -0.763574 -1.594829)
(xy -0.629055 -1.573158) (xy -0.471256 -1.577406) (xy -0.299116 -1.606033) (xy -0.121578 -1.657497)
(xy 0.05242 -1.73026) (xy 0.068188 -1.738097) (xy 0.132329 -1.769626) (xy 0.180289 -1.791683)
(xy 0.20048 -1.799167) (xy 0.204892 -1.779397) (xy 0.208484 -1.725667) (xy 0.210869 -1.646349)
(xy 0.211667 -1.556671) (xy 0.211667 -1.314175) (xy 0.04669 -1.262059) (xy -0.054642 -1.232446)
(xy -0.162556 -1.204646) (xy -0.253911 -1.184615) (xy -0.254935 -1.184423) (xy -0.349356 -1.171573)
(xy -0.466152 -1.162669) (xy -0.592323 -1.15798) (xy -0.714868 -1.157772) (xy -0.820786 -1.162312)
(xy -0.894292 -1.17129) (xy -0.973667 -1.187252) (xy -0.973667 -0.592667) (xy -3.788833 -0.592667)
(xy -3.788619 -0.851958) (xy -3.788404 -1.11125) (xy -3.691228 -1.227667) (xy -2.753326 -1.227667)
(xy -1.942871 -1.227684) (xy -1.132417 -1.2277) (xy -1.222755 -1.272417) (xy -1.367732 -1.366825)
(xy -1.492981 -1.493678) (xy -1.592451 -1.645357) (xy -1.660092 -1.814243) (xy -1.663808 -1.827746)
(xy -1.678724 -1.912308) (xy -1.688158 -2.024014) (xy -1.691884 -2.148001) (xy -1.689677 -2.269407)
(xy -1.68153 -2.370667) (xy -1.076545 -2.370667) (xy -0.300792 -2.370667) (xy -0.318324 -2.448404)
(xy -0.36246 -2.557083) (xy -0.437382 -2.63888) (xy -0.538762 -2.690555) (xy -0.662271 -2.708869)
(xy -0.66642 -2.708869) (xy -0.798212 -2.690354) (xy -0.91018 -2.638495) (xy -0.99706 -2.556982)
(xy -1.053588 -2.449505) (xy -1.058358 -2.434082) (xy -1.076545 -2.370667) (xy -1.68153 -2.370667)
(xy -1.681312 -2.37337) (xy -1.672832 -2.422989) (xy -1.661944 -2.476782) (xy -1.658356 -2.509334)
(xy -1.659172 -2.512894) (xy -1.673809 -2.4991) (xy -1.711713 -2.457234) (xy -1.769026 -2.391729)
(xy -1.841895 -2.307017) (xy -1.926463 -2.207531) (xy -1.980794 -2.143095) (xy -2.08913 -2.014314)
(xy -2.205237 -1.876443) (xy -2.320634 -1.739541) (xy -2.426845 -1.613664) (xy -2.515391 -1.508871)
(xy -2.524955 -1.497565) (xy -2.753326 -1.227667) (xy -3.691228 -1.227667) (xy -2.940318 -2.12725)
(xy -2.092231 -3.14325) (xy -2.929949 -3.148785) (xy -3.767667 -3.154319) (xy -3.767667 -3.788833)
(xy -1.016 -3.788833) (xy -1.016 -3.288689)) (layer F.SilkS) (width 0.01))
(fp_poly (pts (xy 2.207666 -1.024057) (xy 2.273262 -1.013955) (xy 2.330212 -0.992493) (xy 2.3744 -0.968396)
(xy 2.501053 -0.8699) (xy 2.599025 -0.741854) (xy 2.645181 -0.645583) (xy 2.685961 -0.53975)
(xy 2.687064 -0.767292) (xy 2.688167 -0.994833) (xy 3.132667 -0.994833) (xy 3.132667 0.423333)
(xy 2.688167 0.423333) (xy 2.685961 -0.052917) (xy 2.645181 0.052917) (xy 2.57002 0.196383)
(xy 2.468504 0.309449) (xy 2.344269 0.389265) (xy 2.200952 0.432979) (xy 2.152866 0.438782)
(xy 2.004569 0.436976) (xy 1.876802 0.403809) (xy 1.758684 0.3363) (xy 1.747103 0.327637)
(xy 1.651 0.254279) (xy 1.651 0.9525) (xy 1.185819 0.9525) (xy 1.180284 0.115033)
(xy 1.177538 -0.300551) (xy 1.652692 -0.300551) (xy 1.660694 -0.187641) (xy 1.687052 -0.083604)
(xy 1.732023 0.00204) (xy 1.780419 0.050112) (xy 1.846255 0.075872) (xy 1.932137 0.083376)
(xy 2.019848 0.07247) (xy 2.075026 0.052558) (xy 2.13734 0.006643) (xy 2.179162 -0.059496)
(xy 2.203024 -0.152327) (xy 2.211455 -0.278317) (xy 2.211551 -0.296333) (xy 2.204834 -0.426827)
(xy 2.182997 -0.52337) (xy 2.14351 -0.59243) (xy 2.08384 -0.640473) (xy 2.075026 -0.645225)
(xy 1.989624 -0.671278) (xy 1.892808 -0.674331) (xy 1.806616 -0.653963) (xy 1.799167 -0.650491)
(xy 1.736286 -0.597303) (xy 1.690743 -0.514903) (xy 1.662794 -0.412812) (xy 1.652692 -0.300551)
(xy 1.177538 -0.300551) (xy 1.17475 -0.722434) (xy 1.026583 -0.154842) (xy 0.878417 0.41275)
(xy 0.383355 0.424656) (xy 0.362498 0.349117) (xy 0.350927 0.304331) (xy 0.331668 0.22658)
(xy 0.306727 0.124107) (xy 0.278113 0.005155) (xy 0.251575 -0.106244) (xy 0.222709 -0.225502)
(xy 0.196674 -0.328414) (xy 0.17514 -0.408754) (xy 0.159774 -0.460292) (xy 0.152249 -0.476805)
(xy 0.144668 -0.454408) (xy 0.128693 -0.396995) (xy 0.105929 -0.310689) (xy 0.077979 -0.201608)
(xy 0.046449 -0.075875) (xy 0.034452 -0.027397) (xy -0.074083 0.41275) (xy -0.321797 0.418705)
(xy -0.569511 0.424659) (xy -0.590367 0.344621) (xy -0.666863 0.050855) (xy -0.732925 -0.203265)
(xy -0.788885 -0.419031) (xy -0.835077 -0.59774) (xy -0.871834 -0.740684) (xy -0.899489 -0.849158)
(xy -0.918375 -0.924457) (xy -0.928824 -0.967875) (xy -0.931333 -0.980507) (xy -0.91163 -0.9864)
(xy -0.85836 -0.991117) (xy -0.780289 -0.99409) (xy -0.710078 -0.994833) (xy -0.488823 -0.994833)
(xy -0.470222 -0.926042) (xy -0.459474 -0.88389) (xy -0.440884 -0.808447) (xy -0.41637 -0.707614)
(xy -0.387856 -0.589292) (xy -0.358424 -0.466258) (xy -0.265227 -0.075266) (xy -0.167992 -0.476841)
(xy -0.136895 -0.605159) (xy -0.108363 -0.722693) (xy -0.08422 -0.821947) (xy -0.066288 -0.895423)
(xy -0.056392 -0.935624) (xy -0.056142 -0.936625) (xy -0.041527 -0.994833) (xy 0.352246 -0.994833)
(xy 0.45534 -0.560917) (xy 0.486502 -0.432165) (xy 0.515084 -0.318599) (xy 0.539481 -0.226237)
(xy 0.558086 -0.161099) (xy 0.569293 -0.129204) (xy 0.571093 -0.127) (xy 0.579524 -0.146617)
(xy 0.595904 -0.201456) (xy 0.618624 -0.285499) (xy 0.646075 -0.392728) (xy 0.676647 -0.517126)
(xy 0.687146 -0.560917) (xy 0.790538 -0.994834) (xy 1.220769 -0.994833) (xy 1.651 -0.994833)
(xy 1.651 -0.846946) (xy 1.747878 -0.920895) (xy 1.817895 -0.970026) (xy 1.881399 -1.001301)
(xy 1.951775 -1.018557) (xy 2.042408 -1.02563) (xy 2.116667 -1.026583) (xy 2.207666 -1.024057)) (layer F.SilkS) (width 0.01))
)

View file

@ -0,0 +1,259 @@
update=Tue 26 Jan 2021 04:50:01 CET
version=1
last_client=kicad
[general]
version=1
RootSch=
BoardNm=
[cvpcb]
version=1
NetIExt=net
[eeschema]
version=1
LibDir=
[eeschema/libraries]
[schematic_editor]
version=1
PageLayoutDescrFile=
PlotDirectoryName=
SubpartIdSeparator=0
SubpartFirstId=65
NetFmtName=Pcbnew
SpiceAjustPassiveValues=0
LabSize=50
ERC_TestSimilarLabels=1
[pcbnew]
version=1
PageLayoutDescrFile=
LastNetListRead=can_arduino_mini_pcb.net
CopperLayerCount=2
BoardThickness=1.6
AllowMicroVias=0
AllowBlindVias=0
RequireCourtyardDefinitions=0
ProhibitOverlappingCourtyards=1
MinTrackWidth=0.2
MinViaDiameter=0.4
MinViaDrill=0.3
MinMicroViaDiameter=0.2
MinMicroViaDrill=0.09999999999999999
MinHoleToHole=0.25
TrackWidth1=0.25
ViaDiameter1=0.8
ViaDrill1=0.4
dPairWidth1=0.2
dPairGap1=0.25
dPairViaGap1=0.25
SilkLineWidth=0.12
SilkTextSizeV=1
SilkTextSizeH=1
SilkTextSizeThickness=0.15
SilkTextItalic=0
SilkTextUpright=1
CopperLineWidth=0.2
CopperTextSizeV=1.5
CopperTextSizeH=1.5
CopperTextThickness=0.3
CopperTextItalic=0
CopperTextUpright=1
EdgeCutLineWidth=0.05
CourtyardLineWidth=0.05
OthersLineWidth=0.15
OthersTextSizeV=1
OthersTextSizeH=1
OthersTextSizeThickness=0.15
OthersTextItalic=0
OthersTextUpright=1
SolderMaskClearance=0
SolderMaskMinWidth=0
SolderPasteClearance=0
SolderPasteRatio=-0
[pcbnew/Layer.F.Cu]
Name=F.Cu
Type=0
Enabled=1
[pcbnew/Layer.In1.Cu]
Name=In1.Cu
Type=0
Enabled=0
[pcbnew/Layer.In2.Cu]
Name=In2.Cu
Type=0
Enabled=0
[pcbnew/Layer.In3.Cu]
Name=In3.Cu
Type=0
Enabled=0
[pcbnew/Layer.In4.Cu]
Name=In4.Cu
Type=0
Enabled=0
[pcbnew/Layer.In5.Cu]
Name=In5.Cu
Type=0
Enabled=0
[pcbnew/Layer.In6.Cu]
Name=In6.Cu
Type=0
Enabled=0
[pcbnew/Layer.In7.Cu]
Name=In7.Cu
Type=0
Enabled=0
[pcbnew/Layer.In8.Cu]
Name=In8.Cu
Type=0
Enabled=0
[pcbnew/Layer.In9.Cu]
Name=In9.Cu
Type=0
Enabled=0
[pcbnew/Layer.In10.Cu]
Name=In10.Cu
Type=0
Enabled=0
[pcbnew/Layer.In11.Cu]
Name=In11.Cu
Type=0
Enabled=0
[pcbnew/Layer.In12.Cu]
Name=In12.Cu
Type=0
Enabled=0
[pcbnew/Layer.In13.Cu]
Name=In13.Cu
Type=0
Enabled=0
[pcbnew/Layer.In14.Cu]
Name=In14.Cu
Type=0
Enabled=0
[pcbnew/Layer.In15.Cu]
Name=In15.Cu
Type=0
Enabled=0
[pcbnew/Layer.In16.Cu]
Name=In16.Cu
Type=0
Enabled=0
[pcbnew/Layer.In17.Cu]
Name=In17.Cu
Type=0
Enabled=0
[pcbnew/Layer.In18.Cu]
Name=In18.Cu
Type=0
Enabled=0
[pcbnew/Layer.In19.Cu]
Name=In19.Cu
Type=0
Enabled=0
[pcbnew/Layer.In20.Cu]
Name=In20.Cu
Type=0
Enabled=0
[pcbnew/Layer.In21.Cu]
Name=In21.Cu
Type=0
Enabled=0
[pcbnew/Layer.In22.Cu]
Name=In22.Cu
Type=0
Enabled=0
[pcbnew/Layer.In23.Cu]
Name=In23.Cu
Type=0
Enabled=0
[pcbnew/Layer.In24.Cu]
Name=In24.Cu
Type=0
Enabled=0
[pcbnew/Layer.In25.Cu]
Name=In25.Cu
Type=0
Enabled=0
[pcbnew/Layer.In26.Cu]
Name=In26.Cu
Type=0
Enabled=0
[pcbnew/Layer.In27.Cu]
Name=In27.Cu
Type=0
Enabled=0
[pcbnew/Layer.In28.Cu]
Name=In28.Cu
Type=0
Enabled=0
[pcbnew/Layer.In29.Cu]
Name=In29.Cu
Type=0
Enabled=0
[pcbnew/Layer.In30.Cu]
Name=In30.Cu
Type=0
Enabled=0
[pcbnew/Layer.B.Cu]
Name=B.Cu
Type=0
Enabled=1
[pcbnew/Layer.B.Adhes]
Enabled=1
[pcbnew/Layer.F.Adhes]
Enabled=1
[pcbnew/Layer.B.Paste]
Enabled=1
[pcbnew/Layer.F.Paste]
Enabled=1
[pcbnew/Layer.B.SilkS]
Enabled=1
[pcbnew/Layer.F.SilkS]
Enabled=1
[pcbnew/Layer.B.Mask]
Enabled=1
[pcbnew/Layer.F.Mask]
Enabled=1
[pcbnew/Layer.Dwgs.User]
Enabled=1
[pcbnew/Layer.Cmts.User]
Enabled=1
[pcbnew/Layer.Eco1.User]
Enabled=1
[pcbnew/Layer.Eco2.User]
Enabled=1
[pcbnew/Layer.Edge.Cuts]
Enabled=1
[pcbnew/Layer.Margin]
Enabled=1
[pcbnew/Layer.B.CrtYd]
Enabled=1
[pcbnew/Layer.F.CrtYd]
Enabled=1
[pcbnew/Layer.B.Fab]
Enabled=1
[pcbnew/Layer.F.Fab]
Enabled=1
[pcbnew/Layer.Rescue]
Enabled=0
[pcbnew/Netclasses]
[pcbnew/Netclasses/Default]
Name=Default
Clearance=0.2
TrackWidth=0.25
ViaDiameter=0.8
ViaDrill=0.4
uViaDiameter=0.3
uViaDrill=0.1
dPairWidth=0.2
dPairGap=0.25
dPairViaGap=0.25
[pcbnew/Netclasses/1]
Name=Power
Clearance=0.2
TrackWidth=0.35
ViaDiameter=0.8
ViaDrill=0.4
uViaDiameter=0.3
uViaDrill=0.1
dPairWidth=0.2
dPairGap=0.25
dPairViaGap=0.25

View file

@ -0,0 +1,440 @@
EESchema Schematic File Version 4
EELAYER 30 0
EELAYER END
$Descr A4 11693 8268
encoding utf-8
Sheet 1 1
Title ""
Date ""
Rev ""
Comp ""
Comment1 ""
Comment2 ""
Comment3 ""
Comment4 ""
$EndDescr
$Comp
L MCU_Module:Arduino_Nano_v3.x A1
U 1 1 600ED8F8
P 4850 3500
F 0 "A1" H 4850 2411 50 0000 C CNN
F 1 "Arduino_Nano_v3.x" H 4850 2320 50 0000 C CNN
F 2 "Module:Arduino_Nano" H 4850 3500 50 0001 C CIN
F 3 "http://www.mouser.com/pdfdocs/Gravitech_Arduino_Nano3_0.pdf" H 4850 3500 50 0001 C CNN
1 4850 3500
1 0 0 -1
$EndComp
$Comp
L Device:R R2
U 1 1 600F00A2
P 7550 4150
F 0 "R2" V 7343 4150 50 0000 C CNN
F 1 "330" V 7434 4150 50 0000 C CNN
F 2 "Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P7.62mm_Horizontal" V 7480 4150 50 0001 C CNN
F 3 "~" H 7550 4150 50 0001 C CNN
1 7550 4150
0 1 -1 0
$EndComp
$Comp
L Device:R R1
U 1 1 600F0580
P 7550 3950
F 0 "R1" V 7343 3950 50 0000 C CNN
F 1 "330" V 7434 3950 50 0000 C CNN
F 2 "Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P7.62mm_Horizontal" V 7480 3950 50 0001 C CNN
F 3 "~" H 7550 3950 50 0001 C CNN
1 7550 3950
0 1 1 0
$EndComp
$Comp
L Device:LED_RCGB D1
U 1 1 600F1EA5
P 7900 4150
F 0 "D1" H 7900 3683 50 0000 C CNN
F 1 "LED_RCGB" H 7900 3774 50 0000 C CNN
F 2 "LED_THT:LED_D5.0mm-4_RGB" H 7900 4100 50 0001 C CNN
F 3 "~" H 7900 4100 50 0001 C CNN
1 7900 4150
-1 0 0 -1
$EndComp
$Comp
L Connector:Conn_01x15_Female J2
U 1 1 600FC1CE
P 6150 3900
F 0 "J2" H 6178 3926 50 0000 L CNN
F 1 "Conn_01x15_Female" H 6178 3835 50 0000 L CNN
F 2 "Connector_PinSocket_2.54mm:PinSocket_1x15_P2.54mm_Vertical" H 6150 3900 50 0001 C CNN
F 3 "~" H 6150 3900 50 0001 C CNN
1 6150 3900
1 0 0 -1
$EndComp
$Comp
L Connector:Conn_01x15_Female J1
U 1 1 601001CE
P 3650 3400
F 0 "J1" H 3542 2475 50 0000 C CNN
F 1 "Conn_01x15_Female" H 3542 2566 50 0000 C CNN
F 2 "Connector_PinSocket_2.54mm:PinSocket_1x15_P2.54mm_Vertical" H 3650 3400 50 0001 C CNN
F 3 "~" H 3650 3400 50 0001 C CNN
1 3650 3400
-1 0 0 1
$EndComp
Wire Wire Line
4350 4100 4300 4100
Wire Wire Line
4350 3900 3850 3900
Wire Wire Line
4350 3700 4200 3700
Wire Wire Line
4350 3600 4100 3600
Wire Wire Line
4350 3500 3850 3500
Wire Wire Line
4350 3300 4100 3300
Wire Wire Line
4350 3200 3850 3200
Wire Wire Line
4350 3100 4150 3100
Wire Wire Line
4350 3000 4300 3000
Wire Wire Line
4300 3000 4300 2700
Wire Wire Line
4300 2700 3850 2700
Wire Wire Line
4350 2900 4250 2900
Wire Wire Line
4250 2900 4250 2800
Wire Wire Line
4250 2800 3850 2800
Wire Wire Line
5400 1800 4200 1800
Wire Wire Line
4200 1800 4200 2900
Wire Wire Line
4200 2900 3850 2900
$Comp
L power:GND #PWR01
U 1 1 6012CA0F
P 3850 3000
F 0 "#PWR01" H 3850 2750 50 0001 C CNN
F 1 "GND" V 3855 2872 50 0000 R CNN
F 2 "" H 3850 3000 50 0001 C CNN
F 3 "" H 3850 3000 50 0001 C CNN
1 3850 3000
0 -1 -1 0
$EndComp
$Comp
L power:GND #PWR04
U 1 1 6012D65A
P 4850 4500
F 0 "#PWR04" H 4850 4250 50 0001 C CNN
F 1 "GND" H 4855 4327 50 0000 C CNN
F 2 "" H 4850 4500 50 0001 C CNN
F 3 "" H 4850 4500 50 0001 C CNN
1 4850 4500
1 0 0 -1
$EndComp
$Comp
L power:GND #PWR05
U 1 1 6012DD3A
P 4950 4500
F 0 "#PWR05" H 4950 4250 50 0001 C CNN
F 1 "GND" H 4955 4327 50 0000 C CNN
F 2 "" H 4950 4500 50 0001 C CNN
F 3 "" H 4950 4500 50 0001 C CNN
1 4950 4500
1 0 0 -1
$EndComp
Wire Wire Line
5350 3500 5950 3500
Wire Wire Line
5350 3600 5950 3600
Wire Wire Line
5350 3700 5950 3700
Wire Wire Line
5350 3800 5950 3800
Wire Wire Line
5350 4100 5950 4100
Wire Wire Line
5350 4200 5950 4200
Wire Wire Line
5750 4400 5950 4400
$Comp
L power:GND #PWR08
U 1 1 60144FB1
P 5950 4500
F 0 "#PWR08" H 5950 4250 50 0001 C CNN
F 1 "GND" V 5955 4372 50 0000 R CNN
F 2 "" H 5950 4500 50 0001 C CNN
F 3 "" H 5950 4500 50 0001 C CNN
1 5950 4500
0 1 1 0
$EndComp
$Comp
L power:+5V #PWR09
U 1 1 60146393
P 5950 4600
F 0 "#PWR09" H 5950 4450 50 0001 C CNN
F 1 "+5V" V 5965 4728 50 0000 L CNN
F 2 "" H 5950 4600 50 0001 C CNN
F 3 "" H 5950 4600 50 0001 C CNN
1 5950 4600
0 -1 -1 0
$EndComp
$Comp
L power:VCC #PWR07
U 1 1 601470A5
P 5950 4300
F 0 "#PWR07" H 5950 4150 50 0001 C CNN
F 1 "VCC" V 5965 4427 50 0000 L CNN
F 2 "" H 5950 4300 50 0001 C CNN
F 3 "" H 5950 4300 50 0001 C CNN
1 5950 4300
0 -1 -1 0
$EndComp
Wire Wire Line
5350 3300 5400 3300
Wire Wire Line
5400 3300 5400 3400
Wire Wire Line
5400 3400 5950 3400
Wire Wire Line
4350 4200 4350 4750
Wire Wire Line
4350 4750 6400 4750
Wire Wire Line
6400 4750 6400 3050
Wire Wire Line
6400 3050 5950 3050
Wire Wire Line
5950 3050 5950 3200
$Comp
L power:+3.3V #PWR06
U 1 1 60156630
P 5950 3300
F 0 "#PWR06" H 5950 3150 50 0001 C CNN
F 1 "+3.3V" V 5965 3428 50 0000 L CNN
F 2 "" H 5950 3300 50 0001 C CNN
F 3 "" H 5950 3300 50 0001 C CNN
1 5950 3300
0 -1 -1 0
$EndComp
$Comp
L power:VCC #PWR03
U 1 1 601722BB
P 4500 5800
F 0 "#PWR03" H 4500 5650 50 0001 C CNN
F 1 "VCC" H 4515 5973 50 0000 C CNN
F 2 "" H 4500 5800 50 0001 C CNN
F 3 "" H 4500 5800 50 0001 C CNN
1 4500 5800
-1 0 0 1
$EndComp
$Comp
L power:GND #PWR012
U 1 1 60176347
P 8100 4150
F 0 "#PWR012" H 8100 3900 50 0001 C CNN
F 1 "GND" V 8105 4022 50 0000 R CNN
F 2 "" H 8100 4150 50 0001 C CNN
F 3 "" H 8100 4150 50 0001 C CNN
1 8100 4150
0 -1 1 0
$EndComp
NoConn ~ 7700 4350
$Comp
L Connector:Conn_01x02_Female J3
U 1 1 601B1E80
P 6800 5150
F 0 "J3" H 6828 5126 50 0000 L CNN
F 1 "Conn_01x02_Female" H 6828 5035 50 0000 L CNN
F 2 "Connector_PinSocket_2.54mm:PinSocket_1x02_P2.54mm_Vertical" H 6800 5150 50 0001 C CNN
F 3 "~" H 6800 5150 50 0001 C CNN
1 6800 5150
1 0 0 -1
$EndComp
$Comp
L power:GND #PWR010
U 1 1 601B2F1D
P 6600 5150
F 0 "#PWR010" H 6600 4900 50 0001 C CNN
F 1 "GND" V 6605 5022 50 0000 R CNN
F 2 "" H 6600 5150 50 0001 C CNN
F 3 "" H 6600 5150 50 0001 C CNN
1 6600 5150
0 1 1 0
$EndComp
$Comp
L power:+5V #PWR011
U 1 1 601B35EA
P 6600 5250
F 0 "#PWR011" H 6600 5100 50 0001 C CNN
F 1 "+5V" V 6615 5378 50 0000 L CNN
F 2 "" H 6600 5250 50 0001 C CNN
F 3 "" H 6600 5250 50 0001 C CNN
1 6600 5250
0 -1 -1 0
$EndComp
$Comp
L power:+3.3V #PWR014
U 1 1 601B5CED
P 4950 2500
F 0 "#PWR014" H 4950 2350 50 0001 C CNN
F 1 "+3.3V" H 4965 2673 50 0000 C CNN
F 2 "" H 4950 2500 50 0001 C CNN
F 3 "" H 4950 2500 50 0001 C CNN
1 4950 2500
1 0 0 -1
$EndComp
$Comp
L power:VCC #PWR015
U 1 1 601B6094
P 5050 2500
F 0 "#PWR015" H 5050 2350 50 0001 C CNN
F 1 "VCC" H 5065 2673 50 0000 C CNN
F 2 "" H 5050 2500 50 0001 C CNN
F 3 "" H 5050 2500 50 0001 C CNN
1 5050 2500
1 0 0 -1
$EndComp
$Comp
L power:+5V #PWR013
U 1 1 601B69BB
P 4750 2500
F 0 "#PWR013" H 4750 2350 50 0001 C CNN
F 1 "+5V" H 4765 2673 50 0000 C CNN
F 2 "" H 4750 2500 50 0001 C CNN
F 3 "" H 4750 2500 50 0001 C CNN
1 4750 2500
1 0 0 -1
$EndComp
$Comp
L custom_components:CAN_MODULE U1
U 1 1 601E578C
P 4900 5500
F 0 "U1" H 5128 5551 50 0000 L CNN
F 1 "CAN_MODULE" H 5128 5460 50 0000 L CNN
F 2 "Zeusbadge:logo_small" H 4400 5550 50 0001 C CNN
F 3 "" H 4400 5550 50 0001 C CNN
1 4900 5500
1 0 0 -1
$EndComp
$Comp
L Connector:Conn_01x07_Female J4
U 1 1 60215342
P 4700 5500
F 0 "J4" H 4728 5526 50 0000 L CNN
F 1 "Conn_01x07_Female" H 4728 5435 50 0000 L CNN
F 2 "Connector_PinSocket_2.54mm:PinSocket_1x07_P2.54mm_Vertical" H 4700 5500 50 0001 C CNN
F 3 "~" H 4700 5500 50 0001 C CNN
1 4700 5500
1 0 0 -1
$EndComp
Wire Wire Line
4350 4750 4350 5300
Wire Wire Line
4350 5300 4500 5300
Connection ~ 4350 4750
Connection ~ 4500 5300
Wire Wire Line
3850 3800 4350 3800
Wire Wire Line
3850 3400 4350 3400
Wire Wire Line
3850 4000 4250 4000
Wire Wire Line
4300 4100 4300 5500
Wire Wire Line
4300 5500 4500 5500
Connection ~ 4300 4100
Wire Wire Line
4300 4100 3850 4100
Connection ~ 4500 5500
Wire Wire Line
4500 5400 4250 5400
Wire Wire Line
4250 5400 4250 4000
Connection ~ 4500 5400
Connection ~ 4250 4000
Wire Wire Line
4250 4000 4350 4000
Wire Wire Line
4200 3700 4200 5600
Wire Wire Line
4200 5600 4500 5600
Connection ~ 4200 3700
Wire Wire Line
4200 3700 3850 3700
Connection ~ 4500 5600
$Comp
L power:GND #PWR02
U 1 1 60237003
P 4500 5700
F 0 "#PWR02" H 4500 5450 50 0001 C CNN
F 1 "GND" V 4505 5572 50 0000 R CNN
F 2 "" H 4500 5700 50 0001 C CNN
F 3 "" H 4500 5700 50 0001 C CNN
1 4500 5700
0 1 1 0
$EndComp
Connection ~ 4500 5700
Connection ~ 4500 5800
Wire Wire Line
5350 2900 5750 2900
Wire Wire Line
5750 2900 5750 4400
Wire Wire Line
5350 3000 5400 3000
Wire Wire Line
5400 3000 5400 1800
$Comp
L Device:Jumper_NO_Small JP1
U 1 1 602581FC
P 4500 5100
F 0 "JP1" V 4454 5148 50 0000 L CNN
F 1 "Jumper_NO_Small" V 4545 5148 50 0000 L CNN
F 2 "Jumper:SolderJumper-2_P1.3mm_Open_TrianglePad1.0x1.5mm" H 4500 5100 50 0001 C CNN
F 3 "~" H 4500 5100 50 0001 C CNN
1 4500 5100
0 1 1 0
$EndComp
Connection ~ 4500 5200
Wire Wire Line
4500 5000 4500 4500
Wire Wire Line
4500 4500 4150 4500
Wire Wire Line
4150 4500 4150 3100
Connection ~ 4150 3100
Wire Wire Line
4150 3100 3850 3100
Wire Wire Line
5350 4000 5950 4000
Wire Wire Line
5350 3900 5950 3900
Wire Wire Line
7400 3950 7400 1700
Wire Wire Line
7400 1700 3450 1700
Wire Wire Line
3450 1700 3450 3250
Wire Wire Line
3450 3250 4100 3250
Wire Wire Line
4100 3250 4100 3300
Connection ~ 4100 3300
Wire Wire Line
4100 3300 3850 3300
Wire Wire Line
7400 4150 7100 4150
Wire Wire Line
7100 4150 7100 6050
Wire Wire Line
7100 6050 4100 6050
Wire Wire Line
4100 6050 4100 3600
Connection ~ 4100 3600
Wire Wire Line
4100 3600 3850 3600
$EndSCHEMATC

View file

@ -0,0 +1,3 @@
EESchema-DOCLIB Version 2.0
#
#End Doc Library

View file

@ -0,0 +1,23 @@
EESchema-LIBRARY Version 2.4
#encoding utf-8
#
# CAN_MODULE
#
DEF CAN_MODULE U 0 40 Y Y 1 F N
F0 "U" -250 -400 50 H V C CNN
F1 "CAN_MODULE" -50 400 50 H V C CNN
F2 "" -500 50 50 H I C CNN
F3 "" -500 50 50 H I C CNN
DRAW
P 5 0 1 0 -300 350 -300 -350 200 -350 200 350 -300 350 f
X CS ~ -400 -100 100 R 50 50 1 1 I
X GND ~ -400 -200 100 R 50 50 1 1 W
X INT ~ -400 300 100 R 50 50 1 1 O
X SCK ~ -400 200 100 R 50 50 1 1 I
X SI ~ -400 100 100 R 50 50 1 1 I
X SO ~ -400 0 100 R 50 50 1 1 O
X VCC ~ -400 -300 100 R 50 50 1 1 W
ENDDRAW
ENDDEF
#
#End Library

View file

@ -0,0 +1,3 @@
(fp_lib_table
(lib (name can_arduino_mini_pcb)(type KiCad)(uri ${KIPRJMOD}/can_arduino_mini_pcb.pretty)(options "")(descr ""))
)

View file

@ -0,0 +1,3 @@
(sym_lib_table
(lib (name custom_components)(type Legacy)(uri ${KIPRJMOD}/custom_components.lib)(options "")(descr ""))
)

2
pcb/panel/build.sh Executable file
View file

@ -0,0 +1,2 @@
#!/bin/sh
kikit panelize grid --space 3 --gridsize 1 2 --tabwidth 5 --tabheight 10 --htabs 1 --vtabs 1 --mousebites 0.5 1 0.25 --radius 1 ../can_arduino_mini_pcb/can_arduino_mini_pcb.kicad_pcb can_arduino_mini_pcb_panel/can_arduino_mini_pcb_panel.kicad_pcb

View file

@ -0,0 +1,28 @@
# For PCBs designed using KiCad: http://www.kicad-pcb.org/
# Format documentation: http://kicad-pcb.org/help/file-formats/
# Temporary files
*.000
*.bak
*.bck
*.kicad_pcb-bak
*.kicad_sch-bak
*.kicad_prl
*.sch-bak
*~
_autosave-*
*.tmp
*-save.pro
*-save.kicad_pcb
fp-info-cache
# Netlist files (exported from Eeschema)
*.net
# Autorouter files (exported from Pcbnew)
*.dsn
*.ses
# Exported BOM files
*.xml
*.csv

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,33 @@
update=22/05/2015 07:44:53
version=1
last_client=kicad
[general]
version=1
RootSch=
BoardNm=
[pcbnew]
version=1
LastNetListRead=
UseCmpFile=1
PadDrill=0.600000000000
PadDrillOvalY=0.600000000000
PadSizeH=1.500000000000
PadSizeV=1.500000000000
PcbTextSizeV=1.500000000000
PcbTextSizeH=1.500000000000
PcbTextThickness=0.300000000000
ModuleTextSizeV=1.000000000000
ModuleTextSizeH=1.000000000000
ModuleTextSizeThickness=0.150000000000
SolderMaskClearance=0.000000000000
SolderMaskMinWidth=0.000000000000
DrawSegmentWidth=0.200000000000
BoardOutlineThickness=0.100000000000
ModuleOutlineThickness=0.150000000000
[cvpcb]
version=1
NetIExt=net
[eeschema]
version=1
LibDir=
[eeschema/libraries]

View file

@ -0,0 +1,4 @@
EESchema Schematic File Version 2
EELAYER 25 0
EELAYER END
$EndSCHEMATC

BIN
pcb/pcb_kicad.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 KiB

View file

@ -34,6 +34,7 @@ uint8_t state = STATE_INACTIVE;
struct obus_can::module connected_modules_ids[OBUS_MAX_MODULES];
uint8_t nr_connected_modules;
uint8_t nr_connected_puzzles;
uint8_t nr_solved_puzzles;
uint8_t strikes;
// Bitvector for checking if game is solved or not
@ -94,6 +95,9 @@ void add_puzzle_to_bit_vector(uint8_t module_id) {
void solve_puzzle_in_bit_vector(uint8_t module_id) {
uint8_t byte_index = module_id >> 3;
uint8_t bit_index = module_id & 0x07;
if (unsolved_puzzles[byte_index] & (0x1 << bit_index)) {
nr_solved_puzzles++;
}
unsolved_puzzles[byte_index] &= ~(0x1 << bit_index);
}
@ -175,7 +179,7 @@ void receive_hello() {
Serial.println(F("W Max # modules reached"));
}
obus_can::send_c_ack(this_module);
obus_can::send_c_ack(this_module, msg.from);
Serial.println(" ACK");
}
}
@ -189,6 +193,7 @@ void initialize_game() {
}
strikes = 0;
nr_solved_puzzles = 0;
game_start = millis();
last_draw = 0;
@ -198,7 +203,7 @@ void initialize_game() {
Serial.println(" Game started");
draw_display(millis(), OBUS_GAME_DURATION_MS);
obus_can::send_c_gamestart(this_module, OBUS_GAME_DURATION_MS, strikes, OBUS_MAX_STRIKES);
obus_can::send_c_gamestart(this_module, OBUS_GAME_DURATION_MS, strikes, OBUS_MAX_STRIKES, nr_connected_puzzles);
}
@ -254,14 +259,14 @@ void game_loop() {
if (check_solved()) {
Serial.println(" Game solved");
obus_can::send_c_solved(this_module, time_left, strikes, OBUS_MAX_STRIKES);
obus_can::send_c_solved(this_module, time_left, strikes, OBUS_MAX_STRIKES, nr_solved_puzzles);
state = STATE_GAMEOVER;
tm.displayText("dISArmEd");
return;
}
if (time_left == 0) {
Serial.println(" Time's up");
obus_can::send_c_timeout(this_module, time_left, strikes, OBUS_MAX_STRIKES);
obus_can::send_c_timeout(this_module, time_left, strikes, OBUS_MAX_STRIKES, nr_solved_puzzles);
state = STATE_GAMEOVER;
tm.displayText(" boo t");
// m
@ -271,7 +276,7 @@ void game_loop() {
}
if (strikes >= OBUS_MAX_STRIKES) {
Serial.println(" Strikeout");
obus_can::send_c_strikeout(this_module, time_left, strikes, OBUS_MAX_STRIKES);
obus_can::send_c_strikeout(this_module, time_left, strikes, OBUS_MAX_STRIKES, nr_solved_puzzles);
state = STATE_GAMEOVER;
tm.displayText(" boo S");
// m
@ -283,7 +288,7 @@ void game_loop() {
draw_display(current_time, time_left);
if (last_update + OBUS_UPDATE_INTERVAL <= current_time) {
obus_can::send_c_state(this_module, time_left, strikes, OBUS_MAX_STRIKES);
obus_can::send_c_state(this_module, time_left, strikes, OBUS_MAX_STRIKES, nr_solved_puzzles);
last_update = current_time;
}
}

View file

@ -58,8 +58,9 @@ void loop() {
}
}
void callback_game_start() {
void callback_game_start(uint8_t puzzle_modules_connected) {
// Intentionally emtpy
(void)puzzle_modules_connected;
}
void callback_game_stop() {

View file

@ -0,0 +1,6 @@
## Testmodule buttons
If the blue LED is lit, press the green button, otherwise press the red button.
### Credits
Module developed by redfast00.

View file

@ -0,0 +1,69 @@
// (c) 2020, redfast00
// See the LICENSE file for conditions for copying
// A red button connected to pin 5
// A green button connected to pin 6
// A blue led (with 330 ohm resistor) connected to pin 9
#include <obus_module.h>
#include <ezButton.h>
#define BLUE_LED 9
ezButton red_button(5);
ezButton green_button(6);
bool blue_state = false;
bool checking_input = false;
void setup() {
Serial.begin(115200);
obus_module::setup(OBUS_TYPE_PUZZLE, OBUS_PUZZLE_ID_DEVELOPMENT);
red_button.setDebounceTime(100);
green_button.setDebounceTime(100);
pinMode(BLUE_LED, OUTPUT);
}
obus_can::message message;
void loop() {
bool received = obus_module::loopPuzzle(&message, callback_game_start, callback_game_stop);
// TODO handle update frames (not needed for this module, but could be useful as example code)
red_button.loop();
green_button.loop();
if (checking_input) {
if (red_button.getCount() > 0) {
if (blue_state) {
obus_module::strike();
} else {
obus_module::solve();
checking_input = blue_state = false;
}
}
if (green_button.getCount() > 0) {
if (blue_state) {
obus_module::solve();
checking_input = blue_state = false;
} else {
obus_module::strike();
}
}
}
red_button.resetCount();
green_button.resetCount();
digitalWrite(BLUE_LED, blue_state);
}
void callback_game_start(uint8_t puzzle_modules_connected) {
(void)puzzle_modules_connected;
blue_state = random(0, 2);
checking_input = true;
}
void callback_game_stop() {
blue_state = checking_input = false;
}

View file

@ -0,0 +1,131 @@
// (c) 2020, timpy
// See the LICENSE file for conditions for copying
#include <obus_module.h>
#include <ezButton.h>
// yellow
#define DATE_CLOCK_PIN 6
// orange
#define DATE_DATA_PIN 7
// green
#define DATE_READ_PIN 5
// Solve button
#define DATE_SOLVE_BTN 3
#define DATE_MODE_STOP 1
#define DATE_MODE_1S 2
#define DATE_MODE_10S 4
#define DATE_MODE_1M 8
#define DATE_MODE_10M 16
#define DATE_MODE_TIME_IN 32
#define DATE_MODE_DATE_IN 64
#define DATE_MODE_REAL_OUT 128
#define DATE_MODE_NORM_OUT 0
uint8_t correct_code[4] = {
DATE_MODE_STOP,
12,
34,
56
};
ezButton solve_button(DATE_SOLVE_BTN);
void setup() {
Serial.begin(115200);
obus_module::setup(OBUS_TYPE_PUZZLE, 123);
solve_button.setDebounceTime(10);
solve_button.setCountMode(COUNT_RISING);
setup_date_module();
}
obus_can::message message;
void loop() {
bool received = obus_module::loopPuzzle(&message, callback_game_start, callback_game_stop);
// TODO handle update frames (not needed for this module, but could be useful as example code)
solve_button.loop();
if (solve_button.getCount() > 0) {
uint8_t data[4];
read_from_date_module(data);
if (check_date_code(data)) {
Serial.println("SOLVED!");
obus_module::solve();
} else {
Serial.println("STRIKE!");
obus_module::strike();
}
solve_button.resetCount();
}
}
void setup_date_module() {
pinMode(DATE_CLOCK_PIN, OUTPUT);
pinMode(DATE_DATA_PIN, INPUT);
pinMode(DATE_READ_PIN, OUTPUT);
}
uint8_t read_value_from_date_module(uint8_t bit_order) {
digitalWrite(DATE_CLOCK_PIN, LOW);
uint8_t value = 0;
for (int i = 0; i < 8; i++) {
uint8_t read_bit = digitalRead(DATE_DATA_PIN);
if (bit_order == LSBFIRST)
value |= read_bit << i;
else
value |= read_bit << (7 - i);
digitalWrite(DATE_CLOCK_PIN, HIGH);
delayMicroseconds(3);
digitalWrite(DATE_CLOCK_PIN, LOW);
}
return value;
}
void read_from_date_module(uint8_t* data_out) {
digitalWrite(DATE_READ_PIN, HIGH);
delayMicroseconds(3);
digitalWrite(DATE_READ_PIN, LOW);
for (int i = 0; i < 4; i++) {
data_out[i] = read_value_from_date_module(LSBFIRST);
}
for (int i = 1; i < 4; i++) {
// Convert raw data to human interpretable number
data_out[i] = 10*(data_out[i] & 0x0F) + ((data_out[i] & 0xF0) >> 4);
}
//for (int i = 0; i < 4; i++) {
// Serial.print(data_out[i]);
// Serial.print(" ");
//}
//Serial.println();
digitalWrite(DATE_CLOCK_PIN, LOW);
}
bool check_date_code(uint8_t* code) {
for (int i = 0; i < 4; i++) {
if (code[i] != correct_code[i]) {
return false;
}
}
return true;
}
void callback_game_start(uint8_t puzzle_modules_connected) {
// Intentionally emtpy
(void)puzzle_modules_connected;
}
void callback_game_stop() {
// Intentionally empty
}

View file

@ -1,43 +0,0 @@
// (c) 2020, redfast00
// See the LICENSE file for conditions for copying
#include <obus_module.h>
#include <ezButton.h>
ezButton red_button(5);
ezButton green_button(6);
void setup() {
Serial.begin(115200);
obus_module::setup(OBUS_TYPE_PUZZLE, OBUS_PUZZLE_ID_DEVELOPMENT);
red_button.setDebounceTime(100);
green_button.setDebounceTime(100);
}
obus_can::message message;
void loop() {
bool received = obus_module::loopPuzzle(&message, callback_game_start, callback_game_stop);
// TODO handle update frames (not needed for this module, but could be useful as example code)
red_button.loop();
green_button.loop();
if (red_button.getCount() > 0) {
red_button.resetCount();
obus_module::strike();
}
if (green_button.getCount() > 0) {
green_button.resetCount();
obus_module::solve();
}
}
void callback_game_start() {
// Intentionally emtpy
}
void callback_game_stop() {
// Intentionally empty
}

View file

@ -1,6 +0,0 @@
## Testmodule buttons
Don't press the red button. Press the green button to solve the module.
### Credits
Module developed by redfast00.

View file

@ -1,130 +0,0 @@
// (c) 2020, timpy
// See the LICENSE file for conditions for copying
#include <obus_module.h>
#include <ezButton.h>
// yellow
#define DATE_CLOCK_PIN 6
// orange
#define DATE_DATA_PIN 7
// green
#define DATE_READ_PIN 5
// Solve button
#define DATE_SOLVE_BTN 3
#define DATE_MODE_STOP 1
#define DATE_MODE_1S 2
#define DATE_MODE_10S 4
#define DATE_MODE_1M 8
#define DATE_MODE_10M 16
#define DATE_MODE_TIME_IN 32
#define DATE_MODE_DATE_IN 64
#define DATE_MODE_REAL_OUT 128
#define DATE_MODE_NORM_OUT 0
uint8_t correct_code[4] = {
DATE_MODE_STOP,
12,
34,
56
};
ezButton solve_button(DATE_SOLVE_BTN);
void setup() {
Serial.begin(115200);
obus_module::setup(OBUS_TYPE_PUZZLE, 123);
solve_button.setDebounceTime(10);
solve_button.setCountMode(COUNT_RISING);
setup_date_module();
}
obus_can::message message;
void loop() {
bool received = obus_module::loopPuzzle(&message, callback_game_start, callback_game_stop);
// TODO handle update frames (not needed for this module, but could be useful as example code)
solve_button.loop();
if (solve_button.getCount() > 0) {
uint8_t data[4];
read_from_date_module(data);
if (check_date_code(data)) {
Serial.println("SOLVED!");
obus_module::solve();
} else {
Serial.println("STRIKE!");
obus_module::strike();
}
solve_button.resetCount();
}
}
void setup_date_module() {
pinMode(DATE_CLOCK_PIN, OUTPUT);
pinMode(DATE_DATA_PIN, INPUT);
pinMode(DATE_READ_PIN, OUTPUT);
}
uint8_t read_value_from_date_module(uint8_t bit_order) {
digitalWrite(DATE_CLOCK_PIN, LOW);
uint8_t value = 0;
for (int i = 0; i < 8; i++) {
uint8_t read_bit = digitalRead(DATE_DATA_PIN);
if (bit_order == LSBFIRST)
value |= read_bit << i;
else
value |= read_bit << (7 - i);
digitalWrite(DATE_CLOCK_PIN, HIGH);
delay(1);
digitalWrite(DATE_CLOCK_PIN, LOW);
}
return value;
}
void read_from_date_module(uint8_t* data_out) {
digitalWrite(DATE_READ_PIN, HIGH);
delay(200);
digitalWrite(DATE_READ_PIN, LOW);
for (int i = 0; i < 4; i++) {
data_out[i] = read_value_from_date_module(LSBFIRST);
}
for (int i = 1; i < 4; i++) {
// Convert raw data to human interpretable number
data_out[i] = 10*(data_out[i] & 0x0F) + ((data_out[i] & 0xF0) >> 4);
}
//for (int i = 0; i < 4; i++) {
// Serial.print(data_out[i]);
// Serial.print(" ");
//}
//Serial.println();
digitalWrite(DATE_CLOCK_PIN, LOW);
}
bool check_date_code(uint8_t* code) {
for (int i = 0; i < 4; i++) {
if (code[i] != correct_code[i]) {
return false;
}
}
return true;
}
void callback_game_start() {
// Intentionally emtpy
}
void callback_game_stop() {
// Intentionally empty
}

View file

@ -12,12 +12,16 @@ if [ ! -d ./template_module ]; then
exit 1
fi
# Ask for module type
print "Type of module (puzzle/needy/info): "
read module_type
# Ask for module name
print "Name of module (e.g. Oil gauge): "
read module_name
# Determine a "clean" module name for paths: lowercase, no spaces
module="`print "$module_name" | tr [A-Z] [a-z] | sed "s/ /_/g;s/'//g"`"
module="`print "${module_type}_${module_name}" | tr [A-Z] [a-z] | sed "s/ /_/g;s/'//g"`"
# Make sure `modules` directory exists and target directory doesn't
mkdir -p modules
@ -35,7 +39,19 @@ read author
cp -r -- template_module "$module_dir"
cd -- "$module_dir"
# Disallow % in fields that will be used in %-delimited ed substitution
# Fill in the blanks in the template
# `sed -i` is not portable so we create something like it ourselves
sed_inplace="`mktemp`"
cleanup_sed() { rm -f -- "$sed_inplace"; }
trap cleanup_sed EXIT
print '
filename="$1"
shift 1
tmpfile="`mktemp`"
sed "$@" -- "$filename" > "$tmpfile"
mv -- "$tmpfile" "$filename"
' > "$sed_inplace"
chmod 0500 -- "$sed_inplace" # Make executable
assert_no_percent() {
case "$1" in
*"%"*) println "$2 must not contain %" >&2; exit 1 ;;
@ -44,25 +60,11 @@ assert_no_percent() {
assert_no_percent "$author" "Author name"
assert_no_percent "$module_name" "Module name"
assert_no_percent "$module" "Module path name"
# Fill in the blanks in the template
# `sed -i` is not portable so we create something like it ourselves
reced() {
for file in "$1"/*; do
if [ -f "$file" ]; then
ed "$file" <<HERE
%s/{YEAR}/$(date +%Y)/
%s%{AUTHOR}%$author%
%s%{MODULE_NAME}%$module_name%
%s%{MODULE}%$module%
wq
HERE
elif [ -d "$file" ]; then
reced "$file"
fi
done
}
reced .
find . -type f -exec "$sed_inplace" '{}' -e "
s/{YEAR}/$(date +%Y)/
s%{AUTHOR}%$author%
s%{MODULE_NAME}%$module_name%
s%{MODULE}%$module%" \;
# Arduino IDE requires .ino sketches to have the same name as their directory
mv -- main.ino "$module.ino"

View file

@ -16,8 +16,8 @@ void setup() {
obus_can::message message;
void loop() {
bool is_message_valid = obus_module::loop_puzzle(&message, callback_game_start, callback_game_stop);
// bool bool is_message_valid = obus_module::loop_needy(&message);
bool is_message_valid = obus_module::loopPuzzle(&message, callback_game_start, callback_game_stop);
// bool is_message_valid = obus_module::loopNeedy(&message, callback_game_start, callback_game_stop);
}
void callback_game_start() {