Compare commits
No commits in common. "moonrise" and "theAlexes/add-openocd" have entirely different histories.
moonrise
...
theAlexes/
@ -1,4 +1,6 @@
|
|||||||
FROM ubuntu:24.04
|
FROM ubuntu:22.10
|
||||||
|
|
||||||
|
# TODO: install emscripten (https://emscripten.org/docs/getting_started/downloads.html)
|
||||||
|
|
||||||
# TODO: Clean this up once buildkit is supported gracefully in devcontainers
|
# TODO: Clean this up once buildkit is supported gracefully in devcontainers
|
||||||
# https://github.com/microsoft/vscode-remote-release/issues/1409
|
# https://github.com/microsoft/vscode-remote-release/issues/1409
|
||||||
@ -25,9 +27,7 @@ RUN apt-get update \
|
|||||||
# ca certs need to be available for fetching git submodules
|
# ca certs need to be available for fetching git submodules
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
# python is used to convert binaries to uf2 files
|
# python is used to convert binaries to uf2 files
|
||||||
python3 python-is-python3 \
|
python3 python-is-python3
|
||||||
# emscripten for building simulator
|
|
||||||
emscripten
|
|
||||||
|
|
||||||
# Download and verify both x86-64 and aarch64 toolchains. This is unfortunate and
|
# Download and verify both x86-64 and aarch64 toolchains. This is unfortunate and
|
||||||
# slows down the build, but it's a clean-ish option until buildkit can be used.
|
# slows down the build, but it's a clean-ish option until buildkit can be used.
|
||||||
|
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@ -29,7 +29,7 @@ jobs:
|
|||||||
run: make
|
run: make
|
||||||
working-directory: 'movement/make'
|
working-directory: 'movement/make'
|
||||||
- name: Upload UF2
|
- name: Upload UF2
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: watch.uf2
|
name: watch.uf2
|
||||||
path: movement/make/build/watch.uf2
|
path: movement/make/build/watch.uf2
|
||||||
@ -52,7 +52,7 @@ jobs:
|
|||||||
cp watch.html index.html
|
cp watch.html index.html
|
||||||
tar -czf simulator.tar.gz index.html watch.wasm watch.js
|
tar -czf simulator.tar.gz index.html watch.wasm watch.js
|
||||||
- name: Upload simulator build
|
- name: Upload simulator build
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: simulator.tar.gz
|
name: simulator.tar.gz
|
||||||
path: movement/make/build-sim/simulator.tar.gz
|
path: movement/make/build-sim/simulator.tar.gz
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,83 +0,0 @@
|
|||||||
{
|
|
||||||
"board": {
|
|
||||||
"active_layer": 31,
|
|
||||||
"active_layer_preset": "",
|
|
||||||
"auto_track_width": true,
|
|
||||||
"hidden_netclasses": [],
|
|
||||||
"hidden_nets": [],
|
|
||||||
"high_contrast_mode": 0,
|
|
||||||
"net_color_mode": 1,
|
|
||||||
"opacity": {
|
|
||||||
"images": 0.6,
|
|
||||||
"pads": 1.0,
|
|
||||||
"tracks": 1.0,
|
|
||||||
"vias": 1.0,
|
|
||||||
"zones": 0.6
|
|
||||||
},
|
|
||||||
"ratsnest_display_mode": 0,
|
|
||||||
"selection_filter": {
|
|
||||||
"dimensions": true,
|
|
||||||
"footprints": true,
|
|
||||||
"graphics": true,
|
|
||||||
"keepouts": true,
|
|
||||||
"lockedItems": true,
|
|
||||||
"otherItems": true,
|
|
||||||
"pads": true,
|
|
||||||
"text": true,
|
|
||||||
"tracks": true,
|
|
||||||
"vias": true,
|
|
||||||
"zones": true
|
|
||||||
},
|
|
||||||
"visible_items": [
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
3,
|
|
||||||
4,
|
|
||||||
5,
|
|
||||||
8,
|
|
||||||
9,
|
|
||||||
10,
|
|
||||||
11,
|
|
||||||
12,
|
|
||||||
13,
|
|
||||||
14,
|
|
||||||
15,
|
|
||||||
16,
|
|
||||||
17,
|
|
||||||
18,
|
|
||||||
19,
|
|
||||||
20,
|
|
||||||
21,
|
|
||||||
22,
|
|
||||||
23,
|
|
||||||
24,
|
|
||||||
25,
|
|
||||||
26,
|
|
||||||
27,
|
|
||||||
28,
|
|
||||||
29,
|
|
||||||
30,
|
|
||||||
32,
|
|
||||||
33,
|
|
||||||
34,
|
|
||||||
35,
|
|
||||||
36
|
|
||||||
],
|
|
||||||
"visible_layers": "00290aa_80000007",
|
|
||||||
"zone_display_mode": 0
|
|
||||||
},
|
|
||||||
"git": {
|
|
||||||
"repo_password": "",
|
|
||||||
"repo_type": "",
|
|
||||||
"repo_username": "",
|
|
||||||
"ssh_key": ""
|
|
||||||
},
|
|
||||||
"meta": {
|
|
||||||
"filename": "OSO-SWAT-C1-rounded.kicad_prl",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"project": {
|
|
||||||
"files": []
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,692 +0,0 @@
|
|||||||
{
|
|
||||||
"board": {
|
|
||||||
"3dviewports": [],
|
|
||||||
"design_settings": {
|
|
||||||
"defaults": {
|
|
||||||
"apply_defaults_to_fp_fields": false,
|
|
||||||
"apply_defaults_to_fp_shapes": false,
|
|
||||||
"apply_defaults_to_fp_text": false,
|
|
||||||
"board_outline_line_width": 0.05,
|
|
||||||
"copper_line_width": 0.2,
|
|
||||||
"copper_text_italic": false,
|
|
||||||
"copper_text_size_h": 1.5,
|
|
||||||
"copper_text_size_v": 1.5,
|
|
||||||
"copper_text_thickness": 0.3,
|
|
||||||
"copper_text_upright": false,
|
|
||||||
"courtyard_line_width": 0.05,
|
|
||||||
"dimension_precision": 4,
|
|
||||||
"dimension_units": 3,
|
|
||||||
"dimensions": {
|
|
||||||
"arrow_length": 1270000,
|
|
||||||
"extension_offset": 500000,
|
|
||||||
"keep_text_aligned": true,
|
|
||||||
"suppress_zeroes": false,
|
|
||||||
"text_position": 0,
|
|
||||||
"units_format": 1
|
|
||||||
},
|
|
||||||
"fab_line_width": 0.1,
|
|
||||||
"fab_text_italic": false,
|
|
||||||
"fab_text_size_h": 1.0,
|
|
||||||
"fab_text_size_v": 1.0,
|
|
||||||
"fab_text_thickness": 0.15,
|
|
||||||
"fab_text_upright": false,
|
|
||||||
"other_line_width": 0.1,
|
|
||||||
"other_text_italic": false,
|
|
||||||
"other_text_size_h": 1.0,
|
|
||||||
"other_text_size_v": 1.0,
|
|
||||||
"other_text_thickness": 0.15,
|
|
||||||
"other_text_upright": false,
|
|
||||||
"pads": {
|
|
||||||
"drill": 0.9,
|
|
||||||
"height": 0.9,
|
|
||||||
"width": 0.9
|
|
||||||
},
|
|
||||||
"silk_line_width": 0.12,
|
|
||||||
"silk_text_italic": false,
|
|
||||||
"silk_text_size_h": 1.0,
|
|
||||||
"silk_text_size_v": 1.0,
|
|
||||||
"silk_text_thickness": 0.15,
|
|
||||||
"silk_text_upright": false,
|
|
||||||
"zones": {
|
|
||||||
"45_degree_only": false,
|
|
||||||
"min_clearance": 1e-06
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"diff_pair_dimensions": [
|
|
||||||
{
|
|
||||||
"gap": 0.0,
|
|
||||||
"via_gap": 0.0,
|
|
||||||
"width": 0.0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"drc_exclusions": [
|
|
||||||
"clearance|6549579|23514621|0dac23a8-f43b-4e30-9a10-b757851281ba|192908ec-7c4c-4ab1-a565-bc709c96b57f",
|
|
||||||
"clearance|7950000|22690000|821d722e-241b-43f8-bcb8-12290d54f4d9|192908ec-7c4c-4ab1-a565-bc709c96b57f",
|
|
||||||
"clearance|7970521|23400521|e003e765-2ee5-400f-abaa-d669dc68a0c6|192908ec-7c4c-4ab1-a565-bc709c96b57f",
|
|
||||||
"clearance|8581179|22000000|3dde5b5d-55b0-42ee-abfb-5429896be16c|192908ec-7c4c-4ab1-a565-bc709c96b57f",
|
|
||||||
"clearance|8581179|22002512|3cab235c-f7da-46c2-8b4d-9d21002f2b49|192908ec-7c4c-4ab1-a565-bc709c96b57f",
|
|
||||||
"items_not_allowed|6130279|23400521|0dac23a8-f43b-4e30-9a10-b757851281ba|00000000-0000-0000-0000-000000000000",
|
|
||||||
"items_not_allowed|7050400|23400521|e003e765-2ee5-400f-abaa-d669dc68a0c6|00000000-0000-0000-0000-000000000000",
|
|
||||||
"items_not_allowed|7950000|23035000|821d722e-241b-43f8-bcb8-12290d54f4d9|00000000-0000-0000-0000-000000000000",
|
|
||||||
"items_not_allowed|8640000|22000000|3cab235c-f7da-46c2-8b4d-9d21002f2b49|00000000-0000-0000-0000-000000000000",
|
|
||||||
"items_not_allowed|8780000|22000000|3dde5b5d-55b0-42ee-abfb-5429896be16c|00000000-0000-0000-0000-000000000000"
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"filename": "board_design_settings.json",
|
|
||||||
"version": 2
|
|
||||||
},
|
|
||||||
"rule_severities": {
|
|
||||||
"annular_width": "error",
|
|
||||||
"clearance": "error",
|
|
||||||
"connection_width": "warning",
|
|
||||||
"copper_edge_clearance": "warning",
|
|
||||||
"copper_sliver": "warning",
|
|
||||||
"courtyards_overlap": "warning",
|
|
||||||
"diff_pair_gap_out_of_range": "error",
|
|
||||||
"diff_pair_uncoupled_length_too_long": "error",
|
|
||||||
"drill_out_of_range": "error",
|
|
||||||
"duplicate_footprints": "warning",
|
|
||||||
"extra_footprint": "warning",
|
|
||||||
"footprint": "error",
|
|
||||||
"footprint_symbol_mismatch": "warning",
|
|
||||||
"footprint_type_mismatch": "error",
|
|
||||||
"hole_clearance": "error",
|
|
||||||
"hole_near_hole": "error",
|
|
||||||
"holes_co_located": "warning",
|
|
||||||
"invalid_outline": "error",
|
|
||||||
"isolated_copper": "warning",
|
|
||||||
"item_on_disabled_layer": "error",
|
|
||||||
"items_not_allowed": "error",
|
|
||||||
"length_out_of_range": "error",
|
|
||||||
"lib_footprint_issues": "warning",
|
|
||||||
"lib_footprint_mismatch": "warning",
|
|
||||||
"malformed_courtyard": "error",
|
|
||||||
"microvia_drill_out_of_range": "error",
|
|
||||||
"missing_courtyard": "ignore",
|
|
||||||
"missing_footprint": "warning",
|
|
||||||
"net_conflict": "warning",
|
|
||||||
"npth_inside_courtyard": "ignore",
|
|
||||||
"padstack": "error",
|
|
||||||
"pth_inside_courtyard": "ignore",
|
|
||||||
"shorting_items": "error",
|
|
||||||
"silk_edge_clearance": "warning",
|
|
||||||
"silk_over_copper": "warning",
|
|
||||||
"silk_overlap": "warning",
|
|
||||||
"skew_out_of_range": "error",
|
|
||||||
"solder_mask_bridge": "warning",
|
|
||||||
"starved_thermal": "warning",
|
|
||||||
"text_height": "warning",
|
|
||||||
"text_thickness": "warning",
|
|
||||||
"through_hole_pad_without_hole": "error",
|
|
||||||
"too_many_vias": "error",
|
|
||||||
"track_dangling": "warning",
|
|
||||||
"track_width": "error",
|
|
||||||
"tracks_crossing": "error",
|
|
||||||
"unconnected_items": "error",
|
|
||||||
"unresolved_variable": "error",
|
|
||||||
"via_dangling": "warning",
|
|
||||||
"zones_intersect": "error"
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"allow_blind_buried_vias": false,
|
|
||||||
"allow_microvias": false,
|
|
||||||
"max_error": 0.005,
|
|
||||||
"min_clearance": 0.0889,
|
|
||||||
"min_connection": 0.0,
|
|
||||||
"min_copper_edge_clearance": 0.0889,
|
|
||||||
"min_hole_clearance": 0.0889,
|
|
||||||
"min_hole_to_hole": 0.25,
|
|
||||||
"min_microvia_diameter": 0.2,
|
|
||||||
"min_microvia_drill": 0.1,
|
|
||||||
"min_resolved_spokes": 2,
|
|
||||||
"min_silk_clearance": 0.0,
|
|
||||||
"min_text_height": 0.8,
|
|
||||||
"min_text_thickness": 0.08,
|
|
||||||
"min_through_hole_diameter": 0.2,
|
|
||||||
"min_track_width": 0.0889,
|
|
||||||
"min_via_annular_width": 0.125,
|
|
||||||
"min_via_diameter": 0.45,
|
|
||||||
"solder_mask_to_copper_clearance": 0.0,
|
|
||||||
"use_height_for_length_calcs": true
|
|
||||||
},
|
|
||||||
"teardrop_options": [
|
|
||||||
{
|
|
||||||
"td_onpadsmd": true,
|
|
||||||
"td_onroundshapesonly": false,
|
|
||||||
"td_ontrackend": false,
|
|
||||||
"td_onviapad": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"teardrop_parameters": [
|
|
||||||
{
|
|
||||||
"td_allow_use_two_tracks": true,
|
|
||||||
"td_curve_segcount": 0,
|
|
||||||
"td_height_ratio": 1.0,
|
|
||||||
"td_length_ratio": 0.5,
|
|
||||||
"td_maxheight": 2.0,
|
|
||||||
"td_maxlen": 1.0,
|
|
||||||
"td_on_pad_in_zone": false,
|
|
||||||
"td_target_name": "td_round_shape",
|
|
||||||
"td_width_to_size_filter_ratio": 0.9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"td_allow_use_two_tracks": true,
|
|
||||||
"td_curve_segcount": 0,
|
|
||||||
"td_height_ratio": 1.0,
|
|
||||||
"td_length_ratio": 0.5,
|
|
||||||
"td_maxheight": 2.0,
|
|
||||||
"td_maxlen": 1.0,
|
|
||||||
"td_on_pad_in_zone": false,
|
|
||||||
"td_target_name": "td_rect_shape",
|
|
||||||
"td_width_to_size_filter_ratio": 0.9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"td_allow_use_two_tracks": true,
|
|
||||||
"td_curve_segcount": 0,
|
|
||||||
"td_height_ratio": 1.0,
|
|
||||||
"td_length_ratio": 0.5,
|
|
||||||
"td_maxheight": 2.0,
|
|
||||||
"td_maxlen": 1.0,
|
|
||||||
"td_on_pad_in_zone": false,
|
|
||||||
"td_target_name": "td_track_end",
|
|
||||||
"td_width_to_size_filter_ratio": 0.9
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"track_widths": [
|
|
||||||
0.0,
|
|
||||||
0.0762,
|
|
||||||
0.0889,
|
|
||||||
0.1016,
|
|
||||||
0.127,
|
|
||||||
0.1524,
|
|
||||||
0.1778,
|
|
||||||
0.2032,
|
|
||||||
0.254,
|
|
||||||
0.3048,
|
|
||||||
0.55
|
|
||||||
],
|
|
||||||
"tuning_pattern_settings": {
|
|
||||||
"diff_pair_defaults": {
|
|
||||||
"corner_radius_percentage": 80,
|
|
||||||
"corner_style": 1,
|
|
||||||
"max_amplitude": 1.0,
|
|
||||||
"min_amplitude": 0.2,
|
|
||||||
"single_sided": false,
|
|
||||||
"spacing": 1.0
|
|
||||||
},
|
|
||||||
"diff_pair_skew_defaults": {
|
|
||||||
"corner_radius_percentage": 80,
|
|
||||||
"corner_style": 1,
|
|
||||||
"max_amplitude": 1.0,
|
|
||||||
"min_amplitude": 0.2,
|
|
||||||
"single_sided": false,
|
|
||||||
"spacing": 0.6
|
|
||||||
},
|
|
||||||
"single_track_defaults": {
|
|
||||||
"corner_radius_percentage": 80,
|
|
||||||
"corner_style": 1,
|
|
||||||
"max_amplitude": 1.0,
|
|
||||||
"min_amplitude": 0.2,
|
|
||||||
"single_sided": false,
|
|
||||||
"spacing": 0.6
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"via_dimensions": [
|
|
||||||
{
|
|
||||||
"diameter": 0.0,
|
|
||||||
"drill": 0.0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"diameter": 0.5588,
|
|
||||||
"drill": 0.3048
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"zones_allow_external_fillets": false,
|
|
||||||
"zones_use_no_outline": true
|
|
||||||
},
|
|
||||||
"ipc2581": {
|
|
||||||
"dist": "",
|
|
||||||
"distpn": "",
|
|
||||||
"internal_id": "",
|
|
||||||
"mfg": "",
|
|
||||||
"mpn": ""
|
|
||||||
},
|
|
||||||
"layer_presets": [],
|
|
||||||
"viewports": []
|
|
||||||
},
|
|
||||||
"boards": [],
|
|
||||||
"cvpcb": {
|
|
||||||
"equivalence_files": []
|
|
||||||
},
|
|
||||||
"erc": {
|
|
||||||
"erc_exclusions": [],
|
|
||||||
"meta": {
|
|
||||||
"version": 0
|
|
||||||
},
|
|
||||||
"pin_map": [
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"rule_severities": {
|
|
||||||
"bus_definition_conflict": "error",
|
|
||||||
"bus_entry_needed": "error",
|
|
||||||
"bus_to_bus_conflict": "error",
|
|
||||||
"bus_to_net_conflict": "error",
|
|
||||||
"conflicting_netclasses": "error",
|
|
||||||
"different_unit_footprint": "error",
|
|
||||||
"different_unit_net": "error",
|
|
||||||
"duplicate_reference": "error",
|
|
||||||
"duplicate_sheet_names": "error",
|
|
||||||
"endpoint_off_grid": "warning",
|
|
||||||
"extra_units": "error",
|
|
||||||
"global_label_dangling": "warning",
|
|
||||||
"hier_label_mismatch": "error",
|
|
||||||
"label_dangling": "error",
|
|
||||||
"lib_symbol_issues": "warning",
|
|
||||||
"missing_bidi_pin": "warning",
|
|
||||||
"missing_input_pin": "warning",
|
|
||||||
"missing_power_pin": "error",
|
|
||||||
"missing_unit": "warning",
|
|
||||||
"multiple_net_names": "warning",
|
|
||||||
"net_not_bus_member": "warning",
|
|
||||||
"no_connect_connected": "warning",
|
|
||||||
"no_connect_dangling": "warning",
|
|
||||||
"pin_not_connected": "error",
|
|
||||||
"pin_not_driven": "error",
|
|
||||||
"pin_to_pin": "error",
|
|
||||||
"power_pin_not_driven": "error",
|
|
||||||
"similar_labels": "warning",
|
|
||||||
"simulation_model_issue": "error",
|
|
||||||
"unannotated": "error",
|
|
||||||
"unit_value_mismatch": "error",
|
|
||||||
"unresolved_variable": "error",
|
|
||||||
"wire_dangling": "error"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"libraries": {
|
|
||||||
"pinned_footprint_libs": [],
|
|
||||||
"pinned_symbol_libs": []
|
|
||||||
},
|
|
||||||
"meta": {
|
|
||||||
"filename": "OSO-SWAT-C1-rounded.kicad_pro",
|
|
||||||
"version": 1
|
|
||||||
},
|
|
||||||
"net_settings": {
|
|
||||||
"classes": [
|
|
||||||
{
|
|
||||||
"bus_width": 12,
|
|
||||||
"clearance": 0.0889,
|
|
||||||
"diff_pair_gap": 0.0889,
|
|
||||||
"diff_pair_via_gap": 0.25,
|
|
||||||
"diff_pair_width": 0.0889,
|
|
||||||
"line_style": 0,
|
|
||||||
"microvia_diameter": 0.45,
|
|
||||||
"microvia_drill": 0.2,
|
|
||||||
"name": "Default",
|
|
||||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
|
||||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
|
||||||
"track_width": 0.0889,
|
|
||||||
"via_diameter": 0.45,
|
|
||||||
"via_drill": 0.2,
|
|
||||||
"wire_width": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"bus_width": 12,
|
|
||||||
"clearance": 0.0889,
|
|
||||||
"diff_pair_gap": 0.0889,
|
|
||||||
"diff_pair_via_gap": 0.25,
|
|
||||||
"diff_pair_width": 0.0889,
|
|
||||||
"line_style": 0,
|
|
||||||
"microvia_diameter": 0.45,
|
|
||||||
"microvia_drill": 0.2,
|
|
||||||
"name": "gnd",
|
|
||||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
|
||||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
|
||||||
"track_width": 0.2032,
|
|
||||||
"via_diameter": 0.45,
|
|
||||||
"via_drill": 0.2,
|
|
||||||
"wire_width": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"bus_width": 12,
|
|
||||||
"clearance": 0.0889,
|
|
||||||
"diff_pair_gap": 0.0889,
|
|
||||||
"diff_pair_via_gap": 0.25,
|
|
||||||
"diff_pair_width": 0.0889,
|
|
||||||
"line_style": 0,
|
|
||||||
"microvia_diameter": 0.45,
|
|
||||||
"microvia_drill": 0.2,
|
|
||||||
"name": "power",
|
|
||||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
|
||||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
|
||||||
"track_width": 0.2032,
|
|
||||||
"via_diameter": 0.45,
|
|
||||||
"via_drill": 0.2,
|
|
||||||
"wire_width": 6
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"net_colors": null,
|
|
||||||
"netclass_assignments": null,
|
|
||||||
"netclass_patterns": [
|
|
||||||
{
|
|
||||||
"netclass": "gnd",
|
|
||||||
"pattern": "GND"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"netclass": "power",
|
|
||||||
"pattern": "VCC"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"pcbnew": {
|
|
||||||
"last_paths": {
|
|
||||||
"gencad": "",
|
|
||||||
"idf": "",
|
|
||||||
"netlist": "",
|
|
||||||
"plot": "./OSO-SWAT-C1-06",
|
|
||||||
"pos_files": "",
|
|
||||||
"specctra_dsn": "",
|
|
||||||
"step": "OSO-SWAT-C1.step",
|
|
||||||
"svg": "",
|
|
||||||
"vrml": ""
|
|
||||||
},
|
|
||||||
"page_layout_descr_file": ""
|
|
||||||
},
|
|
||||||
"schematic": {
|
|
||||||
"annotate_start_num": 0,
|
|
||||||
"bom_export_filename": "OSO-SWAT-C1-05.csv",
|
|
||||||
"bom_fmt_presets": [],
|
|
||||||
"bom_fmt_settings": {
|
|
||||||
"field_delimiter": ",",
|
|
||||||
"keep_line_breaks": false,
|
|
||||||
"keep_tabs": false,
|
|
||||||
"name": "CSV",
|
|
||||||
"ref_delimiter": ",",
|
|
||||||
"ref_range_delimiter": "",
|
|
||||||
"string_delimiter": "\""
|
|
||||||
},
|
|
||||||
"bom_presets": [],
|
|
||||||
"bom_settings": {
|
|
||||||
"exclude_dnp": false,
|
|
||||||
"fields_ordered": [
|
|
||||||
{
|
|
||||||
"group_by": false,
|
|
||||||
"label": "Reference",
|
|
||||||
"name": "Reference",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": true,
|
|
||||||
"label": "Value",
|
|
||||||
"name": "Value",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": false,
|
|
||||||
"label": "Datasheet",
|
|
||||||
"name": "Datasheet",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": true,
|
|
||||||
"label": "Footprint",
|
|
||||||
"name": "Footprint",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": false,
|
|
||||||
"label": "Qty",
|
|
||||||
"name": "${QUANTITY}",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": true,
|
|
||||||
"label": "DNP",
|
|
||||||
"name": "${DNP}",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": false,
|
|
||||||
"label": "#",
|
|
||||||
"name": "${ITEM_NUMBER}",
|
|
||||||
"show": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": false,
|
|
||||||
"label": "Description",
|
|
||||||
"name": "Description",
|
|
||||||
"show": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"filter_string": "",
|
|
||||||
"group_symbols": true,
|
|
||||||
"name": "",
|
|
||||||
"sort_asc": true,
|
|
||||||
"sort_field": "Reference"
|
|
||||||
},
|
|
||||||
"connection_grid_size": 50.0,
|
|
||||||
"drawing": {
|
|
||||||
"dashed_lines_dash_length_ratio": 12.0,
|
|
||||||
"dashed_lines_gap_length_ratio": 3.0,
|
|
||||||
"default_line_thickness": 6.0,
|
|
||||||
"default_text_size": 50.0,
|
|
||||||
"field_names": [],
|
|
||||||
"intersheets_ref_own_page": false,
|
|
||||||
"intersheets_ref_prefix": "",
|
|
||||||
"intersheets_ref_short": false,
|
|
||||||
"intersheets_ref_show": false,
|
|
||||||
"intersheets_ref_suffix": "",
|
|
||||||
"junction_size_choice": 3,
|
|
||||||
"label_size_ratio": 0.375,
|
|
||||||
"operating_point_overlay_i_precision": 3,
|
|
||||||
"operating_point_overlay_i_range": "~A",
|
|
||||||
"operating_point_overlay_v_precision": 3,
|
|
||||||
"operating_point_overlay_v_range": "~V",
|
|
||||||
"overbar_offset_ratio": 1.23,
|
|
||||||
"pin_symbol_size": 25.0,
|
|
||||||
"text_offset_ratio": 0.15
|
|
||||||
},
|
|
||||||
"legacy_lib_dir": "",
|
|
||||||
"legacy_lib_list": [],
|
|
||||||
"meta": {
|
|
||||||
"version": 1
|
|
||||||
},
|
|
||||||
"net_format_name": "",
|
|
||||||
"ngspice": {
|
|
||||||
"fix_include_paths": true,
|
|
||||||
"fix_passive_vals": false,
|
|
||||||
"meta": {
|
|
||||||
"version": 0
|
|
||||||
},
|
|
||||||
"model_mode": 0,
|
|
||||||
"workbook_filename": ""
|
|
||||||
},
|
|
||||||
"page_layout_descr_file": "empty.kicad_wks",
|
|
||||||
"plot_directory": "",
|
|
||||||
"spice_adjust_passive_values": false,
|
|
||||||
"spice_current_sheet_as_root": false,
|
|
||||||
"spice_external_command": "spice \"%I\"",
|
|
||||||
"spice_model_current_sheet_as_root": true,
|
|
||||||
"spice_save_all_currents": false,
|
|
||||||
"spice_save_all_dissipations": false,
|
|
||||||
"spice_save_all_voltages": false,
|
|
||||||
"subpart_first_id": 65,
|
|
||||||
"subpart_id_separator": 0
|
|
||||||
},
|
|
||||||
"sheets": [
|
|
||||||
[
|
|
||||||
"3048f5e8-34bb-46da-8fa5-8c5aad2586f2",
|
|
||||||
"Root"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"text_variables": {}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
(version 1)
|
|
File diff suppressed because it is too large
Load Diff
@ -1,83 +0,0 @@
|
|||||||
{
|
|
||||||
"board": {
|
|
||||||
"active_layer": 0,
|
|
||||||
"active_layer_preset": "",
|
|
||||||
"auto_track_width": true,
|
|
||||||
"hidden_netclasses": [],
|
|
||||||
"hidden_nets": [],
|
|
||||||
"high_contrast_mode": 0,
|
|
||||||
"net_color_mode": 1,
|
|
||||||
"opacity": {
|
|
||||||
"images": 0.6,
|
|
||||||
"pads": 1.0,
|
|
||||||
"tracks": 1.0,
|
|
||||||
"vias": 1.0,
|
|
||||||
"zones": 0.6
|
|
||||||
},
|
|
||||||
"ratsnest_display_mode": 0,
|
|
||||||
"selection_filter": {
|
|
||||||
"dimensions": true,
|
|
||||||
"footprints": true,
|
|
||||||
"graphics": true,
|
|
||||||
"keepouts": true,
|
|
||||||
"lockedItems": true,
|
|
||||||
"otherItems": true,
|
|
||||||
"pads": true,
|
|
||||||
"text": true,
|
|
||||||
"tracks": true,
|
|
||||||
"vias": true,
|
|
||||||
"zones": true
|
|
||||||
},
|
|
||||||
"visible_items": [
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
3,
|
|
||||||
4,
|
|
||||||
5,
|
|
||||||
8,
|
|
||||||
9,
|
|
||||||
10,
|
|
||||||
11,
|
|
||||||
12,
|
|
||||||
13,
|
|
||||||
14,
|
|
||||||
15,
|
|
||||||
16,
|
|
||||||
17,
|
|
||||||
18,
|
|
||||||
19,
|
|
||||||
20,
|
|
||||||
21,
|
|
||||||
22,
|
|
||||||
23,
|
|
||||||
24,
|
|
||||||
25,
|
|
||||||
26,
|
|
||||||
27,
|
|
||||||
28,
|
|
||||||
29,
|
|
||||||
30,
|
|
||||||
32,
|
|
||||||
33,
|
|
||||||
34,
|
|
||||||
35,
|
|
||||||
36
|
|
||||||
],
|
|
||||||
"visible_layers": "0015055_80000001",
|
|
||||||
"zone_display_mode": 0
|
|
||||||
},
|
|
||||||
"git": {
|
|
||||||
"repo_password": "",
|
|
||||||
"repo_type": "",
|
|
||||||
"repo_username": "",
|
|
||||||
"ssh_key": ""
|
|
||||||
},
|
|
||||||
"meta": {
|
|
||||||
"filename": "OSO-SWAT-C1.kicad_prl",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"project": {
|
|
||||||
"files": []
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,681 +0,0 @@
|
|||||||
{
|
|
||||||
"board": {
|
|
||||||
"3dviewports": [],
|
|
||||||
"design_settings": {
|
|
||||||
"defaults": {
|
|
||||||
"apply_defaults_to_fp_fields": false,
|
|
||||||
"apply_defaults_to_fp_shapes": false,
|
|
||||||
"apply_defaults_to_fp_text": false,
|
|
||||||
"board_outline_line_width": 0.05,
|
|
||||||
"copper_line_width": 0.2,
|
|
||||||
"copper_text_italic": false,
|
|
||||||
"copper_text_size_h": 1.5,
|
|
||||||
"copper_text_size_v": 1.5,
|
|
||||||
"copper_text_thickness": 0.3,
|
|
||||||
"copper_text_upright": false,
|
|
||||||
"courtyard_line_width": 0.05,
|
|
||||||
"dimension_precision": 4,
|
|
||||||
"dimension_units": 3,
|
|
||||||
"dimensions": {
|
|
||||||
"arrow_length": 1270000,
|
|
||||||
"extension_offset": 500000,
|
|
||||||
"keep_text_aligned": true,
|
|
||||||
"suppress_zeroes": false,
|
|
||||||
"text_position": 0,
|
|
||||||
"units_format": 1
|
|
||||||
},
|
|
||||||
"fab_line_width": 0.1,
|
|
||||||
"fab_text_italic": false,
|
|
||||||
"fab_text_size_h": 1.0,
|
|
||||||
"fab_text_size_v": 1.0,
|
|
||||||
"fab_text_thickness": 0.15,
|
|
||||||
"fab_text_upright": false,
|
|
||||||
"other_line_width": 0.1,
|
|
||||||
"other_text_italic": false,
|
|
||||||
"other_text_size_h": 1.0,
|
|
||||||
"other_text_size_v": 1.0,
|
|
||||||
"other_text_thickness": 0.15,
|
|
||||||
"other_text_upright": false,
|
|
||||||
"pads": {
|
|
||||||
"drill": 0.9,
|
|
||||||
"height": 0.9,
|
|
||||||
"width": 0.9
|
|
||||||
},
|
|
||||||
"silk_line_width": 0.12,
|
|
||||||
"silk_text_italic": false,
|
|
||||||
"silk_text_size_h": 1.0,
|
|
||||||
"silk_text_size_v": 1.0,
|
|
||||||
"silk_text_thickness": 0.15,
|
|
||||||
"silk_text_upright": false,
|
|
||||||
"zones": {
|
|
||||||
"45_degree_only": false,
|
|
||||||
"min_clearance": 1e-06
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"diff_pair_dimensions": [
|
|
||||||
{
|
|
||||||
"gap": 0.0,
|
|
||||||
"via_gap": 0.0,
|
|
||||||
"width": 0.0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"drc_exclusions": [],
|
|
||||||
"meta": {
|
|
||||||
"filename": "board_design_settings.json",
|
|
||||||
"version": 2
|
|
||||||
},
|
|
||||||
"rule_severities": {
|
|
||||||
"annular_width": "error",
|
|
||||||
"clearance": "error",
|
|
||||||
"connection_width": "warning",
|
|
||||||
"copper_edge_clearance": "warning",
|
|
||||||
"copper_sliver": "warning",
|
|
||||||
"courtyards_overlap": "warning",
|
|
||||||
"diff_pair_gap_out_of_range": "error",
|
|
||||||
"diff_pair_uncoupled_length_too_long": "error",
|
|
||||||
"drill_out_of_range": "error",
|
|
||||||
"duplicate_footprints": "warning",
|
|
||||||
"extra_footprint": "warning",
|
|
||||||
"footprint": "error",
|
|
||||||
"footprint_symbol_mismatch": "warning",
|
|
||||||
"footprint_type_mismatch": "error",
|
|
||||||
"hole_clearance": "error",
|
|
||||||
"hole_near_hole": "error",
|
|
||||||
"holes_co_located": "warning",
|
|
||||||
"invalid_outline": "error",
|
|
||||||
"isolated_copper": "warning",
|
|
||||||
"item_on_disabled_layer": "error",
|
|
||||||
"items_not_allowed": "error",
|
|
||||||
"length_out_of_range": "error",
|
|
||||||
"lib_footprint_issues": "warning",
|
|
||||||
"lib_footprint_mismatch": "warning",
|
|
||||||
"malformed_courtyard": "error",
|
|
||||||
"microvia_drill_out_of_range": "error",
|
|
||||||
"missing_courtyard": "ignore",
|
|
||||||
"missing_footprint": "warning",
|
|
||||||
"net_conflict": "warning",
|
|
||||||
"npth_inside_courtyard": "ignore",
|
|
||||||
"padstack": "error",
|
|
||||||
"pth_inside_courtyard": "ignore",
|
|
||||||
"shorting_items": "error",
|
|
||||||
"silk_edge_clearance": "warning",
|
|
||||||
"silk_over_copper": "warning",
|
|
||||||
"silk_overlap": "warning",
|
|
||||||
"skew_out_of_range": "error",
|
|
||||||
"solder_mask_bridge": "warning",
|
|
||||||
"starved_thermal": "warning",
|
|
||||||
"text_height": "warning",
|
|
||||||
"text_thickness": "warning",
|
|
||||||
"through_hole_pad_without_hole": "error",
|
|
||||||
"too_many_vias": "error",
|
|
||||||
"track_dangling": "warning",
|
|
||||||
"track_width": "error",
|
|
||||||
"tracks_crossing": "error",
|
|
||||||
"unconnected_items": "error",
|
|
||||||
"unresolved_variable": "error",
|
|
||||||
"via_dangling": "warning",
|
|
||||||
"zones_intersect": "error"
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"allow_blind_buried_vias": false,
|
|
||||||
"allow_microvias": false,
|
|
||||||
"max_error": 0.005,
|
|
||||||
"min_clearance": 0.0889,
|
|
||||||
"min_connection": 0.0,
|
|
||||||
"min_copper_edge_clearance": 0.0889,
|
|
||||||
"min_hole_clearance": 0.0889,
|
|
||||||
"min_hole_to_hole": 0.25,
|
|
||||||
"min_microvia_diameter": 0.2,
|
|
||||||
"min_microvia_drill": 0.1,
|
|
||||||
"min_resolved_spokes": 2,
|
|
||||||
"min_silk_clearance": 0.0,
|
|
||||||
"min_text_height": 0.8,
|
|
||||||
"min_text_thickness": 0.08,
|
|
||||||
"min_through_hole_diameter": 0.2,
|
|
||||||
"min_track_width": 0.0889,
|
|
||||||
"min_via_annular_width": 0.125,
|
|
||||||
"min_via_diameter": 0.45,
|
|
||||||
"solder_mask_to_copper_clearance": 0.0,
|
|
||||||
"use_height_for_length_calcs": true
|
|
||||||
},
|
|
||||||
"teardrop_options": [
|
|
||||||
{
|
|
||||||
"td_onpadsmd": true,
|
|
||||||
"td_onroundshapesonly": false,
|
|
||||||
"td_ontrackend": false,
|
|
||||||
"td_onviapad": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"teardrop_parameters": [
|
|
||||||
{
|
|
||||||
"td_allow_use_two_tracks": true,
|
|
||||||
"td_curve_segcount": 0,
|
|
||||||
"td_height_ratio": 1.0,
|
|
||||||
"td_length_ratio": 0.5,
|
|
||||||
"td_maxheight": 2.0,
|
|
||||||
"td_maxlen": 1.0,
|
|
||||||
"td_on_pad_in_zone": false,
|
|
||||||
"td_target_name": "td_round_shape",
|
|
||||||
"td_width_to_size_filter_ratio": 0.9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"td_allow_use_two_tracks": true,
|
|
||||||
"td_curve_segcount": 0,
|
|
||||||
"td_height_ratio": 1.0,
|
|
||||||
"td_length_ratio": 0.5,
|
|
||||||
"td_maxheight": 2.0,
|
|
||||||
"td_maxlen": 1.0,
|
|
||||||
"td_on_pad_in_zone": false,
|
|
||||||
"td_target_name": "td_rect_shape",
|
|
||||||
"td_width_to_size_filter_ratio": 0.9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"td_allow_use_two_tracks": true,
|
|
||||||
"td_curve_segcount": 0,
|
|
||||||
"td_height_ratio": 1.0,
|
|
||||||
"td_length_ratio": 0.5,
|
|
||||||
"td_maxheight": 2.0,
|
|
||||||
"td_maxlen": 1.0,
|
|
||||||
"td_on_pad_in_zone": false,
|
|
||||||
"td_target_name": "td_track_end",
|
|
||||||
"td_width_to_size_filter_ratio": 0.9
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"track_widths": [
|
|
||||||
0.0,
|
|
||||||
0.0762,
|
|
||||||
0.0889,
|
|
||||||
0.1016,
|
|
||||||
0.127,
|
|
||||||
0.1524,
|
|
||||||
0.1778,
|
|
||||||
0.2032,
|
|
||||||
0.254,
|
|
||||||
0.3048,
|
|
||||||
0.55
|
|
||||||
],
|
|
||||||
"tuning_pattern_settings": {
|
|
||||||
"diff_pair_defaults": {
|
|
||||||
"corner_radius_percentage": 80,
|
|
||||||
"corner_style": 1,
|
|
||||||
"max_amplitude": 1.0,
|
|
||||||
"min_amplitude": 0.2,
|
|
||||||
"single_sided": false,
|
|
||||||
"spacing": 1.0
|
|
||||||
},
|
|
||||||
"diff_pair_skew_defaults": {
|
|
||||||
"corner_radius_percentage": 80,
|
|
||||||
"corner_style": 1,
|
|
||||||
"max_amplitude": 1.0,
|
|
||||||
"min_amplitude": 0.2,
|
|
||||||
"single_sided": false,
|
|
||||||
"spacing": 0.6
|
|
||||||
},
|
|
||||||
"single_track_defaults": {
|
|
||||||
"corner_radius_percentage": 80,
|
|
||||||
"corner_style": 1,
|
|
||||||
"max_amplitude": 1.0,
|
|
||||||
"min_amplitude": 0.2,
|
|
||||||
"single_sided": false,
|
|
||||||
"spacing": 0.6
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"via_dimensions": [
|
|
||||||
{
|
|
||||||
"diameter": 0.0,
|
|
||||||
"drill": 0.0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"diameter": 0.5588,
|
|
||||||
"drill": 0.3048
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"zones_allow_external_fillets": false,
|
|
||||||
"zones_use_no_outline": true
|
|
||||||
},
|
|
||||||
"ipc2581": {
|
|
||||||
"dist": "",
|
|
||||||
"distpn": "",
|
|
||||||
"internal_id": "",
|
|
||||||
"mfg": "",
|
|
||||||
"mpn": ""
|
|
||||||
},
|
|
||||||
"layer_presets": [],
|
|
||||||
"viewports": []
|
|
||||||
},
|
|
||||||
"boards": [],
|
|
||||||
"cvpcb": {
|
|
||||||
"equivalence_files": []
|
|
||||||
},
|
|
||||||
"erc": {
|
|
||||||
"erc_exclusions": [],
|
|
||||||
"meta": {
|
|
||||||
"version": 0
|
|
||||||
},
|
|
||||||
"pin_map": [
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
[
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2,
|
|
||||||
2
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"rule_severities": {
|
|
||||||
"bus_definition_conflict": "error",
|
|
||||||
"bus_entry_needed": "error",
|
|
||||||
"bus_to_bus_conflict": "error",
|
|
||||||
"bus_to_net_conflict": "error",
|
|
||||||
"conflicting_netclasses": "error",
|
|
||||||
"different_unit_footprint": "error",
|
|
||||||
"different_unit_net": "error",
|
|
||||||
"duplicate_reference": "error",
|
|
||||||
"duplicate_sheet_names": "error",
|
|
||||||
"endpoint_off_grid": "warning",
|
|
||||||
"extra_units": "error",
|
|
||||||
"global_label_dangling": "warning",
|
|
||||||
"hier_label_mismatch": "error",
|
|
||||||
"label_dangling": "error",
|
|
||||||
"lib_symbol_issues": "warning",
|
|
||||||
"missing_bidi_pin": "warning",
|
|
||||||
"missing_input_pin": "warning",
|
|
||||||
"missing_power_pin": "error",
|
|
||||||
"missing_unit": "warning",
|
|
||||||
"multiple_net_names": "warning",
|
|
||||||
"net_not_bus_member": "warning",
|
|
||||||
"no_connect_connected": "warning",
|
|
||||||
"no_connect_dangling": "warning",
|
|
||||||
"pin_not_connected": "error",
|
|
||||||
"pin_not_driven": "error",
|
|
||||||
"pin_to_pin": "error",
|
|
||||||
"power_pin_not_driven": "error",
|
|
||||||
"similar_labels": "warning",
|
|
||||||
"simulation_model_issue": "error",
|
|
||||||
"unannotated": "error",
|
|
||||||
"unit_value_mismatch": "error",
|
|
||||||
"unresolved_variable": "error",
|
|
||||||
"wire_dangling": "error"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"libraries": {
|
|
||||||
"pinned_footprint_libs": [],
|
|
||||||
"pinned_symbol_libs": []
|
|
||||||
},
|
|
||||||
"meta": {
|
|
||||||
"filename": "OSO-SWAT-C1.kicad_pro",
|
|
||||||
"version": 1
|
|
||||||
},
|
|
||||||
"net_settings": {
|
|
||||||
"classes": [
|
|
||||||
{
|
|
||||||
"bus_width": 12,
|
|
||||||
"clearance": 0.0889,
|
|
||||||
"diff_pair_gap": 0.0889,
|
|
||||||
"diff_pair_via_gap": 0.25,
|
|
||||||
"diff_pair_width": 0.0889,
|
|
||||||
"line_style": 0,
|
|
||||||
"microvia_diameter": 0.45,
|
|
||||||
"microvia_drill": 0.2,
|
|
||||||
"name": "Default",
|
|
||||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
|
||||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
|
||||||
"track_width": 0.0889,
|
|
||||||
"via_diameter": 0.45,
|
|
||||||
"via_drill": 0.2,
|
|
||||||
"wire_width": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"bus_width": 12,
|
|
||||||
"clearance": 0.0889,
|
|
||||||
"diff_pair_gap": 0.0889,
|
|
||||||
"diff_pair_via_gap": 0.25,
|
|
||||||
"diff_pair_width": 0.0889,
|
|
||||||
"line_style": 0,
|
|
||||||
"microvia_diameter": 0.45,
|
|
||||||
"microvia_drill": 0.2,
|
|
||||||
"name": "gnd",
|
|
||||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
|
||||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
|
||||||
"track_width": 0.2032,
|
|
||||||
"via_diameter": 0.45,
|
|
||||||
"via_drill": 0.2,
|
|
||||||
"wire_width": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"bus_width": 12,
|
|
||||||
"clearance": 0.0889,
|
|
||||||
"diff_pair_gap": 0.0889,
|
|
||||||
"diff_pair_via_gap": 0.25,
|
|
||||||
"diff_pair_width": 0.0889,
|
|
||||||
"line_style": 0,
|
|
||||||
"microvia_diameter": 0.45,
|
|
||||||
"microvia_drill": 0.2,
|
|
||||||
"name": "power",
|
|
||||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
|
||||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
|
||||||
"track_width": 0.2032,
|
|
||||||
"via_diameter": 0.45,
|
|
||||||
"via_drill": 0.2,
|
|
||||||
"wire_width": 6
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"net_colors": null,
|
|
||||||
"netclass_assignments": null,
|
|
||||||
"netclass_patterns": [
|
|
||||||
{
|
|
||||||
"netclass": "gnd",
|
|
||||||
"pattern": "GND"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"netclass": "power",
|
|
||||||
"pattern": "VCC"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"pcbnew": {
|
|
||||||
"last_paths": {
|
|
||||||
"gencad": "",
|
|
||||||
"idf": "",
|
|
||||||
"netlist": "",
|
|
||||||
"plot": "./OSO-SWAT-C1-06",
|
|
||||||
"pos_files": "./temp/",
|
|
||||||
"specctra_dsn": "",
|
|
||||||
"step": "OSO-SWAT-C1.step",
|
|
||||||
"svg": "",
|
|
||||||
"vrml": ""
|
|
||||||
},
|
|
||||||
"page_layout_descr_file": ""
|
|
||||||
},
|
|
||||||
"schematic": {
|
|
||||||
"annotate_start_num": 0,
|
|
||||||
"bom_export_filename": "OSO-SWAT-C1-05-bottom.csv",
|
|
||||||
"bom_fmt_presets": [],
|
|
||||||
"bom_fmt_settings": {
|
|
||||||
"field_delimiter": ",",
|
|
||||||
"keep_line_breaks": false,
|
|
||||||
"keep_tabs": false,
|
|
||||||
"name": "CSV",
|
|
||||||
"ref_delimiter": ",",
|
|
||||||
"ref_range_delimiter": "",
|
|
||||||
"string_delimiter": "\""
|
|
||||||
},
|
|
||||||
"bom_presets": [],
|
|
||||||
"bom_settings": {
|
|
||||||
"exclude_dnp": false,
|
|
||||||
"fields_ordered": [
|
|
||||||
{
|
|
||||||
"group_by": false,
|
|
||||||
"label": "Reference",
|
|
||||||
"name": "Reference",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": true,
|
|
||||||
"label": "Value",
|
|
||||||
"name": "Value",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": false,
|
|
||||||
"label": "Datasheet",
|
|
||||||
"name": "Datasheet",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": true,
|
|
||||||
"label": "Footprint",
|
|
||||||
"name": "Footprint",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": false,
|
|
||||||
"label": "Qty",
|
|
||||||
"name": "${QUANTITY}",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": true,
|
|
||||||
"label": "DNP",
|
|
||||||
"name": "${DNP}",
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": false,
|
|
||||||
"label": "#",
|
|
||||||
"name": "${ITEM_NUMBER}",
|
|
||||||
"show": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group_by": false,
|
|
||||||
"label": "Description",
|
|
||||||
"name": "Description",
|
|
||||||
"show": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"filter_string": "",
|
|
||||||
"group_symbols": true,
|
|
||||||
"name": "",
|
|
||||||
"sort_asc": true,
|
|
||||||
"sort_field": "Reference"
|
|
||||||
},
|
|
||||||
"connection_grid_size": 50.0,
|
|
||||||
"drawing": {
|
|
||||||
"dashed_lines_dash_length_ratio": 12.0,
|
|
||||||
"dashed_lines_gap_length_ratio": 3.0,
|
|
||||||
"default_line_thickness": 6.0,
|
|
||||||
"default_text_size": 50.0,
|
|
||||||
"field_names": [],
|
|
||||||
"intersheets_ref_own_page": false,
|
|
||||||
"intersheets_ref_prefix": "",
|
|
||||||
"intersheets_ref_short": false,
|
|
||||||
"intersheets_ref_show": false,
|
|
||||||
"intersheets_ref_suffix": "",
|
|
||||||
"junction_size_choice": 3,
|
|
||||||
"label_size_ratio": 0.375,
|
|
||||||
"operating_point_overlay_i_precision": 3,
|
|
||||||
"operating_point_overlay_i_range": "~A",
|
|
||||||
"operating_point_overlay_v_precision": 3,
|
|
||||||
"operating_point_overlay_v_range": "~V",
|
|
||||||
"overbar_offset_ratio": 1.23,
|
|
||||||
"pin_symbol_size": 25.0,
|
|
||||||
"text_offset_ratio": 0.15
|
|
||||||
},
|
|
||||||
"legacy_lib_dir": "",
|
|
||||||
"legacy_lib_list": [],
|
|
||||||
"meta": {
|
|
||||||
"version": 1
|
|
||||||
},
|
|
||||||
"net_format_name": "",
|
|
||||||
"ngspice": {
|
|
||||||
"fix_include_paths": true,
|
|
||||||
"fix_passive_vals": false,
|
|
||||||
"meta": {
|
|
||||||
"version": 0
|
|
||||||
},
|
|
||||||
"model_mode": 0,
|
|
||||||
"workbook_filename": ""
|
|
||||||
},
|
|
||||||
"page_layout_descr_file": "empty.kicad_wks",
|
|
||||||
"plot_directory": "",
|
|
||||||
"spice_adjust_passive_values": false,
|
|
||||||
"spice_current_sheet_as_root": false,
|
|
||||||
"spice_external_command": "spice \"%I\"",
|
|
||||||
"spice_model_current_sheet_as_root": true,
|
|
||||||
"spice_save_all_currents": false,
|
|
||||||
"spice_save_all_dissipations": false,
|
|
||||||
"spice_save_all_voltages": false,
|
|
||||||
"subpart_first_id": 65,
|
|
||||||
"subpart_id_separator": 0
|
|
||||||
},
|
|
||||||
"sheets": [
|
|
||||||
[
|
|
||||||
"3048f5e8-34bb-46da-8fa5-8c5aad2586f2",
|
|
||||||
"Root"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"text_variables": {}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,154 +0,0 @@
|
|||||||
(footprint "ELT3KN"
|
|
||||||
(version 20240108)
|
|
||||||
(generator "pcbnew")
|
|
||||||
(generator_version "8.0")
|
|
||||||
(layer "F.Cu")
|
|
||||||
(property "Reference" "REF**"
|
|
||||||
(at 0 -2.5 0)
|
|
||||||
(unlocked yes)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "a169e63e-29cc-4564-a621-b8211c147892")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1 1)
|
|
||||||
(thickness 0.2)
|
|
||||||
(bold yes)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Value" "ELT3KN"
|
|
||||||
(at 0 2.5 0)
|
|
||||||
(unlocked yes)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "12f117ff-fc54-4392-9702-20053568a437")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1 1)
|
|
||||||
(thickness 0.15)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Footprint" ""
|
|
||||||
(at 0 0 0)
|
|
||||||
(unlocked yes)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(hide yes)
|
|
||||||
(uuid "4696eff2-7885-4247-8d7f-ea328aeb61b3")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1 1)
|
|
||||||
(thickness 0.15)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Datasheet" ""
|
|
||||||
(at 0 0 0)
|
|
||||||
(unlocked yes)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(hide yes)
|
|
||||||
(uuid "38e32ed5-5bed-49cc-a302-cc80b63f7eca")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1 1)
|
|
||||||
(thickness 0.15)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Description" ""
|
|
||||||
(at 0 0 0)
|
|
||||||
(unlocked yes)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(hide yes)
|
|
||||||
(uuid "bbe09b54-7873-4c59-90a5-708f27e5af76")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1 1)
|
|
||||||
(thickness 0.15)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(attr smd)
|
|
||||||
(fp_arc
|
|
||||||
(start -1.495202 -0.697761)
|
|
||||||
(mid -0.886339 -1.391726)
|
|
||||||
(end 0 -1.65)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "2b5cd3f8-b18c-4557-94e3-1779ca1608f1")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 0 -1.65)
|
|
||||||
(mid 0.886339 -1.391727)
|
|
||||||
(end 1.495202 -0.697761)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "d473595f-e35a-4857-8449-1d9f3feacdc9")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 0 1.65)
|
|
||||||
(mid -0.886339 1.391727)
|
|
||||||
(end -1.495202 0.697761)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "d37347f0-9221-4e4b-a029-a04f185819ec")
|
|
||||||
)
|
|
||||||
(fp_arc
|
|
||||||
(start 1.495202 0.697761)
|
|
||||||
(mid 0.886339 1.391726)
|
|
||||||
(end 0 1.65)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "f12bf60f-5b3d-45b5-82f7-79448488ae21")
|
|
||||||
)
|
|
||||||
(fp_circle
|
|
||||||
(center 0 0)
|
|
||||||
(end 1.65 0)
|
|
||||||
(stroke
|
|
||||||
(width 0.1)
|
|
||||||
(type default)
|
|
||||||
)
|
|
||||||
(fill none)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "3ab1094b-f4c1-4436-87a3-fa43bddd0a8d")
|
|
||||||
)
|
|
||||||
(fp_text user "${REFERENCE}"
|
|
||||||
(at 0 0 0)
|
|
||||||
(unlocked yes)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "0739cf1b-8f40-4d32-91d0-496ba0ec98b8")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1 1)
|
|
||||||
(thickness 0.15)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(pad "1" smd roundrect
|
|
||||||
(at -2.15 0)
|
|
||||||
(size 1.4 1.05)
|
|
||||||
(layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "e742aada-aafd-47f3-8447-3fbf9c4a7579")
|
|
||||||
)
|
|
||||||
(pad "2" smd roundrect
|
|
||||||
(at 2.15 0)
|
|
||||||
(size 1.4 1.05)
|
|
||||||
(layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(roundrect_rratio 0.25)
|
|
||||||
(thermal_bridge_angle 45)
|
|
||||||
(uuid "fa457dd1-8427-41f4-83ec-ab02d543d005")
|
|
||||||
)
|
|
||||||
)
|
|
@ -1,47 +0,0 @@
|
|||||||
(footprint "FH19C9S05SH10" (version 20211014) (generator pcbnew)
|
|
||||||
(layer "F.Cu")
|
|
||||||
(tedit 0)
|
|
||||||
(descr "<b>FH19C-9S-0.5SH(10)-1</b><br>\n")
|
|
||||||
(fp_text reference "REF**" (at 0 -1.425) (layer "F.SilkS")
|
|
||||||
(effects (font (size 1.1684 1.1684) (thickness 0.1016)))
|
|
||||||
(tstamp f001c7f4-3bac-4901-bfec-55e6729b7a2d)
|
|
||||||
)
|
|
||||||
(fp_text value ">VALUE" (at 0 -1.425) (layer "F.Fab")
|
|
||||||
(effects (font (size 1.1684 1.1684) (thickness 0.1016)))
|
|
||||||
(tstamp 561aeca9-49f1-4f98-93e2-6788ec46bd30)
|
|
||||||
)
|
|
||||||
(fp_line (start -2.75 -2.25) (end -3.25 -2.25) (layer "F.SilkS") (width 0.1) (tstamp 1eac27e8-d706-4fd3-9d7e-f44c3bceecb7))
|
|
||||||
(fp_line (start -3.25 0.75) (end 3.25 0.75) (layer "F.SilkS") (width 0.1) (tstamp 2954b329-e121-4506-a75a-9fd0ad6fb160))
|
|
||||||
(fp_line (start -3.25 -2.25) (end -3.25 -0.75) (layer "F.SilkS") (width 0.1) (tstamp 707c871c-221c-430b-8a6b-9066bbe6a8b7))
|
|
||||||
(fp_line (start 3.25 -2.25) (end 3.25 -0.75) (layer "F.SilkS") (width 0.1) (tstamp c93c51a4-9fbb-472e-8b27-c730f1646c88))
|
|
||||||
(fp_line (start 2.75 -2.25) (end 3.25 -2.25) (layer "F.SilkS") (width 0.1) (tstamp f62c7b3a-070f-4127-95d5-3042f710b35c))
|
|
||||||
(fp_arc (start -2.457 -2.572) (mid -2.407 -2.622) (end -2.357 -2.572) (layer "F.SilkS") (width 0.2) (tstamp 99032ce3-83f4-4d78-bc12-cfc846be0db6))
|
|
||||||
(fp_arc (start -2.357 -2.572) (mid -2.407 -2.522) (end -2.457 -2.572) (layer "F.SilkS") (width 0.2) (tstamp cc85bc5e-d12e-4c30-b330-62e6d8cd831e))
|
|
||||||
(fp_arc (start -2.457 -2.572) (mid -2.407 -2.622) (end -2.357 -2.572) (layer "F.SilkS") (width 0.2) (tstamp e306135f-93e3-4c31-83e0-8c60a6608eec))
|
|
||||||
(fp_line (start 3.25 0.75) (end -3.25 0.75) (layer "F.Fab") (width 0.2) (tstamp 4524f199-9890-4fbd-90ec-2bd6babdbf89))
|
|
||||||
(fp_line (start 3.25 -2.25) (end 3.25 0.75) (layer "F.Fab") (width 0.2) (tstamp 855f1cc0-31ef-4190-b476-18e3b5158686))
|
|
||||||
(fp_line (start -3.25 0.75) (end -3.25 -2.25) (layer "F.Fab") (width 0.2) (tstamp a7aeadd1-064c-4dec-839a-d3cb8b0a8559))
|
|
||||||
(fp_line (start -3.25 -2.25) (end 3.25 -2.25) (layer "F.Fab") (width 0.2) (tstamp b29496a7-f051-4b0c-a792-56f5b1d5ae06))
|
|
||||||
(pad "1" smd rect (at -2 -2.5 90) (size 0.8 0.3) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp acda55bd-5be5-40b1-a960-d198db4ec672))
|
|
||||||
(pad "2" smd rect (at -1.5 -2.5 90) (size 0.8 0.3) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 45b21120-703c-4698-9c56-6564d6e1bf81))
|
|
||||||
(pad "3" smd rect (at -1 -2.5 90) (size 0.8 0.3) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 8b754c17-ed29-4271-a8ee-1331ac5995ef))
|
|
||||||
(pad "4" smd rect (at -0.5 -2.5 90) (size 0.8 0.3) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 9ccadf67-4eb3-4873-b5dd-5cc11b45344d))
|
|
||||||
(pad "5" smd rect (at 0 -2.5 90) (size 0.8 0.3) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp bda542d0-ecb7-417f-8c5a-7bba95d4eba5))
|
|
||||||
(pad "6" smd rect (at 0.5 -2.5 90) (size 0.8 0.3) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 8e3054c6-288a-41ce-abc0-f8e853b26354))
|
|
||||||
(pad "7" smd rect (at 1 -2.5 90) (size 0.8 0.3) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 1f1c1390-fe89-4a71-a866-c4e1f01372f9))
|
|
||||||
(pad "8" smd rect (at 1.5 -2.5 90) (size 0.8 0.3) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 83315760-4e59-4aea-8656-92a90fbb73b7))
|
|
||||||
(pad "9" smd rect (at 2 -2.5 90) (size 0.8 0.3) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp f1470e81-8bfa-4c7b-9a4f-907119981553))
|
|
||||||
(pad "MP1" smd rect (at -3 0 90) (size 0.8 0.4) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 5d56d96c-0e59-4d80-b122-61ae0456f87e))
|
|
||||||
(pad "MP2" smd rect (at 3 0 90) (size 0.8 0.4) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 65badac9-bbc1-4323-b96e-20b366a5c013))
|
|
||||||
)
|
|
@ -1,22 +0,0 @@
|
|||||||
(footprint "FIDUCIAL_1MM" (version 20211014) (generator pcbnew)
|
|
||||||
(layer "F.Cu")
|
|
||||||
(tedit 0)
|
|
||||||
(fp_text reference "REF**" (at 0 0) (layer "F.SilkS")
|
|
||||||
(effects (font (size 1.27 1.27) (thickness 0.15)))
|
|
||||||
(tstamp 084b231a-a841-4989-ba78-c80f52a1d530)
|
|
||||||
)
|
|
||||||
(fp_text value "" (at 0 0) (layer "F.Fab")
|
|
||||||
(effects (font (size 1.27 1.27) (thickness 0.15)))
|
|
||||||
(tstamp 5023af4a-f69e-458d-abff-77e97f0c49aa)
|
|
||||||
)
|
|
||||||
(fp_arc (start -0.75 0) (mid -0.53033 -0.53033) (end 0 -0.75) (layer "F.Mask") (width 0.5) (tstamp 243424d9-367c-4c55-9ce2-5c7f6b71c486))
|
|
||||||
(fp_arc (start 0 0.75) (mid -0.53033 0.53033) (end -0.75 0) (layer "F.Mask") (width 0.5) (tstamp 38a261de-e7ad-4359-9a4e-e8325d947b3c))
|
|
||||||
(fp_arc (start 0.75 0) (mid 0.53033 0.53033) (end 0 0.75) (layer "F.Mask") (width 0.5) (tstamp 3e5e4d91-af7b-467f-93be-7757d59f4acd))
|
|
||||||
(fp_arc (start 0 -0.75) (mid 0.53033 -0.53033) (end 0.75 0) (layer "F.Mask") (width 0.5) (tstamp cba0161e-94ca-4df5-83f4-b38d910a40d8))
|
|
||||||
(fp_arc (start 0 -0.75) (mid 0.53033 -0.53033) (end 0.75 0) (layer "F.CrtYd") (width 0.5) (tstamp 24375f2d-9f3c-47f3-bf1b-d9abc9459487))
|
|
||||||
(fp_arc (start 0.75 0) (mid 0.53033 0.53033) (end 0 0.75) (layer "F.CrtYd") (width 0.5) (tstamp 61d35d35-c7e3-45c7-a1f6-4c560b28917a))
|
|
||||||
(fp_arc (start 0 0.75) (mid -0.53033 0.53033) (end -0.75 0) (layer "F.CrtYd") (width 0.5) (tstamp b245f192-3aeb-4a3c-8f5f-5b2ac372cfb6))
|
|
||||||
(fp_arc (start -0.75 0) (mid -0.53033 -0.53033) (end 0 -0.75) (layer "F.CrtYd") (width 0.5) (tstamp f012c0d9-2bab-4b5b-8327-ed4e32f900bb))
|
|
||||||
(pad "1" smd roundrect (at 0 0) (size 1 1) (layers "F.Cu" "F.Mask") (roundrect_rratio 0.5)
|
|
||||||
(solder_mask_margin 0.0635) (tstamp ea46b6d0-c0be-44d4-aa82-47c56ffdb259))
|
|
||||||
)
|
|
@ -1,26 +0,0 @@
|
|||||||
(footprint "LED_QBLP655" (version 20211014) (generator pcbnew)
|
|
||||||
(layer "F.Cu")
|
|
||||||
(tedit 0)
|
|
||||||
(fp_text reference "REF**" (at 0.011609 -1.462631) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.682286 0.682286) (thickness 0.14977)))
|
|
||||||
(tstamp 441c2b28-158a-4d68-a991-31f4c6a03554)
|
|
||||||
)
|
|
||||||
(fp_text value ">VALUE" (at -0.054931 1.580818) (layer "F.Fab")
|
|
||||||
(effects (font (size 0.677435 0.677435) (thickness 0.148705)))
|
|
||||||
(tstamp 2f361345-03db-4c21-a99d-0b9cfab62aee)
|
|
||||||
)
|
|
||||||
(fp_circle (center -3.1 -0.5) (end -3 -0.5) (layer "F.SilkS") (width 0.2) (fill none) (tstamp 0ba68dd4-e618-4da0-b7e7-599817b38c08))
|
|
||||||
(fp_line (start -1.6 -0.6) (end 1.6 -0.6) (layer "F.Fab") (width 0.127) (tstamp 3629e8ab-0a05-463c-9cb0-81d2e314e044))
|
|
||||||
(fp_line (start -1.6 0.6) (end -1.6 -0.6) (layer "F.Fab") (width 0.127) (tstamp 379a3f23-154c-4da8-9d91-714d85fa6b82))
|
|
||||||
(fp_line (start 1.6 -0.6) (end 1.6 0.6) (layer "F.Fab") (width 0.127) (tstamp 78db06e4-b90e-45d6-90ee-f31a25c04c7d))
|
|
||||||
(fp_line (start 1.6 0.6) (end -1.6 0.6) (layer "F.Fab") (width 0.127) (tstamp de669889-6aee-41d8-9167-24b5b7cd2f7a))
|
|
||||||
(fp_circle (center -3.1 -0.5) (end -3 -0.5) (layer "F.Fab") (width 0.2) (fill none) (tstamp a3f31f15-16ea-4248-8fe2-4f1f6cb6fef0))
|
|
||||||
(pad "1" smd rect (at -1.5 -0.4) (size 1.5 0.5) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp c0b010da-7837-47db-be16-93e46d77ee03))
|
|
||||||
(pad "2" smd rect (at 1.5 -0.4) (size 1.5 0.5) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 0491e5ac-92c6-4da4-a40f-13768f4f5f7c))
|
|
||||||
(pad "3" smd rect (at -1.5 0.4) (size 1.5 0.5) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp d96a3b29-ffbb-4252-a695-34388cf2cce8))
|
|
||||||
(pad "4" smd rect (at 1.5 0.4) (size 1.5 0.5) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp a7b3dfda-cc06-4a25-8ceb-15247a6b386b))
|
|
||||||
)
|
|
@ -1,24 +0,0 @@
|
|||||||
(footprint "LED_QBLP655_RGB" (version 20211014) (generator pcbnew)
|
|
||||||
(layer "F.Cu")
|
|
||||||
(tedit 0)
|
|
||||||
(fp_text reference "REF**" (at 0.011609 -1.462631) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.682286 0.682286) (thickness 0.14977)))
|
|
||||||
(tstamp 441c2b28-158a-4d68-a991-31f4c6a03554)
|
|
||||||
)
|
|
||||||
(fp_text value ">VALUE" (at -0.054931 1.580818) (layer "F.Fab")
|
|
||||||
(effects (font (size 0.677435 0.677435) (thickness 0.148705)))
|
|
||||||
(tstamp 2f361345-03db-4c21-a99d-0b9cfab62aee)
|
|
||||||
)
|
|
||||||
(fp_line (start -1.6 -0.6) (end 1.6 -0.6) (layer "F.Fab") (width 0.127) (tstamp 3629e8ab-0a05-463c-9cb0-81d2e314e044))
|
|
||||||
(fp_line (start -1.6 0.6) (end -1.6 -0.6) (layer "F.Fab") (width 0.127) (tstamp 379a3f23-154c-4da8-9d91-714d85fa6b82))
|
|
||||||
(fp_line (start 1.6 -0.6) (end 1.6 0.6) (layer "F.Fab") (width 0.127) (tstamp 78db06e4-b90e-45d6-90ee-f31a25c04c7d))
|
|
||||||
(fp_line (start 1.6 0.6) (end -1.6 0.6) (layer "F.Fab") (width 0.127) (tstamp de669889-6aee-41d8-9167-24b5b7cd2f7a))
|
|
||||||
(pad "1" smd rect (at 1.5 -0.4) (size 1.5 0.5) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 0491e5ac-92c6-4da4-a40f-13768f4f5f7c))
|
|
||||||
(pad "2" smd rect (at -1.5 -0.4) (size 1.5 0.5) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp c0b010da-7837-47db-be16-93e46d77ee03))
|
|
||||||
(pad "3" smd rect (at -1.5 0.4) (size 1.5 0.5) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp d96a3b29-ffbb-4252-a695-34388cf2cce8))
|
|
||||||
(pad "4" smd rect (at 1.5 0.4) (size 1.5 0.5) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp a7b3dfda-cc06-4a25-8ceb-15247a6b386b))
|
|
||||||
)
|
|
@ -1,15 +0,0 @@
|
|||||||
(footprint "MICROBUILDER_TESTPOINT_ROUND_1.5MM" (version 20211014) (generator pcbnew)
|
|
||||||
(layer "F.Cu")
|
|
||||||
(tedit 0)
|
|
||||||
(fp_text reference "REF**" (at 1.143 0.127) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.666496 0.666496) (thickness 0.146304)) (justify left bottom))
|
|
||||||
(tstamp 3249263f-d424-465a-883e-c9fbfca1c498)
|
|
||||||
)
|
|
||||||
(fp_text value ">VALUE" (at 1.143 0.635) (layer "F.Fab")
|
|
||||||
(effects (font (size 0.36576 0.36576) (thickness 0.04064)) (justify left bottom))
|
|
||||||
(tstamp ffe18277-47dd-48a9-ae75-8daae098595b)
|
|
||||||
)
|
|
||||||
(fp_circle (center 0 0) (end 1 0) (layer "F.SilkS") (width 0.2032) (fill none) (tstamp 10aeb60f-0687-4840-aeb5-a5e914b89db2))
|
|
||||||
(pad "P$1" smd roundrect (at 0 0) (size 1.5 1.5) (layers "F.Cu" "F.Mask") (roundrect_rratio 0.5)
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 278b13e7-2a43-4fc5-a675-ea6ed2efdd4b))
|
|
||||||
)
|
|
@ -1,38 +0,0 @@
|
|||||||
(footprint "MICROBUILDER__0805MP" (version 20211014) (generator pcbnew)
|
|
||||||
(layer "F.Cu")
|
|
||||||
(tedit 0)
|
|
||||||
(descr "<b>0805 MicroPitch</b>")
|
|
||||||
(fp_text reference "REF**" (at -1.5875 -0.9525) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.666496 0.666496) (thickness 0.146304)) (justify left bottom))
|
|
||||||
(tstamp 6d480cb3-ccbc-4f91-b215-36d9b6b90e39)
|
|
||||||
)
|
|
||||||
(fp_text value ">VALUE" (at -1.5875 1.27) (layer "F.Fab")
|
|
||||||
(effects (font (size 0.36576 0.36576) (thickness 0.04064)) (justify left bottom))
|
|
||||||
(tstamp 6bb67786-fe79-4530-a8f0-ca53290823df)
|
|
||||||
)
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy -0.1999 0.5001)
|
|
||||||
(xy 0.1999 0.5001)
|
|
||||||
(xy 0.1999 -0.5001)
|
|
||||||
(xy -0.1999 -0.5001)
|
|
||||||
) (layer "F.Adhes") (width 0) (fill solid) (tstamp 9e351c4d-f895-49c5-ba3f-cecde3dc6e44))
|
|
||||||
(fp_line (start 0 -0.508) (end 0 0.508) (layer "F.SilkS") (width 0.2032) (tstamp 629c7bfb-b888-4932-aba0-6916a21e7f67))
|
|
||||||
(fp_line (start -0.51 0.535) (end 0.51 0.535) (layer "F.Fab") (width 0.1016) (tstamp 22396a4f-3f2f-4a10-9672-ef964a1e15ec))
|
|
||||||
(fp_line (start -0.51 -0.535) (end 0.51 -0.535) (layer "F.Fab") (width 0.1016) (tstamp 90cacfdf-b07f-4151-ac89-23042124f640))
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy 0.4064 0.65)
|
|
||||||
(xy 1 0.65)
|
|
||||||
(xy 1 -0.65)
|
|
||||||
(xy 0.4064 -0.65)
|
|
||||||
) (layer "F.Fab") (width 0) (fill solid) (tstamp 0138f6cb-7190-4a12-af47-1e018fd27b3c))
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy -1 0.65)
|
|
||||||
(xy -0.4168 0.65)
|
|
||||||
(xy -0.4168 -0.65)
|
|
||||||
(xy -1 -0.65)
|
|
||||||
) (layer "F.Fab") (width 0) (fill solid) (tstamp 637ecbcd-a78f-4c8a-8dcf-472bde2de83b))
|
|
||||||
(pad "1" smd rect (at -1.016 0) (size 1.2 1.3) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp bd23358d-4a17-4f52-b69d-122e91d97c44))
|
|
||||||
(pad "2" smd rect (at 1.016 0) (size 1.2 1.3) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 165d5fb4-7aca-4db2-a5bd-306d43842183))
|
|
||||||
)
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,274 +0,0 @@
|
|||||||
(footprint "QFN64_9X9MC_MCH" (version 20211014) (generator pcbnew)
|
|
||||||
(layer "F.Cu")
|
|
||||||
(tedit 0)
|
|
||||||
(fp_text reference "REF**" (at 0 -5.715) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.499872 0.499872) (thickness 0.109728)))
|
|
||||||
(tstamp 3e871d9c-2a1f-438a-ba83-60e5f8d0fa51)
|
|
||||||
)
|
|
||||||
(fp_text value ">VALUE" (at 0 5.715) (layer "F.Fab")
|
|
||||||
(effects (font (size 0.499872 0.499872) (thickness 0.109728)))
|
|
||||||
(tstamp f2dcc10c-546f-4bd9-be1f-368ae783a117)
|
|
||||||
)
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy 2.1606 0.662)
|
|
||||||
(xy 0.8366 0.662)
|
|
||||||
(xy 0.8366 -0.662)
|
|
||||||
(xy 2.1606 -0.662)
|
|
||||||
) (layer "F.Paste") (width 0) (fill solid) (tstamp 2ec0ad3d-3957-4524-a3b2-3e97e3345ecf))
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy 2.1606 -0.8366)
|
|
||||||
(xy 0.8366 -0.8366)
|
|
||||||
(xy 0.8366 -2.1606)
|
|
||||||
(xy 2.1606 -2.1606)
|
|
||||||
) (layer "F.Paste") (width 0) (fill solid) (tstamp 42a0d4d0-fc9b-4730-8110-13a84ab3bcb0))
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy 0.662 0.662)
|
|
||||||
(xy -0.662 0.662)
|
|
||||||
(xy -0.662 -0.662)
|
|
||||||
(xy 0.662 -0.662)
|
|
||||||
) (layer "F.Paste") (width 0) (fill solid) (tstamp 4fbb659c-e71a-4c9b-9e8a-6da964a65cd4))
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy 2.1606 2.1606)
|
|
||||||
(xy 0.8366 2.1606)
|
|
||||||
(xy 0.8366 0.8366)
|
|
||||||
(xy 2.1606 0.8366)
|
|
||||||
) (layer "F.Paste") (width 0) (fill solid) (tstamp 655728ed-daf4-477f-8a3b-b5624d1a73df))
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy -0.8366 2.1606)
|
|
||||||
(xy -2.1606 2.1606)
|
|
||||||
(xy -2.1606 0.8366)
|
|
||||||
(xy -0.8366 0.8366)
|
|
||||||
) (layer "F.Paste") (width 0) (fill solid) (tstamp 6566a81c-4902-448f-a6df-8bc32a765ffa))
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy -0.8366 -0.8366)
|
|
||||||
(xy -2.1606 -0.8366)
|
|
||||||
(xy -2.1606 -2.1606)
|
|
||||||
(xy -0.8366 -2.1606)
|
|
||||||
) (layer "F.Paste") (width 0) (fill solid) (tstamp 99ce666e-158b-4f82-b57f-184f0eedda5c))
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy 0.662 -0.8366)
|
|
||||||
(xy -0.662 -0.8366)
|
|
||||||
(xy -0.662 -2.1606)
|
|
||||||
(xy 0.662 -2.1606)
|
|
||||||
) (layer "F.Paste") (width 0) (fill solid) (tstamp ddf6c3a2-a910-45ea-844b-a8db2b458e91))
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy -0.8366 0.662)
|
|
||||||
(xy -2.1606 0.662)
|
|
||||||
(xy -2.1606 -0.662)
|
|
||||||
(xy -0.8366 -0.662)
|
|
||||||
) (layer "F.Paste") (width 0) (fill solid) (tstamp e3f7e99a-4f59-4e18-a5cb-6900c4b08cae))
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy 0.662 2.1606)
|
|
||||||
(xy -0.662 2.1606)
|
|
||||||
(xy -0.662 0.8366)
|
|
||||||
(xy 0.662 0.8366)
|
|
||||||
) (layer "F.Paste") (width 0) (fill solid) (tstamp f934416f-45a1-43f5-b5e1-fba1dddf1aa4))
|
|
||||||
(fp_line (start 4.2164 4.6228) (end 4.6228 4.6228) (layer "F.SilkS") (width 0.1524) (tstamp 2015e2d6-2795-4247-a207-acb4cf8886e6))
|
|
||||||
(fp_line (start -4.2164 -4.6228) (end -4.6228 -4.6228) (layer "F.SilkS") (width 0.1524) (tstamp 2252c90a-7ebf-4d2d-a791-89982b21117b))
|
|
||||||
(fp_line (start 4.6228 -4.6228) (end 4.2164 -4.6228) (layer "F.SilkS") (width 0.1524) (tstamp 2c7437bb-66d1-4b20-ab25-e4022916701f))
|
|
||||||
(fp_line (start -4.6228 4.6228) (end -4.2164 4.6228) (layer "F.SilkS") (width 0.1524) (tstamp 32c6b15e-f755-475e-b73e-6c7fffdfa53a))
|
|
||||||
(fp_line (start -4.6228 -4.6228) (end -4.6228 -4.2164) (layer "F.SilkS") (width 0.1524) (tstamp 450f1cc5-825a-4891-8a52-c72891a373f0))
|
|
||||||
(fp_line (start 4.6228 4.6228) (end 4.6228 4.2164) (layer "F.SilkS") (width 0.1524) (tstamp 82e659cf-ebcc-4fcd-a243-d4894e4c531e))
|
|
||||||
(fp_line (start 4.6228 -4.2164) (end 4.6228 -4.6228) (layer "F.SilkS") (width 0.1524) (tstamp 8caa9a3a-8461-464c-9a5d-58f28cc73fdb))
|
|
||||||
(fp_line (start -4.6228 4.2164) (end -4.6228 4.6228) (layer "F.SilkS") (width 0.1524) (tstamp 9d03b0af-f67a-4b75-88d5-3fdc2fb53147))
|
|
||||||
(fp_circle (center -5.207 -5.207) (end -5.08 -5.207) (layer "F.SilkS") (width 0.254) (fill none) (tstamp d8471eec-d281-4956-8871-df001c4b9d0e))
|
|
||||||
(fp_line (start 4.4958 -2.5908) (end 4.4958 -2.8956) (layer "F.Fab") (width 0.1524) (tstamp 049458dd-1cf1-4608-bc61-728d12d853ec))
|
|
||||||
(fp_line (start -4.4958 -3.9116) (end -4.4958 -3.6068) (layer "F.Fab") (width 0.1524) (tstamp 05d31c0e-dc59-4cfd-8b11-9750f532f89d))
|
|
||||||
(fp_line (start 4.4958 -0.1016) (end 4.4958 -0.4064) (layer "F.Fab") (width 0.1524) (tstamp 0c83150d-4515-4bc6-947c-a18bb0f583b5))
|
|
||||||
(fp_line (start -3.9116 4.4958) (end -3.6068 4.4958) (layer "F.Fab") (width 0.1524) (tstamp 10420e88-4a28-4643-b21a-9465d0057a73))
|
|
||||||
(fp_line (start 4.4958 0.4064) (end 4.4958 0.1016) (layer "F.Fab") (width 0.1524) (tstamp 10e57a60-62de-407e-b340-5e48d8af51a1))
|
|
||||||
(fp_line (start -4.4958 -2.8956) (end -4.4958 -2.5908) (layer "F.Fab") (width 0.1524) (tstamp 15822844-ae2b-47a9-8d24-dd3b08c9541d))
|
|
||||||
(fp_line (start 4.4958 4.4958) (end 4.4958 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp 189f4344-d732-4381-8d0f-4a31c3fa9319))
|
|
||||||
(fp_line (start 4.4958 -3.0988) (end 4.4958 -3.4036) (layer "F.Fab") (width 0.1524) (tstamp 1da5d536-ffc3-40be-9afa-f932c35159bf))
|
|
||||||
(fp_line (start -0.6096 -4.4958) (end -0.9144 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp 1e512696-3bdf-43ca-8ca3-64344bcd8de6))
|
|
||||||
(fp_line (start -4.4958 -3.4036) (end -4.4958 -3.0988) (layer "F.Fab") (width 0.1524) (tstamp 1efbd3c4-f6bc-449a-85e1-e54dc088704f))
|
|
||||||
(fp_line (start -1.6002 -4.4958) (end -1.905 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp 1fd0b84b-3048-4a24-b2ab-7960a733598e))
|
|
||||||
(fp_line (start 4.4958 1.397) (end 4.4958 1.0922) (layer "F.Fab") (width 0.1524) (tstamp 256bd16a-a961-4e7c-bc57-c47218be0e9b))
|
|
||||||
(fp_line (start 0.1016 4.4958) (end 0.4064 4.4958) (layer "F.Fab") (width 0.1524) (tstamp 2610c8d8-02ed-46ba-b8ce-b15585c89028))
|
|
||||||
(fp_line (start -0.1016 -4.4958) (end -0.4064 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp 2b9a3dd0-e1a1-405a-ac7d-c3e3d878560b))
|
|
||||||
(fp_line (start -4.4958 0.6096) (end -4.4958 0.9144) (layer "F.Fab") (width 0.1524) (tstamp 3132d241-d7f6-4a55-9503-29f1062b517f))
|
|
||||||
(fp_line (start 0.6096 4.4958) (end 0.9144 4.4958) (layer "F.Fab") (width 0.1524) (tstamp 31daf2d4-3957-4ce7-98d3-a043649dd97e))
|
|
||||||
(fp_line (start -4.4958 3.0988) (end -4.4958 3.4036) (layer "F.Fab") (width 0.1524) (tstamp 337e4bb2-4de6-409d-8061-54d04950842d))
|
|
||||||
(fp_line (start 4.4958 -4.4958) (end -4.4958 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp 4115dd93-f2eb-4a67-8dbd-532f41b7a69f))
|
|
||||||
(fp_line (start -4.4958 -0.9144) (end -4.4958 -0.6096) (layer "F.Fab") (width 0.1524) (tstamp 453e6bba-48de-4666-a7eb-66bef0e2b02c))
|
|
||||||
(fp_line (start 3.9116 -4.4958) (end 3.6068 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp 4cda505e-c23d-4504-823e-c4f0c3948a9d))
|
|
||||||
(fp_line (start 4.4958 -1.0922) (end 4.4958 -1.397) (layer "F.Fab") (width 0.1524) (tstamp 503e0041-3118-4b51-83f1-b9c14f77f4b1))
|
|
||||||
(fp_line (start -4.4958 -3.2258) (end -3.2258 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp 54b28547-cb8b-489a-a9df-6ad15177b2e9))
|
|
||||||
(fp_line (start -3.0988 -4.4958) (end -3.4036 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp 5918fd35-f23c-42ff-9fba-9c5a9ac207d3))
|
|
||||||
(fp_line (start 4.4958 3.4036) (end 4.4958 3.0988) (layer "F.Fab") (width 0.1524) (tstamp 5f822173-84ee-42a7-a838-54e1cfc17adf))
|
|
||||||
(fp_line (start 3.6068 4.4958) (end 3.9116 4.4958) (layer "F.Fab") (width 0.1524) (tstamp 632e8422-a140-4238-81b2-8829c7485b2e))
|
|
||||||
(fp_line (start -4.4958 -2.413) (end -4.4958 -2.1082) (layer "F.Fab") (width 0.1524) (tstamp 67448bdd-3f5c-4a5e-8105-da8836876044))
|
|
||||||
(fp_line (start 2.1082 4.4958) (end 2.413 4.4958) (layer "F.Fab") (width 0.1524) (tstamp 69ab593b-1948-43ac-9d69-727c88e9b459))
|
|
||||||
(fp_line (start -2.8956 4.4958) (end -2.5908 4.4958) (layer "F.Fab") (width 0.1524) (tstamp 6dc5284f-c6ff-453d-b163-9f63ed7892ad))
|
|
||||||
(fp_line (start -1.905 4.4958) (end -1.6002 4.4958) (layer "F.Fab") (width 0.1524) (tstamp 6df1e081-1245-47a6-86a6-0c79f1f9db56))
|
|
||||||
(fp_line (start 1.6002 4.4958) (end 1.905 4.4958) (layer "F.Fab") (width 0.1524) (tstamp 709494b8-7fc2-496a-8451-57d7441e8505))
|
|
||||||
(fp_line (start -4.4958 3.6068) (end -4.4958 3.9116) (layer "F.Fab") (width 0.1524) (tstamp 7212588c-17f7-4956-b77b-065540b4ee49))
|
|
||||||
(fp_line (start 2.8956 -4.4958) (end 2.5908 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp 7ce7324c-91ea-47c6-b7c2-bd1b2f2a14c2))
|
|
||||||
(fp_line (start -3.4036 4.4958) (end -3.0988 4.4958) (layer "F.Fab") (width 0.1524) (tstamp 7fb70e9b-db47-465c-b7f5-3f144c3fe511))
|
|
||||||
(fp_line (start 4.4958 -2.1082) (end 4.4958 -2.413) (layer "F.Fab") (width 0.1524) (tstamp 832b785c-4536-49cf-b6de-cedea7d015a6))
|
|
||||||
(fp_line (start 2.5908 4.4958) (end 2.8956 4.4958) (layer "F.Fab") (width 0.1524) (tstamp 838b54da-8d76-4af0-a533-f421e7be02c2))
|
|
||||||
(fp_line (start -4.4958 2.5908) (end -4.4958 2.8956) (layer "F.Fab") (width 0.1524) (tstamp 8c3c449f-a035-419f-9950-338baab558f6))
|
|
||||||
(fp_line (start 4.4958 -1.6002) (end 4.4958 -1.905) (layer "F.Fab") (width 0.1524) (tstamp 8e588935-ced6-458a-a187-91e74c238ac8))
|
|
||||||
(fp_line (start -1.397 4.4958) (end -1.0922 4.4958) (layer "F.Fab") (width 0.1524) (tstamp 8fe96cfe-a951-426f-80b8-9a4ee6265385))
|
|
||||||
(fp_line (start -4.4958 1.0922) (end -4.4958 1.397) (layer "F.Fab") (width 0.1524) (tstamp 8ff9eeba-c353-40da-b499-b20afa11f353))
|
|
||||||
(fp_line (start -4.4958 -4.4958) (end -4.4958 4.4958) (layer "F.Fab") (width 0.1524) (tstamp 93722526-b9c8-4550-8cdd-369ecb315477))
|
|
||||||
(fp_line (start -1.0922 -4.4958) (end -1.397 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp 9a7cda4c-e257-4759-beca-0a008c33f019))
|
|
||||||
(fp_line (start 0.9144 -4.4958) (end 0.6096 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp 9c8602d4-958b-412c-8bb3-0d75d4a4147b))
|
|
||||||
(fp_line (start 4.4958 2.8956) (end 4.4958 2.5908) (layer "F.Fab") (width 0.1524) (tstamp ab68518b-68f5-4fed-903c-3d10b7662e9c))
|
|
||||||
(fp_line (start -4.4958 -0.4064) (end -4.4958 -0.1016) (layer "F.Fab") (width 0.1524) (tstamp ae845f43-7bd0-4d9b-b6ce-ea24c3f78b67))
|
|
||||||
(fp_line (start 4.4958 2.413) (end 4.4958 2.1082) (layer "F.Fab") (width 0.1524) (tstamp ae9df4c2-28e5-48f0-aff2-79a0c1a8a15a))
|
|
||||||
(fp_line (start -0.4064 4.4958) (end -0.1016 4.4958) (layer "F.Fab") (width 0.1524) (tstamp b27f2059-e221-491a-8338-8399fdb6602a))
|
|
||||||
(fp_line (start 1.905 -4.4958) (end 1.6002 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp b30b8721-3fe1-41c3-8198-1a4ccb7ceb74))
|
|
||||||
(fp_line (start -4.4958 4.4958) (end 4.4958 4.4958) (layer "F.Fab") (width 0.1524) (tstamp b476f917-8b6e-4132-b869-771909a051c6))
|
|
||||||
(fp_line (start 1.397 -4.4958) (end 1.0922 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp b5382627-0c47-465b-972a-a305e2e8c255))
|
|
||||||
(fp_line (start -4.4958 0.1016) (end -4.4958 0.4064) (layer "F.Fab") (width 0.1524) (tstamp b6e57a1a-77bc-4011-8ab7-3ca5980c960f))
|
|
||||||
(fp_line (start 4.4958 1.905) (end 4.4958 1.6002) (layer "F.Fab") (width 0.1524) (tstamp b8b1c0a5-6e37-467f-b8f0-bf600730b7aa))
|
|
||||||
(fp_line (start 2.413 -4.4958) (end 2.1082 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp b8c56df8-3039-424a-9681-56118c58b690))
|
|
||||||
(fp_line (start 1.0922 4.4958) (end 1.397 4.4958) (layer "F.Fab") (width 0.1524) (tstamp bb394421-3605-4756-9508-929d6758f654))
|
|
||||||
(fp_line (start -3.6068 -4.4958) (end -3.9116 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp be1b6c3d-7e5b-4a40-908c-b936697a3a15))
|
|
||||||
(fp_line (start 4.4958 -0.6096) (end 4.4958 -0.9144) (layer "F.Fab") (width 0.1524) (tstamp c1182e1e-de77-4a90-a154-0b526180f4ec))
|
|
||||||
(fp_line (start -4.4958 2.1082) (end -4.4958 2.413) (layer "F.Fab") (width 0.1524) (tstamp c1bc3314-d8be-4ff1-a3c3-ed1c9b2d7f54))
|
|
||||||
(fp_line (start -2.1082 -4.4958) (end -2.413 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp c2f4caf6-9472-4b57-8792-997c7297ad6f))
|
|
||||||
(fp_line (start 3.4036 -4.4958) (end 3.0988 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp c580dbd6-b23d-4473-a656-cd0cbd690fa4))
|
|
||||||
(fp_line (start 4.4958 0.9144) (end 4.4958 0.6096) (layer "F.Fab") (width 0.1524) (tstamp c8e7357a-ffca-40b2-9f1f-0e667dd778c7))
|
|
||||||
(fp_line (start 4.4958 -3.6068) (end 4.4958 -3.9116) (layer "F.Fab") (width 0.1524) (tstamp c968c46a-836c-481d-9a49-06172946f81e))
|
|
||||||
(fp_line (start -4.4958 -1.905) (end -4.4958 -1.6002) (layer "F.Fab") (width 0.1524) (tstamp cd74684a-5938-4604-a11c-848de541a8a6))
|
|
||||||
(fp_line (start 0.4064 -4.4958) (end 0.1016 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp d06a81a3-464e-4192-865d-76347fe63188))
|
|
||||||
(fp_line (start -4.4958 1.6002) (end -4.4958 1.905) (layer "F.Fab") (width 0.1524) (tstamp e08784ed-8b2a-49ee-bef9-7b2d3857e5ba))
|
|
||||||
(fp_line (start 4.4958 3.9116) (end 4.4958 3.6068) (layer "F.Fab") (width 0.1524) (tstamp e40896aa-4f74-4b18-add9-342665b200b4))
|
|
||||||
(fp_line (start -0.9144 4.4958) (end -0.6096 4.4958) (layer "F.Fab") (width 0.1524) (tstamp e9b70cd9-c935-4ef0-8469-421eb4fd1bac))
|
|
||||||
(fp_line (start -4.4958 -1.397) (end -4.4958 -1.0922) (layer "F.Fab") (width 0.1524) (tstamp eb56c15a-02df-4139-84ab-d8a1651203fa))
|
|
||||||
(fp_line (start 3.0988 4.4958) (end 3.4036 4.4958) (layer "F.Fab") (width 0.1524) (tstamp f58471ed-0cee-4f6a-b2e5-1373fa172f0d))
|
|
||||||
(fp_line (start -2.5908 -4.4958) (end -2.8956 -4.4958) (layer "F.Fab") (width 0.1524) (tstamp f9ac7fe7-3a4d-4488-bc27-2d7e673008b2))
|
|
||||||
(fp_line (start -2.413 4.4958) (end -2.1082 4.4958) (layer "F.Fab") (width 0.1524) (tstamp f9cb66b4-6171-4d5f-b302-fa11feb7e25e))
|
|
||||||
(pad "1" smd rect (at -4.3942 -3.75 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 0962937a-7e17-49c2-843a-309b9e705166))
|
|
||||||
(pad "2" smd rect (at -4.3942 -3.25 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp a2fedbd9-479b-4398-baab-86589de39528))
|
|
||||||
(pad "3" smd rect (at -4.3942 -2.75 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp e98112c7-b41a-4ab2-8cb2-235538dcf529))
|
|
||||||
(pad "4" smd rect (at -4.3942 -2.25 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 01c8af07-90ff-4b3d-b404-db01135cbcbd))
|
|
||||||
(pad "5" smd rect (at -4.3942 -1.75 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 36cd9aaf-ae25-480f-827b-e14d53a73530))
|
|
||||||
(pad "6" smd rect (at -4.3942 -1.25 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 89a4dae4-94d7-4e16-b389-021d58b92093))
|
|
||||||
(pad "7" smd rect (at -4.3942 -0.75 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp e79aeb81-b0e9-42dc-9659-8a0783bf4de2))
|
|
||||||
(pad "8" smd rect (at -4.3942 -0.25 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 7c204068-d0aa-459b-b4fa-71e8935dd9dd))
|
|
||||||
(pad "9" smd rect (at -4.3942 0.25 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 1c34ed7b-f29c-48ab-a67f-7e34e10696d9))
|
|
||||||
(pad "10" smd rect (at -4.3942 0.75 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 4b62ffb5-f26f-42ce-b28d-6d417a8eb453))
|
|
||||||
(pad "11" smd rect (at -4.3942 1.25 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp b93c79ac-77e5-4fb0-abe6-0f662be65153))
|
|
||||||
(pad "12" smd rect (at -4.3942 1.75 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp a82deada-b3dc-43d8-9675-ea9e287e99f4))
|
|
||||||
(pad "13" smd rect (at -4.3942 2.25 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp f89abcc5-9507-4994-b7ec-08e99b565c34))
|
|
||||||
(pad "14" smd rect (at -4.3942 2.75 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 3b07801d-fbc1-4f67-a403-def8cd01c41d))
|
|
||||||
(pad "15" smd rect (at -4.3942 3.25 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp fc1fc9cb-2099-4de4-8cdd-d83af9dd5f90))
|
|
||||||
(pad "16" smd rect (at -4.3942 3.75 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp bc1d3611-8bc5-4413-b9ae-8a04bfaa0730))
|
|
||||||
(pad "17" smd rect (at -3.75 4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp eae353fe-5b10-44d1-aee2-527fb697339e))
|
|
||||||
(pad "18" smd rect (at -3.25 4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 0be2d7ef-74f7-4c54-9c11-567b325a3550))
|
|
||||||
(pad "19" smd rect (at -2.75 4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 94af1e4e-830f-47d9-b4af-1d2f77f0e846))
|
|
||||||
(pad "20" smd rect (at -2.25 4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 0c875dfd-527c-4ba5-84fd-4d171caf74bb))
|
|
||||||
(pad "21" smd rect (at -1.75 4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp f8327bac-2bfe-4f25-b58b-a76fe59386c6))
|
|
||||||
(pad "22" smd rect (at -1.25 4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 39a31cfe-a89d-4f7b-b480-a9458bbbaeec))
|
|
||||||
(pad "23" smd rect (at -0.75 4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp e1e0568d-368c-488e-902b-8d4d2ca00d90))
|
|
||||||
(pad "24" smd rect (at -0.25 4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp b4c8b1b6-b104-424e-b3ae-e10a63946100))
|
|
||||||
(pad "25" smd rect (at 0.25 4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 43bd0070-dd63-4c69-be69-c4ea652b922a))
|
|
||||||
(pad "26" smd rect (at 0.75 4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 4a1cf31f-d5f4-4210-ac17-84340c530d59))
|
|
||||||
(pad "27" smd rect (at 1.25 4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp a6955bbd-8e2f-47ac-9d2d-1dc038277299))
|
|
||||||
(pad "28" smd rect (at 1.75 4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 7ffcf02c-15fa-481f-81f2-bd642d7f79cb))
|
|
||||||
(pad "29" smd rect (at 2.25 4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 41a0665e-4d1a-4fa6-90c8-82faf5e06664))
|
|
||||||
(pad "30" smd rect (at 2.75 4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp cc003555-3729-46c6-8945-cbd09db502b4))
|
|
||||||
(pad "31" smd rect (at 3.25 4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 5c77f960-ade6-4efb-9c4b-dcf559c7eac2))
|
|
||||||
(pad "32" smd rect (at 3.75 4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp d89499ae-4014-4f85-949d-db2745a5c1be))
|
|
||||||
(pad "33" smd rect (at 4.3942 3.75 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp a15c3c43-a66d-4557-9dd1-9291285217ad))
|
|
||||||
(pad "34" smd rect (at 4.3942 3.25 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 5654db23-3f90-4ce8-879c-12ebe3c1b2f7))
|
|
||||||
(pad "35" smd rect (at 4.3942 2.75 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp cf36d037-47b9-4211-a0ba-1b21c826386c))
|
|
||||||
(pad "36" smd rect (at 4.3942 2.25 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 7446c48e-88d2-43f3-9107-02dc8c28c890))
|
|
||||||
(pad "37" smd rect (at 4.3942 1.75 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp dc190b06-ebe1-480f-9f26-814b886ca30e))
|
|
||||||
(pad "38" smd rect (at 4.3942 1.25 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp f31d87cd-a520-48c6-bd59-16ce7a0c8a4c))
|
|
||||||
(pad "39" smd rect (at 4.3942 0.75 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 3fa7895a-6817-41c8-b122-323e15af05f5))
|
|
||||||
(pad "40" smd rect (at 4.3942 0.25 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 0af777e9-db83-44e5-82b3-4d0cc1118c82))
|
|
||||||
(pad "41" smd rect (at 4.3942 -0.25 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp cc198b2a-7c6d-448a-ba27-a1a291727e63))
|
|
||||||
(pad "42" smd rect (at 4.3942 -0.75 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 4f4f7230-a137-4430-aeca-4b9793e7ef29))
|
|
||||||
(pad "43" smd rect (at 4.3942 -1.25 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 09e93bbc-81b5-4780-a105-25986af4e57c))
|
|
||||||
(pad "44" smd rect (at 4.3942 -1.75 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 80626780-24b0-434f-a133-1859aa0ffc80))
|
|
||||||
(pad "45" smd rect (at 4.3942 -2.25 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp e213e53b-8e52-48ca-828a-5f55b9135f2a))
|
|
||||||
(pad "46" smd rect (at 4.3942 -2.75 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 4c7b79ca-8f05-473a-80e6-3bebce2e229f))
|
|
||||||
(pad "47" smd rect (at 4.3942 -3.25 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 2cab5ab7-2cc3-4048-816f-20e4725e4987))
|
|
||||||
(pad "48" smd rect (at 4.3942 -3.75 270) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 8441a91d-f48e-4251-bcaf-dc7094507898))
|
|
||||||
(pad "49" smd rect (at 3.75 -4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 3c1b33ef-acb9-4266-b8c6-bb013e5dae2c))
|
|
||||||
(pad "50" smd rect (at 3.25 -4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp a8a245a0-1165-437d-87fe-7eee7997aee7))
|
|
||||||
(pad "51" smd rect (at 2.75 -4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 1e99a129-c646-417d-b055-3f37123cf8ef))
|
|
||||||
(pad "52" smd rect (at 2.25 -4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 82864969-1aa8-49df-9eac-4458700e6ca7))
|
|
||||||
(pad "53" smd rect (at 1.75 -4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 4d35c705-5a51-4806-a126-12c937c6b1e7))
|
|
||||||
(pad "54" smd rect (at 1.25 -4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp d491f121-2845-455d-8541-44fa2ec6c594))
|
|
||||||
(pad "55" smd rect (at 0.75 -4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 2186d0aa-6d37-46d1-8257-2c34c61fca1c))
|
|
||||||
(pad "56" smd rect (at 0.25 -4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 732ba6d0-6193-4c48-8070-6779e2d08aac))
|
|
||||||
(pad "57" smd rect (at -0.25 -4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp f7f108f5-a5d2-4a71-bd92-4b7a64cd67ef))
|
|
||||||
(pad "58" smd rect (at -0.75 -4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 5a9c3c03-bc6d-4d54-97af-ccd4b0ec62bd))
|
|
||||||
(pad "59" smd rect (at -1.25 -4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 02619e26-a84a-4ced-aa63-185f88279688))
|
|
||||||
(pad "60" smd rect (at -1.75 -4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 92a99c1b-1f77-4822-9ef0-404ea7ef9b34))
|
|
||||||
(pad "61" smd rect (at -2.25 -4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 90707762-bc1e-4e07-b417-1728eca9f661))
|
|
||||||
(pad "62" smd rect (at -2.75 -4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 3db20676-41a3-4cd5-aaaa-fb7aac0e3ef9))
|
|
||||||
(pad "63" smd rect (at -3.25 -4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 2a66cae8-a800-4958-8ae7-e7d7f25b2674))
|
|
||||||
(pad "64" smd rect (at -3.75 -4.3942 180) (size 0.254 0.8128) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 70110040-44aa-4caf-9824-f55720183967))
|
|
||||||
(pad "65" smd rect (at 0 0) (size 4.572 4.572) (layers "F.Cu" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 1a1fa73c-dc68-468e-8e77-2f7147d220c5))
|
|
||||||
)
|
|
@ -1,29 +0,0 @@
|
|||||||
(footprint "SOD-323F" (version 20211014) (generator pcbnew)
|
|
||||||
(layer "F.Cu")
|
|
||||||
(tedit 0)
|
|
||||||
(fp_text reference "REF**" (at -1.8 -0.9) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.747776 0.747776) (thickness 0.065024)) (justify left bottom))
|
|
||||||
(tstamp 8d130de6-21ac-49e1-b622-a95fb15425d4)
|
|
||||||
)
|
|
||||||
(fp_text value ">VALUE" (at -2.1 1.7) (layer "F.Fab")
|
|
||||||
(effects (font (size 0.747776 0.747776) (thickness 0.065024)) (justify left bottom))
|
|
||||||
(tstamp f5198c37-c2af-4b4a-ace7-b957cdea8352)
|
|
||||||
)
|
|
||||||
(fp_line (start 0.4 -0.6) (end 0.4 0.6) (layer "F.SilkS") (width 0.127) (tstamp 0165360a-2e66-4636-a3c0-be1ba6b7146b))
|
|
||||||
(fp_line (start 0.4 0.6) (end 0.3 0.6) (layer "F.SilkS") (width 0.127) (tstamp 31d6649e-2cb0-4b56-9f6f-94a0dc543d5a))
|
|
||||||
(fp_line (start 0.85 -0.65) (end 0.85 0.65) (layer "F.SilkS") (width 0.127) (tstamp 320884e5-1885-40b5-8b79-b48357d2fa56))
|
|
||||||
(fp_line (start 0.3 0.6) (end 0.3 -0.6) (layer "F.SilkS") (width 0.127) (tstamp 3a4ae6db-a2ad-4e01-be88-bd3d813a8e29))
|
|
||||||
(fp_line (start -0.85 0.65) (end -0.85 -0.65) (layer "F.SilkS") (width 0.127) (tstamp 4fef4a0d-c874-4fe4-9bb4-3b8d64e9347b))
|
|
||||||
(fp_line (start 0.85 0.65) (end -0.85 0.65) (layer "F.SilkS") (width 0.127) (tstamp 7ebd6805-bd0d-4272-b0ea-a17483d80ca5))
|
|
||||||
(fp_line (start -0.85 -0.65) (end 0.85 -0.65) (layer "F.SilkS") (width 0.127) (tstamp cb3724d9-81a8-487f-80a1-8ccce53d6d55))
|
|
||||||
(fp_line (start -0.9 -0.2) (end -1.2 -0.2) (layer "F.Fab") (width 0.127) (tstamp 9290e464-7c10-4d28-b961-53ead5d00f7c))
|
|
||||||
(fp_line (start 1.2 0.2) (end 0.9 0.2) (layer "F.Fab") (width 0.127) (tstamp 9a951f19-776d-408e-9dd7-550047b0e2a6))
|
|
||||||
(fp_line (start -1.2 0.2) (end -0.9 0.2) (layer "F.Fab") (width 0.127) (tstamp c213b2e9-ebc1-49b9-ad72-5803127305a5))
|
|
||||||
(fp_line (start 0.9 -0.2) (end 1.2 -0.2) (layer "F.Fab") (width 0.127) (tstamp c31a6350-0001-4420-90f8-12019bfccaf7))
|
|
||||||
(fp_line (start 1.2 -0.2) (end 1.2 0.2) (layer "F.Fab") (width 0.127) (tstamp d0e73230-a9c2-4595-9b95-ba35aa96b070))
|
|
||||||
(fp_line (start -1.2 -0.2) (end -1.2 0.2) (layer "F.Fab") (width 0.127) (tstamp d91a4af6-4bb8-467f-b69b-1a906bc211a7))
|
|
||||||
(pad "A" smd rect (at -1 0) (size 1 0.8) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 72b76f37-b628-4712-9ff6-021da3f7a013))
|
|
||||||
(pad "C" smd rect (at 1 0) (size 1 0.8) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp cb8dd863-14d8-4470-ad3e-b81fad315442))
|
|
||||||
)
|
|
@ -1,34 +0,0 @@
|
|||||||
(footprint "SOT65P210X110-5N" (version 20211014) (generator pcbnew)
|
|
||||||
(layer "F.Cu")
|
|
||||||
(tedit 0)
|
|
||||||
(fp_text reference "REF**" (at -1.8 -1.4) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.747776 0.747776) (thickness 0.065024)) (justify left bottom))
|
|
||||||
(tstamp 457cb9de-fc22-4a85-9c82-7438f85d137d)
|
|
||||||
)
|
|
||||||
(fp_text value ">VALUE" (at -1.8 1.4) (layer "F.Fab")
|
|
||||||
(effects (font (size 0.747776 0.747776) (thickness 0.065024)) (justify left top))
|
|
||||||
(tstamp 674ecd7e-5cc8-4469-9690-04223952bf82)
|
|
||||||
)
|
|
||||||
(fp_line (start -0.625 1.17) (end 0.625 1.17) (layer "F.SilkS") (width 0.127) (tstamp 2f22abf8-16bd-42ad-a0ee-757b9dc94627))
|
|
||||||
(fp_line (start 0.625 -1.17) (end -0.625 -1.17) (layer "F.SilkS") (width 0.127) (tstamp 7fba8434-1fa5-492e-93c3-f5210db0af84))
|
|
||||||
(fp_circle (center -2.1 -0.9) (end -2 -0.9) (layer "F.SilkS") (width 0.2) (fill none) (tstamp 687a4ff9-95c3-4e33-9daa-47acc0e40e1e))
|
|
||||||
(fp_line (start -1.805 -1.2625) (end -1.805 1.2625) (layer "F.CrtYd") (width 0.05) (tstamp 17863368-ebf9-4b76-8a27-2431df2a120c))
|
|
||||||
(fp_line (start 1.805 -1.2625) (end -1.805 -1.2625) (layer "F.CrtYd") (width 0.05) (tstamp 62cf88fb-d482-4b99-9b0f-281e43055f8b))
|
|
||||||
(fp_line (start -1.805 1.2625) (end 1.805 1.2625) (layer "F.CrtYd") (width 0.05) (tstamp b5135559-37a4-492d-a6dc-8ab982428252))
|
|
||||||
(fp_line (start 1.805 1.2625) (end 1.805 -1.2625) (layer "F.CrtYd") (width 0.05) (tstamp dcf4a5aa-5c00-4b2e-ba11-24374e17c340))
|
|
||||||
(fp_line (start 0.625 1.0125) (end 0.625 -1.0125) (layer "F.Fab") (width 0.127) (tstamp 0d92b703-ef1a-45ad-8945-076840a3419d))
|
|
||||||
(fp_line (start 0.625 -1.0125) (end -0.625 -1.0125) (layer "F.Fab") (width 0.127) (tstamp 3b31ae4c-5100-4114-b54f-c515c85e31ef))
|
|
||||||
(fp_line (start -0.625 -1.0125) (end -0.625 1.0125) (layer "F.Fab") (width 0.127) (tstamp 4479abbf-71f9-42d6-b915-553dfa74ac7a))
|
|
||||||
(fp_line (start -0.625 1.0125) (end 0.625 1.0125) (layer "F.Fab") (width 0.127) (tstamp a7b3fdba-c9c6-4541-aa58-e7d5af1159f7))
|
|
||||||
(fp_circle (center -2.1 -0.9) (end -2 -0.9) (layer "F.Fab") (width 0.2) (fill none) (tstamp 4b3d66f1-3431-45ab-8164-ecd0988102d2))
|
|
||||||
(pad "1" smd rect (at -0.97 -0.65) (size 1.17 0.4) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 79539752-66ac-4cde-9791-7e50fc9c08e9))
|
|
||||||
(pad "2" smd rect (at -0.97 0) (size 1.17 0.4) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 412a873e-1c99-4a4b-86e1-a676f2285a25))
|
|
||||||
(pad "3" smd rect (at -0.97 0.65) (size 1.17 0.4) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp d56e9cb4-6e4a-4ec0-a67f-7fd53cd17c95))
|
|
||||||
(pad "4" smd rect (at 0.97 0.65) (size 1.17 0.4) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp bed9dd9c-f127-43c3-a252-0194a4ef1905))
|
|
||||||
(pad "5" smd rect (at 0.97 -0.65) (size 1.17 0.4) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 468863fa-6e22-4082-9c4f-d4c63b16d5f2))
|
|
||||||
)
|
|
@ -1,282 +0,0 @@
|
|||||||
(footprint "SW_EVP-BB1AAB000"
|
|
||||||
(version 20240108)
|
|
||||||
(generator "pcbnew")
|
|
||||||
(generator_version "8.0")
|
|
||||||
(layer "F.Cu")
|
|
||||||
(property "Reference" "REF**"
|
|
||||||
(at -2.628409 -1.50195 0)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "5bfc1104-d8e6-463d-96bf-3b297940d17a")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1.169909 1.169909)
|
|
||||||
(thickness 0.101731)
|
|
||||||
)
|
|
||||||
(justify left bottom)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Value" ">VALUE"
|
|
||||||
(at -2.629818 3.005518 0)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "0d6e3660-78d4-4c9d-aa40-0c2181937185")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1.170545 1.170545)
|
|
||||||
(thickness 0.101786)
|
|
||||||
)
|
|
||||||
(justify left bottom)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Footprint" ""
|
|
||||||
(at 0 0 0)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(hide yes)
|
|
||||||
(uuid "adf19691-fa3b-4d7a-abc1-3f78748c21cf")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1.27 1.27)
|
|
||||||
(thickness 0.15)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Datasheet" ""
|
|
||||||
(at 0 0 0)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(hide yes)
|
|
||||||
(uuid "e644642e-886c-44ac-b86f-d6c911d62221")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1.27 1.27)
|
|
||||||
(thickness 0.15)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(property "Description" ""
|
|
||||||
(at 0 0 0)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(hide yes)
|
|
||||||
(uuid "36f34cd2-251b-4e5d-9062-61208ddf5d26")
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1.27 1.27)
|
|
||||||
(thickness 0.15)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start -1.325 -0.375)
|
|
||||||
(end -1.325 0.375)
|
|
||||||
(stroke
|
|
||||||
(width 0.465)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.Paste")
|
|
||||||
(uuid "4d800587-4919-426d-b1ba-7b44b3e9466f")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 1.325 -0.375)
|
|
||||||
(end 1.325 0.375)
|
|
||||||
(stroke
|
|
||||||
(width 0.465)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.Paste")
|
|
||||||
(uuid "ce64bb60-7755-4c83-8701-9a2cef3a1c7b")
|
|
||||||
)
|
|
||||||
(fp_poly
|
|
||||||
(pts
|
|
||||||
(xy -1.095 -0.145) (xy -1.555 -0.145) (xy -1.555 -0.605) (xy -1.095 -0.605)
|
|
||||||
)
|
|
||||||
(stroke
|
|
||||||
(width 0)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(fill solid)
|
|
||||||
(layer "F.Paste")
|
|
||||||
(uuid "6db398f8-2729-450b-aef1-8242c2cd2e0f")
|
|
||||||
)
|
|
||||||
(fp_poly
|
|
||||||
(pts
|
|
||||||
(xy -1.095 0.605) (xy -1.555 0.605) (xy -1.555 0.145) (xy -1.095 0.145)
|
|
||||||
)
|
|
||||||
(stroke
|
|
||||||
(width 0)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(fill solid)
|
|
||||||
(layer "F.Paste")
|
|
||||||
(uuid "84da75db-45c9-4044-8d1e-347621238750")
|
|
||||||
)
|
|
||||||
(fp_poly
|
|
||||||
(pts
|
|
||||||
(xy 1.555 -0.145) (xy 1.095 -0.145) (xy 1.095 -0.605) (xy 1.555 -0.605)
|
|
||||||
)
|
|
||||||
(stroke
|
|
||||||
(width 0)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(fill solid)
|
|
||||||
(layer "F.Paste")
|
|
||||||
(uuid "e8fb6dd3-e158-4257-9e15-870695c296b7")
|
|
||||||
)
|
|
||||||
(fp_poly
|
|
||||||
(pts
|
|
||||||
(xy 1.555 0.605) (xy 1.095 0.605) (xy 1.095 0.145) (xy 1.555 0.145)
|
|
||||||
)
|
|
||||||
(stroke
|
|
||||||
(width 0)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(fill solid)
|
|
||||||
(layer "F.Paste")
|
|
||||||
(uuid "85bec7d7-877b-406c-bad8-abaa99fcbe23")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start -1.3 -0.9635)
|
|
||||||
(end 1.3 -0.9635)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "daeab9ff-4ca6-4d3e-8486-53bc65dc2c70")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start -1.3 0.9635)
|
|
||||||
(end 1.3 0.9635)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.SilkS")
|
|
||||||
(uuid "2a0673e1-384a-4091-aad2-73c6b1e7babd")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start -1.325 -0.375)
|
|
||||||
(end -1.325 0.375)
|
|
||||||
(stroke
|
|
||||||
(width 0.55)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.Mask")
|
|
||||||
(uuid "573428fa-1f2a-49c8-b999-dc918c489ec0")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 1.325 -0.375)
|
|
||||||
(end 1.325 0.375)
|
|
||||||
(stroke
|
|
||||||
(width 0.55)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.Mask")
|
|
||||||
(uuid "3f0f8722-1483-4aa6-bcae-dcff8ecba59b")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start -1.85 -1.05)
|
|
||||||
(end 1.85 -1.05)
|
|
||||||
(stroke
|
|
||||||
(width 0.05)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.CrtYd")
|
|
||||||
(uuid "d6daa52c-633b-4f9e-9611-999747c83ff7")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start -1.85 1.05)
|
|
||||||
(end -1.85 -1.05)
|
|
||||||
(stroke
|
|
||||||
(width 0.05)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.CrtYd")
|
|
||||||
(uuid "b1dcf4ab-520c-4ad1-8398-87f8dd8fec29")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 1.85 -1.05)
|
|
||||||
(end 1.85 1.05)
|
|
||||||
(stroke
|
|
||||||
(width 0.05)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.CrtYd")
|
|
||||||
(uuid "4939d836-3fdc-47f9-b885-f87382603570")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 1.85 1.05)
|
|
||||||
(end -1.85 1.05)
|
|
||||||
(stroke
|
|
||||||
(width 0.05)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.CrtYd")
|
|
||||||
(uuid "e4f415ce-fdbb-4c24-b2a1-e501eae24f60")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start -1.3 -0.8)
|
|
||||||
(end 1.3 -0.8)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "8e13a383-d573-4545-b914-42a75e606b8c")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start -1.3 0.8)
|
|
||||||
(end -1.3 -0.8)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "1e090053-4c0c-424f-8664-54986066ef27")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 1.3 -0.8)
|
|
||||||
(end 1.3 0.8)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "df66859c-c21f-4048-8e27-8d86d5f411f0")
|
|
||||||
)
|
|
||||||
(fp_line
|
|
||||||
(start 1.3 0.8)
|
|
||||||
(end -1.3 0.8)
|
|
||||||
(stroke
|
|
||||||
(width 0.127)
|
|
||||||
(type solid)
|
|
||||||
)
|
|
||||||
(layer "F.Fab")
|
|
||||||
(uuid "31b618ce-8704-4bd2-948f-25d290b97ca7")
|
|
||||||
)
|
|
||||||
(pad "A1" smd rect
|
|
||||||
(at -1.325 -0.375)
|
|
||||||
(size 0.55 0.55)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635)
|
|
||||||
(uuid "efeb691d-5593-439a-a931-ffe8a985f2c4")
|
|
||||||
)
|
|
||||||
(pad "A2" smd rect
|
|
||||||
(at -1.325 0.375)
|
|
||||||
(size 0.55 0.55)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635)
|
|
||||||
(uuid "4ceaa3e3-568f-42dd-8491-a773d8add0f9")
|
|
||||||
)
|
|
||||||
(pad "B1" smd rect
|
|
||||||
(at 1.325 -0.375)
|
|
||||||
(size 0.55 0.55)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635)
|
|
||||||
(uuid "5bdc0a88-b8c1-4c56-b2c0-8737e7eeb5ed")
|
|
||||||
)
|
|
||||||
(pad "B2" smd rect
|
|
||||||
(at 1.325 0.375)
|
|
||||||
(size 0.55 0.55)
|
|
||||||
(layers "F.Cu" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635)
|
|
||||||
(uuid "fb158033-514b-4126-84ba-b82cd884d9a2")
|
|
||||||
)
|
|
||||||
)
|
|
@ -1,32 +0,0 @@
|
|||||||
(footprint "XTAL3215" (version 20211014) (generator pcbnew)
|
|
||||||
(layer "F.Cu")
|
|
||||||
(tedit 0)
|
|
||||||
(fp_text reference "REF**" (at -2.3 2.2) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.93472 0.93472) (thickness 0.08128)) (justify left bottom))
|
|
||||||
(tstamp a9c6df82-9b3d-430b-ac3d-773dba21edac)
|
|
||||||
)
|
|
||||||
(fp_text value ">VALUE" (at -2.6 -1.2) (layer "F.Fab")
|
|
||||||
(effects (font (size 0.93472 0.93472) (thickness 0.08128)) (justify left bottom))
|
|
||||||
(tstamp 2d0c10c9-abbe-4218-b4a2-a2a06a7ca92f)
|
|
||||||
)
|
|
||||||
(fp_line (start -1.6 0.4172) (end -1.6 -0.4764) (layer "F.SilkS") (width 0.127) (tstamp 078a622d-2e6e-4da6-9441-6376052c47eb))
|
|
||||||
(fp_line (start -1.1 -0.4) (end 1 -0.4) (layer "F.SilkS") (width 0.127) (tstamp 16000523-6636-4a7c-90fe-2f09fce78d5e))
|
|
||||||
(fp_line (start -1.3 0.2) (end -1.3 -0.1) (layer "F.SilkS") (width 0.127) (tstamp 46b2dcb4-bf9c-401f-993d-249e79f10a6f))
|
|
||||||
(fp_line (start 1 0.4) (end -1 0.4) (layer "F.SilkS") (width 0.127) (tstamp 519e3fa1-ccf8-482c-80ef-bd5f407c1c5f))
|
|
||||||
(fp_line (start 1.3172 0.7) (end -1.3172 0.7) (layer "F.SilkS") (width 0.127) (tstamp 93307323-bd88-4ddc-ab8a-4f2d823906f4))
|
|
||||||
(fp_line (start -1.3764 -0.7) (end 1.2838 -0.7) (layer "F.SilkS") (width 0.127) (tstamp 96d8ac11-ef54-4b37-87dc-dbd4ca0b1cb4))
|
|
||||||
(fp_line (start 1.6 -0.3838) (end 1.6 0.4172) (layer "F.SilkS") (width 0.127) (tstamp bec9dc30-b160-4d84-ad5b-772b0009be76))
|
|
||||||
(fp_line (start 1.3 -0.1) (end 1.3 0.1) (layer "F.SilkS") (width 0.127) (tstamp f4ad8862-e14a-4b15-bbdf-fb0b7a3f55f3))
|
|
||||||
(fp_arc (start -1.3172 0.7) (mid -1.51717 0.61717) (end -1.6 0.4172) (layer "F.SilkS") (width 0.127) (tstamp 0c48587a-6c32-4781-9323-526f5fdc2492))
|
|
||||||
(fp_arc (start 1.3 0.1) (mid 1.212131 0.312132) (end 0.999999 0.399999) (layer "F.SilkS") (width 0.127) (tstamp 11535cde-6a05-4f6a-a42d-7840292384eb))
|
|
||||||
(fp_arc (start -1 0.4) (mid -1.191422 0.362132) (end -1.300001 0.199999) (layer "F.SilkS") (width 0.127) (tstamp 1d879171-52ed-4187-9c41-72a9e6c6b120))
|
|
||||||
(fp_arc (start -1.6 -0.4764) (mid -1.534509 -0.634509) (end -1.3764 -0.7) (layer "F.SilkS") (width 0.127) (tstamp 285901dd-7be7-4fde-bb96-976224872c4a))
|
|
||||||
(fp_arc (start -1.3 -0.1) (mid -1.262161 -0.291441) (end -1.099999 -0.399999) (layer "F.SilkS") (width 0.127) (tstamp 2eacfb6a-d7d1-4bde-b6bc-6096465bc8c1))
|
|
||||||
(fp_arc (start 1.2838 -0.7) (mid 1.507387 -0.607387) (end 1.6 -0.3838) (layer "F.SilkS") (width 0.127) (tstamp 499a51d8-52e8-4eb8-aeac-96a1be49503b))
|
|
||||||
(fp_arc (start 1.6 0.4172) (mid 1.51717 0.61717) (end 1.3172 0.7) (layer "F.SilkS") (width 0.127) (tstamp ab55d0d5-009c-4663-a9bc-dfc975cfe4f8))
|
|
||||||
(fp_arc (start 1 -0.4) (mid 1.212103 -0.312103) (end 1.3 -0.1) (layer "F.SilkS") (width 0.127) (tstamp e095b566-4c68-4a1b-a41d-59524889820a))
|
|
||||||
(pad "P$1" smd rect (at 1.2 0) (size 1.1 1.9) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 4ee07c5d-9f78-4558-bf26-a2f36b7ff744))
|
|
||||||
(pad "P$2" smd rect (at -1.2 0 180) (size 1.1 1.9) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 4d20cca2-e97b-4688-a784-b838b6ce3b76))
|
|
||||||
)
|
|
@ -1,38 +0,0 @@
|
|||||||
(footprint "_0402MP" (version 20211014) (generator pcbnew)
|
|
||||||
(layer "F.Cu")
|
|
||||||
(tedit 0)
|
|
||||||
(descr "<b>0402 MicroPitch<p>")
|
|
||||||
(fp_text reference "REF**" (at -0.635 -0.4763) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.499872 0.499872) (thickness 0.109728)) (justify left bottom))
|
|
||||||
(tstamp 66f54e50-362a-4456-a671-e8b742aabfe7)
|
|
||||||
)
|
|
||||||
(fp_text value ">VALUE" (at -0.635 0.7938) (layer "F.Fab")
|
|
||||||
(effects (font (size 0.36576 0.36576) (thickness 0.04064)) (justify left bottom))
|
|
||||||
(tstamp 7205e05a-db5d-40d5-aa8d-0965b4d6a0a3)
|
|
||||||
)
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy -0.1 0.2)
|
|
||||||
(xy 0.1 0.2)
|
|
||||||
(xy 0.1 -0.2)
|
|
||||||
(xy -0.1 -0.2)
|
|
||||||
) (layer "F.Adhes") (width 0) (fill solid) (tstamp 151adedc-3095-4283-bc8b-67b6c834501c))
|
|
||||||
(fp_line (start 0 -0.127) (end 0 0.127) (layer "F.SilkS") (width 0.2032) (tstamp a31d0c78-4bd5-4839-be72-14af5f3f165d))
|
|
||||||
(fp_line (start -0.245 -0.174) (end 0.245 -0.174) (layer "F.Fab") (width 0.1016) (tstamp ddaa21a2-edd4-401c-ac76-6f183cf5be3d))
|
|
||||||
(fp_line (start 0.245 0.174) (end -0.245 0.174) (layer "F.Fab") (width 0.1016) (tstamp ec8c18e2-500a-4935-81c1-76a24c731e63))
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy -0.5 0.25)
|
|
||||||
(xy -0.254 0.25)
|
|
||||||
(xy -0.254 -0.25)
|
|
||||||
(xy -0.5 -0.25)
|
|
||||||
) (layer "F.Fab") (width 0) (fill solid) (tstamp 335257f6-f886-460f-b838-e2d8232128c8))
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy 0.2588 0.25)
|
|
||||||
(xy 0.5 0.25)
|
|
||||||
(xy 0.5 -0.25)
|
|
||||||
(xy 0.2588 -0.25)
|
|
||||||
) (layer "F.Fab") (width 0) (fill solid) (tstamp 3d7cd32b-2bab-4b7c-a3da-482a6d596be7))
|
|
||||||
(pad "1" smd rect (at -0.508 0) (size 0.5 0.5) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp c609a9e6-5647-44af-a743-b732a2a0c37d))
|
|
||||||
(pad "2" smd rect (at 0.508 0) (size 0.5 0.5) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 1249fd1b-9f93-42c3-bb42-dae4056aa043))
|
|
||||||
)
|
|
@ -1,38 +0,0 @@
|
|||||||
(footprint "_0603MP" (version 20211014) (generator pcbnew)
|
|
||||||
(layer "F.Cu")
|
|
||||||
(tedit 0)
|
|
||||||
(descr "<b>0603 MicroPitch</b>")
|
|
||||||
(fp_text reference "REF**" (at -0.9525 -0.635) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.666496 0.666496) (thickness 0.146304)) (justify left bottom))
|
|
||||||
(tstamp a1f3b960-720c-4050-8c7b-e4fb81f7c447)
|
|
||||||
)
|
|
||||||
(fp_text value ">VALUE" (at -0.9525 0.9525) (layer "F.Fab")
|
|
||||||
(effects (font (size 0.36576 0.36576) (thickness 0.04064)) (justify left bottom))
|
|
||||||
(tstamp f7454cc9-a5be-454b-b5bb-decc69423e09)
|
|
||||||
)
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy -0.1999 0.25)
|
|
||||||
(xy 0.1999 0.25)
|
|
||||||
(xy 0.1999 -0.25)
|
|
||||||
(xy -0.1999 -0.25)
|
|
||||||
) (layer "F.Adhes") (width 0) (fill solid) (tstamp 23d6168b-6030-48a2-96be-111de678cbf9))
|
|
||||||
(fp_line (start 0 -0.254) (end 0 0.254) (layer "F.SilkS") (width 0.2032) (tstamp ebb6e458-b901-41c0-b269-52de840ade47))
|
|
||||||
(fp_line (start -0.432 0.306) (end 0.432 0.306) (layer "F.Fab") (width 0.1016) (tstamp 0ff59386-9f8f-4bc5-871b-4804e001e34f))
|
|
||||||
(fp_line (start 0.432 -0.306) (end -0.432 -0.306) (layer "F.Fab") (width 0.1016) (tstamp c1b693b3-0c6a-47f3-bd85-e73de386676a))
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy 0.4318 0.4)
|
|
||||||
(xy 0.8 0.4)
|
|
||||||
(xy 0.8 -0.4)
|
|
||||||
(xy 0.4318 -0.4)
|
|
||||||
) (layer "F.Fab") (width 0) (fill solid) (tstamp 98d6e8c0-7c85-4056-b142-5a49d5f78f6a))
|
|
||||||
(fp_poly (pts
|
|
||||||
(xy -0.8 0.4)
|
|
||||||
(xy -0.4318 0.4)
|
|
||||||
(xy -0.4318 -0.4)
|
|
||||||
(xy -0.8 -0.4)
|
|
||||||
) (layer "F.Fab") (width 0) (fill solid) (tstamp c67e1e1d-f03c-4cd2-855a-6f77ed9840d4))
|
|
||||||
(pad "1" smd rect (at -0.762 0) (size 0.8 0.8) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp 261178c6-668c-4d25-9316-e97dc5e52e2d))
|
|
||||||
(pad "2" smd rect (at 0.762 0) (size 0.8 0.8) (layers "F.Cu" "F.Paste" "F.Mask")
|
|
||||||
(solder_mask_margin 0.0635) (tstamp aece925f-4ef2-4a3b-a64c-72600b766d22))
|
|
||||||
)
|
|
@ -1,4 +0,0 @@
|
|||||||
Default True 2.0 3
|
|
||||||
gnd True 2.0 3
|
|
||||||
power True 2.0 3
|
|
||||||
True True False
|
|
@ -1,42 +0,0 @@
|
|||||||
(footprint "OSO_SWD_2x3" (version 20211014) (generator pcbnew)
|
|
||||||
(layer "F.Cu")
|
|
||||||
(tedit 0)
|
|
||||||
(attr smd)
|
|
||||||
(fp_text reference "REF**" (at 0 -2.032 unlocked) (layer "F.SilkS") hide
|
|
||||||
(effects (font (size 1 1) (thickness 0.15)))
|
|
||||||
(tstamp cc97765e-03dd-40c8-bc09-9942f8485d23)
|
|
||||||
)
|
|
||||||
(fp_text value "OSO_SWD_2x3" (at 0 -4.572 unlocked) (layer "F.Fab")
|
|
||||||
(effects (font (size 1 1) (thickness 0.15)))
|
|
||||||
(tstamp 3723f1be-f632-4091-a098-c9348aec63f6)
|
|
||||||
)
|
|
||||||
(fp_text user "C" (at -0.508 -0.762 unlocked) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.5 0.5) (thickness 0.1)))
|
|
||||||
(tstamp 88931c8d-237f-4e79-b244-24354b5507cc)
|
|
||||||
)
|
|
||||||
(fp_text user "+" (at -0.508 1.778 unlocked) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.5 0.5) (thickness 0.1)))
|
|
||||||
(tstamp b2d594d3-dac9-41e7-b515-19ad22df4cd2)
|
|
||||||
)
|
|
||||||
(fp_text user "D" (at 2.032 1.778 unlocked) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.5 0.5) (thickness 0.1)))
|
|
||||||
(tstamp c41801cb-4840-4a63-9b83-a0b86093de8d)
|
|
||||||
)
|
|
||||||
(fp_text user "-" (at 2.032 -0.762 unlocked) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.5 0.5) (thickness 0.1)))
|
|
||||||
(tstamp d116e34b-7d96-49fa-980e-61f5adbb5cc2)
|
|
||||||
)
|
|
||||||
(fp_text user "~{R}" (at -0.508 -3.302 unlocked) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.5 0.5) (thickness 0.1)))
|
|
||||||
(tstamp e48e1604-d489-45a4-9587-152a042c354a)
|
|
||||||
)
|
|
||||||
(fp_text user "${REFERENCE}" (at 0 4.318 unlocked) (layer "F.Fab")
|
|
||||||
(effects (font (size 1 1) (thickness 0.15)))
|
|
||||||
(tstamp 3cf253e6-b3d8-4b70-990a-3a9df456d233)
|
|
||||||
)
|
|
||||||
(pad "1" smd circle (at 1.27 2.54) (size 1.5 1.5) (layers "F.Cu" "F.Mask") (tstamp c93a3c51-b06c-47bc-b2c8-dcd43fd3bce4))
|
|
||||||
(pad "2" smd circle (at 1.27 0) (size 1.5 1.5) (layers "F.Cu" "F.Mask") (tstamp 657a0b8d-9c0a-4efd-920e-1742e80dbd77))
|
|
||||||
(pad "3" smd circle (at -1.27 2.54) (size 1.5 1.5) (layers "F.Cu" "F.Mask") (tstamp 110879b7-d820-400e-83c2-2ba83b15a32d))
|
|
||||||
(pad "4" smd circle (at -1.27 0) (size 1.5 1.5) (layers "F.Cu" "F.Mask") (tstamp 0da5021b-2960-4fb1-abd4-df913ada6e37))
|
|
||||||
(pad "5" smd circle (at -1.27 -2.54) (size 1.5 1.5) (layers "F.Cu" "F.Mask") (tstamp 5e6b9662-455f-4d0d-8334-3f95b2cc20e1))
|
|
||||||
)
|
|
@ -1,42 +0,0 @@
|
|||||||
(footprint "OSO_SWD_Linear" (version 20211014) (generator pcbnew)
|
|
||||||
(layer "F.Cu")
|
|
||||||
(tedit 0)
|
|
||||||
(attr smd)
|
|
||||||
(fp_text reference "REF**" (at 0 -2.032 unlocked) (layer "F.SilkS") hide
|
|
||||||
(effects (font (size 1 1) (thickness 0.15)))
|
|
||||||
(tstamp cc97765e-03dd-40c8-bc09-9942f8485d23)
|
|
||||||
)
|
|
||||||
(fp_text value "OSO_SWD_Linear" (at 0 -1.5 unlocked) (layer "F.Fab")
|
|
||||||
(effects (font (size 1 1) (thickness 0.15)))
|
|
||||||
(tstamp 3723f1be-f632-4091-a098-c9348aec63f6)
|
|
||||||
)
|
|
||||||
(fp_text user "SWC" (at 2.54 1.524 unlocked) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.5 0.5) (thickness 0.1)))
|
|
||||||
(tstamp 88931c8d-237f-4e79-b244-24354b5507cc)
|
|
||||||
)
|
|
||||||
(fp_text user "3V3" (at 0 1.524 unlocked) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.5 0.5) (thickness 0.1)))
|
|
||||||
(tstamp b2d594d3-dac9-41e7-b515-19ad22df4cd2)
|
|
||||||
)
|
|
||||||
(fp_text user "SWD" (at -5.08 1.524 unlocked) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.5 0.5) (thickness 0.1)))
|
|
||||||
(tstamp c41801cb-4840-4a63-9b83-a0b86093de8d)
|
|
||||||
)
|
|
||||||
(fp_text user "GND" (at -2.54 1.524 unlocked) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.5 0.5) (thickness 0.1)))
|
|
||||||
(tstamp d116e34b-7d96-49fa-980e-61f5adbb5cc2)
|
|
||||||
)
|
|
||||||
(fp_text user "~{RST}" (at 5.08 1.524 unlocked) (layer "F.SilkS")
|
|
||||||
(effects (font (size 0.5 0.5) (thickness 0.1)))
|
|
||||||
(tstamp e48e1604-d489-45a4-9587-152a042c354a)
|
|
||||||
)
|
|
||||||
(fp_text user "${REFERENCE}" (at 0 3.048 unlocked) (layer "F.Fab")
|
|
||||||
(effects (font (size 1 1) (thickness 0.15)))
|
|
||||||
(tstamp 3cf253e6-b3d8-4b70-990a-3a9df456d233)
|
|
||||||
)
|
|
||||||
(pad "1" smd circle (at -5.08 0) (size 1.5 1.5) (layers "F.Cu" "F.Mask") (tstamp c93a3c51-b06c-47bc-b2c8-dcd43fd3bce4))
|
|
||||||
(pad "2" smd circle (at -2.54 0) (size 1.5 1.5) (layers "F.Cu" "F.Mask") (tstamp 657a0b8d-9c0a-4efd-920e-1742e80dbd77))
|
|
||||||
(pad "3" smd circle (at 0 0) (size 1.5 1.5) (layers "F.Cu" "F.Mask") (tstamp 110879b7-d820-400e-83c2-2ba83b15a32d))
|
|
||||||
(pad "4" smd circle (at 2.54 0) (size 1.5 1.5) (layers "F.Cu" "F.Mask") (tstamp 0da5021b-2960-4fb1-abd4-df913ada6e37))
|
|
||||||
(pad "5" smd circle (at 5.08 0) (size 1.5 1.5) (layers "F.Cu" "F.Mask") (tstamp 5e6b9662-455f-4d0d-8334-3f95b2cc20e1))
|
|
||||||
)
|
|
@ -1,44 +0,0 @@
|
|||||||
(kicad_symbol_lib (version 20211014) (generator kicad_symbol_editor)
|
|
||||||
(symbol "OSO_SWD" (in_bom yes) (on_board yes)
|
|
||||||
(property "Reference" "J" (id 0) (at 0 -7.62 0)
|
|
||||||
(effects (font (size 1.27 1.27)))
|
|
||||||
)
|
|
||||||
(property "Value" "OSO_SWD" (id 1) (at 0 7.62 0)
|
|
||||||
(effects (font (size 1.27 1.27)))
|
|
||||||
)
|
|
||||||
(property "Footprint" "" (id 2) (at 0 0 0)
|
|
||||||
(effects (font (size 1.27 1.27)) hide)
|
|
||||||
)
|
|
||||||
(property "Datasheet" "" (id 3) (at 0 0 0)
|
|
||||||
(effects (font (size 1.27 1.27)) hide)
|
|
||||||
)
|
|
||||||
(symbol "OSO_SWD_0_1"
|
|
||||||
(rectangle (start -5.08 6.35) (end 5.08 -6.35)
|
|
||||||
(stroke (width 0) (type default) (color 0 0 0 0))
|
|
||||||
(fill (type background))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(symbol "OSO_SWD_1_1"
|
|
||||||
(pin bidirectional line (at -7.62 5.08 0) (length 2.54)
|
|
||||||
(name "SWDIO" (effects (font (size 1.27 1.27))))
|
|
||||||
(number "1" (effects (font (size 1.27 1.27))))
|
|
||||||
)
|
|
||||||
(pin power_in line (at -7.62 2.54 0) (length 2.54)
|
|
||||||
(name "GND" (effects (font (size 1.27 1.27))))
|
|
||||||
(number "2" (effects (font (size 1.27 1.27))))
|
|
||||||
)
|
|
||||||
(pin power_in line (at -7.62 0 0) (length 2.54)
|
|
||||||
(name "VCC" (effects (font (size 1.27 1.27))))
|
|
||||||
(number "3" (effects (font (size 1.27 1.27))))
|
|
||||||
)
|
|
||||||
(pin bidirectional line (at -7.62 -2.54 0) (length 2.54)
|
|
||||||
(name "SWCLK" (effects (font (size 1.27 1.27))))
|
|
||||||
(number "4" (effects (font (size 1.27 1.27))))
|
|
||||||
)
|
|
||||||
(pin bidirectional line (at -7.62 -5.08 0) (length 2.54)
|
|
||||||
(name "~{RESET}" (effects (font (size 1.27 1.27))))
|
|
||||||
(number "5" (effects (font (size 1.27 1.27))))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,5 +0,0 @@
|
|||||||
(kicad_wks (version 20210606) (generator pl_editor)
|
|
||||||
(setup (textsize 1.5 1.5)(linewidth 0.15)(textlinewidth 0.15)
|
|
||||||
(left_margin 10)(right_margin 10)(top_margin 10)(bottom_margin 10))
|
|
||||||
(line (name "segm1:Line") (start 0 0) (end 0 0))
|
|
||||||
)
|
|
@ -1,4 +0,0 @@
|
|||||||
(fp_lib_table
|
|
||||||
(lib (name "OSO-SWAT-A1-05")(type "KiCad")(uri "$(KIPRJMOD)/OSO-SWAT-C1.pretty")(options "")(descr ""))
|
|
||||||
(lib (name "OSO-SWD")(type "KiCad")(uri "${KIPRJMOD}/OSO-SWD.pretty")(options "")(descr ""))
|
|
||||||
)
|
|
@ -1,4 +0,0 @@
|
|||||||
(sym_lib_table
|
|
||||||
(lib (name "OSO-SWAT-A1-05-eagle-import")(type "KiCad")(uri "${KIPRJMOD}/OSO-SWAT-A1-05-eagle-import.kicad_sym")(options "")(descr ""))
|
|
||||||
(lib (name "OSO-SWD")(type "KiCad")(uri "${KIPRJMOD}/OSO_SWD.kicad_sym")(options "")(descr ""))
|
|
||||||
)
|
|
11
README.md
11
README.md
@ -74,17 +74,6 @@ python3 -m http.server -d build-sim
|
|||||||
|
|
||||||
Finally, visit [watch.html](http://localhost:8000/watch.html) to see your work.
|
Finally, visit [watch.html](http://localhost:8000/watch.html) to see your work.
|
||||||
|
|
||||||
Hardware Schematics and PCBs
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
| Name | Color | Schematic | Gerbers |
|
|
||||||
| ---- | ----- | --------- | ------- |
|
|
||||||
| Sensorwatch Lite | RED | [PCB/Main Boards/OSO-SWAT-B1](PCB/Main%20Boards/OSO-SWAT-B1) | [OSO-SWAT-B1-03](PCB/Main%20Boards/OSO-SWAT-B1/OSO-SWAT-B1-03.zip) |
|
|
||||||
| Sensorwatch | GREEN | [OSO-SWAT-A1-05](PCB/Main%20Boards/OSO-SWAT-A1/OSO-SWAT-A1-05.sch) (Eagle format) | ? |
|
|
||||||
| Sensorwatch Pro | TBD | TBD | TBD |
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
Different components of the project are licensed differently, see [LICENSE.md](https://github.com/joeycastillo/Sensor-Watch/blob/main/LICENSE.md).
|
Different components of the project are licensed differently, see [LICENSE.md](https://github.com/joeycastillo/Sensor-Watch/blob/main/LICENSE.md).
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "watch.h"
|
#include "watch.h"
|
||||||
#include "watch_utility.h"
|
|
||||||
|
|
||||||
const int8_t UTC_OFFSET = 4; // set to your current UTC offset to see correct beats time
|
const int8_t UTC_OFFSET = 4; // set to your current UTC offset to see correct beats time
|
||||||
const uint8_t BEAT_REFRESH_FREQUENCY = 8;
|
const uint8_t BEAT_REFRESH_FREQUENCY = 8;
|
||||||
@ -204,6 +203,7 @@ void set_time_mode_handle_primary_button(void) {
|
|||||||
|
|
||||||
void set_time_mode_handle_secondary_button(void) {
|
void set_time_mode_handle_secondary_button(void) {
|
||||||
watch_date_time date_time = watch_rtc_get_date_time();
|
watch_date_time date_time = watch_rtc_get_date_time();
|
||||||
|
const uint8_t days_in_month[12] = {31, 28, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31};
|
||||||
|
|
||||||
switch (application_state.page) {
|
switch (application_state.page) {
|
||||||
case 0: // hour
|
case 0: // hour
|
||||||
@ -224,10 +224,13 @@ void set_time_mode_handle_secondary_button(void) {
|
|||||||
break;
|
break;
|
||||||
case 5: // day
|
case 5: // day
|
||||||
date_time.unit.day = date_time.unit.day + 1;
|
date_time.unit.day = date_time.unit.day + 1;
|
||||||
|
// can't set to the 29th on a leap year. if it's february 29, set to 11:59 on the 28th.
|
||||||
|
// and it should roll over.
|
||||||
|
if (date_time.unit.day > days_in_month[date_time.unit.month - 1]) {
|
||||||
|
date_time.unit.day = 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (date_time.unit.day > days_in_month(date_time.unit.month, date_time.unit.year + WATCH_RTC_REFERENCE_YEAR))
|
|
||||||
date_time.unit.day = 1;
|
|
||||||
watch_rtc_set_date_time(date_time);
|
watch_rtc_set_date_time(date_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "watch.h"
|
|
||||||
|
|
||||||
void app_init(void) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_wake_from_backup(void) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_setup(void) {
|
|
||||||
watch_enable_leds();
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_prepare_for_standby(void) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_wake_from_standby(void) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool app_loop(void) {
|
|
||||||
static uint8_t red = 0;
|
|
||||||
static uint8_t green = 0;
|
|
||||||
static uint8_t blue = 255;
|
|
||||||
static uint8_t phase = 0;
|
|
||||||
|
|
||||||
switch (phase) {
|
|
||||||
case 0:
|
|
||||||
red++;
|
|
||||||
if (red == 255) phase = 1;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
green++;
|
|
||||||
if (green == 255) phase = 2;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
red--;
|
|
||||||
if (red == 0) phase = 3;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
blue++;
|
|
||||||
if (blue == 255) phase = 4;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
green--;
|
|
||||||
if (green == 0) phase = 5;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
red++;
|
|
||||||
if (red == 255) phase = 6;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
blue--;
|
|
||||||
if (blue == 0) {
|
|
||||||
phase = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
watch_set_led_color_rgb(red, green, blue);
|
|
||||||
delay_ms(2);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
TOP = ../../..
|
|
||||||
include $(TOP)/make.mk
|
|
||||||
|
|
||||||
INCLUDES += \
|
|
||||||
-I../
|
|
||||||
|
|
||||||
SRCS += \
|
|
||||||
../app.c
|
|
||||||
|
|
||||||
include $(TOP)/rules.mk
|
|
@ -1,420 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "watch.h"
|
|
||||||
#include "spiflash.h"
|
|
||||||
|
|
||||||
bool has_ticked = false;
|
|
||||||
extern struct io_descriptor *uart_io;
|
|
||||||
|
|
||||||
// array of lcd pins from pins.h
|
|
||||||
const uint8_t lcd_pins[] = {
|
|
||||||
SLCD26, // SEG23
|
|
||||||
SLCD25, // SEG22
|
|
||||||
SLCD24, // SEG21
|
|
||||||
SLCD23, // SEG20
|
|
||||||
SLCD22, // SEG19
|
|
||||||
SLCD21, // SEG18
|
|
||||||
SLCD20, // SEG17
|
|
||||||
SLCD19, // SEG16
|
|
||||||
SLCD18, // SEG15
|
|
||||||
SLCD17, // SEG14
|
|
||||||
SLCD16, // SEG13
|
|
||||||
SLCD15, // SEG12
|
|
||||||
SLCD14, // SEG11
|
|
||||||
SLCD13, // SEG10
|
|
||||||
SLCD12, // SEG9
|
|
||||||
SLCD11, // SEG8
|
|
||||||
SLCD10, // SEG7
|
|
||||||
SLCD9, // SEG6
|
|
||||||
SLCD8, // SEG5
|
|
||||||
SLCD7, // SEG4
|
|
||||||
SLCD6, // SEG3
|
|
||||||
SLCD5, // SEG2
|
|
||||||
SLCD4, // SEG1
|
|
||||||
SLCD3, // SEG0
|
|
||||||
SLCD2, // COM2
|
|
||||||
SLCD1, // COM1
|
|
||||||
SLCD0, // COM0
|
|
||||||
};
|
|
||||||
|
|
||||||
void cb_tick(void);
|
|
||||||
void cb_tick(void) {
|
|
||||||
has_ticked = true;
|
|
||||||
watch_rtc_disable_periodic_callback(8);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pass_if(bool passed);
|
|
||||||
void pass_if(bool passed) {
|
|
||||||
if (passed) {
|
|
||||||
watch_set_led_green();
|
|
||||||
delay_ms(100);
|
|
||||||
watch_set_led_off();
|
|
||||||
} else {
|
|
||||||
watch_set_led_red();
|
|
||||||
delay_ms(100);
|
|
||||||
watch_set_led_off();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_init(void) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_wake_from_backup(void) {
|
|
||||||
}
|
|
||||||
|
|
||||||
static void enable_irda_uart() {
|
|
||||||
gpio_set_pin_direction(IR_ENABLE, GPIO_DIRECTION_OUT);
|
|
||||||
gpio_set_pin_level(IR_ENABLE, false);
|
|
||||||
|
|
||||||
SERCOM_USART_CTRLA_Type ctrla;
|
|
||||||
SERCOM_USART_CTRLB_Type ctrlb;
|
|
||||||
ctrla.reg = SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_MODE(1);
|
|
||||||
ctrlb.reg = SERCOM_USART_CTRLB_CHSIZE(0) | SERCOM_USART_CTRLB_ENC;
|
|
||||||
|
|
||||||
MCLK->APBCMASK.reg |= MCLK_APBCMASK_SERCOM0;
|
|
||||||
GCLK->PCHCTRL[SERCOM0_GCLK_ID_CORE].reg = GCLK_PCHCTRL_GEN(0) | GCLK_PCHCTRL_CHEN;
|
|
||||||
|
|
||||||
while (0 == (GCLK->PCHCTRL[SERCOM0_GCLK_ID_CORE].reg & GCLK_PCHCTRL_CHEN));
|
|
||||||
|
|
||||||
usart_sync_init(&USART_0, SERCOM0, (void *)NULL);
|
|
||||||
|
|
||||||
SERCOM0->USART.CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE;
|
|
||||||
|
|
||||||
gpio_set_pin_direction(IRSENSE, GPIO_DIRECTION_IN);
|
|
||||||
gpio_set_pin_function(IRSENSE, PINMUX_PA04D_SERCOM0_PAD0);
|
|
||||||
ctrla.reg |= SERCOM_USART_CTRLA_RXPO(0);
|
|
||||||
ctrlb.reg |= SERCOM_USART_CTRLB_RXEN;
|
|
||||||
|
|
||||||
SERCOM0->USART.CTRLA.reg = ctrla.reg;
|
|
||||||
SERCOM0->USART.CTRLB.reg = ctrlb.reg;
|
|
||||||
|
|
||||||
if (hri_usbdevice_get_CTRLA_ENABLE_bit(USB)) {
|
|
||||||
uint64_t br = 65536 - ((65536 * 16.0f * 600) / 8000000);
|
|
||||||
SERCOM0->USART.BAUD.reg = (uint16_t)br;
|
|
||||||
} else {
|
|
||||||
uint64_t br = 65536 - ((65536 * 16.0f * 600) / 4000000);
|
|
||||||
SERCOM0->USART.BAUD.reg = (uint16_t)br;
|
|
||||||
}
|
|
||||||
|
|
||||||
SERCOM0->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;
|
|
||||||
|
|
||||||
usart_sync_enable(&USART_0);
|
|
||||||
usart_sync_get_io_descriptor(&USART_0, &uart_io);
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_setup(void) {
|
|
||||||
// Set up tick for RTC test
|
|
||||||
watch_rtc_register_periodic_callback(cb_tick, 8);
|
|
||||||
|
|
||||||
// Set up UART for communication with tester
|
|
||||||
enable_irda_uart();
|
|
||||||
|
|
||||||
// Set up LED pins
|
|
||||||
watch_enable_leds();
|
|
||||||
watch_enable_buzzer();
|
|
||||||
|
|
||||||
// Set up buttons with pull-down resistors
|
|
||||||
gpio_set_pin_direction(BTN_ALARM, GPIO_DIRECTION_IN);
|
|
||||||
gpio_set_pin_pull_mode(BTN_ALARM, GPIO_PULL_DOWN);
|
|
||||||
gpio_set_pin_direction(BTN_LIGHT, GPIO_DIRECTION_IN);
|
|
||||||
gpio_set_pin_pull_mode(BTN_LIGHT, GPIO_PULL_DOWN);
|
|
||||||
gpio_set_pin_direction(BTN_MODE, GPIO_DIRECTION_IN);
|
|
||||||
gpio_set_pin_pull_mode(BTN_MODE, GPIO_PULL_DOWN);
|
|
||||||
|
|
||||||
// Set up ADC for thermistor and light sensor tests
|
|
||||||
watch_enable_adc();
|
|
||||||
watch_enable_analog_input(TEMPSENSE);
|
|
||||||
// Pin A0 is the thermistor enable pin
|
|
||||||
gpio_set_pin_direction(TS_ENABLE, GPIO_DIRECTION_OUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_prepare_for_standby(void) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_wake_from_standby(void) {
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool test_i2c(void) {
|
|
||||||
watch_enable_i2c();
|
|
||||||
uint16_t device_id = watch_i2c_read8(0x48, 0x0F);
|
|
||||||
printf("%d\n", device_id);
|
|
||||||
|
|
||||||
return device_id == 0x75;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool test_spi(void) {
|
|
||||||
gpio_set_pin_level(A3, true);
|
|
||||||
gpio_set_pin_direction(A3, GPIO_DIRECTION_OUT);
|
|
||||||
watch_enable_spi();
|
|
||||||
delay_ms(10);
|
|
||||||
|
|
||||||
watch_set_pin_level(A3, false);
|
|
||||||
delay_ms(10);
|
|
||||||
uint8_t read_status_response[3] = {0};
|
|
||||||
bool ok = spi_flash_read_command(0x9F, read_status_response, 3);
|
|
||||||
watch_set_pin_level(A3, true);
|
|
||||||
printf("%d %d %d\n", read_status_response[0], read_status_response[1], read_status_response[2]);
|
|
||||||
|
|
||||||
return (read_status_response[0] == 0xC8 && read_status_response[1] == 0x40 && read_status_response[2] == 0x13);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool app_loop(void) {
|
|
||||||
uint8_t buf[5] = {0};
|
|
||||||
watch_storage_read(10, 0, buf, 4);
|
|
||||||
printf("%s\n", (const char *)buf);
|
|
||||||
|
|
||||||
if (strcmp((const char *)buf, "BEEP") == 0) {
|
|
||||||
watch_set_led_yellow();
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_C5, 150);
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_REST, 25);
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_E5, 150);
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_REST, 25);
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_G5, 150);
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_REST, 25);
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_C6, 150);
|
|
||||||
|
|
||||||
watch_storage_erase(10);
|
|
||||||
delay_ms(10);
|
|
||||||
watch_storage_write(10, 0, (const char *)"9PIN", 4);
|
|
||||||
watch_storage_sync();
|
|
||||||
watch_storage_read(10, 0, buf, 4);
|
|
||||||
delay_ms(10);
|
|
||||||
if(strcmp((const char *)buf, (const char *)"9PIN") == 0) {
|
|
||||||
watch_set_led_off();
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp((const char *)buf, "9PIN") == 0) {
|
|
||||||
bool i2c_passed = test_i2c();
|
|
||||||
bool spi_passed = test_spi();
|
|
||||||
|
|
||||||
if (i2c_passed && spi_passed) {
|
|
||||||
watch_storage_erase(10);
|
|
||||||
delay_ms(10);
|
|
||||||
watch_storage_write(10, 0, (const char *)"PASS", 4);
|
|
||||||
watch_storage_sync();
|
|
||||||
watch_storage_read(10, 0, buf, 4);
|
|
||||||
delay_ms(10);
|
|
||||||
|
|
||||||
if(strcmp((const char *)buf, (const char *)"PASS") == 0) {
|
|
||||||
gpio_set_pin_direction(A0, GPIO_DIRECTION_OUT);
|
|
||||||
gpio_set_pin_level(A0, true);
|
|
||||||
}
|
|
||||||
} else if (i2c_passed) {
|
|
||||||
// SPI failed, RED indicator
|
|
||||||
watch_set_led_color_rgb(128, 0, 0);
|
|
||||||
} else if (spi_passed) {
|
|
||||||
// I2C failed, BLUE indicator
|
|
||||||
watch_set_led_color_rgb(0, 0, 128);
|
|
||||||
} else {
|
|
||||||
// both failed, PURPLE indicator
|
|
||||||
watch_set_led_color_rgb(64, 0, 128);
|
|
||||||
}
|
|
||||||
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strcmp((const char *)buf, (const char *)"PASS") == 0) {
|
|
||||||
watch_set_led_green();
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
char char_received = watch_uart_getc();
|
|
||||||
|
|
||||||
if (char_received) {
|
|
||||||
switch (char_received) {
|
|
||||||
// - [X] RTC
|
|
||||||
case 'R':
|
|
||||||
pass_if(has_ticked);
|
|
||||||
break;
|
|
||||||
// - [X] LCD pin continuity
|
|
||||||
case 'O':
|
|
||||||
// Set all LCD pins high
|
|
||||||
for (int i = 0; i < 27; i++) {
|
|
||||||
gpio_set_pin_function(lcd_pins[i], GPIO_PIN_FUNCTION_OFF);
|
|
||||||
gpio_set_pin_direction(lcd_pins[i], GPIO_DIRECTION_OUT);
|
|
||||||
gpio_set_pin_level(lcd_pins[i], true);
|
|
||||||
}
|
|
||||||
// It is the tester's responsibility to check that the pins are high
|
|
||||||
break;
|
|
||||||
case 'P':
|
|
||||||
// Set all LCD pins low
|
|
||||||
for (int i = 0; i < 27; i++) {
|
|
||||||
gpio_set_pin_function(lcd_pins[i], GPIO_PIN_FUNCTION_OFF);
|
|
||||||
gpio_set_pin_direction(lcd_pins[i], GPIO_DIRECTION_OUT);
|
|
||||||
gpio_set_pin_level(lcd_pins[i], false);
|
|
||||||
}
|
|
||||||
// It is the tester's responsibility to check that the pins are low
|
|
||||||
break;
|
|
||||||
// - [X] LCD pin bridging
|
|
||||||
case 'Q':
|
|
||||||
{
|
|
||||||
bool passed = true;
|
|
||||||
// Pull all LCD pins up
|
|
||||||
for (int i = 0; i < 27; i++) {
|
|
||||||
gpio_set_pin_function(lcd_pins[i], GPIO_PIN_FUNCTION_OFF);
|
|
||||||
gpio_set_pin_direction(lcd_pins[i], GPIO_DIRECTION_IN);
|
|
||||||
gpio_set_pin_pull_mode(lcd_pins[i], GPIO_PULL_UP);
|
|
||||||
}
|
|
||||||
// SEG23 is adjacent to the green LED.
|
|
||||||
// setting the LED green drives GREEN low.
|
|
||||||
watch_set_led_green();
|
|
||||||
if (!gpio_get_pin_level(SLCD26)) {
|
|
||||||
// If SEG23 is low, then it must be bridged to the green pin
|
|
||||||
pass_if(false);
|
|
||||||
}
|
|
||||||
// SEG13 is adjacent to the blue LED.
|
|
||||||
// setting the LED blue drives BLUE low.
|
|
||||||
watch_set_led_color_rgb(0, 0, 255);
|
|
||||||
if (!gpio_get_pin_level(SLCD16)) {
|
|
||||||
// If SEG13 is low, then it must be bridged to the blue pin
|
|
||||||
pass_if(false);
|
|
||||||
}
|
|
||||||
// SEG12 is adjacent to the red LED.
|
|
||||||
// setting the LED red drives RED low.
|
|
||||||
watch_set_led_red();
|
|
||||||
if (!gpio_get_pin_level(SLCD15)) {
|
|
||||||
// If SEG12 is low, then it must be bridged to the red pin
|
|
||||||
pass_if(false);
|
|
||||||
}
|
|
||||||
watch_set_led_off();
|
|
||||||
// After this, all LCD pins are adjacent. Test if each pin is bridged to the previous one.
|
|
||||||
for (int i = 1; i < 27; i++) {
|
|
||||||
gpio_set_pin_direction(lcd_pins[i - 1], GPIO_DIRECTION_OUT);
|
|
||||||
gpio_set_pin_level(lcd_pins[i - 1], false);
|
|
||||||
if (!gpio_get_pin_level(lcd_pins[i])) {
|
|
||||||
passed = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gpio_set_pin_direction(lcd_pins[i - 1], GPIO_DIRECTION_IN);
|
|
||||||
gpio_set_pin_pull_mode(lcd_pins[i - 1], GPIO_PULL_UP);
|
|
||||||
}
|
|
||||||
// Special cases:
|
|
||||||
// SLCD0 neighbors VCC
|
|
||||||
gpio_set_pin_direction(SLCD0, GPIO_DIRECTION_IN);
|
|
||||||
gpio_set_pin_pull_mode(SLCD0, GPIO_PULL_DOWN);
|
|
||||||
if (gpio_get_pin_level(SLCD0)) {
|
|
||||||
passed = false;
|
|
||||||
}
|
|
||||||
// SLCD18 neighbors VCC
|
|
||||||
gpio_set_pin_direction(SLCD18, GPIO_DIRECTION_IN);
|
|
||||||
gpio_set_pin_pull_mode(SLCD18, GPIO_PULL_DOWN);
|
|
||||||
if (gpio_get_pin_level(SLCD18)) {
|
|
||||||
passed = false;
|
|
||||||
}
|
|
||||||
// SLCD26 neighbors USB_N
|
|
||||||
gpio_set_pin_direction(GPIO(GPIO_PORTA, 24), GPIO_DIRECTION_OUT);
|
|
||||||
gpio_set_pin_level(GPIO(GPIO_PORTA, 24), true);
|
|
||||||
gpio_set_pin_direction(SLCD26, GPIO_DIRECTION_IN);
|
|
||||||
gpio_set_pin_pull_mode(SLCD26, GPIO_PULL_DOWN);
|
|
||||||
// if SLCD26 is high, then it is bridged to USB_N
|
|
||||||
if (gpio_get_pin_level(SLCD26)) {
|
|
||||||
passed = false;
|
|
||||||
}
|
|
||||||
// SLCD11 neighbors VLCD
|
|
||||||
watch_enable_display();
|
|
||||||
delay_ms(50);
|
|
||||||
gpio_set_pin_function(SLCD11, GPIO_PIN_FUNCTION_OFF);
|
|
||||||
gpio_set_pin_direction(SLCD11, GPIO_DIRECTION_IN);
|
|
||||||
gpio_set_pin_pull_mode(SLCD11, GPIO_PULL_DOWN);
|
|
||||||
if (gpio_get_pin_level(SLCD11)) {
|
|
||||||
passed = false;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 27; i++) {
|
|
||||||
gpio_set_pin_function(lcd_pins[i], GPIO_PIN_FUNCTION_OFF);
|
|
||||||
gpio_set_pin_direction(lcd_pins[i], GPIO_DIRECTION_IN);
|
|
||||||
gpio_set_pin_pull_mode(lcd_pins[i], GPIO_PULL_OFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
pass_if(passed);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// - [X] Thermistor high
|
|
||||||
case 'U':
|
|
||||||
// Set TS_ENABLE high and read the value of TEMPSENSE via the ADC.
|
|
||||||
// Pass if the value is near VCC.
|
|
||||||
gpio_set_pin_level(TS_ENABLE, true);
|
|
||||||
pass_if(watch_get_analog_pin_level(TEMPSENSE) > 65000);
|
|
||||||
break;
|
|
||||||
// - [X] Thermistor low
|
|
||||||
case 'T':
|
|
||||||
{
|
|
||||||
// Set TS_ENABLE low and read the value of TEMPSENSE via the ADC.
|
|
||||||
// Pass if the value is within the realm of reasonable temperatures.
|
|
||||||
// 15000 is a few minutes in the freezer, 45000 is holding it a few feet above a stovetop
|
|
||||||
gpio_set_pin_level(TS_ENABLE, false);
|
|
||||||
uint16_t value = watch_get_analog_pin_level(TEMPSENSE);
|
|
||||||
pass_if(value < 45000 && value > 15000);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// - [X] VLCD low
|
|
||||||
case 'V':
|
|
||||||
watch_enable_display();
|
|
||||||
SLCD->CTRLA.bit.ENABLE = 0;
|
|
||||||
while(SLCD->SYNCBUSY.bit.ENABLE);
|
|
||||||
SLCD->CTRLC.bit.CTST = 0x0;
|
|
||||||
SLCD->CTRLA.bit.ENABLE = 1;
|
|
||||||
while(SLCD->SYNCBUSY.bit.ENABLE);
|
|
||||||
break;
|
|
||||||
// - [X] VLCD high
|
|
||||||
case 'W':
|
|
||||||
watch_enable_display();
|
|
||||||
SLCD->CTRLA.bit.ENABLE = 0;
|
|
||||||
while(SLCD->SYNCBUSY.bit.ENABLE);
|
|
||||||
SLCD->CTRLC.bit.CTST = 0xD;
|
|
||||||
SLCD->CTRLA.bit.ENABLE = 1;
|
|
||||||
while(SLCD->SYNCBUSY.bit.ENABLE);
|
|
||||||
break;
|
|
||||||
/// TODO: LED
|
|
||||||
case 'r':
|
|
||||||
watch_set_led_color_rgb(255, 0, 0);
|
|
||||||
delay_ms(100);
|
|
||||||
watch_set_led_color_rgb(0, 0, 0);
|
|
||||||
// It is the tester's responsibility to check the LED color.
|
|
||||||
break;
|
|
||||||
case 'g':
|
|
||||||
watch_set_led_color_rgb(0, 255, 0);
|
|
||||||
delay_ms(100);
|
|
||||||
watch_set_led_color_rgb(0, 0, 0);
|
|
||||||
// It is the tester's responsibility to check the LED color.
|
|
||||||
break;
|
|
||||||
case 'b':
|
|
||||||
watch_set_led_color_rgb(0, 0, 255);
|
|
||||||
delay_ms(100);
|
|
||||||
watch_set_led_color_rgb(0, 0, 0);
|
|
||||||
// It is the tester's responsibility to check the LED color.
|
|
||||||
break;
|
|
||||||
// - [X] Buttons
|
|
||||||
case 'B':
|
|
||||||
// Pass if all three buttons are low
|
|
||||||
pass_if(!gpio_get_pin_level(BTN_ALARM) && !gpio_get_pin_level(BTN_LIGHT) && !gpio_get_pin_level(BTN_MODE));
|
|
||||||
break;
|
|
||||||
case 'L':
|
|
||||||
// pass if BTN_LIGHT is high and the other two are low
|
|
||||||
pass_if(gpio_get_pin_level(BTN_LIGHT) && !gpio_get_pin_level(BTN_ALARM) && !gpio_get_pin_level(BTN_MODE));
|
|
||||||
break;
|
|
||||||
case 'A':
|
|
||||||
// pass if BTN_ALARM is high and the other two are low
|
|
||||||
pass_if(gpio_get_pin_level(BTN_ALARM) && !gpio_get_pin_level(BTN_LIGHT) && !gpio_get_pin_level(BTN_MODE));
|
|
||||||
break;
|
|
||||||
case 'M':
|
|
||||||
// pass if BTN_MODE is high and the other two are low
|
|
||||||
pass_if(gpio_get_pin_level(BTN_MODE) && !gpio_get_pin_level(BTN_ALARM) && !gpio_get_pin_level(BTN_LIGHT));
|
|
||||||
break;
|
|
||||||
|
|
||||||
// - [X] File system
|
|
||||||
case 'F':
|
|
||||||
watch_storage_erase(10);
|
|
||||||
delay_ms(10);
|
|
||||||
watch_storage_write(10, 0, (const char *)"BEEP", 4);
|
|
||||||
watch_storage_sync();
|
|
||||||
watch_storage_read(10, 0, buf, 4);
|
|
||||||
delay_ms(10);
|
|
||||||
// No need to do anything here; comparison with 'beep' happens at next loop invocation.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
TOP = ../../..
|
|
||||||
include $(TOP)/make.mk
|
|
||||||
|
|
||||||
INCLUDES += \
|
|
||||||
-I../
|
|
||||||
|
|
||||||
SRCS += \
|
|
||||||
../app.c
|
|
||||||
|
|
||||||
include $(TOP)/rules.mk
|
|
@ -120,8 +120,4 @@
|
|||||||
#define D0 GPIO(GPIO_PORTB, 3)
|
#define D0 GPIO(GPIO_PORTB, 3)
|
||||||
#define D1 GPIO(GPIO_PORTB, 0)
|
#define D1 GPIO(GPIO_PORTB, 0)
|
||||||
|
|
||||||
// interrupt mapping
|
|
||||||
#define EXT_IRQ_AMOUNT 6
|
|
||||||
#define CONFIG_EIC_EXTINT_MAP {0, PIN_PB00}, {1, PIN_PB01}, {2, PIN_PA02}, {3, PIN_PB03}, {5, PIN_PB05}, {7, PIN_PA07},
|
|
||||||
|
|
||||||
#endif // PINS_H_INCLUDED
|
#endif // PINS_H_INCLUDED
|
||||||
|
@ -81,8 +81,4 @@
|
|||||||
#define D0 GPIO(GPIO_PORTB, 3)
|
#define D0 GPIO(GPIO_PORTB, 3)
|
||||||
#define D1 GPIO(GPIO_PORTB, 0)
|
#define D1 GPIO(GPIO_PORTB, 0)
|
||||||
|
|
||||||
// interrupt mapping
|
|
||||||
#define EXT_IRQ_AMOUNT 6
|
|
||||||
#define CONFIG_EIC_EXTINT_MAP {0, PIN_PB00}, {1, PIN_PB01}, {2, PIN_PA02}, {3, PIN_PB03}, {6, PIN_PA22}, {7, PIN_PA23},
|
|
||||||
|
|
||||||
#endif // PINS_H_INCLUDED
|
#endif // PINS_H_INCLUDED
|
||||||
|
@ -81,8 +81,4 @@
|
|||||||
#define D0 GPIO(GPIO_PORTB, 3)
|
#define D0 GPIO(GPIO_PORTB, 3)
|
||||||
#define D1 GPIO(GPIO_PORTB, 0)
|
#define D1 GPIO(GPIO_PORTB, 0)
|
||||||
|
|
||||||
// interrupt mapping
|
|
||||||
#define EXT_IRQ_AMOUNT 6
|
|
||||||
#define CONFIG_EIC_EXTINT_MAP {0, PIN_PB00}, {1, PIN_PB01}, {2, PIN_PA02}, {3, PIN_PB03}, {6, PIN_PA22}, {7, PIN_PA23},
|
|
||||||
|
|
||||||
#endif // PINS_H_INCLUDED
|
#endif // PINS_H_INCLUDED
|
||||||
|
@ -81,8 +81,4 @@
|
|||||||
#define D0 GPIO(GPIO_PORTB, 3)
|
#define D0 GPIO(GPIO_PORTB, 3)
|
||||||
#define D1 GPIO(GPIO_PORTB, 0)
|
#define D1 GPIO(GPIO_PORTB, 0)
|
||||||
|
|
||||||
// interrupt mapping
|
|
||||||
#define EXT_IRQ_AMOUNT 6
|
|
||||||
#define CONFIG_EIC_EXTINT_MAP {0, PIN_PB00}, {1, PIN_PB01}, {2, PIN_PA02}, {3, PIN_PB03}, {6, PIN_PA22}, {7, PIN_PA23},
|
|
||||||
|
|
||||||
#endif // PINS_H_INCLUDED
|
#endif // PINS_H_INCLUDED
|
||||||
|
@ -1,130 +0,0 @@
|
|||||||
#ifndef PINS_H_INCLUDED
|
|
||||||
#define PINS_H_INCLUDED
|
|
||||||
|
|
||||||
// Detects if we are on USB power.
|
|
||||||
#define VBUS_DET GPIO(GPIO_PORTB, 5)
|
|
||||||
|
|
||||||
// Buttons
|
|
||||||
#define BTN_ALARM GPIO(GPIO_PORTA, 2)
|
|
||||||
#define WATCH_BTN_ALARM_EIC_CHANNEL 2
|
|
||||||
#define BTN_LIGHT GPIO(GPIO_PORTA, 30)
|
|
||||||
#define WATCH_BTN_LIGHT_EIC_CHANNEL 10
|
|
||||||
#define BTN_MODE GPIO(GPIO_PORTA, 31)
|
|
||||||
#define WATCH_BTN_MODE_EIC_CHANNEL 11
|
|
||||||
|
|
||||||
// Temperature Sensor
|
|
||||||
#define TS_ENABLE GPIO(GPIO_PORTB, 23)
|
|
||||||
#define TEMPSENSE GPIO(GPIO_PORTA, 3)
|
|
||||||
|
|
||||||
// Light Sensor
|
|
||||||
#define IR_ENABLE GPIO(GPIO_PORTB, 22)
|
|
||||||
#define IRSENSE GPIO(GPIO_PORTA, 4)
|
|
||||||
|
|
||||||
// Buzzer
|
|
||||||
#define BUZZER GPIO(GPIO_PORTA, 27)
|
|
||||||
#define WATCH_BUZZER_TCC_PINMUX PINMUX_PA27F_TCC0_WO5
|
|
||||||
#define WATCH_BUZZER_TCC_CHANNEL 1
|
|
||||||
|
|
||||||
// LEDs
|
|
||||||
#define WATCH_INVERT_LED_POLARITY
|
|
||||||
|
|
||||||
#define RED GPIO(GPIO_PORTA, 12)
|
|
||||||
#define WATCH_RED_TCC_CHANNEL 2
|
|
||||||
#define WATCH_RED_TCC_PINMUX PINMUX_PA12F_TCC0_WO6
|
|
||||||
|
|
||||||
#define BLUE GPIO(GPIO_PORTA, 13)
|
|
||||||
#define WATCH_BLUE_TCC_CHANNEL 3
|
|
||||||
#define WATCH_BLUE_TCC_PINMUX PINMUX_PA13F_TCC0_WO7
|
|
||||||
|
|
||||||
#define GREEN GPIO(GPIO_PORTA, 22)
|
|
||||||
#define WATCH_GREEN_TCC_CHANNEL 0
|
|
||||||
#define WATCH_GREEN_TCC_PINMUX PINMUX_PA22F_TCC0_WO4
|
|
||||||
|
|
||||||
// Segment LCD
|
|
||||||
#define SLCD0 GPIO(GPIO_PORTB, 6)
|
|
||||||
#define SLCD1 GPIO(GPIO_PORTB, 7)
|
|
||||||
#define SLCD2 GPIO(GPIO_PORTB, 8)
|
|
||||||
#define SLCD3 GPIO(GPIO_PORTB, 9)
|
|
||||||
#define SLCD4 GPIO(GPIO_PORTA, 5)
|
|
||||||
#define SLCD5 GPIO(GPIO_PORTA, 6)
|
|
||||||
#define SLCD6 GPIO(GPIO_PORTA, 7)
|
|
||||||
#define SLCD7 GPIO(GPIO_PORTA, 8)
|
|
||||||
#define SLCD8 GPIO(GPIO_PORTA, 9)
|
|
||||||
#define SLCD9 GPIO(GPIO_PORTA, 10)
|
|
||||||
#define SLCD10 GPIO(GPIO_PORTA, 11)
|
|
||||||
#define SLCD11 GPIO(GPIO_PORTB, 11)
|
|
||||||
#define SLCD12 GPIO(GPIO_PORTB, 12)
|
|
||||||
#define SLCD13 GPIO(GPIO_PORTB, 13)
|
|
||||||
#define SLCD14 GPIO(GPIO_PORTB, 14)
|
|
||||||
#define SLCD15 GPIO(GPIO_PORTB, 15)
|
|
||||||
#define SLCD16 GPIO(GPIO_PORTA, 14)
|
|
||||||
#define SLCD17 GPIO(GPIO_PORTA, 15)
|
|
||||||
#define SLCD18 GPIO(GPIO_PORTA, 16)
|
|
||||||
#define SLCD19 GPIO(GPIO_PORTA, 17)
|
|
||||||
#define SLCD20 GPIO(GPIO_PORTA, 18)
|
|
||||||
#define SLCD21 GPIO(GPIO_PORTA, 19)
|
|
||||||
#define SLCD22 GPIO(GPIO_PORTB, 16)
|
|
||||||
#define SLCD23 GPIO(GPIO_PORTB, 17)
|
|
||||||
#define SLCD24 GPIO(GPIO_PORTA, 20)
|
|
||||||
#define SLCD25 GPIO(GPIO_PORTA, 21)
|
|
||||||
#define SLCD26 GPIO(GPIO_PORTA, 23)
|
|
||||||
// This board uses a slightly different pin mapping from the standard watch, and it's not enough to
|
|
||||||
// just declare the pins. We also have to set the LCD Pin Enable register with the SLCD pins we're
|
|
||||||
// using. These numbers are not port/pin numbers, but the "SLCD/LP[x]" numbers in the pinmux table.
|
|
||||||
// If not defined in pins.h, the LCD driver will fall back to the pin mapping in hpl_slcd_config.h.
|
|
||||||
// LPENL is for pins SLCD/LP[0..31].
|
|
||||||
#define CONF_SLCD_LPENL (\
|
|
||||||
(uint32_t)1 << 0 | \
|
|
||||||
(uint32_t)1 << 1 | \
|
|
||||||
(uint32_t)1 << 2 | \
|
|
||||||
(uint32_t)1 << 3 | \
|
|
||||||
(uint32_t)1 << 5 | \
|
|
||||||
(uint32_t)1 << 6 | \
|
|
||||||
(uint32_t)1 << 7 | \
|
|
||||||
(uint32_t)1 << 11 | \
|
|
||||||
(uint32_t)1 << 12 | \
|
|
||||||
(uint32_t)1 << 13 | \
|
|
||||||
(uint32_t)1 << 14 | \
|
|
||||||
(uint32_t)1 << 21 | \
|
|
||||||
(uint32_t)1 << 22 | \
|
|
||||||
(uint32_t)1 << 23 | \
|
|
||||||
(uint32_t)1 << 24 | \
|
|
||||||
(uint32_t)1 << 25 | \
|
|
||||||
(uint32_t)1 << 30 | \
|
|
||||||
(uint32_t)1 << 31 | 0)
|
|
||||||
// LPENH is for pins SLCD/LP[32..51], where bit 0 represents pin 32.
|
|
||||||
#define CONF_SLCD_LPENH (\
|
|
||||||
(uint32_t)1 << (32 - 32) | \
|
|
||||||
(uint32_t)1 << (33 - 32) | \
|
|
||||||
(uint32_t)1 << (34 - 32) | \
|
|
||||||
(uint32_t)1 << (35 - 32) | \
|
|
||||||
(uint32_t)1 << (42 - 32) | \
|
|
||||||
(uint32_t)1 << (43 - 32) | \
|
|
||||||
(uint32_t)1 << (48 - 32) | \
|
|
||||||
(uint32_t)1 << (49 - 32) | \
|
|
||||||
(uint32_t)1 << (51 - 32) | 0)
|
|
||||||
|
|
||||||
|
|
||||||
// 9-pin connector
|
|
||||||
#define A0 GPIO(GPIO_PORTB, 4)
|
|
||||||
#define WATCH_A0_EIC_CHANNEL 4
|
|
||||||
#define A1 GPIO(GPIO_PORTB, 1)
|
|
||||||
#define WATCH_A1_EIC_CHANNEL 1
|
|
||||||
#define A2 GPIO(GPIO_PORTB, 2)
|
|
||||||
#define WATCH_A2_EIC_CHANNEL 2
|
|
||||||
#define A3 GPIO(GPIO_PORTB, 3)
|
|
||||||
#define WATCH_A3_EIC_CHANNEL 3
|
|
||||||
#define A4 GPIO(GPIO_PORTB, 0)
|
|
||||||
#define WATCH_A4_EIC_CHANNEL 0
|
|
||||||
#define SDA GPIO(GPIO_PORTB, 30)
|
|
||||||
#define SCL GPIO(GPIO_PORTB, 31)
|
|
||||||
|
|
||||||
// aliases for as A3/A4; these were mentioned as D0/D1 in early documentation.
|
|
||||||
#define D0 GPIO(GPIO_PORTB, 3)
|
|
||||||
#define D1 GPIO(GPIO_PORTB, 0)
|
|
||||||
|
|
||||||
// interrupt mapping
|
|
||||||
#define EXT_IRQ_AMOUNT 6
|
|
||||||
#define CONFIG_EIC_EXTINT_MAP {0, PIN_PB00}, {1, PIN_PB01}, {2, PIN_PA02}, {3, PIN_PB03}, {10, PIN_PA30}, {11, PIN_PA31},
|
|
||||||
|
|
||||||
#endif // PINS_H_INCLUDED
|
|
22
make.mk
22
make.mk
@ -6,19 +6,7 @@ BUILD = ./build-sim
|
|||||||
endif
|
endif
|
||||||
BIN = watch
|
BIN = watch
|
||||||
|
|
||||||
ifndef COLOR
|
ifndef BOARD
|
||||||
$(error Set the COLOR variable to RED, BLUE, GREEN or PRO depending on what board you have.)
|
|
||||||
endif
|
|
||||||
|
|
||||||
COLOR_VALID := $(filter $(COLOR),RED BLUE GREEN PRO)
|
|
||||||
|
|
||||||
ifeq ($(COLOR_VALID),)
|
|
||||||
$(error COLOR must be RED, BLUE, GREEN or PRO)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(COLOR), PRO)
|
|
||||||
override BOARD = OSO-SWAT-C1-00
|
|
||||||
else
|
|
||||||
override BOARD = OSO-SWAT-A1-05
|
override BOARD = OSO-SWAT-A1-05
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -166,6 +154,7 @@ SRCS += \
|
|||||||
$(TOP)/watch-library/shared/driver/lis2dw.c \
|
$(TOP)/watch-library/shared/driver/lis2dw.c \
|
||||||
$(TOP)/watch-library/shared/driver/opt3001.c \
|
$(TOP)/watch-library/shared/driver/opt3001.c \
|
||||||
$(TOP)/watch-library/shared/driver/spiflash.c \
|
$(TOP)/watch-library/shared/driver/spiflash.c \
|
||||||
|
$(TOP)/watch-library/shared/watch/watch_private_buzzer.c \
|
||||||
$(TOP)/watch-library/shared/watch/watch_private_display.c \
|
$(TOP)/watch-library/shared/watch/watch_private_display.c \
|
||||||
$(TOP)/watch-library/shared/watch/watch_utility.c \
|
$(TOP)/watch-library/shared/watch/watch_utility.c \
|
||||||
|
|
||||||
@ -210,6 +199,7 @@ SRCS += \
|
|||||||
$(TOP)/watch-library/simulator/watch/watch.c \
|
$(TOP)/watch-library/simulator/watch/watch.c \
|
||||||
$(TOP)/watch-library/shared/driver/thermistor_driver.c \
|
$(TOP)/watch-library/shared/driver/thermistor_driver.c \
|
||||||
$(TOP)/watch-library/shared/driver/opt3001.c \
|
$(TOP)/watch-library/shared/driver/opt3001.c \
|
||||||
|
$(TOP)/watch-library/shared/watch/watch_private_buzzer.c \
|
||||||
$(TOP)/watch-library/shared/watch/watch_private_display.c \
|
$(TOP)/watch-library/shared/watch/watch_private_display.c \
|
||||||
$(TOP)/watch-library/shared/watch/watch_utility.c \
|
$(TOP)/watch-library/shared/watch/watch_utility.c \
|
||||||
|
|
||||||
@ -223,12 +213,6 @@ ifndef COLOR
|
|||||||
$(error Set the COLOR variable to RED, BLUE, or GREEN depending on what board you have.)
|
$(error Set the COLOR variable to RED, BLUE, or GREEN depending on what board you have.)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
COLOR_VALID := $(filter $(COLOR),RED BLUE GREEN PRO)
|
|
||||||
|
|
||||||
ifeq ($(COLOR_VALID),)
|
|
||||||
$(error COLOR must be RED, BLUE, or GREEN)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(COLOR), BLUE)
|
ifeq ($(COLOR), BLUE)
|
||||||
CFLAGS += -DWATCH_IS_BLUE_BOARD
|
CFLAGS += -DWATCH_IS_BLUE_BOARD
|
||||||
endif
|
endif
|
||||||
|
@ -120,29 +120,13 @@ bool filesystem_init(void) {
|
|||||||
printf("Ignore that error! Formatting filesystem...\r\n");
|
printf("Ignore that error! Formatting filesystem...\r\n");
|
||||||
err = lfs_format(&lfs, &cfg);
|
err = lfs_format(&lfs, &cfg);
|
||||||
if (err < 0) return false;
|
if (err < 0) return false;
|
||||||
err = lfs_mount(&lfs, &cfg);
|
err = lfs_mount(&lfs, &cfg) == LFS_ERR_OK;
|
||||||
printf("Filesystem mounted with %ld bytes free.\r\n", filesystem_get_free_space());
|
printf("Filesystem mounted with %ld bytes free.\r\n", filesystem_get_free_space());
|
||||||
}
|
}
|
||||||
|
|
||||||
return err == LFS_ERR_OK;
|
return err == LFS_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _filesystem_format(void);
|
|
||||||
int _filesystem_format(void) {
|
|
||||||
int err = lfs_unmount(&lfs);
|
|
||||||
if (err < 0) {
|
|
||||||
printf("Couldn't unmount - continuing to format, but you should reboot afterwards!\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
err = lfs_format(&lfs, &cfg);
|
|
||||||
if (err < 0) return err;
|
|
||||||
|
|
||||||
err = lfs_mount(&lfs, &cfg);
|
|
||||||
if (err < 0) return err;
|
|
||||||
printf("Filesystem re-mounted with %ld bytes free.\r\n", filesystem_get_free_space());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool filesystem_file_exists(char *filename) {
|
bool filesystem_file_exists(char *filename) {
|
||||||
info.type = 0;
|
info.type = 0;
|
||||||
lfs_stat(&lfs, filename, &info);
|
lfs_stat(&lfs, filename, &info);
|
||||||
@ -267,16 +251,6 @@ int filesystem_cmd_rm(int argc, char *argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int filesystem_cmd_format(int argc, char *argv[]) {
|
|
||||||
(void) argc;
|
|
||||||
if(strcmp(argv[1], "YES") == 0) {
|
|
||||||
return _filesystem_format();
|
|
||||||
}
|
|
||||||
printf("usage: format YES\r\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int filesystem_cmd_echo(int argc, char *argv[]) {
|
int filesystem_cmd_echo(int argc, char *argv[]) {
|
||||||
(void) argc;
|
(void) argc;
|
||||||
|
|
||||||
@ -305,3 +279,4 @@ int filesystem_cmd_echo(int argc, char *argv[]) {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +100,6 @@ int filesystem_cmd_ls(int argc, char *argv[]);
|
|||||||
int filesystem_cmd_cat(int argc, char *argv[]);
|
int filesystem_cmd_cat(int argc, char *argv[]);
|
||||||
int filesystem_cmd_df(int argc, char *argv[]);
|
int filesystem_cmd_df(int argc, char *argv[]);
|
||||||
int filesystem_cmd_rm(int argc, char *argv[]);
|
int filesystem_cmd_rm(int argc, char *argv[]);
|
||||||
int filesystem_cmd_format(int argc, char *argv[]);
|
|
||||||
int filesystem_cmd_echo(int argc, char *argv[]);
|
int filesystem_cmd_echo(int argc, char *argv[]);
|
||||||
|
|
||||||
#endif // FILESYSTEM_H_
|
#endif // FILESYSTEM_H_
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include "time.h"
|
#include "time.h"
|
||||||
|
|
||||||
typedef enum __attribute__ ((__packed__)) {
|
typedef enum {
|
||||||
SHA1,
|
SHA1,
|
||||||
SHA224,
|
SHA224,
|
||||||
SHA256,
|
SHA256,
|
||||||
|
@ -1,304 +0,0 @@
|
|||||||
// Compute times of moonrise and moonset at a specified latitude and longitude.
|
|
||||||
//
|
|
||||||
// This software minimizes computational work by performing the full calculation
|
|
||||||
// of the lunar position three times, at the beginning, middle, and end of the
|
|
||||||
// period of interest. Three point interpolation is used to predict the
|
|
||||||
// position for each hour, and the arithmetic mean is used to predict the
|
|
||||||
// half-hour positions.
|
|
||||||
//
|
|
||||||
// The full computational burden is negligible on modern computers, but the
|
|
||||||
// algorithm is effective and still useful for small embedded systems.
|
|
||||||
//
|
|
||||||
// This software was originally adapted to javascript by Stephen R. Schmitt
|
|
||||||
// from a BASIC program from the 'Astronomical Computing' column of Sky &
|
|
||||||
// Telescope, April 1989, page 78.
|
|
||||||
//
|
|
||||||
// Subsequently adapted from Stephen R. Schmitt's javascript to c++ for the
|
|
||||||
// Arduino by Cyrus Rahman.
|
|
||||||
//
|
|
||||||
// Subsequently adapted from Cyrus Rahman's Arduino C++ to C for the Sensor
|
|
||||||
// Watch by hueso, this work is subject to Stephen Schmitt's copyright:
|
|
||||||
//
|
|
||||||
// Copyright 2007 Stephen R. Schmitt
|
|
||||||
// Subsequent work Copyright 2020 Cyrus Rahman
|
|
||||||
// You may use or modify this source code in any way you find useful, provided
|
|
||||||
// that you agree that the author(s) have no warranty, obligations or liability.
|
|
||||||
// You must determine the suitability of this source code for your use.
|
|
||||||
//
|
|
||||||
// Redistributions of this source code must retain this copyright notice.
|
|
||||||
|
|
||||||
#include "moonrise.h"
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#define K1 15 * (M_PI / 180) * 1.0027379
|
|
||||||
|
|
||||||
// Determine the nearest moon rise or set event previous, and the nearest
|
|
||||||
// moon rise or set event subsequent, to the specified time in seconds since the
|
|
||||||
// Unix epoch (January 1, 1970) and at the specified latitude and longitude in
|
|
||||||
// degrees.
|
|
||||||
//
|
|
||||||
// We look for events from MR_WINDOW/2 hours in the past to MR_WINDOW/2 hours
|
|
||||||
// in the future.
|
|
||||||
MoonRise MoonRise_calculate(double latitude, double longitude, uint32_t t) {
|
|
||||||
MoonRise self = {};
|
|
||||||
skyCoordinates moonPosition[3];
|
|
||||||
double offsetDays;
|
|
||||||
|
|
||||||
self.queryTime = t;
|
|
||||||
offsetDays = julianDate(t) - 2451545L; // Days since Jan 1, 2000, 1200UTC.
|
|
||||||
// Begin testing (MR_WINDOW / 2) hours before requested time.
|
|
||||||
// offsetDays -= (double)MR_WINDOW / (2 * 24) ;
|
|
||||||
|
|
||||||
// Calculate coordinates at start, middle, and end of search period.
|
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
moonPosition[i] = moon(offsetDays + i * (double)MR_WINDOW / (2 * 24));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the RA wraps around during this period, unwrap it to keep the
|
|
||||||
// sequence smooth for interpolation.
|
|
||||||
if (moonPosition[1].RA <= moonPosition[0].RA)
|
|
||||||
moonPosition[1].RA += 2 * M_PI;
|
|
||||||
if (moonPosition[2].RA <= moonPosition[1].RA)
|
|
||||||
moonPosition[2].RA += 2 * M_PI;
|
|
||||||
|
|
||||||
// Initialize interpolation array.
|
|
||||||
skyCoordinates mpWindow[3];
|
|
||||||
mpWindow[0].RA = moonPosition[0].RA;
|
|
||||||
mpWindow[0].declination = moonPosition[0].declination;
|
|
||||||
mpWindow[0].distance = moonPosition[0].distance;
|
|
||||||
|
|
||||||
for (int k = 0; k < MR_WINDOW; k++) { // Check each interval of search period
|
|
||||||
float ph = (float)(k + 1) / MR_WINDOW;
|
|
||||||
|
|
||||||
mpWindow[2].RA = interpolate(moonPosition[0].RA, moonPosition[1].RA,
|
|
||||||
moonPosition[2].RA, ph);
|
|
||||||
mpWindow[2].declination =
|
|
||||||
interpolate(moonPosition[0].declination, moonPosition[1].declination,
|
|
||||||
moonPosition[2].declination, ph);
|
|
||||||
mpWindow[2].distance = moonPosition[2].distance;
|
|
||||||
|
|
||||||
// Look for moonrise/set events during this interval.
|
|
||||||
{
|
|
||||||
double ha[3], VHz[3];
|
|
||||||
double lSideTime;
|
|
||||||
|
|
||||||
// Get (local_sidereal_time - MR_WINDOW / 2) hours in radians.
|
|
||||||
lSideTime = localSiderealTime(offsetDays, longitude) * 2 * M_PI / 360;
|
|
||||||
|
|
||||||
// Calculate Hour Angle.
|
|
||||||
ha[0] = lSideTime - mpWindow[0].RA + k * K1;
|
|
||||||
ha[2] = lSideTime - mpWindow[2].RA + k * K1 + K1;
|
|
||||||
|
|
||||||
// Hour Angle and declination at half hour.
|
|
||||||
ha[1] = (ha[2] + ha[0]) / 2;
|
|
||||||
mpWindow[1].declination =
|
|
||||||
(mpWindow[2].declination + mpWindow[0].declination) / 2;
|
|
||||||
|
|
||||||
double s = sin(M_PI / 180 * latitude);
|
|
||||||
double c = cos(M_PI / 180 * latitude);
|
|
||||||
|
|
||||||
// refraction + semidiameter at horizon + distance correction
|
|
||||||
double z = cos(M_PI / 180 * (90.567 - 41.685 / mpWindow[0].distance));
|
|
||||||
|
|
||||||
VHz[0] = s * sin(mpWindow[0].declination) +
|
|
||||||
c * cos(mpWindow[0].declination) * cos(ha[0]) - z;
|
|
||||||
VHz[2] = s * sin(mpWindow[2].declination) +
|
|
||||||
c * cos(mpWindow[2].declination) * cos(ha[2]) - z;
|
|
||||||
|
|
||||||
if (signbit(VHz[0]) == signbit(VHz[2]))
|
|
||||||
goto noevent; // No event this hour.
|
|
||||||
|
|
||||||
VHz[1] = s * sin(mpWindow[1].declination) +
|
|
||||||
c * cos(mpWindow[1].declination) * cos(ha[1]) - z;
|
|
||||||
|
|
||||||
double a, b, d, e, time;
|
|
||||||
a = 2 * VHz[2] - 4 * VHz[1] + 2 * VHz[0];
|
|
||||||
b = 4 * VHz[1] - 3 * VHz[0] - VHz[2];
|
|
||||||
d = b * b - 4 * a * VHz[0];
|
|
||||||
|
|
||||||
if (d < 0)
|
|
||||||
goto noevent; // No event this hour.
|
|
||||||
|
|
||||||
d = sqrt(d);
|
|
||||||
e = (-b + d) / (2 * a);
|
|
||||||
if ((e < 0) || (e > 1))
|
|
||||||
e = (-b - d) / (2 * a);
|
|
||||||
time = k + e + 1 / 120; // Time since k=0 of event (in hours).
|
|
||||||
|
|
||||||
// The time we started searching + the time from the start of the search
|
|
||||||
// to the event is the time of the event.
|
|
||||||
uint32_t eventTime;
|
|
||||||
eventTime = self.queryTime + (time) * 60 * 60;
|
|
||||||
|
|
||||||
double hz, nz, dz, az;
|
|
||||||
hz = ha[0] + e * (ha[2] - ha[0]); // Azimuth of the moon at the event.
|
|
||||||
nz = -cos(mpWindow[1].declination) * sin(hz);
|
|
||||||
dz = c * sin(mpWindow[1].declination) -
|
|
||||||
s * cos(mpWindow[1].declination) * cos(hz);
|
|
||||||
az = atan2(nz, dz) / (M_PI / 180);
|
|
||||||
if (az < 0)
|
|
||||||
az += 360;
|
|
||||||
|
|
||||||
// If there is no previously recorded event of this type, save this event.
|
|
||||||
//
|
|
||||||
// If this event is previous to queryTime, and is the nearest event to
|
|
||||||
// queryTime of events of its type previous to queryType, save this event,
|
|
||||||
// replacing the previously recorded event of its type. Events subsequent
|
|
||||||
// to queryTime are treated similarly, although since events are tested in
|
|
||||||
// chronological order no replacements will occur as successive events
|
|
||||||
// will be further from queryTime.
|
|
||||||
//
|
|
||||||
// If this event is subsequent to queryTime and there is an event of its
|
|
||||||
// type previous to queryTime, then there is an event of the other type
|
|
||||||
// between the two events of this event's type. If the event of the other
|
|
||||||
// type is previous to queryTime, then it is the nearest event to
|
|
||||||
// queryTime that is previous to queryTime. In this case save the current
|
|
||||||
// event, replacing the previously recorded event of its type. Otherwise
|
|
||||||
// discard the current event.
|
|
||||||
//
|
|
||||||
if ((VHz[0] < 0) && (VHz[2] > 0)) {
|
|
||||||
if (!self.hasRise ||
|
|
||||||
((self.riseTime < self.queryTime) == (eventTime < self.queryTime) &&
|
|
||||||
(self.riseTime - self.queryTime) > (eventTime - self.queryTime)) ||
|
|
||||||
((self.riseTime < self.queryTime) != (eventTime < self.queryTime) &&
|
|
||||||
(self.hasSet && (self.riseTime < self.queryTime) ==
|
|
||||||
(self.setTime < self.queryTime)))) {
|
|
||||||
self.riseTime = eventTime;
|
|
||||||
self.riseAz = az;
|
|
||||||
self.hasRise = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((VHz[0] > 0) && (VHz[2] < 0)) {
|
|
||||||
if (!self.hasSet ||
|
|
||||||
((self.setTime < self.queryTime) == (eventTime < self.queryTime) &&
|
|
||||||
(self.setTime - self.queryTime) > (eventTime - self.queryTime)) ||
|
|
||||||
((self.setTime < self.queryTime) != (eventTime < self.queryTime) &&
|
|
||||||
(self.hasRise && (self.setTime < self.queryTime) ==
|
|
||||||
(self.riseTime < self.queryTime)))) {
|
|
||||||
self.setTime = eventTime;
|
|
||||||
self.setAz = az;
|
|
||||||
self.hasSet = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
noevent:
|
|
||||||
// There are obscure cases in the polar regions that require extra logic.
|
|
||||||
if (!self.hasRise && !self.hasSet)
|
|
||||||
self.isVisible = !signbit(VHz[2]);
|
|
||||||
else if (self.hasRise && !self.hasSet)
|
|
||||||
self.isVisible = (self.queryTime > self.riseTime);
|
|
||||||
else if (!self.hasRise && self.hasSet)
|
|
||||||
self.isVisible = (self.queryTime < self.setTime);
|
|
||||||
else
|
|
||||||
self.isVisible =
|
|
||||||
((self.riseTime < self.setTime && self.riseTime < self.queryTime &&
|
|
||||||
self.setTime > self.queryTime) ||
|
|
||||||
(self.riseTime > self.setTime && (self.riseTime < self.queryTime ||
|
|
||||||
self.setTime > self.queryTime)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.hasSet && self.hasRise)
|
|
||||||
break;
|
|
||||||
|
|
||||||
mpWindow[0] = mpWindow[2]; // Advance to next interval.
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Moon position using fundamental arguments
|
|
||||||
// (Van Flandern & Pulkkinen, 1979)
|
|
||||||
skyCoordinates moon(double dayOffset) {
|
|
||||||
double l = 0.606434 + 0.03660110129 * dayOffset;
|
|
||||||
double m = 0.374897 + 0.03629164709 * dayOffset;
|
|
||||||
double f = 0.259091 + 0.03674819520 * dayOffset;
|
|
||||||
double d = 0.827362 + 0.03386319198 * dayOffset;
|
|
||||||
double n = 0.347343 - 0.00014709391 * dayOffset;
|
|
||||||
double g = 0.993126 + 0.00273777850 * dayOffset;
|
|
||||||
|
|
||||||
l = 2 * M_PI * (l - floor(l));
|
|
||||||
m = 2 * M_PI * (m - floor(m));
|
|
||||||
f = 2 * M_PI * (f - floor(f));
|
|
||||||
d = 2 * M_PI * (d - floor(d));
|
|
||||||
n = 2 * M_PI * (n - floor(n));
|
|
||||||
g = 2 * M_PI * (g - floor(g));
|
|
||||||
|
|
||||||
double v, u, w;
|
|
||||||
v = 0.39558 * sin(f + n)
|
|
||||||
+ 0.08200 * sin(f)
|
|
||||||
+ 0.03257 * sin(m - f - n)
|
|
||||||
+ 0.01092 * sin(m + f + n)
|
|
||||||
+ 0.00666 * sin(m - f)
|
|
||||||
- 0.00644 * sin(m + f - 2*d + n)
|
|
||||||
- 0.00331 * sin(f - 2*d + n)
|
|
||||||
- 0.00304 * sin(f - 2*d)
|
|
||||||
- 0.00240 * sin(m - f - 2*d - n)
|
|
||||||
+ 0.00226 * sin(m + f)
|
|
||||||
- 0.00108 * sin(m + f - 2*d)
|
|
||||||
- 0.00079 * sin(f - n)
|
|
||||||
+ 0.00078 * sin(f + 2*d + n);
|
|
||||||
|
|
||||||
u = 1
|
|
||||||
- 0.10828 * cos(m)
|
|
||||||
- 0.01880 * cos(m - 2*d)
|
|
||||||
- 0.01479 * cos(2*d)
|
|
||||||
+ 0.00181 * cos(2*m - 2*d)
|
|
||||||
- 0.00147 * cos(2*m)
|
|
||||||
- 0.00105 * cos(2*d - g)
|
|
||||||
- 0.00075 * cos(m - 2*d + g);
|
|
||||||
|
|
||||||
w = 0.10478 * sin(m)
|
|
||||||
- 0.04105 * sin(2*f + 2*n)
|
|
||||||
- 0.02130 * sin(m - 2*d)
|
|
||||||
- 0.01779 * sin(2*f + n)
|
|
||||||
+ 0.01774 * sin(n)
|
|
||||||
+ 0.00987 * sin(2*d)
|
|
||||||
- 0.00338 * sin(m - 2*f - 2*n)
|
|
||||||
- 0.00309 * sin(g)
|
|
||||||
- 0.00190 * sin(2*f)
|
|
||||||
- 0.00144 * sin(m + n)
|
|
||||||
- 0.00144 * sin(m - 2*f - n)
|
|
||||||
- 0.00113 * sin(m + 2*f + 2*n)
|
|
||||||
- 0.00094 * sin(m - 2*d + g)
|
|
||||||
- 0.00092 * sin(2*m - 2*d);
|
|
||||||
|
|
||||||
double s;
|
|
||||||
skyCoordinates sc;
|
|
||||||
s = w / sqrt(u - v*v);
|
|
||||||
sc.RA = l + atan(s / sqrt(1 - s*s)); // Right ascension
|
|
||||||
|
|
||||||
s = v / sqrt(u);
|
|
||||||
sc.declination = atan(s / sqrt(1 - s*s)); // Declination
|
|
||||||
sc.distance = 60.40974 * sqrt(u); // Distance
|
|
||||||
return(sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3-point interpolation
|
|
||||||
double interpolate(double f0, double f1, double f2, double p) {
|
|
||||||
double a = f1 - f0;
|
|
||||||
double b = f2 - f1 - a;
|
|
||||||
return(f0 + p * (2*a + b * (2*p - 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine Julian date from Unix time.
|
|
||||||
// Provides marginally accurate results with Arduino 4-byte double.
|
|
||||||
double julianDate(uint32_t t) {
|
|
||||||
return (t / 86400.0L + 2440587.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Local Sidereal Time
|
|
||||||
// Provides local sidereal time in degrees, requires longitude in degrees
|
|
||||||
// and time in fractional Julian days since Jan 1, 2000, 1200UTC (e.g. the
|
|
||||||
// Julian date - 2451545).
|
|
||||||
// cf. USNO Astronomical Almanac and
|
|
||||||
// https://astronomy.stackexchange.com/questions/24859/local-sidereal-time
|
|
||||||
double localSiderealTime(double offsetDays, double longitude) {
|
|
||||||
double lSideTime = (15.0L * (6.697374558L + 0.06570982441908L * offsetDays +
|
|
||||||
remainder(offsetDays, 1) * 24 + 12 +
|
|
||||||
0.000026 * (offsetDays / 36525) * (offsetDays / 36525))
|
|
||||||
+ longitude) / 360;
|
|
||||||
lSideTime -= floor(lSideTime);
|
|
||||||
lSideTime *= 360; // Convert to degrees.
|
|
||||||
return(lSideTime);
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
|||||||
#ifndef MoonRise_h
|
|
||||||
#define MoonRise_h
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
// Size of event search window in hours.
|
|
||||||
// Events further away from the search time than MR_WINDOW/2 will not be
|
|
||||||
// found. At higher latitudes the moon rise/set intervals become larger, so if
|
|
||||||
// you want to find the nearest events this will need to increase. Larger
|
|
||||||
// windows will increase interpolation error. Useful values are probably from
|
|
||||||
// 12 - 48 but will depend upon your application.
|
|
||||||
|
|
||||||
#define MR_WINDOW 48 // Even integer
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
double RA; // Right ascension
|
|
||||||
double declination; // Declination
|
|
||||||
double distance; // Distance
|
|
||||||
} skyCoordinates;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t queryTime;
|
|
||||||
uint32_t riseTime;
|
|
||||||
uint32_t setTime;
|
|
||||||
float riseAz;
|
|
||||||
float setAz;
|
|
||||||
bool hasRise;
|
|
||||||
bool hasSet;
|
|
||||||
bool isVisible;
|
|
||||||
} MoonRise;
|
|
||||||
|
|
||||||
MoonRise MoonRise_calculate(double latitude, double longitude, uint32_t t);
|
|
||||||
|
|
||||||
// private:
|
|
||||||
void testMoonRiseSet(MoonRise *self, int i, double offsetDays, double latitude,
|
|
||||||
double longitude, skyCoordinates *mp);
|
|
||||||
skyCoordinates moon(double dayOffset);
|
|
||||||
double interpolate(double f0, double f1, double f2, double p);
|
|
||||||
double julianDate(uint32_t t);
|
|
||||||
double localSiderealTime(double offsetDays, double longitude);
|
|
||||||
|
|
||||||
#endif
|
|
File diff suppressed because it is too large
Load Diff
@ -24,8 +24,6 @@ INCLUDES += \
|
|||||||
-I../lib/vsop87/ \
|
-I../lib/vsop87/ \
|
||||||
-I../lib/astrolib/ \
|
-I../lib/astrolib/ \
|
||||||
-I../lib/morsecalc/ \
|
-I../lib/morsecalc/ \
|
||||||
-I../lib/smallchesslib/ \
|
|
||||||
-I../lib/moonrise/ \
|
|
||||||
|
|
||||||
# If you add any other source files you wish to compile, add them after ../app.c
|
# If you add any other source files you wish to compile, add them after ../app.c
|
||||||
# Note that you will need to add a backslash at the end of any line you wish to continue, i.e.
|
# Note that you will need to add a backslash at the end of any line you wish to continue, i.e.
|
||||||
@ -41,7 +39,6 @@ SRCS += \
|
|||||||
../lib/TOTP/TOTP.c \
|
../lib/TOTP/TOTP.c \
|
||||||
../lib/base32/base32.c \
|
../lib/base32/base32.c \
|
||||||
../lib/sunriset/sunriset.c \
|
../lib/sunriset/sunriset.c \
|
||||||
../lib/moonrise/moonrise.c \
|
|
||||||
../lib/vsop87/vsop87a_milli.c \
|
../lib/vsop87/vsop87a_milli.c \
|
||||||
../lib/astrolib/astrolib.c \
|
../lib/astrolib/astrolib.c \
|
||||||
../lib/morsecalc/calc.c \
|
../lib/morsecalc/calc.c \
|
||||||
@ -55,7 +52,6 @@ SRCS += \
|
|||||||
../shell.c \
|
../shell.c \
|
||||||
../shell_cmd_list.c \
|
../shell_cmd_list.c \
|
||||||
../watch_faces/clock/simple_clock_face.c \
|
../watch_faces/clock/simple_clock_face.c \
|
||||||
../watch_faces/clock/close_enough_clock_face.c \
|
|
||||||
../watch_faces/clock/clock_face.c \
|
../watch_faces/clock/clock_face.c \
|
||||||
../watch_faces/clock/world_clock_face.c \
|
../watch_faces/clock/world_clock_face.c \
|
||||||
../watch_faces/clock/beats_face.c \
|
../watch_faces/clock/beats_face.c \
|
||||||
@ -122,7 +118,6 @@ SRCS += \
|
|||||||
../watch_faces/complication/toss_up_face.c \
|
../watch_faces/complication/toss_up_face.c \
|
||||||
../watch_faces/complication/geomancy_face.c \
|
../watch_faces/complication/geomancy_face.c \
|
||||||
../watch_faces/clock/simple_clock_bin_led_face.c \
|
../watch_faces/clock/simple_clock_bin_led_face.c \
|
||||||
../watch_faces/complication/menstrual_cycle_face.c \
|
|
||||||
../watch_faces/complication/flashlight_face.c \
|
../watch_faces/complication/flashlight_face.c \
|
||||||
../watch_faces/clock/decimal_time_face.c \
|
../watch_faces/clock/decimal_time_face.c \
|
||||||
../watch_faces/clock/wyoscan_face.c \
|
../watch_faces/clock/wyoscan_face.c \
|
||||||
@ -133,25 +128,7 @@ SRCS += \
|
|||||||
../watch_faces/complication/couch_to_5k_face.c \
|
../watch_faces/complication/couch_to_5k_face.c \
|
||||||
../watch_faces/clock/minute_repeater_decimal_face.c \
|
../watch_faces/clock/minute_repeater_decimal_face.c \
|
||||||
../watch_faces/complication/tuning_tones_face.c \
|
../watch_faces/complication/tuning_tones_face.c \
|
||||||
../watch_faces/sensor/minmax_face.c \
|
|
||||||
../watch_faces/complication/kitchen_conversions_face.c \
|
../watch_faces/complication/kitchen_conversions_face.c \
|
||||||
../watch_faces/complication/butterfly_game_face.c \
|
|
||||||
../watch_faces/complication/wareki_face.c \
|
|
||||||
../watch_faces/complication/wordle_face.c \
|
|
||||||
../watch_faces/complication/endless_runner_face.c \
|
|
||||||
../watch_faces/complication/periodic_face.c \
|
|
||||||
../watch_faces/complication/deadline_face.c \
|
|
||||||
../watch_faces/complication/higher_lower_game_face.c \
|
|
||||||
../watch_faces/clock/french_revolutionary_face.c \
|
|
||||||
../watch_faces/clock/minimal_clock_face.c \
|
|
||||||
../watch_faces/complication/simon_face.c \
|
|
||||||
../watch_faces/complication/simple_calculator_face.c \
|
|
||||||
../watch_faces/sensor/alarm_thermometer_face.c \
|
|
||||||
../watch_faces/demo/beeps_face.c \
|
|
||||||
../watch_faces/sensor/accel_interrupt_count_face.c \
|
|
||||||
../watch_faces/complication/metronome_face.c \
|
|
||||||
../watch_faces/complication/smallchess_face.c \
|
|
||||||
../watch_faces/complication/moonrise_face.c \
|
|
||||||
# New watch faces go above this line.
|
# New watch faces go above this line.
|
||||||
|
|
||||||
# Leave this line at the bottom of the file; it has all the targets for making your project.
|
# Leave this line at the bottom of the file; it has all the targets for making your project.
|
||||||
|
@ -201,7 +201,7 @@ static void _movement_handle_scheduled_tasks(void) {
|
|||||||
|
|
||||||
for(uint8_t i = 0; i < MOVEMENT_NUM_FACES; i++) {
|
for(uint8_t i = 0; i < MOVEMENT_NUM_FACES; i++) {
|
||||||
if (scheduled_tasks[i].reg) {
|
if (scheduled_tasks[i].reg) {
|
||||||
if (scheduled_tasks[i].reg <= date_time.reg) {
|
if (scheduled_tasks[i].reg == date_time.reg) {
|
||||||
scheduled_tasks[i].reg = 0;
|
scheduled_tasks[i].reg = 0;
|
||||||
movement_event_t background_event = { EVENT_BACKGROUND_TASK, 0 };
|
movement_event_t background_event = { EVENT_BACKGROUND_TASK, 0 };
|
||||||
watch_faces[i].loop(background_event, &movement_state.settings, watch_face_contexts[i]);
|
watch_faces[i].loop(background_event, &movement_state.settings, watch_face_contexts[i]);
|
||||||
@ -239,24 +239,14 @@ void movement_request_tick_frequency(uint8_t freq) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void movement_illuminate_led(void) {
|
void movement_illuminate_led(void) {
|
||||||
if (movement_state.settings.bit.led_duration != 0b111) {
|
if (movement_state.settings.bit.led_duration) {
|
||||||
watch_set_led_color(movement_state.settings.bit.led_red_color ? (0xF | movement_state.settings.bit.led_red_color << 4) : 0,
|
watch_set_led_color(movement_state.settings.bit.led_red_color ? (0xF | movement_state.settings.bit.led_red_color << 4) : 0,
|
||||||
movement_state.settings.bit.led_green_color ? (0xF | movement_state.settings.bit.led_green_color << 4) : 0);
|
movement_state.settings.bit.led_green_color ? (0xF | movement_state.settings.bit.led_green_color << 4) : 0);
|
||||||
if (movement_state.settings.bit.led_duration == 0) {
|
|
||||||
movement_state.light_ticks = 1;
|
|
||||||
} else {
|
|
||||||
movement_state.light_ticks = (movement_state.settings.bit.led_duration * 2 - 1) * 128;
|
movement_state.light_ticks = (movement_state.settings.bit.led_duration * 2 - 1) * 128;
|
||||||
}
|
|
||||||
_movement_enable_fast_tick_if_needed();
|
_movement_enable_fast_tick_if_needed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _movement_led_off(void) {
|
|
||||||
watch_set_led_off();
|
|
||||||
movement_state.light_ticks = -1;
|
|
||||||
_movement_disable_fast_tick_if_possible();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool movement_default_loop_handler(movement_event_t event, movement_settings_t *settings) {
|
bool movement_default_loop_handler(movement_event_t event, movement_settings_t *settings) {
|
||||||
(void)settings;
|
(void)settings;
|
||||||
|
|
||||||
@ -267,11 +257,6 @@ bool movement_default_loop_handler(movement_event_t event, movement_settings_t *
|
|||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
case EVENT_LIGHT_BUTTON_DOWN:
|
||||||
movement_illuminate_led();
|
movement_illuminate_led();
|
||||||
break;
|
break;
|
||||||
case EVENT_LIGHT_BUTTON_UP:
|
|
||||||
if (movement_state.settings.bit.led_duration == 0) {
|
|
||||||
_movement_led_off();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_MODE_LONG_PRESS:
|
case EVENT_MODE_LONG_PRESS:
|
||||||
if (MOVEMENT_SECONDARY_FACE_INDEX && movement_state.current_face_idx == 0) {
|
if (MOVEMENT_SECONDARY_FACE_INDEX && movement_state.current_face_idx == 0) {
|
||||||
movement_move_to_face(MOVEMENT_SECONDARY_FACE_INDEX);
|
movement_move_to_face(MOVEMENT_SECONDARY_FACE_INDEX);
|
||||||
@ -334,23 +319,15 @@ void movement_request_wake() {
|
|||||||
_movement_reset_inactivity_countdown();
|
_movement_reset_inactivity_countdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void end_buzzing() {
|
void end_buzzing() {
|
||||||
movement_state.is_buzzing = false;
|
movement_state.is_buzzing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void end_buzzing_and_disable_buzzer(void) {
|
void end_buzzing_and_disable_buzzer(void) {
|
||||||
end_buzzing();
|
end_buzzing();
|
||||||
watch_disable_buzzer();
|
watch_disable_buzzer();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_initial_clock_mode(void) {
|
|
||||||
#ifdef CLOCK_FACE_24H_ONLY
|
|
||||||
movement_state.settings.bit.clock_mode_24h = true;
|
|
||||||
#else
|
|
||||||
movement_state.settings.bit.clock_mode_24h = MOVEMENT_DEFAULT_24H_MODE;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void movement_play_signal(void) {
|
void movement_play_signal(void) {
|
||||||
void *maybe_disable_buzzer = end_buzzing_and_disable_buzzer;
|
void *maybe_disable_buzzer = end_buzzing_and_disable_buzzer;
|
||||||
if (watch_is_buzzer_or_led_enabled()) {
|
if (watch_is_buzzer_or_led_enabled()) {
|
||||||
@ -399,14 +376,14 @@ void app_init(void) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
memset(&movement_state, 0, sizeof(movement_state));
|
memset(&movement_state, 0, sizeof(movement_state));
|
||||||
set_initial_clock_mode();
|
|
||||||
|
movement_state.settings.bit.clock_mode_24h = MOVEMENT_DEFAULT_24H_MODE;
|
||||||
movement_state.settings.bit.led_red_color = MOVEMENT_DEFAULT_RED_COLOR;
|
movement_state.settings.bit.led_red_color = MOVEMENT_DEFAULT_RED_COLOR;
|
||||||
movement_state.settings.bit.led_green_color = MOVEMENT_DEFAULT_GREEN_COLOR;
|
movement_state.settings.bit.led_green_color = MOVEMENT_DEFAULT_GREEN_COLOR;
|
||||||
movement_state.settings.bit.button_should_sound = MOVEMENT_DEFAULT_BUTTON_SOUND;
|
movement_state.settings.bit.button_should_sound = MOVEMENT_DEFAULT_BUTTON_SOUND;
|
||||||
movement_state.settings.bit.to_interval = MOVEMENT_DEFAULT_TIMEOUT_INTERVAL;
|
movement_state.settings.bit.to_interval = MOVEMENT_DEFAULT_TIMEOUT_INTERVAL;
|
||||||
movement_state.settings.bit.le_interval = MOVEMENT_DEFAULT_LOW_ENERGY_INTERVAL;
|
movement_state.settings.bit.le_interval = MOVEMENT_DEFAULT_LOW_ENERGY_INTERVAL;
|
||||||
movement_state.settings.bit.led_duration = MOVEMENT_DEFAULT_LED_DURATION;
|
movement_state.settings.bit.led_duration = MOVEMENT_DEFAULT_LED_DURATION;
|
||||||
|
|
||||||
movement_state.light_ticks = -1;
|
movement_state.light_ticks = -1;
|
||||||
movement_state.alarm_ticks = -1;
|
movement_state.alarm_ticks = -1;
|
||||||
movement_state.next_available_backup_register = 4;
|
movement_state.next_available_backup_register = 4;
|
||||||
@ -526,7 +503,9 @@ bool app_loop(void) {
|
|||||||
if (watch_get_pin_level(BTN_LIGHT)) {
|
if (watch_get_pin_level(BTN_LIGHT)) {
|
||||||
movement_state.light_ticks = 1;
|
movement_state.light_ticks = 1;
|
||||||
} else {
|
} else {
|
||||||
_movement_led_off();
|
watch_set_led_off();
|
||||||
|
movement_state.light_ticks = -1;
|
||||||
|
_movement_disable_fast_tick_if_possible();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,17 +543,6 @@ bool app_loop(void) {
|
|||||||
event.subsecond = movement_state.subsecond;
|
event.subsecond = movement_state.subsecond;
|
||||||
// the first trip through the loop overrides the can_sleep state
|
// the first trip through the loop overrides the can_sleep state
|
||||||
can_sleep = wf->loop(event, &movement_state.settings, watch_face_contexts[movement_state.current_face_idx]);
|
can_sleep = wf->loop(event, &movement_state.settings, watch_face_contexts[movement_state.current_face_idx]);
|
||||||
|
|
||||||
// Keep light on if user is still interacting with the watch.
|
|
||||||
if (movement_state.light_ticks > 0) {
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
case EVENT_MODE_BUTTON_DOWN:
|
|
||||||
case EVENT_ALARM_BUTTON_DOWN:
|
|
||||||
movement_illuminate_led();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
event.event_type = EVENT_NONE;
|
event.event_type = EVENT_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ typedef union {
|
|||||||
uint8_t to_interval : 2; // an inactivity interval for asking the active face to resign.
|
uint8_t to_interval : 2; // an inactivity interval for asking the active face to resign.
|
||||||
bool to_always : 1; // if true, always time out from the active face to face 0. otherwise only faces that time out will resign (the default).
|
bool to_always : 1; // if true, always time out from the active face to face 0. otherwise only faces that time out will resign (the default).
|
||||||
uint8_t le_interval : 3; // 0 to disable low energy mode, or an inactivity interval for going into low energy mode.
|
uint8_t le_interval : 3; // 0 to disable low energy mode, or an inactivity interval for going into low energy mode.
|
||||||
uint8_t led_duration : 3; // how many seconds to shine the LED for (x2), 0 to shine only while the button is depressed, or all bits set to disable the LED altogether.
|
uint8_t led_duration : 2; // how many seconds to shine the LED for (x2), or 0 to disable it.
|
||||||
uint8_t led_red_color : 4; // for general purpose illumination, the red LED value (0-15)
|
uint8_t led_red_color : 4; // for general purpose illumination, the red LED value (0-15)
|
||||||
uint8_t led_green_color : 4; // for general purpose illumination, the green LED value (0-15)
|
uint8_t led_green_color : 4; // for general purpose illumination, the green LED value (0-15)
|
||||||
uint8_t time_zone : 6; // an integer representing an index in the time zone table.
|
uint8_t time_zone : 6; // an integer representing an index in the time zone table.
|
||||||
@ -60,10 +60,9 @@ typedef union {
|
|||||||
// time-oriented complication like a sunrise/sunset timer, and a simple locale preference could tell an
|
// time-oriented complication like a sunrise/sunset timer, and a simple locale preference could tell an
|
||||||
// altimeter to display feet or meters as easily as it tells a thermometer to display degrees in F or C.
|
// altimeter to display feet or meters as easily as it tells a thermometer to display degrees in F or C.
|
||||||
bool clock_mode_24h : 1; // indicates whether clock should use 12 or 24 hour mode.
|
bool clock_mode_24h : 1; // indicates whether clock should use 12 or 24 hour mode.
|
||||||
bool clock_24h_leading_zero : 1; // indicates whether clock should leading zero to indicate 24 hour mode.
|
|
||||||
bool use_imperial_units : 1; // indicates whether to use metric units (the default) or imperial.
|
bool use_imperial_units : 1; // indicates whether to use metric units (the default) or imperial.
|
||||||
bool alarm_enabled : 1; // indicates whether there is at least one alarm enabled.
|
bool alarm_enabled : 1; // indicates whether there is at least one alarm enabled.
|
||||||
uint8_t reserved : 5; // room for more preferences if needed.
|
uint8_t reserved : 6; // room for more preferences if needed.
|
||||||
} bit;
|
} bit;
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
} movement_settings_t;
|
} movement_settings_t;
|
||||||
|
@ -67,139 +67,21 @@ int8_t signal_tune[] = {
|
|||||||
};
|
};
|
||||||
#endif // SIGNAL_TUNE_MARIO_THEME
|
#endif // SIGNAL_TUNE_MARIO_THEME
|
||||||
|
|
||||||
#ifdef SIGNAL_TUNE_MGS_CODEC
|
|
||||||
int8_t signal_tune[] = {
|
|
||||||
BUZZER_NOTE_G5SHARP_A5FLAT, 1,
|
|
||||||
BUZZER_NOTE_C6, 1,
|
|
||||||
BUZZER_NOTE_G5SHARP_A5FLAT, 1,
|
|
||||||
BUZZER_NOTE_C6, 1,
|
|
||||||
BUZZER_NOTE_G5SHARP_A5FLAT, 1,
|
|
||||||
BUZZER_NOTE_C6, 1,
|
|
||||||
BUZZER_NOTE_G5SHARP_A5FLAT, 1,
|
|
||||||
BUZZER_NOTE_C6, 1,
|
|
||||||
BUZZER_NOTE_G5SHARP_A5FLAT, 1,
|
|
||||||
BUZZER_NOTE_C6, 1,
|
|
||||||
BUZZER_NOTE_REST, 6,
|
|
||||||
BUZZER_NOTE_G5SHARP_A5FLAT, 1,
|
|
||||||
BUZZER_NOTE_C6, 1,
|
|
||||||
BUZZER_NOTE_G5SHARP_A5FLAT, 1,
|
|
||||||
BUZZER_NOTE_C6, 1,
|
|
||||||
BUZZER_NOTE_G5SHARP_A5FLAT, 1,
|
|
||||||
BUZZER_NOTE_C6, 1,
|
|
||||||
BUZZER_NOTE_G5SHARP_A5FLAT, 1,
|
|
||||||
BUZZER_NOTE_C6, 1,
|
|
||||||
BUZZER_NOTE_G5SHARP_A5FLAT, 1,
|
|
||||||
BUZZER_NOTE_C6, 1,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
#endif // SIGNAL_TUNE_MGS_CODEC
|
|
||||||
|
|
||||||
#ifdef SIGNAL_TUNE_KIM_POSSIBLE
|
#ifdef SIGNAL_TUNE_KIM_POSSIBLE
|
||||||
int8_t signal_tune[] = {
|
int8_t signal_tune[] = {
|
||||||
BUZZER_NOTE_G7, 6,
|
BUZZER_NOTE_G7, 6,
|
||||||
BUZZER_NOTE_G4, 2,
|
BUZZER_NOTE_REST, 1,
|
||||||
|
BUZZER_NOTE_G4, 3,
|
||||||
BUZZER_NOTE_REST, 5,
|
BUZZER_NOTE_REST, 5,
|
||||||
BUZZER_NOTE_G7, 6,
|
BUZZER_NOTE_G7, 6,
|
||||||
BUZZER_NOTE_G4, 2,
|
BUZZER_NOTE_REST, 1,
|
||||||
|
BUZZER_NOTE_G4, 3,
|
||||||
BUZZER_NOTE_REST, 5,
|
BUZZER_NOTE_REST, 5,
|
||||||
BUZZER_NOTE_A7SHARP_B7FLAT, 6,
|
BUZZER_NOTE_A7SHARP_B7FLAT, 6,
|
||||||
BUZZER_NOTE_REST, 2,
|
BUZZER_NOTE_REST, 2,
|
||||||
BUZZER_NOTE_G7, 6,
|
BUZZER_NOTE_G7, 6,
|
||||||
BUZZER_NOTE_G4, 2,
|
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
#endif // SIGNAL_TUNE_KIM_POSSIBLE
|
#endif // SIGNAL_TUNE_KIM_POSSIBLE
|
||||||
|
|
||||||
#ifdef SIGNAL_TUNE_POWER_RANGERS
|
|
||||||
int8_t signal_tune[] = {
|
|
||||||
BUZZER_NOTE_D8, 6,
|
|
||||||
BUZZER_NOTE_REST, 8,
|
|
||||||
BUZZER_NOTE_D8, 6,
|
|
||||||
BUZZER_NOTE_REST, 8,
|
|
||||||
BUZZER_NOTE_C8, 6,
|
|
||||||
BUZZER_NOTE_REST, 2,
|
|
||||||
BUZZER_NOTE_D8, 6,
|
|
||||||
BUZZER_NOTE_REST, 8,
|
|
||||||
BUZZER_NOTE_F8, 6,
|
|
||||||
BUZZER_NOTE_REST, 8,
|
|
||||||
BUZZER_NOTE_D8, 6,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
#endif // SIGNAL_TUNE_POWER_RANGERS
|
|
||||||
|
|
||||||
#ifdef SIGNAL_TUNE_LAYLA
|
|
||||||
int8_t signal_tune[] = {
|
|
||||||
BUZZER_NOTE_A6, 5,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_C7, 5,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_D7, 5,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_F7, 5,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_D7, 5,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_C7, 5,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_D7, 20,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
#endif // SIGNAL_TUNE_LAYLA
|
|
||||||
|
|
||||||
#ifdef SIGNAL_TUNE_HARRY_POTTER_SHORT
|
|
||||||
int8_t signal_tune[] = {
|
|
||||||
BUZZER_NOTE_B5, 12,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_E6, 12,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_G6, 6,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_F6SHARP_G6FLAT, 6,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_E6, 16,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_B6, 8,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_A6, 24,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_F6SHARP_G6FLAT, 24,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
#endif // SIGNAL_TUNE_HARRY_POTTER_SHORT
|
|
||||||
|
|
||||||
#ifdef SIGNAL_TUNE_HARRY_POTTER_LONG
|
|
||||||
int8_t signal_tune[] = {
|
|
||||||
BUZZER_NOTE_B5, 12,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_E6, 12,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_G6, 6,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_F6SHARP_G6FLAT, 6,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_E6, 16,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_B6, 8,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_A6, 24,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_F6SHARP_G6FLAT, 24,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
|
|
||||||
BUZZER_NOTE_E6, 12,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_G6, 6,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_F6SHARP_G6FLAT, 6,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_D6SHARP_E6FLAT, 16,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_F6, 8,
|
|
||||||
BUZZER_NOTE_REST, 1,
|
|
||||||
BUZZER_NOTE_B5, 24,
|
|
||||||
|
|
||||||
0
|
|
||||||
};
|
|
||||||
#endif // SIGNAL_TUNE_HARRY_POTTER_LONG
|
|
||||||
|
|
||||||
#endif // MOVEMENT_CUSTOM_SIGNAL_TUNES_H_
|
#endif // MOVEMENT_CUSTOM_SIGNAL_TUNES_H_
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
#define MOVEMENT_FACES_H_
|
#define MOVEMENT_FACES_H_
|
||||||
|
|
||||||
#include "simple_clock_face.h"
|
#include "simple_clock_face.h"
|
||||||
#include "close_enough_clock_face.h"
|
|
||||||
#include "clock_face.h"
|
#include "clock_face.h"
|
||||||
#include "world_clock_face.h"
|
#include "world_clock_face.h"
|
||||||
#include "preferences_face.h"
|
#include "preferences_face.h"
|
||||||
@ -94,7 +93,6 @@
|
|||||||
#include "geomancy_face.h"
|
#include "geomancy_face.h"
|
||||||
#include "dual_timer_face.h"
|
#include "dual_timer_face.h"
|
||||||
#include "simple_clock_bin_led_face.h"
|
#include "simple_clock_bin_led_face.h"
|
||||||
#include "menstrual_cycle_face.h"
|
|
||||||
#include "flashlight_face.h"
|
#include "flashlight_face.h"
|
||||||
#include "decimal_time_face.h"
|
#include "decimal_time_face.h"
|
||||||
#include "wyoscan_face.h"
|
#include "wyoscan_face.h"
|
||||||
@ -105,25 +103,7 @@
|
|||||||
#include "couch_to_5k_face.h"
|
#include "couch_to_5k_face.h"
|
||||||
#include "minute_repeater_decimal_face.h"
|
#include "minute_repeater_decimal_face.h"
|
||||||
#include "tuning_tones_face.h"
|
#include "tuning_tones_face.h"
|
||||||
#include "minmax_face.h"
|
|
||||||
#include "kitchen_conversions_face.h"
|
#include "kitchen_conversions_face.h"
|
||||||
#include "butterfly_game_face.h"
|
|
||||||
#include "wareki_face.h"
|
|
||||||
#include "wordle_face.h"
|
|
||||||
#include "endless_runner_face.h"
|
|
||||||
#include "periodic_face.h"
|
|
||||||
#include "deadline_face.h"
|
|
||||||
#include "higher_lower_game_face.h"
|
|
||||||
#include "french_revolutionary_face.h"
|
|
||||||
#include "minimal_clock_face.h"
|
|
||||||
#include "simon_face.h"
|
|
||||||
#include "simple_calculator_face.h"
|
|
||||||
#include "alarm_thermometer_face.h"
|
|
||||||
#include "beeps_face.h"
|
|
||||||
#include "accel_interrupt_count_face.h"
|
|
||||||
#include "metronome_face.h"
|
|
||||||
#include "smallchess_face.h"
|
|
||||||
#include "moonrise_face.h"
|
|
||||||
// New includes go above this line.
|
// New includes go above this line.
|
||||||
|
|
||||||
#endif // MOVEMENT_FACES_H_
|
#endif // MOVEMENT_FACES_H_
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#if __EMSCRIPTEN__
|
#if __EMSCRIPTEN__
|
||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
@ -58,7 +57,7 @@ static char *prv_skip_whitespace(char *c) {
|
|||||||
if (*c == 0) {
|
if (*c == 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if ((!isspace((int) *c)) != 0) {
|
if (!isspace((int) *c) != 0) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
c++;
|
c++;
|
||||||
|
@ -85,13 +85,6 @@ shell_command_t g_shell_commands[] = {
|
|||||||
.max_args = 1,
|
.max_args = 1,
|
||||||
.cb = filesystem_cmd_rm,
|
.cb = filesystem_cmd_rm,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.name = "format",
|
|
||||||
.help = "usage: format YES",
|
|
||||||
.min_args = 1,
|
|
||||||
.max_args = 1,
|
|
||||||
.cb = filesystem_cmd_format,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
.name = "echo",
|
.name = "echo",
|
||||||
.help = "usage: echo TEXT {>,>>} FILE",
|
.help = "usage: echo TEXT {>,>>} FILE",
|
||||||
@ -163,3 +156,4 @@ static int stress_cmd(int argc, char *argv[]) {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,10 @@
|
|||||||
#define CLOCK_FACE_LOW_BATTERY_VOLTAGE_THRESHOLD 2200
|
#define CLOCK_FACE_LOW_BATTERY_VOLTAGE_THRESHOLD 2200
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CLOCK_FACE_24H_ONLY
|
||||||
|
#define CLOCK_FACE_24H_ONLY 0
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct {
|
struct {
|
||||||
watch_date_time previous;
|
watch_date_time previous;
|
||||||
@ -53,15 +57,8 @@ typedef struct {
|
|||||||
} clock_state_t;
|
} clock_state_t;
|
||||||
|
|
||||||
static bool clock_is_in_24h_mode(movement_settings_t *settings) {
|
static bool clock_is_in_24h_mode(movement_settings_t *settings) {
|
||||||
#ifdef CLOCK_FACE_24H_ONLY
|
if (CLOCK_FACE_24H_ONLY) { return true; }
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
return settings->bit.clock_mode_24h;
|
return settings->bit.clock_mode_24h;
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool clock_should_set_leading_zero(movement_settings_t *settings) {
|
|
||||||
return clock_is_in_24h_mode(settings) && settings->bit.clock_24h_leading_zero;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clock_indicate(WatchIndicatorSegment indicator, bool on) {
|
static void clock_indicate(WatchIndicatorSegment indicator, bool on) {
|
||||||
@ -73,11 +70,11 @@ static void clock_indicate(WatchIndicatorSegment indicator, bool on) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void clock_indicate_alarm(movement_settings_t *settings) {
|
static void clock_indicate_alarm(movement_settings_t *settings) {
|
||||||
clock_indicate(WATCH_INDICATOR_SIGNAL, settings->bit.alarm_enabled);
|
clock_indicate(WATCH_INDICATOR_BELL, settings->bit.alarm_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clock_indicate_time_signal(clock_state_t *clock) {
|
static void clock_indicate_time_signal(clock_state_t *clock) {
|
||||||
clock_indicate(WATCH_INDICATOR_BELL, clock->time_signal_enabled);
|
clock_indicate(WATCH_INDICATOR_SIGNAL, clock->time_signal_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clock_indicate_24h(movement_settings_t *settings) {
|
static void clock_indicate_24h(movement_settings_t *settings) {
|
||||||
@ -128,13 +125,13 @@ static void clock_toggle_time_signal(clock_state_t *clock) {
|
|||||||
clock_indicate_time_signal(clock);
|
clock_indicate_time_signal(clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clock_display_all(watch_date_time date_time, bool leading_zero) {
|
static void clock_display_all(watch_date_time date_time) {
|
||||||
char buf[10 + 1];
|
char buf[10 + 1];
|
||||||
|
|
||||||
snprintf(
|
snprintf(
|
||||||
buf,
|
buf,
|
||||||
sizeof(buf),
|
sizeof(buf),
|
||||||
leading_zero? "%s%02d%02d%02d%02d" : "%s%2d%2d%02d%02d",
|
"%s%2d%2d%02d%02d",
|
||||||
watch_utility_get_weekday(date_time),
|
watch_utility_get_weekday(date_time),
|
||||||
date_time.unit.day,
|
date_time.unit.day,
|
||||||
date_time.unit.hour,
|
date_time.unit.hour,
|
||||||
@ -184,7 +181,7 @@ static void clock_display_clock(movement_settings_t *settings, clock_state_t *cl
|
|||||||
clock_indicate_pm(settings, current);
|
clock_indicate_pm(settings, current);
|
||||||
current = clock_24h_to_12h(current);
|
current = clock_24h_to_12h(current);
|
||||||
}
|
}
|
||||||
clock_display_all(current, clock_should_set_leading_zero(settings));
|
clock_display_all(current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,233 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2024 Ruben Nic
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include "close_enough_clock_face.h"
|
|
||||||
#include "watch.h"
|
|
||||||
#include "watch_utility.h"
|
|
||||||
|
|
||||||
const char *words[12] = {
|
|
||||||
" ",
|
|
||||||
" 5",
|
|
||||||
"10",
|
|
||||||
"15",
|
|
||||||
"20",
|
|
||||||
"25",
|
|
||||||
"30",
|
|
||||||
"35",
|
|
||||||
"40",
|
|
||||||
"45",
|
|
||||||
"50",
|
|
||||||
"55",
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char *past_word = " P";
|
|
||||||
static const char *to_word = " 2";
|
|
||||||
static const char *oclock_word = "OC";
|
|
||||||
|
|
||||||
// sets when in the five minute period we switch
|
|
||||||
// from "X past HH" to "X to HH+1"
|
|
||||||
static const int hour_switch_index = 8;
|
|
||||||
|
|
||||||
static void _update_alarm_indicator(bool settings_alarm_enabled, close_enough_clock_state_t *state) {
|
|
||||||
state->alarm_enabled = settings_alarm_enabled;
|
|
||||||
if (state->alarm_enabled) {
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
} else {
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void close_enough_clock_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
|
||||||
(void) settings;
|
|
||||||
(void) watch_face_index;
|
|
||||||
|
|
||||||
if (*context_ptr == NULL) {
|
|
||||||
*context_ptr = malloc(sizeof(close_enough_clock_state_t));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void close_enough_clock_face_activate(movement_settings_t *settings, void *context) {
|
|
||||||
close_enough_clock_state_t *state = (close_enough_clock_state_t *)context;
|
|
||||||
|
|
||||||
if (watch_tick_animation_is_running()) {
|
|
||||||
watch_stop_tick_animation();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (settings->bit.clock_mode_24h) {
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_24H);
|
|
||||||
}
|
|
||||||
|
|
||||||
// show alarm indicator if there is an active alarm
|
|
||||||
_update_alarm_indicator(settings->bit.alarm_enabled, state);
|
|
||||||
|
|
||||||
// this ensures that none of the five_minute_periods will match, so we always rerender when the face activates
|
|
||||||
state->prev_five_minute_period = -1;
|
|
||||||
state->prev_min_checked = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool close_enough_clock_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
|
||||||
close_enough_clock_state_t *state = (close_enough_clock_state_t *)context;
|
|
||||||
|
|
||||||
char buf[11];
|
|
||||||
watch_date_time date_time;
|
|
||||||
bool show_next_hour = false;
|
|
||||||
int prev_five_minute_period;
|
|
||||||
int prev_min_checked;
|
|
||||||
int close_enough_hour;
|
|
||||||
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
case EVENT_TICK:
|
|
||||||
case EVENT_LOW_ENERGY_UPDATE:
|
|
||||||
date_time = watch_rtc_get_date_time();
|
|
||||||
prev_five_minute_period = state->prev_five_minute_period;
|
|
||||||
prev_min_checked = state->prev_min_checked;
|
|
||||||
|
|
||||||
// check the battery voltage once a day...
|
|
||||||
if (date_time.unit.day != state->last_battery_check) {
|
|
||||||
state->last_battery_check = date_time.unit.day;
|
|
||||||
watch_enable_adc();
|
|
||||||
uint16_t voltage = watch_get_vcc_voltage();
|
|
||||||
watch_disable_adc();
|
|
||||||
// 2.2 volts will happen when the battery has maybe 5-10% remaining?
|
|
||||||
// we can refine this later.
|
|
||||||
state->battery_low = (voltage < 2200);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...and set the LAP indicator if low.
|
|
||||||
if (state->battery_low) {
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_LAP);
|
|
||||||
}
|
|
||||||
|
|
||||||
// same minute, skip update
|
|
||||||
if (date_time.unit.minute == prev_min_checked) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
state->prev_min_checked = date_time.unit.minute;
|
|
||||||
}
|
|
||||||
|
|
||||||
int five_minute_period = (date_time.unit.minute / 5) % 12;
|
|
||||||
|
|
||||||
// If we are 60% to the next 5 interval, move up to the next period
|
|
||||||
if (fmodf(date_time.unit.minute / 5.0f, 1.0f) > 0.5f) {
|
|
||||||
// If we are on the last 5 interval and moving to the next period we need to display the next hour because we are wrapping around
|
|
||||||
if (five_minute_period == 11) {
|
|
||||||
show_next_hour = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
five_minute_period = (five_minute_period + 1) % 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
// same five_minute_period, skip update
|
|
||||||
if (five_minute_period == prev_five_minute_period) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we don't want to modify date_time.unit.hour just in case other watch faces use it
|
|
||||||
close_enough_hour = date_time.unit.hour;
|
|
||||||
|
|
||||||
// move from "MM(mins) P HH" to "MM(mins) 2 HH+1"
|
|
||||||
if (five_minute_period >= hour_switch_index || show_next_hour) {
|
|
||||||
close_enough_hour = (close_enough_hour + 1) % 24;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!settings->bit.clock_mode_24h) {
|
|
||||||
// if we are in 12 hour mode, do some cleanup.
|
|
||||||
if (close_enough_hour < 12) {
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_PM);
|
|
||||||
} else {
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_PM);
|
|
||||||
}
|
|
||||||
|
|
||||||
close_enough_hour %= 12;
|
|
||||||
if (close_enough_hour == 0) {
|
|
||||||
close_enough_hour = 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
date_time.unit.hour %= 12;
|
|
||||||
if (date_time.unit.hour == 0) {
|
|
||||||
date_time.unit.hour = 12;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char first_word[3];
|
|
||||||
char second_word[3];
|
|
||||||
char third_word[3];
|
|
||||||
if (five_minute_period == 0) { // "HH OC",
|
|
||||||
sprintf(first_word, "%2d", close_enough_hour);
|
|
||||||
strncpy(second_word, words[five_minute_period], 3);
|
|
||||||
strncpy(third_word, oclock_word, 3);
|
|
||||||
} else {
|
|
||||||
int words_length = sizeof(words) / sizeof(words[0]);
|
|
||||||
|
|
||||||
strncpy(
|
|
||||||
first_word,
|
|
||||||
five_minute_period >= hour_switch_index ?
|
|
||||||
words[words_length - five_minute_period] :
|
|
||||||
words[five_minute_period],
|
|
||||||
3
|
|
||||||
);
|
|
||||||
strncpy(
|
|
||||||
second_word,
|
|
||||||
five_minute_period >= hour_switch_index ?
|
|
||||||
to_word : past_word,
|
|
||||||
3
|
|
||||||
);
|
|
||||||
sprintf(third_word, "%2d", close_enough_hour);
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(
|
|
||||||
buf,
|
|
||||||
"%s%2d%s%s%s",
|
|
||||||
watch_utility_get_weekday(date_time),
|
|
||||||
date_time.unit.day,
|
|
||||||
first_word,
|
|
||||||
second_word,
|
|
||||||
third_word
|
|
||||||
);
|
|
||||||
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
state->prev_five_minute_period = five_minute_period;
|
|
||||||
|
|
||||||
// handle alarm indicator
|
|
||||||
if (state->alarm_enabled != settings->bit.alarm_enabled) {
|
|
||||||
_update_alarm_indicator(settings->bit.alarm_enabled, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return movement_default_loop_handler(event, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void close_enough_clock_face_resign(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
(void) context;
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2024 Ruben Nic
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CLOSE_ENOUGH_CLOCK_FACE_H_
|
|
||||||
#define CLOSE_ENOUGH_CLOCK_FACE_H_
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CLOSE ENOUGH CLOCK FACE
|
|
||||||
*
|
|
||||||
* Displays the current time; but only in periods of 5.
|
|
||||||
* Just in the in the formats of:
|
|
||||||
* - "10 past 5"
|
|
||||||
* - "15 to 7"
|
|
||||||
* - "6 o'clock"
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "movement.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int prev_five_minute_period;
|
|
||||||
int prev_min_checked;
|
|
||||||
uint8_t last_battery_check;
|
|
||||||
bool battery_low;
|
|
||||||
bool alarm_enabled;
|
|
||||||
} close_enough_clock_state_t;
|
|
||||||
|
|
||||||
void close_enough_clock_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
|
||||||
void close_enough_clock_face_activate(movement_settings_t *settings, void *context);
|
|
||||||
bool close_enough_clock_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
|
||||||
void close_enough_clock_face_resign(movement_settings_t *settings, void *context);
|
|
||||||
|
|
||||||
#define close_enough_clock_face ((const watch_face_t){ \
|
|
||||||
close_enough_clock_face_setup, \
|
|
||||||
close_enough_clock_face_activate, \
|
|
||||||
close_enough_clock_face_loop, \
|
|
||||||
close_enough_clock_face_resign, \
|
|
||||||
NULL, \
|
|
||||||
})
|
|
||||||
|
|
||||||
#endif // CLOSE_ENOUGH_CLOCK_FACE_H_
|
|
@ -1,245 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 CarpeNoctem
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "french_revolutionary_face.h"
|
|
||||||
|
|
||||||
void french_revolutionary_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
|
||||||
(void) settings;
|
|
||||||
(void) watch_face_index;
|
|
||||||
if (*context_ptr == NULL) {
|
|
||||||
*context_ptr = malloc(sizeof(french_revolutionary_state_t));
|
|
||||||
memset(*context_ptr, 0, sizeof(french_revolutionary_state_t));
|
|
||||||
// Do any one-time tasks in here; the inside of this conditional happens only at boot.
|
|
||||||
french_revolutionary_state_t *state = (french_revolutionary_state_t *)*context_ptr;
|
|
||||||
state->use_am_pm = false;
|
|
||||||
state->show_seconds = true;
|
|
||||||
state->display_type = 0;
|
|
||||||
state->colon_set_after_splash = false;
|
|
||||||
}
|
|
||||||
// Do any pin or peripheral setup here; this will be called whenever the watch wakes from deep sleep.
|
|
||||||
}
|
|
||||||
|
|
||||||
void french_revolutionary_face_activate(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
french_revolutionary_state_t *state = (french_revolutionary_state_t *)context;
|
|
||||||
|
|
||||||
// Handle any tasks related to your watch face coming on screen.
|
|
||||||
state->colon_set_after_splash = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool french_revolutionary_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
|
||||||
french_revolutionary_state_t *state = (french_revolutionary_state_t *)context;
|
|
||||||
|
|
||||||
char buf[11];
|
|
||||||
watch_date_time date_time;
|
|
||||||
fr_decimal_time decimal_time;
|
|
||||||
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
// Initial UI - Show a quick "splash screen"
|
|
||||||
watch_clear_display();
|
|
||||||
watch_display_string("FR dECimL", 0);
|
|
||||||
break;
|
|
||||||
case EVENT_TICK:
|
|
||||||
case EVENT_LOW_ENERGY_UPDATE:
|
|
||||||
|
|
||||||
date_time = watch_rtc_get_date_time();
|
|
||||||
|
|
||||||
decimal_time = get_decimal_time(&date_time);
|
|
||||||
|
|
||||||
set_display_buffer(buf, state, &decimal_time, &date_time);
|
|
||||||
|
|
||||||
// If we're in low-energy mode, don't write out the seconds. Also start the LE tick animation if it's not already going.
|
|
||||||
if (event.event_type == EVENT_LOW_ENERGY_UPDATE) {
|
|
||||||
buf[8] = ' ';
|
|
||||||
buf[9] = ' ';
|
|
||||||
if (!watch_tick_animation_is_running()) { watch_start_tick_animation(500); }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the display with our decimal time
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
|
|
||||||
// Oh, and a one-off to set the colon after the "splash screen"
|
|
||||||
if (!state->colon_set_after_splash) {
|
|
||||||
watch_set_colon();
|
|
||||||
state->colon_set_after_splash = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_BUTTON_UP:
|
|
||||||
state->display_type += 1 ; // cycle through the display types
|
|
||||||
if (state->display_type > 2) { state->display_type = 0; } // but return to 0 after 2
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_LONG_PRESS:
|
|
||||||
// I originally had chiming on the decimal-hour enabled, and this would enable/disable that chime, just like on
|
|
||||||
// the simple clock and decimal time faces. But because decimal seconds don't always line up with normal seconds,
|
|
||||||
// I assume the (decimal-)hourly chime could sometimes be missed. Additionally, I need this button for other purposes,
|
|
||||||
// now that I added seconds on/off toggle and upper normal-time with the ability to toggle that between 12/24hr format.
|
|
||||||
state->show_seconds = !state->show_seconds;
|
|
||||||
if (!state->show_seconds) { watch_display_string(" ", 8); }
|
|
||||||
else { watch_display_string("--", 8); }
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_LONG_PRESS:
|
|
||||||
// In case anyone really wants that upper time in 12-hour format. I thought about using the global setting (settings->bit.clock_mode_24h)
|
|
||||||
// for this preference, but thought someone who prefers 12-hour format normally, might prefer 24hr when compared to a 10hr decimal day,
|
|
||||||
// so this is separate for now.
|
|
||||||
state->use_am_pm = !state->use_am_pm;
|
|
||||||
if (state->use_am_pm) {
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_24H);
|
|
||||||
date_time = watch_rtc_get_date_time();
|
|
||||||
if (date_time.unit.hour < 12) { watch_clear_indicator(WATCH_INDICATOR_PM); }
|
|
||||||
else { watch_set_indicator(WATCH_INDICATOR_PM); }
|
|
||||||
} else {
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_PM);
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_24H);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Movement's default loop handler will step in for any cases you don't handle above:
|
|
||||||
// * EVENT_LIGHT_BUTTON_DOWN lights the LED
|
|
||||||
// * EVENT_MODE_BUTTON_UP moves to the next watch face in the list
|
|
||||||
// * EVENT_MODE_LONG_PRESS returns to the first watch face (or skips to the secondary watch face, if configured)
|
|
||||||
// You can override any of these behaviors by adding a case for these events to this switch statement.
|
|
||||||
return movement_default_loop_handler(event, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
// return true if the watch can enter standby mode. Generally speaking, you should always return true.
|
|
||||||
// Exceptions:
|
|
||||||
// * If you are displaying a color using the low-level watch_set_led_color function, you should return false.
|
|
||||||
// * If you are sounding the buzzer using the low-level watch_set_buzzer_on function, you should return false.
|
|
||||||
// Note that if you are driving the LED or buzzer using Movement functions like movement_illuminate_led or
|
|
||||||
// movement_play_alarm, you can still return true. This guidance only applies to the low-level watch_ functions.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void french_revolutionary_face_resign(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
(void) context;
|
|
||||||
|
|
||||||
// handle any cleanup before your watch face goes off-screen.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate decimal time from normal (24hr) time
|
|
||||||
fr_decimal_time get_decimal_time(watch_date_time *date_time) {
|
|
||||||
uint32_t current_24hr_secs, current_decimal_seconds;
|
|
||||||
fr_decimal_time decimal_time;
|
|
||||||
// Current 24-hr time in seconds (There are 86400 of these in a day.)
|
|
||||||
current_24hr_secs = date_time->unit.hour * 3600 + date_time->unit.minute * 60 + date_time->unit.second;
|
|
||||||
|
|
||||||
// Current Decimal Time in seconds. There are 100000 seconds in a 10-hr decimal-time day.
|
|
||||||
// current_decimal_seconds = current_24hr_seconds * 100000 / 86400, or = current_24_seconds * 1000 / 864;
|
|
||||||
// By chopping the extra zeros off the end, we can use uint32 instead of uint64.
|
|
||||||
current_decimal_seconds = current_24hr_secs * 1000 / 864;
|
|
||||||
|
|
||||||
decimal_time.hour = current_decimal_seconds / 10000;
|
|
||||||
// Remove the hours from total seconds and keep the remainder for below.
|
|
||||||
current_decimal_seconds = current_decimal_seconds - decimal_time.hour * 10000;
|
|
||||||
|
|
||||||
decimal_time.minute = current_decimal_seconds / 100;
|
|
||||||
// Remove the minutes from total seconds and keep the remaining seconds
|
|
||||||
// Note: I think I used an extra seconds variable here because sprintf or movement weren't liking a uint32...
|
|
||||||
decimal_time.second = current_decimal_seconds - decimal_time.minute * 100;
|
|
||||||
return decimal_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fills in the display buffer, depending on the currently-selected display option (and sub-options):
|
|
||||||
// - Decimal-time only
|
|
||||||
// - Decimal-time with date in top-right
|
|
||||||
// - Decimal-time with normal time in the top (minutes first, then hours, due to display limitations)
|
|
||||||
// TODO: There is some power-saving stuff that simple clock does here around not redrawing characters that haven't changed, but we're not doing that here.
|
|
||||||
// I'll try to add that optimization could be added in a future commit.
|
|
||||||
void set_display_buffer(char *buf, french_revolutionary_state_t *state, fr_decimal_time *decimal_time, watch_date_time *date_time) {
|
|
||||||
switch (state->display_type) {
|
|
||||||
// Decimal time only
|
|
||||||
case 0:
|
|
||||||
// Originally I had the day slot set to "FR" (French Revolutionary time), but my brain kept thinking "Friday" whenever I saw it,
|
|
||||||
// so I changed it to dT (Decimal Time) to avoid that confusion. Apologies to anyone who has the other decimal_time face and this one
|
|
||||||
// installed concurrently. Maybe the splash screen will help a little.
|
|
||||||
sprintf( buf, "dT %2d%02d%02d", decimal_time->hour, decimal_time->minute, decimal_time->second );
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_PM);
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_24H);
|
|
||||||
break;
|
|
||||||
// Decimal time and date
|
|
||||||
case 1:
|
|
||||||
sprintf( buf, "dT%2d%2d%02d%02d", date_time->unit.day, decimal_time->hour, decimal_time->minute, decimal_time->second );
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_PM);
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_24H);
|
|
||||||
break;
|
|
||||||
// Decimal time on bottom, normal time above
|
|
||||||
case 2:
|
|
||||||
if (state->use_am_pm) {
|
|
||||||
// if we are in 12 hour mode, do some cleanup.
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_24H);
|
|
||||||
if (date_time->unit.hour < 12) {
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_PM);
|
|
||||||
} else {
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_PM);
|
|
||||||
}
|
|
||||||
date_time->unit.hour %= 12;
|
|
||||||
if (date_time->unit.hour == 0) date_time->unit.hour = 12;
|
|
||||||
} else {
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_PM);
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_24H);
|
|
||||||
}
|
|
||||||
// Note, the date digits don't display a leading zero well, so we don't use it.
|
|
||||||
sprintf( buf, "%02d%2d%2d%02d%02d", date_time->unit.minute, date_time->unit.hour, decimal_time->hour, decimal_time->minute, decimal_time->second );
|
|
||||||
|
|
||||||
// Make the second character of the Day area more readable
|
|
||||||
buf[1] = fix_character_one(buf[1]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Finally, if show_seconds is disabled, trim those off.
|
|
||||||
if (!state->show_seconds) {
|
|
||||||
buf[8] = ' ';
|
|
||||||
buf[9] = ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sadly, the second character of the Day field cannot show all numbers, so we make some replacements.
|
|
||||||
// See https://www.sensorwatch.net/docs/wig/display/#limitations-of-the-weekday-digits
|
|
||||||
char fix_character_one(char digit) {
|
|
||||||
char return_char = digit; // We don't need to update this for 0, 1, 3, 7 and 8.
|
|
||||||
switch(digit) {
|
|
||||||
case '2':
|
|
||||||
// Roman numeral / tally representation of 2
|
|
||||||
return_char = '|'; // Thanks, Joey, for already having this in the character set.
|
|
||||||
break;
|
|
||||||
case '4':
|
|
||||||
// Looks almost like a 4 - just missing the top-left segment.
|
|
||||||
// 0b01000110
|
|
||||||
return_char = '&'; // Slight hack - I want 0b01000110, but 0b01000100 is already in the character set and will do, since B and C segments are linked in this position.
|
|
||||||
break;
|
|
||||||
case '5':
|
|
||||||
return_char = 'F'; // F for Five
|
|
||||||
break;
|
|
||||||
case '6':
|
|
||||||
return_char = 'E'; // Looks almost like a 6 - just missing the bottom-right segment. Not super happy with it, but liked it best of the options I tried.
|
|
||||||
break;
|
|
||||||
case '9':
|
|
||||||
return_char = 'N'; // N for Nine
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return return_char;
|
|
||||||
}
|
|
@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 CarpeNoctem
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FRENCH_REVOLUTIONARY_FACE_H_
|
|
||||||
#define FRENCH_REVOLUTIONARY_FACE_H_
|
|
||||||
|
|
||||||
#include "movement.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* French Revolutionary Decimal Time
|
|
||||||
*
|
|
||||||
* Similar to the Decimal Time face, but with the day divided into ten hours instead of twenty four.
|
|
||||||
* Each hour is divided into one hundred minutes, and those minutes are divided into 100 seconds.
|
|
||||||
* I came across this one the Svalbard watch site here: https://svalbard.watch/pages/about_decimal_time.html
|
|
||||||
* More info here as well: https://en.wikipedia.org/wiki/Decimal_time
|
|
||||||
*
|
|
||||||
* By default, the face just displays the current decimal time. Pressing the alarm button will toggle through other display options:
|
|
||||||
* 1) Just decimal time (with dT indicator at top)
|
|
||||||
* 2) Decimal time, with dT indicator and date above.
|
|
||||||
* 3) Decimal time, with 24-hr time above (where Day and Date would normally be displayed), BUT minutes first then hours.
|
|
||||||
* Sadly, the first character of the date area only goes up to 3 (see https://www.sensorwatch.net/docs/wig/display/#the-day-digits)
|
|
||||||
* I was going to begrudgindly leave this display option out when I realized that, but thought it would be better to have this backwards
|
|
||||||
* representation of the "normal" time than not at all.
|
|
||||||
*
|
|
||||||
* A long-press of the light button will toggle the upper time between 12-hr AM/PM and 24-hr mode. I thought of reading the main setting for this,
|
|
||||||
* but thought that a person could normally prefer 12hr time, but next to a 10hr day want to see the normal time in the 24hr format.
|
|
||||||
*
|
|
||||||
* A long-press of the alarm button will toggle the seconds off and on.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
bool use_am_pm; // Use 12-hr AM/PM for upper display instead of 24-hr? (Default is 24-hr)
|
|
||||||
bool show_seconds;
|
|
||||||
bool colon_set_after_splash;
|
|
||||||
uint8_t display_type : 2;
|
|
||||||
} french_revolutionary_state_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t second : 8; // 0-99
|
|
||||||
uint8_t minute : 8; // 0-99
|
|
||||||
uint8_t hour : 5; // 0-10
|
|
||||||
} fr_decimal_time;
|
|
||||||
|
|
||||||
void french_revolutionary_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
|
||||||
void french_revolutionary_face_activate(movement_settings_t *settings, void *context);
|
|
||||||
bool french_revolutionary_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
|
||||||
void french_revolutionary_face_resign(movement_settings_t *settings, void *context);
|
|
||||||
char fix_character_one(char digit);
|
|
||||||
fr_decimal_time get_decimal_time(watch_date_time *date_time);
|
|
||||||
void set_display_buffer(char *buf, french_revolutionary_state_t *state, fr_decimal_time *decimal_time, watch_date_time *date_time);
|
|
||||||
|
|
||||||
|
|
||||||
#define french_revolutionary_face ((const watch_face_t){ \
|
|
||||||
french_revolutionary_face_setup, \
|
|
||||||
french_revolutionary_face_activate, \
|
|
||||||
french_revolutionary_face_loop, \
|
|
||||||
french_revolutionary_face_resign, \
|
|
||||||
NULL, \
|
|
||||||
})
|
|
||||||
|
|
||||||
#endif // FRENCH_REVOLUTIONARY_FACE_H_
|
|
||||||
|
|
@ -1,117 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Dennisman219
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "minimal_clock_face.h"
|
|
||||||
|
|
||||||
static void _minimal_clock_face_update_display(movement_settings_t *settings) {
|
|
||||||
watch_date_time date_time = watch_rtc_get_date_time();
|
|
||||||
char buffer[11];
|
|
||||||
|
|
||||||
if (!settings->bit.clock_mode_24h) {
|
|
||||||
date_time.unit.hour %= 12;
|
|
||||||
sprintf(buffer, "%2d%02d ", date_time.unit.hour, date_time.unit.minute);
|
|
||||||
} else {
|
|
||||||
sprintf(buffer, "%02d%02d ", date_time.unit.hour, date_time.unit.minute);
|
|
||||||
}
|
|
||||||
|
|
||||||
watch_display_string(buffer, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void minimal_clock_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
|
||||||
(void) settings;
|
|
||||||
(void) watch_face_index;
|
|
||||||
if (*context_ptr == NULL) {
|
|
||||||
*context_ptr = malloc(sizeof(minimal_clock_state_t));
|
|
||||||
memset(*context_ptr, 0, sizeof(minimal_clock_state_t));
|
|
||||||
// Do any one-time tasks in here; the inside of this conditional happens only at boot.
|
|
||||||
}
|
|
||||||
// Do any pin or peripheral setup here; this will be called whenever the watch wakes from deep sleep.
|
|
||||||
}
|
|
||||||
|
|
||||||
void minimal_clock_face_activate(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
(void) context;
|
|
||||||
// Handle any tasks related to your watch face coming on screen.
|
|
||||||
watch_set_colon();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool minimal_clock_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
|
||||||
(void) context;
|
|
||||||
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
// Show your initial UI here.
|
|
||||||
_minimal_clock_face_update_display(settings);
|
|
||||||
break;
|
|
||||||
case EVENT_TICK:
|
|
||||||
// If needed, update your display here.
|
|
||||||
_minimal_clock_face_update_display(settings);
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_UP:
|
|
||||||
// You can use the Light button for your own purposes. Note that by default, Movement will also
|
|
||||||
// illuminate the LED in response to EVENT_LIGHT_BUTTON_DOWN; to suppress that behavior, add an
|
|
||||||
// empty case for EVENT_LIGHT_BUTTON_DOWN.
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_BUTTON_UP:
|
|
||||||
// Just in case you have need for another button.
|
|
||||||
break;
|
|
||||||
case EVENT_TIMEOUT:
|
|
||||||
// Your watch face will receive this event after a period of inactivity. If it makes sense to resign,
|
|
||||||
// you may uncomment this line to move back to the first watch face in the list:
|
|
||||||
// movement_move_to_face(0);
|
|
||||||
break;
|
|
||||||
case EVENT_LOW_ENERGY_UPDATE:
|
|
||||||
// If you did not resign in EVENT_TIMEOUT, you can use this event to update the display once a minute.
|
|
||||||
// Avoid displaying fast-updating values like seconds, since the display won't update again for 60 seconds.
|
|
||||||
// You should also consider starting the tick animation, to show the wearer that this is sleep mode:
|
|
||||||
// watch_start_tick_animation(500);
|
|
||||||
_minimal_clock_face_update_display(settings);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Movement's default loop handler will step in for any cases you don't handle above:
|
|
||||||
// * EVENT_LIGHT_BUTTON_DOWN lights the LED
|
|
||||||
// * EVENT_MODE_BUTTON_UP moves to the next watch face in the list
|
|
||||||
// * EVENT_MODE_LONG_PRESS returns to the first watch face (or skips to the secondary watch face, if configured)
|
|
||||||
// You can override any of these behaviors by adding a case for these events to this switch statement.
|
|
||||||
return movement_default_loop_handler(event, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
// return true if the watch can enter standby mode. Generally speaking, you should always return true.
|
|
||||||
// Exceptions:
|
|
||||||
// * If you are displaying a color using the low-level watch_set_led_color function, you should return false.
|
|
||||||
// * If you are sounding the buzzer using the low-level watch_set_buzzer_on function, you should return false.
|
|
||||||
// Note that if you are driving the LED or buzzer using Movement functions like movement_illuminate_led or
|
|
||||||
// movement_play_alarm, you can still return true. This guidance only applies to the low-level watch_ functions.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void minimal_clock_face_resign(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
(void) context;
|
|
||||||
|
|
||||||
// handle any cleanup before your watch face goes off-screen.
|
|
||||||
}
|
|
||||||
|
|
@ -68,7 +68,7 @@ void repetition_minute_face_activate(movement_settings_t *settings, void *contex
|
|||||||
|
|
||||||
if (watch_tick_animation_is_running()) watch_stop_tick_animation();
|
if (watch_tick_animation_is_running()) watch_stop_tick_animation();
|
||||||
|
|
||||||
if (settings->bit.clock_mode_24h && !settings->bit.clock_24h_leading_zero) watch_set_indicator(WATCH_INDICATOR_24H);
|
if (settings->bit.clock_mode_24h) watch_set_indicator(WATCH_INDICATOR_24H);
|
||||||
|
|
||||||
// handle chime indicator
|
// handle chime indicator
|
||||||
if (state->signal_enabled) watch_set_indicator(WATCH_INDICATOR_BELL);
|
if (state->signal_enabled) watch_set_indicator(WATCH_INDICATOR_BELL);
|
||||||
@ -112,7 +112,6 @@ bool repetition_minute_face_loop(movement_event_t event, movement_settings_t *se
|
|||||||
// ...and set the LAP indicator if low.
|
// ...and set the LAP indicator if low.
|
||||||
if (state->battery_low) watch_set_indicator(WATCH_INDICATOR_LAP);
|
if (state->battery_low) watch_set_indicator(WATCH_INDICATOR_LAP);
|
||||||
|
|
||||||
bool set_leading_zero = false;
|
|
||||||
if ((date_time.reg >> 6) == (previous_date_time >> 6) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
if ((date_time.reg >> 6) == (previous_date_time >> 6) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
||||||
// everything before seconds is the same, don't waste cycles setting those segments.
|
// everything before seconds is the same, don't waste cycles setting those segments.
|
||||||
watch_display_character_lp_seconds('0' + date_time.unit.second / 10, 8);
|
watch_display_character_lp_seconds('0' + date_time.unit.second / 10, 8);
|
||||||
@ -133,8 +132,6 @@ bool repetition_minute_face_loop(movement_event_t event, movement_settings_t *se
|
|||||||
}
|
}
|
||||||
date_time.unit.hour %= 12;
|
date_time.unit.hour %= 12;
|
||||||
if (date_time.unit.hour == 0) date_time.unit.hour = 12;
|
if (date_time.unit.hour == 0) date_time.unit.hour = 12;
|
||||||
} else if (settings->bit.clock_24h_leading_zero && date_time.unit.hour < 10) {
|
|
||||||
set_leading_zero = true;
|
|
||||||
}
|
}
|
||||||
pos = 0;
|
pos = 0;
|
||||||
if (event.event_type == EVENT_LOW_ENERGY_UPDATE) {
|
if (event.event_type == EVENT_LOW_ENERGY_UPDATE) {
|
||||||
@ -145,8 +142,6 @@ bool repetition_minute_face_loop(movement_event_t event, movement_settings_t *se
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
watch_display_string(buf, pos);
|
watch_display_string(buf, pos);
|
||||||
if (set_leading_zero)
|
|
||||||
watch_display_string("0", 4);
|
|
||||||
// handle alarm indicator
|
// handle alarm indicator
|
||||||
if (state->alarm_enabled != settings->bit.alarm_enabled) _update_alarm_indicator(settings->bit.alarm_enabled, state);
|
if (state->alarm_enabled != settings->bit.alarm_enabled) _update_alarm_indicator(settings->bit.alarm_enabled, state);
|
||||||
break;
|
break;
|
||||||
|
@ -60,7 +60,7 @@ void simple_clock_bin_led_face_activate(movement_settings_t *settings, void *con
|
|||||||
|
|
||||||
if (watch_tick_animation_is_running()) watch_stop_tick_animation();
|
if (watch_tick_animation_is_running()) watch_stop_tick_animation();
|
||||||
|
|
||||||
if (settings->bit.clock_mode_24h && !settings->bit.clock_24h_leading_zero) watch_set_indicator(WATCH_INDICATOR_24H);
|
if (settings->bit.clock_mode_24h) watch_set_indicator(WATCH_INDICATOR_24H);
|
||||||
|
|
||||||
// handle chime indicator
|
// handle chime indicator
|
||||||
if (state->signal_enabled) watch_set_indicator(WATCH_INDICATOR_BELL);
|
if (state->signal_enabled) watch_set_indicator(WATCH_INDICATOR_BELL);
|
||||||
@ -138,7 +138,6 @@ bool simple_clock_bin_led_face_loop(movement_event_t event, movement_settings_t
|
|||||||
// ...and set the LAP indicator if low.
|
// ...and set the LAP indicator if low.
|
||||||
if (state->battery_low) watch_set_indicator(WATCH_INDICATOR_LAP);
|
if (state->battery_low) watch_set_indicator(WATCH_INDICATOR_LAP);
|
||||||
|
|
||||||
bool set_leading_zero = false;
|
|
||||||
if ((date_time.reg >> 6) == (previous_date_time >> 6) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
if ((date_time.reg >> 6) == (previous_date_time >> 6) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
||||||
// everything before seconds is the same, don't waste cycles setting those segments.
|
// everything before seconds is the same, don't waste cycles setting those segments.
|
||||||
watch_display_character_lp_seconds('0' + date_time.unit.second / 10, 8);
|
watch_display_character_lp_seconds('0' + date_time.unit.second / 10, 8);
|
||||||
@ -159,8 +158,6 @@ bool simple_clock_bin_led_face_loop(movement_event_t event, movement_settings_t
|
|||||||
}
|
}
|
||||||
date_time.unit.hour %= 12;
|
date_time.unit.hour %= 12;
|
||||||
if (date_time.unit.hour == 0) date_time.unit.hour = 12;
|
if (date_time.unit.hour == 0) date_time.unit.hour = 12;
|
||||||
} else if (settings->bit.clock_24h_leading_zero && date_time.unit.hour < 10) {
|
|
||||||
set_leading_zero = true;
|
|
||||||
}
|
}
|
||||||
pos = 0;
|
pos = 0;
|
||||||
if (event.event_type == EVENT_LOW_ENERGY_UPDATE) {
|
if (event.event_type == EVENT_LOW_ENERGY_UPDATE) {
|
||||||
@ -171,8 +168,6 @@ bool simple_clock_bin_led_face_loop(movement_event_t event, movement_settings_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
watch_display_string(buf, pos);
|
watch_display_string(buf, pos);
|
||||||
if (set_leading_zero)
|
|
||||||
watch_display_string("0", 4);
|
|
||||||
// handle alarm indicator
|
// handle alarm indicator
|
||||||
if (state->alarm_enabled != settings->bit.alarm_enabled) _update_alarm_indicator(settings->bit.alarm_enabled, state);
|
if (state->alarm_enabled != settings->bit.alarm_enabled) _update_alarm_indicator(settings->bit.alarm_enabled, state);
|
||||||
}
|
}
|
||||||
|
@ -51,11 +51,7 @@ void simple_clock_face_activate(movement_settings_t *settings, void *context) {
|
|||||||
|
|
||||||
if (watch_tick_animation_is_running()) watch_stop_tick_animation();
|
if (watch_tick_animation_is_running()) watch_stop_tick_animation();
|
||||||
|
|
||||||
#ifdef CLOCK_FACE_24H_ONLY
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_24H);
|
|
||||||
#else
|
|
||||||
if (settings->bit.clock_mode_24h) watch_set_indicator(WATCH_INDICATOR_24H);
|
if (settings->bit.clock_mode_24h) watch_set_indicator(WATCH_INDICATOR_24H);
|
||||||
#endif
|
|
||||||
|
|
||||||
// handle chime indicator
|
// handle chime indicator
|
||||||
if (state->signal_enabled) watch_set_indicator(WATCH_INDICATOR_BELL);
|
if (state->signal_enabled) watch_set_indicator(WATCH_INDICATOR_BELL);
|
||||||
@ -99,7 +95,6 @@ bool simple_clock_face_loop(movement_event_t event, movement_settings_t *setting
|
|||||||
// ...and set the LAP indicator if low.
|
// ...and set the LAP indicator if low.
|
||||||
if (state->battery_low) watch_set_indicator(WATCH_INDICATOR_LAP);
|
if (state->battery_low) watch_set_indicator(WATCH_INDICATOR_LAP);
|
||||||
|
|
||||||
bool set_leading_zero = false;
|
|
||||||
if ((date_time.reg >> 6) == (previous_date_time >> 6) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
if ((date_time.reg >> 6) == (previous_date_time >> 6) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
||||||
// everything before seconds is the same, don't waste cycles setting those segments.
|
// everything before seconds is the same, don't waste cycles setting those segments.
|
||||||
watch_display_character_lp_seconds('0' + date_time.unit.second / 10, 8);
|
watch_display_character_lp_seconds('0' + date_time.unit.second / 10, 8);
|
||||||
@ -111,7 +106,6 @@ bool simple_clock_face_loop(movement_event_t event, movement_settings_t *setting
|
|||||||
sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second);
|
sprintf(buf, "%02d%02d", date_time.unit.minute, date_time.unit.second);
|
||||||
} else {
|
} else {
|
||||||
// other stuff changed; let's do it all.
|
// other stuff changed; let's do it all.
|
||||||
#ifndef CLOCK_FACE_24H_ONLY
|
|
||||||
if (!settings->bit.clock_mode_24h) {
|
if (!settings->bit.clock_mode_24h) {
|
||||||
// if we are in 12 hour mode, do some cleanup.
|
// if we are in 12 hour mode, do some cleanup.
|
||||||
if (date_time.unit.hour < 12) {
|
if (date_time.unit.hour < 12) {
|
||||||
@ -122,12 +116,6 @@ bool simple_clock_face_loop(movement_event_t event, movement_settings_t *setting
|
|||||||
date_time.unit.hour %= 12;
|
date_time.unit.hour %= 12;
|
||||||
if (date_time.unit.hour == 0) date_time.unit.hour = 12;
|
if (date_time.unit.hour == 0) date_time.unit.hour = 12;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (settings->bit.clock_mode_24h && settings->bit.clock_24h_leading_zero && date_time.unit.hour < 10) {
|
|
||||||
set_leading_zero = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = 0;
|
pos = 0;
|
||||||
if (event.event_type == EVENT_LOW_ENERGY_UPDATE) {
|
if (event.event_type == EVENT_LOW_ENERGY_UPDATE) {
|
||||||
if (!watch_tick_animation_is_running()) watch_start_tick_animation(500);
|
if (!watch_tick_animation_is_running()) watch_start_tick_animation(500);
|
||||||
@ -137,10 +125,6 @@ bool simple_clock_face_loop(movement_event_t event, movement_settings_t *setting
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
watch_display_string(buf, pos);
|
watch_display_string(buf, pos);
|
||||||
|
|
||||||
if (set_leading_zero)
|
|
||||||
watch_display_string("0", 4);
|
|
||||||
|
|
||||||
// handle alarm indicator
|
// handle alarm indicator
|
||||||
if (state->alarm_enabled != settings->bit.alarm_enabled) _update_alarm_indicator(settings->bit.alarm_enabled, state);
|
if (state->alarm_enabled != settings->bit.alarm_enabled) _update_alarm_indicator(settings->bit.alarm_enabled, state);
|
||||||
break;
|
break;
|
||||||
|
@ -50,7 +50,7 @@ void weeknumber_clock_face_activate(movement_settings_t *settings, void *context
|
|||||||
|
|
||||||
if (watch_tick_animation_is_running()) watch_stop_tick_animation();
|
if (watch_tick_animation_is_running()) watch_stop_tick_animation();
|
||||||
|
|
||||||
if (settings->bit.clock_mode_24h && !settings->bit.clock_24h_leading_zero) watch_set_indicator(WATCH_INDICATOR_24H);
|
if (settings->bit.clock_mode_24h) watch_set_indicator(WATCH_INDICATOR_24H);
|
||||||
|
|
||||||
// handle chime indicator
|
// handle chime indicator
|
||||||
if (state->signal_enabled) watch_set_indicator(WATCH_INDICATOR_BELL);
|
if (state->signal_enabled) watch_set_indicator(WATCH_INDICATOR_BELL);
|
||||||
@ -94,7 +94,6 @@ bool weeknumber_clock_face_loop(movement_event_t event, movement_settings_t *set
|
|||||||
// ...and set the LAP indicator if low.
|
// ...and set the LAP indicator if low.
|
||||||
if (state->battery_low) watch_set_indicator(WATCH_INDICATOR_LAP);
|
if (state->battery_low) watch_set_indicator(WATCH_INDICATOR_LAP);
|
||||||
|
|
||||||
bool set_leading_zero = false;
|
|
||||||
if ((date_time.reg >> 12) == (previous_date_time >> 12) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
if ((date_time.reg >> 12) == (previous_date_time >> 12) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
||||||
// everything before minutes is the same.
|
// everything before minutes is the same.
|
||||||
pos = 6;
|
pos = 6;
|
||||||
@ -110,8 +109,6 @@ bool weeknumber_clock_face_loop(movement_event_t event, movement_settings_t *set
|
|||||||
}
|
}
|
||||||
date_time.unit.hour %= 12;
|
date_time.unit.hour %= 12;
|
||||||
if (date_time.unit.hour == 0) date_time.unit.hour = 12;
|
if (date_time.unit.hour == 0) date_time.unit.hour = 12;
|
||||||
} else if (settings->bit.clock_24h_leading_zero && date_time.unit.hour < 10) {
|
|
||||||
set_leading_zero = true;
|
|
||||||
}
|
}
|
||||||
pos = 0;
|
pos = 0;
|
||||||
if (event.event_type == EVENT_LOW_ENERGY_UPDATE) {
|
if (event.event_type == EVENT_LOW_ENERGY_UPDATE) {
|
||||||
@ -122,8 +119,6 @@ bool weeknumber_clock_face_loop(movement_event_t event, movement_settings_t *set
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
watch_display_string(buf, pos);
|
watch_display_string(buf, pos);
|
||||||
if (set_leading_zero)
|
|
||||||
watch_display_string("0", 4);
|
|
||||||
// handle alarm indicator
|
// handle alarm indicator
|
||||||
if (state->alarm_enabled != settings->bit.alarm_enabled) _update_alarm_indicator(settings->bit.alarm_enabled, state);
|
if (state->alarm_enabled != settings->bit.alarm_enabled) _update_alarm_indicator(settings->bit.alarm_enabled, state);
|
||||||
break;
|
break;
|
||||||
|
@ -174,7 +174,7 @@ static bool mode_display(movement_event_t event, movement_settings_t *settings,
|
|||||||
if (refresh_face) {
|
if (refresh_face) {
|
||||||
watch_clear_indicator(WATCH_INDICATOR_SIGNAL);
|
watch_clear_indicator(WATCH_INDICATOR_SIGNAL);
|
||||||
watch_set_colon();
|
watch_set_colon();
|
||||||
if (settings->bit.clock_mode_24h && !settings->bit.clock_24h_leading_zero)
|
if (settings->bit.clock_mode_24h)
|
||||||
watch_set_indicator(WATCH_INDICATOR_24H);
|
watch_set_indicator(WATCH_INDICATOR_24H);
|
||||||
|
|
||||||
state->previous_date_time = REFRESH_TIME;
|
state->previous_date_time = REFRESH_TIME;
|
||||||
@ -188,7 +188,6 @@ static bool mode_display(movement_event_t event, movement_settings_t *settings,
|
|||||||
previous_date_time = state->previous_date_time;
|
previous_date_time = state->previous_date_time;
|
||||||
state->previous_date_time = date_time.reg;
|
state->previous_date_time = date_time.reg;
|
||||||
|
|
||||||
bool set_leading_zero = false;
|
|
||||||
if ((date_time.reg >> 6) == (previous_date_time >> 6) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
if ((date_time.reg >> 6) == (previous_date_time >> 6) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
||||||
/* Everything before seconds is the same, don't waste cycles setting those segments. */
|
/* Everything before seconds is the same, don't waste cycles setting those segments. */
|
||||||
pos = 8;
|
pos = 8;
|
||||||
@ -209,8 +208,6 @@ static bool mode_display(movement_event_t event, movement_settings_t *settings,
|
|||||||
date_time.unit.hour %= 12;
|
date_time.unit.hour %= 12;
|
||||||
if (date_time.unit.hour == 0)
|
if (date_time.unit.hour == 0)
|
||||||
date_time.unit.hour = 12;
|
date_time.unit.hour = 12;
|
||||||
} else if (settings->bit.clock_24h_leading_zero && date_time.unit.hour < 10) {
|
|
||||||
set_leading_zero = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = 0;
|
pos = 0;
|
||||||
@ -233,8 +230,6 @@ static bool mode_display(movement_event_t event, movement_settings_t *settings,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
watch_display_string(buf, pos);
|
watch_display_string(buf, pos);
|
||||||
if (set_leading_zero)
|
|
||||||
watch_display_string("0", 4);
|
|
||||||
break;
|
break;
|
||||||
case EVENT_ALARM_BUTTON_UP:
|
case EVENT_ALARM_BUTTON_UP:
|
||||||
state->current_zone = find_selected_zone(state, FORWARD);
|
state->current_zone = find_selected_zone(state, FORWARD);
|
||||||
|
@ -60,7 +60,7 @@ static bool world_clock_face_do_display_mode(movement_event_t event, movement_se
|
|||||||
watch_date_time date_time;
|
watch_date_time date_time;
|
||||||
switch (event.event_type) {
|
switch (event.event_type) {
|
||||||
case EVENT_ACTIVATE:
|
case EVENT_ACTIVATE:
|
||||||
if (settings->bit.clock_mode_24h && !settings->bit.clock_24h_leading_zero) watch_set_indicator(WATCH_INDICATOR_24H);
|
if (settings->bit.clock_mode_24h) watch_set_indicator(WATCH_INDICATOR_24H);
|
||||||
watch_set_colon();
|
watch_set_colon();
|
||||||
state->previous_date_time = 0xFFFFFFFF;
|
state->previous_date_time = 0xFFFFFFFF;
|
||||||
// fall through
|
// fall through
|
||||||
@ -72,7 +72,6 @@ static bool world_clock_face_do_display_mode(movement_event_t event, movement_se
|
|||||||
previous_date_time = state->previous_date_time;
|
previous_date_time = state->previous_date_time;
|
||||||
state->previous_date_time = date_time.reg;
|
state->previous_date_time = date_time.reg;
|
||||||
|
|
||||||
bool set_leading_zero = false;
|
|
||||||
if ((date_time.reg >> 6) == (previous_date_time >> 6) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
if ((date_time.reg >> 6) == (previous_date_time >> 6) && event.event_type != EVENT_LOW_ENERGY_UPDATE) {
|
||||||
// everything before seconds is the same, don't waste cycles setting those segments.
|
// everything before seconds is the same, don't waste cycles setting those segments.
|
||||||
pos = 8;
|
pos = 8;
|
||||||
@ -92,8 +91,6 @@ static bool world_clock_face_do_display_mode(movement_event_t event, movement_se
|
|||||||
}
|
}
|
||||||
date_time.unit.hour %= 12;
|
date_time.unit.hour %= 12;
|
||||||
if (date_time.unit.hour == 0) date_time.unit.hour = 12;
|
if (date_time.unit.hour == 0) date_time.unit.hour = 12;
|
||||||
} else if (settings->bit.clock_24h_leading_zero && date_time.unit.hour < 10) {
|
|
||||||
set_leading_zero = true;
|
|
||||||
}
|
}
|
||||||
pos = 0;
|
pos = 0;
|
||||||
if (event.event_type == EVENT_LOW_ENERGY_UPDATE) {
|
if (event.event_type == EVENT_LOW_ENERGY_UPDATE) {
|
||||||
@ -115,8 +112,6 @@ static bool world_clock_face_do_display_mode(movement_event_t event, movement_se
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
watch_display_string(buf, pos);
|
watch_display_string(buf, pos);
|
||||||
if (set_leading_zero)
|
|
||||||
watch_display_string("0", 4);
|
|
||||||
break;
|
break;
|
||||||
case EVENT_ALARM_LONG_PRESS:
|
case EVENT_ALARM_LONG_PRESS:
|
||||||
movement_request_tick_frequency(4);
|
movement_request_tick_frequency(4);
|
||||||
|
@ -293,7 +293,6 @@ static void _activity_update_logging_screen(movement_settings_t *settings, activ
|
|||||||
}
|
}
|
||||||
// Briefly, show time without seconds
|
// Briefly, show time without seconds
|
||||||
else {
|
else {
|
||||||
bool set_leading_zero = false;
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_LAP);
|
watch_clear_indicator(WATCH_INDICATOR_LAP);
|
||||||
watch_date_time now = watch_rtc_get_date_time();
|
watch_date_time now = watch_rtc_get_date_time();
|
||||||
uint8_t hour = now.unit.hour;
|
uint8_t hour = now.unit.hour;
|
||||||
@ -305,18 +304,14 @@ static void _activity_update_logging_screen(movement_settings_t *settings, activ
|
|||||||
watch_set_indicator(WATCH_INDICATOR_PM);
|
watch_set_indicator(WATCH_INDICATOR_PM);
|
||||||
hour %= 12;
|
hour %= 12;
|
||||||
if (hour == 0) hour = 12;
|
if (hour == 0) hour = 12;
|
||||||
} else {
|
}
|
||||||
watch_clear_indicator(WATCH_INDICATOR_PM);
|
else {
|
||||||
if (!settings->bit.clock_24h_leading_zero)
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_24H);
|
watch_set_indicator(WATCH_INDICATOR_24H);
|
||||||
else if (hour < 10)
|
watch_clear_indicator(WATCH_INDICATOR_PM);
|
||||||
set_leading_zero = true;
|
|
||||||
}
|
}
|
||||||
sprintf(activity_buf, "%2d%02d ", hour, now.unit.minute);
|
sprintf(activity_buf, "%2d%02d ", hour, now.unit.minute);
|
||||||
watch_set_colon();
|
watch_set_colon();
|
||||||
watch_display_string(activity_buf, 4);
|
watch_display_string(activity_buf, 4);
|
||||||
if (set_leading_zero)
|
|
||||||
watch_display_string("0", 4);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,6 @@ static void _alarm_face_draw(movement_settings_t *settings, alarm_state_t *state
|
|||||||
i = state->alarm[state->alarm_idx].day + 1;
|
i = state->alarm[state->alarm_idx].day + 1;
|
||||||
}
|
}
|
||||||
//handle am/pm for hour display
|
//handle am/pm for hour display
|
||||||
bool set_leading_zero = false;
|
|
||||||
uint8_t h = state->alarm[state->alarm_idx].hour;
|
uint8_t h = state->alarm[state->alarm_idx].hour;
|
||||||
if (!settings->bit.clock_mode_24h) {
|
if (!settings->bit.clock_mode_24h) {
|
||||||
if (h >= 12) {
|
if (h >= 12) {
|
||||||
@ -82,17 +81,8 @@ static void _alarm_face_draw(movement_settings_t *settings, alarm_state_t *state
|
|||||||
watch_clear_indicator(WATCH_INDICATOR_PM);
|
watch_clear_indicator(WATCH_INDICATOR_PM);
|
||||||
}
|
}
|
||||||
if (h == 0) h = 12;
|
if (h == 0) h = 12;
|
||||||
} else {
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_24H);
|
|
||||||
|
|
||||||
if (settings->bit.clock_24h_leading_zero) {
|
|
||||||
if (h < 10) {
|
|
||||||
set_leading_zero = true;
|
|
||||||
}
|
}
|
||||||
}
|
sprintf(buf, "%c%c%2d%2d%02d ",
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(buf, set_leading_zero? "%c%c%2d%02d%02d " : "%c%c%2d%2d%02d ",
|
|
||||||
_dow_strings[i][0], _dow_strings[i][1],
|
_dow_strings[i][0], _dow_strings[i][1],
|
||||||
(state->alarm_idx + 1),
|
(state->alarm_idx + 1),
|
||||||
h,
|
h,
|
||||||
|
@ -1,467 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Hugo Chargois
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Emulator only: need time() to seed the random number generator
|
|
||||||
#if __EMSCRIPTEN__
|
|
||||||
#include <time.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "butterfly_game_face.h"
|
|
||||||
|
|
||||||
static char butterfly_shapes[][3] = {
|
|
||||||
"[]", "][", "25", "52", "9e", "e9", "6a", "a6", "3E", "E3", "00", "HH", "88"
|
|
||||||
};
|
|
||||||
|
|
||||||
static int8_t single_beep[] = {BUZZER_NOTE_A7, 4, 0};
|
|
||||||
static int8_t round_win_melody[] = {
|
|
||||||
BUZZER_NOTE_C6, 4,
|
|
||||||
BUZZER_NOTE_E6, 4,
|
|
||||||
BUZZER_NOTE_G6, 4,
|
|
||||||
BUZZER_NOTE_C7, 12,
|
|
||||||
0};
|
|
||||||
static int8_t round_lose_melody[] = {
|
|
||||||
BUZZER_NOTE_E6, 4,
|
|
||||||
BUZZER_NOTE_F6, 4,
|
|
||||||
BUZZER_NOTE_D6SHARP_E6FLAT, 4,
|
|
||||||
BUZZER_NOTE_C6, 12,
|
|
||||||
0};
|
|
||||||
static int8_t game_win_melody[] = {
|
|
||||||
BUZZER_NOTE_G6, 4,
|
|
||||||
BUZZER_NOTE_A6, 4,
|
|
||||||
BUZZER_NOTE_B6, 4,
|
|
||||||
BUZZER_NOTE_C7, 12,
|
|
||||||
BUZZER_NOTE_D7, 4,
|
|
||||||
BUZZER_NOTE_E7, 4,
|
|
||||||
BUZZER_NOTE_D7, 4,
|
|
||||||
BUZZER_NOTE_C7, 12,
|
|
||||||
BUZZER_NOTE_B6, 4,
|
|
||||||
BUZZER_NOTE_C7, 4,
|
|
||||||
BUZZER_NOTE_D7, 4,
|
|
||||||
BUZZER_NOTE_G7, 24,
|
|
||||||
0};
|
|
||||||
|
|
||||||
#define NUM_SHAPES (sizeof(butterfly_shapes) / sizeof(butterfly_shapes[0]))
|
|
||||||
|
|
||||||
#define POS_LEFT 4
|
|
||||||
#define POS_CENTER 6
|
|
||||||
#define POS_RIGHT 8
|
|
||||||
|
|
||||||
#define TICK_FREQ 8
|
|
||||||
#define TICKS_PER_SHAPE 8
|
|
||||||
|
|
||||||
#define PLAYER_1 0
|
|
||||||
#define PLAYER_2 1
|
|
||||||
|
|
||||||
|
|
||||||
// returns a random integer r with 0 <= r < max
|
|
||||||
static inline uint8_t _get_rand(uint8_t max) {
|
|
||||||
#if __EMSCRIPTEN__
|
|
||||||
return rand() % max;
|
|
||||||
#else
|
|
||||||
return arc4random_uniform(max);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The game is built with a simple state machine where each state is called a
|
|
||||||
* "screen". Each screen can draw on the display and handles events, including
|
|
||||||
* the "activate" event, which is repurposed and sent whenever we move from one
|
|
||||||
* screen to another via the _transition_to function. Basically it's a mini
|
|
||||||
* movement inside movement.
|
|
||||||
*/
|
|
||||||
typedef bool (*screen_fn_t)(movement_event_t, butterfly_game_state_t*);
|
|
||||||
|
|
||||||
static screen_fn_t cur_screen_fn;
|
|
||||||
|
|
||||||
static bool _transition_to(screen_fn_t sf, butterfly_game_state_t *state) {
|
|
||||||
movement_event_t ev = {EVENT_ACTIVATE, 0};
|
|
||||||
cur_screen_fn = sf;
|
|
||||||
return sf(ev, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t _pick_wrong_shape(butterfly_game_state_t *state, bool skip_wrong_shape) {
|
|
||||||
if (!skip_wrong_shape) {
|
|
||||||
// easy case, we only need to skip over 1 shape: the correct shape
|
|
||||||
uint8_t r = _get_rand(NUM_SHAPES-1);
|
|
||||||
if (r >= state->correct_shape) {
|
|
||||||
r++;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
} else {
|
|
||||||
// a bit more complex, we need to skip over 2 shapes: the correct one
|
|
||||||
// and the current wrong one
|
|
||||||
uint8_t r = _get_rand(NUM_SHAPES-2);
|
|
||||||
uint8_t i1, i2; // the 2 indices to skip over, with i1 < i2
|
|
||||||
if (state->correct_shape < state->current_shape) {
|
|
||||||
i1 = state->correct_shape;
|
|
||||||
i2 = state->current_shape;
|
|
||||||
} else {
|
|
||||||
i1 = state->current_shape;
|
|
||||||
i2 = state->correct_shape;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r >= i1) {
|
|
||||||
r++;
|
|
||||||
}
|
|
||||||
if (r >= i2) {
|
|
||||||
r++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _display_shape(uint8_t shape, uint8_t pos) {
|
|
||||||
watch_display_string(butterfly_shapes[shape], pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _display_scores(butterfly_game_state_t *state) {
|
|
||||||
char buf[] = " ";
|
|
||||||
buf[0] = '0' + state->score_p1;
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
buf[0] = '0' + state->score_p2;
|
|
||||||
watch_display_string(buf, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _play_sound(butterfly_game_state_t *state, int8_t *seq) {
|
|
||||||
if (state->sound) watch_buzzer_play_sequence(seq, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _round_start_screen(movement_event_t event, butterfly_game_state_t *state);
|
|
||||||
static bool _reset_screen(movement_event_t event, butterfly_game_state_t *state);
|
|
||||||
|
|
||||||
static bool _game_win_screen(movement_event_t event, butterfly_game_state_t *state) {
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
state->ctr = 4 * TICK_FREQ;
|
|
||||||
watch_clear_display();
|
|
||||||
|
|
||||||
if (state->score_p1 >= state->goal_score) {
|
|
||||||
watch_display_string("pl1 wins", 0);
|
|
||||||
} else {
|
|
||||||
watch_display_string("pl2 wins", 0);
|
|
||||||
}
|
|
||||||
_play_sound(state, game_win_melody);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case EVENT_TICK:
|
|
||||||
state->ctr--;
|
|
||||||
if (state->ctr == 0) {
|
|
||||||
return _transition_to(_reset_screen, state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _round_win_screen(movement_event_t event, butterfly_game_state_t *state) {
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
state->ctr = TICK_FREQ;
|
|
||||||
|
|
||||||
if (state->round_winner == PLAYER_1) {
|
|
||||||
state->score_p1++;
|
|
||||||
} else {
|
|
||||||
state->score_p2++;
|
|
||||||
}
|
|
||||||
|
|
||||||
watch_clear_display();
|
|
||||||
_display_scores(state);
|
|
||||||
_display_shape(state->correct_shape, state->round_winner == PLAYER_1 ? POS_LEFT : POS_RIGHT);
|
|
||||||
_play_sound(state, round_win_melody);
|
|
||||||
break;
|
|
||||||
case EVENT_TICK:
|
|
||||||
state->ctr--;
|
|
||||||
if (state->ctr == 0) {
|
|
||||||
if (state->score_p1 >= state->goal_score || state->score_p2 >= state->goal_score) {
|
|
||||||
return _transition_to(_game_win_screen, state);
|
|
||||||
}
|
|
||||||
return _transition_to(_round_start_screen, state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _round_lose_screen(movement_event_t event, butterfly_game_state_t *state) {
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
state->ctr = TICK_FREQ;
|
|
||||||
|
|
||||||
if (state->round_winner == PLAYER_1) {
|
|
||||||
if (state->score_p2 > 0) state->score_p2--;
|
|
||||||
} else {
|
|
||||||
if (state->score_p1 > 0) state->score_p1--;
|
|
||||||
}
|
|
||||||
|
|
||||||
_display_shape(state->correct_shape, POS_CENTER);
|
|
||||||
_play_sound(state, round_lose_melody);
|
|
||||||
break;
|
|
||||||
case EVENT_TICK:
|
|
||||||
if (--state->ctr == 0) {
|
|
||||||
return _transition_to(_round_start_screen, state);
|
|
||||||
}
|
|
||||||
_display_shape(state->ctr%2 ? state->correct_shape : state->current_shape, POS_CENTER);
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _correct_shape_screen(movement_event_t event, butterfly_game_state_t *state) {
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
_display_shape(state->correct_shape, POS_CENTER);
|
|
||||||
_play_sound(state, single_beep);
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
state->round_winner = PLAYER_1;
|
|
||||||
return _transition_to(_round_win_screen, state);
|
|
||||||
case EVENT_ALARM_BUTTON_DOWN:
|
|
||||||
state->round_winner = PLAYER_2;
|
|
||||||
return _transition_to(_round_win_screen, state);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _wrong_shape_screen(movement_event_t event, butterfly_game_state_t *state) {
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
state->ctr = TICKS_PER_SHAPE;
|
|
||||||
state->current_shape = _pick_wrong_shape(state, true);
|
|
||||||
_display_shape(state->current_shape, POS_CENTER);
|
|
||||||
_play_sound(state, single_beep);
|
|
||||||
break;
|
|
||||||
case EVENT_TICK:
|
|
||||||
if (--state->ctr == 0) {
|
|
||||||
if (--state->show_correct_shape_after == 0) {
|
|
||||||
return _transition_to(_correct_shape_screen, state);
|
|
||||||
}
|
|
||||||
return _transition_to(_wrong_shape_screen, state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
state->round_winner = PLAYER_2;
|
|
||||||
return _transition_to(_round_lose_screen, state);
|
|
||||||
case EVENT_ALARM_BUTTON_DOWN:
|
|
||||||
state->round_winner = PLAYER_1;
|
|
||||||
return _transition_to(_round_lose_screen, state);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _first_wrong_shape_screen(movement_event_t event, butterfly_game_state_t *state) {
|
|
||||||
// the first of the wrong shape screens is a bit different than the next
|
|
||||||
// ones, for 2 reasons:
|
|
||||||
// * we can pick any shape except one (the correct shape); whereas in the
|
|
||||||
// subsequent wrong shape screens, we also must not pick the same wrong
|
|
||||||
// shape as the last
|
|
||||||
// * we don't act on the light/alarm button events; they would normally be
|
|
||||||
// a fail in a wrong shape screen, but in this case it may just be that
|
|
||||||
// the 2 players acknowledge the picked shape (in the previous screen) in
|
|
||||||
// quick succession, and we don't want the second player to immediately
|
|
||||||
// fail.
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
state->ctr = TICKS_PER_SHAPE;
|
|
||||||
state->current_shape = _pick_wrong_shape(state, false);
|
|
||||||
_display_shape(state->current_shape, POS_CENTER);
|
|
||||||
_play_sound(state, single_beep);
|
|
||||||
break;
|
|
||||||
case EVENT_TICK:
|
|
||||||
if (--state->ctr == 0) {
|
|
||||||
return _transition_to(_wrong_shape_screen, state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _round_start_screen(movement_event_t event, butterfly_game_state_t *state) {
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
state->correct_shape = _get_rand(NUM_SHAPES);
|
|
||||||
state->show_correct_shape_after = _get_rand(10) + 1;
|
|
||||||
watch_display_string(" - -", 0);
|
|
||||||
_display_scores(state);
|
|
||||||
_display_shape(state->correct_shape, POS_CENTER);
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
case EVENT_ALARM_BUTTON_DOWN:
|
|
||||||
watch_display_string(" ", 4);
|
|
||||||
return _transition_to(_first_wrong_shape_screen, state);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _goal_select_screen(movement_event_t event, butterfly_game_state_t *state) {
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
watch_clear_display();
|
|
||||||
state->goal_score = 6;
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
return _transition_to(_round_start_screen, state);
|
|
||||||
case EVENT_ALARM_BUTTON_DOWN:
|
|
||||||
state->goal_score += 3;
|
|
||||||
if (state->goal_score > 9) state->goal_score = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buf[] = "GOaL ";
|
|
||||||
buf[5] = '0' + state->goal_score;
|
|
||||||
watch_display_string(buf, 4);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _reset_screen(movement_event_t event, butterfly_game_state_t *state) {
|
|
||||||
(void) event;
|
|
||||||
|
|
||||||
state->score_p1 = 0;
|
|
||||||
state->score_p2 = 0;
|
|
||||||
|
|
||||||
return _transition_to(_goal_select_screen, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _continue_select_screen(movement_event_t event, butterfly_game_state_t *state) {
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
watch_clear_display();
|
|
||||||
|
|
||||||
// no game in progress, start a new game
|
|
||||||
if (state->score_p1 == 0 && state->score_p2 == 0) {
|
|
||||||
return _transition_to(_goal_select_screen, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
state->cont = false;
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
if (state->cont) {
|
|
||||||
return _transition_to(_round_start_screen, state);
|
|
||||||
}
|
|
||||||
return _transition_to(_reset_screen, state);
|
|
||||||
case EVENT_ALARM_BUTTON_DOWN:
|
|
||||||
state->cont = !state->cont;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state->cont) {
|
|
||||||
watch_display_string("Cont y", 4);
|
|
||||||
} else {
|
|
||||||
watch_display_string("Cont n", 4);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _sound_select_screen(movement_event_t event, butterfly_game_state_t *state) {
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
watch_clear_display();
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
return _transition_to(_continue_select_screen, state);
|
|
||||||
case EVENT_ALARM_BUTTON_DOWN:
|
|
||||||
state->sound = !state->sound;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state->sound) {
|
|
||||||
watch_display_string("snd y", 5);
|
|
||||||
} else {
|
|
||||||
watch_display_string("snd n", 5);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _splash_screen(movement_event_t event, butterfly_game_state_t *state) {
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
state->ctr = TICK_FREQ;
|
|
||||||
|
|
||||||
watch_clear_display();
|
|
||||||
watch_display_string("Btrfly", 4);
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
case EVENT_ALARM_BUTTON_DOWN:
|
|
||||||
return _transition_to(_sound_select_screen, state);
|
|
||||||
case EVENT_TICK:
|
|
||||||
if (--state->ctr == 0) {
|
|
||||||
return _transition_to(_sound_select_screen, state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void butterfly_game_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
|
||||||
(void) settings;
|
|
||||||
(void) watch_face_index;
|
|
||||||
|
|
||||||
if (*context_ptr == NULL) {
|
|
||||||
*context_ptr = malloc(sizeof(butterfly_game_state_t));
|
|
||||||
memset(*context_ptr, 0, sizeof(butterfly_game_state_t));
|
|
||||||
// Do any one-time tasks in here; the inside of this conditional happens only at boot.
|
|
||||||
}
|
|
||||||
// Do any pin or peripheral setup here; this will be called whenever the watch wakes from deep sleep.
|
|
||||||
#if __EMSCRIPTEN__
|
|
||||||
// simulator only: seed the random number generator
|
|
||||||
time_t t;
|
|
||||||
srand((unsigned) time(&t));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void butterfly_game_face_activate(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
(void) context;
|
|
||||||
|
|
||||||
movement_request_tick_frequency(TICK_FREQ);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool butterfly_game_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
|
||||||
butterfly_game_state_t *state = (butterfly_game_state_t *)context;
|
|
||||||
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
return _transition_to(_splash_screen, state);
|
|
||||||
case EVENT_TICK:
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
case EVENT_ALARM_BUTTON_DOWN:
|
|
||||||
return (*cur_screen_fn)(event, state);
|
|
||||||
case EVENT_TIMEOUT:
|
|
||||||
movement_move_to_face(0);
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return movement_default_loop_handler(event, settings);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void butterfly_game_face_resign(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
(void) context;
|
|
||||||
|
|
||||||
// handle any cleanup before your watch face goes off-screen.
|
|
||||||
}
|
|
||||||
|
|
@ -1,125 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Hugo Chargois
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BUTTERFLY_GAME_FACE_H_
|
|
||||||
#define BUTTERFLY_GAME_FACE_H_
|
|
||||||
|
|
||||||
#include "movement.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* BUTTERFLY
|
|
||||||
*
|
|
||||||
* A GAME OF SHAPE RECOGNITION AND QUICK REFLEXES FOR 2 PLAYERS
|
|
||||||
*
|
|
||||||
* Setup
|
|
||||||
* =====
|
|
||||||
*
|
|
||||||
* The game is played by 2 players, each using a distinct button:
|
|
||||||
* - player 1 plays with the LIGHT (upper left) button
|
|
||||||
* - player 2 plays with the ALARM (lower right) button
|
|
||||||
*
|
|
||||||
* To play, both players need a firm grip on the watch. A suggested method is to
|
|
||||||
* face each other, remove the watch from the wrist, and position it sideways
|
|
||||||
* between you. Hold one side of the strap in your preferred hand (right or
|
|
||||||
* left) and use your thumb to play.
|
|
||||||
*
|
|
||||||
* Start of the game
|
|
||||||
* =================
|
|
||||||
*
|
|
||||||
* After the splash screen (BtrFly) is shown, the game proceeds through a couple
|
|
||||||
* configuration screens. Use ALARM to cycle through the possible values, and
|
|
||||||
* LIGHT to validate and move to the next screen.
|
|
||||||
*
|
|
||||||
* The configuration options are:
|
|
||||||
*
|
|
||||||
* - snd y/n Toggle sound effects on or off
|
|
||||||
* - goal 3/6/9 Choose to play a game of 3, 6 or 9 points
|
|
||||||
* - cont y/n Decide to continue an unfinished game or start a new one
|
|
||||||
* (this option appears only if a game is in progress)
|
|
||||||
*
|
|
||||||
* Rules
|
|
||||||
* =====
|
|
||||||
*
|
|
||||||
* Prior to each round, a symmetrical shape composed of 2 characters is shown in
|
|
||||||
* the center of the screen. This shape, representing a butterfly's wings, is
|
|
||||||
* randomly chosen from a set of a dozen or so possible shapes. For example:
|
|
||||||
*
|
|
||||||
* ][
|
|
||||||
*
|
|
||||||
* Memorize this shape! Your objective in the round will be to "catch" this
|
|
||||||
* "butterfly" by pressing your button before your opponent does.
|
|
||||||
*
|
|
||||||
* Once you believe you've memorized the shape, press your button. The round
|
|
||||||
* officially begins as soon as either player presses their button.
|
|
||||||
*
|
|
||||||
* Various "butterflies" will then appear on the screen, one after the other.
|
|
||||||
* The fastest player to press their button when the correct butterfly is shown
|
|
||||||
* wins the round. However, if a player presses their button when an incorrect
|
|
||||||
* butterfly is shown, they immediately lose the round.
|
|
||||||
*
|
|
||||||
* Scoring
|
|
||||||
* =======
|
|
||||||
*
|
|
||||||
* The scores are displayed at the top of the screen at all times.
|
|
||||||
*
|
|
||||||
* When a round is won by a player, their score increases by one. When a round
|
|
||||||
* is lost by a player, their score decreases by one; unless they have a score
|
|
||||||
* of 0, in which case it remains unchanged.
|
|
||||||
*
|
|
||||||
* The game ends when a player reaches the set point goal (3, 6 or 9 points).
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
bool cont : 1; // continue
|
|
||||||
bool sound : 1;
|
|
||||||
uint8_t goal_score : 4;
|
|
||||||
|
|
||||||
// a generic ctr used by multiple states to display themselves for multiple frames
|
|
||||||
uint8_t ctr : 6;
|
|
||||||
|
|
||||||
uint8_t correct_shape : 5;
|
|
||||||
uint8_t current_shape : 5;
|
|
||||||
uint8_t show_correct_shape_after : 5;
|
|
||||||
uint8_t round_winner : 1;
|
|
||||||
|
|
||||||
uint8_t score_p1 : 5;
|
|
||||||
uint8_t score_p2 : 5;
|
|
||||||
} butterfly_game_state_t;
|
|
||||||
|
|
||||||
void butterfly_game_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
|
||||||
void butterfly_game_face_activate(movement_settings_t *settings, void *context);
|
|
||||||
bool butterfly_game_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
|
||||||
void butterfly_game_face_resign(movement_settings_t *settings, void *context);
|
|
||||||
|
|
||||||
#define butterfly_game_face ((const watch_face_t){ \
|
|
||||||
butterfly_game_face_setup, \
|
|
||||||
butterfly_game_face_activate, \
|
|
||||||
butterfly_game_face_loop, \
|
|
||||||
butterfly_game_face_resign, \
|
|
||||||
NULL, \
|
|
||||||
})
|
|
||||||
|
|
||||||
#endif // BUTTERFLY_GAME_FACE_H_
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* MIT License
|
* MIT License
|
||||||
*
|
*
|
||||||
* Copyright (c) 2024 Joseph Bryant
|
|
||||||
* Copyright (c) 2023 Konrad Rieck
|
* Copyright (c) 2023 Konrad Rieck
|
||||||
* Copyright (c) 2022 Wesley Ellis
|
* Copyright (c) 2022 Wesley Ellis
|
||||||
*
|
*
|
||||||
@ -69,30 +68,17 @@ static inline void button_beep(movement_settings_t *settings) {
|
|||||||
watch_buzzer_play_note(BUZZER_NOTE_C7, 50);
|
watch_buzzer_play_note(BUZZER_NOTE_C7, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void schedule_countdown(countdown_state_t *state, movement_settings_t *settings) {
|
|
||||||
|
|
||||||
// Calculate the new state->now_ts but don't update it until we've updated the target -
|
|
||||||
// avoid possible race where the old target is compared to the new time and immediately triggers
|
|
||||||
uint32_t new_now = watch_utility_date_time_to_unix_time(watch_rtc_get_date_time(), get_tz_offset(settings));
|
|
||||||
state->target_ts = watch_utility_offset_timestamp(new_now, state->hours, state->minutes, state->seconds);
|
|
||||||
state->now_ts = new_now;
|
|
||||||
watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->target_ts, get_tz_offset(settings));
|
|
||||||
movement_schedule_background_task_for_face(state->watch_face_index, target_dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void auto_repeat(countdown_state_t *state, movement_settings_t *settings) {
|
|
||||||
movement_play_alarm();
|
|
||||||
load_countdown(state);
|
|
||||||
schedule_countdown(state, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void start(countdown_state_t *state, movement_settings_t *settings) {
|
static void start(countdown_state_t *state, movement_settings_t *settings) {
|
||||||
|
watch_date_time now = watch_rtc_get_date_time();
|
||||||
|
|
||||||
state->mode = cd_running;
|
state->mode = cd_running;
|
||||||
schedule_countdown(state, settings);
|
state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
|
||||||
|
state->target_ts = watch_utility_offset_timestamp(state->now_ts, state->hours, state->minutes, state->seconds);
|
||||||
|
watch_date_time target_dt = watch_utility_date_time_from_unix_time(state->target_ts, get_tz_offset(settings));
|
||||||
|
movement_schedule_background_task(target_dt);
|
||||||
|
watch_set_indicator(WATCH_INDICATOR_BELL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void draw(countdown_state_t *state, uint8_t subsecond) {
|
static void draw(countdown_state_t *state, uint8_t subsecond) {
|
||||||
char buf[16];
|
char buf[16];
|
||||||
|
|
||||||
@ -101,9 +87,6 @@ static void draw(countdown_state_t *state, uint8_t subsecond) {
|
|||||||
|
|
||||||
switch (state->mode) {
|
switch (state->mode) {
|
||||||
case cd_running:
|
case cd_running:
|
||||||
if (state->target_ts <= state->now_ts)
|
|
||||||
delta = 0;
|
|
||||||
else
|
|
||||||
delta = state->target_ts - state->now_ts;
|
delta = state->target_ts - state->now_ts;
|
||||||
result = div(delta, 60);
|
result = div(delta, 60);
|
||||||
state->seconds = result.rem;
|
state->seconds = result.rem;
|
||||||
@ -114,7 +97,6 @@ static void draw(countdown_state_t *state, uint8_t subsecond) {
|
|||||||
break;
|
break;
|
||||||
case cd_reset:
|
case cd_reset:
|
||||||
case cd_paused:
|
case cd_paused:
|
||||||
watch_clear_indicator(WATCH_INDICATOR_SIGNAL);
|
|
||||||
sprintf(buf, "CD %2d%02d%02d", state->hours, state->minutes, state->seconds);
|
sprintf(buf, "CD %2d%02d%02d", state->hours, state->minutes, state->seconds);
|
||||||
break;
|
break;
|
||||||
case cd_setting:
|
case cd_setting:
|
||||||
@ -141,13 +123,14 @@ static void draw(countdown_state_t *state, uint8_t subsecond) {
|
|||||||
|
|
||||||
static void pause(countdown_state_t *state) {
|
static void pause(countdown_state_t *state) {
|
||||||
state->mode = cd_paused;
|
state->mode = cd_paused;
|
||||||
movement_cancel_background_task_for_face(state->watch_face_index);
|
movement_cancel_background_task();
|
||||||
watch_clear_indicator(WATCH_INDICATOR_SIGNAL);
|
watch_clear_indicator(WATCH_INDICATOR_BELL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reset(countdown_state_t *state) {
|
static void reset(countdown_state_t *state) {
|
||||||
state->mode = cd_reset;
|
state->mode = cd_reset;
|
||||||
movement_cancel_background_task_for_face(state->watch_face_index);
|
movement_cancel_background_task();
|
||||||
|
watch_clear_indicator(WATCH_INDICATOR_BELL);
|
||||||
load_countdown(state);
|
load_countdown(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,15 +139,6 @@ static void ring(countdown_state_t *state) {
|
|||||||
reset(state);
|
reset(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void times_up(movement_settings_t *settings, countdown_state_t *state) {
|
|
||||||
if(state->repeat) {
|
|
||||||
auto_repeat(state, settings);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ring(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void settings_increment(countdown_state_t *state) {
|
static void settings_increment(countdown_state_t *state) {
|
||||||
switch(state->selection) {
|
switch(state->selection) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -193,7 +167,6 @@ void countdown_face_setup(movement_settings_t *settings, uint8_t watch_face_inde
|
|||||||
memset(*context_ptr, 0, sizeof(countdown_state_t));
|
memset(*context_ptr, 0, sizeof(countdown_state_t));
|
||||||
state->minutes = DEFAULT_MINUTES;
|
state->minutes = DEFAULT_MINUTES;
|
||||||
state->mode = cd_reset;
|
state->mode = cd_reset;
|
||||||
state->watch_face_index = watch_face_index;
|
|
||||||
store_countdown(state);
|
store_countdown(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,11 +177,9 @@ void countdown_face_activate(movement_settings_t *settings, void *context) {
|
|||||||
if(state->mode == cd_running) {
|
if(state->mode == cd_running) {
|
||||||
watch_date_time now = watch_rtc_get_date_time();
|
watch_date_time now = watch_rtc_get_date_time();
|
||||||
state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
|
state->now_ts = watch_utility_date_time_to_unix_time(now, get_tz_offset(settings));
|
||||||
watch_set_indicator(WATCH_INDICATOR_SIGNAL);
|
watch_set_indicator(WATCH_INDICATOR_BELL);
|
||||||
}
|
}
|
||||||
watch_set_colon();
|
watch_set_colon();
|
||||||
if(state->repeat)
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
|
|
||||||
movement_request_tick_frequency(1);
|
movement_request_tick_frequency(1);
|
||||||
quick_ticks_running = false;
|
quick_ticks_running = false;
|
||||||
@ -278,7 +249,6 @@ bool countdown_face_loop(movement_event_t event, movement_settings_t *settings,
|
|||||||
// Only start the timer if we have a valid time.
|
// Only start the timer if we have a valid time.
|
||||||
start(state, settings);
|
start(state, settings);
|
||||||
button_beep(settings);
|
button_beep(settings);
|
||||||
watch_set_indicator(WATCH_INDICATOR_SIGNAL);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case cd_setting:
|
case cd_setting:
|
||||||
@ -288,19 +258,9 @@ bool countdown_face_loop(movement_event_t event, movement_settings_t *settings,
|
|||||||
draw(state, event.subsecond);
|
draw(state, event.subsecond);
|
||||||
break;
|
break;
|
||||||
case EVENT_ALARM_LONG_PRESS:
|
case EVENT_ALARM_LONG_PRESS:
|
||||||
switch(state->mode) {
|
if (state->mode == cd_setting) {
|
||||||
case cd_setting:
|
|
||||||
quick_ticks_running = true;
|
quick_ticks_running = true;
|
||||||
movement_request_tick_frequency(8);
|
movement_request_tick_frequency(8);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Toggle auto-repeat
|
|
||||||
button_beep(settings);
|
|
||||||
state->repeat = !state->repeat;
|
|
||||||
if(state->repeat)
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
else
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EVENT_LIGHT_LONG_PRESS:
|
case EVENT_LIGHT_LONG_PRESS:
|
||||||
@ -322,7 +282,7 @@ bool countdown_face_loop(movement_event_t event, movement_settings_t *settings,
|
|||||||
abort_quick_ticks(state);
|
abort_quick_ticks(state);
|
||||||
break;
|
break;
|
||||||
case EVENT_BACKGROUND_TASK:
|
case EVENT_BACKGROUND_TASK:
|
||||||
times_up(settings, state);
|
ring(state);
|
||||||
break;
|
break;
|
||||||
case EVENT_TIMEOUT:
|
case EVENT_TIMEOUT:
|
||||||
abort_quick_ticks(state);
|
abort_quick_ticks(state);
|
||||||
|
@ -62,8 +62,6 @@ typedef struct {
|
|||||||
uint8_t set_seconds;
|
uint8_t set_seconds;
|
||||||
uint8_t selection;
|
uint8_t selection;
|
||||||
countdown_mode_t mode;
|
countdown_mode_t mode;
|
||||||
bool repeat;
|
|
||||||
uint8_t watch_face_index;
|
|
||||||
} countdown_state_t;
|
} countdown_state_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +26,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "day_one_face.h"
|
#include "day_one_face.h"
|
||||||
#include "watch.h"
|
#include "watch.h"
|
||||||
#include "watch_utility.h"
|
|
||||||
|
static const uint8_t days_in_month[12] = {31, 29, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31};
|
||||||
|
|
||||||
static uint32_t _day_one_face_juliandaynum(uint16_t year, uint16_t month, uint16_t day) {
|
static uint32_t _day_one_face_juliandaynum(uint16_t year, uint16_t month, uint16_t day) {
|
||||||
// from here: https://en.wikipedia.org/wiki/Julian_day#Julian_day_number_calculation
|
// from here: https://en.wikipedia.org/wiki/Julian_day#Julian_day_number_calculation
|
||||||
@ -65,12 +66,13 @@ static void _day_one_face_increment(day_one_state_t *state) {
|
|||||||
break;
|
break;
|
||||||
case PAGE_DAY:
|
case PAGE_DAY:
|
||||||
state->birth_day = state->birth_day + 1;
|
state->birth_day = state->birth_day + 1;
|
||||||
|
if (state->birth_day == 0 || state->birth_day > days_in_month[state->birth_month - 1]) {
|
||||||
|
state->birth_day = 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (state->birth_day == 0 || state->birth_day > days_in_month(state->birth_month, state->birth_year))
|
|
||||||
state->birth_day = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void day_one_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
void day_one_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
||||||
|
@ -1,649 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023-2024 Konrad Rieck
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
* copy of this software and associated documentation files (the
|
|
||||||
* "Software"), to deal in the Software without restriction, including
|
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
||||||
* persons to whom the Software is furnished to do so, subject to the
|
|
||||||
* following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included
|
|
||||||
* in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
|
||||||
* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
|
||||||
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* # Deadline Face
|
|
||||||
*
|
|
||||||
* This is a watch face for tracking deadlines. It draws inspiration from
|
|
||||||
* other watch faces of the project but focuses on keeping track of
|
|
||||||
* deadlines. You can enter and monitor up to four different deadlines by
|
|
||||||
* providing their respective date and time. The face has two modes:
|
|
||||||
* *running mode* and *settings mode*.
|
|
||||||
*
|
|
||||||
* ## Running Mode
|
|
||||||
*
|
|
||||||
* When the watch face is activated, it defaults to running mode. The top
|
|
||||||
* right corner shows the current deadline number, and the main display
|
|
||||||
* presents the time left until the deadline. The format of the display
|
|
||||||
* varies depending on the remaining time.
|
|
||||||
*
|
|
||||||
* - When less than a day is left, the display shows the remaining hours,
|
|
||||||
* minutes, and seconds in the form `HH:MM:SS`.
|
|
||||||
*
|
|
||||||
* - When less than a month is left, the display shows the remaining days
|
|
||||||
* and hours in the form `DD:HH` with the unit `dy` for days.
|
|
||||||
*
|
|
||||||
* - When less than a year is left, the display shows the remaining months
|
|
||||||
* and days in the form `MM:DD` with the unit `mo` for months.
|
|
||||||
*
|
|
||||||
* - When more than a year is left, the years and months are displayed in
|
|
||||||
* the form `YY:MM` with the unit `yr` for years.
|
|
||||||
*
|
|
||||||
* - When a deadline has passed in the last 24 hours, the display shows
|
|
||||||
* `over` to indicate that the deadline has just recently been reached.
|
|
||||||
*
|
|
||||||
* - When no deadline is set for a particular slot, or if a deadline has
|
|
||||||
* already passed by more than 24 hours, `--:--` is displayed.
|
|
||||||
*
|
|
||||||
* The user can navigate in running mode using the following buttons:
|
|
||||||
*
|
|
||||||
* - The *alarm button* moves the next deadline. There are currently four
|
|
||||||
* slots available for deadlines. When the last slot has been reached,
|
|
||||||
* pressing the button moves to the first slot.
|
|
||||||
*
|
|
||||||
* - A *long press* on the *alarm button* activates settings mode and
|
|
||||||
* enables configuring the currently selected deadline.
|
|
||||||
*
|
|
||||||
* - A *long press* on the *light button* activates a deadline alarm. The
|
|
||||||
* bell icon is displayed, and the alarm will ring upon reaching any of
|
|
||||||
* the deadlines set. It is important to note that the watch will not
|
|
||||||
* enter low-energy sleep mode while the alarm is enabled.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* ## Settings Mode
|
|
||||||
*
|
|
||||||
* In settings mode, the currently selected slot for a deadline can be
|
|
||||||
* configured by providing the date and the time. Like running mode, the
|
|
||||||
* top right corner of the display indicates the current deadline number.
|
|
||||||
* The main display shows the date and, on the next page, the time to be
|
|
||||||
* configured.
|
|
||||||
*
|
|
||||||
* The user can use the following buttons in settings mode.
|
|
||||||
*
|
|
||||||
* - The *light button* navigates through the different date and time
|
|
||||||
* settings, going from year, month, day, hour, to minute. The selected
|
|
||||||
* position is blinking.
|
|
||||||
*
|
|
||||||
* - A *long press* on the light button resets the date and time to the next
|
|
||||||
* day at midnight. This is the default deadline.
|
|
||||||
*
|
|
||||||
* - The *alarm button* increments the currently selected position. A *long
|
|
||||||
* press* on the *alarm button* changes the value faster.
|
|
||||||
*
|
|
||||||
* - The *mode button* exists setting mode and returns to *running mode*.
|
|
||||||
* Here the selected deadline slot can be changed.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "deadline_face.h"
|
|
||||||
#include "watch.h"
|
|
||||||
#include "watch_utility.h"
|
|
||||||
|
|
||||||
#define SETTINGS_NUM (5)
|
|
||||||
const char settings_titles[SETTINGS_NUM][3] = { "YR", "MO", "DA", "HR", "M1" };
|
|
||||||
|
|
||||||
/* Local functions */
|
|
||||||
static void _running_init(movement_settings_t *settings, deadline_state_t *state);
|
|
||||||
static bool _running_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
|
||||||
static void _running_display(movement_event_t event, movement_settings_t *settings, deadline_state_t *state);
|
|
||||||
static void _setting_init(movement_settings_t *settings, deadline_state_t *state);
|
|
||||||
static bool _setting_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
|
||||||
static void _setting_display(movement_event_t event, movement_settings_t *settings, deadline_state_t *state, watch_date_time date);
|
|
||||||
|
|
||||||
/* Utility functions */
|
|
||||||
static void _background_alarm_play(movement_settings_t *settings, deadline_state_t *state);
|
|
||||||
static void _background_alarm_schedule(movement_settings_t *settings, deadline_state_t *state);
|
|
||||||
static void _background_alarm_cancel(movement_settings_t *settings, deadline_state_t *state);
|
|
||||||
static void _increment_date(movement_settings_t *settings, deadline_state_t *state, watch_date_time date_time);
|
|
||||||
static inline int32_t _get_tz_offset(movement_settings_t *settings);
|
|
||||||
static inline void _change_tick_freq(uint8_t freq, deadline_state_t *state);
|
|
||||||
static inline bool _is_leap(int16_t y);
|
|
||||||
static inline int _days_in_month(int16_t mpnth, int16_t y);
|
|
||||||
static inline unsigned int _mod(int a, int b);
|
|
||||||
static inline void _beep_button(movement_settings_t *settings);
|
|
||||||
static inline void _beep_enable(movement_settings_t *settings);
|
|
||||||
static inline void _beep_disable(movement_settings_t *settings);
|
|
||||||
static inline void _reset_deadline(movement_settings_t *settings, deadline_state_t *state);
|
|
||||||
|
|
||||||
/* Check for leap year */
|
|
||||||
static inline bool _is_leap(int16_t y)
|
|
||||||
{
|
|
||||||
y += 1900;
|
|
||||||
return !(y % 4) && ((y % 100) || !(y % 400));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Modulo function */
|
|
||||||
static inline unsigned int _mod(int a, int b)
|
|
||||||
{
|
|
||||||
int r = a % b;
|
|
||||||
return r < 0 ? r + b : r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return days in month */
|
|
||||||
static inline int _days_in_month(int16_t month, int16_t year)
|
|
||||||
{
|
|
||||||
uint8_t days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
|
||||||
month = _mod(month - 1, 12);
|
|
||||||
|
|
||||||
if (month == 1 && _is_leap(year)) {
|
|
||||||
return days[month] + 1;
|
|
||||||
} else {
|
|
||||||
return days[month];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return time zone offset */
|
|
||||||
static inline int32_t _get_tz_offset(movement_settings_t *settings)
|
|
||||||
{
|
|
||||||
return movement_timezone_offsets[settings->bit.time_zone] * 60;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Beep for a button press*/
|
|
||||||
static inline void _beep_button(movement_settings_t *settings)
|
|
||||||
{
|
|
||||||
// Play a beep as confirmation for a button press (if applicable)
|
|
||||||
if (!settings->bit.button_should_sound)
|
|
||||||
return;
|
|
||||||
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_C7, 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Beep for entering settings */
|
|
||||||
static inline void _beep_enable(movement_settings_t *settings)
|
|
||||||
{
|
|
||||||
if (!settings->bit.button_should_sound)
|
|
||||||
return;
|
|
||||||
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_G7, 50);
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_REST, 75);
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_C8, 75);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Beep for leaving settings */
|
|
||||||
static inline void _beep_disable(movement_settings_t *settings)
|
|
||||||
{
|
|
||||||
if (!settings->bit.button_should_sound)
|
|
||||||
return;
|
|
||||||
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_C8, 50);
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_REST, 75);
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_G7, 75);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Change tick frequency */
|
|
||||||
static inline void _change_tick_freq(uint8_t freq, deadline_state_t *state)
|
|
||||||
{
|
|
||||||
if (state->tick_freq != freq) {
|
|
||||||
movement_request_tick_frequency(freq);
|
|
||||||
state->tick_freq = freq;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine index of closest deadline */
|
|
||||||
static uint8_t _closest_deadline(movement_settings_t *settings, deadline_state_t *state)
|
|
||||||
{
|
|
||||||
watch_date_time now = watch_rtc_get_date_time();
|
|
||||||
uint32_t now_ts = watch_utility_date_time_to_unix_time(now, _get_tz_offset(settings));
|
|
||||||
uint32_t min_ts = UINT32_MAX;
|
|
||||||
uint8_t min_index = 0;
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < DEADLINE_FACE_DATES; i++) {
|
|
||||||
if (state->deadlines[i] < now_ts || state->deadlines[i] > min_ts)
|
|
||||||
continue;
|
|
||||||
min_ts = state->deadlines[i];
|
|
||||||
min_index = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return min_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Play background alarm */
|
|
||||||
static void _background_alarm_play(movement_settings_t *settings, deadline_state_t *state)
|
|
||||||
{
|
|
||||||
(void) settings;
|
|
||||||
|
|
||||||
/* Use the default alarm from movement and move to foreground */
|
|
||||||
if (state->alarm_enabled) {
|
|
||||||
movement_play_alarm();
|
|
||||||
movement_move_to_face(state->face_idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Schedule background alarm */
|
|
||||||
static void _background_alarm_schedule(movement_settings_t *settings, deadline_state_t *state)
|
|
||||||
{
|
|
||||||
/* We simply re-use the scheduling in the background task */
|
|
||||||
deadline_face_wants_background_task(settings, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cancel background alarm */
|
|
||||||
static void _background_alarm_cancel(movement_settings_t *settings, deadline_state_t *state)
|
|
||||||
{
|
|
||||||
(void) settings;
|
|
||||||
|
|
||||||
movement_cancel_background_task_for_face(state->face_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reset deadline to tomorrow */
|
|
||||||
static inline void _reset_deadline(movement_settings_t *settings, deadline_state_t *state)
|
|
||||||
{
|
|
||||||
/* Get current time and reset hours/minutes/seconds */
|
|
||||||
watch_date_time date_time = watch_rtc_get_date_time();
|
|
||||||
date_time.unit.second = 0;
|
|
||||||
date_time.unit.minute = 0;
|
|
||||||
date_time.unit.hour = 0;
|
|
||||||
|
|
||||||
/* Add 24 hours to obtain first second of tomorrow */
|
|
||||||
uint32_t ts = watch_utility_date_time_to_unix_time(date_time, _get_tz_offset(settings));
|
|
||||||
ts += 24 * 60 * 60;
|
|
||||||
|
|
||||||
state->deadlines[state->current_index] = ts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Increment date in settings mode. Function taken from `set_time_face.c` */
|
|
||||||
static void _increment_date(movement_settings_t *settings, deadline_state_t *state, watch_date_time date_time)
|
|
||||||
{
|
|
||||||
const uint8_t days_in_month[12] = { 31, 28, 31, 30, 31, 30, 30, 31, 30, 31, 30, 31 };
|
|
||||||
|
|
||||||
switch (state->current_page) {
|
|
||||||
case 0:
|
|
||||||
/* Only 10 years covered. Fix this sometime next decade */
|
|
||||||
date_time.unit.year = ((date_time.unit.year % 10) + 1);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
date_time.unit.month = (date_time.unit.month % 12) + 1;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
date_time.unit.day = date_time.unit.day + 1;
|
|
||||||
|
|
||||||
/* Check for leap years */
|
|
||||||
int8_t days = days_in_month[date_time.unit.month - 1];
|
|
||||||
if (date_time.unit.month == 2 && _is_leap(date_time.unit.year))
|
|
||||||
days++;
|
|
||||||
|
|
||||||
if (date_time.unit.day > days)
|
|
||||||
date_time.unit.day = 1;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
date_time.unit.hour = (date_time.unit.hour + 1) % 24;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
date_time.unit.minute = (date_time.unit.minute + 1) % 60;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t ts = watch_utility_date_time_to_unix_time(date_time, _get_tz_offset(settings));
|
|
||||||
state->deadlines[state->current_index] = ts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update display in running mode */
|
|
||||||
static void _running_display(movement_event_t event, movement_settings_t *settings, deadline_state_t *state)
|
|
||||||
{
|
|
||||||
(void) event;
|
|
||||||
(void) settings;
|
|
||||||
|
|
||||||
/* Seconds, minutes, hours, days, months, years */
|
|
||||||
int16_t unit[] = { 0, 0, 0, 0, 0, 0 };
|
|
||||||
uint8_t i, range[] = { 60, 60, 24, 30, 12, 0 };
|
|
||||||
char buf[16];
|
|
||||||
|
|
||||||
/* Display indicators */
|
|
||||||
if (state->alarm_enabled)
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
else
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
|
|
||||||
watch_date_time now = watch_rtc_get_date_time();
|
|
||||||
uint32_t now_ts = watch_utility_date_time_to_unix_time(now, _get_tz_offset(settings));
|
|
||||||
|
|
||||||
/* Deadline expired */
|
|
||||||
if (state->deadlines[state->current_index] < now_ts) {
|
|
||||||
if (state->deadlines[state->current_index] + 24 * 60 * 60 > now_ts)
|
|
||||||
sprintf(buf, "DL%2dOVER ", state->current_index + 1);
|
|
||||||
else
|
|
||||||
sprintf(buf, "DL%2d---- ", state->current_index + 1);
|
|
||||||
|
|
||||||
//watch_clear_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get date time structs */
|
|
||||||
watch_date_time deadline = watch_utility_date_time_from_unix_time(state->deadlines[state->current_index], _get_tz_offset(settings)
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Calculate naive difference of dates */
|
|
||||||
unit[0] = deadline.unit.second - now.unit.second;
|
|
||||||
unit[1] = deadline.unit.minute - now.unit.minute;
|
|
||||||
unit[2] = deadline.unit.hour - now.unit.hour;
|
|
||||||
unit[3] = deadline.unit.day - now.unit.day;
|
|
||||||
unit[4] = deadline.unit.month - now.unit.month;
|
|
||||||
unit[5] = deadline.unit.year - now.unit.year;
|
|
||||||
|
|
||||||
/* Correct errors of naive difference */
|
|
||||||
for (i = 0; i < 6; i++) {
|
|
||||||
if (unit[i] < 0) {
|
|
||||||
/* Correct remaining units */
|
|
||||||
if (i == 3)
|
|
||||||
unit[i] += _days_in_month(deadline.unit.month - 1, deadline.unit.year);
|
|
||||||
else
|
|
||||||
unit[i] += range[i];
|
|
||||||
|
|
||||||
/* Carry over change to next unit if non-zero */
|
|
||||||
if (i < 5 && unit[i + 1] != 0)
|
|
||||||
unit[i + 1] -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set range */
|
|
||||||
i = state->current_index + 1;
|
|
||||||
if (unit[5] > 0) {
|
|
||||||
/* years:months */
|
|
||||||
sprintf(buf, "DL%2d%02d%02dYR", i, unit[5] % 100, unit[4] % 12);
|
|
||||||
} else if (unit[4] > 0) {
|
|
||||||
/* months:days */
|
|
||||||
sprintf(buf, "DL%2d%02d%02dMO", i, (unit[5] * 12 + unit[4]) % 100, unit[3] % 32);
|
|
||||||
} else if (unit[3] > 0) {
|
|
||||||
/* days:hours */
|
|
||||||
sprintf(buf, "DL%2d%02d%02ddY", i, unit[3] % 32, unit[2] % 24);
|
|
||||||
} else {
|
|
||||||
/* hours:minutes:seconds */
|
|
||||||
sprintf(buf, "DL%2d%02d%02d%02d", i, unit[2] % 24, unit[1] % 60, unit[0] % 60);
|
|
||||||
}
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Init running mode */
|
|
||||||
static void _running_init(movement_settings_t *settings, deadline_state_t *state)
|
|
||||||
{
|
|
||||||
(void) settings;
|
|
||||||
(void) state;
|
|
||||||
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_24H);
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_PM);
|
|
||||||
watch_set_colon();
|
|
||||||
|
|
||||||
/* Ensure 1Hz updates only */
|
|
||||||
_change_tick_freq(1, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Loop of running mode */
|
|
||||||
static bool _running_loop(movement_event_t event, movement_settings_t *settings, void *context)
|
|
||||||
{
|
|
||||||
deadline_state_t *state = (deadline_state_t *) context;
|
|
||||||
|
|
||||||
if (event.event_type != EVENT_BACKGROUND_TASK)
|
|
||||||
_running_display(event, settings, state);
|
|
||||||
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ALARM_BUTTON_UP:
|
|
||||||
_beep_button(settings);
|
|
||||||
state->current_index = (state->current_index + 1) % DEADLINE_FACE_DATES;
|
|
||||||
_running_display(event, settings, state);
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_LONG_PRESS:
|
|
||||||
_beep_enable(settings);
|
|
||||||
_setting_init(settings, state);
|
|
||||||
state->mode = DEADLINE_FACE_SETTING;
|
|
||||||
break;
|
|
||||||
case EVENT_MODE_BUTTON_UP:
|
|
||||||
movement_move_to_next_face();
|
|
||||||
return false;
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_LONG_PRESS:
|
|
||||||
_beep_button(settings);
|
|
||||||
state->alarm_enabled = !state->alarm_enabled;
|
|
||||||
if (state->alarm_enabled) {
|
|
||||||
_background_alarm_schedule(settings, context);
|
|
||||||
} else {
|
|
||||||
_background_alarm_cancel(settings, context);
|
|
||||||
}
|
|
||||||
_running_display(event, settings, state);
|
|
||||||
break;
|
|
||||||
case EVENT_TIMEOUT:
|
|
||||||
movement_move_to_face(0);
|
|
||||||
break;
|
|
||||||
case EVENT_BACKGROUND_TASK:
|
|
||||||
_background_alarm_play(settings, state);
|
|
||||||
break;
|
|
||||||
case EVENT_LOW_ENERGY_UPDATE:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return movement_default_loop_handler(event, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update display in settings mode */
|
|
||||||
static void _setting_display(movement_event_t event, movement_settings_t *settings, deadline_state_t *state, watch_date_time date_time)
|
|
||||||
{
|
|
||||||
char buf[11];
|
|
||||||
|
|
||||||
int i = state->current_index + 1;
|
|
||||||
if (state->current_page > 2) {
|
|
||||||
watch_set_colon();
|
|
||||||
if (settings->bit.clock_mode_24h) {
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_24H);
|
|
||||||
sprintf(buf, "%s%2d%2d%02d ", settings_titles[state->current_page], i, date_time.unit.hour, date_time.unit.minute);
|
|
||||||
} else {
|
|
||||||
sprintf(buf, "%s%2d%2d%02d ", settings_titles[state->current_page], i, (date_time.unit.hour % 12) ? (date_time.unit.hour % 12) : 12,
|
|
||||||
date_time.unit.minute);
|
|
||||||
if (date_time.unit.hour < 12)
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_PM);
|
|
||||||
else
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_PM);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
watch_clear_colon();
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_24H);
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_PM);
|
|
||||||
sprintf(buf, "%s%2d%2d%02d%02d", settings_titles[state->current_page], i, date_time.unit.year + 20, date_time.unit.month, date_time.unit.day);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Blink up the parameter we are setting */
|
|
||||||
if (event.subsecond % 2) {
|
|
||||||
switch (state->current_page) {
|
|
||||||
case 0:
|
|
||||||
case 3:
|
|
||||||
buf[4] = buf[5] = ' ';
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 4:
|
|
||||||
buf[6] = buf[7] = ' ';
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
buf[8] = buf[9] = ' ';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Init setting mode */
|
|
||||||
static void _setting_init(movement_settings_t *settings, deadline_state_t *state)
|
|
||||||
{
|
|
||||||
state->current_page = 0;
|
|
||||||
|
|
||||||
/* Init fresh deadline to next day */
|
|
||||||
if (state->deadlines[state->current_index] == 0) {
|
|
||||||
_reset_deadline(settings, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure 1Hz updates only */
|
|
||||||
_change_tick_freq(1, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Loop of setting mode */
|
|
||||||
static bool _setting_loop(movement_event_t event, movement_settings_t *settings, void *context)
|
|
||||||
{
|
|
||||||
deadline_state_t *state = (deadline_state_t *) context;
|
|
||||||
watch_date_time date_time;
|
|
||||||
date_time = watch_utility_date_time_from_unix_time(state->deadlines[state->current_index], _get_tz_offset(settings));
|
|
||||||
|
|
||||||
if (event.event_type != EVENT_BACKGROUND_TASK)
|
|
||||||
_setting_display(event, settings, state, date_time);
|
|
||||||
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_TICK:
|
|
||||||
if (state->tick_freq == 8) {
|
|
||||||
if (watch_get_pin_level(BTN_ALARM)) {
|
|
||||||
_increment_date(settings, state, date_time);
|
|
||||||
_setting_display(event, settings, state, date_time);
|
|
||||||
} else {
|
|
||||||
_change_tick_freq(4, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_LONG_PRESS:
|
|
||||||
_change_tick_freq(8, state);
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_LONG_UP:
|
|
||||||
_change_tick_freq(4, state);
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_LONG_PRESS:
|
|
||||||
_beep_button(settings);
|
|
||||||
_reset_deadline(settings, state);
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_UP:
|
|
||||||
state->current_page = (state->current_page + 1) % SETTINGS_NUM;
|
|
||||||
_setting_display(event, settings, state, date_time);
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_BUTTON_UP:
|
|
||||||
_change_tick_freq(4, state);
|
|
||||||
_increment_date(settings, state, date_time);
|
|
||||||
_setting_display(event, settings, state, date_time);
|
|
||||||
break;
|
|
||||||
case EVENT_TIMEOUT:
|
|
||||||
_beep_button(settings);
|
|
||||||
_background_alarm_schedule(settings, context);
|
|
||||||
_change_tick_freq(1, state);
|
|
||||||
state->mode = DEADLINE_FACE_RUNNING;
|
|
||||||
movement_move_to_face(0);
|
|
||||||
break;
|
|
||||||
case EVENT_MODE_BUTTON_UP:
|
|
||||||
_beep_disable(settings);
|
|
||||||
_background_alarm_schedule(settings, context);
|
|
||||||
_running_init(settings, state);
|
|
||||||
_running_display(event, settings, state);
|
|
||||||
state->mode = DEADLINE_FACE_RUNNING;
|
|
||||||
break;
|
|
||||||
case EVENT_BACKGROUND_TASK:
|
|
||||||
_background_alarm_play(settings, state);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return movement_default_loop_handler(event, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup face */
|
|
||||||
void deadline_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void **context_ptr)
|
|
||||||
{
|
|
||||||
(void) settings;
|
|
||||||
(void) watch_face_index;
|
|
||||||
if (*context_ptr != NULL)
|
|
||||||
return; /* Skip setup if context available */
|
|
||||||
|
|
||||||
/* Allocate state */
|
|
||||||
*context_ptr = malloc(sizeof(deadline_state_t));
|
|
||||||
memset(*context_ptr, 0, sizeof(deadline_state_t));
|
|
||||||
|
|
||||||
/* Store face index for background tasks */
|
|
||||||
deadline_state_t *state = (deadline_state_t *) *context_ptr;
|
|
||||||
state->face_idx = watch_face_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Activate face */
|
|
||||||
void deadline_face_activate(movement_settings_t *settings, void *context)
|
|
||||||
{
|
|
||||||
(void) settings;
|
|
||||||
deadline_state_t *state = (deadline_state_t *) context;
|
|
||||||
|
|
||||||
/* Set display options */
|
|
||||||
_running_init(settings, state);
|
|
||||||
state->mode = DEADLINE_FACE_RUNNING;
|
|
||||||
state->current_index = _closest_deadline(settings, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Loop face */
|
|
||||||
bool deadline_face_loop(movement_event_t event, movement_settings_t *settings, void *context)
|
|
||||||
{
|
|
||||||
(void) settings;
|
|
||||||
deadline_state_t *state = (deadline_state_t *) context;
|
|
||||||
switch (state->mode) {
|
|
||||||
case DEADLINE_FACE_SETTING:
|
|
||||||
_setting_loop(event, settings, context);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
case DEADLINE_FACE_RUNNING:
|
|
||||||
_running_loop(event, settings, context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resign face */
|
|
||||||
void deadline_face_resign(movement_settings_t *settings, void *context)
|
|
||||||
{
|
|
||||||
(void) settings;
|
|
||||||
(void) context;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Want background task */
|
|
||||||
bool deadline_face_wants_background_task(movement_settings_t *settings, void *context)
|
|
||||||
{
|
|
||||||
deadline_state_t *state = (deadline_state_t *) context;
|
|
||||||
|
|
||||||
if (!state->alarm_enabled)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Determine closest deadline */
|
|
||||||
watch_date_time now = watch_rtc_get_date_time();
|
|
||||||
uint32_t now_ts = watch_utility_date_time_to_unix_time(now, _get_tz_offset(settings));
|
|
||||||
uint32_t next_ts = state->deadlines[_closest_deadline(settings, state)];
|
|
||||||
|
|
||||||
/* No active deadline */
|
|
||||||
if (next_ts < now_ts)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* No deadline within next 60 seconds */
|
|
||||||
if (next_ts >= now_ts + 60)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Deadline within next minute. Let's set up an alarm */
|
|
||||||
watch_date_time next = watch_utility_date_time_from_unix_time(next_ts, _get_tz_offset(settings));
|
|
||||||
movement_request_wake();
|
|
||||||
movement_schedule_background_task_for_face(state->face_idx, next);
|
|
||||||
return false;
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023-2024 Konrad Rieck
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
* copy of this software and associated documentation files (the
|
|
||||||
* "Software"), to deal in the Software without restriction, including
|
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
||||||
* persons to whom the Software is furnished to do so, subject to the
|
|
||||||
* following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included
|
|
||||||
* in all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
|
||||||
* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
|
||||||
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DEADLINE_FACE_H_
|
|
||||||
#define DEADLINE_FACE_H_
|
|
||||||
|
|
||||||
#include "movement.h"
|
|
||||||
|
|
||||||
/* Modes of face */
|
|
||||||
typedef enum {
|
|
||||||
DEADLINE_FACE_RUNNING = 0,
|
|
||||||
DEADLINE_FACE_SETTING
|
|
||||||
} deadline_mode_t;
|
|
||||||
|
|
||||||
/* Number of deadline dates */
|
|
||||||
#define DEADLINE_FACE_DATES (4)
|
|
||||||
|
|
||||||
/* Deadline configuration */
|
|
||||||
typedef struct {
|
|
||||||
deadline_mode_t mode:1;
|
|
||||||
uint8_t current_page:3;
|
|
||||||
uint8_t current_index:2;
|
|
||||||
uint8_t alarm_enabled:1;
|
|
||||||
uint8_t tick_freq;
|
|
||||||
uint8_t face_idx;
|
|
||||||
uint32_t deadlines[DEADLINE_FACE_DATES];
|
|
||||||
} deadline_state_t;
|
|
||||||
|
|
||||||
void deadline_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void **context_ptr);
|
|
||||||
void deadline_face_activate(movement_settings_t *settings, void *context);
|
|
||||||
bool deadline_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
|
||||||
void deadline_face_resign(movement_settings_t *settings, void *context);
|
|
||||||
bool deadline_face_wants_background_task(movement_settings_t *settings, void *context);
|
|
||||||
|
|
||||||
#define deadline_face ((const watch_face_t){ \
|
|
||||||
deadline_face_setup, \
|
|
||||||
deadline_face_activate, \
|
|
||||||
deadline_face_loop, \
|
|
||||||
deadline_face_resign, \
|
|
||||||
deadline_face_wants_background_task \
|
|
||||||
})
|
|
||||||
|
|
||||||
#endif // DEADLINE_FACE_H_
|
|
@ -1,617 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2024 <David Volovskiy>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "endless_runner_face.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
JUMPING_FINAL_FRAME = 0,
|
|
||||||
NOT_JUMPING,
|
|
||||||
JUMPING_START,
|
|
||||||
} RunnerJumpState;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
SCREEN_TITLE = 0,
|
|
||||||
SCREEN_PLAYING,
|
|
||||||
SCREEN_LOSE,
|
|
||||||
SCREEN_TIME,
|
|
||||||
SCREEN_COUNT
|
|
||||||
} RunnerCurrScreen;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DIFF_BABY = 0, // FREQ_SLOW FPS; MIN_ZEROES 0's min; Jump is JUMP_FRAMES_EASY frames
|
|
||||||
DIFF_EASY, // FREQ FPS; MIN_ZEROES 0's min; Jump is JUMP_FRAMES_EASY frames
|
|
||||||
DIFF_NORM, // FREQ FPS; MIN_ZEROES 0's min; Jump is JUMP_FRAMES frames
|
|
||||||
DIFF_HARD, // FREQ FPS; MIN_ZEROES_HARD 0's min; jump is JUMP_FRAMES frames
|
|
||||||
DIFF_FUEL, // Mode where the top-right displays the amoount of fuel that you can be above the ground for, dodging obstacles. When on the ground, your fuel recharges.
|
|
||||||
DIFF_FUEL_1, // Same as DIFF_FUEL, but if your fuel is 0, then you won't recharge
|
|
||||||
DIFF_COUNT
|
|
||||||
} RunnerDifficulty;
|
|
||||||
|
|
||||||
#define NUM_GRID 12 // This the length that the obstacle track can be on
|
|
||||||
#define FREQ 8 // Frequency request for the game
|
|
||||||
#define FREQ_SLOW 4 // Frequency request for baby mode
|
|
||||||
#define JUMP_FRAMES 2 // Wait this many frames on difficulties above EASY before coming down from the jump button pressed
|
|
||||||
#define JUMP_FRAMES_EASY 3 // Wait this many frames on difficulties at or below EASY before coming down from the jump button pressed
|
|
||||||
#define MIN_ZEROES 4 // At minimum, we'll have this many spaces between obstacles
|
|
||||||
#define MIN_ZEROES_HARD 3 // At minimum, we'll have this many spaces between obstacles on hard mode
|
|
||||||
#define MAX_HI_SCORE 9999 // Max hi score to store and display on the title screen.
|
|
||||||
#define MAX_DISP_SCORE 39 // The top-right digits can't properly display above 39
|
|
||||||
#define JUMP_FRAMES_FUEL 30 // The max fuel that fuel that the fuel mode game will hold
|
|
||||||
#define JUMP_FRAMES_FUEL_RECHARGE 3 // How much fuel each frame on the ground adds
|
|
||||||
#define MAX_DISP_SCORE_FUEL 9 // Since the fuel mode displays the score in the weekday slot, two digits will display wonky data
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t obst_pattern;
|
|
||||||
uint16_t obst_indx : 8;
|
|
||||||
uint16_t jump_state : 5;
|
|
||||||
uint16_t sec_before_moves : 3;
|
|
||||||
uint16_t curr_score : 10;
|
|
||||||
uint16_t curr_screen : 4;
|
|
||||||
bool loc_2_on;
|
|
||||||
bool loc_3_on;
|
|
||||||
bool success_jump;
|
|
||||||
bool fuel_mode;
|
|
||||||
uint8_t fuel;
|
|
||||||
} game_state_t;
|
|
||||||
|
|
||||||
static game_state_t game_state;
|
|
||||||
static const uint8_t _num_bits_obst_pattern = sizeof(game_state.obst_pattern) * 8;
|
|
||||||
|
|
||||||
static void print_binary(uint32_t value, int bits) {
|
|
||||||
#if __EMSCRIPTEN__
|
|
||||||
for (int i = bits - 1; i >= 0; i--) {
|
|
||||||
// Print each bit
|
|
||||||
printf("%lu", (value >> i) & 1);
|
|
||||||
// Optional: add a space every 4 bits for readability
|
|
||||||
if (i % 4 == 0 && i != 0) {
|
|
||||||
printf(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("\r\n");
|
|
||||||
#else
|
|
||||||
(void) value;
|
|
||||||
(void) bits;
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t get_random(uint32_t max) {
|
|
||||||
#if __EMSCRIPTEN__
|
|
||||||
return rand() % max;
|
|
||||||
#else
|
|
||||||
return arc4random_uniform(max);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t get_random_nonzero(uint32_t max) {
|
|
||||||
uint32_t random;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
random = get_random(max);
|
|
||||||
} while (random == 0);
|
|
||||||
return random;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t get_random_kinda_nonzero(uint32_t max) {
|
|
||||||
// Returns a number that's between 1 and max, unless max is 0 or 1, then it returns 0 to max.
|
|
||||||
if (max == 0) return 0;
|
|
||||||
else if (max == 1) return get_random(max);
|
|
||||||
return get_random_nonzero(max);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t get_random_fuel(uint32_t prev_val) {
|
|
||||||
static uint8_t prev_rand_subset = 0;
|
|
||||||
uint32_t rand;
|
|
||||||
uint8_t max_ones, subset;
|
|
||||||
uint32_t rand_legal = 0;
|
|
||||||
prev_val = prev_val & ~0xFFFF;
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
|
||||||
subset = 0;
|
|
||||||
max_ones = 8;
|
|
||||||
if (prev_rand_subset > 4)
|
|
||||||
max_ones -= prev_rand_subset;
|
|
||||||
rand = get_random_kinda_nonzero(max_ones);
|
|
||||||
if (rand > 5 && prev_rand_subset) rand = 5; // The gap of one or two is awkward
|
|
||||||
for (uint32_t j = 0; j < rand; j++) {
|
|
||||||
subset |= (1 << j);
|
|
||||||
}
|
|
||||||
if (prev_rand_subset >= 7)
|
|
||||||
subset = subset << 1;
|
|
||||||
subset &= 0xFF;
|
|
||||||
rand_legal |= subset << (8 * i);
|
|
||||||
prev_rand_subset = rand;
|
|
||||||
}
|
|
||||||
|
|
||||||
rand_legal = prev_val | rand_legal;
|
|
||||||
print_binary(rand_legal, 32);
|
|
||||||
return rand_legal;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t get_random_legal(uint32_t prev_val, uint16_t difficulty) {
|
|
||||||
/** @brief A legal random number starts with the previous number (which should be the 12 bits on the screen).
|
|
||||||
* @param prev_val The previous value to tack onto. The return will have its first NUM_GRID MSBs be the same as prev_val, and the rest be new
|
|
||||||
* @param difficulty To dictate how spread apart the obsticles must be
|
|
||||||
* @return the new random value, where it's first NUM_GRID MSBs are the same as prev_val
|
|
||||||
*/
|
|
||||||
uint8_t min_zeros = (difficulty == DIFF_HARD) ? MIN_ZEROES_HARD : MIN_ZEROES;
|
|
||||||
uint32_t max = (1 << (_num_bits_obst_pattern - NUM_GRID)) - 1;
|
|
||||||
uint32_t rand = get_random_nonzero(max);
|
|
||||||
uint32_t rand_legal = 0;
|
|
||||||
prev_val = prev_val & ~max;
|
|
||||||
|
|
||||||
for (int i = (NUM_GRID + 1); i <= _num_bits_obst_pattern; i++) {
|
|
||||||
uint32_t mask = 1 << (_num_bits_obst_pattern - i);
|
|
||||||
bool msb = (rand & mask) >> (_num_bits_obst_pattern - i);
|
|
||||||
if (msb) {
|
|
||||||
rand_legal = rand_legal << min_zeros;
|
|
||||||
i+=min_zeros;
|
|
||||||
}
|
|
||||||
rand_legal |= msb;
|
|
||||||
rand_legal = rand_legal << 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rand_legal = rand_legal & max;
|
|
||||||
for (int i = 0; i <= min_zeros; i++) {
|
|
||||||
if (prev_val & (1 << (i + _num_bits_obst_pattern - NUM_GRID))){
|
|
||||||
rand_legal = rand_legal >> (min_zeros - i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rand_legal = prev_val | rand_legal;
|
|
||||||
print_binary(rand_legal, 32);
|
|
||||||
return rand_legal;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void display_ball(bool jumping) {
|
|
||||||
if (!jumping) {
|
|
||||||
watch_set_pixel(0, 21);
|
|
||||||
watch_set_pixel(1, 21);
|
|
||||||
watch_set_pixel(0, 20);
|
|
||||||
watch_set_pixel(1, 20);
|
|
||||||
watch_clear_pixel(1, 17);
|
|
||||||
watch_clear_pixel(2, 20);
|
|
||||||
watch_clear_pixel(2, 21);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
watch_clear_pixel(0, 21);
|
|
||||||
watch_clear_pixel(1, 21);
|
|
||||||
watch_clear_pixel(0, 20);
|
|
||||||
watch_set_pixel(1, 20);
|
|
||||||
watch_set_pixel(1, 17);
|
|
||||||
watch_set_pixel(2, 20);
|
|
||||||
watch_set_pixel(2, 21);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void display_score(uint8_t score) {
|
|
||||||
char buf[3];
|
|
||||||
if (game_state.fuel_mode) {
|
|
||||||
score %= (MAX_DISP_SCORE_FUEL + 1);
|
|
||||||
sprintf(buf, "%1d", score);
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
score %= (MAX_DISP_SCORE + 1);
|
|
||||||
sprintf(buf, "%2d", score);
|
|
||||||
watch_display_string(buf, 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_to_score(endless_runner_state_t *state) {
|
|
||||||
if (game_state.curr_score <= MAX_HI_SCORE) {
|
|
||||||
game_state.curr_score++;
|
|
||||||
if (game_state.curr_score > state -> hi_score)
|
|
||||||
state -> hi_score = game_state.curr_score;
|
|
||||||
}
|
|
||||||
game_state.success_jump = true;
|
|
||||||
display_score(game_state.curr_score);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void display_fuel(uint8_t subsecond, uint8_t difficulty) {
|
|
||||||
char buf[4];
|
|
||||||
if (difficulty == DIFF_FUEL_1 && game_state.fuel == 0 && subsecond % (FREQ/2) == 0) {
|
|
||||||
watch_display_string(" ", 2); // Blink the 0 fuel to show it cannot be refilled.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sprintf(buf, "%2d", game_state.fuel);
|
|
||||||
watch_display_string(buf, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void check_and_reset_hi_score(endless_runner_state_t *state) {
|
|
||||||
// Resets the hi score at the beginning of each month.
|
|
||||||
watch_date_time date_time = watch_rtc_get_date_time();
|
|
||||||
if ((state -> year_last_hi_score != date_time.unit.year) ||
|
|
||||||
(state -> month_last_hi_score != date_time.unit.month))
|
|
||||||
{
|
|
||||||
// The high score resets itself every new month.
|
|
||||||
state -> hi_score = 0;
|
|
||||||
state -> year_last_hi_score = date_time.unit.year;
|
|
||||||
state -> month_last_hi_score = date_time.unit.month;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void display_difficulty(uint16_t difficulty) {
|
|
||||||
switch (difficulty)
|
|
||||||
{
|
|
||||||
case DIFF_BABY:
|
|
||||||
watch_display_string(" b", 2);
|
|
||||||
break;
|
|
||||||
case DIFF_EASY:
|
|
||||||
watch_display_string(" E", 2);
|
|
||||||
break;
|
|
||||||
case DIFF_HARD:
|
|
||||||
watch_display_string(" H", 2);
|
|
||||||
break;
|
|
||||||
case DIFF_FUEL:
|
|
||||||
watch_display_string(" F", 2);
|
|
||||||
break;
|
|
||||||
case DIFF_FUEL_1:
|
|
||||||
watch_display_string("1F", 2);
|
|
||||||
break;
|
|
||||||
case DIFF_NORM:
|
|
||||||
default:
|
|
||||||
watch_display_string(" N", 2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
game_state.fuel_mode = difficulty >= DIFF_FUEL && difficulty <= DIFF_FUEL_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void change_difficulty(endless_runner_state_t *state) {
|
|
||||||
state -> difficulty = (state -> difficulty + 1) % DIFF_COUNT;
|
|
||||||
display_difficulty(state -> difficulty);
|
|
||||||
if (state -> soundOn) {
|
|
||||||
if (state -> difficulty == 0) watch_buzzer_play_note(BUZZER_NOTE_B4, 30);
|
|
||||||
else watch_buzzer_play_note(BUZZER_NOTE_C5, 30);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void toggle_sound(endless_runner_state_t *state) {
|
|
||||||
state -> soundOn = !state -> soundOn;
|
|
||||||
if (state -> soundOn){
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_C5, 30);
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void display_title(endless_runner_state_t *state) {
|
|
||||||
uint16_t hi_score = state -> hi_score;
|
|
||||||
uint8_t difficulty = state -> difficulty;
|
|
||||||
bool sound_on = state -> soundOn;
|
|
||||||
game_state.curr_screen = SCREEN_TITLE;
|
|
||||||
memset(&game_state, 0, sizeof(game_state));
|
|
||||||
game_state.sec_before_moves = 1; // The first obstacles will all be 0s, which is about an extra second of delay.
|
|
||||||
if (sound_on) game_state.sec_before_moves--; // Start chime is about 1 second
|
|
||||||
watch_set_colon();
|
|
||||||
if (hi_score > MAX_HI_SCORE) {
|
|
||||||
watch_display_string("ER HS --", 0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
char buf[14];
|
|
||||||
sprintf(buf, "ER HS%4d", hi_score);
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
}
|
|
||||||
display_difficulty(difficulty);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void display_time(watch_date_time date_time, bool clock_mode_24h) {
|
|
||||||
static watch_date_time previous_date_time;
|
|
||||||
char buf[6 + 1];
|
|
||||||
|
|
||||||
// If the hour needs updating or it's the first time displaying the time
|
|
||||||
if ((game_state.curr_screen != SCREEN_TIME) || (date_time.unit.hour != previous_date_time.unit.hour)) {
|
|
||||||
uint8_t hour = date_time.unit.hour;
|
|
||||||
game_state.curr_screen = SCREEN_TIME;
|
|
||||||
|
|
||||||
if (clock_mode_24h) watch_set_indicator(WATCH_INDICATOR_24H);
|
|
||||||
else {
|
|
||||||
if (hour >= 12) watch_set_indicator(WATCH_INDICATOR_PM);
|
|
||||||
hour %= 12;
|
|
||||||
if (hour == 0) hour = 12;
|
|
||||||
}
|
|
||||||
watch_set_colon();
|
|
||||||
sprintf( buf, "%2d%02d ", hour, date_time.unit.minute);
|
|
||||||
watch_display_string(buf, 4);
|
|
||||||
}
|
|
||||||
// If both digits of the minute need updating
|
|
||||||
else if ((date_time.unit.minute / 10) != (previous_date_time.unit.minute / 10)) {
|
|
||||||
sprintf( buf, "%02d ", date_time.unit.minute);
|
|
||||||
watch_display_string(buf, 6);
|
|
||||||
}
|
|
||||||
// If only the ones-place of the minute needs updating.
|
|
||||||
else if (date_time.unit.minute != previous_date_time.unit.minute) {
|
|
||||||
sprintf( buf, "%d ", date_time.unit.minute % 10);
|
|
||||||
watch_display_string(buf, 7);
|
|
||||||
}
|
|
||||||
previous_date_time.reg = date_time.reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void begin_playing(endless_runner_state_t *state) {
|
|
||||||
uint8_t difficulty = state -> difficulty;
|
|
||||||
game_state.curr_screen = SCREEN_PLAYING;
|
|
||||||
watch_clear_colon();
|
|
||||||
movement_request_tick_frequency((state -> difficulty == DIFF_BABY) ? FREQ_SLOW : FREQ);
|
|
||||||
if (game_state.fuel_mode) {
|
|
||||||
watch_display_string(" ", 0);
|
|
||||||
game_state.obst_pattern = get_random_fuel(0);
|
|
||||||
if ((16 * JUMP_FRAMES_FUEL_RECHARGE) < JUMP_FRAMES_FUEL) // 16 frames of zeros at the start of a level
|
|
||||||
game_state.fuel = JUMP_FRAMES_FUEL - (16 * JUMP_FRAMES_FUEL_RECHARGE); // Have it below its max to show it counting up when starting.
|
|
||||||
if (game_state.fuel < JUMP_FRAMES_FUEL_RECHARGE) game_state.fuel = JUMP_FRAMES_FUEL_RECHARGE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
watch_display_string(" ", 2);
|
|
||||||
game_state.obst_pattern = get_random_legal(0, difficulty);
|
|
||||||
}
|
|
||||||
game_state.jump_state = NOT_JUMPING;
|
|
||||||
display_ball(game_state.jump_state != NOT_JUMPING);
|
|
||||||
display_score( game_state.curr_score);
|
|
||||||
if (state -> soundOn){
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_C5, 200);
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_E5, 200);
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_G5, 200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void display_lose_screen(endless_runner_state_t *state) {
|
|
||||||
game_state.curr_screen = SCREEN_LOSE;
|
|
||||||
game_state.curr_score = 0;
|
|
||||||
watch_display_string(" LOSE ", 0);
|
|
||||||
if (state -> soundOn)
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_A1, 600);
|
|
||||||
else
|
|
||||||
delay_ms(600);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void display_obstacle(bool obstacle, int grid_loc, endless_runner_state_t *state) {
|
|
||||||
static bool prev_obst_pos_two = 0;
|
|
||||||
switch (grid_loc)
|
|
||||||
{
|
|
||||||
case 2:
|
|
||||||
game_state.loc_2_on = obstacle;
|
|
||||||
if (obstacle)
|
|
||||||
watch_set_pixel(0, 20);
|
|
||||||
else if (game_state.jump_state != NOT_JUMPING) {
|
|
||||||
watch_clear_pixel(0, 20);
|
|
||||||
if (game_state.fuel_mode && prev_obst_pos_two)
|
|
||||||
add_to_score(state);
|
|
||||||
}
|
|
||||||
prev_obst_pos_two = obstacle;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
game_state.loc_3_on = obstacle;
|
|
||||||
if (obstacle)
|
|
||||||
watch_set_pixel(1, 21);
|
|
||||||
else if (game_state.jump_state != NOT_JUMPING)
|
|
||||||
watch_clear_pixel(1, 21);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
if (!game_state.fuel_mode && obstacle) // If an obstacle is here, it means the ball cleared it
|
|
||||||
add_to_score(state);
|
|
||||||
//fall through
|
|
||||||
case 0:
|
|
||||||
case 5:
|
|
||||||
if (obstacle)
|
|
||||||
watch_set_pixel(0, 18 + grid_loc);
|
|
||||||
else
|
|
||||||
watch_clear_pixel(0, 18 + grid_loc);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
if (obstacle)
|
|
||||||
watch_set_pixel(1, 22);
|
|
||||||
else
|
|
||||||
watch_clear_pixel(1, 22);
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
if (obstacle)
|
|
||||||
watch_set_pixel(1, 0);
|
|
||||||
else
|
|
||||||
watch_clear_pixel(1, 0);
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
case 8:
|
|
||||||
if (obstacle)
|
|
||||||
watch_set_pixel(0, grid_loc - 6);
|
|
||||||
else
|
|
||||||
watch_clear_pixel(0, grid_loc - 6);
|
|
||||||
break;
|
|
||||||
case 9:
|
|
||||||
case 10:
|
|
||||||
if (obstacle)
|
|
||||||
watch_set_pixel(0, grid_loc - 5);
|
|
||||||
else
|
|
||||||
watch_clear_pixel(0, grid_loc - 5);
|
|
||||||
break;
|
|
||||||
case 11:
|
|
||||||
if (obstacle)
|
|
||||||
watch_set_pixel(1, 6);
|
|
||||||
else
|
|
||||||
watch_clear_pixel(1, 6);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void stop_jumping(endless_runner_state_t *state) {
|
|
||||||
game_state.jump_state = NOT_JUMPING;
|
|
||||||
display_ball(game_state.jump_state != NOT_JUMPING);
|
|
||||||
if (state -> soundOn){
|
|
||||||
if (game_state.success_jump)
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_C5, 60);
|
|
||||||
else
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_C3, 60);
|
|
||||||
}
|
|
||||||
game_state.success_jump = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void display_obstacles(endless_runner_state_t *state) {
|
|
||||||
for (int i = 0; i < NUM_GRID; i++) {
|
|
||||||
// Use a bitmask to isolate each bit and shift it to the least significant position
|
|
||||||
uint32_t mask = 1 << ((_num_bits_obst_pattern - 1) - i);
|
|
||||||
bool obstacle = (game_state.obst_pattern & mask) >> ((_num_bits_obst_pattern - 1) - i);
|
|
||||||
display_obstacle(obstacle, i, state);
|
|
||||||
}
|
|
||||||
game_state.obst_pattern = game_state.obst_pattern << 1;
|
|
||||||
game_state.obst_indx++;
|
|
||||||
if (game_state.fuel_mode) {
|
|
||||||
if (game_state.obst_indx >= (_num_bits_obst_pattern / 2)) {
|
|
||||||
game_state.obst_indx = 0;
|
|
||||||
game_state.obst_pattern = get_random_fuel(game_state.obst_pattern);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (game_state.obst_indx >= _num_bits_obst_pattern - NUM_GRID) {
|
|
||||||
game_state.obst_indx = 0;
|
|
||||||
game_state.obst_pattern = get_random_legal(game_state.obst_pattern, state -> difficulty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_game(endless_runner_state_t *state, uint8_t subsecond) {
|
|
||||||
uint8_t curr_jump_frame = 0;
|
|
||||||
if (game_state.sec_before_moves != 0) {
|
|
||||||
if (subsecond == 0) --game_state.sec_before_moves;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
display_obstacles(state);
|
|
||||||
switch (game_state.jump_state)
|
|
||||||
{
|
|
||||||
case NOT_JUMPING:
|
|
||||||
if (game_state.fuel_mode) {
|
|
||||||
for (int i = 0; i < JUMP_FRAMES_FUEL_RECHARGE; i++)
|
|
||||||
{
|
|
||||||
if(game_state.fuel >= JUMP_FRAMES_FUEL || (state -> difficulty == DIFF_FUEL_1 && !game_state.fuel))
|
|
||||||
break;
|
|
||||||
game_state.fuel++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case JUMPING_FINAL_FRAME:
|
|
||||||
stop_jumping(state);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (game_state.fuel_mode) {
|
|
||||||
if (!game_state.fuel)
|
|
||||||
game_state.jump_state = JUMPING_FINAL_FRAME;
|
|
||||||
else
|
|
||||||
game_state.fuel--;
|
|
||||||
if (!watch_get_pin_level(BTN_ALARM) && !watch_get_pin_level(BTN_LIGHT)) stop_jumping(state);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
curr_jump_frame = game_state.jump_state - NOT_JUMPING;
|
|
||||||
if (curr_jump_frame >= JUMP_FRAMES_EASY || (state -> difficulty >= DIFF_NORM && curr_jump_frame >= JUMP_FRAMES))
|
|
||||||
game_state.jump_state = JUMPING_FINAL_FRAME;
|
|
||||||
else
|
|
||||||
game_state.jump_state++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (game_state.jump_state == NOT_JUMPING && (game_state.loc_2_on || game_state.loc_3_on)) {
|
|
||||||
delay_ms(200); // To show the player jumping onto the obstacle before displaying the lose screen.
|
|
||||||
display_lose_screen(state);
|
|
||||||
}
|
|
||||||
else if (game_state.fuel_mode)
|
|
||||||
display_fuel(subsecond, state -> difficulty);
|
|
||||||
}
|
|
||||||
|
|
||||||
void endless_runner_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
|
||||||
(void) settings;
|
|
||||||
(void) watch_face_index;
|
|
||||||
if (*context_ptr == NULL) {
|
|
||||||
*context_ptr = malloc(sizeof(endless_runner_state_t));
|
|
||||||
memset(*context_ptr, 0, sizeof(endless_runner_state_t));
|
|
||||||
endless_runner_state_t *state = (endless_runner_state_t *)*context_ptr;
|
|
||||||
state->difficulty = DIFF_NORM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void endless_runner_face_activate(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
(void) context;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool endless_runner_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
|
||||||
endless_runner_state_t *state = (endless_runner_state_t *)context;
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
check_and_reset_hi_score(state);
|
|
||||||
if (state -> soundOn) watch_set_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
display_title(state);
|
|
||||||
break;
|
|
||||||
case EVENT_TICK:
|
|
||||||
switch (game_state.curr_screen)
|
|
||||||
{
|
|
||||||
case SCREEN_TITLE:
|
|
||||||
case SCREEN_LOSE:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
update_game(state, event.subsecond);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_UP:
|
|
||||||
case EVENT_ALARM_BUTTON_UP:
|
|
||||||
if (game_state.curr_screen == SCREEN_TITLE)
|
|
||||||
begin_playing(state);
|
|
||||||
else if (game_state.curr_screen == SCREEN_LOSE)
|
|
||||||
display_title(state);
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_LONG_PRESS:
|
|
||||||
if (game_state.curr_screen == SCREEN_TITLE)
|
|
||||||
change_difficulty(state);
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
case EVENT_ALARM_BUTTON_DOWN:
|
|
||||||
if (game_state.curr_screen == SCREEN_PLAYING && game_state.jump_state == NOT_JUMPING){
|
|
||||||
if (game_state.fuel_mode && !game_state.fuel) break;
|
|
||||||
game_state.jump_state = JUMPING_START;
|
|
||||||
display_ball(game_state.jump_state != NOT_JUMPING);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_LONG_PRESS:
|
|
||||||
if (game_state.curr_screen != SCREEN_PLAYING)
|
|
||||||
toggle_sound(state);
|
|
||||||
break;
|
|
||||||
case EVENT_TIMEOUT:
|
|
||||||
if (game_state.curr_screen != SCREEN_TITLE)
|
|
||||||
display_title(state);
|
|
||||||
break;
|
|
||||||
case EVENT_LOW_ENERGY_UPDATE:
|
|
||||||
display_time(watch_rtc_get_date_time(), settings->bit.clock_mode_24h);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return movement_default_loop_handler(event, settings);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void endless_runner_face_resign(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
(void) context;
|
|
||||||
}
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2024 <David Volovskiy>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ENDLESS_RUNNER_FACE_H_
|
|
||||||
#define ENDLESS_RUNNER_FACE_H_
|
|
||||||
|
|
||||||
#include "movement.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
ENDLESS_RUNNER face
|
|
||||||
|
|
||||||
This is a basic endless-runner, like the [Chrome Dino game](https://en.wikipedia.org/wiki/Dinosaur_Game).
|
|
||||||
On the title screen, you can select a difficulty by long-pressing LIGHT or toggle sound by long-pressing ALARM.
|
|
||||||
LED or ALARM are used to jump.
|
|
||||||
High-score is displayed on the top-right on the title screen. During a game, the current score is displayed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint16_t hi_score : 10;
|
|
||||||
uint8_t difficulty : 3;
|
|
||||||
uint8_t month_last_hi_score : 4;
|
|
||||||
uint8_t year_last_hi_score : 6;
|
|
||||||
uint8_t soundOn : 1;
|
|
||||||
/* 24 bits, likely aligned to 32 bits = 4 bytes */
|
|
||||||
} endless_runner_state_t;
|
|
||||||
|
|
||||||
void endless_runner_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
|
||||||
void endless_runner_face_activate(movement_settings_t *settings, void *context);
|
|
||||||
bool endless_runner_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
|
||||||
void endless_runner_face_resign(movement_settings_t *settings, void *context);
|
|
||||||
|
|
||||||
#define endless_runner_face ((const watch_face_t){ \
|
|
||||||
endless_runner_face_setup, \
|
|
||||||
endless_runner_face_activate, \
|
|
||||||
endless_runner_face_loop, \
|
|
||||||
endless_runner_face_resign, \
|
|
||||||
NULL, \
|
|
||||||
})
|
|
||||||
|
|
||||||
#endif // ENDLESS_RUNNER_FACE_H_
|
|
||||||
|
|
@ -1,396 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Chris Ellis
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Emulator only: need time() to seed the random number generator.
|
|
||||||
#if __EMSCRIPTEN__
|
|
||||||
#include <time.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "higher_lower_game_face.h"
|
|
||||||
#include "watch_private_display.h"
|
|
||||||
|
|
||||||
#define TITLE_TEXT "Hi-Lo"
|
|
||||||
#define GAME_BOARD_SIZE 6
|
|
||||||
#define MAX_BOARDS 40
|
|
||||||
#define GUESSES_PER_SCREEN 5
|
|
||||||
#define WIN_SCORE (MAX_BOARDS * GUESSES_PER_SCREEN)
|
|
||||||
#define STATUS_DISPLAY_START 0
|
|
||||||
#define BOARD_SCORE_DISPLAY_START 2
|
|
||||||
#define BOARD_DISPLAY_START 4
|
|
||||||
#define BOARD_DISPLAY_END 9
|
|
||||||
#define MIN_CARD_VALUE 2
|
|
||||||
#define MAX_CARD_VALUE 14
|
|
||||||
#define CARD_RANK_COUNT (MAX_CARD_VALUE - MIN_CARD_VALUE + 1)
|
|
||||||
#define CARD_SUIT_COUNT 4
|
|
||||||
#define DECK_SIZE (CARD_SUIT_COUNT * CARD_RANK_COUNT)
|
|
||||||
#define FLIP_BOARD_DIRECTION false
|
|
||||||
|
|
||||||
typedef struct card_t {
|
|
||||||
uint8_t value;
|
|
||||||
bool revealed;
|
|
||||||
} card_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
A, B, C, D, E, F, G
|
|
||||||
} segment_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
HL_GUESS_EQUAL,
|
|
||||||
HL_GUESS_HIGHER,
|
|
||||||
HL_GUESS_LOWER
|
|
||||||
} guess_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
HL_GS_TITLE_SCREEN,
|
|
||||||
HL_GS_GUESSING,
|
|
||||||
HL_GS_WIN,
|
|
||||||
HL_GS_LOSE,
|
|
||||||
HL_GS_SHOW_SCORE,
|
|
||||||
} game_state_t;
|
|
||||||
|
|
||||||
static game_state_t game_state = HL_GS_TITLE_SCREEN;
|
|
||||||
static card_t game_board[GAME_BOARD_SIZE] = {0};
|
|
||||||
static uint8_t guess_position = 0;
|
|
||||||
static uint8_t score = 0;
|
|
||||||
static uint8_t completed_board_count = 0;
|
|
||||||
static uint8_t deck[DECK_SIZE] = {0};
|
|
||||||
static uint8_t current_card = 0;
|
|
||||||
|
|
||||||
static uint8_t generate_random_number(uint8_t num_values) {
|
|
||||||
// Emulator: use rand. Hardware: use arc4random.
|
|
||||||
#if __EMSCRIPTEN__
|
|
||||||
return rand() % num_values;
|
|
||||||
#else
|
|
||||||
return arc4random_uniform(num_values);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void stack_deck(void) {
|
|
||||||
for (size_t i = 0; i < CARD_RANK_COUNT; i++) {
|
|
||||||
for (size_t j = 0; j < CARD_SUIT_COUNT; j++)
|
|
||||||
deck[(i * CARD_SUIT_COUNT) + j] = MIN_CARD_VALUE + i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void shuffle_deck(void) {
|
|
||||||
// Randomize shuffle with Fisher Yates
|
|
||||||
size_t i;
|
|
||||||
size_t j;
|
|
||||||
uint8_t tmp;
|
|
||||||
|
|
||||||
for (i = DECK_SIZE - 1; i > 0; i--) {
|
|
||||||
j = generate_random_number(0xFF) % (i + 1);
|
|
||||||
tmp = deck[j];
|
|
||||||
deck[j] = deck[i];
|
|
||||||
deck[i] = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void reset_deck(void) {
|
|
||||||
current_card = 0;
|
|
||||||
stack_deck();
|
|
||||||
shuffle_deck();
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t get_next_card(void) {
|
|
||||||
if (current_card >= DECK_SIZE)
|
|
||||||
reset_deck();
|
|
||||||
return deck[current_card++];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void reset_board(bool first_round) {
|
|
||||||
// First card is random on the first board, and carried over from the last position on subsequent boards
|
|
||||||
const uint8_t first_card_value = first_round
|
|
||||||
? get_next_card()
|
|
||||||
: game_board[GAME_BOARD_SIZE - 1].value;
|
|
||||||
|
|
||||||
game_board[0].value = first_card_value;
|
|
||||||
game_board[0].revealed = true; // Always reveal first card
|
|
||||||
|
|
||||||
// Fill remainder of board
|
|
||||||
for (size_t i = 1; i < GAME_BOARD_SIZE; ++i) {
|
|
||||||
game_board[i] = (card_t) {
|
|
||||||
.value = get_next_card(),
|
|
||||||
.revealed = false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init_game(void) {
|
|
||||||
watch_clear_display();
|
|
||||||
watch_display_string(TITLE_TEXT, BOARD_DISPLAY_START);
|
|
||||||
watch_display_string("GA", STATUS_DISPLAY_START);
|
|
||||||
reset_deck();
|
|
||||||
reset_board(true);
|
|
||||||
score = 0;
|
|
||||||
completed_board_count = 0;
|
|
||||||
guess_position = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_segment_at_position(segment_t segment, uint8_t position) {
|
|
||||||
const uint64_t position_segment_data = (Segment_Map[position] >> (8 * (uint8_t) segment)) & 0xFF;
|
|
||||||
const uint8_t com_pin = position_segment_data >> 6;
|
|
||||||
const uint8_t seg = position_segment_data & 0x3F;
|
|
||||||
watch_set_pixel(com_pin, seg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void render_board_position(size_t board_position) {
|
|
||||||
const size_t display_position = FLIP_BOARD_DIRECTION
|
|
||||||
? BOARD_DISPLAY_START + board_position
|
|
||||||
: BOARD_DISPLAY_END - board_position;
|
|
||||||
const bool revealed = game_board[board_position].revealed;
|
|
||||||
|
|
||||||
//// Current position indicator spot
|
|
||||||
//if (board_position == guess_position) {
|
|
||||||
// watch_display_character('-', display_position);
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
|
|
||||||
if (!revealed) {
|
|
||||||
// Higher or lower indicator (currently just an empty space)
|
|
||||||
watch_display_character(' ', display_position);
|
|
||||||
//set_segment_at_position(F, display_position);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t value = game_board[board_position].value;
|
|
||||||
switch (value) {
|
|
||||||
case 14: // A (≡)
|
|
||||||
watch_display_character(' ', display_position);
|
|
||||||
set_segment_at_position(A, display_position);
|
|
||||||
set_segment_at_position(D, display_position);
|
|
||||||
set_segment_at_position(G, display_position);
|
|
||||||
break;
|
|
||||||
case 13: // K (=)
|
|
||||||
watch_display_character(' ', display_position);
|
|
||||||
set_segment_at_position(A, display_position);
|
|
||||||
set_segment_at_position(D, display_position);
|
|
||||||
break;
|
|
||||||
case 12: // Q (-)
|
|
||||||
watch_display_character('-', display_position);
|
|
||||||
break;
|
|
||||||
default: {
|
|
||||||
const char display_char = (value - MIN_CARD_VALUE) + '0';
|
|
||||||
watch_display_character(display_char, display_position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void render_board(void) {
|
|
||||||
for (size_t i = 0; i < GAME_BOARD_SIZE; ++i) {
|
|
||||||
render_board_position(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void render_board_count(void) {
|
|
||||||
// Render completed boards (screens)
|
|
||||||
char buf[3] = {0};
|
|
||||||
snprintf(buf, sizeof(buf), "%2hhu", completed_board_count);
|
|
||||||
watch_display_string(buf, BOARD_SCORE_DISPLAY_START);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void render_final_score(void) {
|
|
||||||
watch_display_string("SC", STATUS_DISPLAY_START);
|
|
||||||
char buf[7] = {0};
|
|
||||||
const uint8_t complete_boards = score / GUESSES_PER_SCREEN;
|
|
||||||
snprintf(buf, sizeof(buf), "%2hu %03hu", complete_boards, score);
|
|
||||||
watch_set_colon();
|
|
||||||
watch_display_string(buf, BOARD_DISPLAY_START);
|
|
||||||
}
|
|
||||||
|
|
||||||
static guess_t get_answer(void) {
|
|
||||||
if (guess_position < 1 || guess_position > GAME_BOARD_SIZE)
|
|
||||||
return HL_GUESS_EQUAL; // Maybe add an error state, shouldn't ever hit this.
|
|
||||||
|
|
||||||
game_board[guess_position].revealed = true;
|
|
||||||
const uint8_t previous_value = game_board[guess_position - 1].value;
|
|
||||||
const uint8_t current_value = game_board[guess_position].value;
|
|
||||||
|
|
||||||
if (current_value > previous_value)
|
|
||||||
return HL_GUESS_HIGHER;
|
|
||||||
else if (current_value < previous_value)
|
|
||||||
return HL_GUESS_LOWER;
|
|
||||||
else
|
|
||||||
return HL_GUESS_EQUAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void do_game_loop(guess_t user_guess) {
|
|
||||||
switch (game_state) {
|
|
||||||
case HL_GS_TITLE_SCREEN:
|
|
||||||
init_game();
|
|
||||||
render_board();
|
|
||||||
render_board_count();
|
|
||||||
game_state = HL_GS_GUESSING;
|
|
||||||
break;
|
|
||||||
case HL_GS_GUESSING: {
|
|
||||||
const guess_t answer = get_answer();
|
|
||||||
|
|
||||||
// Render answer indicator
|
|
||||||
switch (answer) {
|
|
||||||
case HL_GUESS_EQUAL:
|
|
||||||
watch_display_string("==", STATUS_DISPLAY_START);
|
|
||||||
break;
|
|
||||||
case HL_GUESS_HIGHER:
|
|
||||||
watch_display_string("HI", STATUS_DISPLAY_START);
|
|
||||||
break;
|
|
||||||
case HL_GUESS_LOWER:
|
|
||||||
watch_display_string("LO", STATUS_DISPLAY_START);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scoring
|
|
||||||
if (answer == user_guess) {
|
|
||||||
score++;
|
|
||||||
} else if (answer == HL_GUESS_EQUAL) {
|
|
||||||
// No score for two consecutive identical cards
|
|
||||||
} else {
|
|
||||||
// Incorrect guess, game over
|
|
||||||
watch_display_string("GO", STATUS_DISPLAY_START);
|
|
||||||
game_board[guess_position].revealed = true;
|
|
||||||
render_board_position(guess_position);
|
|
||||||
game_state = HL_GS_LOSE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (score >= WIN_SCORE) {
|
|
||||||
// Win, perhaps some kind of animation sequence?
|
|
||||||
watch_display_string("WI", STATUS_DISPLAY_START);
|
|
||||||
watch_display_string(" ", BOARD_SCORE_DISPLAY_START);
|
|
||||||
watch_display_string("------", BOARD_DISPLAY_START);
|
|
||||||
game_state = HL_GS_WIN;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next guess position
|
|
||||||
const bool final_board_guess = guess_position == GAME_BOARD_SIZE - 1;
|
|
||||||
if (final_board_guess) {
|
|
||||||
// Seed new board
|
|
||||||
completed_board_count++;
|
|
||||||
render_board_count();
|
|
||||||
guess_position = 1;
|
|
||||||
reset_board(false);
|
|
||||||
render_board();
|
|
||||||
} else {
|
|
||||||
guess_position++;
|
|
||||||
render_board_position(guess_position - 1);
|
|
||||||
render_board_position(guess_position);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case HL_GS_WIN:
|
|
||||||
case HL_GS_LOSE:
|
|
||||||
// Show score screen on button press from either state
|
|
||||||
watch_clear_display();
|
|
||||||
render_final_score();
|
|
||||||
game_state = HL_GS_SHOW_SCORE;
|
|
||||||
break;
|
|
||||||
case HL_GS_SHOW_SCORE:
|
|
||||||
watch_clear_display();
|
|
||||||
watch_display_string(TITLE_TEXT, BOARD_DISPLAY_START);
|
|
||||||
watch_display_string("GA", STATUS_DISPLAY_START);
|
|
||||||
game_state = HL_GS_TITLE_SCREEN;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
watch_display_string("ERROR", BOARD_DISPLAY_START);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void light_button_handler(void) {
|
|
||||||
do_game_loop(HL_GUESS_HIGHER);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void alarm_button_handler(void) {
|
|
||||||
do_game_loop(HL_GUESS_LOWER);
|
|
||||||
}
|
|
||||||
|
|
||||||
void higher_lower_game_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void **context_ptr) {
|
|
||||||
(void) settings;
|
|
||||||
(void) watch_face_index;
|
|
||||||
|
|
||||||
if (*context_ptr == NULL) {
|
|
||||||
*context_ptr = malloc(sizeof(higher_lower_game_face_state_t));
|
|
||||||
memset(*context_ptr, 0, sizeof(higher_lower_game_face_state_t));
|
|
||||||
// Do any one-time tasks in here; the inside of this conditional happens only at boot.
|
|
||||||
memset(game_board, 0, sizeof(game_board));
|
|
||||||
}
|
|
||||||
// Do any pin or peripheral setup here; this will be called whenever the watch wakes from deep sleep.
|
|
||||||
}
|
|
||||||
|
|
||||||
void higher_lower_game_face_activate(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
higher_lower_game_face_state_t *state = (higher_lower_game_face_state_t *) context;
|
|
||||||
(void) state;
|
|
||||||
// Handle any tasks related to your watch face coming on screen.
|
|
||||||
game_state = HL_GS_TITLE_SCREEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool higher_lower_game_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
|
||||||
higher_lower_game_face_state_t *state = (higher_lower_game_face_state_t *) context;
|
|
||||||
(void) state;
|
|
||||||
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
// Show your initial UI here.
|
|
||||||
watch_display_string(TITLE_TEXT, BOARD_DISPLAY_START);
|
|
||||||
watch_display_string("GA", STATUS_DISPLAY_START);
|
|
||||||
break;
|
|
||||||
case EVENT_TICK:
|
|
||||||
// If needed, update your display here.
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_UP:
|
|
||||||
light_button_handler();
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
// Don't trigger light
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_BUTTON_UP:
|
|
||||||
alarm_button_handler();
|
|
||||||
break;
|
|
||||||
case EVENT_TIMEOUT:
|
|
||||||
// Your watch face will receive this event after a period of inactivity. If it makes sense to resign,
|
|
||||||
// you may uncomment this line to move back to the first watch face in the list:
|
|
||||||
// movement_move_to_face(0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return movement_default_loop_handler(event, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
// return true if the watch can enter standby mode. Generally speaking, you should always return true.
|
|
||||||
// Exceptions:
|
|
||||||
// * If you are displaying a color using the low-level watch_set_led_color function, you should return false.
|
|
||||||
// * If you are sounding the buzzer using the low-level watch_set_buzzer_on function, you should return false.
|
|
||||||
// Note that if you are driving the LED or buzzer using Movement functions like movement_illuminate_led or
|
|
||||||
// movement_play_alarm, you can still return true. This guidance only applies to the low-level watch_ functions.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void higher_lower_game_face_resign(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
(void) context;
|
|
||||||
|
|
||||||
// handle any cleanup before your watch face goes off-screen.
|
|
||||||
}
|
|
@ -1,106 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Chris Ellis
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef HIGHER_LOWER_GAME_FACE_H_
|
|
||||||
#define HIGHER_LOWER_GAME_FACE_H_
|
|
||||||
|
|
||||||
#include "movement.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Higher-Lower game face
|
|
||||||
* ======================
|
|
||||||
*
|
|
||||||
* A game face based on the "higher-lower" card game where the objective is to correctly guess if the next card will
|
|
||||||
* be higher or lower than the last revealed cards.
|
|
||||||
*
|
|
||||||
* Game Flow:
|
|
||||||
* - When the face is selected, the "Hi-Lo" "Title" screen will be displayed, and the status indicator will display "GA" for game
|
|
||||||
* - Pressing `ALARM` or `LIGHT` will start the game and proceed to the "Guessing" screen
|
|
||||||
* - The first card will be revealed and the player must now make a guess
|
|
||||||
* - A player can guess `Higher` by pressing the `LIGHT` button, and `Lower` by pressing the `ALARM` button
|
|
||||||
* - The status indicator will show the result of the guess: HI (Higher), LO (Lower), or == (Equal)
|
|
||||||
* - There are five guesses to make on each game screen, once the end of the screen is reached, a new screen
|
|
||||||
* will be started, with the last revealed card carried over
|
|
||||||
* - The number of completed screens is displayed in the top right (see Scoring)
|
|
||||||
* - If the player has guessed correctly, the score is updated and play continues (see Scoring)
|
|
||||||
* - If the player has guessed incorrectly, the status will change to GO (Game Over)
|
|
||||||
* - The current card will be revealed
|
|
||||||
* - Pressing `ALARM` or `LIGHT` will transition to the "Score" screen
|
|
||||||
* - If the game is won, the status indicator will display "WI" and the "Win" screen will be displayed
|
|
||||||
* - Pressing `ALARM` or `LIGHT` will transition to the "Score" screen
|
|
||||||
* - The status indicator will change to "SC" when the final score is displayed
|
|
||||||
* - The number of completed game screens will be displayed on using the first two digits
|
|
||||||
* - The number of correct guesses will be displayed using the final three digits
|
|
||||||
* - E.g. "13: 063" represents 13 completed screens, with 63 correct guesses
|
|
||||||
* - Pressing `ALARM` or `LIGHT` while on the "Score" screen will transition to back to the "Title" screen
|
|
||||||
*
|
|
||||||
* Scoring:
|
|
||||||
* - If the player guesses correctly (HI/LO) a point is gained
|
|
||||||
* - If the player guesses incorrectly the game ends
|
|
||||||
* - Unless the revealed card is equal (==) to the last card, in which case play continues, but no point is gained
|
|
||||||
* - If the player completes 40 screens full of cards, the game ends and a win screen is displayed
|
|
||||||
*
|
|
||||||
* Misc:
|
|
||||||
* The face tries to remain true to the spirit of using "cards"; to cope with the display limitations I've arrived at
|
|
||||||
* the following mapping of card values to screen display, but am open to better suggestions:
|
|
||||||
*
|
|
||||||
* Thanks to voloved for adding deck shuffling and drawing!
|
|
||||||
*
|
|
||||||
* | Cards | |
|
|
||||||
* |---------|--------------------------|
|
|
||||||
* | Value |2|3|4|5|6|7|8|9|10|J|Q|K|A|
|
|
||||||
* | Display |0|1|2|3|4|5|6|7|8 |9|-|=|≡|
|
|
||||||
*
|
|
||||||
* A previous alternative can be found in the git history:
|
|
||||||
* | Cards | |
|
|
||||||
* |---------|--------------------------|
|
|
||||||
* | Value |2|3|4|5|6|7|8|9|10|J|Q|K|A|
|
|
||||||
* | Display |2|3|4|5|6|7|8|9| 0|-|=|≡|H|
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Future Ideas:
|
|
||||||
* - Add sounds
|
|
||||||
* - Save/Display high score
|
|
||||||
* - Add a "Win" animation
|
|
||||||
* - Consider using lap indicator for larger score limit
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
// Anything you need to keep track of, put it here!
|
|
||||||
} higher_lower_game_face_state_t;
|
|
||||||
|
|
||||||
void higher_lower_game_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
|
||||||
void higher_lower_game_face_activate(movement_settings_t *settings, void *context);
|
|
||||||
bool higher_lower_game_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
|
||||||
void higher_lower_game_face_resign(movement_settings_t *settings, void *context);
|
|
||||||
|
|
||||||
#define higher_lower_game_face ((const watch_face_t){ \
|
|
||||||
higher_lower_game_face_setup, \
|
|
||||||
higher_lower_game_face_activate, \
|
|
||||||
higher_lower_game_face_loop, \
|
|
||||||
higher_lower_game_face_resign, \
|
|
||||||
NULL, \
|
|
||||||
})
|
|
||||||
|
|
||||||
#endif // HIGHER_LOWER_GAME_FACE_H_
|
|
@ -1,472 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Joseph Borne Komosa | @jokomo24
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Menstrual Cycle Face
|
|
||||||
*
|
|
||||||
* Background:
|
|
||||||
*
|
|
||||||
* I discovered the Casio F-91W through my partner, appreciated the retro aesthetic of the watch,
|
|
||||||
* and got one for myself. Soon afterward I discovered the Sensor Watch project and ordered two boards!
|
|
||||||
* I introduced the Sensor Watch to my partner who inquired whether she could track her menstrual cycle.
|
|
||||||
* So I decided to implement a menstrual cycle watch face that also calculates the peak fertility window
|
|
||||||
* using The Calendar Method. While this information may be useful when attempting to achieve or avoid
|
|
||||||
* pregnancy, it is important to understand that these are rough estimates at best.
|
|
||||||
*
|
|
||||||
* How to use:
|
|
||||||
*
|
|
||||||
* 1. To begin tracking, go to 'Last Period' page and toggle the alarm button to the number of days since
|
|
||||||
* the last, most recent, period and hold the alarm button to enter. This will perform the following actions:
|
|
||||||
* - Store the corresponding date as the 'first' period in order to calculate the total_days_tracked.
|
|
||||||
* - Turn on the Signal Indicator to signify that tracking has been activated.
|
|
||||||
* - Deactivate this page and instead show the ticking animation.
|
|
||||||
* - Adjust the days left in the 'Period in <num> Days' page accordingly.
|
|
||||||
* - Activate the 'Period Is Here' page and no longer display 'NA'. To prevent accidental user entry,
|
|
||||||
* the page will display the ticking animation until ten days have passed since the date of the last
|
|
||||||
* period entered.
|
|
||||||
* - Activate the 'Peak Fertility' page to begin showing the estimated window,
|
|
||||||
* as well as display the Alarm Indicator, on this page and on the main 'Period in <num> Days' page,
|
|
||||||
* whenever the current date falls within the Peak Fertility Window.
|
|
||||||
*
|
|
||||||
* 2. Toggle and enter 'y' in the 'Period Is Here' page on the day of every sequential period afterward.
|
|
||||||
* DO NOT FORGET TO DO SO!
|
|
||||||
* - If forgotten, the data will become inaccurate and tracking will need to be reset! -> (FIXME, allow one to enter a 'missed' period using the 'Last Period' page).
|
|
||||||
* This will perform the following actions:
|
|
||||||
* - Calculate this completed cycle's length and reevaluate the shortest and longest cycle variables.
|
|
||||||
* - Increment total_cycles by one.
|
|
||||||
* - Recalculate and save the average cycle for 'Average Cycle' page.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "menstrual_cycle_face.h"
|
|
||||||
#include "watch.h"
|
|
||||||
#include "watch_utility.h"
|
|
||||||
|
|
||||||
#define TYPICAL_AVG_CYC 28
|
|
||||||
#define SECONDS_PER_DAY 86400
|
|
||||||
|
|
||||||
#define MENSTRUAL_CYCLE_FACE_NUM_PAGES (6)
|
|
||||||
enum {
|
|
||||||
period_in_num_days,
|
|
||||||
average_cycle,
|
|
||||||
peak_fertility_window,
|
|
||||||
period_is_here,
|
|
||||||
first_period,
|
|
||||||
reset,
|
|
||||||
} page_titles_e;
|
|
||||||
const char menstrual_cycle_face_titles[MENSTRUAL_CYCLE_FACE_NUM_PAGES][11] = {
|
|
||||||
"Prin day", // Period In <num> Days: Estimated days till the next period occurs
|
|
||||||
"Av cycle ", // Average Cycle: The average number of days estimated per cycle
|
|
||||||
"Peak Fert ", // Peak Fertility Window: The first and last day of month (displayed top & bottom right, respectively, once tracking) for the estimated window of fertility
|
|
||||||
"Prishere ", // Period Is Here: Toggle and enter 'y' on the day the actual period occurs to improve Avg and Fert estimations
|
|
||||||
"Last Per ", // Last Period: Enter the number of days since the last period to begin tracking from that corresponding date by storing it as the 'first'
|
|
||||||
" Reset ", // Reset: Toggle and enter 'y' to reset tracking data
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Beep function */
|
|
||||||
static inline void beep(movement_settings_t *settings) {
|
|
||||||
if (settings->bit.button_should_sound)
|
|
||||||
watch_buzzer_play_note(BUZZER_NOTE_E8, 75);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the total number of days for which menstrual cycle tracking has been active
|
|
||||||
static inline uint32_t total_days_tracked(menstrual_cycle_state_t *state) {
|
|
||||||
|
|
||||||
// If tracking has not yet been activated, return 0
|
|
||||||
if (!(state->dates.reg))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Otherwise, set the start date to the first day of the first tracked cycle
|
|
||||||
watch_date_time date_time_start;
|
|
||||||
date_time_start.unit.second = 0;
|
|
||||||
date_time_start.unit.minute = 0;
|
|
||||||
date_time_start.unit.hour = 0;
|
|
||||||
date_time_start.unit.day = state->dates.bit.first_day;
|
|
||||||
date_time_start.unit.month = state->dates.bit.first_month;
|
|
||||||
date_time_start.unit.year = state->dates.bit.first_year;
|
|
||||||
|
|
||||||
// Get the current date and time
|
|
||||||
watch_date_time date_time_now = watch_rtc_get_date_time();
|
|
||||||
|
|
||||||
// Convert the start date and current date to Unix time
|
|
||||||
uint32_t unix_start = watch_utility_date_time_to_unix_time(date_time_start, state->utc_offset);
|
|
||||||
uint32_t unix_now = watch_utility_date_time_to_unix_time(date_time_now, state->utc_offset);
|
|
||||||
|
|
||||||
// Calculate the total number of days and return it
|
|
||||||
return (unix_now - unix_start) / SECONDS_PER_DAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the number of days until the next menstrual period
|
|
||||||
static inline int8_t days_till_period(menstrual_cycle_state_t *state) {
|
|
||||||
|
|
||||||
// Calculate the number of days left until the next period based on the average cycle length and the number of cycles tracked
|
|
||||||
int8_t days_left = (state->cycles.bit.average_cycle * (state->cycles.bit.total_cycles + 1)) - total_days_tracked(state);
|
|
||||||
|
|
||||||
// If the result is negative, return 0 (i.e., the period is expected to start today or has already started)
|
|
||||||
return (days_left < 0) ? 0 : days_left;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void reset_tracking(menstrual_cycle_state_t *state) {
|
|
||||||
|
|
||||||
state->dates.bit.first_day = 0;
|
|
||||||
state->dates.bit.first_month = 0;
|
|
||||||
state->dates.bit.first_year = 0;
|
|
||||||
|
|
||||||
state->dates.bit.prev_day = 0;
|
|
||||||
state->dates.bit.prev_month = 0;
|
|
||||||
state->dates.bit.prev_year = 0;
|
|
||||||
|
|
||||||
state->cycles.bit.shortest_cycle = TYPICAL_AVG_CYC;
|
|
||||||
state->cycles.bit.longest_cycle = TYPICAL_AVG_CYC;
|
|
||||||
state->cycles.bit.average_cycle = TYPICAL_AVG_CYC;
|
|
||||||
state->cycles.bit.total_cycles = 0;
|
|
||||||
|
|
||||||
state->dates.bit.reserved = 0;
|
|
||||||
state->cycles.bit.reserved = 0;
|
|
||||||
|
|
||||||
watch_store_backup_data(state->dates.reg, state->backup_register_dt);
|
|
||||||
watch_store_backup_data(state->cycles.reg, state->backup_register_cy);
|
|
||||||
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_SIGNAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Fertility Window based on "The Calendar Method"
|
|
||||||
Source: https://www.womenshealth.gov/pregnancy/you-get-pregnant/trying-conceive
|
|
||||||
|
|
||||||
The Calendar Method has several steps:
|
|
||||||
|
|
||||||
Step 1: Track the menstrual cycle for 8–12 months. One cycle is from the first day of one
|
|
||||||
period until the first day of the next period. The average cycle is 28 days, but
|
|
||||||
it may be as short as 24 days or as long as 38 days.
|
|
||||||
Step 2: Subtract 18 from the number of days in the shortest menstrual cycle.
|
|
||||||
Step 3: Subtract 11 from the number of days in the longest menstrual cycle.
|
|
||||||
Step 4: Using a calendar, mark down the start of the next period (using previous instead). Count ahead by the number
|
|
||||||
of days calculated in step 2. This is when peak fertility begins. Peak fertility ends
|
|
||||||
at the number of days calculated in step 3.
|
|
||||||
NOTE: Right now, the fertility window face displays its estimated window as soon as tracking is activated, although
|
|
||||||
it is important to keep in mind that The Calendar Method states that peak accuracy of the window will be
|
|
||||||
reached only after at least 8 months of tracking the menstrual cycle (can make it so that it only displays
|
|
||||||
after total_days_tracked >= 8 months...but the info is interesting and should already be taken with the understanding that,
|
|
||||||
in general, it is a rough estimation at best).
|
|
||||||
*/
|
|
||||||
typedef enum Fertile_Window {first_day, last_day} fertile_window;
|
|
||||||
// Calculate the predicted starting or ending day of peak fertility
|
|
||||||
static inline uint32_t get_day_pk_fert(menstrual_cycle_state_t *state, fertile_window which_day) {
|
|
||||||
|
|
||||||
// Get the date of the previous period
|
|
||||||
watch_date_time date_prev_period;
|
|
||||||
date_prev_period.unit.second = 0;
|
|
||||||
date_prev_period.unit.minute = 0;
|
|
||||||
date_prev_period.unit.hour = 0;
|
|
||||||
date_prev_period.unit.day = state->dates.bit.prev_day;
|
|
||||||
date_prev_period.unit.month = state->dates.bit.prev_month;
|
|
||||||
date_prev_period.unit.year = state->dates.bit.prev_year;
|
|
||||||
|
|
||||||
// Convert the previous period date to Unix time
|
|
||||||
uint32_t unix_prev_period = watch_utility_date_time_to_unix_time(date_prev_period, state->utc_offset);
|
|
||||||
|
|
||||||
// Calculate the Unix time of the predicted peak fertility day based on the length of the shortest/longest cycle
|
|
||||||
uint32_t unix_pk_date;
|
|
||||||
switch(which_day) {
|
|
||||||
case first_day:
|
|
||||||
unix_pk_date = unix_prev_period + ((state->cycles.bit.shortest_cycle - 18) * SECONDS_PER_DAY);
|
|
||||||
break;
|
|
||||||
case last_day:
|
|
||||||
unix_pk_date = unix_prev_period + ((state->cycles.bit.longest_cycle - 11) * SECONDS_PER_DAY);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the Unix time of the predicted peak fertility day to a date/time and return the day of the month
|
|
||||||
return watch_utility_date_time_from_unix_time(unix_pk_date, state->utc_offset).unit.day;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine if today falls within the predicted peak fertility window
|
|
||||||
static inline bool inside_fert_window(menstrual_cycle_state_t *state) {
|
|
||||||
|
|
||||||
// If tracking has not yet been activated, return false
|
|
||||||
if (!(state->dates.reg))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Get the current date/time
|
|
||||||
watch_date_time date_time_now = watch_rtc_get_date_time();
|
|
||||||
|
|
||||||
// Check if the current day falls between the first and last predicted peak fertility days
|
|
||||||
if (get_day_pk_fert(state, first_day) > get_day_pk_fert(state, last_day)) { // We are crossing over the end of the month
|
|
||||||
if (date_time_now.unit.day >= get_day_pk_fert(state, first_day) ||
|
|
||||||
date_time_now.unit.day <= get_day_pk_fert(state, last_day))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (date_time_now.unit.day >= get_day_pk_fert(state, first_day) &&
|
|
||||||
date_time_now.unit.day <= get_day_pk_fert(state, last_day))
|
|
||||||
return true;
|
|
||||||
// If the current day does not fall within the predicted peak fertility window, return false
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the shortest and longest menstrual cycles based on the previous menstrual cycle
|
|
||||||
static inline void update_shortest_longest_cycle(menstrual_cycle_state_t *state) {
|
|
||||||
|
|
||||||
// Get the date of the previous menstrual cycle
|
|
||||||
watch_date_time date_prev_period;
|
|
||||||
date_prev_period.unit.second = 0;
|
|
||||||
date_prev_period.unit.minute = 0;
|
|
||||||
date_prev_period.unit.hour = 0;
|
|
||||||
date_prev_period.unit.day = state->dates.bit.prev_day;
|
|
||||||
date_prev_period.unit.month = state->dates.bit.prev_month;
|
|
||||||
date_prev_period.unit.year = state->dates.bit.prev_year;
|
|
||||||
|
|
||||||
// Convert the date of the previous menstrual cycle to UNIX time
|
|
||||||
uint32_t unix_prev_period = watch_utility_date_time_to_unix_time(date_prev_period, state->utc_offset);
|
|
||||||
|
|
||||||
// Calculate the length of the current menstrual cycle
|
|
||||||
uint8_t cycle_length = total_days_tracked(state) - (unix_prev_period / SECONDS_PER_DAY);
|
|
||||||
|
|
||||||
// Update the shortest or longest cycle length if necessary
|
|
||||||
if (cycle_length < state->cycles.bit.shortest_cycle)
|
|
||||||
state->cycles.bit.shortest_cycle = cycle_length;
|
|
||||||
else if (cycle_length > state->cycles.bit.longest_cycle)
|
|
||||||
state->cycles.bit.longest_cycle = cycle_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void menstrual_cycle_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
|
||||||
(void) watch_face_index;
|
|
||||||
(void) settings;
|
|
||||||
|
|
||||||
if (*context_ptr == NULL) {
|
|
||||||
*context_ptr = malloc(sizeof(menstrual_cycle_state_t));
|
|
||||||
memset(*context_ptr, 0, sizeof(menstrual_cycle_state_t));
|
|
||||||
menstrual_cycle_state_t *state = ((menstrual_cycle_state_t *)*context_ptr);
|
|
||||||
|
|
||||||
state->dates.bit.first_day = 0;
|
|
||||||
state->dates.bit.first_month = 0;
|
|
||||||
state->dates.bit.first_year = 0;
|
|
||||||
|
|
||||||
state->dates.bit.prev_day = 0;
|
|
||||||
state->dates.bit.prev_month = 0;
|
|
||||||
state->dates.bit.prev_year = 0;
|
|
||||||
|
|
||||||
state->cycles.bit.shortest_cycle = TYPICAL_AVG_CYC;
|
|
||||||
state->cycles.bit.longest_cycle = TYPICAL_AVG_CYC;
|
|
||||||
state->cycles.bit.average_cycle = TYPICAL_AVG_CYC;
|
|
||||||
state->cycles.bit.total_cycles = 0;
|
|
||||||
|
|
||||||
state->dates.bit.reserved = 0;
|
|
||||||
state->cycles.bit.reserved = 0;
|
|
||||||
|
|
||||||
state->backup_register_dt = 0;
|
|
||||||
state->backup_register_cy = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
menstrual_cycle_state_t *state = ((menstrual_cycle_state_t *)*context_ptr);
|
|
||||||
if (!(state->backup_register_dt && state->backup_register_cy)) {
|
|
||||||
state->backup_register_dt = movement_claim_backup_register();
|
|
||||||
state->backup_register_cy = movement_claim_backup_register();
|
|
||||||
|
|
||||||
if (state->backup_register_dt && state->backup_register_cy) {
|
|
||||||
watch_store_backup_data(state->dates.reg, state->backup_register_dt);
|
|
||||||
watch_store_backup_data(state->cycles.reg, state->backup_register_cy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
state->dates.reg = watch_get_backup_data(state->backup_register_dt);
|
|
||||||
state->cycles.reg = watch_get_backup_data(state->backup_register_cy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void menstrual_cycle_face_activate(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
menstrual_cycle_state_t *state = (menstrual_cycle_state_t *)context;
|
|
||||||
state->period_today = 0;
|
|
||||||
state->current_page = 0;
|
|
||||||
state->reset_tracking = 0;
|
|
||||||
state->utc_offset = movement_timezone_offsets[settings->bit.time_zone] * 60;
|
|
||||||
movement_request_tick_frequency(4); // we need to manually blink some pixels
|
|
||||||
}
|
|
||||||
|
|
||||||
bool menstrual_cycle_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
|
||||||
menstrual_cycle_state_t *state = (menstrual_cycle_state_t *)context;
|
|
||||||
watch_date_time date_period;
|
|
||||||
uint8_t current_page = state->current_page;
|
|
||||||
uint8_t first_day_fert;
|
|
||||||
uint8_t last_day_fert;
|
|
||||||
uint32_t unix_now;
|
|
||||||
uint32_t unix_prev_period;
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_TICK:
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
// Do nothing; handled below.
|
|
||||||
break;
|
|
||||||
case EVENT_MODE_BUTTON_UP:
|
|
||||||
movement_move_to_next_face();
|
|
||||||
return false;
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
current_page = (current_page + 1) % MENSTRUAL_CYCLE_FACE_NUM_PAGES;
|
|
||||||
state->current_page = current_page;
|
|
||||||
state->days_prev_period = 0;
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
if (watch_tick_animation_is_running())
|
|
||||||
watch_stop_tick_animation();
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_LONG_PRESS:
|
|
||||||
switch (current_page) {
|
|
||||||
case period_in_num_days:
|
|
||||||
break;
|
|
||||||
case average_cycle:
|
|
||||||
break;
|
|
||||||
case peak_fertility_window:
|
|
||||||
break;
|
|
||||||
case period_is_here:
|
|
||||||
if (state->period_today && total_days_tracked(state)) {
|
|
||||||
// Calculate before updating date of last period
|
|
||||||
update_shortest_longest_cycle(state);
|
|
||||||
// Update the date of last period after calulating the, now previous, cycle length
|
|
||||||
date_period = watch_rtc_get_date_time();
|
|
||||||
state->dates.bit.prev_day = date_period.unit.day;
|
|
||||||
state->dates.bit.prev_month = date_period.unit.month;
|
|
||||||
state->dates.bit.prev_year = date_period.unit.year;
|
|
||||||
// Calculate new cycle average
|
|
||||||
state->cycles.bit.total_cycles += 1;
|
|
||||||
state->cycles.bit.average_cycle = total_days_tracked(state) / state->cycles.bit.total_cycles;
|
|
||||||
// Store the new data
|
|
||||||
watch_store_backup_data(state->dates.reg, state->backup_register_dt);
|
|
||||||
watch_store_backup_data(state->cycles.reg, state->backup_register_cy);
|
|
||||||
state->period_today = !(state->period_today);
|
|
||||||
beep(settings);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case first_period:
|
|
||||||
// If tracking has not yet been activated
|
|
||||||
if (!(state->dates.reg)) {
|
|
||||||
unix_now = watch_utility_date_time_to_unix_time(watch_rtc_get_date_time(), state->utc_offset);
|
|
||||||
unix_prev_period = unix_now - (state->days_prev_period * SECONDS_PER_DAY);
|
|
||||||
date_period = watch_utility_date_time_from_unix_time(unix_prev_period, state->utc_offset);
|
|
||||||
state->dates.bit.first_day = date_period.unit.day;
|
|
||||||
state->dates.bit.first_month = date_period.unit.month;
|
|
||||||
state->dates.bit.first_year = date_period.unit.year;
|
|
||||||
state->dates.bit.prev_day = date_period.unit.day;
|
|
||||||
state->dates.bit.prev_month = date_period.unit.month;
|
|
||||||
state->dates.bit.prev_year = date_period.unit.year;
|
|
||||||
watch_store_backup_data(state->dates.reg, state->backup_register_dt);
|
|
||||||
beep(settings);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case reset:
|
|
||||||
if (state->reset_tracking) {
|
|
||||||
reset_tracking(state);
|
|
||||||
state->reset_tracking = !(state->reset_tracking);
|
|
||||||
beep(settings);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_BUTTON_UP:
|
|
||||||
switch (current_page) {
|
|
||||||
case period_in_num_days:
|
|
||||||
break;
|
|
||||||
case average_cycle:
|
|
||||||
break;
|
|
||||||
case peak_fertility_window:
|
|
||||||
break;
|
|
||||||
case period_is_here:
|
|
||||||
if (total_days_tracked(state))
|
|
||||||
state->period_today = !(state->period_today);
|
|
||||||
break;
|
|
||||||
case first_period:
|
|
||||||
if (!(state->dates.reg))
|
|
||||||
state->days_prev_period = (state->days_prev_period > 99) ? 0 : state->days_prev_period + 1; // Cycle through pages to quickly reset to 0
|
|
||||||
break;
|
|
||||||
case reset:
|
|
||||||
state->reset_tracking = !(state->reset_tracking);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_TIMEOUT:
|
|
||||||
movement_move_to_face(0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return movement_default_loop_handler(event, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
watch_display_string((char *)menstrual_cycle_face_titles[current_page], 0);
|
|
||||||
if (state->dates.reg)
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_SIGNAL); // signal that we are now in a tracking state
|
|
||||||
|
|
||||||
char buf[13];
|
|
||||||
switch (current_page) {
|
|
||||||
case period_in_num_days:
|
|
||||||
sprintf(buf, "%2d", days_till_period(state));
|
|
||||||
if (inside_fert_window(state))
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
watch_display_string(buf, 4);
|
|
||||||
break;
|
|
||||||
case average_cycle:
|
|
||||||
sprintf(buf, "%2d", state->cycles.bit.average_cycle);
|
|
||||||
watch_display_string(buf, 2);
|
|
||||||
break;
|
|
||||||
case peak_fertility_window:
|
|
||||||
if (event.subsecond % 5 && state->dates.reg) { // blink active for 3 quarter-seconds
|
|
||||||
first_day_fert = get_day_pk_fert(state, first_day);
|
|
||||||
last_day_fert = get_day_pk_fert(state, last_day);
|
|
||||||
sprintf(buf, "Fr%2d To %2d", first_day_fert, last_day_fert); // From: first day | To: last day
|
|
||||||
if (inside_fert_window(state))
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case period_is_here:
|
|
||||||
if (event.subsecond % 5) { // blink active for 3 quarter-seconds
|
|
||||||
if (!(state->dates.reg))
|
|
||||||
watch_display_string("NA", 8); // Not Applicable: Do not allow period entry until tracking is activated...
|
|
||||||
else if (state->period_today)
|
|
||||||
watch_display_string("y", 9);
|
|
||||||
else
|
|
||||||
watch_display_string("n", 9);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case first_period:
|
|
||||||
if (state->dates.reg) {
|
|
||||||
if (!watch_tick_animation_is_running())
|
|
||||||
watch_start_tick_animation(500); // Tracking activated
|
|
||||||
}
|
|
||||||
else if (event.subsecond % 5) { // blink active for 3 quarter-seconds
|
|
||||||
sprintf(buf, "%2d", state->days_prev_period);
|
|
||||||
watch_display_string(buf, 8);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case reset:
|
|
||||||
// blink active for 3 quarter-seconds
|
|
||||||
if (event.subsecond % 5 && state->reset_tracking)
|
|
||||||
watch_display_string("y", 9);
|
|
||||||
else if (event.subsecond % 5)
|
|
||||||
watch_display_string("n", 9);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void menstrual_cycle_face_resign(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
(void) context;
|
|
||||||
}
|
|
@ -1,80 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Joseph Borne Komosa | @jokomo24
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MENSTRUAL_CYCLE_FACE_H_
|
|
||||||
#define MENSTRUAL_CYCLE_FACE_H_
|
|
||||||
|
|
||||||
#include "movement.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
// Store the date of the 'first' and the total cycles since to calulate and store the average menstrual cycle.
|
|
||||||
// Store the date of the previous, most recent, period to calculate the cycle length.
|
|
||||||
// Store the shortest and longest cycle to calculate the fertility window for The Calender Method.
|
|
||||||
// NOTE: Not thrilled about using two registers, but could not find a way to perform The Calender Method
|
|
||||||
// without requiring both the 'first' and 'prev' dates.
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
uint8_t first_day : 5;
|
|
||||||
uint8_t first_month : 4;
|
|
||||||
uint8_t first_year : 6; // 0-63 (representing 2020-2083)
|
|
||||||
uint8_t prev_day : 5;
|
|
||||||
uint8_t prev_month : 4;
|
|
||||||
uint8_t prev_year : 6; // 0-63 (representing 2020-2083)
|
|
||||||
uint8_t reserved : 2; // left over bit space
|
|
||||||
} bit;
|
|
||||||
uint32_t reg; // Tracking's been activated if > 0
|
|
||||||
} dates;
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
uint8_t shortest_cycle : 6; // For step 2 of The Calender Method
|
|
||||||
uint8_t longest_cycle : 6; // For step 3 of The Calender Method
|
|
||||||
uint8_t average_cycle : 6; // The average menstrual cycle lasts 28 days, but normal cycles can vary from 21 to 35 days
|
|
||||||
uint16_t total_cycles : 11; // The total cycles (periods) entered since the start of tracking
|
|
||||||
uint8_t reserved : 3; // left over bit space
|
|
||||||
} bit;
|
|
||||||
uint32_t reg;
|
|
||||||
} cycles;
|
|
||||||
uint8_t backup_register_dt;
|
|
||||||
uint8_t backup_register_cy;
|
|
||||||
uint8_t current_page;
|
|
||||||
uint8_t days_prev_period;
|
|
||||||
int32_t utc_offset;
|
|
||||||
bool period_today;
|
|
||||||
bool reset_tracking;
|
|
||||||
} menstrual_cycle_state_t;
|
|
||||||
|
|
||||||
void menstrual_cycle_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
|
||||||
void menstrual_cycle_face_activate(movement_settings_t *settings, void *context);
|
|
||||||
bool menstrual_cycle_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
|
||||||
void menstrual_cycle_face_resign(movement_settings_t *settings, void *context);
|
|
||||||
|
|
||||||
#define menstrual_cycle_face ((const watch_face_t){ \
|
|
||||||
menstrual_cycle_face_setup, \
|
|
||||||
menstrual_cycle_face_activate, \
|
|
||||||
menstrual_cycle_face_loop, \
|
|
||||||
menstrual_cycle_face_resign, \
|
|
||||||
NULL, \
|
|
||||||
})
|
|
||||||
|
|
||||||
#endif // MENSTRUAL_CYCLE_FACE_H_
|
|
@ -1,263 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Austin Teets
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "metronome_face.h"
|
|
||||||
#include "watch.h"
|
|
||||||
|
|
||||||
static const int8_t _sound_seq_start[] = {BUZZER_NOTE_C8, 2, 0};
|
|
||||||
static const int8_t _sound_seq_beat[] = {BUZZER_NOTE_C6, 2, 0};
|
|
||||||
|
|
||||||
void metronome_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
|
||||||
(void) settings;
|
|
||||||
(void) watch_face_index;
|
|
||||||
if (*context_ptr == NULL) {
|
|
||||||
*context_ptr = malloc(sizeof(metronome_state_t));
|
|
||||||
memset(*context_ptr, 0, sizeof(metronome_state_t));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void metronome_face_activate(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
metronome_state_t *state = (metronome_state_t *)context;
|
|
||||||
movement_request_tick_frequency(2);
|
|
||||||
if (state->bpm == 0) {
|
|
||||||
state->count = 4;
|
|
||||||
state->bpm = 120;
|
|
||||||
state->soundOn = true;
|
|
||||||
}
|
|
||||||
state->mode = metWait;
|
|
||||||
state->correction = 0;
|
|
||||||
state->setCur = hundred;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _metronome_face_update_lcd(metronome_state_t *state) {
|
|
||||||
char buf[11];
|
|
||||||
if (state->soundOn) {
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
} else {
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
}
|
|
||||||
sprintf(buf, "MN %d %03d%s", state->count, state->bpm, "bp");
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _metronome_start_stop(metronome_state_t *state) {
|
|
||||||
if (state->mode != metRun) {
|
|
||||||
movement_request_tick_frequency(64);
|
|
||||||
state->mode = metRun;
|
|
||||||
watch_clear_display();
|
|
||||||
double ticks = 3840.0 / (double)state->bpm;
|
|
||||||
state->tick = (int) ticks;
|
|
||||||
state->curTick = (int) ticks;
|
|
||||||
state->halfBeat = (int)(state->tick/2);
|
|
||||||
state->curCorrection = ticks - state->tick;
|
|
||||||
state->correction = ticks - state->tick;
|
|
||||||
state->curBeat = 1;
|
|
||||||
} else {
|
|
||||||
state->mode = metWait;
|
|
||||||
movement_request_tick_frequency(2);
|
|
||||||
_metronome_face_update_lcd(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _metronome_tick_beat(metronome_state_t *state) {
|
|
||||||
char buf[11];
|
|
||||||
if (state->soundOn) {
|
|
||||||
if (state->curBeat == 1) {
|
|
||||||
watch_buzzer_play_sequence((int8_t *)_sound_seq_start, NULL);
|
|
||||||
} else {
|
|
||||||
watch_buzzer_play_sequence((int8_t *)_sound_seq_beat, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sprintf(buf, "MN %d %03d%s", state->count, state->bpm, "bp");
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _metronome_event_tick(uint8_t subsecond, metronome_state_t *state) {
|
|
||||||
(void) subsecond;
|
|
||||||
|
|
||||||
if (state->curCorrection >= 1) {
|
|
||||||
state->curCorrection -= 1;
|
|
||||||
state->curTick -= 1;
|
|
||||||
}
|
|
||||||
int diff = state->curTick - state->tick;
|
|
||||||
if(diff == 0) {
|
|
||||||
_metronome_tick_beat(state);
|
|
||||||
state->curTick = 0;
|
|
||||||
state->curCorrection += state->correction;
|
|
||||||
if (state->curBeat < state->count ) {
|
|
||||||
state->curBeat += 1;
|
|
||||||
} else {
|
|
||||||
state->curBeat = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (state->curTick == state->halfBeat) {
|
|
||||||
watch_clear_display();
|
|
||||||
}
|
|
||||||
state->curTick += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _metronome_setting_tick(uint8_t subsecond, metronome_state_t *state) {
|
|
||||||
char buf[13];
|
|
||||||
sprintf(buf, "MN %d %03d%s", state->count, state->bpm, "bp");
|
|
||||||
if (subsecond%2 == 0) {
|
|
||||||
switch (state->setCur) {
|
|
||||||
case hundred:
|
|
||||||
buf[5] = ' ';
|
|
||||||
break;
|
|
||||||
case ten:
|
|
||||||
buf[6] = ' ';
|
|
||||||
break;
|
|
||||||
case one:
|
|
||||||
buf[7] = ' ';
|
|
||||||
break;
|
|
||||||
case count:
|
|
||||||
buf[3] = ' ';
|
|
||||||
break;
|
|
||||||
case alarm:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (state->setCur == alarm) {
|
|
||||||
sprintf(buf, "MN 8eep%s", state->soundOn ? "On" : " -");
|
|
||||||
}
|
|
||||||
if (state->soundOn) {
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
} else {
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
}
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _metronome_update_setting(metronome_state_t *state) {
|
|
||||||
char buf[13];
|
|
||||||
switch (state->setCur) {
|
|
||||||
case hundred:
|
|
||||||
if (state->bpm < 100) {
|
|
||||||
state->bpm += 100;
|
|
||||||
} else {
|
|
||||||
state->bpm -= 100;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ten:
|
|
||||||
if ((state->bpm / 10) % 10 < 9) {
|
|
||||||
state->bpm += 10;
|
|
||||||
} else {
|
|
||||||
state->bpm -= 90;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case one:
|
|
||||||
if (state->bpm%10 < 9) {
|
|
||||||
state->bpm += 1;
|
|
||||||
} else {
|
|
||||||
state->bpm -= 9;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case count:
|
|
||||||
if (state->count < 9) {
|
|
||||||
state->count += 1;
|
|
||||||
} else {
|
|
||||||
state->count = 2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case alarm:
|
|
||||||
state->soundOn = !state->soundOn;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sprintf(buf, "MN %d %03d%s", state->count % 10, state->bpm, "bp");
|
|
||||||
if (state->setCur == alarm) {
|
|
||||||
sprintf(buf, "MN 8eep%s", state->soundOn ? "On" : " -");
|
|
||||||
}
|
|
||||||
if (state->soundOn) {
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
} else {
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_BELL);
|
|
||||||
}
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool metronome_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
|
||||||
metronome_state_t *state = (metronome_state_t *)context;
|
|
||||||
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
_metronome_face_update_lcd(state);
|
|
||||||
break;
|
|
||||||
case EVENT_TICK:
|
|
||||||
if (state->mode == metRun){
|
|
||||||
_metronome_event_tick(event.subsecond, state);
|
|
||||||
} else if (state->mode == setMenu) {
|
|
||||||
_metronome_setting_tick(event.subsecond, state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_BUTTON_UP:
|
|
||||||
if (state->mode == setMenu) {
|
|
||||||
_metronome_update_setting(state);
|
|
||||||
} else {
|
|
||||||
_metronome_start_stop(state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
if (state->mode == setMenu) {
|
|
||||||
if (state->setCur < alarm) {
|
|
||||||
state->setCur += 1;
|
|
||||||
} else {
|
|
||||||
state->setCur = hundred;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_LONG_PRESS:
|
|
||||||
if (state->mode != metRun && state->mode != setMenu) {
|
|
||||||
movement_request_tick_frequency(2);
|
|
||||||
state->mode = setMenu;
|
|
||||||
_metronome_face_update_lcd(state);
|
|
||||||
} else if (state->mode == setMenu) {
|
|
||||||
state->mode = metWait;
|
|
||||||
_metronome_face_update_lcd(state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_MODE_BUTTON_UP:
|
|
||||||
movement_move_to_next_face();
|
|
||||||
break;
|
|
||||||
case EVENT_TIMEOUT:
|
|
||||||
if (state->mode != metRun) {
|
|
||||||
movement_move_to_face(0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_LOW_ENERGY_UPDATE:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return movement_default_loop_handler(event, settings);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void metronome_face_resign(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
(void) context;
|
|
||||||
}
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Austin Teets
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef METRONOME_FACE_H_
|
|
||||||
#define METRONOME_FACE_H_
|
|
||||||
|
|
||||||
#include "movement.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A Metronome watch complication
|
|
||||||
* Allows the user to set the BPM, counts per measure, beep sound on/off
|
|
||||||
* Screen flashes on on the beat and off on the half beat (1/8th note)
|
|
||||||
* Beep will sound high for downbeat and low for subsequent beats in measure
|
|
||||||
* USE:
|
|
||||||
* Press Alarm to start/stop metronome_face
|
|
||||||
* Hold Alarm to enter settings menu
|
|
||||||
* Short Light press will move through options
|
|
||||||
* Short Alarm press will increment/toggle options
|
|
||||||
* Long alarm press will exit options
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
metWait,
|
|
||||||
metRun,
|
|
||||||
setMenu
|
|
||||||
} metronome_mode_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
hundred,
|
|
||||||
ten,
|
|
||||||
one,
|
|
||||||
count,
|
|
||||||
alarm
|
|
||||||
} setting_cursor_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
// Anything you need to keep track of, put it here!
|
|
||||||
uint8_t bpm;
|
|
||||||
double correction;
|
|
||||||
double curCorrection;
|
|
||||||
int count;
|
|
||||||
int tick;
|
|
||||||
int curTick;
|
|
||||||
int curBeat;
|
|
||||||
int halfBeat;
|
|
||||||
metronome_mode_t mode : 3;
|
|
||||||
setting_cursor_t setCur : 4;
|
|
||||||
bool soundOn;
|
|
||||||
} metronome_state_t;
|
|
||||||
|
|
||||||
void metronome_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
|
||||||
void metronome_face_activate(movement_settings_t *settings, void *context);
|
|
||||||
bool metronome_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
|
||||||
void metronome_face_resign(movement_settings_t *settings, void *context);
|
|
||||||
|
|
||||||
#define metronome_face ((const watch_face_t){ \
|
|
||||||
metronome_face_setup, \
|
|
||||||
metronome_face_activate, \
|
|
||||||
metronome_face_loop, \
|
|
||||||
metronome_face_resign, \
|
|
||||||
NULL, \
|
|
||||||
})
|
|
||||||
|
|
||||||
#endif // METRONOME_FACE_H_
|
|
||||||
|
|
@ -1,384 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2025 hueso
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include "moonrise_face.h"
|
|
||||||
#include "sunrise_sunset_face.h"
|
|
||||||
#include "watch.h"
|
|
||||||
#include "watch_utility.h"
|
|
||||||
#include "moonrise.h"
|
|
||||||
|
|
||||||
#if __EMSCRIPTEN__
|
|
||||||
#include <emscripten.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const uint8_t _location_count = sizeof(longLatPresets) / sizeof(long_lat_presets_t);
|
|
||||||
|
|
||||||
static void _moonrise_face_update(movement_settings_t *settings, moonrise_state_t *state) {
|
|
||||||
char buf[11];
|
|
||||||
movement_location_t movement_location;
|
|
||||||
|
|
||||||
if (state->longLatToUse == 0 || _location_count <= 1)
|
|
||||||
movement_location = (movement_location_t) watch_get_backup_data(1);
|
|
||||||
else{
|
|
||||||
movement_location.bit.latitude = longLatPresets[state->longLatToUse].latitude;
|
|
||||||
movement_location.bit.longitude = longLatPresets[state->longLatToUse].longitude;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (movement_location.reg == 0) {
|
|
||||||
watch_clear_colon();
|
|
||||||
watch_display_string("Mz no Loc", 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
watch_date_time date_time = watch_rtc_get_date_time(); // the current local date / time
|
|
||||||
watch_date_time scratch_time; // scratchpad, contains different values at different times
|
|
||||||
scratch_time.reg = date_time.reg;
|
|
||||||
|
|
||||||
double lat = (double)movement_location.bit.latitude / 100.0;
|
|
||||||
double lon = (double)movement_location.bit.longitude / 100.0;
|
|
||||||
|
|
||||||
uint32_t t = watch_utility_date_time_to_unix_time(date_time, movement_timezone_offsets[settings->bit.time_zone] * 60);
|
|
||||||
MoonRise mr = MoonRise_calculate(lat, lon, t);
|
|
||||||
|
|
||||||
if(mr.isVisible)
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_LAP);
|
|
||||||
else
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_LAP);
|
|
||||||
|
|
||||||
if ( (state->rise_index == 0 && !mr.hasRise) ||
|
|
||||||
(state->rise_index == 1 && !mr.hasSet) ) {
|
|
||||||
watch_clear_colon();
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_PM);
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_24H);
|
|
||||||
snprintf(buf, sizeof(buf), "%s%2d none ", state->rise_index ? "M_" : "M~", scratch_time.unit.day);
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
watch_set_colon();
|
|
||||||
if (settings->bit.clock_mode_24h && !settings->bit.clock_24h_leading_zero)
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_24H);
|
|
||||||
|
|
||||||
if(state->rise_index == 0)
|
|
||||||
scratch_time = watch_utility_date_time_from_unix_time(mr.riseTime, movement_timezone_offsets[settings->bit.time_zone] * 60);
|
|
||||||
else
|
|
||||||
scratch_time = watch_utility_date_time_from_unix_time(mr.setTime, movement_timezone_offsets[settings->bit.time_zone] * 60);
|
|
||||||
|
|
||||||
state->rise_set_expires.reg = scratch_time.reg;
|
|
||||||
|
|
||||||
bool set_leading_zero = false;
|
|
||||||
if (!settings->bit.clock_mode_24h)
|
|
||||||
if (watch_utility_convert_to_12_hour(&scratch_time))
|
|
||||||
watch_set_indicator(WATCH_INDICATOR_PM);
|
|
||||||
else
|
|
||||||
watch_clear_indicator(WATCH_INDICATOR_PM);
|
|
||||||
else if (settings->bit.clock_24h_leading_zero && scratch_time.unit.hour < 10) {
|
|
||||||
set_leading_zero = true;
|
|
||||||
}
|
|
||||||
snprintf(buf, sizeof(buf), "%s%2d%2d%02d%2s", state->rise_index ? "M_" : "M~", scratch_time.unit.day, scratch_time.unit.hour, scratch_time.unit.minute,longLatPresets[state->longLatToUse].name);
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
|
|
||||||
if (set_leading_zero)
|
|
||||||
watch_display_string("0", 4);
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int16_t _moonrise_face_latlon_from_struct(moonrise_lat_lon_settings_t val) {
|
|
||||||
int16_t retval = (val.sign ? -1 : 1) *
|
|
||||||
(
|
|
||||||
val.hundreds * 10000 +
|
|
||||||
val.tens * 1000 +
|
|
||||||
val.ones * 100 +
|
|
||||||
val.tenths * 10 +
|
|
||||||
val.hundredths
|
|
||||||
);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static moonrise_lat_lon_settings_t _moonrise_face_struct_from_latlon(int16_t val) {
|
|
||||||
moonrise_lat_lon_settings_t retval;
|
|
||||||
|
|
||||||
retval.sign = val < 0;
|
|
||||||
val = abs(val);
|
|
||||||
retval.hundredths = val % 10;
|
|
||||||
val /= 10;
|
|
||||||
retval.tenths = val % 10;
|
|
||||||
val /= 10;
|
|
||||||
retval.ones = val % 10;
|
|
||||||
val /= 10;
|
|
||||||
retval.tens = val % 10;
|
|
||||||
val /= 10;
|
|
||||||
retval.hundreds = val % 10;
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _moonrise_face_update_location_register(moonrise_state_t *state) {
|
|
||||||
if (state->location_changed) {
|
|
||||||
movement_location_t movement_location;
|
|
||||||
int16_t lat = _moonrise_face_latlon_from_struct(state->working_latitude);
|
|
||||||
int16_t lon = _moonrise_face_latlon_from_struct(state->working_longitude);
|
|
||||||
movement_location.bit.latitude = lat;
|
|
||||||
movement_location.bit.longitude = lon;
|
|
||||||
watch_store_backup_data(movement_location.reg, 1);
|
|
||||||
state->location_changed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _moonrise_face_update_settings_display(movement_event_t event, moonrise_state_t *state) {
|
|
||||||
char buf[12];
|
|
||||||
|
|
||||||
switch (state->page) {
|
|
||||||
case 0:
|
|
||||||
return;
|
|
||||||
case 1:
|
|
||||||
snprintf(buf, sizeof(buf), "LA %c %04d", state->working_latitude.sign ? '-' : '+', abs(_moonrise_face_latlon_from_struct(state->working_latitude)));
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
snprintf(buf, sizeof(buf), "LO %c%05d", state->working_longitude.sign ? '-' : '+', abs(_moonrise_face_latlon_from_struct(state->working_longitude)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (event.subsecond % 2) {
|
|
||||||
buf[state->active_digit + 4] = ' ';
|
|
||||||
}
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _moonrise_face_advance_digit(moonrise_state_t *state) {
|
|
||||||
state->location_changed = true;
|
|
||||||
switch (state->page) {
|
|
||||||
case 1: // latitude
|
|
||||||
switch (state->active_digit) {
|
|
||||||
case 0:
|
|
||||||
state->working_latitude.sign++;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
// we skip this digit
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
state->working_latitude.tens = (state->working_latitude.tens + 1) % 10;
|
|
||||||
if (abs(_moonrise_face_latlon_from_struct(state->working_latitude)) > 9000) {
|
|
||||||
// prevent latitude from going over ±90.
|
|
||||||
// TODO: perform these checks when advancing the digit?
|
|
||||||
state->working_latitude.ones = 0;
|
|
||||||
state->working_latitude.tenths = 0;
|
|
||||||
state->working_latitude.hundredths = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
state->working_latitude.ones = (state->working_latitude.ones + 1) % 10;
|
|
||||||
if (abs(_moonrise_face_latlon_from_struct(state->working_latitude)) > 9000) state->working_latitude.ones = 0;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
state->working_latitude.tenths = (state->working_latitude.tenths + 1) % 10;
|
|
||||||
if (abs(_moonrise_face_latlon_from_struct(state->working_latitude)) > 9000) state->working_latitude.tenths = 0;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
state->working_latitude.hundredths = (state->working_latitude.hundredths + 1) % 10;
|
|
||||||
if (abs(_moonrise_face_latlon_from_struct(state->working_latitude)) > 9000) state->working_latitude.hundredths = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2: // longitude
|
|
||||||
switch (state->active_digit) {
|
|
||||||
case 0:
|
|
||||||
state->working_longitude.sign++;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
state->working_longitude.hundreds = (state->working_longitude.hundreds + 1) % 10;
|
|
||||||
if (abs(_moonrise_face_latlon_from_struct(state->working_longitude)) > 18000) {
|
|
||||||
// prevent longitude from going over ±180
|
|
||||||
state->working_longitude.tens = 8;
|
|
||||||
state->working_longitude.ones = 0;
|
|
||||||
state->working_longitude.tenths = 0;
|
|
||||||
state->working_longitude.hundredths = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
state->working_longitude.tens = (state->working_longitude.tens + 1) % 10;
|
|
||||||
if (abs(_moonrise_face_latlon_from_struct(state->working_longitude)) > 18000) state->working_longitude.tens = 0;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
state->working_longitude.ones = (state->working_longitude.ones + 1) % 10;
|
|
||||||
if (abs(_moonrise_face_latlon_from_struct(state->working_longitude)) > 18000) state->working_longitude.ones = 0;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
state->working_longitude.tenths = (state->working_longitude.tenths + 1) % 10;
|
|
||||||
if (abs(_moonrise_face_latlon_from_struct(state->working_longitude)) > 18000) state->working_longitude.tenths = 0;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
state->working_longitude.hundredths = (state->working_longitude.hundredths + 1) % 10;
|
|
||||||
if (abs(_moonrise_face_latlon_from_struct(state->working_longitude)) > 18000) state->working_longitude.hundredths = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void moonrise_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr) {
|
|
||||||
(void) settings;
|
|
||||||
(void) watch_face_index;
|
|
||||||
if (*context_ptr == NULL) {
|
|
||||||
*context_ptr = malloc(sizeof(moonrise_state_t));
|
|
||||||
memset(*context_ptr, 0, sizeof(moonrise_state_t));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void moonrise_face_activate(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
if (watch_tick_animation_is_running()) watch_stop_tick_animation();
|
|
||||||
|
|
||||||
#if __EMSCRIPTEN__
|
|
||||||
int16_t browser_lat = EM_ASM_INT({
|
|
||||||
return lat;
|
|
||||||
});
|
|
||||||
int16_t browser_lon = EM_ASM_INT({
|
|
||||||
return lon;
|
|
||||||
});
|
|
||||||
if ((watch_get_backup_data(1) == 0) && (browser_lat || browser_lon)) {
|
|
||||||
movement_location_t browser_loc;
|
|
||||||
browser_loc.bit.latitude = browser_lat;
|
|
||||||
browser_loc.bit.longitude = browser_lon;
|
|
||||||
watch_store_backup_data(browser_loc.reg, 1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
moonrise_state_t *state = (moonrise_state_t *)context;
|
|
||||||
movement_location_t movement_location = (movement_location_t) watch_get_backup_data(1);
|
|
||||||
state->working_latitude = _moonrise_face_struct_from_latlon(movement_location.bit.latitude);
|
|
||||||
state->working_longitude = _moonrise_face_struct_from_latlon(movement_location.bit.longitude);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool moonrise_face_loop(movement_event_t event, movement_settings_t *settings, void *context) {
|
|
||||||
moonrise_state_t *state = (moonrise_state_t *)context;
|
|
||||||
|
|
||||||
switch (event.event_type) {
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
_moonrise_face_update(settings, state);
|
|
||||||
break;
|
|
||||||
case EVENT_LOW_ENERGY_UPDATE:
|
|
||||||
case EVENT_TICK:
|
|
||||||
if (state->page == 0) {
|
|
||||||
// if entering low energy mode, start tick animation
|
|
||||||
if (event.event_type == EVENT_LOW_ENERGY_UPDATE && !watch_tick_animation_is_running()) watch_start_tick_animation(1000);
|
|
||||||
// check if we need to update the display
|
|
||||||
watch_date_time date_time = watch_rtc_get_date_time();
|
|
||||||
if (date_time.reg >= state->rise_set_expires.reg) {
|
|
||||||
// and on the off chance that this happened before EVENT_TIMEOUT snapped us back to rise/set 0, go back now
|
|
||||||
state->rise_index = 0;
|
|
||||||
_moonrise_face_update(settings, state);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_moonrise_face_update_settings_display(event, state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
if (state->page) {
|
|
||||||
state->active_digit++;
|
|
||||||
if (state->page == 1 && state->active_digit == 1) state->active_digit++; // max latitude is +- 90, no hundreds place
|
|
||||||
if (state->active_digit > 5) {
|
|
||||||
state->active_digit = 0;
|
|
||||||
state->page = (state->page + 1) % 3;
|
|
||||||
_moonrise_face_update_location_register(state);
|
|
||||||
}
|
|
||||||
_moonrise_face_update_settings_display(event, context);
|
|
||||||
} else if (_location_count <= 1) {
|
|
||||||
movement_illuminate_led();
|
|
||||||
}
|
|
||||||
if (state->page == 0) {
|
|
||||||
movement_request_tick_frequency(1);
|
|
||||||
_moonrise_face_update(settings, state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_LONG_PRESS:
|
|
||||||
if (_location_count <= 1) break;
|
|
||||||
else if (!state->page) movement_illuminate_led();
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_UP:
|
|
||||||
if (state->page == 0 && _location_count > 1) {
|
|
||||||
state->longLatToUse = (state->longLatToUse + 1) % _location_count;
|
|
||||||
_moonrise_face_update(settings, state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_BUTTON_UP:
|
|
||||||
if (state->page) {
|
|
||||||
_moonrise_face_advance_digit(state);
|
|
||||||
_moonrise_face_update_settings_display(event, context);
|
|
||||||
} else {
|
|
||||||
state->rise_index = (state->rise_index + 1) % 2;
|
|
||||||
_moonrise_face_update(settings, state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_LONG_PRESS:
|
|
||||||
if (state->page == 0) {
|
|
||||||
if (state->longLatToUse != 0) {
|
|
||||||
state->longLatToUse = 0;
|
|
||||||
_moonrise_face_update(settings, state);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
state->page++;
|
|
||||||
state->active_digit = 0;
|
|
||||||
watch_clear_display();
|
|
||||||
movement_request_tick_frequency(4);
|
|
||||||
_moonrise_face_update_settings_display(event, context);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
state->active_digit = 0;
|
|
||||||
state->page = 0;
|
|
||||||
_moonrise_face_update_location_register(state);
|
|
||||||
_moonrise_face_update(settings, state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_TIMEOUT:
|
|
||||||
if (watch_get_backup_data(1) == 0) {
|
|
||||||
// if no location set, return home
|
|
||||||
movement_move_to_face(0);
|
|
||||||
} else if (state->page || state->rise_index) {
|
|
||||||
// otherwise on timeout, exit settings mode and return to the next sunrise or sunset
|
|
||||||
state->page = 0;
|
|
||||||
state->rise_index = 0;
|
|
||||||
movement_request_tick_frequency(1);
|
|
||||||
_moonrise_face_update(settings, state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return movement_default_loop_handler(event, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void moonrise_face_resign(movement_settings_t *settings, void *context) {
|
|
||||||
(void) settings;
|
|
||||||
moonrise_state_t *state = (moonrise_state_t *)context;
|
|
||||||
state->page = 0;
|
|
||||||
state->active_digit = 0;
|
|
||||||
state->rise_index = 0;
|
|
||||||
_moonrise_face_update_location_register(state);
|
|
||||||
}
|
|
@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2022 Joey Castillo
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MOONRISE_FACE_H_
|
|
||||||
#define MOONRISE_FACE_H_
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SUNRISE & SUNSET FACE
|
|
||||||
*
|
|
||||||
* The Sunrise/Sunset face is designed to display the next sunrise or sunset
|
|
||||||
* for a given location. It also functions as an interface for setting the
|
|
||||||
* location register, which other watch faces can use for various purposes.
|
|
||||||
*
|
|
||||||
* Refer to the wiki for usage instructions:
|
|
||||||
* https://www.sensorwatch.net/docs/watchfaces/complication/#sunrisesunset
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "movement.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t sign: 1; // 0-1
|
|
||||||
uint8_t hundreds: 1; // 0-1, ignored for latitude
|
|
||||||
uint8_t tens: 4; // 0-9 (must wrap at 10)
|
|
||||||
uint8_t ones: 4; // 0-9 (must wrap at 10)
|
|
||||||
uint8_t tenths: 4; // 0-9 (must wrap at 10)
|
|
||||||
uint8_t hundredths: 4; // 0-9 (must wrap at 10)
|
|
||||||
} moonrise_lat_lon_settings_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t page;
|
|
||||||
uint8_t rise_index;
|
|
||||||
uint8_t active_digit;
|
|
||||||
bool location_changed;
|
|
||||||
watch_date_time rise_set_expires;
|
|
||||||
moonrise_lat_lon_settings_t working_latitude;
|
|
||||||
moonrise_lat_lon_settings_t working_longitude;
|
|
||||||
uint8_t longLatToUse;
|
|
||||||
} moonrise_state_t;
|
|
||||||
|
|
||||||
void moonrise_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
|
||||||
void moonrise_face_activate(movement_settings_t *settings, void *context);
|
|
||||||
bool moonrise_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
|
||||||
void moonrise_face_resign(movement_settings_t *settings, void *context);
|
|
||||||
|
|
||||||
#define moonrise_face ((const watch_face_t){ \
|
|
||||||
moonrise_face_setup, \
|
|
||||||
moonrise_face_activate, \
|
|
||||||
moonrise_face_loop, \
|
|
||||||
moonrise_face_resign, \
|
|
||||||
NULL, \
|
|
||||||
})
|
|
||||||
|
|
||||||
/*
|
|
||||||
typedef struct {
|
|
||||||
char name[2];
|
|
||||||
int16_t latitude;
|
|
||||||
int16_t longitude;
|
|
||||||
} long_lat_presets_t;
|
|
||||||
|
|
||||||
|
|
||||||
static const long_lat_presets_t longLatPresets[] =
|
|
||||||
{
|
|
||||||
{ .name = " "}, // Default, the long and lat get replaced by what's set in the watch
|
|
||||||
// { .name = "Ny", .latitude = 4072, .longitude = -7401 }, // New York City, NY
|
|
||||||
// { .name = "LA", .latitude = 3405, .longitude = -11824 }, // Los Angeles, CA
|
|
||||||
// { .name = "dE", .latitude = 4221, .longitude = -8305 }, // Detroit, MI
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
#endif // MOONRISE_FACE_H_
|
|
@ -1,503 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 PrimmR
|
|
||||||
* Copyright (c) 2024 David Volovskiy
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "periodic_face.h"
|
|
||||||
|
|
||||||
#define FREQ_FAST 8
|
|
||||||
#define FREQ 2
|
|
||||||
|
|
||||||
static bool _quick_ticks_running;
|
|
||||||
static uint8_t _ts_ticks = 0;
|
|
||||||
static int16_t _text_pos;
|
|
||||||
static const char* _text_looping;
|
|
||||||
static const char title_text[] = "Periodic Table";
|
|
||||||
|
|
||||||
void periodic_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void **context_ptr)
|
|
||||||
{
|
|
||||||
(void)settings;
|
|
||||||
(void)watch_face_index;
|
|
||||||
if (*context_ptr == NULL)
|
|
||||||
{
|
|
||||||
*context_ptr = malloc(sizeof(periodic_state_t));
|
|
||||||
memset(*context_ptr, 0, sizeof(periodic_state_t));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void periodic_face_activate(movement_settings_t *settings, void *context)
|
|
||||||
{
|
|
||||||
(void)settings;
|
|
||||||
periodic_state_t *state = (periodic_state_t *)context;
|
|
||||||
|
|
||||||
state->atomic_num = 0;
|
|
||||||
state->mode = 0;
|
|
||||||
state->selection_index = 0;
|
|
||||||
_quick_ticks_running = false;
|
|
||||||
movement_request_tick_frequency(FREQ);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
char symbol[3];
|
|
||||||
char name[14]; // Longest is Rutherfordium
|
|
||||||
int16_t year_discovered; // Negative is BC
|
|
||||||
uint16_t atomic_mass; // In units of 0.01 AMU
|
|
||||||
uint16_t electronegativity; // In units of 0.01
|
|
||||||
char group[3];
|
|
||||||
} element;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
SCREEN_TITLE = 0,
|
|
||||||
SCREEN_ELEMENT,
|
|
||||||
SCREEN_ATOMIC_MASS,
|
|
||||||
SCREEN_DISCOVER_YEAR,
|
|
||||||
SCREEN_ELECTRONEGATIVITY,
|
|
||||||
SCREEN_FULL_NAME,
|
|
||||||
SCREENS_COUNT
|
|
||||||
} PeriodicScreens;
|
|
||||||
|
|
||||||
const char screen_name[SCREENS_COUNT][3] = {
|
|
||||||
[SCREEN_ATOMIC_MASS] = "am",
|
|
||||||
[SCREEN_DISCOVER_YEAR] = " y",
|
|
||||||
[SCREEN_ELECTRONEGATIVITY] = "EL",
|
|
||||||
[SCREEN_FULL_NAME] = " n",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Comments on the table denote symbols that cannot be displayed
|
|
||||||
#define MAX_ELEMENT 118
|
|
||||||
const element table[MAX_ELEMENT] = {
|
|
||||||
{ .symbol = "H", .name = "Hydrogen", .year_discovered = 1671, .atomic_mass = 101, .electronegativity = 220, .group = " " },
|
|
||||||
{ .symbol = "HE", .name = "Helium", .year_discovered = 1868, .atomic_mass = 400, .electronegativity = 0, .group = "0" },
|
|
||||||
{ .symbol = "LI", .name = "Lithium", .year_discovered = 1817, .atomic_mass = 694, .electronegativity = 98, .group = "1" },
|
|
||||||
{ .symbol = "BE", .name = "Beryllium", .year_discovered = 1798, .atomic_mass = 901, .electronegativity = 157, .group = "2" },
|
|
||||||
{ .symbol = "B", .name = "Boron", .year_discovered = 1787, .atomic_mass = 1081, .electronegativity = 204, .group = "3" },
|
|
||||||
{ .symbol = "C", .name = "Carbon", .year_discovered = -26000, .atomic_mass = 1201, .electronegativity = 255, .group = "4" },
|
|
||||||
{ .symbol = "N", .name = "Nitrogen", .year_discovered = 1772, .atomic_mass = 1401, .electronegativity = 304, .group = "5" },
|
|
||||||
{ .symbol = "O", .name = "Oxygen", .year_discovered = 1771, .atomic_mass = 1600, .electronegativity = 344, .group = "6" },
|
|
||||||
{ .symbol = "F", .name = "Fluorine", .year_discovered = 1771, .atomic_mass = 1900, .electronegativity = 398, .group = "7" },
|
|
||||||
{ .symbol = "NE", .name = "Neon", .year_discovered = 1898, .atomic_mass = 2018, .electronegativity = 0, .group = "0" },
|
|
||||||
{ .symbol = "NA", .name = "Sodium", .year_discovered = 1702, .atomic_mass = 2299, .electronegativity = 93, .group = "1" },
|
|
||||||
{ .symbol = "MG", .name = "Magnesium", .year_discovered = 1755, .atomic_mass = 2431, .electronegativity = 131, .group = "2" },
|
|
||||||
{ .symbol = "AL", .name = "Aluminium", .year_discovered = 1746, .atomic_mass = 2698, .electronegativity = 161, .group = "3" },
|
|
||||||
{ .symbol = "SI", .name = "Silicon", .year_discovered = 1739, .atomic_mass = 2809, .electronegativity = 190, .group = "4" },
|
|
||||||
{ .symbol = "P", .name = "Phosphorus", .year_discovered = 1669, .atomic_mass = 3097, .electronegativity = 219, .group = "5" },
|
|
||||||
{ .symbol = "S", .name = "Sulfur", .year_discovered = -2000, .atomic_mass = 3206, .electronegativity = 258, .group = "6" },
|
|
||||||
{ .symbol = "CL", .name = "Chlorine", .year_discovered = 1774, .atomic_mass = 3545., .electronegativity = 316, .group = "7" },
|
|
||||||
{ .symbol = "AR", .name = "Argon", .year_discovered = 1894, .atomic_mass = 3995., .electronegativity = 0, .group = "0" },
|
|
||||||
{ .symbol = "K", .name = "Potassium", .year_discovered = 1702, .atomic_mass = 3910, .electronegativity = 82, .group = "1" },
|
|
||||||
{ .symbol = "CA", .name = "Calcium", .year_discovered = 1739, .atomic_mass = 4008, .electronegativity = 100, .group = "2" },
|
|
||||||
{ .symbol = "SC", .name = "Scandium", .year_discovered = 1879, .atomic_mass = 4496, .electronegativity = 136, .group = " T" },
|
|
||||||
{ .symbol = "TI", .name = "Titanium", .year_discovered = 1791, .atomic_mass = 4787, .electronegativity = 154, .group = " T" },
|
|
||||||
{ .symbol = "W", .name = "Vanadium", .year_discovered = 1801, .atomic_mass = 5094, .electronegativity = 163, .group = " T" },
|
|
||||||
{ .symbol = "CR", .name = "Chromium", .year_discovered = 1797, .atomic_mass = 5200, .electronegativity = 166, .group = " T" },
|
|
||||||
{ .symbol = "MN", .name = "Manganese", .year_discovered = 1774, .atomic_mass = 5494, .electronegativity = 155, .group = " T" },
|
|
||||||
{ .symbol = "FE", .name = "Iron", .year_discovered = -5000, .atomic_mass = 5585, .electronegativity = 183, .group = " T" },
|
|
||||||
{ .symbol = "CO", .name = "Cobalt", .year_discovered = 1735, .atomic_mass = 5893, .electronegativity = 188, .group = " T" },
|
|
||||||
{ .symbol = "NI", .name = "Nickel", .year_discovered = 1751, .atomic_mass = 5869, .electronegativity = 191, .group = " T" },
|
|
||||||
{ .symbol = "CU", .name = "Copper", .year_discovered = -9000, .atomic_mass = 6355, .electronegativity = 190, .group = " T" },
|
|
||||||
{ .symbol = "ZN", .name = "Zinc", .year_discovered = -1000, .atomic_mass = 6538, .electronegativity = 165, .group = " T" },
|
|
||||||
{ .symbol = "GA", .name = "Gallium", .year_discovered = 1875, .atomic_mass = 6972, .electronegativity = 181, .group = "3" },
|
|
||||||
{ .symbol = "GE", .name = "Germanium", .year_discovered = 1886, .atomic_mass = 7263, .electronegativity = 201, .group = "4" },
|
|
||||||
{ .symbol = "AS", .name = "Arsenic", .year_discovered = 300, .atomic_mass = 7492, .electronegativity = 218, .group = "5" },
|
|
||||||
{ .symbol = "SE", .name = "Selenium", .year_discovered = 1817, .atomic_mass = 7897, .electronegativity = 255, .group = "6" },
|
|
||||||
{ .symbol = "BR", .name = "Bromine", .year_discovered = 1825, .atomic_mass = 7990., .electronegativity = 296, .group = "7" },
|
|
||||||
{ .symbol = "KR", .name = "Krypton", .year_discovered = 1898, .atomic_mass = 8380, .electronegativity = 300, .group = "0" },
|
|
||||||
{ .symbol = "RB", .name = "Rubidium", .year_discovered = 1861, .atomic_mass = 8547, .electronegativity = 82, .group = "1" },
|
|
||||||
{ .symbol = "SR", .name = "Strontium", .year_discovered = 1787, .atomic_mass = 8762, .electronegativity = 95, .group = "2" },
|
|
||||||
{ .symbol = "Y", .name = "Yttrium", .year_discovered = 1794, .atomic_mass = 8891, .electronegativity = 122, .group = " T" },
|
|
||||||
{ .symbol = "ZR", .name = "Zirconium", .year_discovered = 1789, .atomic_mass = 9122, .electronegativity = 133, .group = " T" },
|
|
||||||
{ .symbol = "NB", .name = "Niobium", .year_discovered = 1801, .atomic_mass = 9291, .electronegativity = 160, .group = " T" },
|
|
||||||
{ .symbol = "MO", .name = "Molybdenum", .year_discovered = 1778, .atomic_mass = 9595, .electronegativity = 216, .group = " T" },
|
|
||||||
{ .symbol = "TC", .name = "Technetium", .year_discovered = 1937, .atomic_mass = 9700, .electronegativity = 190, .group = " T" },
|
|
||||||
{ .symbol = "RU", .name = "Ruthenium", .year_discovered = 1844, .atomic_mass = 10107, .electronegativity = 220, .group = " T" },
|
|
||||||
{ .symbol = "RH", .name = "Rhodium", .year_discovered = 1804, .atomic_mass = 10291, .electronegativity = 228, .group = " T" },
|
|
||||||
{ .symbol = "PD", .name = "Palladium", .year_discovered = 1802, .atomic_mass = 10642, .electronegativity = 220, .group = " T" },
|
|
||||||
{ .symbol = "AG", .name = "Silver", .year_discovered = -5000, .atomic_mass = 10787, .electronegativity = 193, .group = " T" },
|
|
||||||
{ .symbol = "CD", .name = "Cadmium", .year_discovered = 1817, .atomic_mass = 11241, .electronegativity = 169, .group = " T" },
|
|
||||||
{ .symbol = "IN", .name = "Indium", .year_discovered = 1863, .atomic_mass = 11482, .electronegativity = 178, .group = "3" },
|
|
||||||
{ .symbol = "SN", .name = "Tin", .year_discovered = -3500, .atomic_mass = 11871, .electronegativity = 196, .group = "4" },
|
|
||||||
{ .symbol = "SB", .name = "Antimony", .year_discovered = -3000, .atomic_mass = 12176, .electronegativity = 205, .group = "5" },
|
|
||||||
{ .symbol = "TE", .name = "Tellurium", .year_discovered = 1782, .atomic_mass = 12760, .electronegativity = 210, .group = "6" },
|
|
||||||
{ .symbol = "I", .name = "Iodine", .year_discovered = 1811, .atomic_mass = 12690, .electronegativity = 266, .group = "7" },
|
|
||||||
{ .symbol = "XE", .name = "Xenon", .year_discovered = 1898, .atomic_mass = 13129, .electronegativity = 260, .group = "0" },
|
|
||||||
{ .symbol = "CS", .name = "Caesium", .year_discovered = 1860, .atomic_mass = 13291, .electronegativity = 79, .group = "1" },
|
|
||||||
{ .symbol = "BA", .name = "Barium", .year_discovered = 1772, .atomic_mass = 13733., .electronegativity = 89, .group = "2" },
|
|
||||||
{ .symbol = "LA", .name = "Lanthanum", .year_discovered = 1838, .atomic_mass = 13891, .electronegativity = 110, .group = "1a" },
|
|
||||||
{ .symbol = "CE", .name = "Cerium", .year_discovered = 1803, .atomic_mass = 14012, .electronegativity = 112, .group = "1a" },
|
|
||||||
{ .symbol = "PR", .name = "Praseodymium", .year_discovered = 1885, .atomic_mass = 14091, .electronegativity = 113, .group = "1a" },
|
|
||||||
{ .symbol = "ND", .name = "Neodymium", .year_discovered = 1841, .atomic_mass = 14424, .electronegativity = 114, .group = "1a" },
|
|
||||||
{ .symbol = "PM", .name = "Promethium", .year_discovered = 1945, .atomic_mass = 14500, .electronegativity = 113, .group = "1a" },
|
|
||||||
{ .symbol = "SM", .name = "Samarium", .year_discovered = 1879, .atomic_mass = 15036., .electronegativity = 117, .group = "1a" },
|
|
||||||
{ .symbol = "EU", .name = "Europium", .year_discovered = 1896, .atomic_mass = 15196, .electronegativity = 120, .group = "1a" },
|
|
||||||
{ .symbol = "GD", .name = "Gadolinium", .year_discovered = 1880, .atomic_mass = 15725, .electronegativity = 120, .group = "1a" },
|
|
||||||
{ .symbol = "TB", .name = "Terbium", .year_discovered = 1843, .atomic_mass = 15893, .electronegativity = 120, .group = "1a" },
|
|
||||||
{ .symbol = "DY", .name = "Dysprosium", .year_discovered = 1886, .atomic_mass = 16250, .electronegativity = 122, .group = "1a" },
|
|
||||||
{ .symbol = "HO", .name = "Holmium", .year_discovered = 1878, .atomic_mass = 16493, .electronegativity = 123, .group = "1a" },
|
|
||||||
{ .symbol = "ER", .name = "Erbium", .year_discovered = 1843, .atomic_mass = 16726, .electronegativity = 124, .group = "1a" },
|
|
||||||
{ .symbol = "TM", .name = "Thulium", .year_discovered = 1879, .atomic_mass = 16893, .electronegativity = 125, .group = "1a" },
|
|
||||||
{ .symbol = "YB", .name = "Ytterbium", .year_discovered = 1878, .atomic_mass = 17305, .electronegativity = 110, .group = "1a" },
|
|
||||||
{ .symbol = "LU", .name = "Lutetium", .year_discovered = 1906, .atomic_mass = 17497, .electronegativity = 127, .group = "1a" },
|
|
||||||
{ .symbol = "HF", .name = "Hafnium", .year_discovered = 1922, .atomic_mass = 17849, .electronegativity = 130, .group = " T" },
|
|
||||||
{ .symbol = "TA", .name = "Tantalum", .year_discovered = 1802, .atomic_mass = 18095, .electronegativity = 150, .group = " T" },
|
|
||||||
{ .symbol = "W", .name = "Tungsten", .year_discovered = 1781, .atomic_mass = 18384, .electronegativity = 236, .group = " T" },
|
|
||||||
{ .symbol = "RE", .name = "Rhenium", .year_discovered = 1908, .atomic_mass = 18621, .electronegativity = 190, .group = " T" },
|
|
||||||
{ .symbol = "OS", .name = "Osmium", .year_discovered = 1803, .atomic_mass = 19023, .electronegativity = 220, .group = " T" },
|
|
||||||
{ .symbol = "IR", .name = "Iridium", .year_discovered = 1803, .atomic_mass = 19222, .electronegativity = 220, .group = " T" },
|
|
||||||
{ .symbol = "PT", .name = "Platinum", .year_discovered = -600, .atomic_mass = 19508, .electronegativity = 228, .group = " T" },
|
|
||||||
{ .symbol = "AU", .name = "Gold", .year_discovered = -6000, .atomic_mass = 19697, .electronegativity = 254, .group = " T" },
|
|
||||||
{ .symbol = "HG", .name = "Mercury", .year_discovered = -1500, .atomic_mass = 20059, .electronegativity = 200, .group = " T" },
|
|
||||||
{ .symbol = "TL", .name = "Thallium", .year_discovered = 1861, .atomic_mass = 20438, .electronegativity = 162, .group = "3" },
|
|
||||||
{ .symbol = "PB", .name = "Lead", .year_discovered = -7000, .atomic_mass = 20720, .electronegativity = 187, .group = "4" },
|
|
||||||
{ .symbol = "BI", .name = "Bismuth", .year_discovered = 1500, .atomic_mass = 20898, .electronegativity = 202, .group = "5" },
|
|
||||||
{ .symbol = "PO", .name = "Polonium", .year_discovered = 1898, .atomic_mass = 20900, .electronegativity = 200, .group = "6" },
|
|
||||||
{ .symbol = "AT", .name = "Astatine", .year_discovered = 1940, .atomic_mass = 21000, .electronegativity = 220, .group = "7" },
|
|
||||||
{ .symbol = "RN", .name = "Radon", .year_discovered = 1899, .atomic_mass = 22200, .electronegativity = 220, .group = "0" },
|
|
||||||
{ .symbol = "FR", .name = "Francium", .year_discovered = 1939, .atomic_mass = 22300, .electronegativity = 79, .group = "1" },
|
|
||||||
{ .symbol = "RA", .name = "Radium", .year_discovered = 1898, .atomic_mass = 22600, .electronegativity = 90, .group = "2" },
|
|
||||||
{ .symbol = "AC", .name = "Actinium", .year_discovered = 1902, .atomic_mass = 22700, .electronegativity = 110, .group = "Ac" },
|
|
||||||
{ .symbol = "TH", .name = "Thorium", .year_discovered = 1829, .atomic_mass = 23204, .electronegativity = 130, .group = "Ac" },
|
|
||||||
{ .symbol = "PA", .name = "Protactinium", .year_discovered = 1913, .atomic_mass = 23104, .electronegativity = 150, .group = "Ac" },
|
|
||||||
{ .symbol = "U", .name = "Uranium", .year_discovered = 1789, .atomic_mass = 23803, .electronegativity = 138, .group = "Ac" },
|
|
||||||
{ .symbol = "NP", .name = "Neptunium", .year_discovered = 1940, .atomic_mass = 23700, .electronegativity = 136, .group = "Ac" },
|
|
||||||
{ .symbol = "PU", .name = "Plutonium", .year_discovered = 1941, .atomic_mass = 24400, .electronegativity = 128, .group = "Ac" },
|
|
||||||
{ .symbol = "AM", .name = "Americium", .year_discovered = 1944, .atomic_mass = 24300, .electronegativity = 113, .group = "Ac" },
|
|
||||||
{ .symbol = "CM", .name = "Curium", .year_discovered = 1944, .atomic_mass = 24700, .electronegativity = 128, .group = "Ac" },
|
|
||||||
{ .symbol = "BK", .name = "Berkelium", .year_discovered = 1949, .atomic_mass = 24700, .electronegativity = 130, .group = "Ac" },
|
|
||||||
{ .symbol = "CF", .name = "Californium", .year_discovered = 1950, .atomic_mass = 25100, .electronegativity = 130, .group = "Ac" },
|
|
||||||
{ .symbol = "ES", .name = "Einsteinium", .year_discovered = 1952, .atomic_mass = 25200, .electronegativity = 130, .group = "Ac" },
|
|
||||||
{ .symbol = "FM", .name = "Fermium", .year_discovered = 1953, .atomic_mass = 25700, .electronegativity = 130, .group = "Ac" },
|
|
||||||
{ .symbol = "MD", .name = "Mendelevium", .year_discovered = 1955, .atomic_mass = 25800, .electronegativity = 130, .group = "Ac" },
|
|
||||||
{ .symbol = "NO", .name = "Nobelium", .year_discovered = 1965, .atomic_mass = 25900, .electronegativity = 130, .group = "Ac" },
|
|
||||||
{ .symbol = "LR", .name = "Lawrencium", .year_discovered = 1961, .atomic_mass = 26600, .electronegativity = 130, .group = "Ac" },
|
|
||||||
{ .symbol = "RF", .name = "Rutherfordium", .year_discovered = 1969, .atomic_mass = 26700, .electronegativity = 0, .group = " T" },
|
|
||||||
{ .symbol = "DB", .name = "Dubnium", .year_discovered = 1970, .atomic_mass = 26800, .electronegativity = 0, .group = " T" },
|
|
||||||
{ .symbol = "SG", .name = "Seaborgium", .year_discovered = 1974, .atomic_mass = 26700, .electronegativity = 0, .group = " T" },
|
|
||||||
{ .symbol = "BH", .name = "Bohrium", .year_discovered = 1981, .atomic_mass = 27000, .electronegativity = 0, .group = " T" },
|
|
||||||
{ .symbol = "HS", .name = "Hassium", .year_discovered = 1984, .atomic_mass = 27100, .electronegativity = 0, .group = " T" },
|
|
||||||
{ .symbol = "MT", .name = "Meitnerium", .year_discovered = 1982, .atomic_mass = 27800, .electronegativity = 0, .group = " T" },
|
|
||||||
{ .symbol = "DS", .name = "Darmstadtium", .year_discovered = 1994, .atomic_mass = 28100, .electronegativity = 0, .group = " T" },
|
|
||||||
{ .symbol = "RG", .name = "Roentgenium", .year_discovered = 1994, .atomic_mass = 28200, .electronegativity = 0, .group = " T" },
|
|
||||||
{ .symbol = "CN", .name = "Copernicium", .year_discovered = 1996, .atomic_mass = 28500, .electronegativity = 0, .group = " T" },
|
|
||||||
{ .symbol = "NH", .name = "Nihonium", .year_discovered = 2004, .atomic_mass = 28600, .electronegativity = 0, .group = "3" },
|
|
||||||
{ .symbol = "FL", .name = "Flerovium", .year_discovered = 1999, .atomic_mass = 28900, .electronegativity = 0, .group = "4" },
|
|
||||||
{ .symbol = "MC", .name = "Moscovium", .year_discovered = 2003, .atomic_mass = 29000, .electronegativity = 0, .group = "5" },
|
|
||||||
{ .symbol = "LW", .name = "Livermorium", .year_discovered = 2000, .atomic_mass = 29300, .electronegativity = 0, .group = "6" },
|
|
||||||
{ .symbol = "TS", .name = "Tennessine", .year_discovered = 2009, .atomic_mass = 29400, .electronegativity = 0, .group = "7" },
|
|
||||||
{ .symbol = "OG", .name = "Oganesson", .year_discovered = 2002, .atomic_mass = 29400, .electronegativity = 0, .group = "0" },
|
|
||||||
};
|
|
||||||
|
|
||||||
static void _make_upper(char *string) {
|
|
||||||
size_t i = 0;
|
|
||||||
while(string[i] != 0) {
|
|
||||||
if (string[i] >= 'a' && string[i] <= 'z')
|
|
||||||
string[i]-=32; // 32 = 'a'-'A'
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _display_element(periodic_state_t *state)
|
|
||||||
{
|
|
||||||
char buf[9];
|
|
||||||
char ele[3];
|
|
||||||
uint8_t atomic_num = state->atomic_num;
|
|
||||||
strcpy(ele, table[atomic_num - 1].symbol);
|
|
||||||
_make_upper(ele);
|
|
||||||
sprintf(buf, "%2s%3d %-2s", table[atomic_num - 1].group, atomic_num, ele);
|
|
||||||
watch_display_string(buf, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _display_atomic_mass(periodic_state_t *state)
|
|
||||||
{
|
|
||||||
char buf[11];
|
|
||||||
uint16_t mass = table[state->atomic_num - 1].atomic_mass;
|
|
||||||
uint16_t integer = mass / 100;
|
|
||||||
uint16_t decimal = mass % 100;
|
|
||||||
if (decimal == 0)
|
|
||||||
sprintf(buf, "%-2s%2s%4d", table[state->atomic_num - 1].symbol, screen_name[state->mode], integer);
|
|
||||||
else
|
|
||||||
sprintf(buf, "%-2s%2s%3d_%.2d", table[state->atomic_num - 1].symbol, screen_name[state->mode], integer, decimal);
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _display_year_discovered(periodic_state_t *state)
|
|
||||||
{
|
|
||||||
char buf[11];
|
|
||||||
char year_buf[7];
|
|
||||||
int16_t year = table[state->atomic_num - 1].year_discovered;
|
|
||||||
if (abs(year) > 9999)
|
|
||||||
sprintf(year_buf, "---- ");
|
|
||||||
else
|
|
||||||
sprintf(year_buf, "%4d ", abs(year));
|
|
||||||
if (year < 0) {
|
|
||||||
year_buf[4] = 'b';
|
|
||||||
year_buf[5] = 'c';
|
|
||||||
}
|
|
||||||
sprintf(buf, "%-2s%-2s%s", table[state->atomic_num - 1].symbol, screen_name[state->mode], year_buf);
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _display_name(periodic_state_t *state)
|
|
||||||
{
|
|
||||||
char buf[11];
|
|
||||||
_text_looping = table[state->atomic_num - 1].name;
|
|
||||||
_text_pos = 0;
|
|
||||||
sprintf(buf, "%-2s%-2s%s", table[state->atomic_num - 1].symbol, screen_name[state->mode], table[state->atomic_num - 1].name);
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _display_electronegativity(periodic_state_t *state)
|
|
||||||
{
|
|
||||||
char buf[11];
|
|
||||||
uint16_t electronegativity = table[state->atomic_num - 1].electronegativity;
|
|
||||||
uint16_t integer = electronegativity / 100;
|
|
||||||
uint16_t decimal = electronegativity % 100;
|
|
||||||
if (decimal == 0)
|
|
||||||
sprintf(buf, "%-2s%2s%4d", table[state->atomic_num - 1].symbol, screen_name[state->mode], integer);
|
|
||||||
else
|
|
||||||
sprintf(buf, "%-2s%2s%3d_%.2d", table[state->atomic_num - 1].symbol, screen_name[state->mode], integer, decimal);
|
|
||||||
watch_display_string(buf, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void start_quick_cyc(void){
|
|
||||||
_quick_ticks_running = true;
|
|
||||||
movement_request_tick_frequency(FREQ_FAST);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void stop_quick_cyc(void){
|
|
||||||
_quick_ticks_running = false;
|
|
||||||
movement_request_tick_frequency(FREQ);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int16_t _loop_text(const char* text, int8_t curr_loc, uint8_t char_len){
|
|
||||||
// if curr_loc, then use that many ticks as a delay before looping
|
|
||||||
char buf[15];
|
|
||||||
uint8_t next_pos;
|
|
||||||
uint8_t text_len = strlen(text);
|
|
||||||
uint8_t pos = 10 - char_len;
|
|
||||||
if (curr_loc == -1) curr_loc = 0; // To avoid double-showing the 0
|
|
||||||
if (char_len >= text_len || curr_loc < 0) {
|
|
||||||
sprintf(buf, "%s", text);
|
|
||||||
watch_display_string(buf, pos);
|
|
||||||
if (curr_loc < 0) return ++curr_loc;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if (curr_loc == (text_len + 1))
|
|
||||||
curr_loc = 0;
|
|
||||||
next_pos = curr_loc + 1;
|
|
||||||
sprintf(buf, "%.6s %.6s", text + curr_loc, text);
|
|
||||||
watch_display_string(buf, pos);
|
|
||||||
return next_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _display_title(periodic_state_t *state){
|
|
||||||
state->atomic_num = 0;
|
|
||||||
watch_clear_colon();
|
|
||||||
watch_clear_all_indicators();
|
|
||||||
_text_looping = title_text;
|
|
||||||
_text_pos = FREQ * -1;
|
|
||||||
_text_pos = _loop_text(_text_looping, _text_pos, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _display_screen(periodic_state_t *state, bool should_sound){
|
|
||||||
watch_clear_display();
|
|
||||||
watch_clear_all_indicators();
|
|
||||||
switch (state->mode)
|
|
||||||
{
|
|
||||||
case SCREEN_TITLE:
|
|
||||||
_display_title(state);
|
|
||||||
break;
|
|
||||||
case SCREEN_ELEMENT:
|
|
||||||
case SCREENS_COUNT:
|
|
||||||
_display_element(state);
|
|
||||||
break;
|
|
||||||
case SCREEN_ATOMIC_MASS:
|
|
||||||
_display_atomic_mass(state);
|
|
||||||
break;
|
|
||||||
case SCREEN_DISCOVER_YEAR:
|
|
||||||
_display_year_discovered(state);
|
|
||||||
break;
|
|
||||||
case SCREEN_ELECTRONEGATIVITY:
|
|
||||||
_display_electronegativity(state);
|
|
||||||
break;
|
|
||||||
case SCREEN_FULL_NAME:
|
|
||||||
_display_name(state);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (should_sound) watch_buzzer_play_note(BUZZER_NOTE_C7, 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _handle_forward(periodic_state_t *state, bool should_sound){
|
|
||||||
state->atomic_num = (state->atomic_num % MAX_ELEMENT) + 1; // Wraps back to 1
|
|
||||||
state->mode = SCREEN_ELEMENT;
|
|
||||||
_display_screen(state, false);
|
|
||||||
if (should_sound) watch_buzzer_play_note(BUZZER_NOTE_C7, 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _handle_backward(periodic_state_t *state, bool should_sound){
|
|
||||||
if (state->atomic_num <= 1) state->atomic_num = MAX_ELEMENT;
|
|
||||||
else state->atomic_num = state->atomic_num - 1;
|
|
||||||
state->mode = SCREEN_ELEMENT;
|
|
||||||
_display_screen(state, false);
|
|
||||||
if (should_sound) watch_buzzer_play_note(BUZZER_NOTE_A6, 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _handle_mode_still_pressed(periodic_state_t *state, bool should_sound) {
|
|
||||||
if (_ts_ticks != 0){
|
|
||||||
if (!watch_get_pin_level(BTN_MODE)) {
|
|
||||||
_ts_ticks = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (--_ts_ticks == 0){
|
|
||||||
switch (state->mode)
|
|
||||||
{
|
|
||||||
case SCREEN_TITLE:
|
|
||||||
movement_move_to_face(0);
|
|
||||||
return;
|
|
||||||
case SCREEN_ELEMENT:
|
|
||||||
state->mode = SCREEN_TITLE;
|
|
||||||
_display_screen(state, should_sound);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
state->mode = SCREEN_ELEMENT;
|
|
||||||
_display_screen(state, should_sound);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ts_ticks = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool periodic_face_loop(movement_event_t event, movement_settings_t *settings, void *context)
|
|
||||||
{
|
|
||||||
periodic_state_t *state = (periodic_state_t *)context;
|
|
||||||
switch (event.event_type)
|
|
||||||
{
|
|
||||||
case EVENT_ACTIVATE:
|
|
||||||
state->mode = SCREEN_TITLE;
|
|
||||||
_display_screen(state, false);
|
|
||||||
break;
|
|
||||||
case EVENT_TICK:
|
|
||||||
if (state->mode == SCREEN_TITLE) _text_pos = _loop_text(_text_looping, _text_pos, 5);
|
|
||||||
else if (state->mode == SCREEN_FULL_NAME) _text_pos = _loop_text(_text_looping, _text_pos, 6);
|
|
||||||
if (_quick_ticks_running) {
|
|
||||||
if (watch_get_pin_level(BTN_LIGHT)) _handle_backward(state, false);
|
|
||||||
else if (watch_get_pin_level(BTN_ALARM)) _handle_forward(state, false);
|
|
||||||
else stop_quick_cyc();
|
|
||||||
}
|
|
||||||
|
|
||||||
_handle_mode_still_pressed(state, settings->bit.button_should_sound);
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_UP:
|
|
||||||
if (state->mode <= SCREEN_ELEMENT) {
|
|
||||||
_handle_backward(state, settings->bit.button_should_sound);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
state->mode = SCREEN_ELEMENT;
|
|
||||||
_display_screen(state, settings->bit.button_should_sound);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_BUTTON_DOWN:
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_BUTTON_UP:
|
|
||||||
if (state->mode <= SCREEN_ELEMENT) {
|
|
||||||
_handle_forward(state, settings->bit.button_should_sound);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
state->mode = SCREEN_ELEMENT;
|
|
||||||
_display_screen(state, settings->bit.button_should_sound);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_ALARM_LONG_PRESS:
|
|
||||||
if (state->mode <= SCREEN_ELEMENT) {
|
|
||||||
start_quick_cyc();
|
|
||||||
_handle_forward(state, settings->bit.button_should_sound);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_LIGHT_LONG_PRESS:
|
|
||||||
if (state->mode <= SCREEN_ELEMENT) {
|
|
||||||
start_quick_cyc();
|
|
||||||
_handle_backward(state, settings->bit.button_should_sound);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
movement_illuminate_led();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_MODE_BUTTON_UP:
|
|
||||||
if (state->mode == SCREEN_TITLE) movement_move_to_next_face();
|
|
||||||
else {
|
|
||||||
state->mode = (state->mode + 1) % SCREENS_COUNT;
|
|
||||||
if (state->mode == SCREEN_TITLE)
|
|
||||||
state->mode = (state->mode + 1) % SCREENS_COUNT;
|
|
||||||
if (state->mode == SCREEN_ELEMENT){
|
|
||||||
_display_screen(state, false);
|
|
||||||
if (settings->bit.button_should_sound) watch_buzzer_play_note(BUZZER_NOTE_A6, 50);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_display_screen(state, settings->bit.button_should_sound);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EVENT_MODE_LONG_PRESS:
|
|
||||||
switch (state->mode)
|
|
||||||
{
|
|
||||||
case SCREEN_TITLE:
|
|
||||||
movement_move_to_face(0);
|
|
||||||
return true;
|
|
||||||
case SCREEN_ELEMENT:
|
|
||||||
state->mode = SCREEN_TITLE;
|
|
||||||
_display_screen(state, settings->bit.button_should_sound);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
state->mode = SCREEN_ELEMENT;
|
|
||||||
_display_screen(state, settings->bit.button_should_sound);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ts_ticks = 2;
|
|
||||||
break;
|
|
||||||
case EVENT_TIMEOUT:
|
|
||||||
// Display title after timeout
|
|
||||||
if (state->mode == SCREEN_TITLE) break;
|
|
||||||
state->mode = SCREEN_TITLE;
|
|
||||||
_display_screen(state, false);
|
|
||||||
break;
|
|
||||||
case EVENT_LOW_ENERGY_UPDATE:
|
|
||||||
// Display static title and tick animation during LE
|
|
||||||
watch_display_string("Pd Table", 0);
|
|
||||||
watch_start_tick_animation(500);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return movement_default_loop_handler(event, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void periodic_face_resign(movement_settings_t *settings, void *context)
|
|
||||||
{
|
|
||||||
(void)settings;
|
|
||||||
(void)context;
|
|
||||||
|
|
||||||
// handle any cleanup before your watch face goes off-screen.
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user