010d6041e6
into 45d60214f4
@ -0,0 +1,21 @@ | |||
/* Copyright 2024 QMK | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 2 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#pragma once | |||
#define CH_CFG_ST_FREQUENCY 10000 | |||
#include_next <chconf.h> |
@ -0,0 +1,12 @@ | |||
// Copyright 2023 georgsnarbuts (@georgsnarbuts) | |||
// SPDX-License-Identifier: GPL-2.0-or-later | |||
#pragma once | |||
#define TM1638_CLK_PIN A8 | |||
#define TM1638_DIO_PIN A9 | |||
#define TM1638_STB_PIN B15 | |||
#define VBUS_CHECK_PIN B5 | |||
#undef PRINTF_SUPPORT_DECIMAL_SPECIFIERS | |||
#define PRINTF_SUPPORT_DECIMAL_SPECIFIERS 1 |
@ -0,0 +1,23 @@ | |||
/* Copyright 2024 QMK | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 2 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#pragma once | |||
#define HAL_USE_ADC TRUE | |||
#define HAL_USE_I2C TRUE | |||
#include_next <halconf.h> |
@ -0,0 +1,50 @@ | |||
{ | |||
"manufacturer": "georgsnarbuts", | |||
"keyboard_name": "kalkulators", | |||
"maintainer": "georgsnarbuts", | |||
"bootloader": "stm32-dfu", | |||
"diode_direction": "COL2ROW", | |||
"features": { | |||
"bootmagic": true, | |||
"command": true, | |||
"console": true, | |||
"extrakey": true, | |||
"mousekey": true, | |||
"nkro": true | |||
}, | |||
"matrix_pins": { | |||
"cols": ["A6", "A5", "A4", "A3"], | |||
"rows": ["A7", "B0", "A2", "A1", "A0"] | |||
}, | |||
"processor": "STM32F072", | |||
"url": "", | |||
"usb": { | |||
"device_version": "1.0.0", | |||
"pid": "0x4B4C", | |||
"vid": "0x474E", | |||
"no_startup_check": true | |||
}, | |||
"layouts": { | |||
"LAYOUT_calc": { | |||
"layout": [ | |||
{"matrix": [0, 0], "x": 0, "y": 0}, | |||
{"matrix": [0, 1], "x": 1, "y": 0}, | |||
{"matrix": [0, 2], "x": 2, "y": 0}, | |||
{"matrix": [0, 3], "x": 3, "y": 0}, | |||
{"matrix": [1, 0], "x": 0, "y": 1}, | |||
{"matrix": [1, 1], "x": 1, "y": 1}, | |||
{"matrix": [1, 2], "x": 2, "y": 1}, | |||
{"matrix": [2, 0], "x": 0, "y": 2}, | |||
{"matrix": [2, 1], "x": 1, "y": 2}, | |||
{"matrix": [2, 2], "x": 2, "y": 2}, | |||
{"matrix": [1, 3], "x": 3, "y": 1, "h": 2}, | |||
{"matrix": [3, 0], "x": 0, "y": 3}, | |||
{"matrix": [3, 1], "x": 1, "y": 3}, | |||
{"matrix": [3, 2], "x": 2, "y": 3}, | |||
{"matrix": [4, 0], "x": 0, "y": 4, "w": 2}, | |||
{"matrix": [4, 2], "x": 2, "y": 4}, | |||
{"matrix": [3, 3], "x": 3, "y": 3, "h": 2} | |||
] | |||
} | |||
} | |||
} |
@ -0,0 +1,471 @@ | |||
/* Copyright 2024 georgsnarbuts | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 2 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include QMK_KEYBOARD_H | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <math.h> | |||
#include <ctype.h> | |||
#include <string.h> | |||
#include "kalkulators.h" | |||
#include "halconf.h" | |||
#include "tm1638.h" | |||
#include "usb_util.h" | |||
#include "wait.h" | |||
// calculate the number of whole digits and decimal digits in a double | |||
void countDigitsAndDecimalPlaces(double input, int *wholeDigits, int *decimalPlaces) { | |||
// Convert double to string | |||
char inputString[32]; // Adjust the size based on your needs | |||
snprintf(inputString, sizeof(inputString), "%f", input); | |||
// Remove trailing zeros | |||
char *end = inputString + strlen(inputString) - 1; | |||
while (*end == '0') { | |||
*end-- = '\0'; | |||
} | |||
// Initialize counts | |||
*wholeDigits = 0; | |||
*decimalPlaces = 0; | |||
int decimalFound = 0; | |||
// Skip the negative sign if present | |||
int startIdx = (inputString[0] == '-') ? 1 : 0; | |||
// Iterate through each character in the modified input string | |||
for (int i = startIdx; i < strlen(inputString); i++) { | |||
if (isdigit((unsigned char)inputString[i])) { | |||
if (!decimalFound) { | |||
(*wholeDigits)++; // Increment count of whole digits | |||
} else { | |||
(*decimalPlaces)++; // Increment count of decimal places | |||
} | |||
} else if (inputString[i] == '.') { | |||
decimalFound = 1; // Decimal point is found | |||
} else { | |||
// Break the loop if a non-digit or non-decimal point character is encountered | |||
break; | |||
} | |||
} | |||
} | |||
enum custom_keycodes { | |||
KC_cl = QK_KB_0, | |||
KC_div, | |||
KC_times, | |||
KC_minus, | |||
KC_seven, | |||
KC_eight, | |||
KC_nine, | |||
KC_four, | |||
KC_five, | |||
KC_six, | |||
KC_plus, | |||
KC_one, | |||
KC_two, | |||
KC_three, | |||
KC_zero, | |||
KC_dot, | |||
KC_equals | |||
}; | |||
typedef struct { | |||
double accumulator; | |||
char current_input[8]; | |||
} results; | |||
results number = {0, ""}; | |||
typedef struct { | |||
bool dp_pressed; | |||
bool operator_pressed; | |||
bool input_start; | |||
bool negative_number; | |||
bool nonzero_pressed; | |||
bool waiting_for_operator; | |||
bool plus_operator_pressed; | |||
bool minus_operator_pressed; | |||
bool multiplication_operator_pressed; | |||
bool division_operator_pressed; | |||
bool operator_pressed_first_time; | |||
bool enter_pressed; | |||
} operations; | |||
operations operation_state = {false, false, true, false, false, false, false, false, false, false, true, false}; | |||
void reset_states(void) { | |||
number.accumulator = 0; | |||
number.current_input[0] = '\0'; | |||
operation_state.dp_pressed = false; | |||
operation_state.operator_pressed = false; | |||
operation_state.input_start = true; | |||
operation_state.negative_number = false; | |||
operation_state.nonzero_pressed = false; | |||
operation_state.waiting_for_operator = false; | |||
operation_state.plus_operator_pressed = false; | |||
operation_state.minus_operator_pressed = false; | |||
operation_state.multiplication_operator_pressed = false; | |||
operation_state.division_operator_pressed = false; | |||
operation_state.operator_pressed_first_time = true; | |||
operation_state.enter_pressed = false; | |||
}; | |||
void reset_states_after_enter(void) { | |||
number.current_input[0] = '\0'; | |||
operation_state.dp_pressed = false; | |||
operation_state.operator_pressed = false; | |||
operation_state.input_start = true; | |||
operation_state.negative_number = false; | |||
operation_state.nonzero_pressed = false; | |||
operation_state.waiting_for_operator = true; | |||
operation_state.plus_operator_pressed = false; | |||
operation_state.minus_operator_pressed = false; | |||
operation_state.multiplication_operator_pressed = false; | |||
operation_state.division_operator_pressed = false; | |||
operation_state.enter_pressed = false; | |||
}; | |||
// display a char on the 7seg display | |||
void display_result(const char *text) { | |||
reset(); | |||
int x; | |||
sscanf(text, "%d", &x); | |||
print(text); | |||
if ((strcmp(text, "inf") == 0) || ((x > 99999999))) { | |||
displayText("Error "); | |||
reset_states(); | |||
return; | |||
} | |||
if (strchr(text, '.') == NULL) { | |||
displayTextRight(text); | |||
} else { | |||
displayTextRightFloat(text); | |||
} | |||
} | |||
void display_final_result(void) { | |||
char output[10]; | |||
int wholeDigits, decimalPlaces; | |||
countDigitsAndDecimalPlaces(number.accumulator, &wholeDigits, &decimalPlaces); | |||
snprintf(output, 10, "%*.*f", wholeDigits, decimalPlaces, number.accumulator); | |||
display_result(output); | |||
} | |||
void into_current_input(double input) { | |||
char input_char[11]; | |||
snprintf(input_char, sizeof(input_char), "%.0f", input); | |||
// limiting input to 8 digits | |||
if (strlen(number.current_input) + strlen(input_char) <= 8 && strchr(number.current_input, '.') == NULL) { | |||
strcat(number.current_input, input_char); | |||
display_result(number.current_input); | |||
} else if (strlen(number.current_input) + strlen(input_char) <= 9 && strchr(number.current_input, '.') != NULL) { | |||
strcat(number.current_input, input_char); | |||
display_result(number.current_input); | |||
} | |||
}; | |||
// equals | |||
void equals_operation(void) { | |||
if ((operation_state.plus_operator_pressed == true)) { | |||
number.accumulator += atof(number.current_input); | |||
display_final_result(); | |||
reset_states_after_enter(); | |||
} else if ((operation_state.minus_operator_pressed == true)) { | |||
number.accumulator -= atof(number.current_input); | |||
display_final_result(); | |||
reset_states_after_enter(); | |||
} else if ((operation_state.multiplication_operator_pressed == true)) { | |||
number.accumulator *= atof(number.current_input); | |||
display_final_result(); | |||
reset_states_after_enter(); | |||
} else if ((operation_state.division_operator_pressed == true)) { | |||
number.accumulator /= atof(number.current_input); | |||
display_final_result(); | |||
reset_states_after_enter(); | |||
} | |||
}; | |||
void plus_operation(void) { | |||
if (number.current_input[0] != '\0') { | |||
equals_operation(); | |||
number.accumulator = number.accumulator + atof(number.current_input); | |||
} else { | |||
operation_state.operator_pressed_first_time = true; | |||
} | |||
reset(); | |||
operation_state.plus_operator_pressed = true; | |||
operation_state.minus_operator_pressed = false; | |||
operation_state.multiplication_operator_pressed = false; | |||
operation_state.division_operator_pressed = false; | |||
number.current_input[0] = '\0'; | |||
if (operation_state.operator_pressed_first_time == true) { | |||
display_result("\0"); | |||
} else { | |||
display_final_result(); | |||
} | |||
operation_state.operator_pressed_first_time = false; | |||
}; | |||
void minus_operation(void) { | |||
if (number.current_input[0] != '\0') { | |||
equals_operation(); | |||
number.accumulator = number.accumulator + atof(number.current_input); | |||
} else { | |||
operation_state.operator_pressed_first_time = true; | |||
} | |||
reset(); | |||
operation_state.plus_operator_pressed = false; | |||
operation_state.minus_operator_pressed = true; | |||
operation_state.multiplication_operator_pressed = false; | |||
operation_state.division_operator_pressed = false; | |||
number.current_input[0] = '\0'; | |||
if (operation_state.operator_pressed_first_time == true) { | |||
display_result("\0"); | |||
} else { | |||
display_final_result(); | |||
} | |||
operation_state.operator_pressed_first_time = false; | |||
}; | |||
void multiply_operation(void) { | |||
if (number.current_input[0] != '\0') { | |||
equals_operation(); | |||
number.accumulator = number.accumulator + atof(number.current_input); | |||
} else { | |||
operation_state.operator_pressed_first_time = true; | |||
} | |||
reset(); | |||
operation_state.plus_operator_pressed = false; | |||
operation_state.minus_operator_pressed = false; | |||
operation_state.multiplication_operator_pressed = true; | |||
operation_state.division_operator_pressed = false; | |||
number.current_input[0] = '\0'; | |||
if (operation_state.operator_pressed_first_time == true) { | |||
display_result("\0"); | |||
} else { | |||
display_final_result(); | |||
} | |||
operation_state.operator_pressed_first_time = false; | |||
}; | |||
void divide_operation(void) { | |||
if (number.current_input[0] != '\0') { | |||
equals_operation(); | |||
number.accumulator = number.accumulator + atof(number.current_input); | |||
} else { | |||
operation_state.operator_pressed_first_time = true; | |||
} | |||
reset(); | |||
operation_state.plus_operator_pressed = false; | |||
operation_state.minus_operator_pressed = false; | |||
operation_state.multiplication_operator_pressed = false; | |||
operation_state.division_operator_pressed = true; | |||
number.current_input[0] = '\0'; | |||
if (operation_state.operator_pressed_first_time == true) { | |||
display_result("\0"); | |||
} else { | |||
display_final_result(); | |||
} | |||
operation_state.operator_pressed_first_time = false; | |||
}; | |||
// clearing the display | |||
void clear_operation(void) { | |||
reset_states(); | |||
reset(); | |||
displayTextRight("0"); | |||
}; | |||
// processes input from the process_record_user function | |||
void process_input(double input) { | |||
// Reset states if enter key was pressed and a number is entered | |||
if (operation_state.enter_pressed == true && input < 10) { | |||
reset_states(); | |||
print("entered new calculations"); | |||
} | |||
// handle number inputs | |||
if (input < 10) { | |||
// handle so that multiple zeros can't be pressed at the start of writing | |||
if (operation_state.input_start == true && input == 0) { | |||
into_current_input(input); | |||
operation_state.input_start = false; | |||
} else { | |||
if (input == 0) { | |||
if (operation_state.nonzero_pressed) { | |||
into_current_input(input); | |||
operation_state.waiting_for_operator = true; | |||
} | |||
} else { | |||
if ((strcmp(number.current_input, "0") == 0)) { | |||
number.current_input[0] = '\0'; | |||
} | |||
into_current_input(input); | |||
operation_state.input_start = false; | |||
operation_state.nonzero_pressed = true; | |||
operation_state.waiting_for_operator = true; | |||
} | |||
} | |||
} | |||
// handle clearing | |||
else if (input == 777) { | |||
number.accumulator = 0; | |||
number.current_input[0] = '\0'; | |||
clear_operation(); | |||
operation_state.enter_pressed = false; // Reset the flag | |||
} | |||
// handle decimal point | |||
else if ((operation_state.input_start == false) && (operation_state.dp_pressed == false) && (input == 111)) { | |||
char buffer[2] = "."; | |||
strcat(number.current_input, buffer); | |||
display_result(number.current_input); | |||
operation_state.dp_pressed = true; | |||
operation_state.nonzero_pressed = true; | |||
} | |||
// handle summation | |||
else if (input == 333 && operation_state.waiting_for_operator == true) { | |||
reset(); | |||
plus_operation(); | |||
operation_state.nonzero_pressed = false; | |||
operation_state.dp_pressed = false; | |||
operation_state.input_start = true; | |||
operation_state.enter_pressed = false; // Reset the flag | |||
} | |||
// handle minus | |||
else if (input == 444 && operation_state.waiting_for_operator == true) { | |||
reset(); | |||
minus_operation(); | |||
operation_state.nonzero_pressed = false; | |||
operation_state.dp_pressed = false; | |||
operation_state.input_start = true; | |||
operation_state.enter_pressed = false; // Reset the flag | |||
} | |||
// handle multiplication | |||
else if (input == 555 && operation_state.waiting_for_operator == true) { | |||
reset(); | |||
multiply_operation(); | |||
operation_state.nonzero_pressed = false; | |||
operation_state.dp_pressed = false; | |||
operation_state.input_start = true; | |||
operation_state.enter_pressed = false; // Reset the flag | |||
} | |||
// handle division | |||
else if (input == 666 && operation_state.waiting_for_operator == true) { | |||
reset(); | |||
divide_operation(); | |||
operation_state.nonzero_pressed = false; | |||
operation_state.dp_pressed = false; | |||
operation_state.input_start = true; | |||
operation_state.enter_pressed = false; // Reset the flag | |||
} | |||
else if (input == 999) { | |||
equals_operation(); | |||
if (!operation_state.waiting_for_operator) { | |||
operation_state.enter_pressed = true; // Set the flag only if a valid calculation was performed | |||
} | |||
} | |||
} | |||
// listens for keypresses | |||
bool process_record_kb(uint16_t keycode, keyrecord_t *record) { | |||
if (record->event.pressed) { | |||
switch (keycode) { | |||
case KC_cl: | |||
process_input(777); | |||
break; | |||
case KC_div: | |||
process_input(666); | |||
break; | |||
case KC_times: | |||
process_input(555); | |||
break; | |||
case KC_minus: | |||
process_input(444); | |||
break; | |||
case KC_seven: | |||
process_input(7); | |||
break; | |||
case KC_eight: | |||
process_input(8); | |||
break; | |||
case KC_nine: | |||
process_input(9); | |||
break; | |||
case KC_four: | |||
process_input(4); | |||
break; | |||
case KC_five: | |||
process_input(5); | |||
break; | |||
case KC_six: | |||
process_input(6); | |||
break; | |||
case KC_plus: | |||
process_input(333); | |||
break; | |||
case KC_one: | |||
process_input(1); | |||
break; | |||
case KC_two: | |||
process_input(2); | |||
break; | |||
case KC_three: | |||
process_input(3); | |||
break; | |||
case KC_zero: | |||
process_input(0); | |||
break; | |||
case KC_dot: | |||
process_input(111); | |||
break; | |||
case KC_equals: | |||
process_input(999); | |||
operation_state.enter_pressed = true; | |||
break; | |||
} | |||
} | |||
return process_record_user(keycode, record); | |||
}; |
@ -0,0 +1,31 @@ | |||
/* Copyright 2024 georgsnarbuts | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 2 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#pragma once | |||
void countDigitsAndDecimalPlaces(double input, int *wholeDigits, int *decimalPlaces); | |||
void reset_states(void); | |||
void reset_states_after_enter(void); | |||
void display_result(const char* text); | |||
void display_final_result(void); | |||
void into_current_input(double input); | |||
void equals_operation(void); | |||
void plus_operation(void); | |||
void minus_operation(void); | |||
void multiply_operation(void); | |||
void divide_operation(void); | |||
void clear_operation(void); | |||
void process_input(double input); |
@ -0,0 +1,274 @@ | |||
// Copyright 2023 QMK | |||
// SPDX-License-Identifier: GPL-2.0-or-later | |||
#include QMK_KEYBOARD_H | |||
#include <stdio.h> | |||
#include "halconf.h" | |||
#include "tm1638.h" | |||
#include "wait.h" | |||
#include "usb_util.h" | |||
#include "kalkulators.h" | |||
int brightness_level = 7; | |||
bool show_usb_connection = true; | |||
bool show_calc_connection = true; | |||
bool pc_connection; | |||
int layer; | |||
void keyboard_post_init_user(void) { | |||
// Customise these values to desired behaviour | |||
debug_enable=true; | |||
debug_matrix=true; | |||
debug_keyboard=true; | |||
setPinOutput(TM1638_CLK_PIN); | |||
setPinOutput(TM1638_STB_PIN); | |||
setPinOutput(TM1638_DIO_PIN); | |||
displayBegin(); | |||
wait_ms(0.1); | |||
brightness(brightness_level); | |||
if (usb_connected_state() == 1) { | |||
set_single_persistent_default_layer(0); | |||
if (show_usb_connection == true){ | |||
layer = 0; | |||
pc_connection = true; | |||
show_usb_connection = false; | |||
reset(); | |||
display7Seg(3, 0b01110011); | |||
display7Seg(4, 0b00111001); | |||
wait_ms(500); | |||
reset(); | |||
} | |||
show_calc_connection = true; | |||
} else if (usb_connected_state() == 0){ | |||
set_single_persistent_default_layer(1); | |||
if (show_calc_connection == true){ | |||
layer = 1; | |||
pc_connection = false; | |||
show_calc_connection = false; | |||
reset(); | |||
display7Seg(2, 0b00111001); | |||
display7Seg(3, 0b01110111); | |||
display7Seg(4, 0b00111000); | |||
display7Seg(5, 0b00111001); | |||
wait_ms(500); | |||
reset(); | |||
display7Seg(7, 0b00111111); | |||
} | |||
show_usb_connection = true; | |||
} | |||
}; | |||
enum custom_keycodes { | |||
KC_cl = QK_KB_0, | |||
KC_div, | |||
KC_times, | |||
KC_minus, | |||
KC_seven, | |||
KC_eight, | |||
KC_nine, | |||
KC_four, | |||
KC_five, | |||
KC_six, | |||
KC_plus, | |||
KC_one, | |||
KC_two, | |||
KC_three, | |||
KC_zero, | |||
KC_dot, | |||
KC_equals | |||
}; | |||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||
/* | |||
* ┌───┬───┬───┬───┐ | |||
* │TG1│ / │ * │ - │ | |||
* ├───┼───┼───┼───┤ | |||
* │ 7 │ 8 │ 9 │ │ | |||
* ├───┼───┼───┤ + │ | |||
* │ 4 │ 5 │ 6 │ │ | |||
* ├───┼───┼───┼───┤ | |||
* │ 1 │ 2 │ 3 │ │ | |||
* ├───┴───┼───┤Ent│ | |||
* │ 0 │ . │ │ | |||
* └───────┴───┴───┘ | |||
*/ | |||
[0] = LAYOUT_calc( | |||
KC_DELETE, KC_PSLS, KC_PAST, KC_PMNS, | |||
KC_P7, KC_P8, KC_P9, | |||
KC_P4, KC_P5, KC_P6, KC_PPLS, | |||
KC_P1, KC_P2, KC_P3, | |||
KC_P0, KC_PDOT, KC_PENT | |||
), | |||
[1] = LAYOUT_calc( | |||
QK_KB_0, KC_div, KC_times, KC_minus, | |||
KC_seven, KC_eight, KC_nine, | |||
KC_four, KC_five, KC_six, KC_plus, | |||
KC_one, KC_two, KC_three, | |||
KC_zero, KC_dot, KC_equals | |||
) | |||
}; | |||
void housekeeping_task_user(void) { | |||
if (usb_connected_state() == 1) { | |||
if (show_usb_connection == true){ | |||
set_single_persistent_default_layer(0); | |||
layer = 0; | |||
pc_connection = true; | |||
show_usb_connection = false; | |||
reset(); | |||
display7Seg(3, 0b01110011); | |||
display7Seg(4, 0b00111001); | |||
wait_ms(500); | |||
reset(); | |||
} | |||
show_calc_connection = true; | |||
} else if (usb_connected_state() == 0){ | |||
set_single_persistent_default_layer(1); | |||
if (show_calc_connection == true){ | |||
pc_connection = false; | |||
show_calc_connection = false; | |||
reset(); | |||
reset_states(); | |||
display7Seg(2, 0b00111001); | |||
display7Seg(3, 0b01110111); | |||
display7Seg(4, 0b00111000); | |||
display7Seg(5, 0b00111001); | |||
wait_ms(500); | |||
reset(); | |||
display7Seg(7, 0b00111111); | |||
} | |||
show_usb_connection = true; | |||
} | |||
} | |||
enum combo_events { | |||
CHANGE_BRIGHTNESS_UP, | |||
CHANGE_BRIGHTNESS_DOWN, | |||
CHANGE_LAYER, | |||
CHANGE_LAYER_ON_PC | |||
}; | |||
const uint16_t PROGMEM brightness_combo_up[] = {KC_cl, KC_times, COMBO_END}; | |||
const uint16_t PROGMEM brightness_combo_down[] = {KC_cl, KC_div, COMBO_END}; | |||
const uint16_t PROGMEM change_layer[] = {KC_minus, KC_plus, COMBO_END}; | |||
const uint16_t PROGMEM change_layer_on_pc[] = {KC_PMNS, KC_PPLS, COMBO_END}; | |||
combo_t key_combos[] = { | |||
[CHANGE_BRIGHTNESS_UP] = COMBO_ACTION(brightness_combo_up), | |||
[CHANGE_BRIGHTNESS_DOWN] = COMBO_ACTION(brightness_combo_down), | |||
[CHANGE_LAYER] = COMBO_ACTION(change_layer), | |||
[CHANGE_LAYER_ON_PC] = COMBO_ACTION(change_layer_on_pc) | |||
}; | |||
void process_combo_event(uint16_t combo_index, bool pressed) { | |||
switch(combo_index) { | |||
case CHANGE_BRIGHTNESS_UP: | |||
if (pressed) { | |||
if (brightness_level < 7){ | |||
brightness_level += 1; | |||
brightness(brightness_level); | |||
} | |||
} | |||
break; | |||
case CHANGE_BRIGHTNESS_DOWN: | |||
if (pressed) { | |||
if (brightness_level > 0){ | |||
brightness_level -= 1; | |||
brightness(brightness_level); | |||
} | |||
} | |||
break; | |||
case CHANGE_LAYER: | |||
if (pressed) { | |||
print("changing_layer"); | |||
if (pc_connection == true){ | |||
if (layer == 1){ | |||
set_single_persistent_default_layer(0); | |||
layer = 0; | |||
reset(); | |||
display7Seg(3, 0b01110011); | |||
display7Seg(4, 0b00111001); | |||
wait_ms(500); | |||
reset(); | |||
} | |||
else if (layer == 0){ | |||
set_single_persistent_default_layer(1); | |||
layer = 1; | |||
reset(); | |||
reset_states(); | |||
display7Seg(2, 0b00111001); | |||
display7Seg(3, 0b01110111); | |||
display7Seg(4, 0b00111000); | |||
display7Seg(5, 0b00111001); | |||
wait_ms(500); | |||
reset(); | |||
display7Seg(7, 0b00111111); | |||
} | |||
} | |||
} | |||
break; | |||
case CHANGE_LAYER_ON_PC: | |||
if (pressed) { | |||
print("changing_layer"); | |||
if (pc_connection == true){ | |||
if (layer == 1){ | |||
set_single_persistent_default_layer(0); | |||
layer = 0; | |||
reset(); | |||
display7Seg(3, 0b01110011); | |||
display7Seg(4, 0b00111001); | |||
wait_ms(500); | |||
reset(); | |||
} | |||
else if (layer == 0){ | |||
set_single_persistent_default_layer(1); | |||
layer = 1; | |||
reset(); | |||
reset_states(); | |||
display7Seg(2, 0b00111001); | |||
display7Seg(3, 0b01110111); | |||
display7Seg(4, 0b00111000); | |||
display7Seg(5, 0b00111001); | |||
wait_ms(500); | |||
reset(); | |||
display7Seg(7, 0b00111111); | |||
} | |||
} | |||
} | |||
break; | |||
} | |||
} | |||
@ -0,0 +1 @@ | |||
COMBO_ENABLE = yes |
@ -0,0 +1,278 @@ | |||
// Copyright 2023 QMK | |||
// SPDX-License-Identifier: GPL-2.0-or-later | |||
#include QMK_KEYBOARD_H | |||
#include <stdio.h> | |||
#include "halconf.h" | |||
#include "tm1638.h" | |||
#include "wait.h" | |||
#include "usb_util.h" | |||
#include "kalkulators.h" | |||
int brightness_level = 7; | |||
bool show_usb_connection = true; | |||
bool show_calc_connection = true; | |||
bool pc_connection; | |||
int layer; | |||
void keyboard_post_init_user(void) { | |||
// Customise these values to desired behaviour | |||
debug_enable=true; | |||
debug_matrix=true; | |||
debug_keyboard=true; | |||
setPinOutput(TM1638_CLK_PIN); | |||
setPinOutput(TM1638_STB_PIN); | |||
setPinOutput(TM1638_DIO_PIN); | |||
displayBegin(); | |||
wait_ms(0.1); | |||
brightness(brightness_level); | |||
if (usb_connected_state() == 1) { | |||
set_single_persistent_default_layer(0); | |||
if (show_usb_connection == true){ | |||
layer = 0; | |||
pc_connection = true; | |||
show_usb_connection = false; | |||
reset(); | |||
display7Seg(3, 0b01110011); | |||
display7Seg(4, 0b00111001); | |||
wait_ms(500); | |||
reset(); | |||
} | |||
show_calc_connection = true; | |||
} else if (usb_connected_state() == 0){ | |||
set_single_persistent_default_layer(1); | |||
if (show_calc_connection == true){ | |||
layer = 1; | |||
pc_connection = false; | |||
show_calc_connection = false; | |||
reset(); | |||
display7Seg(2, 0b00111001); | |||
display7Seg(3, 0b01110111); | |||
display7Seg(4, 0b00111000); | |||
display7Seg(5, 0b00111001); | |||
wait_ms(500); | |||
reset(); | |||
display7Seg(7, 0b00111111); | |||
} | |||
show_usb_connection = true; | |||
} | |||
}; | |||
enum custom_keycodes { | |||
KC_cl = QK_KB_0, | |||
KC_div, | |||
KC_times, | |||
KC_minus, | |||
KC_seven, | |||
KC_eight, | |||
KC_nine, | |||
KC_four, | |||
KC_five, | |||
KC_six, | |||
KC_plus, | |||
KC_one, | |||
KC_two, | |||
KC_three, | |||
KC_zero, | |||
KC_dot, | |||
KC_equals | |||
}; | |||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||
/* | |||
* ┌───┬───┬───┬───┐ | |||
* │TG1│ / │ * │ - │ | |||
* ├───┼───┼───┼───┤ | |||
* │ 7 │ 8 │ 9 │ │ | |||
* ├───┼───┼───┤ + │ | |||
* │ 4 │ 5 │ 6 │ │ | |||
* ├───┼───┼───┼───┤ | |||
* │ 1 │ 2 │ 3 │ │ | |||
* ├───┴───┼───┤Ent│ | |||
* │ 0 │ . │ │ | |||
* └───────┴───┴───┘ | |||
*/ | |||
[0] = LAYOUT_calc( | |||
KC_DELETE, KC_PSLS, KC_PAST, KC_PMNS, | |||
KC_P7, KC_P8, KC_P9, | |||
KC_P4, KC_P5, KC_P6, KC_PPLS, | |||
KC_P1, KC_P2, KC_P3, | |||
KC_P0, KC_PDOT, KC_PENT | |||
), | |||
[1] = LAYOUT_calc( | |||
QK_KB_0, KC_div, KC_times, KC_minus, | |||
KC_seven, KC_eight, KC_nine, | |||
KC_four, KC_five, KC_six, KC_plus, | |||
KC_one, KC_two, KC_three, | |||
KC_zero, KC_dot, KC_equals | |||
) | |||
}; | |||
void housekeeping_task_user(void) { | |||
if (usb_connected_state() == 1) { | |||
if (show_usb_connection == true){ | |||
set_single_persistent_default_layer(0); | |||
layer = 0; | |||
pc_connection = true; | |||
show_usb_connection = false; | |||
reset(); | |||
display7Seg(3, 0b01110011); | |||
display7Seg(4, 0b00111001); | |||
wait_ms(500); | |||
reset(); | |||
} | |||
show_calc_connection = true; | |||
} else if (usb_connected_state() == 0){ | |||
set_single_persistent_default_layer(1); | |||
if (show_calc_connection == true){ | |||
pc_connection = false; | |||
show_calc_connection = false; | |||
reset(); | |||
reset_states(); | |||
display7Seg(2, 0b00111001); | |||
display7Seg(3, 0b01110111); | |||
display7Seg(4, 0b00111000); | |||
display7Seg(5, 0b00111001); | |||
wait_ms(500); | |||
reset(); | |||
display7Seg(7, 0b00111111); | |||
} | |||
show_usb_connection = true; | |||
} | |||
} | |||
enum combo_events { | |||
CHANGE_BRIGHTNESS_UP, | |||
CHANGE_BRIGHTNESS_DOWN, | |||
CHANGE_LAYER, | |||
CHANGE_LAYER_ON_PC | |||
}; | |||
const uint16_t PROGMEM brightness_combo_up[] = {KC_cl, KC_times, COMBO_END}; | |||
const uint16_t PROGMEM brightness_combo_down[] = {KC_cl, KC_div, COMBO_END}; | |||
const uint16_t PROGMEM change_layer[] = {KC_minus, KC_plus, COMBO_END}; | |||
const uint16_t PROGMEM change_layer_on_pc[] = {KC_PMNS, KC_PPLS, COMBO_END}; | |||
combo_t key_combos[] = { | |||
[CHANGE_BRIGHTNESS_UP] = COMBO_ACTION(brightness_combo_up), | |||
[CHANGE_BRIGHTNESS_DOWN] = COMBO_ACTION(brightness_combo_down), | |||
[CHANGE_LAYER] = COMBO_ACTION(change_layer), | |||
[CHANGE_LAYER_ON_PC] = COMBO_ACTION(change_layer_on_pc) | |||
}; | |||
void process_combo_event(uint16_t combo_index, bool pressed) { | |||
switch(combo_index) { | |||
case CHANGE_BRIGHTNESS_UP: | |||
if (pressed) { | |||
if (brightness_level < 7){ | |||
brightness_level += 1; | |||
brightness(brightness_level); | |||
} | |||
} | |||
break; | |||
case CHANGE_BRIGHTNESS_DOWN: | |||
if (pressed) { | |||
if (brightness_level > 0){ | |||
brightness_level -= 1; | |||
brightness(brightness_level); | |||
} | |||
} | |||
break; | |||
case CHANGE_LAYER: | |||
if (pressed) { | |||
print("changing_layer"); | |||
if (pc_connection == true){ | |||
if (layer == 1){ | |||
set_single_persistent_default_layer(0); | |||
layer = 0; | |||
reset(); | |||
display7Seg(3, 0b01110011); | |||
display7Seg(4, 0b00111001); | |||
wait_ms(500); | |||
reset(); | |||
} | |||
else if (layer == 0){ | |||
set_single_persistent_default_layer(1); | |||
layer = 1; | |||
reset(); | |||
reset_states(); | |||
display7Seg(2, 0b00111001); | |||
display7Seg(3, 0b01110111); | |||
display7Seg(4, 0b00111000); | |||
display7Seg(5, 0b00111001); | |||
wait_ms(500); | |||
reset(); | |||
display7Seg(7, 0b00111111); | |||
} | |||
} | |||
} | |||
break; | |||
case CHANGE_LAYER_ON_PC: | |||
if (pressed) { | |||
print("changing_layer"); | |||
if (pc_connection == true){ | |||
if (layer == 1){ | |||
set_single_persistent_default_layer(0); | |||
layer = 0; | |||
reset(); | |||
display7Seg(3, 0b01110011); | |||
display7Seg(4, 0b00111001); | |||
wait_ms(500); | |||
reset(); | |||
} | |||
else if (layer == 0){ | |||
set_single_persistent_default_layer(1); | |||
layer = 1; | |||
reset(); | |||
reset_states(); | |||
display7Seg(2, 0b00111001); | |||
display7Seg(3, 0b01110111); | |||
display7Seg(4, 0b00111000); | |||
display7Seg(5, 0b00111001); | |||
wait_ms(500); | |||
reset(); | |||
display7Seg(7, 0b00111111); | |||
} | |||
} | |||
} | |||
break; | |||
} | |||
} | |||
@ -0,0 +1,2 @@ | |||
VIA_ENABLE = yes | |||
COMBO_ENABLE = yes |
@ -0,0 +1,26 @@ | |||
/* Copyright 2024 QMK | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 2 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#pragma once | |||
#include_next <mcuconf.h> | |||
#undef STM32_ADC_USE_ADC1 | |||
#define STM32_ADC_USE_ADC1 TRUE | |||
#undef STM32_I2C_USE_I2C1 | |||
#define STM32_I2C_USE_I2C1 TRUE | |||
@ -0,0 +1,46 @@ | |||
# kalkulators | |||
![kalkulators](https://i.imgur.com/hodQbV1h.jpeg) | |||
An 8 digit 7-segment display calculator and numpad. | |||
USB-C, STM32F072, TM1638 LED controller, 1xAA battery. | |||
**When editing layers through keymap or VIA, do not delete/edit the 1st layer, it is needed for the calculator functionality!** | |||
* Keyboard Maintainer: [georgsnarbuts](https://github.com/georgsnarbuts) | |||
Make example for this keyboard (after setting up your build environment): | |||
make kalkulators:default | |||
Flashing example for this keyboard: | |||
make kalkulators:default:flash | |||
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs). | |||
## Combos | |||
* **To decrese display brightness**: | |||
Tap "Delete" and "Divide" buttons in unison. | |||
* **To increase display brightness**: | |||
Tap "Delete" and "*" buttons in unison. | |||
* **To switch between calculator and numpad mode when connected to a host computer**: | |||
Tap "+" and "-" buttons in unison. | |||
## Bootloader | |||
Enter the bootloader: | |||
* **Physical reset button**: | |||
1) Turn off the battery power switch on the right side of the board. | |||
2) Toggle the boot switch to the bottom position on the back of the PCB. | |||
3) If board already connected to a host computer through USB-C, press the reset button on the back of the PCB. If not plugged in, then just connect the USB-C cable to a host computer and the PCB. | |||
4) Board should have entered the bootloader. | |||
@ -0,0 +1 @@ | |||
SRC += tm1638.c |
@ -0,0 +1,319 @@ | |||
/* Copyright 2024 georgsnarbuts | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 2 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include <stdint.h> | |||
#include <stdbool.h> | |||
#include "tm1638.h" | |||
#include "gpio.h" | |||
#include "progmem.h" | |||
#include "wait.h" | |||
#include <stdio.h> | |||
#include "halconf.h" | |||
#include "print.h" | |||
#include <math.h> | |||
#include "kalkulators.h" | |||
#ifndef TM1638_CLK_PIN | |||
# error tm1638: no CLK pin defined! | |||
#endif | |||
#ifndef TM1638_STB_PIN | |||
# error tm1638: no STB pin defined! | |||
#endif | |||
#ifndef TM1638_DIO_PIN | |||
# error tm1638: no DIO pin defined! | |||
#endif | |||
static const unsigned char PROGMEM SevenSeg[] = { | |||
0x00, /* (space) */ | |||
0x86, /* ! */ | |||
0x22, /* " */ | |||
0x7E, /* # */ | |||
0x6D, /* $ */ | |||
0xD2, /* % */ | |||
0x46, /* & */ | |||
0x20, /* ' */ | |||
0x29, /* ( */ | |||
0x0B, /* ) */ | |||
0x21, /* * */ | |||
0x70, /* + */ | |||
0x10, /* , */ | |||
0x40, /* - */ | |||
0x80, /* . */ | |||
0x52, /* / */ | |||
0x3F, /* 0 */ | |||
0x06, /* 1 */ | |||
0x5B, /* 2 */ | |||
0x4F, /* 3 */ | |||
0x66, /* 4 */ | |||
0x6D, /* 5 */ | |||
0x7D, /* 6 */ | |||
0x07, /* 7 */ | |||
0x7F, /* 8 */ | |||
0x6F, /* 9 */ | |||
0x09, /* : */ | |||
0x0D, /* ; */ | |||
0x61, /* < */ | |||
0x48, /* = */ | |||
0x43, /* > */ | |||
0xD3, /* ? */ | |||
0x5F, /* @ */ | |||
0x77, /* A */ | |||
0x7C, /* B */ | |||
0x39, /* C */ | |||
0x5E, /* D */ | |||
0x79, /* E */ | |||
0x71, /* F */ | |||
0x3D, /* G */ | |||
0x76, /* H */ | |||
0x30, /* I */ | |||
0x1E, /* J */ | |||
0x75, /* K */ | |||
0x38, /* L */ | |||
0x15, /* M */ | |||
0x37, /* N */ | |||
0x3F, /* O */ | |||
0x73, /* P */ | |||
0x6B, /* Q */ | |||
0x33, /* R */ | |||
0x6D, /* S */ | |||
0x78, /* T */ | |||
0x3E, /* U */ | |||
0x3E, /* V */ | |||
0x2A, /* W */ | |||
0x76, /* X */ | |||
0x6E, /* Y */ | |||
0x5B, /* Z */ | |||
0x39, /* [ */ | |||
0x64, /* \ */ | |||
0x0F, /* ] */ | |||
0x23, /* ^ */ | |||
0x08, /* _ */ | |||
0x02, /* ` */ | |||
0x5F, /* a */ | |||
0x7C, /* b */ | |||
0x58, /* c */ | |||
0x5E, /* d */ | |||
0x7B, /* e */ | |||
0x71, /* f */ | |||
0x6F, /* g */ | |||
0x74, /* h */ | |||
0x10, /* i */ | |||
0x0C, /* j */ | |||
0x75, /* k */ | |||
0x30, /* l */ | |||
0x14, /* m */ | |||
0x54, /* n */ | |||
0x5C, /* o */ | |||
0x73, /* p */ | |||
0x67, /* q */ | |||
0x50, /* r */ | |||
0x6D, /* s */ | |||
0x78, /* t */ | |||
0x1C, /* u */ | |||
0x1C, /* v */ | |||
0x14, /* w */ | |||
0x76, /* x */ | |||
0x6E, /* y */ | |||
0x5B, /* z */ | |||
0x46, /* { */ | |||
0x30, /* | */ | |||
0x70, /* } */ | |||
0x01, /* ~ */ | |||
}; | |||
const unsigned char *pFontSevenSegptr = SevenSeg; /**< Pointer to the seven segment font data table */ | |||
void shiftOut(uint8_t val) { | |||
uint8_t i; | |||
for (i = 0; i < 8; i++) { | |||
writePin(TM1638_DIO_PIN, !!(val & (1 << i))); | |||
writePinHigh(TM1638_CLK_PIN); | |||
writePinLow(TM1638_CLK_PIN); | |||
} | |||
} | |||
void sendData(uint8_t data) { | |||
shiftOut(data); | |||
} | |||
void sendCommand(uint8_t value) { | |||
writePinLow(TM1638_STB_PIN); | |||
sendData(value); | |||
writePinHigh(TM1638_STB_PIN); | |||
} | |||
void reset() { | |||
sendCommand(TM_WRITE_INC); | |||
writePinLow(TM1638_STB_PIN); | |||
sendData(TM_SEG_ADR); | |||
for (uint8_t position = 0; position < 16; position++) { | |||
sendData(0x00); | |||
} | |||
writePinHigh(TM1638_STB_PIN); | |||
} | |||
void brightness(uint8_t brightness) { | |||
uint8_t value = 0; | |||
value = TM_BRIGHT_ADR + (TM_BRIGHT_MASK & brightness); | |||
sendCommand(value); | |||
} | |||
void displayBegin() { | |||
sendCommand(TM_ACTIVATE); | |||
brightness(TM_DEFAULT_BRIGHTNESS); | |||
reset(); | |||
} | |||
void display7Seg(uint8_t position, uint8_t value) { | |||
sendCommand(TM_WRITE_LOC); | |||
writePinLow(TM1638_STB_PIN); | |||
sendData(TM_SEG_ADR + (position << 1)); | |||
sendData(value); | |||
writePinHigh(TM1638_STB_PIN); | |||
} | |||
void displayASCIIwDot(uint8_t position, uint8_t ascii) { | |||
// add 128 or 0x080 0b1000000 to turn on decimal point/dot in seven seg | |||
display7Seg(position, pgm_read_byte(pFontSevenSegptr + (ascii - TM_ASCII_OFFSET)) + TM_DOT_MASK_DEC); | |||
} | |||
void displayASCII(uint8_t position, uint8_t ascii) { | |||
display7Seg(position, pgm_read_byte(pFontSevenSegptr + (ascii - TM_ASCII_OFFSET))); | |||
} | |||
void displayText(const char *text) { | |||
char c, pos; | |||
pos = 0; | |||
while ((c = (*text++)) && pos < TM_DISPLAY_SIZE) { | |||
if (*text == '.' && c != '.') { | |||
displayASCIIwDot(pos++, c); | |||
text++; | |||
} else { | |||
displayASCII(pos++, c); | |||
} | |||
} | |||
} | |||
void displayTextRight(const char *text) { | |||
// Calculate the starting position to display the text on the far right | |||
uint8_t startPos = TM_DISPLAY_SIZE - strlen(text); | |||
// Ensure startPos is not negative | |||
startPos = startPos < 0 ? 0 : startPos; | |||
char c; | |||
while ((c = (*text++)) && startPos < TM_DISPLAY_SIZE) { | |||
if (*text == '.' && c != '.') { | |||
displayASCIIwDot((startPos++), c); | |||
text++; | |||
} else { | |||
displayASCII(startPos++, c); | |||
} | |||
} | |||
} | |||
void displayTextRightFloat(const char *text) { | |||
// Calculate the starting position to display the text on the far right | |||
// if there is "." in the text | |||
uint8_t startPos = TM_DISPLAY_SIZE - strlen(text) + 1; | |||
// Ensure startPos is not negative | |||
startPos = startPos < 0 ? 0 : startPos; | |||
char c; | |||
while ((c = (*text++)) && startPos < TM_DISPLAY_SIZE) { | |||
if (*text == '.' && c != '.') { | |||
displayASCIIwDot((startPos++), c); | |||
text++; | |||
} else { | |||
displayASCII(startPos++, c); | |||
} | |||
} | |||
} | |||
void displayIntNum(unsigned long number, bool leadingZeros) { | |||
char values[TM_DISPLAY_SIZE + 1]; | |||
char TextDisplay[5] = "%"; | |||
char TextLeft[3] = "ld"; | |||
char TextRight[4] = "8ld"; | |||
if (strcmp(TextAlignment, "TMAlignTextLeft") == 0) { | |||
strcat(TextDisplay, TextLeft); // %ld | |||
} else if (strcmp(TextAlignment, "TMAlignTextRight") == 0) { | |||
strcat(TextDisplay, TextRight); // %8ld | |||
} | |||
snprintf(values, TM_DISPLAY_SIZE + 1, leadingZeros ? "%08ld" : TextDisplay, number); | |||
displayText(values); | |||
} | |||
void displayHex(uint8_t position, uint8_t hex) { | |||
uint8_t offset = 0; | |||
hex = hex % 16; | |||
if (hex <= 9) { | |||
display7Seg(position, pgm_read_byte(pFontSevenSegptr + (hex + TM_HEX_OFFSET))); | |||
// 16 is offset in reduced ASCII table for number 0 | |||
} else if ((hex >= 10) && (hex <= 15)) { | |||
// Calculate offset in reduced ASCII table for AbCDeF | |||
switch (hex) { | |||
case 10: | |||
offset = 'A'; | |||
break; | |||
case 11: | |||
offset = 'b'; | |||
break; | |||
case 12: | |||
offset = 'C'; | |||
break; | |||
case 13: | |||
offset = 'd'; | |||
break; | |||
case 14: | |||
offset = 'E'; | |||
break; | |||
case 15: | |||
offset = 'F'; | |||
break; | |||
} | |||
display7Seg(position, pgm_read_byte(pFontSevenSegptr + (offset - TM_ASCII_OFFSET))); | |||
} | |||
} | |||
void DisplayDecNumNibble(uint16_t numberUpper, uint16_t numberLower, bool leadingZeros) { | |||
char valuesUpper[TM_DISPLAY_SIZE + 1]; | |||
char valuesLower[TM_DISPLAY_SIZE / 2 + 1]; | |||
char TextDisplay[5] = "%"; | |||
char TextLeft[4] = "-4d"; | |||
char TextRight[3] = "4d"; | |||
if (strcmp(TextAlignment, "TMAlignTextLeft") == 0) { | |||
strcat(TextDisplay, TextLeft); // %-4d | |||
} else if (strcmp(TextAlignment, "TMAlignTextRight") == 0) { | |||
strcat(TextDisplay, TextRight); // %4d | |||
} | |||
snprintf(valuesUpper, TM_DISPLAY_SIZE / 2 + 1, leadingZeros ? "%04d" : TextDisplay, numberUpper); | |||
snprintf(valuesLower, TM_DISPLAY_SIZE / 2 + 1, leadingZeros ? "%04d" : TextDisplay, numberLower); | |||
strcat(valuesUpper, valuesLower); | |||
displayText(valuesUpper); | |||
}; |
@ -0,0 +1,56 @@ | |||
/* Copyright 2024 georgsnarbuts | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 2 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#pragma once | |||
extern const unsigned char * pFontSevenSegptr; | |||
#define TextAlignment "TMAlignTextRight" | |||
#define TM_ACTIVATE 0x8F /**< Start up device */ | |||
#define TM_BUTTONS_MODE 0x42 /**< Buttons mode */ | |||
#define TM_WRITE_LOC 0x44 /**< Write to a memory location */ | |||
#define TM_WRITE_INC 0x40 /**< Incremental write */ | |||
#define TM_SEG_ADR 0xC0 /**< leftmost segment Address C0 C2 C4 C6 C8 CA CC CE */ | |||
#define TM_LEDS_ADR 0xC1 /**< Leftmost LED address C1 C3 C5 C7 C9 CB CD CF */ | |||
#define TM_BRIGHT_ADR 0x88 /**< Brightness address */ | |||
#define TM_BRIGHT_MASK 0x07 /**< Brightness mask */ | |||
#define TM_DEFAULT_BRIGHTNESS 0x02 /**< Brightness can be 0x00 to 0x07 , 0x00 is least bright */ | |||
#define TM_DISPLAY_SIZE 8 /**< Size of display in digits */ | |||
#define TM_ASCII_OFFSET 32 /**< ASCII table offset to jump over first missing 32 chars */ | |||
#define TM_HEX_OFFSET 16 /**< ASCII table offset to reach the number position */ | |||
#define TM_DOT_MASK_DEC 128 /**< 0x80 Mask to switch on decimal point in seven segement */ | |||
#define TM_RED_LED 0x02 /**< Turn LED red color Model 3 only */ | |||
#define TM_GREEN_LED 0x01 /**< Turn LED green color Model 3 only */ | |||
#define TM_OFF_LED 0x00 /**< Switch off LED */ | |||
void displayBegin(void); | |||
void reset(void); | |||
void brightness(uint8_t brightness); | |||
void sendCommand(uint8_t value); | |||
void sendData(uint8_t data); | |||
void shiftOut(uint8_t val); | |||
void display7Seg(uint8_t position, uint8_t value); | |||
void displayASCIIwDot(uint8_t position, uint8_t ascii); | |||
void displayASCII(uint8_t position, uint8_t ascii); | |||
void displayText(const char *text); | |||
void displayTextRight(const char *text); | |||
void displayTextRightFloat(const char *text); | |||
void displayIntNum(unsigned long number, bool leadingZeros); | |||
void displayHex(uint8_t position, uint8_t hex); | |||
void DisplayDecNumNibble(uint16_t numberUpper, uint16_t numberLower, bool leadingZeros); |