Compare commits

...

46 Commits

Author SHA1 Message Date
Marc Poulhiès 8713ec559d wip readme 2 years ago
Marc Poulhiès bcd7a985e9 Firmware 2 years ago
Marc Poulhiès 423b316ff5 First compatible firmware 2 years ago
Marc Poulhiès 0f38e479d5 ordered 2 years ago
Marc Poulhiès 8725a1ed80 PCB with silk 2 years ago
Marc Poulhiès d967bade59 image for back silk 2 years ago
Marc Poulhiès 6baf832218 useful res 2 years ago
Marc Poulhiès f8edfc2cfb add image 2 years ago
Marc Poulhiès 3cacac0ee8 clean libraries 2 years ago
Marc Poulhiès 77654b71dd Add more vias to GND, remove level shifter for UART 2 years ago
Marc Poulhiès 6caa42cc20
Update README.md 2 years ago
Marc Poulhiès bb8b11e559 wip: update readme, fix ERC errors 2 years ago
Marc Poulhiès b0f4555fdb fix buffer for RX pin 2 years ago
Marc Poulhiès 9d50a50389 WIP 2 years ago
Marc Poulhiès 086f530c3f change ESD part, better handling mounting hole, remove unused pin on debug connector 2 years ago
Marc Poulhiès 8451c76eec move capacitor for all VDDs 2 years ago
Marc Poulhiès 5a20bfb060 WIP. 2 years ago
Marc Poulhiès f9d9dc5899 wip 2 years ago
Marc Poulhiès b5049c7fdd change LDO, add filter on USB, move capacitors 2 years ago
Marc Poulhiès 2eaf26408f wip 2 years ago
Marc Poulhiès d0b5f47082 wip 2 years ago
Marc Poulhiès 73ade3073e wip 2 years ago
Marc Poulhiès 146a01f0d0 Merge branch 'keyseebee-refactor' into dev-preonic-clone 2 years ago
Marc Poulhiès c9fa378a85 wip 2 years ago
Marc Poulhiès e8fab76406 Merge branch 'keyseebee-refactor' into dev-preonic-clone 2 years ago
Marc Poulhiès 9099ecf1b8 wip 2 years ago
Marc Poulhiès 9844d786f4 Merge branch 'keyseebee-refactor' into dev-preonic-clone 2 years ago
Marc Poulhiès 95bf8033e6 wip 2 years ago
Marc Poulhiès 6b5dcb3207 :Merge branch 'keyseebee-refactor' into dev-preonic-clone 2 years ago
Marc Poulhiès 9fd21824fa wip 2 years ago
Marc Poulhiès 597c7977e4 wip 2 years ago
Marc Poulhiès 096e43b699 wib 2 years ago
Marc Poulhiès bb3c08e2d4 wip 2 years ago
Marc Poulhiès 15bb997ed4 wip 2 years ago
Marc Poulhiès f9497fcde4 wpi 2 years ago
Marc Poulhiès 82281c4410 wip 2 years ago
Marc Poulhiès f81a9a2cc9 wip 2 years ago
Marc Poulhiès d5212073a1 WIP: use more std footprint for MX only 2 years ago
Marc Poulhiès a22c37617a WIP: routing complete 2 years ago
Marc Poulhiès f48ab3c10b WIP DRC and unconnected sw 2 years ago
Marc Poulhiès 6c85b20744 WIP: routing, changed visual layout of diodes 2 years ago
Marc Poulhiès d02d23bb89 WIP routing 2 years ago
Marc Poulhiès f41da44ce0 fix footprind wrt silk 2 years ago
Marc Poulhiès 33a05566cf WIP: some more routing 2 years ago
Marc Poulhiès 9640742967 WIP add lib 2 years ago
Marc Poulhiès 654d0b9f5d WIP for ortho 12x5 2 years ago
  1. 12
      .gitmodules
  2. 1
      LICENSE
  3. 64
      README.md
  4. 152
      firmware/Cargo.lock
  5. 9
      firmware/Cargo.toml
  6. 260
      firmware/src/main.rs
  7. 27
      pcb/gerbers/CHANGELOG.md
  8. BIN
      pcb/gerbers/v0.1/left.zip
  9. 6827
      pcb/gerbers/v0.1/left/left-B.Cu.gbl
  10. 8292
      pcb/gerbers/v0.1/left/left-B.Mask.gbs
  11. 996
      pcb/gerbers/v0.1/left/left-B.SilkS.gbo
  12. 38
      pcb/gerbers/v0.1/left/left-Edge.Cuts.gm1
  13. 8556
      pcb/gerbers/v0.1/left/left-F.Cu.gtl
  14. 4867
      pcb/gerbers/v0.1/left/left-F.Mask.gts
  15. 3190
      pcb/gerbers/v0.1/left/left-F.SilkS.gto
  16. 134
      pcb/gerbers/v0.1/left/left-NPTH.drl
  17. 163
      pcb/gerbers/v0.1/left/left-PTH.drl
  18. BIN
      pcb/gerbers/v0.1/right.zip
  19. 11201
      pcb/gerbers/v0.1/right/right-B.Cu.gbl
  20. 7207
      pcb/gerbers/v0.1/right/right-B.Mask.gbs
  21. 995
      pcb/gerbers/v0.1/right/right-B.SilkS.gbo
  22. 40
      pcb/gerbers/v0.1/right/right-Edge.Cuts.gm1
  23. 12921
      pcb/gerbers/v0.1/right/right-F.Cu.gtl
  24. 5086
      pcb/gerbers/v0.1/right/right-F.Mask.gts
  25. 3158
      pcb/gerbers/v0.1/right/right-F.SilkS.gto
  26. 134
      pcb/gerbers/v0.1/right/right-NPTH.drl
  27. 176
      pcb/gerbers/v0.1/right/right-PTH.drl
  28. 4
      pcb/images/README.md
  29. 89
      pcb/images/rocket.svg
  30. 1
      pcb/kicad/Keebio-Parts.pretty
  31. 25
      pcb/kicad/custom.pretty/CherryMX_Choc_1u.kicad_mod
  32. 1
      pcb/kicad/jmdaly_keyboard_parts.pretty
  33. 1
      pcb/kicad/kbd
  34. 1
      pcb/kicad/keyswitches.pretty
  35. 7
      pcb/kicad/left/fp-lib-table
  36. 1091
      pcb/kicad/left/left.bak
  37. 4788
      pcb/kicad/left/left.kicad_pcb
  38. 4788
      pcb/kicad/left/left.kicad_pcb-bak
  39. 1091
      pcb/kicad/left/left.sch
  40. 286
      pcb/kicad/pouetpouet-images.pretty/pouetpouet-images.kicad_mod
  41. 263
      pcb/kicad/pouetpouet/bac.light.sch
  42. 263
      pcb/kicad/pouetpouet/bac.light.sch-bak
  43. 6
      pcb/kicad/pouetpouet/fp-lib-table
  44. 264
      pcb/kicad/pouetpouet/pouetpouet-cache.lib
  45. 2
      pcb/kicad/pouetpouet/pouetpouet.bak
  46. 14945
      pcb/kicad/pouetpouet/pouetpouet.kicad_pcb
  47. 14948
      pcb/kicad/pouetpouet/pouetpouet.kicad_pcb-bak
  48. 12
      pcb/kicad/pouetpouet/pouetpouet.pro
  49. 2383
      pcb/kicad/pouetpouet/pouetpouet.sch
  50. 2383
      pcb/kicad/pouetpouet/pouetpouet.sch-bak
  51. 7
      pcb/kicad/right/fp-lib-table
  52. 306
      pcb/kicad/right/right-cache.lib
  53. 5662
      pcb/kicad/right/right.kicad_pcb
  54. 5662
      pcb/kicad/right/right.kicad_pcb-bak
  55. 33
      pcb/kicad/right/right.pro
  56. 1082
      pcb/kicad/right/right.sch

12
.gitmodules vendored

@ -1,9 +1,9 @@
[submodule "pcb/kicad/kicad-footprints"]
path = pcb/kicad/kicad-footprints
url = https://github.com/KiCad/kicad-footprints
[submodule "pcb/kicad/Keebio-Parts.pretty"]
path = pcb/kicad/Keebio-Parts.pretty
url = https://github.com/keebio/Keebio-Parts.pretty
[submodule "pcb/kicad/kbd"]
path = pcb/kicad/kbd
url = https://github.com/foostan/kbd.git
[submodule "pcb/kicad/keyswitches.pretty"]
path = pcb/kicad/keyswitches.pretty
url = https://github.com/daprice/keyswitches.pretty
[submodule "pcb/kicad/jmdaly_keyboard_parts.pretty"]
path = pcb/kicad/jmdaly_keyboard_parts.pretty
url = https://gitlab.com/jmdaly/jmdaly_keyboard_parts.pretty.git

1
LICENSE

@ -1,6 +1,7 @@
MIT License
Copyright (c) 2020 Guillaume P.
Copyright (c) 2020 Marc Poulhiès
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

64
README.md

@ -1,35 +1,47 @@
# KeySeeBee
![KeySeeBee](images/keyseebee.jpg)
KeySeeBee is a split ergo keyboard. It is only 2 PCB (so the name)
with (almost) only SMD components on it. It's only a keyboard, no LED,
no display, nothing more than keys and USB.
# PouetPouet
The firmware is [Keyberon](https://github.com/TeXitoi/keyberon), a
pure rust firmware.
## Features
* 44 keys, using Cherry MX or Kailh choc switches, only 1U keycaps;
* USB-C connector on the 2 sides;
* TRRS cable for connecting the 2 halves (for power and UART communication between the 2 halves);
* 2 STM32F072 MCU, with hardware USB DFU bootloader and crystal less USB;
* Only onboard SMD component (except for the switches and TRRS connector).
* 60 keys, using Cherry MX switches, only 1U keycaps;
* USB-C connector;
* 1 STM32F072 MCU, with hardware USB DFU bootloader;
* Only onboard SMD component (except for the switches).
## Inspiration
* [Plaid](https://github.com/hsgw/plaid) for "show the components"
* [GergoPlex](https://www.gboards.ca/product/gergoplex) for "just a keyboard" and "only a PCB with SMD components"
* [Lily58](https://github.com/kata0510/Lily58) for the thumb cluster
* [Kyria](https://blog.splitkb.com/blog/introducing-the-kyria) for
"don't be affraid of pinky stagger"
## Gallery
![From above with one side upside down](images/above-with-back.jpg)
![Side view](images/side-view.jpg)
* [Keyseebee](https://github.com/TeXitoi/keyseebee) for being the «I will change it quickly and have something ready in an hour» base project (even if I ended up redoing most of the hardware design).
* [Steamvan](https://github.com/jmdaly/steamvan) for some KiCad design ideas;
* [help-14](https://github.com/help-14/mechanical-keyboard) for making a nice list of existing keyboard;
* [Masterzen](http://www.masterzen.fr/2020/05/03/designing-a-keyboard-part-1/) and many others for writing online tutorials for newbies like me.
## Usefull resources
* [Mechanical Keyboard](https://github.com/help-14/mechanical-keyboard) is a list of DIY keyboards
* [Awesome Mechanical Keyboard](https://github.com/BenRoe/awesome-mechanical-keyboard) is another [https://github.com/topics/awesome](«awesome») list
## Bill Of Materials
|Item |Package|Qty|Remarks |Price |
|--------------------------------------------------------------------------|-------|--:|---------------------------------------|-----:|
| PCB | | 3 | aisler | |
| 100 nF | 0805 | 5 | magic match aisler | 0 |
| PRTR5V0U2X,215 | sot-143| 1 | | 0.43 |
| 4.7 uF | 0805 | 2 | | 0 |
| 470 Ohm | 0805 | 1 | magic match aisler | 0 |
| TLV70233DBVR | sot-23| 1 | magic match aisler | 0.37 |
| 74LVC1G34GW,125 | | 1 | magic match aisler | 0.28 |
| 0805L050WR (500mA Polyfuse) | 0805 | 1 | magic match aisler | 1.91 |
| RS282G05A3SMRT (micro switch) | | 2 | magic match aisler | 1.26 |
| 100nF | 0805 | 2 | magic match aisler | 0 |
| 5.1 kOhm | 0805 | 3 | magic match aisler | 0 |
| 0805L050WR (500mA Polyfuse) | 0805 | 1 | magic match aisler | 0 |
| 1N4148WS-7-F | sod-323 | 60| | |
| WS2812B | | 10| | |
| USB TypeC HRO Receptacle | | 1 | | |
| Gateron Switch | | 60| | |
| Keycaps | | 60| | |
## Compiling and flashing
@ -47,19 +59,19 @@ Compile:
```shell
cd firmware
cargo objcopy --bin keyseebee --release -- -O binary keyseebee.bin
cargo objcopy --bin pouetpouet --release -- -O binary pouetpouet.bin
```
To flash using dfu-util, first put the board in dfu mode by pressing
BOOT, pressing and releasing RESET and releasing BOOT. Then:
```shell
dfu-util -d 0483:df11 -a 0 -s 0x08000000:leave -D keyseebee.bin
dfu-util -d 0483:df11 -a 0 -s 0x08000000:leave -D pouetpouet.bin
```
The fist time, if the write fail, your flash might be protected. To
unprotect:
```shell
dfu-util -d 0483:df11 -a 0 -s 0x08000000:force:unprotect -D keyseebee.bin
dfu-util -d 0483:df11 -a 0 -s 0x08000000:force:unprotect -D pouetpouet.bin
```

152
firmware/Cargo.lock generated

@ -17,20 +17,21 @@ checksum = "f0ffd3d69bd89910509a5d31d1f1353f38ccffdd116dd0099bbd6627f7bd8ad8"
[[package]]
name = "as-slice"
version = "0.1.3"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37dfb65bc03b2bc85ee827004f14a6817e04160e3b1a28931986a666a9290e70"
checksum = "bb4d1c23475b74e3672afa8c2be22040b8b7783ad9b461021144ed10a46bb0e6"
dependencies = [
"generic-array 0.12.3",
"generic-array 0.13.2",
"generic-array 0.14.4",
"stable_deref_trait",
]
[[package]]
name = "autocfg"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bare-metal"
@ -47,6 +48,12 @@ version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
[[package]]
name = "bytemuck"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41aa2ec95ca3b5c54cf73c91acf06d24f4495d5f1b1c12506ae3483d646177ac"
[[package]]
name = "byteorder"
version = "1.3.4"
@ -64,9 +71,9 @@ dependencies = [
[[package]]
name = "cortex-m"
version = "0.6.3"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2be99930c99669a74d986f7fd2162085498b322e6daae8ef63a97cc9ac1dc73c"
checksum = "88cdafeafba636c00c467ded7f1587210725a1adfab0c24028a7844b87738263"
dependencies = [
"aligned",
"bare-metal",
@ -76,9 +83,9 @@ dependencies = [
[[package]]
name = "cortex-m-rt"
version = "0.6.12"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00d518da72bba39496024b62607c1d8e37bcece44b2536664f1132a73a499a28"
checksum = "980c9d0233a909f355ed297ef122f257942de5e0a2cb1c39f60684b65bcb90fb"
dependencies = [
"cortex-m-rt-macros",
"r0",
@ -97,9 +104,9 @@ dependencies = [
[[package]]
name = "cortex-m-rtic"
version = "0.5.3"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cd388b154c7e7d212c5af7541ee1f174f29ccb0c22e9117f8d13a5aad233b6"
checksum = "b30efcb6b7920d9016182c485687f0012487032a14c415d2fce6e9862ef8260e"
dependencies = [
"cortex-m",
"cortex-m-rt",
@ -111,9 +118,9 @@ dependencies = [
[[package]]
name = "cortex-m-rtic-macros"
version = "0.5.0"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29e29e01b3ec80d59bfd96aaf94d04008bebfde3ab7016e12bfbd6c0b466d22a"
checksum = "9a1a6a4c9550373038c0e21a78d44d529bd697c25bbf6b8004bddc6e63b119c7"
dependencies = [
"proc-macro2",
"quote",
@ -123,9 +130,9 @@ dependencies = [
[[package]]
name = "either"
version = "1.5.3"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "embedded-hal"
@ -155,6 +162,16 @@ dependencies = [
"typenum",
]
[[package]]
name = "generic-array"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "hash32"
version = "0.1.1"
@ -166,18 +183,15 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.8.1"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34f595585f103464d8d2f6e9864682d74c1601fed5e07d62b1c9058dba8246fb"
dependencies = [
"autocfg",
]
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
[[package]]
name = "heapless"
version = "0.5.5"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73a8a2391a3bc70b31f60e7a90daa5755a360559c0b6b9c5cfc0fee482362dc0"
checksum = "74911a68a1658cfcfb61bc0ccfbd536e3b6e906f8c2f7883ee50157e3e2184f1"
dependencies = [
"as-slice",
"generic-array 0.13.2",
@ -187,9 +201,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "1.5.0"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b88cd59ee5f71fea89a62248fc8f387d44400cefe05ef548466d61ced9029a7"
checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2"
dependencies = [
"autocfg",
"hashbrown",
@ -197,8 +211,8 @@ dependencies = [
[[package]]
name = "keyberon"
version = "0.1.0"
source = "git+https://github.com/TeXitoi/keyberon#1d5ddd00785ea612fe4beccbe2abb4097842facb"
version = "0.1.1"
source = "git+https://github.com/TeXitoi/keyberon#c1fd84fd9a6a55b51c42ccc67d642ac1fdca2e4e"
dependencies = [
"arraydeque",
"either",
@ -208,22 +222,6 @@ dependencies = [
"usb-device",
]
[[package]]
name = "keyseebee"
version = "0.1.0"
dependencies = [
"cortex-m",
"cortex-m-rt",
"cortex-m-rtic",
"embedded-hal",
"generic-array 0.13.2",
"keyberon",
"nb 1.0.0",
"panic-halt",
"stm32f0xx-hal",
"usb-device",
]
[[package]]
name = "nb"
version = "0.1.3"
@ -245,11 +243,29 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"
[[package]]
name = "pouetpouet"
version = "0.1.0"
dependencies = [
"cortex-m",
"cortex-m-rt",
"cortex-m-rtic",
"embedded-hal",
"generic-array 0.13.2",
"keyberon",
"nb 1.0.0",
"panic-halt",
"smart-leds",
"stm32f0xx-hal",
"usb-device",
"ws2812-spi",
]
[[package]]
name = "proc-macro2"
version = "1.0.19"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
dependencies = [
"unicode-xid",
]
@ -269,6 +285,15 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f"
[[package]]
name = "rgb"
version = "0.8.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "287f3c3f8236abb92d8b7e36797f19159df4b58f0a658cc3fb6dd3004b1f3bd3"
dependencies = [
"bytemuck",
]
[[package]]
name = "rtic-core"
version = "0.3.0"
@ -310,6 +335,24 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "smart-leds"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38dd45fa275f70b4110eac5f5182611ad384f88bb22b68b9a9c3cafd7015290b"
dependencies = [
"smart-leds-trait",
]
[[package]]
name = "smart-leds-trait"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebf6d833fa93f16a1c1874e62c2aebe8567e5bdd436d59bf543ed258b6f7a8e3"
dependencies = [
"rgb",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
@ -341,9 +384,7 @@ dependencies = [
[[package]]
name = "stm32f0xx-hal"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "212a649a93c47b422e05dfab72dd45ef24b226d826654f393caeef729e110582"
version = "0.17.1"
dependencies = [
"bare-metal",
"cast",
@ -357,9 +398,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.37"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "239f255b9e3429350f188c27b807fc9920a15eb9145230ff1a7d054c08fec319"
checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac"
dependencies = [
"proc-macro2",
"quote",
@ -380,9 +421,9 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "usb-device"
version = "0.2.5"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e5e2b9ba23f0d9ef7a34e498b6581c9d67944a1916542bfc7238bf1dc0d6acd"
checksum = "849eed9b4dc61a1f17ba1d7a5078ceb095b9410caa38a506eb281ed5eff12fbd"
[[package]]
name = "vcell"
@ -410,3 +451,14 @@ checksum = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286"
dependencies = [
"vcell",
]
[[package]]
name = "ws2812-spi"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6c2ba0d6c0ea9c117487411e93dc5dacaafc2c17698677a03d1c67901d4c70a"
dependencies = [
"embedded-hal",
"nb 0.1.3",
"smart-leds-trait",
]

9
firmware/Cargo.toml

@ -1,11 +1,12 @@
[package]
name = "keyseebee"
name = "pouetpouet"
version = "0.1.0"
authors = ["Guillaume Pinot <texitoi@texitoi.eu>"]
authors = ["Marc Poulhiès <dkm@kataplop.net>", "Guillaume Pinot <texitoi@texitoi.eu>"]
edition = "2018"
[dependencies]
stm32f0xx-hal = { version = "0.17.0", features = ["rt", "stm32f072", "stm32-usbd"] }
stm32f0xx-hal = { path = "../../rust-embedded/stm32f0xx-hal/", features = ["rt", "stm32f072", "stm32-usbd"] }
##{ version = "0.17.0", features = ["rt", "stm32f072", "stm32-usbd"] }
cortex-m = "0.6"
cortex-m-rt = { version = "0.6.10", features = ["device"] }
panic-halt = "0.2.0"
@ -15,6 +16,8 @@ generic-array = "0.13"
embedded-hal = "0.2"
usb-device = "0.2.0"
nb = "1.0.0"
ws2812-spi = "0.3.0"
smart-leds = "0.3.0"
[profile.release]
lto = true

260
firmware/src/main.rs

@ -4,14 +4,26 @@
// set the panic handler
use panic_halt as _;
extern crate smart_leds;
extern crate ws2812_spi;
use smart_leds::{brightness, colors, SmartLedsWrite, RGB8};
use ws2812_spi as ws2812;
use core::convert::Infallible;
use embedded_hal::digital::v2::{InputPin, OutputPin};
use generic_array::typenum::{U4, U6};
use hal::gpio::{gpioa, gpiob, Floating, Input, Output, PullUp, PushPull};
use generic_array::typenum::{U12, U5};
use hal::gpio::{gpioa, gpiob, Alternate, Input, Output, PullUp, PushPull, AF0};
use hal::prelude::*;
use hal::serial;
use embedded_hal::spi::FullDuplex;
use hal::usb;
use hal::{stm32, timers};
use hal::{
spi::{EightBit, Mode, Phase, Polarity, Spi},
stm32, timers,
};
use keyberon::action::{k, l, m, Action, Action::*};
use keyberon::debounce::Debouncer;
use keyberon::impl_heterogenous_array;
@ -19,15 +31,28 @@ use keyberon::key_code::KbHidReport;
use keyberon::key_code::KeyCode::*;
use keyberon::layout::{Event, Layout};
use keyberon::matrix::{Matrix, PressedKeys};
use nb::block;
use rtic::app;
use stm32f0xx_hal as hal;
use usb_device::bus::UsbBusAllocator;
use usb_device::class::UsbClass as _;
use usb_device::device::UsbDeviceState;
type UsbClass = keyberon::Class<'static, usb::UsbBusType, ()>;
type UsbDevice = keyberon::Device<'static, usb::UsbBusType>;
type UsbClass = keyberon::Class<
'static,
usb::UsbBusType,
Leds<
Spi<
stm32::SPI1,
gpioa::PA5<Alternate<AF0>>,
gpioa::PA6<Alternate<AF0>>,
gpioa::PA7<Alternate<AF0>>,
EightBit,
>,
>,
>;
type UsbDevice = usb_device::device::UsbDevice<'static, usb::UsbBusType>;
trait ResultExt<T> {
fn get(self) -> T;
@ -42,18 +67,24 @@ impl<T> ResultExt<T> for Result<T, Infallible> {
}
pub struct Cols(
gpioa::PA15<Input<PullUp>>,
gpiob::PB3<Input<PullUp>>,
gpiob::PB4<Input<PullUp>>,
gpiob::PB5<Input<PullUp>>,
gpiob::PB8<Input<PullUp>>,
gpiob::PB9<Input<PullUp>>,
gpioa::PA0<Input<PullUp>>, // 12
gpioa::PA1<Input<PullUp>>, // 11
gpiob::PB13<Input<PullUp>>, // 10
gpiob::PB12<Input<PullUp>>, // 9
gpiob::PB14<Input<PullUp>>, // 8
gpiob::PB15<Input<PullUp>>, // 7
gpioa::PA15<Input<PullUp>>, // 6
gpiob::PB3<Input<PullUp>>, // 5
gpiob::PB4<Input<PullUp>>, // 4
gpiob::PB5<Input<PullUp>>, // 3
gpiob::PB8<Input<PullUp>>, // 2
gpiob::PB9<Input<PullUp>>, // 1
);
impl_heterogenous_array! {
Cols,
dyn InputPin<Error = Infallible>,
U6,
[0, 1, 2, 3, 4, 5]
U12,
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
}
pub struct Rows(
@ -61,12 +92,13 @@ pub struct Rows(
gpiob::PB1<Output<PushPull>>,
gpiob::PB2<Output<PushPull>>,
gpiob::PB10<Output<PushPull>>,
gpiob::PB11<Output<PushPull>>,
);
impl_heterogenous_array! {
Rows,
dyn OutputPin<Error = Infallible>,
U4,
[0, 1, 2, 3]
U5,
[0, 1, 2, 3, 4]
}
const CUT: Action = m(&[LShift, Delete]);
@ -97,40 +129,73 @@ macro_rules! a {
#[rustfmt::skip]
pub static LAYERS: keyberon::layout::Layers = &[
&[
&[k(Tab), k(Q), k(W), k(E), k(R), k(T), k(Y), k(U), k(I), k(O), k(P), k(LBracket)],
&[k(RBracket),k(A), k(S), k(D), k(F), k(G), k(H), k(J), k(K), k(L), k(SColon),k(Quote) ],
&[k(Equal), k(Z), k(X), k(C), k(V), k(B), k(N), k(M), k(Comma),k(Dot), k(Slash), k(Bslash) ],
&[Trans, Trans,k(LGui),k(LAlt),L1_SP,k(LCtrl),k(RShift),L2_ENTER,k(RAlt),k(BSpace),Trans, Trans ],
], &[
&[Trans, k(Pause),Trans, k(PScreen),Trans, Trans,Trans, Trans, k(Delete),Trans, Trans, Trans ],
&[Trans, Trans, k(NumLock),k(Insert), k(Escape),Trans,k(CapsLock),k(Left),k(Down), k(Up), k(Right),Trans ],
&[k(NonUsBslash),k(Undo), CUT, COPY, PASTE, Trans,Trans, k(Home),k(PgDown),k(PgUp),k(End), Trans ],
&[Trans, Trans, Trans, Trans, Trans, Trans,Trans, Trans, Trans, Trans, Trans, Trans ],
], &[
&[s!(Grave),s!(Kb1),s!(Kb2),s!(Kb3),s!(Kb4),s!(Kb5),s!(Kb6),s!(Kb7),s!(Kb8),s!(Kb9),s!(Kb0),s!(Minus)],
&[ k(Grave), k(Kb1), k(Kb2), k(Kb3), k(Kb4), k(Kb5), k(Kb6), k(Kb7), k(Kb8), k(Kb9), k(Kb0), k(Minus)],
&[a!(Grave),a!(Kb1),a!(Kb2),a!(Kb3),a!(Kb4),a!(Kb5),a!(Kb6),a!(Kb7),a!(Kb8),a!(Kb9),a!(Kb0),a!(Minus)],
&[Trans, Trans, Trans, Trans, CSPACE, Trans, Trans, Trans, Trans, Trans, Trans, Trans ],
&[k(Grave), k(Kb1),k(Kb2),k(Kb3), k(Kb4),k(Kb5), k(Kb6), k(Kb7), k(Kb8), k(Kb9), k(Kb0), k(Minus), k(Space)],
&[k(Q), k(W), k(E), k(R), k(T), k(Tab), k(Y), k(U), k(I), k(O), k(P), k(LBracket)],
&[k(A), k(S), k(D), k(F), k(G), k(BSpace), k(H), k(J), k(K), k(L), k(SColon), k(Quote)],
&[k(Z), k(X), k(C), k(V), k(B), k(Enter), k(N), k(M), k(Comma), k(Dot), k(Slash), k(Bslash) ],
&[k(LCtrl), k(LShift), k(LGui), l(1), k(LAlt), k(Space), k(Delete), k(RAlt), k(Equal), k(RBracket),k(RShift), k(RCtrl)],
], &[
&[k(F1),k(F2),k(F3),k(F4),k(F5),k(F6),k(F7),k(F8),k(F9),k(F10),k(F11),k(F12)],
&[Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans, Trans, Trans ],
&[Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans, Trans, Trans ],
&[Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans,Trans, Trans, Trans ],
&[k(SysReq), k(NumLock), Trans, Trans, Trans, k(Escape), k(Insert), k(PgUp), k(PgDown), Trans, Trans, Trans ],
&[Trans , Trans , Trans, Trans, Trans, Trans, k(Home), k(Up), k(End), Trans, Trans, Trans ],
&[Trans, Trans, Trans, Trans, Trans, Trans, k(Left), k(Down), k(Right), Trans, Trans, Trans ],
&[Trans, Trans, Trans, Trans, Trans, Trans, Trans, Trans, Trans, Trans, Trans, Trans ],
],
];
pub struct Leds<SPI> {
ws: ws2812::Ws2812<SPI>,
leds: [RGB8; 10],
}
impl<SPI, E> keyberon::keyboard::Leds for Leds<SPI>
where
SPI: FullDuplex<u8, Error = E>,
{
fn caps_lock(&mut self, status: bool) {
if status {
self.leds[0] = colors::BLUE;
} else {
self.leds[0] = colors::BLACK;
}
self.ws
.write(brightness(self.leds.iter().cloned(), 10));
}
fn num_lock(&mut self, status: bool) {
if status {
self.leds[1] = colors::GREEN;
} else {
self.leds[1] = colors::BLACK;
}
self.ws
.write(brightness(self.leds.iter().cloned(), 10));
}
fn compose(&mut self, status: bool) {
if status {
self.leds[3] = colors::VIOLET;
} else {
self.leds[3] = colors::BLACK;
}
self.ws
.write(brightness(self.leds.iter().cloned(), 10));
}
}
#[app(device = crate::hal::pac, peripherals = true)]
const APP: () = {
struct Resources {
usb_dev: UsbDevice,
usb_class: UsbClass,
matrix: Matrix<Cols, Rows>,
debouncer: Debouncer<PressedKeys<U4, U6>>,
debouncer: Debouncer<PressedKeys<U5, U12>>,
layout: Layout,
timer: timers::Timer<stm32::TIM3>,
transpose: fn(Event) -> Event,
tx: serial::Tx<hal::pac::USART1>,
rx: serial::Rx<hal::pac::USART1>,
}
#[init]
@ -158,32 +223,61 @@ const APP: () = {
*USB_BUS = Some(usb::UsbBusType::new(usb));
let usb_bus = USB_BUS.as_ref().unwrap();
let usb_class = keyberon::new_class(usb_bus, ());
let usb_dev = keyberon::new_device(usb_bus);
// Handling of ws2812 leds
let mut timer = timers::Timer::tim3(c.device.TIM3, 1.khz(), &mut rcc);
timer.listen(timers::Event::TimeOut);
let pa5 = gpioa.pa5; // sck
let pa6 = gpioa.pa6; // miso
let pa7 = gpioa.pa7; // mosi
let pb12: &gpiob::PB12<Input<Floating>> = &gpiob.pb12;
let is_left = pb12.is_low().get();
let transpose = if is_left {
transpose_left
} else {
transpose_right
// Configure pins for SPI
let (sck, miso, mosi) = cortex_m::interrupt::free(move |cs| {
(
pa5.into_alternate_af0(cs),
pa6.into_alternate_af0(cs),
pa7.into_alternate_af0(cs),
)
});
const MODE: Mode = Mode {
polarity: Polarity::IdleHigh,
phase: Phase::CaptureOnSecondTransition,
};
let spi = Spi::spi1(
c.device.SPI1,
(sck, miso, mosi),
MODE,
3_000_000.hz(),
&mut rcc,
);
let (pa9, pa10) = (gpioa.pa9, gpioa.pa10);
let pins = cortex_m::interrupt::free(move |cs| {
(pa9.into_alternate_af1(cs), pa10.into_alternate_af1(cs))
});
let mut serial = serial::Serial::usart1(c.device.USART1, pins, 38_400.bps(), &mut rcc);
serial.listen(serial::Event::Rxne);
let (tx, rx) = serial.split();
// ws2812
let mut ws = ws2812::Ws2812::new(spi);
let mut leds = Leds {
ws,
leds: [colors::BLACK; 10],
};
leds.ws.write(leds.leds.iter().cloned()).unwrap();
let usb_class = keyberon::new_class(usb_bus, leds);
let usb_dev = keyberon::new_device(usb_bus);
let mut timer = timers::Timer::tim3(c.device.TIM3, 1.khz(), &mut rcc);
timer.listen(timers::Event::TimeOut);
let pa15 = gpioa.pa15;
let pa1 = gpioa.pa1;
let pa0 = gpioa.pa0;
let matrix = cortex_m::interrupt::free(move |cs| {
Matrix::new(
Cols(
pa0.into_pull_up_input(cs),
pa1.into_pull_up_input(cs),
gpiob.pb13.into_pull_up_input(cs),
gpiob.pb12.into_pull_up_input(cs),
gpiob.pb14.into_pull_up_input(cs),
gpiob.pb15.into_pull_up_input(cs),
pa15.into_pull_up_input(cs),
gpiob.pb3.into_pull_up_input(cs),
gpiob.pb4.into_pull_up_input(cs),
@ -196,6 +290,7 @@ const APP: () = {
gpiob.pb1.into_push_pull_output(cs),
gpiob.pb2.into_push_pull_output(cs),
gpiob.pb10.into_push_pull_output(cs),
gpiob.pb11.into_push_pull_output(cs),
),
)
});
@ -207,25 +302,6 @@ const APP: () = {
debouncer: Debouncer::new(PressedKeys::default(), PressedKeys::default(), 5),
matrix: matrix.get(),
layout: Layout::new(LAYERS),
transpose,
tx,
rx,
}
}
#[task(binds = USART1, priority = 5, spawn = [handle_event], resources = [rx])]
fn rx(c: rx::Context) {
static mut BUF: [u8; 4] = [0; 4];
if let Ok(b) = c.resources.rx.read() {
BUF.rotate_left(1);
BUF[3] = b;
if BUF[3] == b'\n' {
if let Ok(event) = de(&BUF[..]) {
c.spawn.handle_event(Some(event)).unwrap();
}
}
}
}
@ -259,20 +335,12 @@ const APP: () = {
binds = TIM3,
priority = 2,
spawn = [handle_event],
resources = [matrix, debouncer, timer, &transpose, tx],
resources = [matrix, debouncer, timer],
)]
fn tick(c: tick::Context) {
c.resources.timer.wait().ok();
for event in c
.resources
.debouncer
.events(c.resources.matrix.get().get())
.map(c.resources.transpose)
{
for &b in &ser(event) {
block!(c.resources.tx.write(b)).get();
}
for event in c.resources.debouncer.events(c.resources.matrix.get().get()) {
c.spawn.handle_event(Some(event)).unwrap();
}
c.spawn.handle_event(None).unwrap();
@ -282,27 +350,3 @@ const APP: () = {
fn CEC_CAN();
}
};
fn transpose_left(e: Event) -> Event {
e
}
fn transpose_right(e: Event) -> Event {
match e {
Event::Press(i, j) => Event::Press(i, 11 - j),
Event::Release(i, j) => Event::Release(i, 11 - j),
}
}
fn de(bytes: &[u8]) -> Result<Event, ()> {
match *bytes {
[b'P', i, j, b'\n'] => Ok(Event::Press(i as usize, j as usize)),
[b'R', i, j, b'\n'] => Ok(Event::Release(i as usize, j as usize)),
_ => Err(()),
}
}
fn ser(e: Event) -> [u8; 4] {
match e {
Event::Press(i, j) => [b'P', i as u8, j as u8, b'\n'],
Event::Release(i, j) => [b'R', i as u8, j as u8, b'\n'],
}
}

27
pcb/gerbers/CHANGELOG.md

@ -1,27 +0,0 @@
# Gerber change log
## v0.2 (Unreleased)
Same as v0.1 with the bugs fixed.
Modifications:
* Fix LDO.
* Fix Diodes.
* Remove references of the MCU and the USB connector on the left to
be consistent with the right.
Not ordered nor tested.
## v0.1 (2020-08-02)
First version. Ordered at JLCPCB. Tested and functional with the
workaround.
This version has the placeholder `JLCJLCJLCJLC` for use with the
option "Remove Order Number -> Specify a location" at JLCPCB.
Bugs:
* LDO is badly wired. Workaround: solder it with a roation of 120°
clockwise.
* Diodes are in the wrong direction. Workaround: solder them in
reverse (line on the diode up).

BIN
pcb/gerbers/v0.1/left.zip

Binary file not shown.

6827
pcb/gerbers/v0.1/left/left-B.Cu.gbl

File diff suppressed because it is too large Load Diff

8292
pcb/gerbers/v0.1/left/left-B.Mask.gbs

File diff suppressed because it is too large Load Diff

996
pcb/gerbers/v0.1/left/left-B.SilkS.gbo

@ -1,996 +0,0 @@
G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,5.0.2+dfsg1-1*
G04 #@! TF.CreationDate,2020-08-02T18:17:46+02:00*
G04 #@! TF.ProjectId,left,6c656674-2e6b-4696-9361-645f70636258,rev?*
G04 #@! TF.SameCoordinates,Original*
G04 #@! TF.FileFunction,Legend,Bot*
G04 #@! TF.FilePolarity,Positive*
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 5.0.2+dfsg1-1) date dim. 02 août 2020 18:17:46 CEST*
%MOMM*%
%LPD*%
G01*
G04 APERTURE LIST*
%ADD10C,0.300000*%
%ADD11C,0.120000*%
%ADD12C,0.150000*%
%ADD13C,2.200000*%
%ADD14C,4.000000*%
%ADD15C,1.900000*%
%ADD16C,1.700000*%
%ADD17O,1.600000X2.000000*%
%ADD18C,0.800000*%
%ADD19R,2.500000X1.000000*%
%ADD20O,1.000000X2.100000*%
%ADD21C,0.650000*%
%ADD22O,1.000000X1.600000*%
G04 APERTURE END LIST*
D10*
X234953571Y-62043571D02*
X235667857Y-62043571D01*
X235739285Y-62757857D01*
X235667857Y-62686428D01*
X235525000Y-62615000D01*
X235167857Y-62615000D01*
X235025000Y-62686428D01*
X234953571Y-62757857D01*
X234882142Y-62900714D01*
X234882142Y-63257857D01*
X234953571Y-63400714D01*
X235025000Y-63472142D01*
X235167857Y-63543571D01*
X235525000Y-63543571D01*
X235667857Y-63472142D01*
X235739285Y-63400714D01*
X234453571Y-62043571D02*
X233953571Y-63543571D01*
X233453571Y-62043571D01*
X235667857Y-66083571D02*
X235667857Y-64583571D01*
X235096428Y-64583571D01*
X234953571Y-64655000D01*
X234882142Y-64726428D01*
X234810714Y-64869285D01*
X234810714Y-65083571D01*
X234882142Y-65226428D01*
X234953571Y-65297857D01*
X235096428Y-65369285D01*
X235667857Y-65369285D01*
X233667857Y-65297857D02*
X233453571Y-65369285D01*
X233382142Y-65440714D01*
X233310714Y-65583571D01*
X233310714Y-65797857D01*
X233382142Y-65940714D01*
X233453571Y-66012142D01*
X233596428Y-66083571D01*
X234167857Y-66083571D01*
X234167857Y-64583571D01*
X233667857Y-64583571D01*
X233525000Y-64655000D01*
X233453571Y-64726428D01*
X233382142Y-64869285D01*
X233382142Y-65012142D01*
X233453571Y-65155000D01*
X233525000Y-65226428D01*
X233667857Y-65297857D01*
X234167857Y-65297857D01*
X232810714Y-64583571D02*
X231810714Y-64583571D01*
X232453571Y-66083571D01*
X235667857Y-68623571D02*
X235667857Y-67123571D01*
X235096428Y-67123571D01*
X234953571Y-67195000D01*
X234882142Y-67266428D01*
X234810714Y-67409285D01*
X234810714Y-67623571D01*
X234882142Y-67766428D01*
X234953571Y-67837857D01*
X235096428Y-67909285D01*
X235667857Y-67909285D01*
X233667857Y-67837857D02*
X233453571Y-67909285D01*
X233382142Y-67980714D01*
X233310714Y-68123571D01*
X233310714Y-68337857D01*
X233382142Y-68480714D01*
X233453571Y-68552142D01*
X233596428Y-68623571D01*
X234167857Y-68623571D01*
X234167857Y-67123571D01*
X233667857Y-67123571D01*
X233525000Y-67195000D01*
X233453571Y-67266428D01*
X233382142Y-67409285D01*
X233382142Y-67552142D01*
X233453571Y-67695000D01*
X233525000Y-67766428D01*
X233667857Y-67837857D01*
X234167857Y-67837857D01*
X232025000Y-67123571D02*
X232310714Y-67123571D01*
X232453571Y-67195000D01*
X232525000Y-67266428D01*
X232667857Y-67480714D01*
X232739285Y-67766428D01*
X232739285Y-68337857D01*
X232667857Y-68480714D01*
X232596428Y-68552142D01*
X232453571Y-68623571D01*
X232167857Y-68623571D01*
X232025000Y-68552142D01*
X231953571Y-68480714D01*
X231882142Y-68337857D01*
X231882142Y-67980714D01*
X231953571Y-67837857D01*
X232025000Y-67766428D01*
X232167857Y-67695000D01*
X232453571Y-67695000D01*
X232596428Y-67766428D01*
X232667857Y-67837857D01*
X232739285Y-67980714D01*
X234882142Y-69735000D02*
X235025000Y-69663571D01*
X235239285Y-69663571D01*
X235453571Y-69735000D01*
X235596428Y-69877857D01*
X235667857Y-70020714D01*
X235739285Y-70306428D01*
X235739285Y-70520714D01*
X235667857Y-70806428D01*
X235596428Y-70949285D01*
X235453571Y-71092142D01*
X235239285Y-71163571D01*
X235096428Y-71163571D01*
X234882142Y-71092142D01*
X234810714Y-71020714D01*
X234810714Y-70520714D01*
X235096428Y-70520714D01*
X234167857Y-71163571D02*
X234167857Y-69663571D01*
X233310714Y-71163571D01*
X233310714Y-69663571D01*
X232596428Y-71163571D02*
X232596428Y-69663571D01*
X232239285Y-69663571D01*
X232025000Y-69735000D01*
X231882142Y-69877857D01*
X231810714Y-70020714D01*
X231739285Y-70306428D01*
X231739285Y-70520714D01*
X231810714Y-70806428D01*
X231882142Y-70949285D01*
X232025000Y-71092142D01*
X232239285Y-71163571D01*
X232596428Y-71163571D01*
X235667857Y-73703571D02*
X235667857Y-72203571D01*
X235096428Y-72203571D01*
X234953571Y-72275000D01*
X234882142Y-72346428D01*
X234810714Y-72489285D01*
X234810714Y-72703571D01*
X234882142Y-72846428D01*
X234953571Y-72917857D01*
X235096428Y-72989285D01*
X235667857Y-72989285D01*
X234239285Y-73275000D02*
X233525000Y-73275000D01*
X234382142Y-73703571D02*
X233882142Y-72203571D01*
X233382142Y-73703571D01*
X233025000Y-72203571D02*
X232025000Y-72203571D01*
X232667857Y-73703571D01*
X235667857Y-76243571D02*
X235667857Y-74743571D01*
X235096428Y-74743571D01*
X234953571Y-74815000D01*
X234882142Y-74886428D01*
X234810714Y-75029285D01*
X234810714Y-75243571D01*
X234882142Y-75386428D01*
X234953571Y-75457857D01*
X235096428Y-75529285D01*
X235667857Y-75529285D01*
X234239285Y-75815000D02*
X233525000Y-75815000D01*
X234382142Y-76243571D02*
X233882142Y-74743571D01*
X233382142Y-76243571D01*
X232239285Y-74743571D02*
X232525000Y-74743571D01*
X232667857Y-74815000D01*
X232739285Y-74886428D01*
X232882142Y-75100714D01*
X232953571Y-75386428D01*
X232953571Y-75957857D01*
X232882142Y-76100714D01*
X232810714Y-76172142D01*
X232667857Y-76243571D01*
X232382142Y-76243571D01*
X232239285Y-76172142D01*
X232167857Y-76100714D01*
X232096428Y-75957857D01*
X232096428Y-75600714D01*
X232167857Y-75457857D01*
X232239285Y-75386428D01*
X232382142Y-75315000D01*
X232667857Y-75315000D01*
X232810714Y-75386428D01*
X232882142Y-75457857D01*
X232953571Y-75600714D01*
X235667857Y-78783571D02*
X235667857Y-77283571D01*
X235096428Y-77283571D01*
X234953571Y-77355000D01*
X234882142Y-77426428D01*
X234810714Y-77569285D01*
X234810714Y-77783571D01*
X234882142Y-77926428D01*
X234953571Y-77997857D01*
X235096428Y-78069285D01*
X235667857Y-78069285D01*
X234239285Y-78355000D02*
X233525000Y-78355000D01*
X234382142Y-78783571D02*
X233882142Y-77283571D01*
X233382142Y-78783571D01*
X232167857Y-77283571D02*
X232882142Y-77283571D01*
X232953571Y-77997857D01*
X232882142Y-77926428D01*
X232739285Y-77855000D01*
X232382142Y-77855000D01*
X232239285Y-77926428D01*
X232167857Y-77997857D01*
X232096428Y-78140714D01*
X232096428Y-78497857D01*
X232167857Y-78640714D01*
X232239285Y-78712142D01*
X232382142Y-78783571D01*
X232739285Y-78783571D01*
X232882142Y-78712142D01*
X232953571Y-78640714D01*
X235667857Y-81323571D02*
X235667857Y-79823571D01*
X235096428Y-79823571D01*
X234953571Y-79895000D01*
X234882142Y-79966428D01*
X234810714Y-80109285D01*
X234810714Y-80323571D01*
X234882142Y-80466428D01*
X234953571Y-80537857D01*
X235096428Y-80609285D01*
X235667857Y-80609285D01*
X234239285Y-80895000D02*
X233525000Y-80895000D01*
X234382142Y-81323571D02*
X233882142Y-79823571D01*
X233382142Y-81323571D01*
X232239285Y-80323571D02*
X232239285Y-81323571D01*
X232596428Y-79752142D02*
X232953571Y-80823571D01*
X232025000Y-80823571D01*
X234882142Y-82435000D02*
X235025000Y-82363571D01*
X235239285Y-82363571D01*
X235453571Y-82435000D01*
X235596428Y-82577857D01*
X235667857Y-82720714D01*
X235739285Y-83006428D01*
X235739285Y-83220714D01*
X235667857Y-83506428D01*
X235596428Y-83649285D01*
X235453571Y-83792142D01*
X235239285Y-83863571D01*
X235096428Y-83863571D01*
X234882142Y-83792142D01*
X234810714Y-83720714D01*
X234810714Y-83220714D01*
X235096428Y-83220714D01*
X234167857Y-83863571D02*
X234167857Y-82363571D01*
X233310714Y-83863571D01*
X233310714Y-82363571D01*
X232596428Y-83863571D02*
X232596428Y-82363571D01*
X232239285Y-82363571D01*
X232025000Y-82435000D01*
X231882142Y-82577857D01*
X231810714Y-82720714D01*
X231739285Y-83006428D01*
X231739285Y-83220714D01*
X231810714Y-83506428D01*
X231882142Y-83649285D01*
X232025000Y-83792142D01*
X232239285Y-83863571D01*
X232596428Y-83863571D01*
X235739285Y-86332142D02*
X235525000Y-86403571D01*
X235167857Y-86403571D01*
X235025000Y-86332142D01*
X234953571Y-86260714D01*
X234882142Y-86117857D01*
X234882142Y-85975000D01*
X234953571Y-85832142D01*
X235025000Y-85760714D01*
X235167857Y-85689285D01*
X235453571Y-85617857D01*
X235596428Y-85546428D01*
X235667857Y-85475000D01*
X235739285Y-85332142D01*
X235739285Y-85189285D01*
X235667857Y-85046428D01*
X235596428Y-84975000D01*
X235453571Y-84903571D01*
X235096428Y-84903571D01*
X234882142Y-84975000D01*
X234382142Y-84903571D02*
X234025000Y-86403571D01*
X233739285Y-85332142D01*
X233453571Y-86403571D01*
X233096428Y-84903571D01*
X232525000Y-86403571D02*
X232525000Y-84903571D01*
X232167857Y-84903571D01*
X231953571Y-84975000D01*
X231810714Y-85117857D01*
X231739285Y-85260714D01*
X231667857Y-85546428D01*
X231667857Y-85760714D01*
X231739285Y-86046428D01*
X231810714Y-86189285D01*
X231953571Y-86332142D01*
X232167857Y-86403571D01*
X232525000Y-86403571D01*
X230167857Y-86260714D02*
X230239285Y-86332142D01*
X230453571Y-86403571D01*
X230596428Y-86403571D01*
X230810714Y-86332142D01*
X230953571Y-86189285D01*
X231025000Y-86046428D01*
X231096428Y-85760714D01*
X231096428Y-85546428D01*
X231025000Y-85260714D01*
X230953571Y-85117857D01*
X230810714Y-84975000D01*
X230596428Y-84903571D01*
X230453571Y-84903571D01*