From 72da24d5c086516c1f7b8d50077296bd4a16623b Mon Sep 17 00:00:00 2001 From: SQFMI Date: Fri, 8 Sep 2023 01:08:38 -0400 Subject: [PATCH] Deploy website - based on 39c4ab872147d48ae84a8725cf4d9bdf51bcc08a --- .DS_Store | Bin 10244 -> 10244 bytes 404.html | 4 ++-- ...0b142.37221a00.js => 0480b142.0d696442.js} | 2 +- assets/js/076cabff.1638b735.js | 1 - assets/js/076cabff.bd453fea.js | 1 + ...5b8de.e55c6278.js => 3ac5b8de.d45c63d2.js} | 2 +- assets/js/641522b2.778c3aba.js | 1 - assets/js/641522b2.dae1daae.js | 1 + ...aaaeb.564c28e0.js => 64baaaeb.2dd6e154.js} | 2 +- assets/js/78a7c784.8ac9c576.js | 1 + assets/js/78a7c784.f7ed345a.js | 1 - assets/js/935f2afb.4023d4de.js | 1 + assets/js/935f2afb.ff46232f.js | 1 - assets/js/d589d3a7.2e5b9b0a.js | 1 + assets/js/d589d3a7.f7031d1d.js | 1 - assets/js/f3cedf5b.b27a675d.js | 1 + assets/js/f3cedf5b.dd5a4b2d.js | 1 - assets/js/runtime~main.5ced46a9.js | 1 - assets/js/runtime~main.84972518.js | 1 + docs/3D.html | 4 ++-- docs/category/firmware.html | 6 +++--- docs/category/hardware.html | 4 ++-- docs/category/software.html | 6 +++--- docs/faq.html | 6 +++--- docs/firmware/keyboard.html | 6 +++--- docs/firmware/power.html | 6 +++--- docs/firmware/rgb-led.html | 9 ++++----- docs/getting-started.html | 6 +++--- docs/hardware/pinouts.html | 4 ++-- docs/hardware/schematic.html | 4 ++-- docs/hardware/specs.html | 4 ++-- docs/software/linux-drivers.html | 8 ++++---- docs/software/os-image.html | 6 +++--- gallery.html | 4 ++-- img/symbol-keys.png | Bin 0 -> 67972 bytes index.html | 4 ++-- markdown-page.html | 4 ++-- 37 files changed, 57 insertions(+), 58 deletions(-) rename assets/js/{0480b142.37221a00.js => 0480b142.0d696442.js} (76%) delete mode 100644 assets/js/076cabff.1638b735.js create mode 100644 assets/js/076cabff.bd453fea.js rename assets/js/{3ac5b8de.e55c6278.js => 3ac5b8de.d45c63d2.js} (51%) delete mode 100644 assets/js/641522b2.778c3aba.js create mode 100644 assets/js/641522b2.dae1daae.js rename assets/js/{64baaaeb.564c28e0.js => 64baaaeb.2dd6e154.js} (51%) create mode 100644 assets/js/78a7c784.8ac9c576.js delete mode 100644 assets/js/78a7c784.f7ed345a.js create mode 100644 assets/js/935f2afb.4023d4de.js delete mode 100644 assets/js/935f2afb.ff46232f.js create mode 100644 assets/js/d589d3a7.2e5b9b0a.js delete mode 100644 assets/js/d589d3a7.f7031d1d.js create mode 100644 assets/js/f3cedf5b.b27a675d.js delete mode 100644 assets/js/f3cedf5b.dd5a4b2d.js delete mode 100644 assets/js/runtime~main.5ced46a9.js create mode 100644 assets/js/runtime~main.84972518.js create mode 100644 img/symbol-keys.png diff --git a/.DS_Store b/.DS_Store index e24971b460d8ae456a1f2f9870dfb98c09392407..4e05843dd3f624029a428cf10db39242c0f7f87b 100644 GIT binary patch delta 21 ccmZn(XbITBB*bB4X{@7QXlAmROX!y<0760q*Z=?k delta 21 ccmZn(XbITBB*bBAV5*~FXl${WOX!y<074c8)c^nh diff --git a/404.html b/404.html index 13bcf85..5f25171 100644 --- a/404.html +++ b/404.html @@ -7,13 +7,13 @@ - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- + \ No newline at end of file diff --git a/assets/js/0480b142.37221a00.js b/assets/js/0480b142.0d696442.js similarity index 76% rename from assets/js/0480b142.37221a00.js rename to assets/js/0480b142.0d696442.js index e7ebe44..13e74f5 100644 --- a/assets/js/0480b142.37221a00.js +++ b/assets/js/0480b142.0d696442.js @@ -1 +1 @@ -"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[836],{3905:(e,t,a)=>{a.d(t,{Zo:()=>l,kt:()=>y});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var c=n.createContext({}),p=function(e){var t=n.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},l=function(e){var t=p(e.components);return n.createElement(c.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),d=p(a),u=r,y=d["".concat(c,".").concat(u)]||d[u]||h[u]||i;return a?n.createElement(y,o(o({ref:t},l),{},{components:a})):n.createElement(y,o({ref:t},l))}));function y(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=u;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var p=2;p{a.r(t),a.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var n=a(7462),r=(a(7294),a(3905));const i={sidebar_position:6},o="FAQ",s={unversionedId:"faq",id:"faq",title:"FAQ",description:"What's a Beepy?",source:"@site/docs/faq.md",sourceDirName:".",slug:"/faq",permalink:"/docs/faq",draft:!1,editUrl:"https://github.com/sqfmi/beepy-docs/blob/main/docs/faq.md",tags:[],version:"current",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"docsSidebar",previous:{title:"Case Designs & 3D Models",permalink:"/docs/3D"}},c={},p=[{value:"What's a Beepy?",id:"whats-a-beepy",level:3},{value:"What is Beeper?",id:"what-is-beeper",level:3},{value:"Does it have LTE/4G/5G/LoRA/Zigbee/GPS/etc. connectivity?",id:"does-it-have-lte4g5glorazigbeegpsetc-connectivity",level:3},{value:"Does Beepy come with a case?",id:"does-beepy-come-with-a-case",level:3},{value:"My Beepy LED is always on",id:"my-beepy-led-is-always-on",level:3},{value:"I just opened the box and have no idea what to do",id:"i-just-opened-the-box-and-have-no-idea-what-to-do",level:3},{value:"Help, the screen is stuck displaying a very striking static pattern, even after I've flashed the SD card",id:"help-the-screen-is-stuck-displaying-a-very-striking-static-pattern-even-after-ive-flashed-the-sd-card",level:3},{value:"I set my WiFi SSID and password in the Pi imager but it can't seem to connect",id:"i-set-my-wifi-ssid-and-password-in-the-pi-imager-but-it-cant-seem-to-connect",level:3},{value:"I prefer a white background with black text",id:"i-prefer-a-white-background-with-black-text",level:3}],l={toc:p},d="wrapper";function h(e){let{components:t,...a}=e;return(0,r.kt)(d,(0,n.Z)({},l,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"faq"},"FAQ"),(0,r.kt)("h3",{id:"whats-a-beepy"},"What's a Beepy?"),(0,r.kt)("p",null,"Beepy is a portable computing device, with a beautiful high contrast, high resolution display, and a tactile keyboard + touchpad, it is the ultimate everyday hacking gadget."),(0,r.kt)("p",null,"Powered by the Raspberry Pi Zero W (or any other compatible SBCs), you can use it as a chat device (supporting all chat networks on Beeper e.g. iMessage/WhatsApp/Signal/etc. ), or use it as a hackable handheld cyberdeck, running any Linux application that runs on the Pi."),(0,r.kt)("h3",{id:"what-is-beeper"},"What is Beeper?"),(0,r.kt)("p",null,"Beeper is a universal chat app. It\u2019s a single app to chat with friends on 15 different chat networks."),(0,r.kt)("p",null,"Learn more at ",(0,r.kt)("a",{parentName:"p",href:"https://www.beeper.com"},"https://www.beeper.com")),(0,r.kt)("h3",{id:"does-it-have-lte4g5glorazigbeegpsetc-connectivity"},"Does it have LTE/4G/5G/LoRA/Zigbee/GPS/etc. connectivity?"),(0,r.kt)("p",null,"Additional connectivity can be expanded via USB or GPIO ports."),(0,r.kt)("h3",{id:"does-beepy-come-with-a-case"},"Does Beepy come with a case?"),(0,r.kt)("p",null,"No, but you can ",(0,r.kt)("a",{parentName:"p",href:"/docs/3D"},"3D print your own case"),". We'll be offering a case soon. Beepy can also be used as is (with the addition of a rubber band)."),(0,r.kt)("h3",{id:"my-beepy-led-is-always-on"},"My Beepy LED is always on"),(0,r.kt)("p",null,"You may be running an older version of the firmware, follow these instructions to ",(0,r.kt)("a",{parentName:"p",href:"/docs/getting-started#firmware-update"},(0,r.kt)("strong",{parentName:"a"},"update the firmware")),"."),(0,r.kt)("h3",{id:"i-just-opened-the-box-and-have-no-idea-what-to-do"},"I just opened the box and have no idea what to do"),(0,r.kt)("p",null,"First you need to follow the instructions to ",(0,r.kt)("a",{parentName:"p",href:"/docs/getting-started"},"flash an SD card with the OS"),", then make sure the battery is charged by plugging in the USB C port and flipping the power switch. "),(0,r.kt)("h3",{id:"help-the-screen-is-stuck-displaying-a-very-striking-static-pattern-even-after-ive-flashed-the-sd-card"},"Help, the screen is stuck displaying a very striking static pattern, even after I've flashed the SD card"),(0,r.kt)("p",null,"Follow the ",(0,r.kt)("a",{parentName:"p",href:"/docs/getting-started#software-setup"},"Getting Started")," guide and run the install script before the screen can display anything."),(0,r.kt)("h3",{id:"i-set-my-wifi-ssid-and-password-in-the-pi-imager-but-it-cant-seem-to-connect"},"I set my WiFi SSID and password in the Pi imager but it can't seem to connect"),(0,r.kt)("p",null,"The Pi Zero W only supports 2.4GHz WiFi networks. Make sure you're not trying to connect to a 5GHz network."),(0,r.kt)("h3",{id:"i-prefer-a-white-background-with-black-text"},"I prefer a white background with black text"),(0,r.kt)("p",null,"You can invert the display mode by running ",(0,r.kt)("inlineCode",{parentName:"p"},"echo -e '\\033[?5h' > /dev/tty1"),". You can append this line to your .bashrc to set it as the default."))}h.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[836],{3905:(e,t,a)=>{a.d(t,{Zo:()=>l,kt:()=>y});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var c=n.createContext({}),p=function(e){var t=n.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},l=function(e){var t=p(e.components);return n.createElement(c.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),d=p(a),u=r,y=d["".concat(c,".").concat(u)]||d[u]||h[u]||i;return a?n.createElement(y,o(o({ref:t},l),{},{components:a})):n.createElement(y,o({ref:t},l))}));function y(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=u;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var p=2;p{a.r(t),a.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var n=a(7462),r=(a(7294),a(3905));const i={sidebar_position:6},o="FAQ",s={unversionedId:"faq",id:"faq",title:"FAQ",description:"What's a Beepy?",source:"@site/docs/faq.md",sourceDirName:".",slug:"/faq",permalink:"/docs/faq",draft:!1,editUrl:"https://github.com/sqfmi/beepy-docs/blob/main/docs/faq.md",tags:[],version:"current",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"docsSidebar",previous:{title:"Case Designs & 3D Models",permalink:"/docs/3D"}},c={},p=[{value:"What's a Beepy?",id:"whats-a-beepy",level:3},{value:"What is Beeper?",id:"what-is-beeper",level:3},{value:"Does it have LTE/4G/5G/LoRA/Zigbee/GPS/etc. connectivity?",id:"does-it-have-lte4g5glorazigbeegpsetc-connectivity",level:3},{value:"Does Beepy come with a case?",id:"does-beepy-come-with-a-case",level:3},{value:"My Beepy LED is always on",id:"my-beepy-led-is-always-on",level:3},{value:"I just opened the box and have no idea what to do",id:"i-just-opened-the-box-and-have-no-idea-what-to-do",level:3},{value:"Help, the screen is stuck displaying a very striking static pattern, even after I've flashed the SD card",id:"help-the-screen-is-stuck-displaying-a-very-striking-static-pattern-even-after-ive-flashed-the-sd-card",level:3},{value:"I set my WiFi SSID and password in the Pi imager but it can't seem to connect",id:"i-set-my-wifi-ssid-and-password-in-the-pi-imager-but-it-cant-seem-to-connect",level:3},{value:"I prefer a white background with black text",id:"i-prefer-a-white-background-with-black-text",level:3}],l={toc:p},d="wrapper";function h(e){let{components:t,...a}=e;return(0,r.kt)(d,(0,n.Z)({},l,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"faq"},"FAQ"),(0,r.kt)("h3",{id:"whats-a-beepy"},"What's a Beepy?"),(0,r.kt)("p",null,"Beepy is a portable computing device, with a beautiful high contrast, high resolution display, and a tactile keyboard + touchpad, it is the ultimate everyday hacking gadget."),(0,r.kt)("p",null,"Powered by the Raspberry Pi Zero W (or any other compatible SBCs), you can use it as a chat device (supporting all chat networks on Beeper e.g. iMessage/WhatsApp/Signal/etc. ), or use it as a hackable handheld cyberdeck, running any Linux application that runs on the Pi."),(0,r.kt)("h3",{id:"what-is-beeper"},"What is Beeper?"),(0,r.kt)("p",null,"Beeper is a universal chat app. It\u2019s a single app to chat with friends on 15 different chat networks."),(0,r.kt)("p",null,"Learn more at ",(0,r.kt)("a",{parentName:"p",href:"https://www.beeper.com"},"https://www.beeper.com")),(0,r.kt)("h3",{id:"does-it-have-lte4g5glorazigbeegpsetc-connectivity"},"Does it have LTE/4G/5G/LoRA/Zigbee/GPS/etc. connectivity?"),(0,r.kt)("p",null,"Additional connectivity can be expanded via USB or GPIO ports."),(0,r.kt)("h3",{id:"does-beepy-come-with-a-case"},"Does Beepy come with a case?"),(0,r.kt)("p",null,"No, but you can ",(0,r.kt)("a",{parentName:"p",href:"/docs/3D"},"3D print your own case"),". We'll be offering a case soon. Beepy can also be used as is (with the addition of a rubber band)."),(0,r.kt)("h3",{id:"my-beepy-led-is-always-on"},"My Beepy LED is always on"),(0,r.kt)("p",null,"You may be running an older version of the firmware, follow the firmware flashing instructions to ",(0,r.kt)("a",{parentName:"p",href:"/docs/getting-started#software-setup"},(0,r.kt)("strong",{parentName:"a"},"update the firmware")),"."),(0,r.kt)("h3",{id:"i-just-opened-the-box-and-have-no-idea-what-to-do"},"I just opened the box and have no idea what to do"),(0,r.kt)("p",null,"First you need to follow the instructions to ",(0,r.kt)("a",{parentName:"p",href:"/docs/getting-started"},"flash an SD card with the OS"),", then make sure the battery is charged by plugging in the USB C port and flipping the power switch. "),(0,r.kt)("h3",{id:"help-the-screen-is-stuck-displaying-a-very-striking-static-pattern-even-after-ive-flashed-the-sd-card"},"Help, the screen is stuck displaying a very striking static pattern, even after I've flashed the SD card"),(0,r.kt)("p",null,"Follow the ",(0,r.kt)("a",{parentName:"p",href:"/docs/getting-started#software-setup"},"Getting Started")," guide and run the install script before the screen can display anything."),(0,r.kt)("h3",{id:"i-set-my-wifi-ssid-and-password-in-the-pi-imager-but-it-cant-seem-to-connect"},"I set my WiFi SSID and password in the Pi imager but it can't seem to connect"),(0,r.kt)("p",null,"The Pi Zero W only supports 2.4GHz WiFi networks. Make sure you're not trying to connect to a 5GHz network."),(0,r.kt)("h3",{id:"i-prefer-a-white-background-with-black-text"},"I prefer a white background with black text"),(0,r.kt)("p",null,"You can invert the display mode by running ",(0,r.kt)("inlineCode",{parentName:"p"},"echo 1 | sudo tee /sys/module/sharp_drm/parameters/mono_invert")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/076cabff.1638b735.js b/assets/js/076cabff.1638b735.js deleted file mode 100644 index 5ffe788..0000000 --- a/assets/js/076cabff.1638b735.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[636],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>b});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),s=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},c=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),d=s(r),m=a,b=d["".concat(p,".").concat(m)]||d[m]||u[m]||o;return r?n.createElement(b,l(l({ref:t},c),{},{components:r})):n.createElement(b,l({ref:t},c))}));function b(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,l=new Array(o);l[0]=m;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i[d]="string"==typeof e?e:a,l[1]=i;for(var s=2;s{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>s});var n=r(7462),a=(r(7294),r(3905));const o={sidebar_position:2},l="Power Management & Battery",i={unversionedId:"firmware/power",id:"firmware/power",title:"Power Management & Battery",description:'The onboard RP2040 controls the power to the Pi, as well as measuring the battery level with its ADC. The Beepy can be safely shutdown by holding the "End Call" button on the keyboard.',source:"@site/docs/firmware/power.md",sourceDirName:"firmware",slug:"/firmware/power",permalink:"/docs/firmware/power",draft:!1,editUrl:"https://github.com/sqfmi/beepy-docs/blob/main/docs/firmware/power.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"docsSidebar",previous:{title:"Keyboard Firmware",permalink:"/docs/firmware/keyboard"},next:{title:"RGB LED",permalink:"/docs/firmware/rgb-led"}},p={},s=[{value:"Examples",id:"examples",level:2},{value:"Battery Level Reporting",id:"battery-level-reporting",level:3},{value:"Command-line Example",id:"command-line-example",level:4},{value:"Script",id:"script",level:2},{value:"Sleep/Wake",id:"sleepwake",level:3}],c={toc:s},d="wrapper";function u(e){let{components:t,...r}=e;return(0,a.kt)(d,(0,n.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"power-management--battery"},"Power Management & Battery"),(0,a.kt)("p",null,'The onboard RP2040 controls the power to the Pi, as well as measuring the battery level with its ADC. The Beepy can be safely shutdown by holding the "End Call" button on the keyboard.'),(0,a.kt)("h2",{id:"examples"},"Examples"),(0,a.kt)("h3",{id:"battery-level-reporting"},"Battery Level Reporting"),(0,a.kt)("p",null,"To read the battery voltage on the Beepy, you can read from the register ",(0,a.kt)("inlineCode",{parentName:"p"},"0x17")," over I2C."),(0,a.kt)("p",null,"This is a read-only register, it is 2 bytes in size."),(0,a.kt)("p",null,"It returns a 16 bit value from the ADC (VREF = 3.3V). On the Beepy there is a voltage divider, so the battery voltage can be calculated as ",(0,a.kt)("strong",{parentName:"p"},"VBAT = 3.3V ","*"," (value/4095) ","*"," 2"),"."),(0,a.kt)("h4",{id:"command-line-example"},"Command-line Example"),(0,a.kt)("p",null,"First release the I2C bus from the keyboard driver, then read 1 word (2 bytes) from I2C bus 1, address 0x1F, register 0x17"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"sudo modprobe -r bbqX0kbd\nsudo i2cget -y 1 0x1F 0x17 w\n")),(0,a.kt)("h2",{id:"script"},"Script"),(0,a.kt)("p",null,"Script to calculate the battery voltage"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"#!/bin/sh\n\nsudo modprobe -r bbqX0kbd\nV=$(i2cget -y 1 0x1F 0x17 w | sed s/0x// | tr '[:lower:]' '[:upper:]')\nsudo modprobe bbqX0kbd\n\nV=$(echo \"obase=10; ibase=16; $V\" | bc)\necho \"$V * 3.3 * 2 / 4095\" | bc -l | cut -c1-5\n")),(0,a.kt)("h3",{id:"sleepwake"},"Sleep/Wake"),(0,a.kt)("p",null,"To Do"))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/076cabff.bd453fea.js b/assets/js/076cabff.bd453fea.js new file mode 100644 index 0000000..fdca975 --- /dev/null +++ b/assets/js/076cabff.bd453fea.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[636],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>d});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),s=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},c=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),u=s(r),y=a,d=u["".concat(p,".").concat(y)]||u[y]||m[y]||o;return r?n.createElement(d,l(l({ref:t},c),{},{components:r})):n.createElement(d,l({ref:t},c))}));function d(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,l=new Array(o);l[0]=y;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i[u]="string"==typeof e?e:a,l[1]=i;for(var s=2;s{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>m,frontMatter:()=>o,metadata:()=>i,toc:()=>s});var n=r(7462),a=(r(7294),r(3905));const o={sidebar_position:2},l="Power Management & Battery",i={unversionedId:"firmware/power",id:"firmware/power",title:"Power Management & Battery",description:'The onboard RP2040 controls the power to the Pi, as well as measuring the battery level with its ADC. The Beepy can be safely shutdown by holding the "End Call" button on the keyboard.',source:"@site/docs/firmware/power.md",sourceDirName:"firmware",slug:"/firmware/power",permalink:"/docs/firmware/power",draft:!1,editUrl:"https://github.com/sqfmi/beepy-docs/blob/main/docs/firmware/power.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"docsSidebar",previous:{title:"Keyboard Firmware",permalink:"/docs/firmware/keyboard"},next:{title:"RGB LED",permalink:"/docs/firmware/rgb-led"}},p={},s=[{value:"Examples",id:"examples",level:2},{value:"Battery Level Reporting",id:"battery-level-reporting",level:3},{value:"Script",id:"script",level:2},{value:"Sleep/Wake",id:"sleepwake",level:3}],c={toc:s},u="wrapper";function m(e){let{components:t,...r}=e;return(0,a.kt)(u,(0,n.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"power-management--battery"},"Power Management & Battery"),(0,a.kt)("p",null,'The onboard RP2040 controls the power to the Pi, as well as measuring the battery level with its ADC. The Beepy can be safely shutdown by holding the "End Call" button on the keyboard.'),(0,a.kt)("p",null,"To battery voltage on the Beepy can read from the register ",(0,a.kt)("inlineCode",{parentName:"p"},"0x17")," over I2C. This is a read-only register, it is 2 bytes in size. It returns a 16 bit value from the ADC (VREF = 3.3V). There is a voltage divider so the battery voltage can be calculated as VBAT = 3.3V ",(0,a.kt)("em",{parentName:"p"}," (value/4095) ")," 2."),(0,a.kt)("h2",{id:"examples"},"Examples"),(0,a.kt)("h3",{id:"battery-level-reporting"},"Battery Level Reporting"),(0,a.kt)("p",null,"The following sysfs entries are available under ",(0,a.kt)("inlineCode",{parentName:"p"},"/sys/firmware/beepy")," to read the system battery level:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"battery_raw"),": raw numerical battery level as reported by firmware. Read-only"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"battery_volts"),": battery voltage estimation. Read-only"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"battery_percent"),": battery percentage estimation. Read-only")),(0,a.kt)("h2",{id:"script"},"Script"),(0,a.kt)("p",null,"The following script is an example to calculate a voltage estimation from the raw battery level:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'#!/bin/sh\n\nV=$(cat /sys/firmware/beepy/battery_raw)\n\nV=$(echo "obase=10; ibase=16; $V" | bc)\necho "$V * 3.3 * 2 / 4095" | bc -l | cut -c1-5\n')),(0,a.kt)("h3",{id:"sleepwake"},"Sleep/Wake"),(0,a.kt)("p",null,"To Do"))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/3ac5b8de.e55c6278.js b/assets/js/3ac5b8de.d45c63d2.js similarity index 51% rename from assets/js/3ac5b8de.e55c6278.js rename to assets/js/3ac5b8de.d45c63d2.js index fc892dd..b4fd464 100644 --- a/assets/js/3ac5b8de.e55c6278.js +++ b/assets/js/3ac5b8de.d45c63d2.js @@ -1 +1 @@ -"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[828],{3499:e=>{e.exports=JSON.parse('{"title":"Firmware","slug":"/category/firmware","permalink":"/docs/category/firmware","navigation":{"previous":{"title":"Linux Drivers","permalink":"/docs/software/linux-drivers"},"next":{"title":"Keyboard Firmware","permalink":"/docs/firmware/keyboard"}}}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[828],{3499:e=>{e.exports=JSON.parse('{"title":"Firmware","slug":"/category/firmware","permalink":"/docs/category/firmware","navigation":{"previous":{"title":"RGB LED","permalink":"/docs/software/linux-drivers"},"next":{"title":"Keyboard Firmware","permalink":"/docs/firmware/keyboard"}}}')}}]); \ No newline at end of file diff --git a/assets/js/641522b2.778c3aba.js b/assets/js/641522b2.778c3aba.js deleted file mode 100644 index 8d01c83..0000000 --- a/assets/js/641522b2.778c3aba.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[434],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>f});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function l(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),d=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},s=function(e){var t=d(e.components);return n.createElement(p.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,l=e.originalType,p=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),c=d(r),u=a,f=c["".concat(p,".").concat(u)]||c[u]||m[u]||l;return r?n.createElement(f,o(o({ref:t},s),{},{components:r})):n.createElement(f,o({ref:t},s))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=r.length,o=new Array(l);o[0]=u;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i[c]="string"==typeof e?e:a,o[1]=i;for(var d=2;d{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>m,frontMatter:()=>l,metadata:()=>i,toc:()=>d});var n=r(7462),a=(r(7294),r(3905));const l={sidebar_position:3},o="RGB LED",i={unversionedId:"firmware/rgb-led",id:"firmware/rgb-led",title:"RGB LED",description:"The RGB LED is connected to the RP2040 and can be controlled by the Pi via I\xb2C.",source:"@site/docs/firmware/rgb-led.md",sourceDirName:"firmware",slug:"/firmware/rgb-led",permalink:"/docs/firmware/rgb-led",draft:!1,editUrl:"https://github.com/sqfmi/beepy-docs/blob/main/docs/firmware/rgb-led.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"docsSidebar",previous:{title:"Power Management & Battery",permalink:"/docs/firmware/power"},next:{title:"Hardware",permalink:"/docs/category/hardware"}},p={},d=[{value:"Example",id:"example",level:2}],s={toc:d},c="wrapper";function m(e){let{components:t,...r}=e;return(0,a.kt)(c,(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"rgb-led"},"RGB LED"),(0,a.kt)("p",null,"The RGB LED is connected to the RP2040 and can be controlled by the Pi via ",(0,a.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/I%C2%B2C"},"I\xb2C"),"."),(0,a.kt)("p",null,"The LED color on the Beepy is exposed on I2C bus 1 at the chip address ",(0,a.kt)("inlineCode",{parentName:"p"},"0x1F"),"."),(0,a.kt)("p",null,"Controls are available at the following specific data addresses:"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"Function"),(0,a.kt)("th",{parentName:"tr",align:null},"Read"),(0,a.kt)("th",{parentName:"tr",align:null},"Write"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Power"),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0x20")),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0xA0"))),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Red"),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0x21")),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0xA1"))),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Green"),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0x22")),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0xA2"))),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Blue"),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0x23")),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0xA3"))))),(0,a.kt)("p",null,"=======\nTo get/set the LED color on the Beepy, you can read/write to the following registers over I2C. The values can be 0x00 - 0xFF."),(0,a.kt)("p",null,(0,a.kt)("em",{parentName:"p"},"Note: write addresses are the read address masked with 0x80.")),(0,a.kt)("p",null,"Valid RGB values are on the range ",(0,a.kt)("inlineCode",{parentName:"p"},"0x00")," to ",(0,a.kt)("inlineCode",{parentName:"p"},"0xFF"),"."),(0,a.kt)("p",null,"A value of 0 in the power register represents the LED's off state, while any other value represents on."),(0,a.kt)("h2",{id:"example"},"Example"),(0,a.kt)("p",null,"To set the RGB values to red and turn the LED on from the command line:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"# Format:\n# i2cset -y [i2cbus] [chip-address] [data-address] value\ni2cset -y 1 0x1F 0xA1 0xFF\ni2cset -y 1 0x1F 0xA2 0x00\ni2cset -y 1 0x1F 0xA3 0x00\ni2cset -y 1 0x1F 0xA0 0xFF\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/641522b2.dae1daae.js b/assets/js/641522b2.dae1daae.js new file mode 100644 index 0000000..198ded5 --- /dev/null +++ b/assets/js/641522b2.dae1daae.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[434],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>k});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function l(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),d=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},s=function(e){var t=d(e.components);return n.createElement(p.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,l=e.originalType,p=e.parentName,s=o(e,["components","mdxType","originalType","parentName"]),m=d(r),u=a,k=m["".concat(p,".").concat(u)]||m[u]||c[u]||l;return r?n.createElement(k,i(i({ref:t},s),{},{components:r})):n.createElement(k,i({ref:t},s))}));function k(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=r.length,i=new Array(l);i[0]=u;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[m]="string"==typeof e?e:a,i[1]=o;for(var d=2;d{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>c,frontMatter:()=>l,metadata:()=>o,toc:()=>d});var n=r(7462),a=(r(7294),r(3905));const l={sidebar_position:3},i="RGB LED",o={unversionedId:"firmware/rgb-led",id:"firmware/rgb-led",title:"RGB LED",description:"The following sysfs entries are available under /sys/firmware/beepy:",source:"@site/docs/firmware/rgb-led.md",sourceDirName:"firmware",slug:"/firmware/rgb-led",permalink:"/docs/firmware/rgb-led",draft:!1,editUrl:"https://github.com/sqfmi/beepy-docs/blob/main/docs/firmware/rgb-led.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"docsSidebar",previous:{title:"Power Management & Battery",permalink:"/docs/firmware/power"},next:{title:"Hardware",permalink:"/docs/category/hardware"}},p={},d=[{value:"RGB LED over I2C",id:"rgb-led-over-i2c",level:2},{value:"Example",id:"example",level:2}],s={toc:d},m="wrapper";function c(e){let{components:t,...r}=e;return(0,a.kt)(m,(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"rgb-led"},"RGB LED"),(0,a.kt)("p",null,"The following sysfs entries are available under ",(0,a.kt)("inlineCode",{parentName:"p"},"/sys/firmware/beepy"),":"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"led"),": 0 to disable LED, 1 to enable. Write-only"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"led_red"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"led_green"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"led_blue"),": set LED color intensity from 0 to 255. Write- only")),(0,a.kt)("h2",{id:"rgb-led-over-i2c"},"RGB LED over I2C"),(0,a.kt)("p",null,"The RGB LED is connected to the RP2040. When the keyboard driver is unloaded via ",(0,a.kt)("inlineCode",{parentName:"p"},"rmmod beepy-kbd"),", they can be controlled directly by the Pi via ",(0,a.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/I%C2%B2C"},"I\xb2C"),"."),(0,a.kt)("p",null,"The LED color on the Beepy is exposed on I2C bus 1 at the chip address ",(0,a.kt)("inlineCode",{parentName:"p"},"0x1F"),"."),(0,a.kt)("p",null,"Controls are available at the following specific data addresses:"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"Function"),(0,a.kt)("th",{parentName:"tr",align:null},"Read"),(0,a.kt)("th",{parentName:"tr",align:null},"Write"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Power"),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0x20")),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0xA0"))),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Red"),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0x21")),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0xA1"))),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Green"),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0x22")),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0xA2"))),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Blue"),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0x23")),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0xA3"))))),(0,a.kt)("p",null,"To get/set the LED color on the Beepy, you can read/write to the above registers over I2C. The values are in the range of ",(0,a.kt)("inlineCode",{parentName:"p"},"0x00")," - ",(0,a.kt)("inlineCode",{parentName:"p"},"0xFF"),"."),(0,a.kt)("p",null,(0,a.kt)("em",{parentName:"p"},"Note: write addresses are the read address masked with ",(0,a.kt)("inlineCode",{parentName:"em"},"0x80"),".")),(0,a.kt)("p",null,"A value of 0 in the power register represents the LED's off state, while any other value represents on."),(0,a.kt)("h2",{id:"example"},"Example"),(0,a.kt)("p",null,"To set the RGB values to red and turn the LED on from the command line:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"# Format:\n# i2cset -y [i2cbus] [chip-address] [data-address] value\ni2cset -y 1 0x1F 0xA1 0xFF\ni2cset -y 1 0x1F 0xA2 0x00\ni2cset -y 1 0x1F 0xA3 0x00\ni2cset -y 1 0x1F 0xA0 0xFF\n")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/64baaaeb.564c28e0.js b/assets/js/64baaaeb.2dd6e154.js similarity index 51% rename from assets/js/64baaaeb.564c28e0.js rename to assets/js/64baaaeb.2dd6e154.js index f4e94ee..7abd01e 100644 --- a/assets/js/64baaaeb.564c28e0.js +++ b/assets/js/64baaaeb.2dd6e154.js @@ -1 +1 @@ -"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[253],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>d});var o=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function a(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=o.createContext({}),p=function(e){var t=o.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=p(e.components);return o.createElement(l.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},f=o.forwardRef((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=p(r),f=n,d=c["".concat(l,".").concat(f)]||c[f]||m[f]||i;return r?o.createElement(d,a(a({ref:t},u),{},{components:r})):o.createElement(d,a({ref:t},u))}));function d(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,a=new Array(i);a[0]=f;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:n,a[1]=s;for(var p=2;p{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>m,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var o=r(7462),n=(r(7294),r(3905));const i={sidebar_position:1},a="OS Image",s={unversionedId:"software/os-image",id:"software/os-image",title:"OS Image",description:"The base OS image is Raspberry Pi OS Lite 32-bit (Debian version 11 bullseye, Kernel 6.1)",source:"@site/docs/software/os-image.md",sourceDirName:"software",slug:"/software/os-image",permalink:"/docs/software/os-image",draft:!1,editUrl:"https://github.com/sqfmi/beepy-docs/blob/main/docs/software/os-image.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"docsSidebar",previous:{title:"Software",permalink:"/docs/category/software"},next:{title:"Linux Drivers",permalink:"/docs/software/linux-drivers"}},l={},p=[{value:"Optimizing Boot Speed",id:"optimizing-boot-speed",level:2},{value:"Optimizing Battery Life",id:"optimizing-battery-life",level:2},{value:"Pi Zero 2W Settings",id:"pi-zero-2w-settings",level:3},{value:"Optimizing Apps for small screens",id:"optimizing-apps-for-small-screens",level:2}],u={toc:p},c="wrapper";function m(e){let{components:t,...r}=e;return(0,n.kt)(c,(0,o.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"os-image"},"OS Image"),(0,n.kt)("p",null,"The base OS image is ",(0,n.kt)("a",{parentName:"p",href:"https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2023-05-03/2023-05-03-raspios-bullseye-armhf-lite.img.xz"},"Raspberry Pi OS Lite 32-bit")," (Debian version 11 bullseye, Kernel 6.1)"),(0,n.kt)("h2",{id:"optimizing-boot-speed"},"Optimizing Boot Speed"),(0,n.kt)("p",null,"To Do - Optimized boot script to reduce boot up time"),(0,n.kt)("h2",{id:"optimizing-battery-life"},"Optimizing Battery Life"),(0,n.kt)("h3",{id:"pi-zero-2w-settings"},"Pi Zero 2W Settings"),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Restrict number of cores to limit peak power use")," - the Zero 2W can be limited to use two cores and is still much faster than the pi zero, but peak power use is nearly half of what 4 cores will use."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"sudo vi /boot/cmdline.txt"),(0,n.kt)("li",{parentName:"ul"},'Add "maxcpus=2" after "console=tty1".'),(0,n.kt)("li",{parentName:"ul"},"Reboot")),(0,n.kt)("h2",{id:"optimizing-apps-for-small-screens"},"Optimizing Apps for small screens"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"By default, the LCD display shows a character screen of 50x15. If you develop text-based apps for Beepy, targeting this format will give you compatibility with the widest userbase.")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"top")," - You can reduce the number of columns shown by default so that it shows more useful information on the sharp display. "),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"ssh to the Beepy (the needed menu doesn't render correctly on the small screen)"),(0,n.kt)("li",{parentName:"ul"},'run "top"'),(0,n.kt)("li",{parentName:"ul"},'type "f" to enter the columns config screen'),(0,n.kt)("li",{parentName:"ul"},'use the up and down keys to move, and space to remove the "',"*",'" from all of the columns except: PID, USER, S, %CPU, %MEM, COMMAND'),(0,n.kt)("li",{parentName:"ul"},'type "q" to return to the main screen'),(0,n.kt)("li",{parentName:"ul"},'type "W" (capital w) to save the config.'),(0,n.kt)("li",{parentName:"ul"},'type "q" to quit. Then go back to the Beepy and top should have a nice setup.')))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[253],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>d});var o=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function a(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=o.createContext({}),p=function(e){var t=o.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=p(e.components);return o.createElement(l.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},f=o.forwardRef((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=p(r),f=n,d=c["".concat(l,".").concat(f)]||c[f]||m[f]||i;return r?o.createElement(d,a(a({ref:t},u),{},{components:r})):o.createElement(d,a({ref:t},u))}));function d(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,a=new Array(i);a[0]=f;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:n,a[1]=s;for(var p=2;p{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>m,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var o=r(7462),n=(r(7294),r(3905));const i={sidebar_position:1},a="OS Image",s={unversionedId:"software/os-image",id:"software/os-image",title:"OS Image",description:"The base OS image is Raspberry Pi OS Lite 32-bit (Debian version 11 bullseye, Kernel 6.1)",source:"@site/docs/software/os-image.md",sourceDirName:"software",slug:"/software/os-image",permalink:"/docs/software/os-image",draft:!1,editUrl:"https://github.com/sqfmi/beepy-docs/blob/main/docs/software/os-image.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"docsSidebar",previous:{title:"Software",permalink:"/docs/category/software"},next:{title:"RGB LED",permalink:"/docs/software/linux-drivers"}},l={},p=[{value:"Optimizing Boot Speed",id:"optimizing-boot-speed",level:2},{value:"Optimizing Battery Life",id:"optimizing-battery-life",level:2},{value:"Pi Zero 2W Settings",id:"pi-zero-2w-settings",level:3},{value:"Optimizing Apps for small screens",id:"optimizing-apps-for-small-screens",level:2}],u={toc:p},c="wrapper";function m(e){let{components:t,...r}=e;return(0,n.kt)(c,(0,o.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"os-image"},"OS Image"),(0,n.kt)("p",null,"The base OS image is ",(0,n.kt)("a",{parentName:"p",href:"https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2023-05-03/2023-05-03-raspios-bullseye-armhf-lite.img.xz"},"Raspberry Pi OS Lite 32-bit")," (Debian version 11 bullseye, Kernel 6.1)"),(0,n.kt)("h2",{id:"optimizing-boot-speed"},"Optimizing Boot Speed"),(0,n.kt)("p",null,"To Do - Optimized boot script to reduce boot up time"),(0,n.kt)("h2",{id:"optimizing-battery-life"},"Optimizing Battery Life"),(0,n.kt)("h3",{id:"pi-zero-2w-settings"},"Pi Zero 2W Settings"),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Restrict number of cores to limit peak power use")," - the Zero 2W can be limited to use two cores and is still much faster than the pi zero, but peak power use is nearly half of what 4 cores will use."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"sudo vi /boot/cmdline.txt"),(0,n.kt)("li",{parentName:"ul"},'Add "maxcpus=2" after "console=tty1".'),(0,n.kt)("li",{parentName:"ul"},"Reboot")),(0,n.kt)("h2",{id:"optimizing-apps-for-small-screens"},"Optimizing Apps for small screens"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"By default, the LCD display shows a character screen of 50x15. If you develop text-based apps for Beepy, targeting this format will give you compatibility with the widest userbase.")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"top")," - You can reduce the number of columns shown by default so that it shows more useful information on the sharp display. "),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"ssh to the Beepy (the needed menu doesn't render correctly on the small screen)"),(0,n.kt)("li",{parentName:"ul"},'run "top"'),(0,n.kt)("li",{parentName:"ul"},'type "f" to enter the columns config screen'),(0,n.kt)("li",{parentName:"ul"},'use the up and down keys to move, and space to remove the "',"*",'" from all of the columns except: PID, USER, S, %CPU, %MEM, COMMAND'),(0,n.kt)("li",{parentName:"ul"},'type "q" to return to the main screen'),(0,n.kt)("li",{parentName:"ul"},'type "W" (capital w) to save the config.'),(0,n.kt)("li",{parentName:"ul"},'type "q" to quit. Then go back to the Beepy and top should have a nice setup.')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/78a7c784.8ac9c576.js b/assets/js/78a7c784.8ac9c576.js new file mode 100644 index 0000000..7dd7185 --- /dev/null +++ b/assets/js/78a7c784.8ac9c576.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[985],{3905:(e,t,a)=>{a.d(t,{Zo:()=>m,kt:()=>k});var r=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function n(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var p=r.createContext({}),s=function(e){var t=r.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):n(n({},t),e)),a},m=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},d="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var a=e.components,i=e.mdxType,l=e.originalType,p=e.parentName,m=o(e,["components","mdxType","originalType","parentName"]),d=s(a),u=i,k=d["".concat(p,".").concat(u)]||d[u]||y[u]||l;return a?r.createElement(k,n(n({ref:t},m),{},{components:a})):r.createElement(k,n({ref:t},m))}));function k(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=a.length,n=new Array(l);n[0]=u;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[d]="string"==typeof e?e:i,n[1]=o;for(var s=2;s{a.r(t),a.d(t,{assets:()=>p,contentTitle:()=>n,default:()=>y,frontMatter:()=>l,metadata:()=>o,toc:()=>s});var r=a(7462),i=(a(7294),a(3905));const l={sidebar_position:1},n="Keyboard Firmware",o={unversionedId:"firmware/keyboard",id:"firmware/keyboard",title:"Keyboard Firmware",description:"The keyboard firmware is a fork of i2cpuppet with a few additional features to support the Beepy.",source:"@site/docs/firmware/keyboard.md",sourceDirName:"firmware",slug:"/firmware/keyboard",permalink:"/docs/firmware/keyboard",draft:!1,editUrl:"https://github.com/sqfmi/beepy-docs/blob/main/docs/firmware/keyboard.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"docsSidebar",previous:{title:"Firmware",permalink:"/docs/category/firmware"},next:{title:"Power Management & Battery",permalink:"/docs/firmware/power"}},p={},s=[{value:"Basic key mappings",id:"basic-key-mappings",level:2},{value:"Alt and Sym modifiers",id:"alt-and-sym-modifiers",level:2},{value:"Symbol key map",id:"symbol-key-map",level:3},{value:"Sticky modifier keys",id:"sticky-modifier-keys",level:3},{value:"Meta mode",id:"meta-mode",level:2},{value:"sysfs Interface",id:"sysfs-interface",level:2},{value:"Module parameters",id:"module-parameters",level:2},{value:"Custom Keymap",id:"custom-keymap",level:2}],m={toc:s},d="wrapper";function y(e){let{components:t,...a}=e;return(0,i.kt)(d,(0,r.Z)({},m,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"keyboard-firmware"},"Keyboard Firmware"),(0,i.kt)("p",null,"The keyboard firmware is a fork of ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/solderparty/i2c_puppet"},"i2c_puppet")," with a few additional features to support the Beepy."),(0,i.kt)("p",null,"You can download the latest version of the Beepy firmware here: ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/sqfmi/i2c_puppet/releases/latest/download/i2c_puppet.uf2"},"https://github.com/sqfmi/i2c_puppet/releases/latest/download/i2c_puppet.uf2")),(0,i.kt)("h2",{id:"basic-key-mappings"},"Basic key mappings"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Call is mapped to Control"),(0,i.kt)("li",{parentName:"ul"},'"Berry" key is mapped to Tmux prefix (customize the prefix in the keymap file)'),(0,i.kt)("li",{parentName:"ul"},"Touchpad click enters Meta mode (see the section on Meta mode). Double click enters touchpad scroll mode"),(0,i.kt)("li",{parentName:"ul"},"Back is mapped to Escape"),(0,i.kt)("li",{parentName:"ul"},'Holding "End Call" safely shuts down the Pi'),(0,i.kt)("li",{parentName:"ul"},"Physical Alt is mapped to symbols printed on the keycap"),(0,i.kt)("li",{parentName:"ul"},"Symbol is mapped to AltGr (Right Alt), mapped to more symbols via the keymap file"),(0,i.kt)("li",{parentName:"ul"},"Physical Alt + Enter is mapped to Tab")),(0,i.kt)("h2",{id:"alt-and-sym-modifiers"},"Alt and Sym modifiers"),(0,i.kt)("p",null,"The alternate symbols printed directly on the Beepy keys are triggered by pressing the physical Alt key, then the key on which the symbol is printed. For additional symbols not printed directly on the keys, the Sym key is used."),(0,i.kt)("h3",{id:"symbol-key-map"},"Symbol key map"),(0,i.kt)("img",{src:"/img/symbol-keys.png",width:"100%"}),(0,i.kt)("h3",{id:"sticky-modifier-keys"},"Sticky modifier keys"),(0,i.kt)("p",null,"The keyboard driver supports sticky modifier keys. Holding a modifier key (Shift, Alt, Sym) while typing an alpha keys will apply the modifier to all alpha keys until the modifier is released."),(0,i.kt)("p",null,"One press and release of the modifier will enter sticky mode, applying the modifier to the next alpha key only. If the same modifier key is pressed and released again in sticky mode, it will be canceled."),(0,i.kt)("p",null,"Visual mode indicators are drawn in the top right corner of the display, with indicators for Shift, Physical Alt, Control, Alt, Symbol, and Meta mode."),(0,i.kt)("h2",{id:"meta-mode"},"Meta mode"),(0,i.kt)("p",null,"Meta mode is a modal layer that assists in rapidly moving the cursor and scrolling with single keypresses. To enter Meta mode, click the touchpad button once. Then, the following keymap is applied, staying in Meta mode until dismissed:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"E: up, S: down, W: left, D: right",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Why not WASD? This way, you can place your thumb in the middle of all four of these keys, and more fluidly move the cursor without mistyping"))),(0,i.kt)("li",{parentName:"ul"},"R: Home, F: End, O: PageUp, P: PageDown"),(0,i.kt)("li",{parentName:"ul"},"Q: Alt+Left (back one word), A: Alt+Right (forward one word)"),(0,i.kt)("li",{parentName:"ul"},"T: Tab (dismisses Meta mode)"),(0,i.kt)("li",{parentName:"ul"},"X: Apply Control to next key (dismisses Meta mode)"),(0,i.kt)("li",{parentName:"ul"},"C: Apply Alt to next key (dismisses Meta mode)"),(0,i.kt)("li",{parentName:"ul"},"0: Toggle display black/white inversion"),(0,i.kt)("li",{parentName:"ul"},"N: Decrease keyboard backlight brightness"),(0,i.kt)("li",{parentName:"ul"},"M: Increase keyboard backlight brightness"),(0,i.kt)("li",{parentName:"ul"},"$: Toggle keyboard backlight"),(0,i.kt)("li",{parentName:"ul"},"Touchpad click (while in Meta mode): Enable touchpad scroll mode (up and down arrrow keys)",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Other Meta mode keys will continue to work as normal"),(0,i.kt)("li",{parentName:"ul"},"Exiting meta mode will also exit touchpad scroll mode"),(0,i.kt)("li",{parentName:"ul"},"Subsequent clicks of the touchpad will type Enter."))),(0,i.kt)("li",{parentName:"ul"},'Esc: ("Back" button): exit meta mode')),(0,i.kt)("p",null,"Typing any other key while in Meta mode will exit Meta mode and send the key as if it was typed normally."),(0,i.kt)("h2",{id:"sysfs-interface"},(0,i.kt)("inlineCode",{parentName:"h2"},"sysfs")," Interface"),(0,i.kt)("p",null,"The following sysfs entries are available under ",(0,i.kt)("inlineCode",{parentName:"p"},"/sys/firmware/beepy"),":"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"led"),": 0 to disable LED, 1 to enable. Write-only"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"led_red"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"led_green"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"led_blue"),": set LED color intensity from 0 to 255. Write- only"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"keyboard_backlight"),": set keyboard brightness from 0 to 255. Write-only"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"battery_raw"),": raw numerical battery level as reported by firmware. Read-only"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"battery_volts"),": battery voltage estimation. Read-only"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"battery_percent"),": battery percentage estimation. Read-only")),(0,i.kt)("h2",{id:"module-parameters"},"Module parameters"),(0,i.kt)("p",null,"Write to ",(0,i.kt)("inlineCode",{parentName:"p"},"/sys/module/beepy_kbd/parameters/")," to set, or unload and reload the module with ",(0,i.kt)("inlineCode",{parentName:"p"},"beepy-kbd param=val"),"."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"touchpad"),": one of ",(0,i.kt)("inlineCode",{parentName:"li"},"meta")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"keys"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"meta"),": default, will use the touchpad button to enable or disable Meta mode"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"keys"),": touchpad always on, swiping sends arrow keys, clicking sends Enter")))),(0,i.kt)("h2",{id:"custom-keymap"},"Custom Keymap"),(0,i.kt)("p",null,'The Alt and Sym keymaps and the Tmux prefix sent by the "Berry" key can be edited in the file ',(0,i.kt)("inlineCode",{parentName:"p"},"/usr/share/kbd/keymaps/beepy-kbd.map"),". To reapply the keymap without rebooting, run ",(0,i.kt)("inlineCode",{parentName:"p"},"loadkeys /usr/share/kbd/keymaps/beepy-kbd.map"),"."))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/78a7c784.f7ed345a.js b/assets/js/78a7c784.f7ed345a.js deleted file mode 100644 index 83307eb..0000000 --- a/assets/js/78a7c784.f7ed345a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[985],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>f});var o=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function n(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=o.createContext({}),l=function(e){var t=o.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},s=function(e){var t=l(e.components);return o.createElement(c.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},d=o.forwardRef((function(e,t){var r=e.components,a=e.mdxType,n=e.originalType,c=e.parentName,s=p(e,["components","mdxType","originalType","parentName"]),u=l(r),d=a,f=u["".concat(c,".").concat(d)]||u[d]||m[d]||n;return r?o.createElement(f,i(i({ref:t},s),{},{components:r})):o.createElement(f,i({ref:t},s))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var n=r.length,i=new Array(n);i[0]=d;var p={};for(var c in t)hasOwnProperty.call(t,c)&&(p[c]=t[c]);p.originalType=e,p[u]="string"==typeof e?e:a,i[1]=p;for(var l=2;l{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>m,frontMatter:()=>n,metadata:()=>p,toc:()=>l});var o=r(7462),a=(r(7294),r(3905));const n={sidebar_position:1},i="Keyboard Firmware",p={unversionedId:"firmware/keyboard",id:"firmware/keyboard",title:"Keyboard Firmware",description:"The keyboard firmware is a fork of i2cpuppet with a few additional features to support the Beepy.",source:"@site/docs/firmware/keyboard.md",sourceDirName:"firmware",slug:"/firmware/keyboard",permalink:"/docs/firmware/keyboard",draft:!1,editUrl:"https://github.com/sqfmi/beepy-docs/blob/main/docs/firmware/keyboard.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"docsSidebar",previous:{title:"Firmware",permalink:"/docs/category/firmware"},next:{title:"Power Management & Battery",permalink:"/docs/firmware/power"}},c={},l=[{value:"Custom Keymap",id:"custom-keymap",level:2},{value:"Custom Trackpad",id:"custom-trackpad",level:2},{value:"Backlight Control",id:"backlight-control",level:2}],s={toc:l},u="wrapper";function m(e){let{components:t,...r}=e;return(0,a.kt)(u,(0,o.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"keyboard-firmware"},"Keyboard Firmware"),(0,a.kt)("p",null,"The keyboard firmware is a fork of ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/solderparty/i2c_puppet"},"i2c_puppet")," with a few additional features to support the Beepy."),(0,a.kt)("p",null,"You can download the latest version of the Beepy firmware here: ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/sqfmi/i2c_puppet/releases/latest/download/i2c_puppet.uf2"},"https://github.com/sqfmi/i2c_puppet/releases/latest/download/i2c_puppet.uf2")),(0,a.kt)("h2",{id:"custom-keymap"},"Custom Keymap"),(0,a.kt)("p",null,"To Do - How to customize keymap"),(0,a.kt)("h2",{id:"custom-trackpad"},"Custom Trackpad"),(0,a.kt)("p",null,"To Do - How to customize trackpad function (i.e. mouse, arrow keys, scroll. etc)"),(0,a.kt)("h2",{id:"backlight-control"},"Backlight Control"),(0,a.kt)("p",null,"To Do - Keypad backlight control"))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/935f2afb.4023d4de.js b/assets/js/935f2afb.4023d4de.js new file mode 100644 index 0000000..a1db2b9 --- /dev/null +++ b/assets/js/935f2afb.4023d4de.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[53],{1109:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"docsSidebar":[{"type":"link","label":"Getting Started","href":"/docs/getting-started","docId":"getting-started"},{"type":"category","label":"Software","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"OS Image","href":"/docs/software/os-image","docId":"software/os-image"},{"type":"link","label":"RGB LED","href":"/docs/software/linux-drivers","docId":"software/linux-drivers"}],"href":"/docs/category/software"},{"type":"category","label":"Firmware","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Keyboard Firmware","href":"/docs/firmware/keyboard","docId":"firmware/keyboard"},{"type":"link","label":"Power Management & Battery","href":"/docs/firmware/power","docId":"firmware/power"},{"type":"link","label":"RGB LED","href":"/docs/firmware/rgb-led","docId":"firmware/rgb-led"}],"href":"/docs/category/firmware"},{"type":"category","label":"Hardware","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Tech Specs","href":"/docs/hardware/specs","docId":"hardware/specs"},{"type":"link","label":"Pinouts","href":"/docs/hardware/pinouts","docId":"hardware/pinouts"},{"type":"link","label":"Schematic","href":"/docs/hardware/schematic","docId":"hardware/schematic"}],"href":"/docs/category/hardware"},{"type":"link","label":"Case Designs & 3D Models","href":"/docs/3D","docId":"3D"},{"type":"link","label":"FAQ","href":"/docs/faq","docId":"faq"}]},"docs":{"3D":{"id":"3D","title":"Case Designs & 3D Models","description":"Beepy STEP model","sidebar":"docsSidebar"},"faq":{"id":"faq","title":"FAQ","description":"What\'s a Beepy?","sidebar":"docsSidebar"},"firmware/keyboard":{"id":"firmware/keyboard","title":"Keyboard Firmware","description":"The keyboard firmware is a fork of i2cpuppet with a few additional features to support the Beepy.","sidebar":"docsSidebar"},"firmware/power":{"id":"firmware/power","title":"Power Management & Battery","description":"The onboard RP2040 controls the power to the Pi, as well as measuring the battery level with its ADC. The Beepy can be safely shutdown by holding the \\"End Call\\" button on the keyboard.","sidebar":"docsSidebar"},"firmware/rgb-led":{"id":"firmware/rgb-led","title":"RGB LED","description":"The following sysfs entries are available under /sys/firmware/beepy:","sidebar":"docsSidebar"},"getting-started":{"id":"getting-started","title":"Getting Started","description":"Software Setup","sidebar":"docsSidebar"},"hardware/pinouts":{"id":"hardware/pinouts","title":"Pinouts","description":"Raspberry Pi Header Breakout","sidebar":"docsSidebar"},"hardware/schematic":{"id":"hardware/schematic","title":"Schematic","description":"beepy-schematic-v1.pdf","sidebar":"docsSidebar"},"hardware/specs":{"id":"hardware/specs","title":"Tech Specs","description":"Beepy Technical Diagram","sidebar":"docsSidebar"},"software/linux-drivers":{"id":"software/linux-drivers","title":"RGB LED","description":"The following sysfs entries are available under /sys/firmware/beepy:","sidebar":"docsSidebar"},"software/os-image":{"id":"software/os-image","title":"OS Image","description":"The base OS image is Raspberry Pi OS Lite 32-bit (Debian version 11 bullseye, Kernel 6.1)","sidebar":"docsSidebar"}}}')}}]); \ No newline at end of file diff --git a/assets/js/935f2afb.ff46232f.js b/assets/js/935f2afb.ff46232f.js deleted file mode 100644 index 6e4f817..0000000 --- a/assets/js/935f2afb.ff46232f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[53],{1109:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"docsSidebar":[{"type":"link","label":"Getting Started","href":"/docs/getting-started","docId":"getting-started"},{"type":"category","label":"Software","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"OS Image","href":"/docs/software/os-image","docId":"software/os-image"},{"type":"link","label":"Linux Drivers","href":"/docs/software/linux-drivers","docId":"software/linux-drivers"}],"href":"/docs/category/software"},{"type":"category","label":"Firmware","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Keyboard Firmware","href":"/docs/firmware/keyboard","docId":"firmware/keyboard"},{"type":"link","label":"Power Management & Battery","href":"/docs/firmware/power","docId":"firmware/power"},{"type":"link","label":"RGB LED","href":"/docs/firmware/rgb-led","docId":"firmware/rgb-led"}],"href":"/docs/category/firmware"},{"type":"category","label":"Hardware","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Tech Specs","href":"/docs/hardware/specs","docId":"hardware/specs"},{"type":"link","label":"Pinouts","href":"/docs/hardware/pinouts","docId":"hardware/pinouts"},{"type":"link","label":"Schematic","href":"/docs/hardware/schematic","docId":"hardware/schematic"}],"href":"/docs/category/hardware"},{"type":"link","label":"Case Designs & 3D Models","href":"/docs/3D","docId":"3D"},{"type":"link","label":"FAQ","href":"/docs/faq","docId":"faq"}]},"docs":{"3D":{"id":"3D","title":"Case Designs & 3D Models","description":"Beepy STEP model","sidebar":"docsSidebar"},"faq":{"id":"faq","title":"FAQ","description":"What\'s a Beepy?","sidebar":"docsSidebar"},"firmware/keyboard":{"id":"firmware/keyboard","title":"Keyboard Firmware","description":"The keyboard firmware is a fork of i2cpuppet with a few additional features to support the Beepy.","sidebar":"docsSidebar"},"firmware/power":{"id":"firmware/power","title":"Power Management & Battery","description":"The onboard RP2040 controls the power to the Pi, as well as measuring the battery level with its ADC. The Beepy can be safely shutdown by holding the \\"End Call\\" button on the keyboard.","sidebar":"docsSidebar"},"firmware/rgb-led":{"id":"firmware/rgb-led","title":"RGB LED","description":"The RGB LED is connected to the RP2040 and can be controlled by the Pi via I\xb2C.","sidebar":"docsSidebar"},"getting-started":{"id":"getting-started","title":"Getting Started","description":"Software Setup","sidebar":"docsSidebar"},"hardware/pinouts":{"id":"hardware/pinouts","title":"Pinouts","description":"Raspberry Pi Header Breakout","sidebar":"docsSidebar"},"hardware/schematic":{"id":"hardware/schematic","title":"Schematic","description":"beepy-schematic-v1.pdf","sidebar":"docsSidebar"},"hardware/specs":{"id":"hardware/specs","title":"Tech Specs","description":"Beepy Technical Diagram","sidebar":"docsSidebar"},"software/linux-drivers":{"id":"software/linux-drivers","title":"Linux Drivers","description":"Linux drivers for the Beepy","sidebar":"docsSidebar"},"software/os-image":{"id":"software/os-image","title":"OS Image","description":"The base OS image is Raspberry Pi OS Lite 32-bit (Debian version 11 bullseye, Kernel 6.1)","sidebar":"docsSidebar"}}}')}}]); \ No newline at end of file diff --git a/assets/js/d589d3a7.2e5b9b0a.js b/assets/js/d589d3a7.2e5b9b0a.js new file mode 100644 index 0000000..6981f6f --- /dev/null +++ b/assets/js/d589d3a7.2e5b9b0a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[162],{3905:(e,t,r)=>{r.d(t,{Zo:()=>d,kt:()=>h});var a=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function o(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=a.createContext({}),s=function(e){var t=a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},d=function(e){var t=s(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,d=p(e,["components","mdxType","originalType","parentName"]),u=s(r),m=n,h=u["".concat(l,".").concat(m)]||u[m]||c[m]||i;return r?a.createElement(h,o(o({ref:t},d),{},{components:r})):a.createElement(h,o({ref:t},d))}));function h(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,o=new Array(i);o[0]=m;var p={};for(var l in t)hasOwnProperty.call(t,l)&&(p[l]=t[l]);p.originalType=e,p[u]="string"==typeof e?e:n,o[1]=p;for(var s=2;s{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>p,toc:()=>s});var a=r(7462),n=(r(7294),r(3905));const i={sidebar_position:1},o="Getting Started",p={unversionedId:"getting-started",id:"getting-started",title:"Getting Started",description:"Software Setup",source:"@site/docs/getting-started.md",sourceDirName:".",slug:"/getting-started",permalink:"/docs/getting-started",draft:!1,editUrl:"https://github.com/sqfmi/beepy-docs/blob/main/docs/getting-started.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"docsSidebar",next:{title:"Software",permalink:"/docs/category/software"}},l={},s=[{value:"Software Setup",id:"software-setup",level:2},{value:"Hardware Setup",id:"hardware-setup",level:2},{value:"Additional Details",id:"additional-details",level:2},{value:"Join the Beepy Discord!",id:"join-the-beepy-discord",level:2},{value:"Matrix Bridge",id:"matrix-bridge",level:3}],d={toc:s},u="wrapper";function c(e){let{components:t,...r}=e;return(0,n.kt)(u,(0,a.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"getting-started"},"Getting Started"),(0,n.kt)("h2",{id:"software-setup"},"Software Setup"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},"Use the ",(0,n.kt)("a",{parentName:"p",href:"https://www.raspberrypi.com/software/"},"Raspberry Pi Imager tool")," to flash an SD card with the latest Raspberry Pi OS image"),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Choose OS - Raspberry Pi OS (other) - ",(0,n.kt)("strong",{parentName:"li"},(0,n.kt)("em",{parentName:"strong"},"Raspberry Pi OS Lite (32-bit) image"))),(0,n.kt)("li",{parentName:"ul"},"Click the gear icon \u2699 to set up a new user, WiFi, and enable SSH"))),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},"Update Beepy's firmware"),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Download the ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/sqfmi/i2c_puppet/releases/latest/download/i2c_puppet.uf2"},"latest firmware image")),(0,n.kt)("li",{parentName:"ul"},"Slide the power switch off (left if facing up)"),(0,n.kt)("li",{parentName:"ul"},"Connect the Beepy to your computer via USB-C"),(0,n.kt)("li",{parentName:"ul"},'While holding the "End Call" key (top right on the keypad), slide the power switch on'),(0,n.kt)("li",{parentName:"ul"},"The Beepy will present itself as a USB mass storage device, drag'n'drop the new firmware (i2c_puppet.uf2) into the drive and it will reboot with the new firmware"))),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},"SSH into the Pi and install driver packages. The LED will remain green until drivers are installed and the system has rebooted"))),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre"},'curl -s --compressed "https://ardangelo.github.io/beepy-ppa/KEY.gpg" | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/beepy.gpg >/dev/null \\\n&& sudo curl -s --compressed -o /etc/apt/sources.list.d/beepy.list "https://ardangelo.github.io/beepy-ppa/beepy.list" \\\n&& sudo apt update \\\n&& sudo apt-get -y install beepy-kbd sharp-drm \\\n&& sudo shutdown -r now\n')),(0,n.kt)("ol",{start:4},(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},"Your Beepy is now ready, enjoy!"),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Review the ",(0,n.kt)("a",{parentName:"li",href:"/docs/firmware/keyboard"},"default symbol keymap"))))),(0,n.kt)("h2",{id:"hardware-setup"},"Hardware Setup"),(0,n.kt)("p",null,"If you are installing your own Raspberry Pi Zero or any other SBC, make sure all the mounting pins are properly aligned to each hole before tightening the screws. ",(0,n.kt)("strong",{parentName:"p"},"If you cannot see the pin through a header hole, then it is not properly mounted"),'. You can move the board around until all the pins "click" into place.'),(0,n.kt)("img",{alt:"Beepy Raspberry Pi Zero mounting diagram",src:"/img/beepy-header-mount-diagram.jpg",width:"600"}),(0,n.kt)("p",null,"The USB-C port at the bottom powers and charges the Beepy. ",(0,n.kt)("strong",{parentName:"p"},"Do not power the Raspberry Pi Zero through its Micro-USB port (PWR IN).")),(0,n.kt)("h2",{id:"additional-details"},"Additional Details"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"In ",(0,n.kt)("inlineCode",{parentName:"li"},"/boot/cmdline.txt"),", edit ",(0,n.kt)("inlineCode",{parentName:"li"},"fbcon=font:VGA8x8")," to change the font/size. See ",(0,n.kt)("a",{parentName:"li",href:"https://www.kernel.org/doc/Documentation/fb/fbcon.txt"},"fbcon")," for more details"),(0,n.kt)("li",{parentName:"ul"},'Long holding the "End Call" key (5 seconds) will trigger the key ',(0,n.kt)("inlineCode",{parentName:"li"},"KEY_POWER")," and safely shutdown the Pi",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"The LED will turn red until OS shutdown has completed"),(0,n.kt)("li",{parentName:"ul"},"Wait another few seconds until the disk activity light on the Pi has turned off to ensure disks are synced"))),(0,n.kt)("li",{parentName:"ul"},'After shutting down using the "End Call" key, holding the key for 1 second will turn the Pi back on')),(0,n.kt)("h2",{id:"join-the-beepy-discord"},"Join the Beepy Discord!"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://discord.gg/QERrSferdF"},(0,n.kt)("strong",{parentName:"a"},"Discord Invite"))),(0,n.kt)("h3",{id:"matrix-bridge"},"Matrix Bridge"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://matrix.to/#/#beepberry-general:beeper.com"},(0,n.kt)("strong",{parentName:"a"},"#beepy-general"))),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://matrix.to/#/#beepberry-dev:beeper.com"},(0,n.kt)("strong",{parentName:"a"},"#beepy-dev"))),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://matrix.to/#/#beepberry-apps:beeper.com"},(0,n.kt)("strong",{parentName:"a"},"#beepy-apps"))),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://matrix.to/#/#beepberry-hw:beeper.com"},(0,n.kt)("strong",{parentName:"a"},"#beepy-hw"))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d589d3a7.f7031d1d.js b/assets/js/d589d3a7.f7031d1d.js deleted file mode 100644 index 6824a89..0000000 --- a/assets/js/d589d3a7.f7031d1d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[162],{3905:(e,t,r)=>{r.d(t,{Zo:()=>d,kt:()=>h});var a=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function i(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=a.createContext({}),s=function(e){var t=a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},d=function(e){var t=s(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,l=e.parentName,d=p(e,["components","mdxType","originalType","parentName"]),u=s(r),m=n,h=u["".concat(l,".").concat(m)]||u[m]||c[m]||o;return r?a.createElement(h,i(i({ref:t},d),{},{components:r})):a.createElement(h,i({ref:t},d))}));function h(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=m;var p={};for(var l in t)hasOwnProperty.call(t,l)&&(p[l]=t[l]);p.originalType=e,p[u]="string"==typeof e?e:n,i[1]=p;for(var s=2;s{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>p,toc:()=>s});var a=r(7462),n=(r(7294),r(3905));const o={sidebar_position:1},i="Getting Started",p={unversionedId:"getting-started",id:"getting-started",title:"Getting Started",description:"Software Setup",source:"@site/docs/getting-started.md",sourceDirName:".",slug:"/getting-started",permalink:"/docs/getting-started",draft:!1,editUrl:"https://github.com/sqfmi/beepy-docs/blob/main/docs/getting-started.md",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"docsSidebar",next:{title:"Software",permalink:"/docs/category/software"}},l={},s=[{value:"Software Setup",id:"software-setup",level:2},{value:"Hardware Setup",id:"hardware-setup",level:2},{value:"Firmware Update",id:"firmware-update",level:2},{value:"Additional Details",id:"additional-details",level:2},{value:"Join the Beepy Discord!",id:"join-the-beepy-discord",level:2},{value:"Matrix Bridge",id:"matrix-bridge",level:3}],d={toc:s},u="wrapper";function c(e){let{components:t,...r}=e;return(0,n.kt)(u,(0,a.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"getting-started"},"Getting Started"),(0,n.kt)("h2",{id:"software-setup"},"Software Setup"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},"Use the ",(0,n.kt)("a",{parentName:"p",href:"https://www.raspberrypi.com/software/"},"Raspberry Pi Imager tool")," to flash an SD card with the latest Raspberry Pi OS image"),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Choose the ",(0,n.kt)("strong",{parentName:"li"},(0,n.kt)("em",{parentName:"strong"},"Raspberry Pi OS Lite (32-bit) image"))),(0,n.kt)("li",{parentName:"ul"},"Click the gear icon \u2699 to also setup WiFi and enable SSH"))),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},"SSH into the Pi and update the kernel and reboot"))),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre"},"sudo apt-get update && sudo apt-get install raspberrypi-kernel\n")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre"},"sudo shutdown -r now\n")),(0,n.kt)("ol",{start:3},(0,n.kt)("li",{parentName:"ol"},"After reboot, SSH into the Pi again and run the setup script")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre"},"curl -s https://raw.githubusercontent.com/beeper/beepy/main/raspberrypi/setup.sh | bash\n")),(0,n.kt)("ol",{start:4},(0,n.kt)("li",{parentName:"ol"},"Your Beepy is now ready, enjoy!")),(0,n.kt)("h2",{id:"hardware-setup"},"Hardware Setup"),(0,n.kt)("p",null,"If you are installing your own Raspberry Pi Zero W or any other SBC, make sure all the mounting pins are properly aligned to each hole before tightening the screws. ",(0,n.kt)("strong",{parentName:"p"},"If you cannot see the pin through a header hole, then it is not properly mounted"),'. You can move the board around until all the pins "click" into place.'),(0,n.kt)("img",{alt:"Beepy Raspberry Pi Zero mounting diagram",src:"/img/beepy-header-mount-diagram.jpg",width:"600"}),(0,n.kt)("p",null,"The USB-C port at the bottom powers and charges the Beepy. ",(0,n.kt)("strong",{parentName:"p"},"Do not power the Raspberry Pi Zero through its Micro-USB port (PWR IN).")),(0,n.kt)("h2",{id:"firmware-update"},"Firmware Update"),(0,n.kt)("p",null,"To update the Beepy's firmware:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Slide the power switch off (left if facing up)"),(0,n.kt)("li",{parentName:"ol"},"Connect the Beepy to your computer via USB-C"),(0,n.kt)("li",{parentName:"ol"},'While holding the "End Call" key (top right on the keypad), slide the power switch on'),(0,n.kt)("li",{parentName:"ol"},"The Beepy will present itself as a USB mass storage device, drag'n'drop the new firmware (","*",".uf2) into the drive and it will reboot with the new firmware")),(0,n.kt)("p",null,"The latest Beepy firmware can be found here: ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/sqfmi/i2c_puppet/releases/latest/download/i2c_puppet.uf2"},(0,n.kt)("strong",{parentName:"a"},"i2c_puppet.uf2"))),(0,n.kt)("h2",{id:"additional-details"},"Additional Details"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"In ",(0,n.kt)("inlineCode",{parentName:"li"},"/boot/cmdline.txt"),", edit ",(0,n.kt)("inlineCode",{parentName:"li"},"fbcon=font:VGA8x8")," to change the font/size. See ",(0,n.kt)("a",{parentName:"li",href:"https://www.kernel.org/doc/Documentation/fb/fbcon.txt"},"fbcon")," for more details"),(0,n.kt)("li",{parentName:"ul"},'Long holding the "End Call" key (~3 seconds) will trigger the key ',(0,n.kt)("inlineCode",{parentName:"li"},"KEY_POWER")," and safely shutdown the Pi")),(0,n.kt)("h2",{id:"join-the-beepy-discord"},"Join the Beepy Discord!"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://discord.gg/QERrSferdF"},(0,n.kt)("strong",{parentName:"a"},"Discord Invite"))),(0,n.kt)("h3",{id:"matrix-bridge"},"Matrix Bridge"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://matrix.to/#/#beepberry-general:beeper.com"},(0,n.kt)("strong",{parentName:"a"},"#beepy-general"))),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://matrix.to/#/#beepberry-dev:beeper.com"},(0,n.kt)("strong",{parentName:"a"},"#beepy-dev"))),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://matrix.to/#/#beepberry-apps:beeper.com"},(0,n.kt)("strong",{parentName:"a"},"#beepy-apps"))),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://matrix.to/#/#beepberry-hw:beeper.com"},(0,n.kt)("strong",{parentName:"a"},"#beepy-hw"))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f3cedf5b.b27a675d.js b/assets/js/f3cedf5b.b27a675d.js new file mode 100644 index 0000000..e5a84d6 --- /dev/null +++ b/assets/js/f3cedf5b.b27a675d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[713],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>k});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function l(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),d=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},s=function(e){var t=d(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},c=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,l=e.originalType,p=e.parentName,s=o(e,["components","mdxType","originalType","parentName"]),u=d(r),c=a,k=u["".concat(p,".").concat(c)]||u[c]||m[c]||l;return r?n.createElement(k,i(i({ref:t},s),{},{components:r})):n.createElement(k,i({ref:t},s))}));function k(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=r.length,i=new Array(l);i[0]=c;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[u]="string"==typeof e?e:a,i[1]=o;for(var d=2;d{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>m,frontMatter:()=>l,metadata:()=>o,toc:()=>d});var n=r(7462),a=(r(7294),r(3905));const l={sidebar_position:3},i="RGB LED",o={unversionedId:"software/linux-drivers",id:"software/linux-drivers",title:"RGB LED",description:"The following sysfs entries are available under /sys/firmware/beepy:",source:"@site/docs/software/linux-drivers.md",sourceDirName:"software",slug:"/software/linux-drivers",permalink:"/docs/software/linux-drivers",draft:!1,editUrl:"https://github.com/sqfmi/beepy-docs/blob/main/docs/software/linux-drivers.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"docsSidebar",previous:{title:"OS Image",permalink:"/docs/software/os-image"},next:{title:"Firmware",permalink:"/docs/category/firmware"}},p={},d=[{value:"RGB LED over I2C",id:"rgb-led-over-i2c",level:2},{value:"Example",id:"example",level:2}],s={toc:d},u="wrapper";function m(e){let{components:t,...r}=e;return(0,a.kt)(u,(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"rgb-led"},"RGB LED"),(0,a.kt)("p",null,"The following sysfs entries are available under ",(0,a.kt)("inlineCode",{parentName:"p"},"/sys/firmware/beepy"),":"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"led"),": 0 to disable LED, 1 to enable. Write-only"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"led_red"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"led_green"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"led_blue"),": set LED color intensity from 0 to 255. Write- only")),(0,a.kt)("h2",{id:"rgb-led-over-i2c"},"RGB LED over I2C"),(0,a.kt)("p",null,"The RGB LED is connected to the RP2040. When the keyboard driver is unloaded via ",(0,a.kt)("inlineCode",{parentName:"p"},"rmmod beepy-kbd"),", they can be controlled directly by the Pi via ",(0,a.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/I%C2%B2C"},"I\xb2C"),"."),(0,a.kt)("p",null,"The LED color on the Beepy is exposed on I2C bus 1 at the chip address ",(0,a.kt)("inlineCode",{parentName:"p"},"0x1F"),"."),(0,a.kt)("p",null,"Controls are available at the following specific data addresses:"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"Function"),(0,a.kt)("th",{parentName:"tr",align:null},"Read"),(0,a.kt)("th",{parentName:"tr",align:null},"Write"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Power"),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0x20")),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0xA0"))),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Red"),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0x21")),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0xA1"))),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Green"),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0x22")),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0xA2"))),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Blue"),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0x23")),(0,a.kt)("td",{parentName:"tr",align:null},(0,a.kt)("inlineCode",{parentName:"td"},"0xA3"))))),(0,a.kt)("p",null,"To get/set the LED color on the Beepy, you can read/write to the above registers over I2C. The values are in the range of ",(0,a.kt)("inlineCode",{parentName:"p"},"0x00")," - ",(0,a.kt)("inlineCode",{parentName:"p"},"0xFF"),"."),(0,a.kt)("p",null,(0,a.kt)("em",{parentName:"p"},"Note: write addresses are the read address masked with ",(0,a.kt)("inlineCode",{parentName:"em"},"0x80"),".")),(0,a.kt)("p",null,"A value of 0 in the power register represents the LED's off state, while any other value represents on."),(0,a.kt)("h2",{id:"example"},"Example"),(0,a.kt)("p",null,"To set the RGB values to red and turn the LED on from the command line:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"# Format:\n# i2cset -y [i2cbus] [chip-address] [data-address] value\ni2cset -y 1 0x1F 0xA1 0xFF\ni2cset -y 1 0x1F 0xA2 0x00\ni2cset -y 1 0x1F 0xA3 0x00\ni2cset -y 1 0x1F 0xA0 0xFF\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f3cedf5b.dd5a4b2d.js b/assets/js/f3cedf5b.dd5a4b2d.js deleted file mode 100644 index c6f80fe..0000000 --- a/assets/js/f3cedf5b.dd5a4b2d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkbeepy=self.webpackChunkbeepy||[]).push([[713],{3905:(e,r,t)=>{t.d(r,{Zo:()=>c,kt:()=>f});var o=t(7294);function n(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function i(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);r&&(o=o.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,o)}return t}function a(e){for(var r=1;r=0||(n[t]=e[t]);return n}(e,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(n[t]=e[t])}return n}var p=o.createContext({}),s=function(e){var r=o.useContext(p),t=r;return e&&(t="function"==typeof e?e(r):a(a({},r),e)),t},c=function(e){var r=s(e.components);return o.createElement(p.Provider,{value:r},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var r=e.children;return o.createElement(o.Fragment,{},r)}},y=o.forwardRef((function(e,r){var t=e.components,n=e.mdxType,i=e.originalType,p=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=s(t),y=n,f=u["".concat(p,".").concat(y)]||u[y]||d[y]||i;return t?o.createElement(f,a(a({ref:r},c),{},{components:t})):o.createElement(f,a({ref:r},c))}));function f(e,r){var t=arguments,n=r&&r.mdxType;if("string"==typeof e||n){var i=t.length,a=new Array(i);a[0]=y;var l={};for(var p in r)hasOwnProperty.call(r,p)&&(l[p]=r[p]);l.originalType=e,l[u]="string"==typeof e?e:n,a[1]=l;for(var s=2;s{t.r(r),t.d(r,{assets:()=>p,contentTitle:()=>a,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var o=t(7462),n=(t(7294),t(3905));const i={sidebar_position:2},a="Linux Drivers",l={unversionedId:"software/linux-drivers",id:"software/linux-drivers",title:"Linux Drivers",description:"Linux drivers for the Beepy",source:"@site/docs/software/linux-drivers.md",sourceDirName:"software",slug:"/software/linux-drivers",permalink:"/docs/software/linux-drivers",draft:!1,editUrl:"https://github.com/sqfmi/beepy-docs/blob/main/docs/software/linux-drivers.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"docsSidebar",previous:{title:"OS Image",permalink:"/docs/software/os-image"},next:{title:"Firmware",permalink:"/docs/category/firmware"}},p={},s=[{value:"Display",id:"display",level:2},{value:"Keyboard",id:"keyboard",level:2},{value:"How to customize keyboard layout",id:"how-to-customize-keyboard-layout",level:3},{value:"Peripherals",id:"peripherals",level:2},{value:"Power Control",id:"power-control",level:3},{value:"Battery Level",id:"battery-level",level:3},{value:"RGB LED Control",id:"rgb-led-control",level:3}],c={toc:s},u="wrapper";function d(e){let{components:r,...t}=e;return(0,n.kt)(u,(0,o.Z)({},c,t,{components:r,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"linux-drivers"},"Linux Drivers"),(0,n.kt)("p",null,"Linux drivers for the Beepy"),(0,n.kt)("h2",{id:"display"},"Display"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://github.com/w4ilun/Sharp-Memory-LCD-Kernel-Driver"},"Sharp Memory LCD Kernel Drive")),(0,n.kt)("h2",{id:"keyboard"},"Keyboard"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://github.com/w4ilun/bbqX0kbd_driver"},"BBQX0KBD i2c Keyboard Device Driver")),(0,n.kt)("h3",{id:"how-to-customize-keyboard-layout"},"How to customize keyboard layout"),(0,n.kt)("p",null,"To Do"),(0,n.kt)("h2",{id:"peripherals"},"Peripherals"),(0,n.kt)("p",null,"To Do - This driver provides an interface to read/write to the peripherals on the Beepy"),(0,n.kt)("h3",{id:"power-control"},"Power Control"),(0,n.kt)("p",null,"To Do - Controlling the power switch and detecting the shutdown signal"),(0,n.kt)("h3",{id:"battery-level"},"Battery Level"),(0,n.kt)("p",null,"To Do - Reading from the ADC on the RP2040"),(0,n.kt)("h3",{id:"rgb-led-control"},"RGB LED Control"),(0,n.kt)("p",null,"To Do - LED control via userspace application"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.5ced46a9.js b/assets/js/runtime~main.5ced46a9.js deleted file mode 100644 index 6a57ffb..0000000 --- a/assets/js/runtime~main.5ced46a9.js +++ /dev/null @@ -1 +0,0 @@ -(()=>{"use strict";var e,t,r,a,o,f={},n={};function d(e){var t=n[e];if(void 0!==t)return t.exports;var r=n[e]={id:e,loaded:!1,exports:{}};return f[e].call(r.exports,r,r.exports,d),r.loaded=!0,r.exports}d.m=f,d.c=n,e=[],d.O=(t,r,a,o)=>{if(!r){var f=1/0;for(i=0;i=o)&&Object.keys(d.O).every((e=>d.O[e](r[b])))?r.splice(b--,1):(n=!1,o0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[r,a,o]},d.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return d.d(t,{a:t}),t},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,d.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var o=Object.create(null);d.r(o);var f={};t=t||[null,r({}),r([]),r(r)];for(var n=2&a&&e;"object"==typeof n&&!~t.indexOf(n);n=r(n))Object.getOwnPropertyNames(n).forEach((t=>f[t]=()=>e[t]));return f.default=()=>e,d.d(o,f),o},d.d=(e,t)=>{for(var r in t)d.o(t,r)&&!d.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},d.f={},d.e=e=>Promise.all(Object.keys(d.f).reduce(((t,r)=>(d.f[r](e,t),t)),[])),d.u=e=>"assets/js/"+({28:"4911bd28",50:"6d6b0c7d",53:"935f2afb",85:"1f391b9e",142:"468be650",162:"d589d3a7",195:"c4f5d8e4",253:"64baaaeb",340:"3abff280",414:"393be207",434:"641522b2",514:"1be78505",584:"0dcbb7ac",615:"8efe2991",636:"076cabff",713:"f3cedf5b",728:"9ecc4874",817:"14eb3368",828:"3ac5b8de",836:"0480b142",858:"8a3a63f7",908:"476425e3",918:"17896441",985:"78a7c784"}[e]||e)+"."+{28:"69eafd0e",50:"b5d37d9d",53:"ff46232f",85:"a2ea3d64",142:"d782fe3f",162:"f7031d1d",195:"7178cc93",253:"564c28e0",340:"651b7c07",414:"73902c4f",434:"778c3aba",514:"cce27128",584:"45b41684",615:"9bac1428",636:"1638b735",666:"3e2d3414",713:"dd5a4b2d",728:"847faa25",817:"1a876807",828:"e55c6278",836:"37221a00",858:"b98318ad",908:"3781a8f8",918:"cf34640d",972:"410a0c09",985:"f7ed345a"}[e]+".js",d.miniCssF=e=>{},d.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),d.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a={},o="beepy:",d.l=(e,t,r,f)=>{if(a[e])a[e].push(t);else{var n,b;if(void 0!==r)for(var c=document.getElementsByTagName("script"),i=0;i{n.onerror=n.onload=null,clearTimeout(s);var o=a[e];if(delete a[e],n.parentNode&&n.parentNode.removeChild(n),o&&o.forEach((e=>e(r))),t)return t(r)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:n}),12e4);n.onerror=l.bind(null,n.onerror),n.onload=l.bind(null,n.onload),b&&document.head.appendChild(n)}},d.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},d.p="/",d.gca=function(e){return e={17896441:"918","4911bd28":"28","6d6b0c7d":"50","935f2afb":"53","1f391b9e":"85","468be650":"142",d589d3a7:"162",c4f5d8e4:"195","64baaaeb":"253","3abff280":"340","393be207":"414","641522b2":"434","1be78505":"514","0dcbb7ac":"584","8efe2991":"615","076cabff":"636",f3cedf5b:"713","9ecc4874":"728","14eb3368":"817","3ac5b8de":"828","0480b142":"836","8a3a63f7":"858","476425e3":"908","78a7c784":"985"}[e]||e,d.p+d.u(e)},(()=>{var e={303:0,532:0};d.f.j=(t,r)=>{var a=d.o(e,t)?e[t]:void 0;if(0!==a)if(a)r.push(a[2]);else if(/^(303|532)$/.test(t))e[t]=0;else{var o=new Promise(((r,o)=>a=e[t]=[r,o]));r.push(a[2]=o);var f=d.p+d.u(t),n=new Error;d.l(f,(r=>{if(d.o(e,t)&&(0!==(a=e[t])&&(e[t]=void 0),a)){var o=r&&("load"===r.type?"missing":r.type),f=r&&r.target&&r.target.src;n.message="Loading chunk "+t+" failed.\n("+o+": "+f+")",n.name="ChunkLoadError",n.type=o,n.request=f,a[1](n)}}),"chunk-"+t,t)}},d.O.j=t=>0===e[t];var t=(t,r)=>{var a,o,f=r[0],n=r[1],b=r[2],c=0;if(f.some((t=>0!==e[t]))){for(a in n)d.o(n,a)&&(d.m[a]=n[a]);if(b)var i=b(d)}for(t&&t(r);c{"use strict";var e,t,r,a,o,f={},n={};function b(e){var t=n[e];if(void 0!==t)return t.exports;var r=n[e]={id:e,loaded:!1,exports:{}};return f[e].call(r.exports,r,r.exports,b),r.loaded=!0,r.exports}b.m=f,b.c=n,e=[],b.O=(t,r,a,o)=>{if(!r){var f=1/0;for(i=0;i=o)&&Object.keys(b.O).every((e=>b.O[e](r[d])))?r.splice(d--,1):(n=!1,o0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[r,a,o]},b.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return b.d(t,{a:t}),t},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,b.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var o=Object.create(null);b.r(o);var f={};t=t||[null,r({}),r([]),r(r)];for(var n=2&a&&e;"object"==typeof n&&!~t.indexOf(n);n=r(n))Object.getOwnPropertyNames(n).forEach((t=>f[t]=()=>e[t]));return f.default=()=>e,b.d(o,f),o},b.d=(e,t)=>{for(var r in t)b.o(t,r)&&!b.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},b.f={},b.e=e=>Promise.all(Object.keys(b.f).reduce(((t,r)=>(b.f[r](e,t),t)),[])),b.u=e=>"assets/js/"+({28:"4911bd28",50:"6d6b0c7d",53:"935f2afb",85:"1f391b9e",142:"468be650",162:"d589d3a7",195:"c4f5d8e4",253:"64baaaeb",340:"3abff280",414:"393be207",434:"641522b2",514:"1be78505",584:"0dcbb7ac",615:"8efe2991",636:"076cabff",713:"f3cedf5b",728:"9ecc4874",817:"14eb3368",828:"3ac5b8de",836:"0480b142",858:"8a3a63f7",908:"476425e3",918:"17896441",985:"78a7c784"}[e]||e)+"."+{28:"69eafd0e",50:"b5d37d9d",53:"4023d4de",85:"a2ea3d64",142:"d782fe3f",162:"2e5b9b0a",195:"7178cc93",253:"2dd6e154",340:"651b7c07",414:"73902c4f",434:"dae1daae",514:"cce27128",584:"45b41684",615:"9bac1428",636:"bd453fea",666:"3e2d3414",713:"b27a675d",728:"847faa25",817:"1a876807",828:"d45c63d2",836:"0d696442",858:"b98318ad",908:"3781a8f8",918:"cf34640d",972:"410a0c09",985:"8ac9c576"}[e]+".js",b.miniCssF=e=>{},b.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),b.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a={},o="beepy:",b.l=(e,t,r,f)=>{if(a[e])a[e].push(t);else{var n,d;if(void 0!==r)for(var c=document.getElementsByTagName("script"),i=0;i{n.onerror=n.onload=null,clearTimeout(s);var o=a[e];if(delete a[e],n.parentNode&&n.parentNode.removeChild(n),o&&o.forEach((e=>e(r))),t)return t(r)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:n}),12e4);n.onerror=l.bind(null,n.onerror),n.onload=l.bind(null,n.onload),d&&document.head.appendChild(n)}},b.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},b.p="/",b.gca=function(e){return e={17896441:"918","4911bd28":"28","6d6b0c7d":"50","935f2afb":"53","1f391b9e":"85","468be650":"142",d589d3a7:"162",c4f5d8e4:"195","64baaaeb":"253","3abff280":"340","393be207":"414","641522b2":"434","1be78505":"514","0dcbb7ac":"584","8efe2991":"615","076cabff":"636",f3cedf5b:"713","9ecc4874":"728","14eb3368":"817","3ac5b8de":"828","0480b142":"836","8a3a63f7":"858","476425e3":"908","78a7c784":"985"}[e]||e,b.p+b.u(e)},(()=>{var e={303:0,532:0};b.f.j=(t,r)=>{var a=b.o(e,t)?e[t]:void 0;if(0!==a)if(a)r.push(a[2]);else if(/^(303|532)$/.test(t))e[t]=0;else{var o=new Promise(((r,o)=>a=e[t]=[r,o]));r.push(a[2]=o);var f=b.p+b.u(t),n=new Error;b.l(f,(r=>{if(b.o(e,t)&&(0!==(a=e[t])&&(e[t]=void 0),a)){var o=r&&("load"===r.type?"missing":r.type),f=r&&r.target&&r.target.src;n.message="Loading chunk "+t+" failed.\n("+o+": "+f+")",n.name="ChunkLoadError",n.type=o,n.request=f,a[1](n)}}),"chunk-"+t,t)}},b.O.j=t=>0===e[t];var t=(t,r)=>{var a,o,f=r[0],n=r[1],d=r[2],c=0;if(f.some((t=>0!==e[t]))){for(a in n)b.o(n,a)&&(b.m[a]=n[a]);if(d)var i=d(b)}for(t&&t(r);c - +

Case Designs & 3D Models

Beepy STEP model

beepy-v1.step

Case Designs

Below are some case designs for the Beepy. If you have any designs you'd like to share with the community, please submit a Pull Request to this repo (include a brief description and some renders/pics): https://github.com/sqfmi/beepy-hardware.

V1

V1 design of a Beepy case, suitable for 3D printing, requires some tweaking for a proper fit. Screws are M2.5x5mm.

STLs and STEP model

Slim Flat

Slim, flat, minimal case for the Beepy

STLs and STEP model

CNC Case

Coming Soon

Transparent Plastic

Coming Soon

- + \ No newline at end of file diff --git a/docs/category/firmware.html b/docs/category/firmware.html index 6ac1557..1d5d8fe 100644 --- a/docs/category/firmware.html +++ b/docs/category/firmware.html @@ -7,13 +7,13 @@ - + - + + \ No newline at end of file diff --git a/docs/category/hardware.html b/docs/category/hardware.html index ec24b78..d5519c1 100644 --- a/docs/category/hardware.html +++ b/docs/category/hardware.html @@ -7,13 +7,13 @@ - + - + \ No newline at end of file diff --git a/docs/category/software.html b/docs/category/software.html index 58064f8..23d8fda 100644 --- a/docs/category/software.html +++ b/docs/category/software.html @@ -7,13 +7,13 @@ - + - + + \ No newline at end of file diff --git a/docs/faq.html b/docs/faq.html index 05b1d3e..b381e58 100644 --- a/docs/faq.html +++ b/docs/faq.html @@ -7,13 +7,13 @@ - +
-

FAQ

What's a Beepy?

Beepy is a portable computing device, with a beautiful high contrast, high resolution display, and a tactile keyboard + touchpad, it is the ultimate everyday hacking gadget.

Powered by the Raspberry Pi Zero W (or any other compatible SBCs), you can use it as a chat device (supporting all chat networks on Beeper e.g. iMessage/WhatsApp/Signal/etc. ), or use it as a hackable handheld cyberdeck, running any Linux application that runs on the Pi.

What is Beeper?

Beeper is a universal chat app. It’s a single app to chat with friends on 15 different chat networks.

Learn more at https://www.beeper.com

Does it have LTE/4G/5G/LoRA/Zigbee/GPS/etc. connectivity?

Additional connectivity can be expanded via USB or GPIO ports.

Does Beepy come with a case?

No, but you can 3D print your own case. We'll be offering a case soon. Beepy can also be used as is (with the addition of a rubber band).

My Beepy LED is always on

You may be running an older version of the firmware, follow these instructions to update the firmware.

I just opened the box and have no idea what to do

First you need to follow the instructions to flash an SD card with the OS, then make sure the battery is charged by plugging in the USB C port and flipping the power switch.

Help, the screen is stuck displaying a very striking static pattern, even after I've flashed the SD card

Follow the Getting Started guide and run the install script before the screen can display anything.

I set my WiFi SSID and password in the Pi imager but it can't seem to connect

The Pi Zero W only supports 2.4GHz WiFi networks. Make sure you're not trying to connect to a 5GHz network.

I prefer a white background with black text

You can invert the display mode by running echo -e '\033[?5h' > /dev/tty1. You can append this line to your .bashrc to set it as the default.

- +

FAQ

What's a Beepy?

Beepy is a portable computing device, with a beautiful high contrast, high resolution display, and a tactile keyboard + touchpad, it is the ultimate everyday hacking gadget.

Powered by the Raspberry Pi Zero W (or any other compatible SBCs), you can use it as a chat device (supporting all chat networks on Beeper e.g. iMessage/WhatsApp/Signal/etc. ), or use it as a hackable handheld cyberdeck, running any Linux application that runs on the Pi.

What is Beeper?

Beeper is a universal chat app. It’s a single app to chat with friends on 15 different chat networks.

Learn more at https://www.beeper.com

Does it have LTE/4G/5G/LoRA/Zigbee/GPS/etc. connectivity?

Additional connectivity can be expanded via USB or GPIO ports.

Does Beepy come with a case?

No, but you can 3D print your own case. We'll be offering a case soon. Beepy can also be used as is (with the addition of a rubber band).

My Beepy LED is always on

You may be running an older version of the firmware, follow the firmware flashing instructions to update the firmware.

I just opened the box and have no idea what to do

First you need to follow the instructions to flash an SD card with the OS, then make sure the battery is charged by plugging in the USB C port and flipping the power switch.

Help, the screen is stuck displaying a very striking static pattern, even after I've flashed the SD card

Follow the Getting Started guide and run the install script before the screen can display anything.

I set my WiFi SSID and password in the Pi imager but it can't seem to connect

The Pi Zero W only supports 2.4GHz WiFi networks. Make sure you're not trying to connect to a 5GHz network.

I prefer a white background with black text

You can invert the display mode by running echo 1 | sudo tee /sys/module/sharp_drm/parameters/mono_invert

+ \ No newline at end of file diff --git a/docs/firmware/keyboard.html b/docs/firmware/keyboard.html index 96560ba..cf5a42f 100644 --- a/docs/firmware/keyboard.html +++ b/docs/firmware/keyboard.html @@ -7,13 +7,13 @@ - +
-

Keyboard Firmware

The keyboard firmware is a fork of i2c_puppet with a few additional features to support the Beepy.

You can download the latest version of the Beepy firmware here: https://github.com/sqfmi/i2c_puppet/releases/latest/download/i2c_puppet.uf2

Custom Keymap

To Do - How to customize keymap

Custom Trackpad

To Do - How to customize trackpad function (i.e. mouse, arrow keys, scroll. etc)

Backlight Control

To Do - Keypad backlight control

- +

Keyboard Firmware

The keyboard firmware is a fork of i2c_puppet with a few additional features to support the Beepy.

You can download the latest version of the Beepy firmware here: https://github.com/sqfmi/i2c_puppet/releases/latest/download/i2c_puppet.uf2

Basic key mappings

  • Call is mapped to Control
  • "Berry" key is mapped to Tmux prefix (customize the prefix in the keymap file)
  • Touchpad click enters Meta mode (see the section on Meta mode). Double click enters touchpad scroll mode
  • Back is mapped to Escape
  • Holding "End Call" safely shuts down the Pi
  • Physical Alt is mapped to symbols printed on the keycap
  • Symbol is mapped to AltGr (Right Alt), mapped to more symbols via the keymap file
  • Physical Alt + Enter is mapped to Tab

Alt and Sym modifiers

The alternate symbols printed directly on the Beepy keys are triggered by pressing the physical Alt key, then the key on which the symbol is printed. For additional symbols not printed directly on the keys, the Sym key is used.

Symbol key map

Sticky modifier keys

The keyboard driver supports sticky modifier keys. Holding a modifier key (Shift, Alt, Sym) while typing an alpha keys will apply the modifier to all alpha keys until the modifier is released.

One press and release of the modifier will enter sticky mode, applying the modifier to the next alpha key only. If the same modifier key is pressed and released again in sticky mode, it will be canceled.

Visual mode indicators are drawn in the top right corner of the display, with indicators for Shift, Physical Alt, Control, Alt, Symbol, and Meta mode.

Meta mode

Meta mode is a modal layer that assists in rapidly moving the cursor and scrolling with single keypresses. To enter Meta mode, click the touchpad button once. Then, the following keymap is applied, staying in Meta mode until dismissed:

  • E: up, S: down, W: left, D: right
    • Why not WASD? This way, you can place your thumb in the middle of all four of these keys, and more fluidly move the cursor without mistyping
  • R: Home, F: End, O: PageUp, P: PageDown
  • Q: Alt+Left (back one word), A: Alt+Right (forward one word)
  • T: Tab (dismisses Meta mode)
  • X: Apply Control to next key (dismisses Meta mode)
  • C: Apply Alt to next key (dismisses Meta mode)
  • 0: Toggle display black/white inversion
  • N: Decrease keyboard backlight brightness
  • M: Increase keyboard backlight brightness
  • $: Toggle keyboard backlight
  • Touchpad click (while in Meta mode): Enable touchpad scroll mode (up and down arrrow keys)
    • Other Meta mode keys will continue to work as normal
    • Exiting meta mode will also exit touchpad scroll mode
    • Subsequent clicks of the touchpad will type Enter.
  • Esc: ("Back" button): exit meta mode

Typing any other key while in Meta mode will exit Meta mode and send the key as if it was typed normally.

sysfs Interface

The following sysfs entries are available under /sys/firmware/beepy:

  • led: 0 to disable LED, 1 to enable. Write-only
  • led_red, led_green, led_blue: set LED color intensity from 0 to 255. Write- only
  • keyboard_backlight: set keyboard brightness from 0 to 255. Write-only
  • battery_raw: raw numerical battery level as reported by firmware. Read-only
  • battery_volts: battery voltage estimation. Read-only
  • battery_percent: battery percentage estimation. Read-only

Module parameters

Write to /sys/module/beepy_kbd/parameters/<param> to set, or unload and reload the module with beepy-kbd param=val.

  • touchpad: one of meta or keys
    • meta: default, will use the touchpad button to enable or disable Meta mode
    • keys: touchpad always on, swiping sends arrow keys, clicking sends Enter

Custom Keymap

The Alt and Sym keymaps and the Tmux prefix sent by the "Berry" key can be edited in the file /usr/share/kbd/keymaps/beepy-kbd.map. To reapply the keymap without rebooting, run loadkeys /usr/share/kbd/keymaps/beepy-kbd.map.

+ \ No newline at end of file diff --git a/docs/firmware/power.html b/docs/firmware/power.html index 3cdc8aa..00b72a7 100644 --- a/docs/firmware/power.html +++ b/docs/firmware/power.html @@ -7,13 +7,13 @@ - +
-

Power Management & Battery

The onboard RP2040 controls the power to the Pi, as well as measuring the battery level with its ADC. The Beepy can be safely shutdown by holding the "End Call" button on the keyboard.

Examples

Battery Level Reporting

To read the battery voltage on the Beepy, you can read from the register 0x17 over I2C.

This is a read-only register, it is 2 bytes in size.

It returns a 16 bit value from the ADC (VREF = 3.3V). On the Beepy there is a voltage divider, so the battery voltage can be calculated as VBAT = 3.3V * (value/4095) * 2.

Command-line Example

First release the I2C bus from the keyboard driver, then read 1 word (2 bytes) from I2C bus 1, address 0x1F, register 0x17

sudo modprobe -r bbqX0kbd
sudo i2cget -y 1 0x1F 0x17 w

Script

Script to calculate the battery voltage

#!/bin/sh

sudo modprobe -r bbqX0kbd
V=$(i2cget -y 1 0x1F 0x17 w | sed s/0x// | tr '[:lower:]' '[:upper:]')
sudo modprobe bbqX0kbd

V=$(echo "obase=10; ibase=16; $V" | bc)
echo "$V * 3.3 * 2 / 4095" | bc -l | cut -c1-5

Sleep/Wake

To Do

- +

Power Management & Battery

The onboard RP2040 controls the power to the Pi, as well as measuring the battery level with its ADC. The Beepy can be safely shutdown by holding the "End Call" button on the keyboard.

To battery voltage on the Beepy can read from the register 0x17 over I2C. This is a read-only register, it is 2 bytes in size. It returns a 16 bit value from the ADC (VREF = 3.3V). There is a voltage divider so the battery voltage can be calculated as VBAT = 3.3V (value/4095) 2.

Examples

Battery Level Reporting

The following sysfs entries are available under /sys/firmware/beepy to read the system battery level:

  • battery_raw: raw numerical battery level as reported by firmware. Read-only
  • battery_volts: battery voltage estimation. Read-only
  • battery_percent: battery percentage estimation. Read-only

Script

The following script is an example to calculate a voltage estimation from the raw battery level:

#!/bin/sh

V=$(cat /sys/firmware/beepy/battery_raw)

V=$(echo "obase=10; ibase=16; $V" | bc)
echo "$V * 3.3 * 2 / 4095" | bc -l | cut -c1-5

Sleep/Wake

To Do

+ \ No newline at end of file diff --git a/docs/firmware/rgb-led.html b/docs/firmware/rgb-led.html index e4a29c9..318cf8e 100644 --- a/docs/firmware/rgb-led.html +++ b/docs/firmware/rgb-led.html @@ -3,18 +3,17 @@ -RGB LED | Beepy +RGB LED | Beepy - +
-

RGB LED

The RGB LED is connected to the RP2040 and can be controlled by the Pi via I²C.

The LED color on the Beepy is exposed on I2C bus 1 at the chip address 0x1F.

Controls are available at the following specific data addresses:

FunctionReadWrite
Power0x200xA0
Red0x210xA1
Green0x220xA2
Blue0x230xA3

======= -To get/set the LED color on the Beepy, you can read/write to the following registers over I2C. The values can be 0x00 - 0xFF.

Note: write addresses are the read address masked with 0x80.

Valid RGB values are on the range 0x00 to 0xFF.

A value of 0 in the power register represents the LED's off state, while any other value represents on.

Example

To set the RGB values to red and turn the LED on from the command line:

# Format:
# i2cset -y [i2cbus] [chip-address] [data-address] value
i2cset -y 1 0x1F 0xA1 0xFF
i2cset -y 1 0x1F 0xA2 0x00
i2cset -y 1 0x1F 0xA3 0x00
i2cset -y 1 0x1F 0xA0 0xFF
- +

RGB LED

The following sysfs entries are available under /sys/firmware/beepy:

  • led: 0 to disable LED, 1 to enable. Write-only
  • led_red, led_green, led_blue: set LED color intensity from 0 to 255. Write- only

RGB LED over I2C

The RGB LED is connected to the RP2040. When the keyboard driver is unloaded via rmmod beepy-kbd, they can be controlled directly by the Pi via I²C.

The LED color on the Beepy is exposed on I2C bus 1 at the chip address 0x1F.

Controls are available at the following specific data addresses:

FunctionReadWrite
Power0x200xA0
Red0x210xA1
Green0x220xA2
Blue0x230xA3

To get/set the LED color on the Beepy, you can read/write to the above registers over I2C. The values are in the range of 0x00 - 0xFF.

Note: write addresses are the read address masked with 0x80.

A value of 0 in the power register represents the LED's off state, while any other value represents on.

Example

To set the RGB values to red and turn the LED on from the command line:

# Format:
# i2cset -y [i2cbus] [chip-address] [data-address] value
i2cset -y 1 0x1F 0xA1 0xFF
i2cset -y 1 0x1F 0xA2 0x00
i2cset -y 1 0x1F 0xA3 0x00
i2cset -y 1 0x1F 0xA0 0xFF
+ \ No newline at end of file diff --git a/docs/getting-started.html b/docs/getting-started.html index e924319..cb0535f 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -7,13 +7,13 @@ - +
-

Getting Started

Software Setup

  1. Use the Raspberry Pi Imager tool to flash an SD card with the latest Raspberry Pi OS image

    • Choose the Raspberry Pi OS Lite (32-bit) image
    • Click the gear icon ⚙ to also setup WiFi and enable SSH
  2. SSH into the Pi and update the kernel and reboot

sudo apt-get update && sudo apt-get install raspberrypi-kernel
sudo shutdown -r now
  1. After reboot, SSH into the Pi again and run the setup script
curl -s https://raw.githubusercontent.com/beeper/beepy/main/raspberrypi/setup.sh | bash
  1. Your Beepy is now ready, enjoy!

Hardware Setup

If you are installing your own Raspberry Pi Zero W or any other SBC, make sure all the mounting pins are properly aligned to each hole before tightening the screws. If you cannot see the pin through a header hole, then it is not properly mounted. You can move the board around until all the pins "click" into place.

Beepy Raspberry Pi Zero mounting diagram

The USB-C port at the bottom powers and charges the Beepy. Do not power the Raspberry Pi Zero through its Micro-USB port (PWR IN).

Firmware Update

To update the Beepy's firmware:

  1. Slide the power switch off (left if facing up)
  2. Connect the Beepy to your computer via USB-C
  3. While holding the "End Call" key (top right on the keypad), slide the power switch on
  4. The Beepy will present itself as a USB mass storage device, drag'n'drop the new firmware (*.uf2) into the drive and it will reboot with the new firmware

The latest Beepy firmware can be found here: i2c_puppet.uf2

Additional Details

  • In /boot/cmdline.txt, edit fbcon=font:VGA8x8 to change the font/size. See fbcon for more details
  • Long holding the "End Call" key (~3 seconds) will trigger the key KEY_POWER and safely shutdown the Pi

Join the Beepy Discord!

Discord Invite

Matrix Bridge

#beepy-general

#beepy-dev

#beepy-apps

#beepy-hw

- +

Getting Started

Software Setup

  1. Use the Raspberry Pi Imager tool to flash an SD card with the latest Raspberry Pi OS image

    • Choose OS - Raspberry Pi OS (other) - Raspberry Pi OS Lite (32-bit) image
    • Click the gear icon ⚙ to set up a new user, WiFi, and enable SSH
  2. Update Beepy's firmware

    • Download the latest firmware image
    • Slide the power switch off (left if facing up)
    • Connect the Beepy to your computer via USB-C
    • While holding the "End Call" key (top right on the keypad), slide the power switch on
    • The Beepy will present itself as a USB mass storage device, drag'n'drop the new firmware (i2c_puppet.uf2) into the drive and it will reboot with the new firmware
  3. SSH into the Pi and install driver packages. The LED will remain green until drivers are installed and the system has rebooted

curl -s --compressed "https://ardangelo.github.io/beepy-ppa/KEY.gpg" | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/beepy.gpg >/dev/null \
&& sudo curl -s --compressed -o /etc/apt/sources.list.d/beepy.list "https://ardangelo.github.io/beepy-ppa/beepy.list" \
&& sudo apt update \
&& sudo apt-get -y install beepy-kbd sharp-drm \
&& sudo shutdown -r now
  1. Your Beepy is now ready, enjoy!

Hardware Setup

If you are installing your own Raspberry Pi Zero or any other SBC, make sure all the mounting pins are properly aligned to each hole before tightening the screws. If you cannot see the pin through a header hole, then it is not properly mounted. You can move the board around until all the pins "click" into place.

Beepy Raspberry Pi Zero mounting diagram

The USB-C port at the bottom powers and charges the Beepy. Do not power the Raspberry Pi Zero through its Micro-USB port (PWR IN).

Additional Details

  • In /boot/cmdline.txt, edit fbcon=font:VGA8x8 to change the font/size. See fbcon for more details
  • Long holding the "End Call" key (5 seconds) will trigger the key KEY_POWER and safely shutdown the Pi
    • The LED will turn red until OS shutdown has completed
    • Wait another few seconds until the disk activity light on the Pi has turned off to ensure disks are synced
  • After shutting down using the "End Call" key, holding the key for 1 second will turn the Pi back on

Join the Beepy Discord!

Discord Invite

Matrix Bridge

#beepy-general

#beepy-dev

#beepy-apps

#beepy-hw

+ \ No newline at end of file diff --git a/docs/hardware/pinouts.html b/docs/hardware/pinouts.html index 85eba9c..c000829 100644 --- a/docs/hardware/pinouts.html +++ b/docs/hardware/pinouts.html @@ -7,13 +7,13 @@ - +

Pinouts

Raspberry Pi Header Breakout

RGB LED

RGB LEDRP2040 Pins
RedGPIO 20
GreenGPIO 19
BlueGPIO 17

Programmable Button

Pi GPIO 17

Display

DisplayPi Pins
SCKGPIO 11
SDIGPIO 10
CSGPIO 8
EXTINGPIO 23

Keyboard

KeyboardPi PinsRP2040 Pins
SDAGPIO 2GPIO 28
SCLGPIO 3GPIO 29
INTGPIO 4GPIO 0

SWD Header

Power Management

Power ManagementPi PinsRP2040 Pins
Pi Power Switch-GPIO 15
Pi Shutdown SignalGPIO 26GPIO 21
Battery ADC-GPIO 26
- + \ No newline at end of file diff --git a/docs/hardware/schematic.html b/docs/hardware/schematic.html index b8ab51c..11e61a4 100644 --- a/docs/hardware/schematic.html +++ b/docs/hardware/schematic.html @@ -7,13 +7,13 @@ - +
- + \ No newline at end of file diff --git a/docs/hardware/specs.html b/docs/hardware/specs.html index e469bad..33f0f07 100644 --- a/docs/hardware/specs.html +++ b/docs/hardware/specs.html @@ -7,13 +7,13 @@ - +

Tech Specs

Beepy Technical Diagram

  • Ultra-low power high contrast Sharp Memory LCD 2.7″ 400 x 240
  • Raspberry Pi Zero W (optional) with compatible low profile solderless header
  • Tactile keyboard w/ backlight and touchpad
  • Programmable RGB LED for notifications
  • Programmable side button
  • Onboard RP2040 MCU (for keyboard and peripherals control)
  • GPIOs breakout
  • USB-C programming & charging
  • 2000mAh LiPo battery
  • 74mm x 104mm x 15mm
- + \ No newline at end of file diff --git a/docs/software/linux-drivers.html b/docs/software/linux-drivers.html index 59807a5..8062356 100644 --- a/docs/software/linux-drivers.html +++ b/docs/software/linux-drivers.html @@ -3,17 +3,17 @@ -Linux Drivers | Beepy +RGB LED | Beepy - +
-

Linux Drivers

Linux drivers for the Beepy

Display

Sharp Memory LCD Kernel Drive

Keyboard

BBQX0KBD i2c Keyboard Device Driver

How to customize keyboard layout

To Do

Peripherals

To Do - This driver provides an interface to read/write to the peripherals on the Beepy

Power Control

To Do - Controlling the power switch and detecting the shutdown signal

Battery Level

To Do - Reading from the ADC on the RP2040

RGB LED Control

To Do - LED control via userspace application

- +

RGB LED

The following sysfs entries are available under /sys/firmware/beepy:

  • led: 0 to disable LED, 1 to enable. Write-only
  • led_red, led_green, led_blue: set LED color intensity from 0 to 255. Write- only

RGB LED over I2C

The RGB LED is connected to the RP2040. When the keyboard driver is unloaded via rmmod beepy-kbd, they can be controlled directly by the Pi via I²C.

The LED color on the Beepy is exposed on I2C bus 1 at the chip address 0x1F.

Controls are available at the following specific data addresses:

FunctionReadWrite
Power0x200xA0
Red0x210xA1
Green0x220xA2
Blue0x230xA3

To get/set the LED color on the Beepy, you can read/write to the above registers over I2C. The values are in the range of 0x00 - 0xFF.

Note: write addresses are the read address masked with 0x80.

A value of 0 in the power register represents the LED's off state, while any other value represents on.

Example

To set the RGB values to red and turn the LED on from the command line:

# Format:
# i2cset -y [i2cbus] [chip-address] [data-address] value
i2cset -y 1 0x1F 0xA1 0xFF
i2cset -y 1 0x1F 0xA2 0x00
i2cset -y 1 0x1F 0xA3 0x00
i2cset -y 1 0x1F 0xA0 0xFF
+ \ No newline at end of file diff --git a/docs/software/os-image.html b/docs/software/os-image.html index 9254402..cf799b3 100644 --- a/docs/software/os-image.html +++ b/docs/software/os-image.html @@ -7,13 +7,13 @@ - +
-

OS Image

The base OS image is Raspberry Pi OS Lite 32-bit (Debian version 11 bullseye, Kernel 6.1)

Optimizing Boot Speed

To Do - Optimized boot script to reduce boot up time

Optimizing Battery Life

Pi Zero 2W Settings

Restrict number of cores to limit peak power use - the Zero 2W can be limited to use two cores and is still much faster than the pi zero, but peak power use is nearly half of what 4 cores will use.

  • sudo vi /boot/cmdline.txt
  • Add "maxcpus=2" after "console=tty1".
  • Reboot

Optimizing Apps for small screens

  • By default, the LCD display shows a character screen of 50x15. If you develop text-based apps for Beepy, targeting this format will give you compatibility with the widest userbase.

top - You can reduce the number of columns shown by default so that it shows more useful information on the sharp display.

  • ssh to the Beepy (the needed menu doesn't render correctly on the small screen)
  • run "top"
  • type "f" to enter the columns config screen
  • use the up and down keys to move, and space to remove the "*" from all of the columns except: PID, USER, S, %CPU, %MEM, COMMAND
  • type "q" to return to the main screen
  • type "W" (capital w) to save the config.
  • type "q" to quit. Then go back to the Beepy and top should have a nice setup.
- +

OS Image

The base OS image is Raspberry Pi OS Lite 32-bit (Debian version 11 bullseye, Kernel 6.1)

Optimizing Boot Speed

To Do - Optimized boot script to reduce boot up time

Optimizing Battery Life

Pi Zero 2W Settings

Restrict number of cores to limit peak power use - the Zero 2W can be limited to use two cores and is still much faster than the pi zero, but peak power use is nearly half of what 4 cores will use.

  • sudo vi /boot/cmdline.txt
  • Add "maxcpus=2" after "console=tty1".
  • Reboot

Optimizing Apps for small screens

  • By default, the LCD display shows a character screen of 50x15. If you develop text-based apps for Beepy, targeting this format will give you compatibility with the widest userbase.

top - You can reduce the number of columns shown by default so that it shows more useful information on the sharp display.

  • ssh to the Beepy (the needed menu doesn't render correctly on the small screen)
  • run "top"
  • type "f" to enter the columns config screen
  • use the up and down keys to move, and space to remove the "*" from all of the columns except: PID, USER, S, %CPU, %MEM, COMMAND
  • type "q" to return to the main screen
  • type "W" (capital w) to save the config.
  • type "q" to quit. Then go back to the Beepy and top should have a nice setup.
+ \ No newline at end of file diff --git a/gallery.html b/gallery.html index b85b5a4..3c37d4d 100644 --- a/gallery.html +++ b/gallery.html @@ -7,13 +7,13 @@ - + - + \ No newline at end of file diff --git a/img/symbol-keys.png b/img/symbol-keys.png new file mode 100644 index 0000000000000000000000000000000000000000..84dbda3eb232d219336baab9c2fd9fa94ace4f36 GIT binary patch literal 67972 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

{>9H+1FHOEh2@sSHsr!R%3lX|3$6QW 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

G1^jN(f}fF*M^WdZO}ky7td7ke*2R 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 literal 0 HcmV?d00001 diff --git a/index.html b/index.html index 7c8752b..d1d19fc 100644 --- a/index.html +++ b/index.html @@ -7,13 +7,13 @@ - +

- + \ No newline at end of file diff --git a/markdown-page.html b/markdown-page.html index 391216a..0aa579e 100644 --- a/markdown-page.html +++ b/markdown-page.html @@ -7,13 +7,13 @@ - +

Markdown page example

You don't need React to write simple standalone pages.

- + \ No newline at end of file

Technical Diagram

Display

Sharp Display

Ultra-low power, high contrast, high resolution, Sharp Memory LCD display.

Tactile keyboard & touchpad

Clicky keyboard w/ backlight and touchpad for easy input and navigation. Customizable keymap to suit your needs.

Powered by Raspberry Pi

Powered by the Pi Zero W (optional) or any other compatible SBCs (e.g. Radxa Zero, MQ-Pro) with the low profile solderless header.

See it in action