Skip to content

Commit 665ebc3

Browse files
authored
feat(nano): add Arduino Nano element #8
* feat(nano): WIP. Done except for reset button (#8) * feat(nano): layout fixed + reset button logic (#8) * feat(nano): allow button press with keyboard * feat(nano): make button lose focus on mouseleave * feat(nano): review actions Co-authored-by: sutaburosu <sutaburosu@gmail.com>
1 parent f698e0c commit 665ebc3

File tree

4 files changed

+333
-0
lines changed

4 files changed

+333
-0
lines changed

src/arduino-nano-element.stories.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { boolean, withKnobs } from '@storybook/addon-knobs';
2+
import { storiesOf } from '@storybook/web-components';
3+
import { html } from 'lit-html';
4+
import { logEvent } from 'storybook-events-logger';
5+
import './arduino-nano-element';
6+
7+
storiesOf('Arduino Nano', module)
8+
.addParameters({ component: 'wokwi-arduino-nano' })
9+
.addDecorator(withKnobs)
10+
.add(
11+
'Nano',
12+
() => html`
13+
<wokwi-arduino-nano
14+
.led13=${boolean('LED 13', false)}
15+
.ledTX=${boolean('TX LED', false)}
16+
.ledRX=${boolean('RX LED', false)}
17+
.ledPower=${boolean('Power LED', true)}
18+
@button-press=${logEvent}
19+
@button-release=${logEvent}
20+
></wokwi-arduino-nano>
21+
`
22+
);

src/arduino-nano-element.ts

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
import { customElement, html, LitElement, property, svg, query } from 'lit-element';
2+
import { analog, ElementPin, i2c, spi, usart } from './pin';
3+
4+
const triggerKeys = ['Spacebar', ' ', 'Enter'];
5+
6+
@customElement('wokwi-arduino-nano')
7+
export class ArduinoNanoElement extends LitElement {
8+
@property() led13 = false;
9+
@property() ledRX = false;
10+
@property() ledTX = false;
11+
@property() ledPower = false;
12+
@property() resetPressed = false;
13+
@query('#reset-button') resetButton!: SVGCircleElement;
14+
15+
readonly pinInfo: ElementPin[] = [
16+
{ name: '12', x: 19.7, y: 4.8, signals: [spi('MISO')] },
17+
{ name: '11', x: 29.3, y: 4.8, signals: [spi('MOSI'), { type: 'pwm' }] },
18+
{ name: '10', x: 38.9, y: 4.8, signals: [spi('SS'), { type: 'pwm' }] },
19+
{ name: '9', x: 48.5, y: 4.8, signals: [{ type: 'pwm' }] },
20+
{ name: '8', x: 58.1, y: 4.8, signals: [] },
21+
{ name: '7', x: 67.7, y: 4.8, signals: [] },
22+
{ name: '6', x: 77.3, y: 4.8, signals: [{ type: 'pwm' }] },
23+
{ name: '5', x: 86.9, y: 4.8, signals: [{ type: 'pwm' }] },
24+
{ name: '4', x: 96.5, y: 4.8, signals: [] },
25+
{ name: '3', x: 106.1, y: 4.8, signals: [{ type: 'pwm' }] },
26+
{ name: '2', x: 115.7, y: 4.8, signals: [] },
27+
{ name: 'GND.2', x: 125.3, y: 4.8, signals: [{ type: 'power', signal: 'GND' }] },
28+
{ name: 'RESET.2', x: 134.9, y: 4.8, signals: [] },
29+
{ name: '1', x: 144.5, y: 4.8, signals: [usart('TX')] },
30+
{ name: '0', x: 154.1, y: 4.8, signals: [usart('RX')] },
31+
{ name: '13', x: 19.7, y: 62.4, signals: [spi('SCK')] },
32+
{ name: '3.3V', x: 29.3, y: 62.4, signals: [{ type: 'power', signal: 'VCC', voltage: 3.3 }] },
33+
{ name: 'AREF', x: 38.9, y: 62.4, signals: [] },
34+
{ name: 'A0', x: 48.5, y: 62.4, signals: [analog(0)] },
35+
{ name: 'A1', x: 58.1, y: 62.4, signals: [analog(1)] },
36+
{ name: 'A2', x: 67.7, y: 62.4, signals: [analog(2)] },
37+
{ name: 'A3', x: 77.3, y: 62.4, signals: [analog(3)] },
38+
{ name: 'A4', x: 86.9, y: 62.4, signals: [analog(4), i2c('SCL')] },
39+
{ name: 'A5', x: 96.5, y: 62.4, signals: [analog(5), i2c('SDA')] },
40+
{ name: 'A6', x: 106.1, y: 62.4, signals: [analog(6)] },
41+
{ name: 'A7', x: 115.7, y: 62.4, signals: [analog(7)] },
42+
{ name: '5V.1', x: 125.3, y: 62.4, signals: [{ type: 'power', signal: 'VCC', voltage: 5 }] },
43+
{ name: 'RESET.1', x: 134.9, y: 62.4, signals: [] },
44+
{ name: 'GND.1', x: 144.5, y: 62.4, signals: [{ type: 'power', signal: 'GND' }] },
45+
{ name: 'VIN', x: 154.1, y: 62.4, signals: [{ type: 'power', signal: 'VCC' }] },
46+
{ name: '12.2', x: 163.7, y: 43.2, signals: [spi('MISO')] },
47+
{ name: '5V.2', x: 154.1, y: 43.2, signals: [{ type: 'power', signal: 'VCC', voltage: 5 }] },
48+
{ name: '13.2', x: 163.7, y: 33.6, signals: [spi('SCK')] },
49+
{ name: '11.2', x: 154.1, y: 33.6, signals: [spi('MOSI'), { type: 'pwm' }] },
50+
{ name: 'RESET.3', x: 163.7, y: 24, signals: [] },
51+
{ name: 'GND.3', x: 154.1, y: 24, signals: [{ type: 'power', signal: 'GND' }] },
52+
];
53+
54+
render() {
55+
const { ledPower, led13, ledRX, ledTX } = this;
56+
return html`
57+
<style>
58+
text {
59+
user-select: none;
60+
}
61+
circle[tabindex]:hover,
62+
circle[tabindex]:focus {
63+
stroke: white;
64+
outline: none;
65+
}
66+
</style>
67+
68+
<svg
69+
width="44.9mm"
70+
height="17.8mm"
71+
viewBox="-1.4 0 44.9 17.8"
72+
font-size="1px"
73+
font-family="DejaVu Mono, Cascadia Mono, monospace"
74+
font-weight="bold"
75+
version="1.1"
76+
xmlns="http://www.w3.org/2000/svg"
77+
xmlns:xlink="http://www.w3.org/1999/xlink"
78+
>
79+
<defs>
80+
<filter id="solderPlate" style="color-interpolation-filters:sRGB;">
81+
<feTurbulence result="r0" type="fractalNoise" baseFrequency="1" numOctaves="1" />
82+
<feComposite
83+
result="r1"
84+
in="r0"
85+
in2="SourceGraphic"
86+
operator="arithmetic"
87+
k1=".6"
88+
k2=".6"
89+
k3="1.2"
90+
k4=".25"
91+
/>
92+
<feBlend result="r2" in="r1" in2="SourceGraphic" mode="luminosity" />
93+
<feComposite result="r3" in="r2" in2="SourceGraphic" operator="in" />
94+
</filter>
95+
<pattern id="pins-tqfp-0.5mm" width="1" height=".5" patternUnits="userSpaceOnUse">
96+
<rect fill="#333" width="1" height=".2" y=".17" />
97+
</pattern>
98+
<pattern id="pins-pth-0.75" width="2.54" height="2.54" patternUnits="userSpaceOnUse">
99+
<circle r=".75" cx="1.27" cy="1.27" fill="#333" filter="url(#solderPlate)" />
100+
<g stroke="#333" stroke-width=".05" paint-order="stroke fill">
101+
<circle r=".375" cx="1.27" cy="1.27" fill="#eee" />
102+
</g>
103+
</pattern>
104+
<pattern id="pins-pth-1.00" width="2.54" height="2.54" patternUnits="userSpaceOnUse">
105+
<circle r=".75" cx="1.27" cy="1.27" fill="#333" filter="url(#solderPlate)" />
106+
<g stroke="#333" stroke-width=".05" paint-order="stroke fill">
107+
<circle r=".5" cx="1.27" cy="1.27" fill="#eee" />
108+
</g>
109+
</pattern>
110+
<g id="led-body" fill="#eee">
111+
<rect x="0" y="0" height="1.2" width="2.6" fill="#333" filter="url(#solderPlate)" />
112+
<rect x=".6" y="-0.1" width="1.35" height="1.4" stroke="#aaa" stroke-width=".05" />
113+
</g>
114+
<filter id="ledFilter" x="-0.8" y="-0.8" height="2.2" width="2.8">
115+
<feGaussianBlur stdDeviation=".5" />
116+
</filter>
117+
</defs>
118+
119+
<!-- PCB -->
120+
<g id="pcb" fill="#fff">
121+
<rect width="43.5" height="17.8" x="0" y="0" fill="#1b7e84" />
122+
<circle cx="1" cy="1" r=".889" />
123+
<circle cx="42.42" cy="1" r=".889" />
124+
<circle cx="42.42" cy="16.6" r=".889" />
125+
<circle cx="1" cy="16.6" r=".889" />
126+
</g>
127+
128+
<!-- silkscreen -->
129+
<g id="silkscreen" fill="#eee" text-anchor="middle">
130+
<rect x="30.48" y="0" width="2.54" height="3.2" />
131+
<rect x="35.56" y="14.6" width="2.54" height="3.2" />
132+
<g fill="#1b7e84" transform="translate(1.27 1.27)">
133+
<circle r=".85" cx="30.48" />
134+
<circle r=".85" cx="35.56" cy="15.24" />
135+
</g>
136+
<g transform="translate(1.27 3)">
137+
<text x="2.54">D12</text>
138+
<text x="5.08">D11</text>
139+
<text x="7.62">D10</text>
140+
<text x="10.16">D9</text>
141+
<text x="12.7">D8</text>
142+
<text x="15.24">D7</text>
143+
<text x="17.78">D6</text>
144+
<text x="20.32">D5</text>
145+
<text x="22.86">D4</text>
146+
<text x="25.4">D3</text>
147+
<text x="27.94">D2</text>
148+
<text x="30.48" fill="#1b7e84">GND</text>
149+
<text x="33.02">RST</text>
150+
<text x="35.56" y=".65" font-size="200%"></text>
151+
<text x="35.56" y="1.5">RX0</text>
152+
<text x="38.1" y=".65" font-size="200%"></text>
153+
<text x="38.1" y="1.5">TX0</text>
154+
</g>
155+
<g transform="translate(1.27 15.5)">
156+
<text x="2.54">D13</text>
157+
<text x="5.08">3V3</text>
158+
<text x="7.62">AREF</text>
159+
<text x="10.16">A0</text>
160+
<text x="12.7">A1</text>
161+
<text x="15.24">A2</text>
162+
<text x="17.78">A3</text>
163+
<text x="20.32">A4</text>
164+
<text x="22.86">A5</text>
165+
<text x="25.4">A6</text>
166+
<text x="27.94">A7</text>
167+
<text x="30.48">5V</text>
168+
<text x="33.02">RST</text>
169+
<text x="35.56" fill="#1b7e84">GND</text>
170+
<text x="38.1">VIN</text>
171+
</g>
172+
<g transform="rotate(90)">
173+
<text x="8.7" y="-22.5">RESET</text>
174+
<text x="5.6" y="-32.2">TX</text>
175+
<text x="5.6" y="-30.7" font-size="200%"></text>
176+
<text x="7.6" y="-32.2">RX</text>
177+
<text x="7.6" y="-30.7" font-size="200%"></text>
178+
<text x="9.6" y="-30.7">ON</text>
179+
<text x="11.6" y="-30.7">L</text>
180+
</g>
181+
</g>
182+
183+
<!-- MCU -->
184+
<g id="mcu" transform="rotate(45 -2.978 23.39)">
185+
<g fill="url(#pins-tqfp-0.5mm)" filter="url(#solderPlate)">
186+
<rect x="-2.65" y="-1.975" width="5.3" height="3.95" />
187+
<rect x="-2.65" y="-1.975" width="5.3" height="3.95" transform="rotate(90)" />
188+
</g>
189+
<rect x="-2.275" y="-2.275" width="4.55" height="4.55" fill="#444" />
190+
<circle transform="rotate(45)" cx=".012" cy="-2.5" r=".35" fill="#222" />
191+
</g>
192+
193+
<!-- pins -->
194+
<g id="pins" fill="url(#pins-pth-0.75)">
195+
<g id="pins-pin1" fill="#333" filter="url(#solderPlate)">
196+
<rect x="${15.5 * 2.54 - 0.875}" y="${0.5 * 2.54 - 0.875}" width="1.75" height="1.75" />
197+
<rect x="${15.5 * 2.54 - 0.875}" y="${6.5 * 2.54 - 0.875}" width="1.75" height="1.75" />
198+
</g>
199+
<rect x="2.54" width="${15 * 2.54}" height="2.54" />
200+
<rect x="2.54" y="${6 * 2.54}" width="${15 * 2.54}" height="2.54" />
201+
</g>
202+
203+
<!-- programming header -->
204+
<g id="pgm-header" fill="url(#pins-pth-1.00)" stroke="#eee" stroke-width=".1">
205+
<g id="pgm-pin1" stroke="none" fill="#333" filter="url(#solderPlate)">
206+
<rect x="${16.5 * 2.54 - 0.875}" y="${4.5 * 2.54 - 0.875}" width="1.75" height="1.75" />
207+
</g>
208+
<rect x="${15 * 2.54}" y="${2 * 2.54}" width="${2 * 2.54}" height="${3 * 2.54}" />
209+
</g>
210+
211+
<!-- USB mini type B -->
212+
<g id="usb-mini-b" stroke-width=".1" paint-order="stroke fill">
213+
<g fill="#333" filter="url(#solderPlate)">
214+
<rect x=".3" y="3.8" width="1.6" height="9.8" />
215+
<rect x="5.5" y="3.8" width="1.6" height="9.8" />
216+
<rect x="7.3" y="7.07" width="1.1" height=".48" />
217+
<rect x="7.3" y="7.82" width="1.1" height=".48" />
218+
<rect x="7.3" y="8.58" width="1.1" height=".48" />
219+
<rect x="7.3" y="9.36" width="1.1" height=".48" />
220+
<rect x="7.3" y="10.16" width="1.1" height=".48" />
221+
</g>
222+
<rect x="-1.4" y="4.8" width="8.9" height="7.8" fill="#999" stroke-width=".26" />
223+
<rect x="-1.25" y="5" width="8.6" height="7.4" fill="#ccc" stroke="#bbb" />
224+
<g fill="none" stroke="#333" stroke-width=".26" stroke-linecap="round">
225+
<path d="m2.6 5.9h-3.3v0.9h3.3m0 3.7h-3.3v0.9h3.3M-0.6 7.6l4.3 0.3v1.5l-4.3 0.3" />
226+
<path d="m3.3 7.9v1.5" stroke-width="1" stroke-linecap="butt" />
227+
<path d="m6 6.4v4.5" stroke-width=".35" />
228+
</g>
229+
</g>
230+
231+
<!-- LEDs -->
232+
<g transform="translate(27.7 5)">
233+
<use xlink:href="#led-body" />
234+
${ledTX &&
235+
svg`<circle cx="1.3" cy=".55" r="1.3" fill="#ff8080" filter="url(#ledFilter)" />`}
236+
</g>
237+
<g transform="translate(27.7 7)">
238+
<use xlink:href="#led-body" />
239+
${ledRX &&
240+
svg`<circle cx="1.3" cy=".55" r="1.3" fill="#80ff80" filter="url(#ledFilter)" />`}
241+
</g>
242+
<g transform="translate(27.7 9)">
243+
<use xlink:href="#led-body" />
244+
${ledPower &&
245+
svg`<circle cx="1.3" cy=".55" r="1.3" fill="#80ff80" filter="url(#ledFilter)" />`}
246+
</g>
247+
<g transform="translate(27.7 11)">
248+
<use xlink:href="#led-body" />
249+
${led13 &&
250+
svg`<circle cx="1.3" cy=".55" r="1.3" fill="#ffff80" filter="url(#ledFilter)" />`}
251+
</g>
252+
253+
<!-- reset button -->
254+
<g stroke-width=".1" paint-order="fill stroke">
255+
<rect x="24.3" y="6.3" width="1" height="4.8" filter="url(#solderPlate)" fill="#333" />
256+
<rect x="23.54" y="6.8" width="2.54" height="3.8" fill="#ccc" stroke="#888" />
257+
<circle
258+
id="reset-button"
259+
cx="24.8"
260+
cy="8.7"
261+
r="1"
262+
fill="#eeb"
263+
stroke="#777"
264+
tabindex="0"
265+
@mousedown=${() => this.down()}
266+
@touchstart=${() => this.down()}
267+
@mouseup=${() => this.up()}
268+
@mouseleave=${() => this.leave()}
269+
@touchend=${() => this.leave()}
270+
@keydown=${(e: KeyboardEvent) => triggerKeys.includes(e.key) && this.down()}
271+
@keyup=${(e: KeyboardEvent) => triggerKeys.includes(e.key) && this.up()}
272+
/>
273+
</g>
274+
</svg>
275+
`;
276+
}
277+
278+
private down() {
279+
if (this.resetPressed) {
280+
return;
281+
}
282+
this.resetPressed = true;
283+
this.resetButton.style.stroke = '#333';
284+
this.dispatchEvent(
285+
new CustomEvent('button-press', {
286+
detail: 'reset',
287+
})
288+
);
289+
}
290+
291+
private up() {
292+
if (!this.resetPressed) {
293+
return;
294+
}
295+
this.resetPressed = false;
296+
this.resetButton.style.stroke = '';
297+
this.dispatchEvent(
298+
new CustomEvent('button-release', {
299+
detail: 'reset',
300+
})
301+
);
302+
}
303+
304+
private leave() {
305+
this.resetButton.blur();
306+
this.up();
307+
}
308+
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ export { RotaryDialerElement } from './rotary-dialer-element';
1818
export { ServoElement } from './servo-element';
1919
export { DHT22Element as Dht22Element } from './dht22-element';
2020
export { ArduinoMegaElement } from './arduino-mega-element';
21+
export { ArduinoNanoElement } from './arduino-nano-element';

src/react-types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { SSD1306Element } from './ssd1306-element';
1717
import { ServoElement } from './servo-element';
1818
import { DHT22Element } from './dht22-element';
1919
import { ArduinoMegaElement } from './arduino-mega-element';
20+
import { ArduinoNanoElement } from './arduino-nano-element';
2021

2122
declare global {
2223
namespace JSX {
@@ -37,6 +38,7 @@ declare global {
3738
'wokwi-servo': Partial<ServoElement>;
3839
'wokwi-dht22': Partial<DHT22Element>;
3940
'wokwi-arduino-mega': Partial<ArduinoMegaElement>;
41+
'wokwi-arduino-nano': Partial<ArduinoNanoElement>;
4042
}
4143
}
4244
}

0 commit comments

Comments
 (0)