自己打造一台恩尼格玛密码机

在对称加密学当中,恩尼格玛机绝对是承前启后的存在。它将密码学研究从以前的语言文字学中心完全转移到了数学身上。在这里牵涉的密码并不是我们平时邮箱、银行帐号那种狭义概念,那种顶多叫做口令。这里说的密码就是通过某种映射方式,把一篇文章变得面目全非,以达到保密效果;只有特定的转换规律才能将其解密。这篇文章适于电脑控、军事控、历史控、数学控阅读,请做好烧脑准备。

EDIT: This Instructable has won Second prize in the 2013 Radio Shack Microcontroller Contest. Thank You to all who voted!
按:这个作品是2013年无线电单片机竞赛的亚军。感谢所有支持这个作品的你们!
EDIT2: An Open Enigma with fake Standup Nixie Tubes like the ones pictured in this Instructable will soon be available as a Special Kickstarter edition.

This is our very first Instructable and this step by step guide will show you how to build a fully functional electronic replica of the world famous German Enigma machine. This Arduino based Open Source project is able to encrypt & decrypt any Enigma M4 encoded message.
这是我们的初号机。以下教程将手把手教你如何完美复刻史上著名的德国恩尼格玛密码机。这个基于Arduino的开源程序能够加解密任何Enigma机M4型(海军型)的信息。
This first ever fully functional Open Source Enigma “exact” Replica was inspired by the Kid’s Game to Arduino Enigma Machine by sketchsk3tch.
这个第一台全功能开源完美Enigma机复制品是根据sketchsk3tch写的《Kid’s Game to Arduino Enigma Machine(从儿童玩具到Arduino恩尼格玛机)》所作。
Using Multiplexing for the LEDs, this circuit with 115 light emitting diodes uses only 38 pins and the 36 push buttons use only 4 pins total thanks to properly placed resistors (and the P-Channel MOSFETs) in the keyboard loop. These 4 16-Segment displays & an LED for each keyboard button would add up quickly the total number of pins required and even the Arduino Mega would have ran out of pins without the 2 methods mentioned above….
采用多路复用LED电路,仅用38个针脚的115个发光二极管和4个针脚的36个按键所连接的整个电路,全靠在键盘回路里准确放置的电阻以及P沟道场效应晶体管得以实现。要不然,4个16段显示器,以及每个按键上的LED将大幅增加所需针脚总量——即使用了Arduino Mega板,但如果没用上述两个方法,电路也不能如此简洁。
In response to the overwhelming demand, we designed the PCB and made it available through www.stgeotronics.com. Skip to Step 10 & beyond for more info. We also offer it as a complete electronics kit & an assembled & tested complete product.
面对电路的超额需求,我们在 http://www.stgeotronics.com 设计了专用的PCB板。直接跳到第10步和以后的步骤可以找到更多信息。同时,我们也发布了测试过的完整电子组装套装。

Step 1: Proof of Concept on Breadboard

第一步:面包板上的论证


Before going all out on the development of this electronic Enigma replica, we wanted to make sure we could properly drive the 16 Segment LEDs. If we can do that, than we will be able to do everything as the rest is only Math…
在开始制作电子Enigma机之前,我们先要确保能驱动16段LED显示。如果成功,我们就能做接下来的所有步骤——除了数学上的问题,一切都是浮云。

Step 2: Gather the Raw Materials…

第二步:万事具备

You will need:

  • 1 Arduino Mega
  • 26 Alpha Buttons
  • 26 1/4” Jacks Mono
  • 10 1/4” Plugs Mono
  • 36 Pushbuttons
  • 1 On/Off/On Switch
  • 4 16Segment Orange
  • 4 Injection molded 2-Liter Soda Bottle preform (test tubes)
  • 1 Case Plywood
  • 1 Hinge & Hooks
  • 1 Half-Mortise Lock
  • 1 Perfboard
  • 38 Resistors 470 Ohms
  • 40 Resistors 1K Ohms
  • 7 IRF9Z24N P-Channel MOSFET
  • 1 Piece of Metal & Spray paint

你所需要的是:

  • 1个Arduino Mega 2560板
  • 26个字母按键
  • 26个1/4英寸单通道母接口
  • 10个1/4英寸单通道公接口
  • 36个机械按钮
  • 1个单刀三掷开关
  • 4个16段橙色LED显示
  • 4个注塑2升汽水瓶罩子
  • 1个胶合板盒子
  • 一个铰链
  • 一个半榫接锁
  • 一个接线盘
  • 38个470欧电阻
  • 40个1千欧电阻
  • 7个IRF9Z24N P沟道场效应晶体管
  • 1块金属片以及喷漆。

Optional:

  • Battery Case
  • Rechargeable Batteries
  • Battery Charger/Connectors

可选项:

  • 电池盒
  • 充电电池
  • 充电器/充电接头

If we were to do it again, we wouldn’t use 1/4” Jacks & Plugs as these are pretty big and tend to overwhelm the whole Enigma. Banana plugs & jacks are smaller & closer to the original connectors used by the real German Enigmas.
我们真要做的时候,是不会用1/4英寸接口的。它们太大的体积几乎要超过整个恩尼格玛机。香蕉插头体积较小,而且比原版德国Enigma机结合得更紧密些。

Step 3: Lay the Components Down

第三步:布置零件






The Radio Shack 6” x 8” Micro Perboard is the perfect size to host all components as it provides just the right amount of space to fit everything on & will fit perfectly inside the Enigma box.
6*8寸无线电面包版是最适合放置所有元件的,既不多余也不拥挤,而且和Enigma机盒子内部完美吻合。
We started dividing the space on the Perfboard equally between the 3 regions, but realized soon that this would make the electonic Enigma longer than the real one, so we compressed everything down to the proper spacing.
最初我们将面包板等分为三块区域,但很快意识到,如此一来,电子版Enigma机将比原版的机械Enigma机长。于是我们将所有零件缩放到正好够占用的空间。
Once satisfied with the positioning of each components, next step is soldering.
每个元件位置就绪,下一步就是焊接。

Step 4: Soldering, Soldering & a Little More Soldering

第四步:我焊,我焊,我焊焊焊……






OK, this proved to be the most solder I have used on a single project ever. With 18 pins per 16 Segment, times 4 plus 26 keyboard keys + 26 keyboard lamps + a few LEDs & 1 SPDT on/off/on switch, that was a lot of solder.
好吧,在单一作品身上,我从没焊接如此多次。16段显示的18个针脚,还有26个字母键乘以每个4个脚,外加26个键盘灯,一些其他LED,一个三掷开关,真乃『成吉思焊』。
Our decision to raise the 16 Segment displays up to make them look like old-time Nixie tubes certainly added a lot of solder points!
当初我们的决定是使这些16段LED显示看起来像老式电子管的感觉,增加了不少焊点,『巨焊』!
Our Arduino Mega Pin assignment:
Arduino Mega板上针脚的分配:

17 Segments:
Seg Pin Wire DuinoPin
a 2 blue 24
b 1 white 22
c 16 wh-bl 25
d 13 green 31
e 9 wh-br 38
f 8 brown 36
g 6 green 32
h 5 wh-or 30
k 4 orang 28
m 3 wh-bl 26
n 17 blue 23
p 15 orang 27
r 12 wh-gr 33
s 11 brown 35
t 7 wh-gr 34
u 14 wh-or 29
dp 10 wh-br 37
anode1 18 red 39
anode2 18 red 41
anode3 18 red 43
anode4 18 red 45

LEDs:
1 40
2 42
3 44
4 46
5 48

Lamps:
QAP 10
WSY 9
EDX 8
RFC 7
TGV 6
ZHB 5
UJN 4
IKM 3
OL 2
anode1 (First Row) 11
anode2 (Second Row) 12
anode3 (Third Row) 13

Function Keys:
A0

Keyboard:
First Row A1
Second Row A2
Third Row A3

Step 5: Make a Box and Cut & Drill the Top Plate.

第五步:门面工夫——做个盒子钻出面板




After obtaining the exact dimensions of the original M4 wooden box, we purchased a sheet of plywood & cut it in pieces so we could assemble our case.
在原版M4型木盒内得到确定位置数据后,我们买了一块胶合板,将它切块,然后砌盒子。
We decided to cut a steel plate from an obsolete rack mounted server as it had just the right thickness of metal for our needs. After making a transparency that showed where every button/lamp was located & cutting it out, we were able to superimpose it on the metal piece and draw each required hole with a sharpie.
我们从旧服务器机架上卸了一块钢板,厚度正合需要。将模具(上面早已画好每个按键和灯位,并切好了洞洞)盖在钢板上,然后用记号笔画出需要切出的洞洞。
We then spray painted it textured black to look like the real Enigma.
接着,我们用喷漆把它涂黑,就像真的Enigma机那样。

Step 6: Integration Tests

第六步:组装测试







First is the permanent fitting of the metal plate on top of the perfboard making sure every button is working and every LED can shine.
首先把金属板在面包版上永久固定,确保所有按键正常工作,所有LED都能发光。
Then is the fitting of this solid assembly into the wooden case ensuring we didn’t introduce a short anywhere.
接着就是把这一大坨东东装入木盒,确保没有空隙位置。

Step 7: Software - Ohhhh…. Ouch!

第七步:软件啊,日完软啊!


During each hardware assembly phase, we had created small Arduino sketches that would test the specific individual section we were working on:
在组装硬件过程中,我们也写了个小型Arduino程序框架,用以测试特定几个需要关注的部分:
A code that tests that each keyboard button is read accurately.
A second code that tests each of the 10 function buttons.
用来测试每个按键信号能准确读取,还有测试10个功能按键的代码。
An Enigma_POST (Power On Self Test) sketch that tests that each keyboard lamp can be lit precisely and move each LED through each mode, with some modifications to the original breadboard code to ensure each segment of the 4 16-Segment LEDs is working perfectly.
Enigma_POST(上电自检)确保在每种模式下所有键盘等都能准确亮起,在每种模式下每个LED信号都能传送。我们对原本面包板上的代码做了修正,确保4个16段LED显示的每个部件无懈可击。
But, even with all these sample codes on hand that tested every piece of hardware on the machine, the task of reproducing the encrypting/decrypting functionality of a real M4 Enigma was a Mathematics tour-de-force!
但,即使所有手上的程序片段都说明机器状态完好,重现M4海军型Enigma机加解密功能,数学方面居功至伟。
All Arduino sketches will be available on our Github that we are currently setting up.
所有的Arduino程序片段即将在我们刚刚建好的Github组织中发布。
Here is the Enigma_POST sketch:
以下是Enigma_POST程序片段(上电自检):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* Enigma Development Code to Test each of the 4 Nixies, the 5 LEDs,
then Turn On each Lamp in sequence.
Written by Marc Tessier & James Sanderson 9/8/13
*/

// Define the 16-Segments Pins
int segment[17] = { 24,22,25,31,38,36,32,30,28,26,23,27,33,35,34,29,37 };
int anode[4] = { 39,41,43,45 };

// Define the 9 lamps Pins
int lamp[9] = { 10,9,8,7,6,5,4,3,2 };
int lanode[3] = { 11,12,13 };

// LTP587P Segments: A,B,C,D,E,F,G,H,K,M,N,P,R,S,T,U,dp
boolean segmentvals[39][17] = {
{ 0,0,0,0,1,1,0,0,1,1,1,0,1,1,1,0,1 }, // = A
{ 0,0,0,0,0,0,1,1,1,0,1,0,1,0,1,1,1 }, // = B
{ 0,0,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1 }, // = C
{ 0,0,0,0,0,0,1,1,1,0,1,1,1,0,1,1,1 }, // = D
{ 0,0,1,1,0,0,0,0,1,1,1,0,1,1,1,0,1 }, // = E
{ 0,0,1,1,1,1,0,0,1,1,1,0,1,1,1,0,1 }, // = F
{ 0,0,1,0,0,0,0,0,1,1,1,0,1,1,1,1,1 }, // = G
{ 1,1,0,0,1,1,0,0,1,1,1,0,1,1,1,0,1 }, // = H
{ 0,0,1,1,0,0,1,1,1,0,1,1,1,0,1,1,1 }, // = I
{ 1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1 }, // = J
{ 1,1,1,1,1,1,0,0,1,1,0,1,0,1,1,0,1 }, // = K
{ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1 }, // = L
{ 1,1,0,0,1,1,0,0,0,1,0,1,1,1,1,1,1 }, // = M
{ 1,1,0,0,1,1,0,0,0,1,1,1,0,1,1,1,1 }, // = N
{ 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 }, // = O
{ 0,0,0,1,1,1,0,0,1,1,1,0,1,1,1,0,1 }, // = P
{ 0,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1 }, // = Q
{ 0,0,0,1,1,1,0,0,1,1,1,0,0,1,1,0,1 }, // = R
{ 0,0,1,0,0,0,1,0,1,1,1,0,1,1,1,0,1 }, // = S
{ 0,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1 }, // = T
{ 1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 }, // = U
{ 1,1,1,1,1,1,0,0,1,1,0,1,1,1,0,1,1 }, // = V
{ 1,1,0,0,1,1,0,0,1,1,1,1,0,1,0,1,1 }, // = W
{ 1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1 }, // = X
{ 1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1 }, // = Y
{ 0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,1 }, // = Z
{ 0,0,0,0,0,0,0,0,1,1,0,1,1,1,0,1,1 }, // = 0
{ 1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1 }, // = 1
{ 0,0,0,1,0,0,0,1,1,1,1,0,1,1,1,0,1 }, // = 2
{ 0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1 }, // = 3
{ 1,1,0,0,1,1,1,0,1,1,1,0,1,1,1,0,1 }, // = 4
{ 0,0,1,0,0,0,1,0,1,1,1,0,1,1,1,0,1 }, // = 5
{ 0,0,1,0,0,0,0,0,1,1,1,0,1,1,1,0,1 }, // = 6
{ 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1 }, // = 7
{ 0,0,0,0,0,0,0,0,1,1,1,0,1,1,1,0,1 }, // = 8
{ 0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,0,1 }, // = 9
{ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, // = Space
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, // = Full Lit
{ 1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1 } // = SS
};
// LTP587P Segments: A,B,C,D,E,F,G,H,K,M,N,P,R,S,T,U,dp

boolean lampvals[9][9] = {
{ 0,1,1,1,1,1,1,1,1 }, // = Q or A or P
{ 1,0,1,1,1,1,1,1,1 }, // = W or S or Y
{ 1,1,0,1,1,1,1,1,1 }, // = E or D or X
{ 1,1,1,0,1,1,1,1,1 }, // = R or F or C
{ 1,1,1,1,0,1,1,1,1 }, // = T or G or V
{ 1,1,1,1,1,0,1,1,1 }, // = Z or H or B
{ 1,1,1,1,1,1,0,1,1 }, // = U or J or N
{ 1,1,1,1,1,1,1,0,1 }, // = I or K or M
{ 1,1,1,1,1,1,1,1,0 } // = O or L
};

int value_row1 = 0;
int value_row2 = 0;
int value_row3 = 0;
char key = 91;

int led1 = 40;
int led2 = 42;
int led3 = 44;
int led4 = 46;
int led5 = 48;
int wait = 100;

void setup() {
for (int index = 0; index <= 3; index++) {
pinMode(anode[index], OUTPUT);
digitalWrite(anode[index], 1);
}
for (int index = 0; index <= 16; index++) {
pinMode(segment[index], OUTPUT);
digitalWrite(segment[index], 1);
}
// initialize the digital pins as an output.
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);
pinMode(led4, OUTPUT);
pinMode(led5, OUTPUT);
for (int index = 0; index <= 2; index++) {
pinMode (lanode[index], OUTPUT);
digitalWrite (lanode[index], 1);
}
for (int index = 0; index <= 8; index++) {
pinMode(lamp[index], OUTPUT);
digitalWrite(lamp[index], 1);
}
}

void loop() {
sixteenSegWrite(0, 38);
sixteenSegWrite(1, 38);
sixteenSegWrite(2, 38);
sixteenSegWrite(3, 38);

digitalWrite(led1, HIGH); // turn the LED on (HIGH is the voltage level)
delay(200); // wait for a second
digitalWrite(led1, LOW); // turn the LED off by making the voltage LOW
delay(wait); // wait for a second
digitalWrite(led2, HIGH); // turn the LED on (HIGH is the voltage level)
delay(200); // wait for a second
digitalWrite(led2, LOW); // turn the LED off by making the voltage LOW
delay(wait); // wait for a second
digitalWrite(led3, HIGH); // turn the LED on (HIGH is the voltage level)
delay(200); // wait for a second
digitalWrite(led3, LOW); // turn the LED off by making the voltage LOW
delay(wait); // wait for a second
digitalWrite(led4, HIGH); // turn the LED on (HIGH is the voltage level)
delay(200); // wait for a second
digitalWrite(led4, LOW); // turn the LED off by making the voltage LOW
delay(wait); // wait for a second
digitalWrite(led5, HIGH); // turn the LED on (HIGH is the voltage level)
delay(200); // wait for a second
digitalWrite(led5, LOW); // turn the LED off by making the voltage LOW
delay(wait); // wait for a second

for (int index = 0; index <= 2; index++) {
digitalWrite(lanode[index], 0);
for (int mychar = 0; mychar < 9; mychar++) {
for (int sindex = 0; sindex < 9; sindex++) {
digitalWrite(lamp[sindex], lampvals[mychar][sindex]);
delay(30);
}
}
digitalWrite(lanode[index], 1);
}
}

void sixteenSegWrite(int digit, int character) {
digitalWrite(anode[digit],0);
for (int index = 0; index < 17; index++) {
digitalWrite(segment[index], segmentvals[character][index]);
}
}

Step 8: More Software!

第八步:再多一些软件!









So we first created a function for each mode the Enigma operates in:
首先,我们写了个函数,给每个Enigma机工作模式用。
In Mode 0, Default Mode, the Enigma is nothing but a simple typewriter with a Marquee that displays its Model Number.
在模式0、默认模式,Enigma机仅仅是一台普通打字机,以跑马灯方式显示它的型号。
Mode 1 allows the user to select the 3 (out of 8) Rotors he will use along with which one (of the 2) Reflector he wants to use.
模式1下,允许用户从八个转子中选取三个,两个反射器中选择一个进行使用。
In Mode 2, the user can select the Internal position of each Rotor.
模式2下,允许用户排列转子次序。
Mode 3 is used to specify the starting (external) position of each Rotor.
模式3用于自定义转子初始字母排列。
In Mode 4, a user can enter up to 10 Swapped pairs of letters.
选择模式4,用户最多可以使用接线板上10对交换字母排列。
Mode 5 is Run mode and at that point, the Enigma will encrypt or decrypt any letter typed on the keyboard.
模式5是运行模式,此时Enigma机能加解密任何从键盘录入的信息。
Here is the Complete sketch that runs the whole Enigma:
以下是整个Enigma机工作流程完整程序片段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
/* S&T GeoTronics Enigma Code. This Arduino Mega custom shield is programmed to replicate
exactly the behavior of a true German M4 Enigma machine.
It uses 4 16-Segment units, 5 LEDs, 26 Lamps setup as keyboard, 26 keyboard buttons
& 10 Function keys. The 115 light emitting diodes are charlie-plexed to minimize the
amount of pins needed down to 38 and all 36 pushbuttons keys are sharing a total of 4 pins.
Designed, assembled & programmed by Marc Tessier & James Sanderson 9/20/13
*/
// Define the variables
unsigned long time = millis();
unsigned long otime = time;
int inpin[4] = { A0, A1, A2, A3 };
int inval[4] = { 0, 0, 0, 0 };
int keyval = 100;
boolean windex = 0;
boolean windex1 = 0;
boolean windex2 = 0;
int lampval = 100;
int procesval = 0;
int procesvala = 0;
int mode = 0;
unsigned long mtime;
int mdex = 0;

// Define each Nixie character
int dig1 = 37;
int dig2 = 37;
int dig3 = 37;
int dig4 = 37;

int data[36] = { 36,36,36,36,18,39,19,36,6,4,14,19,17,14,13,8,2,18,36,4,13,8,6,12,0,36,12,0,17,10,36,30,36,36,36,36 };

// Define the 16-Segments Pins as 2 Arrays
int segment[17] = { 24,22,25,31,38,36,32,30,28,26,23,27,33,35,34,29,37 }; //cathode array
int anode[4] = { 39,41,43,45 }; //annode array commin annode

// Define the 26 Lamps as a 2D Array
int lamparray[26][2] = {
{12,10}, {13,5}, {13,7}, {12,8}, {11,8}, {12,7,}, {12,6}, {12,5}, {11,3},
{12,4}, {12,3}, {13,2}, {13,3}, {13,4}, {11,2}, {13,10}, {11,10}, {11,7},
{12,9}, {11,6}, {11,4}, {13,6}, {11,9}, {13,8}, {13,9}, {11,5}
};

// Define the 12 Lamp Pins for initialization
int lamppin[12] = { 2,3,4,5,6,7,8,9,10,11,12,13 }; //2 to 10 cathode, 11 to 13 common annode

// Define each LTP587P Segments: A,B,C,D,E,F,G,H,K,M,N,P,R,S,T,U,dp
boolean segmentvals[40][17] = {
{ 0,0,0,0,1,1,0,0,1,1,1,0,1,1,1,0,1 }, // = A 0
{ 0,0,0,0,0,0,1,1,1,0,1,0,1,0,1,1,1 }, // = B 1
{ 0,0,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1 }, // = C 2
{ 0,0,0,0,0,0,1,1,1,0,1,1,1,0,1,1,1 }, // = D 3
{ 0,0,1,1,0,0,0,0,1,1,1,0,1,1,1,0,1 }, // = E 4
{ 0,0,1,1,1,1,0,0,1,1,1,0,1,1,1,0,1 }, // = F 5
{ 0,0,1,0,0,0,0,0,1,1,1,0,1,1,1,1,1 }, // = G 6
{ 1,1,0,0,1,1,0,0,1,1,1,0,1,1,1,0,1 }, // = H 7
{ 0,0,1,1,0,0,1,1,1,0,1,1,1,0,1,1,1 }, // = I 8
{ 1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1 }, // = J 9
{ 1,1,1,1,1,1,0,0,1,1,0,1,0,1,1,0,1 }, // = K 10
{ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1 }, // = L 11
{ 1,1,0,0,1,1,0,0,0,1,0,1,1,1,1,1,1 }, // = M 12
{ 1,1,0,0,1,1,0,0,0,1,1,1,0,1,1,1,1 }, // = N 13
{ 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 }, // = O 14
{ 0,0,0,1,1,1,0,0,1,1,1,0,1,1,1,0,1 }, // = P 15
{ 0,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1 }, // = Q 16
{ 0,0,0,1,1,1,0,0,1,1,1,0,0,1,1,0,1 }, // = R 17
{ 0,0,1,0,0,0,1,0,1,1,1,0,1,1,1,0,1 }, // = S 18
{ 0,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1 }, // = T 19
{ 1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 }, // = U 20
{ 1,1,1,1,1,1,0,0,1,1,0,1,1,1,0,1,1 }, // = V 21
{ 1,1,0,0,1,1,0,0,1,1,1,1,0,1,0,1,1 }, // = W 22
{ 1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1 }, // = X 23
{ 1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1 }, // = Y 24
{ 0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,1 }, // = Z 25
{ 0,0,0,0,0,0,0,0,1,1,0,1,1,1,0,1,1 }, // = 0 26
{ 1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1 }, // = 1 27
{ 0,0,0,1,0,0,0,1,1,1,1,0,1,1,1,0,1 }, // = 2 28
{ 0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1 }, // = 3 29
{ 1,1,0,0,1,1,1,0,1,1,1,0,1,1,1,0,1 }, // = 4 30
{ 0,0,1,0,0,0,1,0,1,1,1,0,1,1,1,0,1 }, // = 5 31
{ 0,0,1,0,0,0,0,0,1,1,1,0,1,1,1,0,1 }, // = 6 32
{ 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1 }, // = 7 33
{ 0,0,0,0,0,0,0,0,1,1,1,0,1,1,1,0,1 }, // = 8 34
{ 0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,0,1 }, // = 9 35
{ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, // = Space 36
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, // = Full Lit 37
{ 1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1 }, // = SS 38
{ 0,1,1,1,0,0,0,1,0,0,1,1,0,1,1,0,1 } // = & 39
};
// LTP587P Segments: A,B,C,D,E,F,G,H,K,M,N,P,R,S,T,U,dp

// Define the 5 Mode LEDs
int led1 = 40;
int led2 = 42;
int led3 = 44;
int led4 = 46;
int led5 = 48;

//4,10,12,5,11,6,3,16,21,25,13,19,14,22,24,7,23,20,18,15,0,8,1,17,2,9
//Define the rotor values A B C D E F G H I J K L M N O P Q
static const int rotorvals[12][78] = {
{ 4,10,12,5,11,6,3,16,21,25,13,19,14,22,24,7,123,20,18,15,0,8,1,17,2,9,
4,10,12,5,11,6,3,16,21,25,13,19,14,22,24,7,123,20,18,15,0,8,1,17,2,9,
4,10,12,5,11,6,3,16,21,25,13,19,14,22,24,7,123,20,18,15,0,8,1,17,2,9 }, // wheel 1

{ 0,9,3,10,118,8,17,20,23,1,11,7,22,19,12,2,16,6,25,13,15,24,5,21,14,4,
0,9,3,10,118,8,17,20,23,1,11,7,22,19,12,2,16,6,25,13,15,24,5,21,14,4,
0,9,3,10,118,8,17,20,23,1,11,7,22,19,12,2,16,6,25,13,15,24,5,21,14,4 }, // wheel 2

{ 1,3,5,7,9,11,2,15,17,19,23,21,25,13,24,4,8,22,6,0,10,112,20,18,16,14,
1,3,5,7,9,11,2,15,17,19,23,21,25,13,24,4,8,22,6,0,10,112,20,18,16,14,
1,3,5,7,9,11,2,15,17,19,23,21,25,13,24,4,8,22,6,0,10,112,20,18,16,14 }, // wheel 3

{ 4,18,14,21,15,25,9,0,24,116,20,8,17,7,23,11,13,5,19,6,10,3,2,12,22,1,
4,18,14,21,15,25,9,0,24,116,20,8,17,7,23,11,13,5,19,6,10,3,2,12,22,1,
4,18,14,21,15,25,9,0,24,116,20,8,17,7,23,11,13,5,19,6,10,3,2,12,22,1 }, // wheel 4

{ 21,25,1,17,6,8,19,24,20,15,18,3,13,7,11,23,0,22,12,9,16,14,5,4,2,110,
21,25,1,17,6,8,19,24,20,15,18,3,13,7,11,23,0,22,12,9,16,14,5,4,2,110,
21,25,1,17,6,8,19,24,20,15,18,3,13,7,11,23,0,22,12,9,16,14,5,4,2,110 }, // wheel 5

{ 9,15,6,21,14,20,12,5,24,16,1,4,113,7,25,17,3,10,0,18,23,11,8,2,19,122,
9,15,6,21,14,20,12,5,24,16,1,4,113,7,25,17,3,10,0,18,23,11,8,2,19,122,
9,15,6,21,14,20,12,5,24,16,1,4,113,7,25,17,3,10,0,18,23,11,8,2,19,122 }, // wheel 6

{ 13,25,9,7,6,17,2,23,12,24,18,22,101,14,20,5,0,8,21,11,15,4,10,16,3,119,
13,25,9,7,6,17,2,23,12,24,18,22,101,14,20,5,0,8,21,11,15,4,10,16,3,119,
13,25,9,7,6,17,2,23,12,24,18,22,101,14,20,5,0,8,21,11,15,4,10,16,3,119 }, // wheel 7

{ 5,10,16,7,19,11,23,14,2,1,9,18,115,3,25,17,0,12,4,22,13,8,20,24,6,121,
5,10,16,7,19,11,23,14,2,1,9,18,115,3,25,17,0,12,4,22,13,8,20,24,6,121,
5,10,16,7,19,11,23,14,2,1,9,18,115,3,25,17,0,12,4,22,13,8,20,24,6,121 }, // wheel 8

{ 11,4,24,9,21,2,13,8,23,22,15,1,16,12,3,17,19,0,10,25,6,5,20,7,14,18,
11,4,24,9,21,2,13,8,23,22,15,1,16,12,3,17,19,0,10,25,6,5,20,7,14,18,
11,4,24,9,21,2,13,8,23,22,15,1,16,12,3,17,19,0,10,25,6,5,20,7,14,18 }, // Beta

{ 5,18,14,10,0,13,20,4,17,7,12,1,19,8,24,2,22,11,16,15,25,23,21,6,9,3,
5,18,14,10,0,13,20,4,17,7,12,1,19,8,24,2,22,11,16,15,25,23,21,6,9,3,
5,18,14,10,0,13,20,4,17,7,12,1,19,8,24,2,22,11,16,15,25,23,21,6,9,3 }, // Gamma

{ 4,13,10,16,0,20,24,22,9,8,2,14,15,1,11,12,3,23,25,21,5,19,7,17,6,18,
4,13,10,16,0,20,24,22,9,8,2,14,15,1,11,12,3,23,25,21,5,19,7,17,6,18,
4,13,10,16,0,20,24,22,9,8,2,14,15,1,11,12,3,23,25,21,5,19,7,17,6,18}, // = UKW-B

{ 17,3,14,1,9,13,19,10,21,4,7,12,11,5,2,22,25,0,23,6,24,8,15,18,20,16,
17,3,14,1,9,13,19,10,21,4,7,12,11,5,2,22,25,0,23,6,24,8,15,18,20,16,
17,3,14,1,9,13,19,10,21,4,7,12,11,5,2,22,25,0,23,6,24,8,15,18,20,16 } // = UKW-C
};

static const int rotorvali[10][78] = {
{ 20,22,24,6,0,3,5,15,21,25,1,4,2,10,12,19,7,23,18,11,17,8,13,16,14,9,
20,22,24,6,0,3,5,15,21,25,1,4,2,10,12,19,7,23,18,11,17,8,13,16,14,9,
20,22,24,6,0,3,5,15,21,25,1,4,2,10,12,19,7,23,18,11,17,8,13,16,14,9 }, //wheel 1 i

{ 0,9,15,2,25,22,17,11,5,1,3,10,14,19,24,20,16,6,4,13,7,23,12,8,21,18,
0,9,15,2,25,22,17,11,5,1,3,10,14,19,24,20,16,6,4,13,7,23,12,8,21,18,
0,9,15,2,25,22,17,11,5,1,3,10,14,19,24,20,16,6,4,13,7,23,12,8,21,18 }, //wheel 2 i

{ 19,0,6,1,15,2,18,3,16,4,20,5,21,13,25,7,24,8,23,9,22,11,17,10,14,12,
19,0,6,1,15,2,18,3,16,4,20,5,21,13,25,7,24,8,23,9,22,11,17,10,14,12,
19,0,6,1,15,2,18,3,16,4,20,5,21,13,25,7,24,8,23,9,22,11,17,10,14,12 }, //wheel 3 i

{ 7,25,22,21,0,17,19,13,11,6,20,15,23,16,2,4,9,12,1,18,10,3,24,14,8,5,
7,25,22,21,0,17,19,13,11,6,20,15,23,16,2,4,9,12,1,18,10,3,24,14,8,5,
7,25,22,21,0,17,19,13,11,6,20,15,23,16,2,4,9,12,1,18,10,3,24,14,8,5 }, //wheel 4 i

{ 16,2,24,11,23,22,4,13,5,19,25,14,18,12,21,9,20,3,10,6,8,0,17,15,7,1,
16,2,24,11,23,22,4,13,5,19,25,14,18,12,21,9,20,3,10,6,8,0,17,15,7,1,
16,2,24,11,23,22,4,13,5,19,25,14,18,12,21,9,20,3,10,6,8,0,17,15,7,1 }, //wheel 5 i

{ 18,10,23,16,11,7,2,13,22,0,17,21,06,12,4,1,9,15,19,24,5,3,25,20,8,14,
18,10,23,16,11,7,2,13,22,0,17,21,06,12,4,1,9,15,19,24,5,3,25,20,8,14,
18,10,23,16,11,7,2,13,22,0,17,21,06,12,4,1,9,15,19,24,5,3,25,20,8,14 }, //wheel 6 i

{ 16,12,6,24,21,15,4,3,17,2,22,19,8,0,13,20,23,5,10,25,14,18,11,7,9,1,
16,12,6,24,21,15,4,3,17,2,22,19,8,0,13,20,23,5,10,25,14,18,11,7,9,1,
16,12,6,24,21,15,4,3,17,2,22,19,8,0,13,20,23,5,10,25,14,18,11,7,9,1 }, //wheel 7 i

{ 16,9,8,13,18,0,24,3,21,10,1,5,17,20,7,12,2,15,11,4,22,25,19,6,23,14,
16,9,8,13,18,0,24,3,21,10,1,5,17,20,7,12,2,15,11,4,22,25,19,6,23,14,
16,9,8,13,18,0,24,3,21,10,1,5,17,20,7,12,2,15,11,4,22,25,19,6,23,14 }, //wheel 8 i

{ 17,11,5,14,1,21,20,23,7,3,18,0,13,6,24,10,12,15,25,16,22,4,9,8,2,19,
17,11,5,14,1,21,20,23,7,3,18,0,13,6,24,10,12,15,25,16,22,4,9,8,2,19,
17,11,5,14,1,21,20,23,7,3,18,0,13,6,24,10,12,15,25,16,22,4,9,8,2,19 }, //Beta i

{ 4,11,15,25,7,0,23,9,13,24,3,17,10,5,2,19,18,8,1,12,6,22,16,21,14,20,
4,11,15,25,7,0,23,9,13,24,3,17,10,5,2,19,18,8,1,12,6,22,16,21,14,20,
4,11,15,25,7,0,23,9,13,24,3,17,10,5,2,19,18,8,1,12,6,22,16,21,14,20 } //Gamma i
};

// Define a 2D Array for keeping the wheel locations & positions
int wheel[3][3] = {
{26,0,0}, {26,0,0}, {26,0,0}
};
int reflect[2] = {1, 0};

// Define Array for plugbord values 25 x2 position 0 holds use position 1 holds value int plugu holds the total nomber of plugs used (10 max)
int plugval[2][26] = {
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25 }
};
int pluguse = 0;
int paindex = 0;
int pbindex = 1;

void setup() {
// Initialize all 38 LED pins as Output
for (int index = 0; index <= 11; index++) {
pinMode(lamppin[index], OUTPUT);
digitalWrite(lamppin[index],1);
}
for (int index = 0; index <= 3; index++) {
pinMode(anode[index], OUTPUT);
digitalWrite(anode[index], 1);
}
for (int index = 0; index <= 16; index++) {
pinMode(segment[index], OUTPUT);
digitalWrite(segment[index], 1);
}
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);
pinMode(led4, OUTPUT);
pinMode(led5, OUTPUT);

// Serial.begin(9600);
// Initialize all 4 pusbutton pins as Input
for (int index = 0; index <= 3; index++) {
pinMode(inpin[index], INPUT);
}
}

void loop() {
// Keyboard debounce & test for new key pressed
time = millis();
if (time > otime + 500) keyval = readkbde();
if ((keyval == 45) && (windex == 1)) modeselect();
// The whole Enigma machine operation revolves around which Operating Mode is current
if (mode == 0) mode0();
else if (mode == 1) mode1();
else if (mode == 2) mode2();
else if (mode == 3) mode3();
else if (mode == 4) mode4();
else if (mode == 5) mode5();
else {}

//Serial.println(keyval); // for debuging prints keybord value to serial monitor// for run or del
}

// This function takes care of figuring out which key has been pressed & returns a unique Integer
int readkbde() {
int kval = 100;
for (int index = 0; index <= 3; index++) {
inval[index] = analogRead(inpin[index]);
} //Reads analog input values
if ((inval[0] > 925) && (inval[1] > 828) && (inval[2] > 730) && (inval[3] > 828)) kval = 100; // no key press
else if ((inval[0] < 924) && (inval[0] > 915)) kval = 49; //up arrow 4
else if ((inval[0] < 914) && (inval[0] > 903)) kval = 48; //up arrow 3
else if ((inval[0] < 902) && (inval[0] > 887)) kval = 47; //up arrow 2
else if ((inval[0] < 886) && (inval[0] > 865)) kval = 46; //up arrow 1
else if ((inval[0] < 864) && (inval[0] > 836)) kval = 45; //mode
else if ((inval[0] < 834) && (inval[0] > 793)) kval = 44; //enter
else if ((inval[0] < 792) && (inval[0] > 724)) kval = 43;
else if ((inval[0] < 723) && (inval[0] > 594)) kval = 42;
else if ((inval[0] < 593) && (inval[0] > 260)) kval = 41;
else if (inval[0] < 259) kval = 40;
else if ((inval[1] < 827) && (inval[1] > 807)) kval = 14;
else if ((inval[1] < 806) && (inval[1] > 781)) kval = 8;
else if ((inval[1] < 780) && (inval[1] > 749)) kval = 20;
else if ((inval[1] < 748) && (inval[1] > 706)) kval = 25;
else if ((inval[1] < 705) && (inval[1] > 647)) kval = 19;
else if ((inval[1] < 646) && (inval[1] > 555)) kval = 17;
else if ((inval[1] < 554) && (inval[1] > 418)) kval = 4;
else if ((inval[1] < 417) && (inval[1] > 169)) kval = 22;
else if (inval[1] < 168) kval = 16;
else if ((inval[2] < 729) && (inval[2] > 699)) kval = 10;
else if ((inval[2] < 698) && (inval[2] > 660)) kval = 9;
else if ((inval[2] < 659) && (inval[2] > 611)) kval = 7;
else if ((inval[2] < 610) && (inval[2] > 547)) kval = 6;
else if ((inval[2] < 546) && (inval[2] > 455)) kval = 5;
else if ((inval[2] < 454) && (inval[2] > 331)) kval = 3;
else if ((inval[2] < 330) && (inval[2] > 127)) kval = 18;
else if (inval[2] < 126) kval = 0;
else if ((inval[3] < 827) && (inval[3] > 807)) kval = 11;
else if ((inval[3] < 806) && (inval[3] > 781)) kval = 12;
else if ((inval[3] < 780) && (inval[3] > 749)) kval = 13;
else if ((inval[3] < 748) && (inval[3] > 706)) kval = 1;
else if ((inval[3] < 705) && (inval[3] > 647)) kval = 21;
else if ((inval[3] < 646) && (inval[3] > 555)) kval = 2;
else if ((inval[3] < 554) && (inval[3] > 418)) kval = 23;
else if ((inval[3] < 417) && (inval[3] > 169)) kval = 24;
else if (inval[3] < 169) kval = 15;
else kval = 100;
if (kval < 99) otime = millis(); // Starts key debounce timer
if ((kval >= 0) && (kval <= 99)) windex = 1;
// windex showing true (1) indicates the return of a fresh key stroke
return kval;
}

// Function to change operating Mode
void modeselect() {
mode++;
if (mode >= 6) mode = 0;
windex = 0;
}

// Default Mode: Enigma is a Typewriter
void mode0() {
if ((keyval >= 0) && (keyval <= 25)) lampval = keyval;
lampita();
marquee();
lampitb();
}

// Select the Rotors & the Reflector
void mode1() {
int index;
digitalWrite(led1, HIGH);
if (windex == 1) {
if ((keyval == 43) || (keyval == 46)) {
reflect[0]++;
if (reflect[0] > 2) {
reflect[0] = 1;
}
windex = 0;
}
}
if (windex == 1) {
if (keyval == 47) {
for (index = wheel[2][0]; (index == wheel[1][0]) || (index == wheel[0][0]) || (index == wheel[2][0]); index++) {
if (index > 33) index = 26;
}
wheel[2][0] = index;
windex = 0;
}
}
if (windex == 1) {
if (keyval == 48) {
for (index = wheel[1][0]; (index == wheel[2][0]) || (index == wheel[0][0]) || (index == wheel[1][0]); index++) {
if (index > 33) index = 26;
}
wheel[1][0] = index;
windex = 0;
}
}
if (windex == 1) {
if (keyval == 49) {
for (index = wheel[0][0]; (index == wheel[2][0]) || (index == wheel[1][0]) || (index == wheel[0][0]); index++) {
if (index > 33) index = 26;
}
wheel[0][0] = index;
windex = 0;
}
}
if (windex == 1) {
if (keyval == 42) {
for (index = wheel[2][0]; (index == wheel[1][0]) || (index == wheel[0][0]) || (index == wheel[2][0]); index--) {
if (index < 28) index = 35;
}
wheel[2][0] = index;
windex = 0;
}
}
if (windex == 1) {
if (keyval == 41) {
for (index = wheel[1][0]; (index == wheel[2][0]) || (index == wheel[0][0]) || (index == wheel[1][0]); index--) {
if (index < 28) index = 35;
}
wheel[1][0] = index;
windex = 0;
}
}
if (windex == 1) {
if (keyval == 40) {
for (index = wheel[0][0]; (index == wheel[2][0]) || (index == wheel[1][0]) || (index == wheel[0][0]); index--) {
if (index < 28) index = 35;
}
wheel[0][0] = index;
windex = 0;
}
}
dig1 = reflect[0]; dig2 = wheel[2][0]; dig3 = wheel[1][0]; dig4 = wheel[0][0];
nixisend();
dig1 = 37; dig2 = 37; dig3 = 37; dig4 = 37;
digitalWrite(led1, LOW);
}

// Position the Inner setting of each Rotor
void mode2() {
digitalWrite(led2, HIGH);
if (windex == 1) {
if (keyval == 47) { wheel[2][1]++; if (wheel[2][1] > 25) wheel[2][1] = 0; }
if (keyval == 48) { wheel[1][1]++; if (wheel[1][1] > 25) wheel[1][1] = 0; }
if (keyval == 49) { wheel[0][1]++; if (wheel[0][1] > 25) wheel[0][1] = 0; }
if (keyval == 42) { wheel[2][1]--; if (wheel[2][1] < 0) wheel[2][1] = 25; }
if (keyval == 41) { wheel[1][1]--; if (wheel[1][1] < 0) wheel[1][1] = 25; }
if (keyval == 40) { wheel[0][1]--; if (wheel[0][1] < 0) wheel[0][1] = 25; }
windex = 0;
}
dig2 = wheel[2][1]; dig3 = wheel[1][1]; dig4 = wheel[0][1]; dig1 = 0;
nixisend();
dig1 = 37; dig2 = 37; dig3 = 37; dig4 = 37;
digitalWrite(led2, LOW);
}

// Position the Start character of each Wheel
void mode3() {
digitalWrite(led3, HIGH);
if (windex == 1) {
if (keyval == 46) { reflect[1]++; if (reflect[1] > 25) reflect[1] = 0; }
if (keyval == 47) { wheel[2][2]++; if (wheel[2][2] > 25) wheel[2][2] = 0; }
if (keyval == 48) { wheel[1][2]++; if (wheel[1][2] > 25) wheel[1][2] = 0; }
if (keyval == 49) { wheel[0][2]++; if (wheel[0][2] > 25) wheel[0][2] = 0; }
if (keyval == 43) { reflect[1]--; if (reflect[1] < 0) reflect[1] = 25; }
if (keyval == 42) { wheel[2][2]--; if (wheel[2][2] < 0) wheel[2][2] = 25; }
if (keyval == 41) { wheel[1][2]--; if (wheel[1][2] < 0) wheel[1][2] = 25; }
if (keyval == 40) { wheel[0][2]--; if (wheel[0][2] < 0) wheel[0][2] = 25; }
windex = 0;
}
dig1 = reflect[1]; dig2 = wheel[2][2]; dig3 = wheel[1][2]; dig4 = wheel[0][2];
nixisend();
dig1 = 37; dig2 = 37; dig3 = 37; dig4 = 37;
digitalWrite(led3, LOW);
}

// Define the Plugboard pairs
void mode4() {
int index = 0;
digitalWrite(led4, HIGH);
if (pluguse <= 9) {
if (plugval[0][paindex] == 1) {
for (index = paindex;(index == paindex) || (index == pbindex) || (plugval[0][index] == 1); index++) {
if (index > 24) index = -1;
}
paindex = index;
}
if (plugval[0][pbindex] == 1) {
for (index = pbindex;(index == pbindex) || (index == paindex) || (plugval[0][index] == 1); index++) {
if (index > 24) index = -1;
}
pbindex = index;
}
if (windex == 1) {
if (keyval == 46) {
for (index = paindex;(index == paindex) || (index == pbindex) || (plugval[0][index] == 1); index++) {
if (index > 24) index = -1;
}
paindex = index;
windex = 0;
}
if (keyval == 43) {
for (index = paindex;(index == paindex) || (index == pbindex) || (plugval[0][index] == 1); index--) {
if (index < 1) index = 26;
}
paindex = index;
windex = 0;
}
if (keyval == 49) {
for (index = pbindex;(index == pbindex) || (index == paindex) || (plugval[0][index] == 1); index++) {
if (index > 24) index = -1;
}
pbindex = index;
windex = 0;
}
if (keyval == 40) {
for (index = pbindex;(index == pbindex) || (index == paindex) || (plugval[0][index] == 1); index--) {
if (index < 1) index = 26;
}
pbindex = index;
windex = 0;
}
if (keyval == 44) {
plugval[0][paindex] = 1;
plugval[1][paindex] = pbindex;
plugval[0][pbindex] = 1;
plugval[1][pbindex] = paindex;
windex = 0;
pluguse++;
}
}
dig1 = paindex; dig2 = 19; dig3 = 14; dig4 = pbindex;
nixisend();
dig1 = 37; dig2 = 37; dig3 = 37; dig4 = 37;
}
else done();
digitalWrite(led4, LOW);
}

// This is Normal Operation Mode to Encrypt/Decrypt
void mode5() {
int pv = 0;
digitalWrite(led5, HIGH);

if ((keyval >= 0) && (keyval <= 25) && (windex == 1)) {
procesvala = keyval;
indexwheels();
}
windex = 0;
procesval = procesvala;
procesval = plugval[1][procesval];
//Serial.print(procesval); Serial.print(" ");

pv = procesval + (wheel[0][2] - wheel[0][1]);
if (pv < 0) pv += 26;
procesval = rotorvals[wheel[0][0] - 27][pv];
if (procesval >= 100) procesval -= 100;
procesval = (procesval - (wheel[0][2] - wheel[0][1]));
if (procesval < 0) procesval += 26;
if (procesval > 25) procesval -= 26;
//Serial.print(procesval); Serial.print(" ");

pv = procesval + (wheel[1][2] - wheel[1][1]);
if (pv < 0) pv += pv + 26;
procesval = rotorvals[wheel[1][0] - 27][pv];
if (procesval >= 100) procesval -= 100;
procesval = (procesval - (wheel[1][2] - wheel[1][1]));
if (procesval < 0) procesval += 26;
if (procesval > 25) procesval -= 26;
//Serial.print(procesval); Serial.print(" ");

pv = procesval + (wheel[2][2] - wheel[2][1]);
if (pv < 0) pv += 26;
procesval = rotorvals[wheel[2][0] - 27][pv];
if (procesval >= 100) procesval -= 100;
procesval = (procesval - (wheel[2][2] - wheel[2][1]));
if (procesval < 0) procesval += 26;
if (procesval > 25) procesval -= 26;
//Serial.print(procesval); Serial.print(" ");

pv = procesval;
procesval = rotorvals[reflect[0] + 7][pv];
if (procesval >= 100) procesval -= 100;
if (procesval < 0) procesval += 26;
if (procesval > 25) procesval -= 26;
//Serial.print(procesval); Serial.print(" ");

procesval = rotorvals[reflect[0] + 9][procesval];
//Serial.print(procesval); Serial.print(" ");

pv = procesval + 26;
procesval = rotorvali[reflect[0] + 7][pv];
if (procesval >= 100) procesval -= 100;
if (procesval < 0) procesval += 26;
if (procesval > 25) procesval -= 26;
//Serial.print(procesval); Serial.print(" ");

pv = procesval + (wheel[2][2] - wheel[2][1]);
if (pv < 0) pv += 26;
procesval = rotorvali[wheel[2][0] - 27][pv];
if (procesval >= 100) procesval -= 100;
procesval = (procesval - (wheel[2][2] - wheel[2][1]));
if (procesval < 0) procesval += 26;
if (procesval > 25) procesval -= 26;
//Serial.print(procesval); Serial.print(" ");

pv = procesval + (wheel[1][2] - wheel[1][1]);
if (pv < 0) pv += 26;
procesval = rotorvali[wheel[1][0] - 27][pv];
if (procesval >= 100) procesval -= 100;
procesval = (procesval - (wheel[1][2] - wheel[1][1]));
if (procesval < 0) procesval += 26;
if (procesval > 25) procesval -= 26;
//Serial.print(procesval); Serial.print(" ");

pv = procesval + (wheel[0][2] - wheel[0][1]);
if (pv < 0) pv += 26;
procesval = rotorvali[wheel[0][0] - 27][pv];
if (procesval >= 100) procesval -= 100;
procesval = (procesval - (wheel[0][2] - wheel[0][1]));
if (procesval < 0) procesval += 26;
if (procesval > 25) procesval -= 26;

//Serial.print(procesval); Serial.print(" ");
procesval = plugval[1][procesval];

lampval = procesval;
//Serial.println(lampval);
dig1 = reflect[1]; dig2 = wheel[2][2]; dig3 = wheel[1][2]; dig4 = wheel[0][2];
lampita();
nixisend();
lampitb();
dig1 = 37; dig2 = 37; dig3 = 37; dig4 = 37;
digitalWrite(led5, LOW);
}

// Helper Function to light the proper key
void lampita() {
digitalWrite(lamparray[lampval][0], 0);
digitalWrite(lamparray[lampval][1], 0);
}
void lampitb(){
digitalWrite(lamparray[lampval][0], 1);
digitalWrite(lamparray[lampval][1], 1);
}

// Help Function to illuminate "Nixies"
void nixisend() {
sixteenSegWrite(0, dig1);
sixteenSegWrite(1, dig2);
sixteenSegWrite(2, dig3);
sixteenSegWrite(3, dig4);
}

void marquee() {
time = millis();
if (mtime < time) {
mtime = time + 400;
mdex++;
}
dig1 = data[mdex];
dig2 = data[mdex + 1];
dig3 = data[mdex + 2];
dig4 = data[mdex + 3];
if (mdex >= 31) mdex = 0;
nixisend();
}
// Function that actually turns on each of 17 appropriate segments on each "Nixie"
void sixteenSegWrite(int digit, int character) {
digitalWrite(anode[digit],0);
for (int index = 0; index < 17; index++) {
digitalWrite(segment[index], segmentvals[character][index]);
}
delay(7);
for (int index = 0; index <= 16; index++) {
digitalWrite(segment[index], 1);
}
digitalWrite(anode[digit], 1);
}

void done() {
dig1 = 3; dig2 = 14; dig3 = 13; dig4 = 4;
nixisend();
dig1 = 37; dig2 = 37; dig3 = 37; dig4 = 37;
}

void indexwheels() {
//Serial.print(rotorvals[wheel[0][0]-27][wheel[0][2]]);
//Serial.print(" "); Serial.print(wheel[0][0]-27); Serial.print(" "); Serial.println(wheel[0][2]);
if (rotorvals[wheel[0][0] - 27][wheel[0][2]] >= 100) windex1 = 1;
wheel[0][2]++;
if (wheel[0][2] > 25) wheel[0][2] = 0;
windex = 0;
if (windex1 == 1) {
if (rotorvals[wheel[1][0] - 27][wheel[1][2]] >= 100) windex2 = 1;
wheel[1][2]++;
if (wheel[1][2] > 25) wheel[1][2] = 0;
}
windex1 = 0;
if (windex2 == 1) {
wheel[2][2]++;
if (wheel[2][2] > 25) wheel[2][2] = 0;
windex2 = 0;
}
}

IF there is enough interest, we plan on are creating a PCB that would will allow for a much easier assembly of this wonderful fully functional Enigma replica. Please visit http://www.stgeotronics.com to find out about availability, pricing & to place your order or pre-order now. The Circuit schematics are published, so the PCB has entered it’s development stage. Soon to be tested.
如果有足够的利润,我们将研发能够使全功能Enigma机复制品装载更为容易的印刷电路板。请登陆 http://www.stgeotronics.com 查询商品上架与否、价格、下单或预订吧。电路图已经发布了,印刷电路也已进入开发阶段,即将内测。

Step 9: Circuit Schematics

第九步:电路图


In response to the popular demand, here are the two Circuit Schematics.
徇众要求,电路图两份在此。
The first one shows how our fake nixie tubes (the 4 elevated 16-Segment units) are wired in order to provide the response that the rotors provide on a real Enigma machine. They are also used in each setup mode to provide feedback on the setting up of the machine.
第一个是仿电子管(4个16段显示单元)如何布线,用于显示转子在Enigma机上的输出信号。同时,它们也用于每种调试模式,反馈用户机器设定信息。
The second one shows how each of the 26 keyboard buttons and 10 function keys, the 26 key lamps & the 5 LEDS are all wired.
第二幅电路图显示26个字母按键及10个功能键、26个键盘灯和5个LED是如何布线的。
All LED resistors are 470 Ohms and all Pushbutton resistors are 1KOhm.
所有LED电阻都是470欧,而开关电阻则都是1千欧。
Stay tuned for the PCB design file…
印刷电路设计档仍在修正中。
We hope you enjoyed our first Instructable!
希望你享受我们第一份制作教程!
Thank You for your time.
感谢你抽出宝贵时间阅读!

Step 10: Prototype Boards

第十步:PCB样机版


Due to popular demand, we designed & ordered some Printed Circuit Boards. Well, our PCBs are finally in and at first glance, they look beautiful! We have been busy populating & testing one to make sure it performs as good as it looks and more importantly, as well as our proof-of-concept device.
徇众要求,我们设计及定制了一些印刷电路板。它们终于面世了,如此清纯可爱!我们忙于组装,并测试其中一块样品,确保它在功能上与外观一样完美无暇。更重要的是,能实现和那台原型测试机一样的功能。
The boards we ordered are almost perfect: they each need a little jumper wire to fix a small design flaw. This small flaw does not affect behavior or functionality and is an easy fix.
订购回来的底板几乎完美,只需一点引脚线去修补设计瑕疵。而这些瑕疵对功能没有影响,修理它们是小菜一碟。
With this jumper in place, you can now make your own Enigma Replica much easier & faster than running all wires this instructable shows. So, we are now happy to report that testing is completed & the new boards work just fine!
有了这些引脚,你能更容易制作自己的Enigma复刻机,比起教程里的布线方便多了。我们在此很高兴宣布,测试完成,新型板一样给力!
We are now accepting orders at www.stgeotronics.com & have started shipping.
Pictures of the assembly have been added as Step 11.
下单订购请登陆 http://www.stgeotronics.com ,已发货热卖中。组装图片请见第十一步。
Thank You for your overwhelming support & wonderful feedback!
感谢大家的不懈支持和宝贵反馈意见!

Step 11: Assembled Kits

第十一步:组装完成的作品



更多图片可以前往原文查看。
This assembly took one evening & you can look at assembly pictures above for an overview of the process.
花了一晚上组装完成,全过程的概览如上图所示。
Thank You for the support & feedback!
感谢你的支持与反馈!

更多

博主在深入了解Enigma机后,制作了一个JavaScript版本的虚拟机,实现了几乎全部功能,可以点击下方链接前往。
本站的JavaScript版本:Galaxy Mimi>应用>原创游戏>Enigma
这个版本暂未针对移动端进行优化,请使用桌面端打开。
而原文中基于Arduino开发的实体机器,由于制作过于复杂,博主还在进行研究,看上去所有的代码都是功能正常的。


本文翻译自:MAKE YOUR OWN ENIGMA REPLICA

参考文章:
恩尼格玛密码机
自己打造一台恩尼格码密码机
Bletchley Park

🍭支持一根棒棒糖!
0%