Skip to content
Snippets Groups Projects
Commit 577610cc authored by chris007's avatar chris007
Browse files

Merge branch 'master' into bme680

parents 5cead188 4d77b5c4
No related branches found
No related tags found
1 merge request!147Integration of BME680 Sensor (#33)
How To Build
============
If you just want to write MicroPython code for card10, you probably **won't**
need to build the firmware yourself. This page is for people who want to work
on the underlying firmware itself.
need to build the firmware yourself. This page is for people **who want to work
on the underlying firmware itself**.
Dependencies
------------
......@@ -27,7 +27,20 @@ Dependencies
dnf install arm-none-eabi-gcc arm-none-eabi-binutils arm-none-eabi-newlib
- macOS (Note: The card10 firmware team used Linux so far. macOS recommendations here are experimental.)
You can use `Homebrew`_ to install the required tools.
The version of the Arm crosscompiler tool chain is quite important; with the wrong version, e.g. strip and/or ld might throw strange errors.
.. code-block:: shell-session
brew tap px4/px4
brew install px4/px4/gcc-arm-none-eabi-63
brew install coreutils
- Alternative: Download `ARM's GNU toolchain`_. **TODO**
.. _Homebrew: https://brew.sh/
* **python3**: For meson and various scripts needed for building.
* **meson** (>0.43.0) & **ninja**: Unfortunately most distros only have very old versions
of meson in their repositories. Instead, you'll probably save yourself a lot
......@@ -46,9 +59,22 @@ Dependencies
pacman -S meson
- macOS
.. code-block:: shell-session
brew install ninja
pip3 install --user meson # see https://mesonbuild.com/Getting-meson.html - you will have to add ~/.local/bin to your PATH.
* **python3-crc16**: Install with ``pip3 install --user crc16``.
* **python3-pillow**: Python Image Library ``pip3 install --user pillow``.
- Arch
.. code-block:: shell-session
pacman -S python-crc16 python-pillow
.. _ARM's GNU toolchain: https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads
Cloning
......
......@@ -2,7 +2,8 @@
``os`` - OS Functions
=====================
The ``os`` module allows access to a few core functionalities of Epicardium and functions found in CPythons ``os`` module.
The ``os`` module allows access to a few core functionalities of Epicardium and
functions found in CPythons ``os`` module.
CPython-Like
------------
......@@ -29,8 +30,8 @@ CPython-Like
:returns: ``bytes()`` object with ``n`` random bytes.
Epicardium-Specific
-------------------
Card10-Specific
---------------
.. py:function:: exit(ret = None)
......@@ -52,6 +53,15 @@ Epicardium-Specific
:param str name: Path to new app/script/l0dable.
:return: This function never returns. It can, however raise an exception.
.. py:function:: read_battery()
Read the current battery voltage in V. Please keep in mind that battery
voltage behaves exponentially when interpreting this value.
.. warning::
Card10 will hard-shutdown once the voltage drops below 3.4 V
.. py:function:: reset()
Reboot card10.
......
......@@ -2,7 +2,12 @@
``personal_state`` - Personal State
===================================
The :py:mod:`personal_state` module allows you to set and get the card10 users personal state from your script. The personal state is displayed on the top-left LED on the bottom of the harmonics board. While the personal state is set the LED can't be controlled by the :py:mod:`leds` module.
The :py:mod:`personal_state` module allows you to set and get the card10 users
`personal state`_ from your script. The personal state is displayed on the
top-left LED on the bottom of the harmonics board. While the personal state is
set the LED can't be controlled by the :py:mod:`leds` module.
.. _personal state: https://card10.badge.events.ccc.de/ps/
**Example**:
......@@ -26,8 +31,13 @@ The :py:mod:`personal_state` module allows you to set and get the card10 users p
Set the users personal state.
:param int state: ID of the personal state to set. Must be one of :py:data:`personal_state.NO_CONTACT`, :py:data:`personal_state.CHAOS`, :py:data:`personal_state.COMMUNICATION`, :py:data:`personal_state.CAMP`.
:param int persistent: Controls whether the personal state is persistent. A persistent state is not reset when the pycardium application is changed or restarted. In persistent mode the personal state LED is not controllable by the pycardium application.
:param int state: ID of the personal state to set. Must be one of
:py:data:`personal_state.NO_CONTACT`, :py:data:`personal_state.CHAOS`,
:py:data:`personal_state.COMMUNICATION`, :py:data:`personal_state.CAMP`.
:param int persistent: Controls whether the personal state is persistent. A
persistent state is not reset when the pycardium application is changed
or restarted. In persistent mode the personal state LED is not
controllable by the pycardium application.
.. py:function:: clear()
......@@ -40,7 +50,8 @@ The :py:mod:`personal_state` module allows you to set and get the card10 users p
Get the users personal state.
:returns: A tuple containing the currently set state and a boolean indicating if it's persistent or not.
:returns: A tuple containing the currently set state and a boolean
indicating if it's persistent or not.
.. py:data:: NO_STATE
......
......@@ -33,6 +33,7 @@
#include "hci_vs.h"
#include <epicardium.h>
#include "modules/log.h"
#include "util/bstream.h"
#include "att_api.h"
......@@ -40,6 +41,7 @@
#include "FreeRTOS.h"
#include "crc32.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
......@@ -217,9 +219,11 @@ static void sendCrcResponse(
msg,
sizeof(answer) - len);
len += strlen(msg);
printf("BLE file transfer: %s\n", msg);
LOG_ERR("filetrans", "%s\n", msg);
} else {
printf("error message \"%s\" too long\n", msg);
LOG_ERR("filetrans",
"error message \"%s\" too long\n",
msg);
}
}
......@@ -227,6 +231,41 @@ static void sendCrcResponse(
AttsHandleValueNtf(connId, FILE_TRANS_CENTRAL_RX_VAL_HDL, len, answer);
}
/*
* This function splits the path into the folders and the file name and
* creates all the missing folders.
*/
static int bleFileCreateOrOpen(char *filepath)
{
char *pathEnd;
int pos = 0;
int ret;
while (true) {
pathEnd = strchr(filepath + pos, '/');
if (!pathEnd)
return epic_file_open(filepath, "w");
pathEnd[0] = '\00';
pos = pathEnd - filepath + 1;
if (strlen(filepath)) {
ret = epic_file_stat(filepath, NULL);
if (ret == -ENOENT) {
ret = epic_file_mkdir(filepath);
if (ret) {
LOG_ERR("filetrans",
"mkdir failed: %s, ret: %i\n",
filepath,
ret);
return ret;
}
}
}
pathEnd[0] = '/';
}
}
static uint8_t bleFileOpen(dmConnId_t connId, uint8_t *pValue, uint16_t len)
{
char filepath[100];
......@@ -238,11 +277,12 @@ static uint8_t bleFileOpen(dmConnId_t connId, uint8_t *pValue, uint16_t len)
/* Copy only file path and not type, make sure this is NULL terminated */
strncpy(filepath, (char *)pValue + 1, len - 1);
filepath[len - 1] = 0;
if (file_fd != -1)
epic_file_close(file_fd);
file_fd = epic_file_open(filepath, "w");
file_fd = bleFileCreateOrOpen(filepath);
if (file_fd < 0) {
sendCrcResponse(connId, 'e', 0, NULL, "open failed");
return ATT_ERR_RESOURCES;
......@@ -305,7 +345,8 @@ static uint8_t handleCentralTX(
} else if (
operation != ATT_PDU_EXEC_WRITE_REQ &&
operation != ATT_PDU_WRITE_CMD) {
printf("operation 0x%x not supported, try normal write\n",
LOG_ERR("filetrans",
"operation 0x%x not supported, try normal write\n",
operation);
return ATT_ERR_INVALID_PDU;
}
......@@ -334,7 +375,7 @@ static uint8_t handleCentralTX(
return ATT_SUCCESS;
case 'E':
printf("Error was acked");
LOG_ERR("filetrans", "Error was acked");
return ATT_SUCCESS;
default:
......@@ -365,7 +406,9 @@ static uint8_t writeCallback(
connId, handle, operation, offset, len, pValue, pAttr
);
default:
printf("unsupported characteristic: %c\n", handle);
LOG_ERR("filetrans",
"unsupported characteristic: %c\n",
handle);
return ATT_ERR_HANDLE;
}
}
......@@ -377,7 +420,7 @@ static uint8_t readCallback(
uint16_t offset,
attsAttr_t *pAttr
) {
printf("read callback\n");
LOG_ERR("filetrans", "read callback\n");
return ATT_SUCCESS;
}
......
......@@ -86,17 +86,25 @@ void gfx_puts(
Color fg,
Color bg
) {
// iterate over the string
while (*str) {
gfx_putchar(font, r, x, y, *str, fg, bg);
str++;
x += font->Width;
if (x >= r->width) {
// if the current position plus the width of the next character
// would bring us outside of the display ...
if ((x + font->Width) > r->width) {
// ... we move down a line before printing the character
x = 0;
y += font->Height;
}
// if the line is outside the display we return
if (y >= r->height)
return;
// now print the character
gfx_putchar(font, r, x, y, *str, fg, bg);
str++;
// move along on the x axis to get the position of the next character
x += font->Width;
}
}
......
......@@ -7,7 +7,6 @@ Improvement ideas
- fade effekt
- led nick writing
"""
import utime
import display
import leds
......@@ -19,7 +18,7 @@ import os
FILENAME = 'nickname.txt'
FILENAME_ADV = 'nickname.json'
ANIM_TYPES = ['none', 'led', 'fade']
ANIM_TYPES = ['none', 'led', 'fade', 'gay']
def render_error(err1, err2):
......@@ -31,24 +30,70 @@ def render_error(err1, err2):
disp.close()
def get_time():
timestamp = ''
if utime.localtime()[3] < 10:
timestamp = timestamp + '0'
timestamp = timestamp + str(utime.localtime()[3]) + ':'
if utime.localtime()[4] < 10:
timestamp = timestamp + '0'
timestamp = timestamp + str(utime.localtime()[4]) + ':'
if utime.localtime()[5] < 10:
timestamp = timestamp + '0'
timestamp = timestamp + str(utime.localtime()[5])
return timestamp
def toggle_rockets(state):
brightness = 15
if not state:
brightness = 0
leds.set_rocket(0, brightness)
leds.set_rocket(1, brightness)
leds.set_rocket(2, brightness)
def render_nickname(title, sub, fg, bg, fg_sub, bg_sub, main_bg):
anim = 'led'
anim = 0
posy = 30
if sub != '':
posy = 18
r = 255
g = 0
b = 0
r_sub = sub
last_btn_poll = utime.time() - 2
while True:
sleep = 0.5
if sub == '#time':
r_sub = get_time()
dark = 0
if light_sensor.get_reading() < 30:
if light_sensor.get_reading() < 40:
dark = 1
r_fg_color = fg[dark]
r_bg_color = bg[dark]
r_fg_sub_color = fg_sub[dark]
r_bg_sub_color = bg_sub[dark]
r_bg = main_bg[dark]
if anim == 'fade':
# Button handling
pressed = buttons.read(
buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT
)
if utime.time() - last_btn_poll >= 1:
last_btn_poll = utime.time()
if pressed & buttons.BOTTOM_RIGHT != 0:
anim = anim + 1
if anim >= len(ANIM_TYPES):
anim = 0
if pressed & buttons.BOTTOM_LEFT != 0:
anim = anim - 1
if anim < 0:
anim = len(ANIM_TYPES) - 1
# Animations
if ANIM_TYPES[anim] == 'fade':
sleep = 0.1
leds.clear()
toggle_rockets(False)
if r > 0 and b == 0:
r = r - 1
g = g + 1
......@@ -59,34 +104,32 @@ def render_nickname(title, sub, fg, bg, fg_sub, bg_sub, main_bg):
r = r + 1
b = b - 1
r_bg = [r, g, b]
if anim == 'led':
r_bg_color = r_bg
r_bg_sub_color = r_bg
if ANIM_TYPES[anim] == 'led':
if dark == 1:
for i in range(0, 11):
leds.prep(i, r_bg)
leds.update()
leds.dim_top(3)
leds.set_rocket(0, 15)
leds.set_rocket(1, 15)
leds.set_rocket(2, 15)
if anim == 'none':
leds.dim_top(4)
toggle_rockets(True)
else:
leds.clear()
toggle_rockets(False)
if ANIM_TYPES[anim] == 'gay':
toggle_rockets(False)
leds.gay(0.4)
if ANIM_TYPES[anim] == 'none':
leds.clear()
leds.set_rocket(0, 0)
leds.set_rocket(1, 0)
leds.set_rocket(2, 0)
toggle_rockets(False)
with display.open() as disp:
disp.rect(0, 0, 160, 80, col=r_bg, filled=True)
disp.print(title, fg=r_fg_color, bg=r_bg_color, posx=80 - round(len(title) / 2 * 14), posy=posy)
if sub != '':
disp.print(sub, fg=r_fg_sub_color, bg=r_bg_sub_color, posx=80 - round(len(sub) / 2 * 14), posy=42)
if r_sub != '':
disp.print(r_sub, fg=r_fg_sub_color, bg=r_bg_sub_color, posx=80 - round(len(r_sub) / 2 * 14), posy=42)
disp.update()
disp.close()
pressed = buttons.read(
buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT
)
if pressed & buttons.BOTTOM_LEFT != 0:
anim = ANIM_TYPES[1]
if pressed & buttons.BOTTOM_RIGHT != 0:
anim = ANIM_TYPES[0]
utime.sleep(0.3)
utime.sleep(sleep)
def get_key(json, key, default):
......@@ -95,12 +138,10 @@ def get_key(json, key, default):
except KeyError:
return default
leds.clear()
with display.open() as disp:
disp.clear().update()
disp.close()
if FILENAME_ADV in os.listdir("."):
f = open(FILENAME_ADV, 'r')
try:
......
{"name":"Card10 Nickname","description":"Nickname app for the card10 badge\r\n\r\nEverything you need can be found here: https:\/\/github.com\/vabene1111\/card10-nickname","category":"graphics","author":"vabene1111","revision":3}
\ No newline at end of file
{"name":"Card10 Nickname","description":"Nickname app for the card10 badge\r\n\r\nEverything you need can be found here: https:\/\/github.com\/vabene1111\/card10-nickname","category":"graphics","author":"vabene1111","revision":4}
\ No newline at end of file
import display
import leds
import utime
_rand = 123456789
def rand():
global _rand
_rand = (1103515245 * _rand + 12345) & 0xffffff
return _rand
gs = 160
colors = [ ((i>>2)*gs, (i>>1&1)*gs, (i&1)*gs) for i in range(1, 8) ]
nick = 'sample text'
try:
with open('/nickname.txt') as f:
nick = f.read()
except:
pass
while True:
with display.open() as d:
for k in range(4):
(x1, y1) = (rand()%159, rand()%79)
(x2, y2) = (min(x1+rand()%40, 159), min(y1+rand()%40, 79))
try:
d.rect(x1, y1, x2, y2, col=colors[rand() % len(colors)], filled=True)
except:
pass
fg = colors[rand()%len(colors)]
nx = 80-round(len(nick)/2 * 14)
d.print(nick, fg=fg, bg=[0xff-c for c in fg], posx=(nx-8)+rand()%16, posy=22+rand()%16)
d.update()
d.close()
leds.set(rand() % 11, colors[rand() % len(colors)])
leds.set_rocket(rand() % 3, rand() % 32)
utime.sleep_us(1) # Feed watch doge
\ No newline at end of file
{"name":"LSD-Nickname","description":"Renderer for nickname.txt, but oh god what the fuck","category":"graphics","author":"polyfloyd","revision":1}
\ No newline at end of file
import leds, utime, math
import leds
import math
import utime
def col_cor(colors, brightness=1, gamma=1):
......@@ -13,11 +15,14 @@ def col_cor(colors, brightness=1, gamma=1):
def halo(colors):
"""
sets the four bottom/side LEDs to colors corresponding to the color spectrum on the outermost of the top 11 LEDs
Set the four bottom/side LEDs to colors corresponding to the color spectrum
on the outermost of the top 11 LEDs.
"""
used_leds = len(colors)
# add additional RGB-Color-lists to the colors-list to fill up the top LEDs with emptiness
colors += [[0, 0, 0]] * (11 - used_leds)
# add four additional colors. the last one, the first one twice, the last one.
colors += [colors[used_leds - 1]] + [colors[0]] * 2 + [colors[used_leds - 1]]
return colors
......@@ -30,22 +35,31 @@ def kitt(
minimum=0.3,
rgb=[255, 0, 0],
spectrum=[],
halo=False,
):
"""
LED Animation. Knight rider-Style.
:param cycles: amount of cycles for the animation
:param delay: time in microseconds until the animation moves on. (we could also call it framerate)
:param power: the shape of your brightness curve. bigger values make a steeper curve, smaller values make the curve wider.
:param minimum: the minimal brightness
:param rgb: if you don't enter a spectrum this is the color we'll use
:param specttrum: a color spectrum consisting of up to 11 RGB-Value-Lists (e.g. [[255,255,255], [0,0,0], [255,255,255] and so on] - ). if you use less, the animation will be less wide.
:param int cycles: Amount of cycles for the animation
:param int delay: Time in microseconds until the animation moves on (Inverse of Framerate).
:param int power: Shape of your brightness curve. Bigger values make a
steeper curve, smaller values make the curve wider.
:param float minimum: Minimal brightness.
:param [r,g,b] rgb: If you don't enter a spectrum this is the color used.
:param list spectrum: A color spectrum consisting of up to 11 RGB-Value-Lists
(e.g. ``[[255,255,255], [0,0,0], [255,255,255], ...]`` ). If you use
less, the animation will be less wide.
:param func halo: Halo function. See :py:func:`ledfx.halo`.
"""
# create a basic table of values for a smooth increment of the LED brightness (if you don't understand this, don't worry, i don't either. just paste it into the python shell and see the output). Basically creates a negative cosinus curve.
# create a basic table of values for a smooth increment of the LED
# brightness (if you don't understand this, don't worry, i don't either.
# just paste it into the python shell and see the output). Basically
# creates a negative cosinus curve.
kitt_table = [((-math.cos(math.pi * (x / 10.0))) + 1) / 2.0 for x in range(21)]
#adjust the values to start with a minimum brightness and the width of the curve to the given power.
# adjust the values to start with a minimum brightness and the width of the
# curve to the given power.
kitt_table = [math.pow(x, power) * (1 - minimum) + minimum for x in kitt_table]
# for the amount of specified cycles
......@@ -55,26 +69,27 @@ def kitt(
# and go backwards after 10 steps
if j > 10:
j = 20 - j
#if a color spectrum wasn't given
if spectrum == []:
#set the amount of LEDs used to 11, because we're using the full width
used_leds = 11
#set the color values to the LEDs by multiplying the given color value with the corresponding brightness value in the kitt table
# set the color values to the LEDs by multiplying the given color
# value with the corresponding brightness value in the kitt table
output = [[int(x * y) for y in rgb] for x in kitt_table[j : (j + used_leds)]]
else:
#use the amount of leds specified in the spectrum
used_leds = len(spectrum)
#multiply the color values in the corresponding spectrum tuple with the brightness value in the kitt table
# multiply the color values in the corresponding spectrum tuple
# with the brightness value in the kitt table
output = [
[int(y * kitt_table[j + x]) for y in spectrum[x]]
for x in range(used_leds)
]
#if a halo is True, also use the four bottom LEDs
if halo:
halo(output)
#set the LEDs to the output defined above
leds.set_all(output)
#sleep for the amount of milliseconds specified in delay
utime.sleep_ms(delay)
#Switch off all LEDs.
leds.clear()
meson~=0.51.1
crc16~=0.1.1
pillow~=6.1.0
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment