mirror of
https://github.com/firewalkwithm3/Sensor-Watch.git
synced 2024-11-22 19:20:30 +08:00
Periodic Table Face
This commit is contained in:
parent
3487d742f1
commit
7eb725a5f6
|
@ -121,6 +121,7 @@ SRCS += \
|
|||
../watch_faces/complication/couch_to_5k_face.c \
|
||||
../watch_faces/clock/minute_repeater_decimal_face.c \
|
||||
../watch_faces/complication/tuning_tones_face.c \
|
||||
../watch_faces/complication/periodic_face.c \
|
||||
# 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.
|
||||
|
|
|
@ -98,6 +98,7 @@
|
|||
#include "couch_to_5k_face.h"
|
||||
#include "minute_repeater_decimal_face.h"
|
||||
#include "tuning_tones_face.h"
|
||||
#include "periodic_face.h"
|
||||
// New includes go above this line.
|
||||
|
||||
#endif // MOVEMENT_FACES_H_
|
||||
|
|
357
movement/watch_faces/complication/periodic_face.c
Normal file
357
movement/watch_faces/complication/periodic_face.c
Normal file
|
@ -0,0 +1,357 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2023 PrimmR
|
||||
*
|
||||
* 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"
|
||||
|
||||
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 = 1;
|
||||
state->mode = 0;
|
||||
state->selection_index = 0;
|
||||
|
||||
movement_request_tick_frequency(2);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[3];
|
||||
uint16_t atomic_mass;
|
||||
char group[3];
|
||||
} element;
|
||||
|
||||
// Comments on the table denote symbols that cannot be displayed
|
||||
#define MAX_ELEMENT 118
|
||||
const element table[MAX_ELEMENT] = {
|
||||
{"H ", 1, " "},
|
||||
{"He", 4, " 0"},
|
||||
{"Li", 7, " 1"},
|
||||
{"Be", 9, " 2"},
|
||||
{"B ", 11, " 3"},
|
||||
{"C ", 12, " 4"},
|
||||
{"N ", 14, " 5"},
|
||||
{"O ", 16, " 6"},
|
||||
{"F ", 19, " 7"},
|
||||
{"Ne", 20, " 0"},
|
||||
{"Na", 23, " 1"},
|
||||
{"Mg", 24, " 2"}, //
|
||||
{"Al", 27, " 3"},
|
||||
{"Si", 28, " 4"},
|
||||
{"P ", 31, " 5"},
|
||||
{"S ", 32, " 6"},
|
||||
{"Cl", 355, " 7"},
|
||||
{"Ar", 40, " 0"},
|
||||
{"K ", 39, " 1"},
|
||||
{"Ca", 40, " 2"},
|
||||
{"Sc", 45, " T"},
|
||||
{"Ti", 48, " T"},
|
||||
{" W", 51, " T"}, // "V"
|
||||
{"Cr", 52, " T"},
|
||||
{"Mn", 55, " T"},
|
||||
{"Fe", 56, " T"},
|
||||
{"Co", 59, " T"},
|
||||
{"Ni", 59, " T"},
|
||||
{"Cu", 635, " T"},
|
||||
{"Zn", 65, " T"},
|
||||
{"Ga", 70, " 3"},
|
||||
{"Ge", 73, " 4"},
|
||||
{"As", 75, " 5"}, //
|
||||
{"Se", 79, " 6"},
|
||||
{"Br", 80, " 7"},
|
||||
{"Kr", 84, " 0"},
|
||||
{"Rb", 85, " 1"},
|
||||
{"Sr", 88, " 2"},
|
||||
{"Y ", 89, " T"},
|
||||
{"Zr", 91, " T"},
|
||||
{"Nb", 93, " T"},
|
||||
{"Mo", 96, " T"},
|
||||
{"Tc", 97, " T"},
|
||||
{"Ru", 101, " T"},
|
||||
{"Rh", 103, " T"},
|
||||
{"Pd", 106, " T"},
|
||||
{"Ag", 108, " T"}, //
|
||||
{"Cd", 112, " T"},
|
||||
{"In", 115, " 3"},
|
||||
{"Sn", 119, " 4"},
|
||||
{"Sb", 122, " 5"},
|
||||
{"Te", 128, " 6"},
|
||||
{"I ", 127, " 7"},
|
||||
{"Xe", 131, " 0"},
|
||||
{"CS", 133, " 1"},
|
||||
{"Ba", 137, " 2"},
|
||||
{"La", 139, "1a"}, // La
|
||||
{"Ce", 140, "1a"},
|
||||
{"Pr", 141, "1a"},
|
||||
{"Nd", 144, "1a"},
|
||||
{"Pm", 145, "1a"},
|
||||
{"Sm", 150, "1a"},
|
||||
{"Eu", 152, "1a"},
|
||||
{"Gd", 157, "1a"},
|
||||
{"Tb", 159, "1a"},
|
||||
{"Dy", 163, "1a"}, // .5 Rounded up due to space constraints
|
||||
{"Ho", 165, "1a"},
|
||||
{"Er", 167, "1a"},
|
||||
{"Tm", 169, "1a"},
|
||||
{"Yb", 173, "1a"},
|
||||
{"Lu", 175, "1a"},
|
||||
{"Hf", 179, " T"},
|
||||
{"Ta", 181, " T"},
|
||||
{"W ", 184, " T"},
|
||||
{"Re", 186, " T"},
|
||||
{"OS", 190, " T"},
|
||||
{"Ir", 192, " T"},
|
||||
{"Pt", 195, " T"},
|
||||
{"Au", 197, " T"},
|
||||
{"Hg", 201, " T"}, //
|
||||
{"Tl", 204, " 3"},
|
||||
{"Pb", 207, " 4"},
|
||||
{"Bi", 209, " 5"},
|
||||
{"Po", 209, " 6"},
|
||||
{"At", 210, " 7"},
|
||||
{"Rn", 222, " 0"},
|
||||
{"Fr", 223, " 1"},
|
||||
{"Ra", 226, " 2"},
|
||||
{"Ac", 227, "Ac"},
|
||||
{"Th", 232, "Ac"},
|
||||
{"Pa", 231, "Ac"},
|
||||
{"U ", 238, "Ac"},
|
||||
{"Np", 237, "Ac"}, //
|
||||
{"Pu", 244, "Ac"},
|
||||
{"Am", 243, "Ac"},
|
||||
{"Cm", 247, "Ac"},
|
||||
{"Bk", 247, "Ac"}, //
|
||||
{"Cf", 251, "Ac"},
|
||||
{"Es", 252, "Ac"}, //
|
||||
{"Fm", 257, "Ac"},
|
||||
{"Md", 258, "Ac"},
|
||||
{"No", 259, "Ac"},
|
||||
{"Lr", 262, "Ac"},
|
||||
{"Rf", 267, " T"},
|
||||
{"Db", 262, " T"},
|
||||
{"Sg", 269, " T"}, //
|
||||
{"Bh", 264, " T"},
|
||||
{"Hs", 269, " T"},
|
||||
{"Mt", 278, " T"},
|
||||
{"Ds", 281, " T"}, //
|
||||
{"Rg", 282, " T"}, //
|
||||
{"Cn", 285, " T"},
|
||||
{"Nh", 286, " 3"},
|
||||
{"Fl", 289, " 4"},
|
||||
{"Mc", 289, " 5"},
|
||||
{"LW", 293, " 6"}, // Lv
|
||||
{"Ts", 294, " 7"}, //
|
||||
{"Og", 294, " 0"}, //
|
||||
};
|
||||
|
||||
// Warning light for symbols that can't be displayed
|
||||
static void _warning(periodic_state_t *state)
|
||||
{
|
||||
char second_char = table[state->atomic_num - 1].name[1];
|
||||
if (second_char == 'p' || second_char == 'g' || second_char == 'y' || second_char == 's')
|
||||
{
|
||||
watch_set_indicator(WATCH_INDICATOR_BELL);
|
||||
}
|
||||
else
|
||||
{
|
||||
watch_clear_indicator(WATCH_INDICATOR_BELL);
|
||||
}
|
||||
}
|
||||
|
||||
// Regular mode display
|
||||
static void _periodic_face_update_lcd(periodic_state_t *state)
|
||||
{
|
||||
// Colon as a decimal for Cl & Cu
|
||||
if (state->atomic_num == 17 || state->atomic_num == 29)
|
||||
{
|
||||
watch_set_colon();
|
||||
}
|
||||
else
|
||||
{
|
||||
watch_clear_colon();
|
||||
}
|
||||
|
||||
_warning(state);
|
||||
|
||||
char buf[11];
|
||||
sprintf(buf, "%s%s%-3d%3d", table[state->atomic_num - 1].name, table[state->atomic_num - 1].group, table[state->atomic_num - 1].atomic_mass, state->atomic_num);
|
||||
watch_display_string(buf, 0);
|
||||
}
|
||||
|
||||
// Selection mode logic
|
||||
static void _periodic_face_selection_increment(periodic_state_t *state)
|
||||
{
|
||||
uint8_t digit0 = (state->atomic_num / 100) % 10;
|
||||
uint8_t digit1 = (state->atomic_num / 10) % 10;
|
||||
uint8_t digit2 = (state->atomic_num) % 10;
|
||||
|
||||
// Increment the selected digit by 1
|
||||
switch (state->selection_index)
|
||||
{
|
||||
case 0:
|
||||
digit0 ^= 1;
|
||||
break;
|
||||
case 1:
|
||||
if (digit0 == MAX_ELEMENT / 100 && digit1 == (MAX_ELEMENT / 10) % 10)
|
||||
digit1 = 0;
|
||||
else
|
||||
digit1 = (digit1 + 1) % 10;
|
||||
break;
|
||||
case 2:
|
||||
if (digit0 == MAX_ELEMENT / 100 && digit1 == (MAX_ELEMENT / 10) % 10 && digit2 == MAX_ELEMENT % 10)
|
||||
digit2 = 0;
|
||||
else
|
||||
digit2 = (digit2 + 1) % 10;
|
||||
break;
|
||||
}
|
||||
|
||||
// Prevent 000
|
||||
if (digit0 == 0 && digit1 == 0 && digit2 == 0) {
|
||||
digit2 = 1;
|
||||
}
|
||||
|
||||
// Prevent Overflow
|
||||
if (digit0 == (MAX_ELEMENT / 100) % 10 && digit1 > (MAX_ELEMENT / 10) % 10)
|
||||
{
|
||||
digit2 = MAX_ELEMENT % 10;
|
||||
digit1 = (MAX_ELEMENT / 10) % 10;
|
||||
}
|
||||
|
||||
state->atomic_num = digit0 * 100 + digit1 * 10 + digit2;
|
||||
}
|
||||
|
||||
// Selection mode display
|
||||
static void _periodic_face_selection(periodic_state_t *state, uint8_t subsec)
|
||||
{
|
||||
uint8_t digit0 = (state->atomic_num / 100) % 10;
|
||||
uint8_t digit1 = (state->atomic_num / 10) % 10;
|
||||
uint8_t digit2 = (state->atomic_num) % 10;
|
||||
|
||||
watch_display_string(" ", 0);
|
||||
|
||||
char buf[2] = {'\0'};
|
||||
|
||||
buf[0] = (state->selection_index == 0 && subsec == 0) ? ' ' : digit0 + '0';
|
||||
watch_display_string(buf, 5);
|
||||
|
||||
buf[0] = (state->selection_index == 1 && subsec == 0) ? ' ' : digit1 + '0';
|
||||
watch_display_string(buf, 6);
|
||||
|
||||
buf[0] = (state->selection_index == 2 && subsec == 0) ? ' ' : digit2 + '0';
|
||||
watch_display_string(buf, 7);
|
||||
|
||||
char buf2[3];
|
||||
sprintf(buf2, "%s", table[state->atomic_num - 1].name);
|
||||
watch_display_string(buf2, 0);
|
||||
|
||||
_warning(state);
|
||||
}
|
||||
|
||||
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:
|
||||
_periodic_face_update_lcd(state);
|
||||
break;
|
||||
case EVENT_TICK:
|
||||
if (state->mode != 0)
|
||||
{
|
||||
_periodic_face_selection(state, event.subsecond % 2);
|
||||
}
|
||||
break;
|
||||
case EVENT_LIGHT_BUTTON_UP:
|
||||
// Only light LED when in regular mode
|
||||
if (state->mode != MODE_VIEW)
|
||||
{
|
||||
state->selection_index = (state->selection_index + 1) % 3;
|
||||
_periodic_face_selection(state, event.subsecond % 2);
|
||||
}
|
||||
break;
|
||||
case EVENT_LIGHT_BUTTON_DOWN:
|
||||
if (state->mode != MODE_SELECT)
|
||||
movement_illuminate_led();
|
||||
break;
|
||||
case EVENT_ALARM_BUTTON_UP:
|
||||
if (state->mode == MODE_VIEW)
|
||||
{
|
||||
state->atomic_num = (state->atomic_num % MAX_ELEMENT) + 1; // Wraps back to 1
|
||||
_periodic_face_update_lcd(state);
|
||||
if (settings->bit.button_should_sound) watch_buzzer_play_note(BUZZER_NOTE_C7, 50);
|
||||
}
|
||||
else
|
||||
{
|
||||
_periodic_face_selection_increment(state);
|
||||
_periodic_face_selection(state, event.subsecond % 2);
|
||||
}
|
||||
break;
|
||||
case EVENT_ALARM_LONG_PRESS:
|
||||
// Toggle between selection mode and regular
|
||||
if (state->mode == MODE_VIEW)
|
||||
{
|
||||
state->mode = MODE_SELECT;
|
||||
_periodic_face_selection(state, event.subsecond % 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->mode = MODE_VIEW;
|
||||
_periodic_face_update_lcd(state);
|
||||
}
|
||||
if (settings->bit.button_should_sound) watch_buzzer_play_note(BUZZER_NOTE_C8, 50);
|
||||
|
||||
break;
|
||||
case EVENT_TIMEOUT:
|
||||
break;
|
||||
case EVENT_LOW_ENERGY_UPDATE:
|
||||
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.
|
||||
}
|
61
movement/watch_faces/complication/periodic_face.h
Normal file
61
movement/watch_faces/complication/periodic_face.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2023 PrimmR
|
||||
*
|
||||
* 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 PERIODIC_FACE_H_
|
||||
#define PERIODIC_FACE_H_
|
||||
|
||||
#include "movement.h"
|
||||
|
||||
/*
|
||||
* Periodic Table Face
|
||||
*
|
||||
* Elements can be viewed sequentially with a short press of the alarm button,
|
||||
* or the atomic number can be input directly after holding down the alarm button.
|
||||
*
|
||||
*/
|
||||
|
||||
#define MODE_VIEW 0
|
||||
#define MODE_SELECT 1
|
||||
|
||||
typedef struct {
|
||||
uint8_t atomic_num;
|
||||
uint8_t mode;
|
||||
uint8_t selection_index;
|
||||
} periodic_state_t;
|
||||
|
||||
void periodic_face_setup(movement_settings_t *settings, uint8_t watch_face_index, void ** context_ptr);
|
||||
void periodic_face_activate(movement_settings_t *settings, void *context);
|
||||
bool periodic_face_loop(movement_event_t event, movement_settings_t *settings, void *context);
|
||||
void periodic_face_resign(movement_settings_t *settings, void *context);
|
||||
|
||||
#define periodic_face ((const watch_face_t){ \
|
||||
periodic_face_setup, \
|
||||
periodic_face_activate, \
|
||||
periodic_face_loop, \
|
||||
periodic_face_resign, \
|
||||
NULL, \
|
||||
})
|
||||
|
||||
#endif // PERIODIC_FACE_H_
|
||||
|
Loading…
Reference in a new issue