add keyboard

This commit is contained in:
Kizarm 2024-04-23 14:16:07 +02:00
parent dfcba8ee41
commit f97a7d9ce5
8 changed files with 270 additions and 0 deletions

54
keyboard/Makefile Normal file
View file

@ -0,0 +1,54 @@
# ch32v003
TARGET?= ch32v003
TOOL ?= gcc
PRJ = example
VPATH = . ./$(TARGET)
BLD = ./build/
DFLAGS = -d
LFLAGS = -g
LDLIBS =
BFLAGS = --strip-unneeded
CFLAGS = -MMD -Wall -ggdb -fno-exceptions -ffunction-sections -fdata-sections
CFLAGS+= -I. -I./common -I./$(TARGET) -I/usr/include/newlib
DEL = rm -f
# zdrojaky
OBJS = main.o keyboard.o
OBJS += usart.o pcmdma.o sin.o
include $(TARGET)/$(TOOL).mk
BOBJS = $(addprefix $(BLD),$(OBJS))
all: $(BLD) $(PRJ).elf
# ... atd.
-include $(BLD)*.d
# linker
$(PRJ).elf: $(BOBJS)
-@echo [LD $(TOOL),$(TARGET)] $@
@$(LD) $(LFLAGS) -o $(PRJ).elf $(BOBJS) $(LDLIBS)
-@echo "size:"
@$(SIZE) $(PRJ).elf
-@echo "listing:"
$(DUMP) $(DFLAGS) $(PRJ).elf > $(PRJ).lst
-@echo "OK."
$(COPY) $(BFLAGS) -O binary $(PRJ).elf $(PRJ).bin
# preloz co je potreba
$(BLD)%.o: %.c
-@echo [CC $(TOOL),$(TARGET)] $@
@$(CC) -c $(CFLAGS) $< -o $@
$(BLD)%.o: %.cpp
-@echo [CX $(TOOL),$(TARGET)] $@
@$(CXX) -std=c++17 -fno-rtti -c $(CFLAGS) $< -o $@
$(BLD):
mkdir $(BLD)
sin.c: sin.py
./sin.py
flash: $(PRJ).elf
minichlink -w $(PRJ).bin flash -b
# vycisti
clean:
$(DEL) $(BLD)* *.lst *.bin *.elf *.map sin.c *~
.PHONY: all clean

1
keyboard/ch32v003 Symbolic link
View file

@ -0,0 +1 @@
../ch32v003/

1
keyboard/common Symbolic link
View file

@ -0,0 +1 @@
../common/

22
keyboard/generator.h Normal file
View file

@ -0,0 +1,22 @@
#ifndef GENERATOR_H
#define GENERATOR_H
#include "oneway.h"
extern "C" const int16_t sin_tab[];
/* Něco jako DDS, přesná frekvence není řešena (závisí na TIM1). */
class Generator {
unsigned base, freq;
public:
explicit Generator () noexcept : base(0u), freq (0u) {};
int16_t step () {
const int16_t r = sin_tab [base >> 24];
base += freq;
return r;
}
void set (const unsigned f) {
if (!f) base = 0u;
freq = f;
}
protected:
};
#endif // GENERATOR_H

92
keyboard/keyboard.cpp Normal file
View file

@ -0,0 +1,92 @@
#include "keyboard.h"
#include "usart.h"
extern "C" {
extern const unsigned dtmf_low_tab [];
extern const unsigned dtmf_hi__tab [];
};
static const uint32_t col_table [] = {
0x0002'001Cu,
0x0004'001Au,
0x0008'0016u,
0x0010'000Eu,
};
static const char * out_table [] = {
"*741", "0852", "#963"
};
unsigned int Keyboard::Send(uint16_t * const ptr, const unsigned int len) {
for (unsigned n=0u; n<len; n++) ptr [n] = 1000 + gl.step() + gh.step();
const unsigned index = (col_cnt >> 1) & 3u;
if ((col_cnt & 1) == 0u) { // sudý cnt zapíše 0 na port (řádek)
GPIOC.BSHR.R = col_table [ index ];
} else { // lichý, následný přečte sloupec
const uint32_t row = (~GPIOC.INDR.R >> 5) & 0x7u;
if (status [index] != row) { // změna - je potřeba něco udělat
if (row) led << false;
else led << true;
char c = '\0';
gl.set(dtmf_low_tab [index]);
if (row & 1u) { // ono to row je vlastně sloupec,
c = out_table [2] [index]; // nechce se mi to přepisovat
gh.set (dtmf_hi__tab [2]);
} else if (row & 2u) {
c = out_table [0] [index];
gh.set (dtmf_hi__tab [0]);
} else if (row & 4u) {
c = out_table [1] [index];
gh.set (dtmf_hi__tab [1]);
} else { // konec stisku tlačítka
gh.set(0u); gl.set(0u); // ticho
}
if (c) out(c);
status [index] = row;
}
}
col_cnt += 1u;
return len;
}
void Keyboard::init() {
for (unsigned n=0u; n<4u; n++) status [n] = 0u;
led << true;
RCC.APB2PCENR.B.IOPCEN = SET;
GPIOC.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto {
r.B.MODE1 = 1u; // Output mode, maximum speed 10MHz
r.B.CNF1 = 1u; // Universal open-drain output mode
r.B.MODE2 = 1u; // Output mode, maximum speed 10MHz
r.B.CNF2 = 1u; // Universal open-drain output mode
r.B.MODE3 = 1u; // Output mode, maximum speed 10MHz
r.B.CNF3 = 1u; // Universal open-drain output mode
r.B.MODE4 = 1u; // Output mode, maximum speed 10MHz
r.B.CNF4 = 1u; // Universal open-drain output mode
r.B.MODE5 = 0u; // Input mode
r.B.CNF5 = 2u; // With pull-up and pull-down mode
r.B.MODE6 = 0u; // Input mode
r.B.CNF6 = 2u; // With pull-up and pull-down mode
r.B.MODE7 = 0u; // Input mode
r.B.CNF7 = 2u; // With pull-up and pull-down mode
return r.R;
});
GPIOC.OUTDR.R |= 0xE0u; // pull-up vstupů
}
void Keyboard::out(const char c) {
usart.Down (&c, 1u);
if (c == '#') {
usart.Down ("\r\n", 2u);
pas_num = BEGIN;
pas_cnt = 0u;
relay << false;
return;
}
if (c == password [pas_cnt] and pas_num == BEGIN) {
pas_cnt += 1u;
if (password [pas_cnt] == '\0') { // konec
pas_num = END;
pas_cnt = 0u;
relay << true;
}
} else {
pas_num = BEGIN;
pas_cnt = 0u;
relay << false;
}
}

29
keyboard/keyboard.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef KEYBOARD_H
#define KEYBOARD_H
#include "gpio.h"
#include "oneway.h"
#include "generator.h"
class Usart;
class Keyboard : public OneWay {
enum PASSENUM { BEGIN = 0, END };
Usart & usart;
GpioClass led, relay;
Generator gl,gh;
unsigned col_cnt, pas_cnt;
const char * password;
PASSENUM pas_num;
uint8_t status [4];
public:
explicit Keyboard (Usart & serial) noexcept : OneWay(), usart (serial), led (GPIOD, 4u), relay (GPIOD, 3u),
gl (), gh (), col_cnt (0u), pas_cnt (0u), password (nullptr), pas_num (BEGIN) {
init();
}
void setPassword (const char * const pwd) { password = pwd; }
unsigned int Send (uint16_t * const ptr, const unsigned int len) override;
protected:
void init () noexcept;
void out (const char c);
};
#endif // KEYBOARD_H

26
keyboard/main.cpp Normal file
View file

@ -0,0 +1,26 @@
#include "usart.h"
#include "pcmdma.h"
#include "keyboard.h"
//////////////////////////////////////
/* Klávesnice Tesla Jihlava je připojena
* k portu C, bity 1,2,3,4 řádky, 5,6,7
* sloupce. Nejsou potřeba další součástky.
*
* Generuje DTMF (PWM PD0,PD2) a posílá
* znaky na USART (PD5, PD6).
* Může to fungovat např. jako el. zámek.
* Indikační LED je na PD4, relé na PD3.
* */
//////////////////////////////////////
static Usart usart (115200u);
static Keyboard kbd (usart);
static PcmDma pcm;
//////////////////////////////////////
int main () {
pcm.attach(kbd);
kbd.setPassword("3*1415926");
for (;;) {
// do nothing
}
return 0;
}

45
keyboard/sin.py Executable file
View file

@ -0,0 +1,45 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import math
header = '''/* Generated file */
#include <stdint.h>
const int16_t sin_tab[] = {{{0:s}
}};
'''
def generate():
s = ''
for n in range(0,256):
if (n % 16) == 0:
s += '\n '
a = float(n) * math.pi / 128.0
v = int (round (480.0 * (math.sin (a))));
s += '{0:+6d},'.format(v)
return s
def dtmf():
f0 = 24000.0
mf = math.pow (2.0, 32.0) / f0
dtmf_l = [ 941, 852, 770, 697 ]
dtmf_h = [1209, 1336, 1477, 1633]
s = 'const unsigned dtmf_low_tab [] = {'
for f in dtmf_l:
n = int (f * mf)
s += ' 0x{0:08x},'.format (n)
s += ' };\n'
s += 'const unsigned dtmf_hi__tab [] = {'
for f in dtmf_h:
n = int (f * mf)
s += ' 0x{0:08x},'.format (n)
s += ' };\n'
return s
if __name__ == '__main__':
s = generate()
f = open ('sin.c','w')
f.write(header.format(s))
f.write(dtmf())
f.close()