Arduino-WinForms Workstation
Building a Control Panel or Workstation for Your Arduino Project is Limited only by Your Imagination!
Devices & Components
1
Arduino Nano
Software & Tools
Arduino IDE
Project description
Code
Arduino_Workstation
cpp
Arduino Sketch Template in Workstation
1/* ============================================================================================ 2 3 Provides the basic COM interface for controlling the BDEE Computer from a windows workstation 4 i.e., desktop/laptop or whatever. The code is highly optimized for speed – not very elegant. 5 6 Created 2026/03/31 by Luis Furr 7 8 This example code is in the public domain. 9 10 https://www.automatedword.com 11 12 13 Provides the basic COM interface for controlling the BDEE Computer from a windows workstation 14 i.e., desktop/laptop or whatever. The code is highly optimized for speed – not very elegant. 15 16 Created 2026/03/31 by Luis Furr 17 18 This example code is in the public domain. 19 20 https://www.automatedword.com 21 22 23 ----------------------------------------------------------------------------------------------------- 24 Arduino Sketch BDEE Control Protocol: (Total: 16 digital pins – also pin 13 is used in the testbed). 25 26 1 bit (Read Pin) 0 = CPU Stopped (Enable Interface Operation) / 1 = CPU Running (Disable Interface). 27 1 bit (Read Pin) 0 = CPU Issues an interrupt to the Arduino. 28 1 bit (output) = Latch/Strobe (Held HIGH until 1-0-1). 29 30 2 bits (Control – to the 139)... 31 ------------------------------- 32 00: 0 - Disable Control & Enable Commands 33 01: 1 - Start 34 10: 2 - Stop 35 11: 3 - Step 36 37 3 bits (Commands – to the 138)... 38 ------------------------------- 39 000: 0 - Read Data Byte 40 001: 1 - Write Data Byte 41 010: 2 – Increment (Increments Data Pointer by 1) 42 011: 3 - Load Data Pointer 0 (Low-order byte) 43 100: 4 - Load Data Pointer 1 (Middle-order byte) 44 101: 5 - Load Data Pointer 2 (High-order byte) 45 110: 6 – Interrupt (Pings the Interrupt line to the CPU) 46 111: 7 – Reset CPU (Sets CPU Instruction Counter to 000000) 47 48 8 bits (Data Byte) - Low-order bit at Nano (Logic) pin D2 (Board pin# 5)... on up to pin D9. 49-------------------------------------------------------------------------------------------------- */ 50 51#define PIN_COMPUTER 13 // In the test-bed, this pin (as OUTPUT) simulates the computer's run status: true=running (for development/debug). 52#define PIN_INTERRUPT 12 // In production, this pin (as INPUT) will be the computer's way of signaling an interrupt back to the workstation. 53 54#define PIN_CONTROL_0 17 55#define PIN_CONTROL_1 18 56#define PIN_COMMAND_0 14 57#define PIN_COMMAND_1 15 58#define PIN_COMMAND_2 16 59 60#define PIN_STROBE 10 61#define PIN_TESTMODE 11 62#define PIN_CRUN 19 63 64#define PIN_DATAPORT_0 2 65#define PIN_DATAPORT_1 3 66#define PIN_DATAPORT_2 4 67#define PIN_DATAPORT_3 5 68#define PIN_DATAPORT_4 6 69#define PIN_DATAPORT_5 7 70#define PIN_DATAPORT_6 8 71#define PIN_DATAPORT_7 9 72 73#define SLOW_STROBE_WAIT 600 // Milliseconds 74#define SLOW_STROBE_LATCH 50 // Milliseconds 75#define FAST_STROBE_WAIT 10 // Microseconds 76#define FAST_STROBE_LATCH 5 // Microseconds 77 78#define COMBUFFER_SIZE 63 // Max Serial Buffer size is apparently 63 (for the nanao). 79#define COMBUFFER_DATA 60 // Max Usable size for containing data for transport. 80 81#define READ_BYTES_PER_ROW 16 // Max Usable size for containing data for transport. 82#define TEST_BUFFER_SIZE 256 // Max size for containing test data. 83 84// My convention for naming intrinsic data types for variables. 85// Each variable is prefaced with the following lower-case letters... 86// (I use the same convention even if the array is a List<T>). 87// 'i' = Integer (int) 88// 'ia' = Integer (int) array 89// 'l' = long 90// 'la' = long array 91// 'b' = bool 92// 'bb' = single byte 93// 'ba' = byte array 94// 'c' = single character 95// 'ca' = character array 96// 's' = string 97// 'sa' = string array 98 99String sTextTESTMode_ON = "TEST Mode ON"; // Better to have one copy of strings that are used more than once... 100String sTextTESTMode_OFF = "TEST Mode OFF"; // Otherwise, they quickly eat up precious variable memory if you pepper 101String sTextFinPackets = "-Fin: Packets="; // your code with lots of string constants (especially in the Nano-only 2K). 102String sTextByteCount = ", Byte Count="; 103String sTextStartAddress = " Starting Address="; 104String sTextByteLimit = ", Byte Limit="; 105String sTextCDP = ", CDP:"; 106String sTextRDP = ", RDP:"; 107String sTextERR = "ERR"; 108String sTextCommandNF = ": Command Not Found"; 109String sTextCommandNV = ": Invalid Command"; 110String sTextXinFast = "EXECUTING IN FAST MODE"; 111String sTextXinSlow = "EXECUTING IN SLOW MODE"; 112String sTextTimer = ", T="; 113String sTextmillis = "ms"; 114 115bool bIsTESTModeON = false; // for Demonstration/Debugging (false = actual production mode). 116bool bIsPingMode = false; 117bool bExecSpeedSlow = false; // false = FAST (production), true = SLOW (Demonstration/Debugging) 118bool bSuppressPrompt = false; 119 120byte baCOMBuffer[COMBUFFER_SIZE]; // Make this array very small (max of 63 for Arduino Nano). 121 122long lGlobPacketCount = 0; 123long lGlobByteLimit = 0; 124long lGlobByteCount = 0; 125long lGlobReadAddress = 0; 126long lGlobWriteAddress = 0; 127 128int iaDataByte[8]; 129 130byte baTestData[TEST_BUFFER_SIZE]; // This is a temporary test container for some data bytes simulating the computer's SRAM. 131int iTestDataPointer = 0; 132unsigned long lTestTimeStart = 0; 133unsigned long lTestTimeStop = 0; 134int iTestTime = 0; 135bool bHelloWorld = true; 136 137// the setup function runs once when you press reset or power the board... 138void setup() { 139 140 Serial.begin(115200); 141 while (!Serial); // Wait for Serial process to be ready. 142 143 pinMode(LED_BUILTIN, OUTPUT); // The built-in LED is reserved for bebug/development purposes only. 144 digitalWrite(LED_BUILTIN, LOW); 145 146 pinMode(PIN_COMPUTER, OUTPUT); // PIN_COMPUTER simulates the computer's run status (for development/debug). 147 digitalWrite(PIN_COMPUTER, LOW); // PIN_COMPUTER simulates the computer's run status (HIGH=running, LOW=stopped). 148 149 pinMode(PIN_INTERRUPT, INPUT); 150 pinMode(PIN_CRUN, INPUT); 151 152 pinMode(PIN_STROBE, OUTPUT); 153 pinMode(PIN_TESTMODE, OUTPUT); // When bIsTESTModeON this pin is used as the strobe. 154 155 pinMode(PIN_CONTROL_0, OUTPUT); 156 pinMode(PIN_CONTROL_1, OUTPUT); 157 pinMode(PIN_COMMAND_0, OUTPUT); 158 pinMode(PIN_COMMAND_1, OUTPUT); 159 pinMode(PIN_COMMAND_2, OUTPUT); 160 161 digitalWrite(PIN_STROBE, HIGH); 162 digitalWrite(PIN_TESTMODE, HIGH); 163 digitalWrite(PIN_CONTROL_0, HIGH); 164 digitalWrite(PIN_CONTROL_1, LOW); 165 digitalWrite(PIN_COMMAND_0, LOW); 166 digitalWrite(PIN_COMMAND_1, LOW); 167 digitalWrite(PIN_COMMAND_2, LOW); 168 169 if (bHelloWorld) // This should only happen on the very first transmmition... 170 { // If you see it twice, it is probably the initial COM connection. (Nothing to worry about) 171 bHelloWorld = false; 172 Serial.println("Arduino says: Hello, World!"); 173 } 174} 175 176// the loop function runs over and over again forever... (There is no escape!) 177void loop() { 178 179 if (bIsPingMode) 180 { 181 if (!bSuppressPrompt) 182 Serial.println("PING:"); 183 184 while (Serial.available() < 1) {} // Wait for data available. 185 int bytesRead = Serial.readBytes(baCOMBuffer, COMBUFFER_SIZE); // Binary data transfer (in PING Mode). 186 String sRetValue = ""; 187 bool bNotFound = true; 188 189 if ((char)baCOMBuffer[0] == 'X' && (char)baCOMBuffer[1] == 'W' && (char)baCOMBuffer[2] == 'C') // Load Byte Collection (LC) Continued. 190 { 191 int iLimit = (lGlobByteLimit > COMBUFFER_DATA) ? COMBUFFER_DATA : lGlobByteLimit; 192 lGlobByteLimit -= iLimit; 193 194 for (int i = 0; i < iLimit; i++) 195 { 196 if (bIsTESTModeON) 197 { 198 iTestDataPointer += 1; //TEST... 199 if (iTestDataPointer < TEST_BUFFER_SIZE) 200 baTestData[iTestDataPointer] = baCOMBuffer[3 + i]; 201 } 202 203 String sDataHexByte = convertByteToHexByte(baCOMBuffer[3 + i]); 204 205 sRetValue = setDataByte(sDataHexByte); 206 207 if (sRetValue.length() > 0) 208 { 209 bSuppressPrompt = false; 210 Serial.println("WRITEB-ERR: " + sRetValue + sTextCDP + padNumber(lGlobWriteAddress, 8)); 211 break; 212 } 213 214 loadHexDataByte(true); // true = increment address pointer afterwards. 215 lGlobByteCount += 1; 216 } 217 218 if (lGlobByteLimit > 0 && sRetValue.length() < 1) 219 { 220 lGlobPacketCount += 1; 221 bSuppressPrompt = true; 222 Serial.println("XWC:" + padNumber(lGlobPacketCount, 4) + sTextCDP + padNumber(lGlobWriteAddress, 8)); 223 } 224 else 225 { 226 endOfCommand(); 227 228 if (sRetValue.length() > 0) 229 { 230 Serial.println(sRetValue); 231 sRetValue = ""; 232 } 233 234 lTestTimeStop = millis(); 235 unsigned long iTime = lTestTimeStop - lTestTimeStart; 236 237 bSuppressPrompt = false; 238 sRetValue += "WRITEC" + sTextFinPackets + padNumber(lGlobPacketCount, 4) + sTextByteCount + String(lGlobByteCount) 239 + sTextCDP + padNumber(lGlobWriteAddress, 8) + sTextTimer + String(iTime) + sTextmillis; 240 } 241 242 bNotFound = false; 243 } 244 else if ((char)baCOMBuffer[0] == 'X' && (char)baCOMBuffer[1] == 'R' && (char)baCOMBuffer[2] == 'C') // Read Byte Collection (RC) Continued. 245 { 246 if (lGlobByteCount >= lGlobByteLimit) 247 { 248 endOfCommand(); 249 250 lTestTimeStop = millis(); 251 unsigned long iTime = lTestTimeStop - lTestTimeStart; 252 253 bSuppressPrompt = false; 254 sRetValue = "READC" + sTextFinPackets + String(lGlobPacketCount) + sTextByteCount + String(lGlobByteCount) 255 + sTextRDP + padNumber(lGlobReadAddress, 8) + sTextTimer + String(iTime) + sTextmillis; 256 } 257 else 258 { 259 lGlobPacketCount += 1; 260 sRetValue = "XRC-" + padNumber(lGlobReadAddress, 8) + ":"; 261 262 for (int i = 0; i < READ_BYTES_PER_ROW; i++) 263 { 264 if (lGlobByteCount >= lGlobByteLimit) 265 break; 266 267 String sHexByte = readHexDataByte(true); // true = increment address pointer afterwards. 268 lGlobByteCount += 1; 269 270 sRetValue = sRetValue + " " + sHexByte; 271 } 272 273 Serial.println(sRetValue); 274 } 275 276 bNotFound = false; 277 } 278 else if ((char)baCOMBuffer[0] == 'R' && (char)baCOMBuffer[1] == 'B') // Command Read Byte (RB). 279 { 280 setDataPortDirection(false); // true = OUTPUT, false = INPUT 281 sRetValue = readDataByte(); 282 bNotFound = false; 283 } 284 else if ((char)baCOMBuffer[0] == 'R' && (char)baCOMBuffer[1] == 'C') // Command Read Byte Collection (RC). 285 { 286 lTestTimeStart = millis(); 287 288 String sHighHexByte = convertByteToHexByte(baCOMBuffer[2]); 289 String sMidHexByte = convertByteToHexByte(baCOMBuffer[3]); 290 String sLowHexByte = convertByteToHexByte(baCOMBuffer[4]); 291 292 String sHexAddress = sHighHexByte + sMidHexByte + sLowHexByte; 293 294 // Start Continuous process by seting the starting address. 295 sRetValue = loadAddress(sHexAddress, false); // For reading. 296 297 if (sRetValue.indexOf(sTextERR) < 0 ) 298 { 299 lGlobByteLimit = ((long)baCOMBuffer[5] << 16) | ((long)baCOMBuffer[6] << 8) | (long)baCOMBuffer[7]; 300 sRetValue = ""; 301 302 digitalWrite(PIN_CONTROL_0, LOW); // Allow the upcoming stream of commands.. 303 digitalWrite(PIN_CONTROL_1, LOW); 304 305 lGlobPacketCount = 0; 306 lGlobByteCount = 0; 307 308 bSuppressPrompt = true; 309 Serial.println("READC:" + sTextStartAddress + padNumber(lGlobReadAddress, 8) + sTextByteLimit + String(lGlobByteLimit)); 310 setDataPortDirection(false); // true = OUTPUT, false = INPUT 311 beginCommand(); 312 } 313 314 bNotFound = false; 315 } 316 else if ((char)baCOMBuffer[0] == 'W' && (char)baCOMBuffer[1] == 'B') // Command Write Byte (WB). 317 { 318 String sHexByte = convertByteToHexByte(baCOMBuffer[2]); 319 320 setDataPortDirection(true); // If bWrite is true, then OUTPUT, else INPUT 321 sRetValue = loadDataByte(sHexByte); 322 323 bNotFound = false; 324 } 325 else if ((char)baCOMBuffer[0] == 'W' && (char)baCOMBuffer[1] == 'C') // Command Write Byte Collection (WC). 326 { 327 lTestTimeStart = millis(); 328 329 String sHighHexByte = convertByteToHexByte(baCOMBuffer[2]); 330 String sMidHexByte = convertByteToHexByte(baCOMBuffer[3]); 331 String sLowHexByte = convertByteToHexByte(baCOMBuffer[4]); 332 333 String sHexAddress = sHighHexByte + sMidHexByte + sLowHexByte; 334 335 // Start Continuous process by seting the starting address. 336 sRetValue = loadAddress(sHexAddress, true); // For writing. 337 338 if (sRetValue.indexOf(sTextERR) < 0 ) 339 { 340 lGlobByteLimit = ((long)baCOMBuffer[5] << 16) | ((long)baCOMBuffer[6] << 8) | (long)baCOMBuffer[7]; 341 sRetValue = ""; 342 343 digitalWrite(PIN_CONTROL_0, LOW); // Allow the upcoming stream of commands.. 344 digitalWrite(PIN_CONTROL_1, LOW); 345 346 lGlobByteCount = 0; 347 lGlobPacketCount = 1; 348 iTestDataPointer = -1; 349 350 bSuppressPrompt = true; 351 Serial.println("WRITEC:" + sTextStartAddress + padNumber(lGlobWriteAddress, 8) + sTextByteLimit + String(lGlobByteLimit)); 352 Serial.println("XWC:" + padNumber(lGlobPacketCount, 4) + sTextCDP + padNumber(lGlobWriteAddress, 8)); 353 setDataPortDirection(true); // true = OUTPUT, false = INPUT 354 beginCommand(); 355 } 356 357 bNotFound = false; 358 } 359 else if ((char)baCOMBuffer[0] == 'L' && (char)baCOMBuffer[1] == 'W') // Command Load Address (LW) for writing. 360 { 361 String sHighHexByte = convertByteToHexByte(baCOMBuffer[2]); 362 String sMidHexByte = convertByteToHexByte(baCOMBuffer[3]); 363 String sLowHexByte = convertByteToHexByte(baCOMBuffer[4]); 364 365 String sHexAddress = sHighHexByte + sMidHexByte + sLowHexByte; 366 367 setDataPortDirection(true); // true = OUTPUT, false = INPUT 368 sRetValue = loadAddress(sHexAddress, true); // For writing. 369 370 bNotFound = false; 371 } 372 else if ((char)baCOMBuffer[0] == 'L' && (char)baCOMBuffer[1] == 'R') // Command Load Address (LR) for reading... 373 { 374 String sHighHexByte = convertByteToHexByte(baCOMBuffer[2]); 375 String sMidHexByte = convertByteToHexByte(baCOMBuffer[3]); 376 String sLowHexByte = convertByteToHexByte(baCOMBuffer[4]); 377 378 String sHexAddress = sHighHexByte + sMidHexByte + sLowHexByte; 379 380 setDataPortDirection(true); // true = OUTPUT, false = INPUT 381 sRetValue = loadAddress(sHexAddress, false); // For reading. 382 383 bNotFound = false; 384 } 385 else if ((char)baCOMBuffer[0] == 'I' && (char)baCOMBuffer[1] == 'A') // Command INCRA (IA) Increment Address for writing. 386 { 387 sRetValue = incrAddress(); // For writing. 388 bNotFound = false; 389 } 390 else if ((char)baCOMBuffer[0] == 'I' && (char)baCOMBuffer[1] == 'T') // Command INTRP (IT) Interrupt the CPU. 391 { 392 sRetValue = intrpCPU(); 393 Serial.println(sRetValue); 394 bNotFound = false; 395 } 396 else if ((char)baCOMBuffer[0] == 'I' && (char)baCOMBuffer[1] == 'P') // Command CLRIP (IP) Clear the CPU's Instruction Pointer. 397 { 398 sRetValue = resetCPU(); 399 Serial.println(sRetValue); 400 bNotFound = false; 401 } 402 else if ((char)baCOMBuffer[0] == 'P' && (char)baCOMBuffer[1] == 'O') 403 { 404 bIsPingMode = false; 405 bNotFound = false; 406 } 407 else if ((char)baCOMBuffer[0] == 'F' && (char)baCOMBuffer[1] == 'A') 408 { 409 bExecSpeedSlow = false; 410 Serial.println(sTextXinFast); 411 bNotFound = false; 412 } 413 else if ((char)baCOMBuffer[0] == 'L' && (char)baCOMBuffer[1] == 'O') 414 { 415 bExecSpeedSlow = true; 416 Serial.println(sTextXinSlow); 417 bNotFound = false; 418 } 419 else if ((char)baCOMBuffer[0] == 'X' && (char)baCOMBuffer[1] == 'X') // Reset Arduino Workstation Program. 420 { 421 bSuppressPrompt = false; 422 digitalWrite(PIN_COMPUTER, LOW); // PIN_COMPUTER simulates the computer's run status (LOW = STOPPED) 423 endOfCommand(); 424 bNotFound = false; 425 } 426 else if ((char)baCOMBuffer[0] == 'X' && (char)baCOMBuffer[1] == '0') // Clear Arduino TEST RAM. 427 { 428 Serial.println(eraseTESTRAM()); 429 bNotFound = false; 430 } 431 432 if ((char)baCOMBuffer[0] == 'S') 433 { 434 if ((char)baCOMBuffer[0] == 'S' && (char)baCOMBuffer[1] == 'T') // Control "Start"... 435 { 436 sRetValue = startComputer(); 437 bNotFound = false; 438 } 439 else if ((char)baCOMBuffer[0] == 'S' && (char)baCOMBuffer[1] == 'P') // Control "Stop"... 440 { 441 sRetValue = stopComputer(); 442 bNotFound = false; 443 } 444 else if ((char)baCOMBuffer[0] == 'S' && (char)baCOMBuffer[1] == 'S') // Control "Step"... 445 { 446 sRetValue = stepComputer(); 447 bNotFound = false; 448 } 449 else if ((char)baCOMBuffer[0] == 'S' && (char)baCOMBuffer[1] == 'E') // Enter TEST Mode... 450 { 451 bIsTESTModeON = true; 452 Serial.println(sTextTESTMode_ON); 453 bNotFound = false; 454 } 455 else if ((char)baCOMBuffer[0] == 'S' && (char)baCOMBuffer[1] == 'X') // Exit TEST Mode... 456 { 457 bIsTESTModeON = false; 458 Serial.println(sTextTESTMode_OFF); 459 bNotFound = false; 460 } 461 } 462 463 if (bNotFound) 464 { 465 bSuppressPrompt = false; 466 Serial.println(sTextERR + sTextCommandNF); 467 } 468 else 469 { 470 if (sRetValue.indexOf(sTextERR) > -1 || sRetValue.indexOf("DP:") > -1) 471 { 472 bSuppressPrompt = false; 473 Serial.println(sRetValue); 474 } 475 } 476 } 477 else // The following code is the human interface for testing each fundamental function (PONG mode)... 478 { 479 Serial.println("READY:"); 480 481 while (Serial.available() == 0) {} // Wait for data available. 482 String sInput = Serial.readString(); // Read until timeout. 483 sInput.trim(); // Remove any \r \n whitespace at the end of the String. 484 sInput.toUpperCase(); // Make sure everything is in Upper Case. 485 String sRetValue = ""; 486 bool bNotFound = true; 487 488 if (sInput == "PING") 489 { 490 bIsPingMode = true; 491 bNotFound = false; 492 493 } 494 else if (sInput == "SLOW") 495 { 496 bExecSpeedSlow = true; 497 Serial.println(sTextXinSlow); 498 bNotFound = false; 499 } 500 else if (sInput == "FAST") 501 { 502 bExecSpeedSlow = false; 503 Serial.println(sTextXinFast); 504 bNotFound = false; 505 } 506 else if (sInput == "RESET") // Reset Device. 507 { 508 bSuppressPrompt = false; 509 digitalWrite(PIN_COMPUTER, LOW); // PIN_COMPUTER simulates the computer's run status (LOW = STOPPED) 510 endOfCommand(); 511 bNotFound = false; 512 } 513 else 514 { 515 Serial.println("RCVD: '" + sInput + "'"); 516 517 if (sInput == "START") 518 { 519 sRetValue = startComputer(); 520 bNotFound = false; 521 } 522 else if (sInput == "STOP") 523 { 524 sRetValue = stopComputer(); 525 bNotFound = false; 526 } 527 else if (sInput == "STEP") 528 { 529 sRetValue = stepComputer(); 530 bNotFound = false; 531 } 532 else if (sInput == "TMENT") // Enter TEST Mode... 533 { 534 bIsTESTModeON = true; 535 sRetValue = sTextTESTMode_ON; 536 bNotFound = false; 537 } 538 else if (sInput == "TMEXT") // Exit TEST Mode... 539 { 540 bIsTESTModeON = false; 541 sRetValue = sTextTESTMode_OFF; 542 bNotFound = false; 543 } 544 else if (sInput.startsWith("LOADA")) 545 { 546 bNotFound = false; 547 if (sInput.length() != 12) 548 { 549 sRetValue = sTextERR + sTextCommandNV; 550 } 551 else 552 { 553 String sHexAddress = sInput.substring(6); 554 sRetValue = loadAddress(sHexAddress, true); // true = for writing. 555 } 556 } 557 else if (sInput.startsWith("INCRA")) 558 { 559 bNotFound = false; 560 sRetValue = incrAddress(); 561 } 562 else if (sInput.startsWith("INTRP")) 563 { 564 bNotFound = false; 565 sRetValue = intrpCPU(); 566 } 567 else if (sInput.startsWith("CLRIP")) 568 { 569 bNotFound = false; 570 sRetValue = resetCPU(); 571 } 572 else if (sInput.startsWith("WRITEB")) 573 { 574 bNotFound = false; 575 if (sInput.length() != 9) 576 { 577 sRetValue = sTextERR + sTextCommandNV; 578 } 579 else 580 { 581 String sHexByte = sInput.substring(6); 582 sRetValue = loadDataByte(sHexByte); 583 } 584 } 585 else if (sInput.startsWith("READB")) 586 { 587 bNotFound = false; 588 if (sInput.length() != 5) 589 { 590 sRetValue = sTextERR + sTextCommandNV; 591 } 592 else 593 { 594 String sHexByte = sInput.substring(6); 595 sRetValue = readDataByte(); 596 } 597 } 598 else if (sInput.startsWith("ERASE")) // Clear Arduino TEST RAM. 599 { 600 bNotFound = false; 601 sRetValue = eraseTESTRAM(); 602 } 603 } 604 605 if (bNotFound) 606 { 607 Serial.println(sTextERR + sTextCommandNF); 608 } 609 else 610 { 611 if (sRetValue.length() > 0) 612 Serial.println("RTND: '" + sRetValue + "'"); 613 } 614 } 615} 616 617// ================================================================================================== 618// 619// These functions Exist outside of the main execution loop so they can be called to perform lower 620// level of operation regardless of whether the execution loop is procedural or interrupt driven... 621// 622 623String startComputer() 624{ 625 String sReturnValue = isRunning(); 626 if (sReturnValue.length() > 0) return sReturnValue; 627 628 digitalWrite(PIN_CONTROL_0, HIGH); 629 digitalWrite(PIN_CONTROL_1, LOW); 630 631 strobeLatch(); 632 633 digitalWrite(PIN_COMPUTER, HIGH); // PIN_COMPUTER simulates the computer's run status (HIGH = running) 634 635 return "STARTED"; 636} 637 638String stopComputer() 639{ 640 String sReturnValue = isRunning(); 641 if (sReturnValue.length() < 1) return "ERR: Computer not running"; 642 643 digitalWrite(PIN_CONTROL_0, LOW); 644 digitalWrite(PIN_CONTROL_1, HIGH); 645 646 strobeLatch(); 647 648 digitalWrite(PIN_COMPUTER, LOW); // PIN_COMPUTER simulates the computer's run status (HIGH = running) 649 650 return "STOPPED"; 651} 652 653String stepComputer() 654{ 655 String sReturnValue = isRunning(); 656 if (sReturnValue.length() > 0) return sReturnValue; 657 658 digitalWrite(PIN_CONTROL_0, HIGH); 659 digitalWrite(PIN_CONTROL_1, HIGH); 660 661 //strobeLatch(bExecSpeedSlow); 662 strobeLatch(); // Force the strobe to be slow moving. 663 664 if (bExecSpeedSlow) // This is done for simulation purposes... 665 { 666 digitalWrite(PIN_COMPUTER, HIGH); 667 delay(500); 668 digitalWrite(PIN_COMPUTER, LOW); 669 } 670 671 return "STEPPED"; 672} 673 674String loadAddress(String sHexAddress, bool bWrite) // false = 'for reading, true = 'for writing. 675{ 676 String sReturnValue = beginCommand(); 677 if (sReturnValue.length() > 0) 678 return sReturnValue; 679 680 for (int i = 0; i < 3; i++) 681 { 682 String sHexByte = sHexAddress.substring(i * 2, (i * 2) + 2); 683 sReturnValue = setDataByte(sHexByte); 684 685 if (sReturnValue.length() > 0) 686 { 687 /* 688 switch(i) 689 { 690 case 0: 691 sHexByte = "0"; 692 break; 693 case 1: 694 sHexByte = "1"; 695 break; 696 case 2: 697 sHexByte = "2"; 698 break; 699 } 700 */ 701 return "LOADA-ERR: (" + sReturnValue + ")"; 702 } 703 704 writeDataPort(); 705 706 switch (i) 707 { 708 case 0: // Set Address BYTE0 is Cmomand 3 for the 138. 709 digitalWrite(PIN_COMMAND_0, HIGH); 710 digitalWrite(PIN_COMMAND_1, HIGH); 711 digitalWrite(PIN_COMMAND_2, LOW); 712 break; 713 case 1: // Set Address BYTE1 is Cmomand 4 for the 138. 714 digitalWrite(PIN_COMMAND_0, LOW); 715 digitalWrite(PIN_COMMAND_1, LOW); 716 digitalWrite(PIN_COMMAND_2, HIGH); 717 break; 718 case 2: // Set Address BYTE2 is Cmomand 5 for the 138. 719 digitalWrite(PIN_COMMAND_0, HIGH); 720 digitalWrite(PIN_COMMAND_1, LOW); 721 digitalWrite(PIN_COMMAND_2, HIGH); 722 break; 723 } 724 725 waitStrobeLatch(); 726 } 727 728 endOfCommand(); 729 730 char buf[sHexAddress.length() + 1]; // convert HEX annotated string to long int... 731 sHexAddress.toCharArray(buf, sizeof(buf)); 732 char *endPtr; 733 if (bWrite) 734 { 735 lGlobWriteAddress = strtol(buf, &endPtr, 16); 736 return "LOADW" + sTextCDP + padNumber(lGlobWriteAddress, 8); 737 } 738 else 739 { 740 lGlobReadAddress = strtol(buf, &endPtr, 16); 741 return "LOADR" + sTextRDP + padNumber(lGlobReadAddress, 8); 742 } 743} 744 745String incrAddress() 746{ 747 String sReturnValue = beginCommand(); 748 if (sReturnValue.length() > 0) 749 return sReturnValue; 750 751 incrementAddr(); 752 753 lGlobWriteAddress += 1; 754 if (lGlobWriteAddress > 16777215) 755 lGlobWriteAddress = 0; 756 757 endOfCommand(); 758 return "INCRA" + sTextCDP + padNumber(lGlobWriteAddress, 8); 759} 760 761void incrementAddr() 762{ 763 digitalWrite(PIN_COMMAND_0, LOW); // Increment Address is Command 2 to the 138. 764 digitalWrite(PIN_COMMAND_1, HIGH); 765 digitalWrite(PIN_COMMAND_2, LOW); 766 767 strobeLatch(); 768} 769 770String intrpCPU() 771{ 772 String sReturnValue = beginCommand(); 773 if (sReturnValue.length() > 0) 774 return sReturnValue; 775 776 interruptCPU(); 777 778 endOfCommand(); 779 return "INTRP-SUCCESS"; 780} 781 782void interruptCPU() 783{ 784 digitalWrite(PIN_COMMAND_0, LOW); // Interrupt the CPU is Command 6 to the 138. 785 digitalWrite(PIN_COMMAND_1, HIGH); 786 digitalWrite(PIN_COMMAND_2, HIGH); 787 788 strobeLatch(); 789} 790 791String resetCPU() 792{ 793 String sReturnValue = beginCommand(); 794 if (sReturnValue.length() > 0) 795 return sReturnValue; 796 797 clearIP(); 798 799 endOfCommand(); 800 return "CLRIP-SUCCESS"; 801} 802 803void clearIP() 804{ 805 digitalWrite(PIN_COMMAND_0, HIGH); // Clear instruction pointer is Command 7 to the 138. 806 digitalWrite(PIN_COMMAND_1, HIGH); 807 digitalWrite(PIN_COMMAND_2, HIGH); 808 809 strobeLatch(); 810} 811 812String loadDataByte(String sDataHexByte) 813{ 814 String sReturnValue = beginCommand(); 815 if (sReturnValue.length() > 0) 816 return sReturnValue; 817 818 sReturnValue = setDataByte(sDataHexByte); 819 820 if (sReturnValue.length() > 0) 821 { 822 endOfCommand(); 823 return "WRITEB-ERR (" + sReturnValue + ")"; 824 } 825 826 loadHexDataByte(false); // true = increment address pointer afterwards. 827 828 endOfCommand(); 829 return "WRITEB-Writing '" + sDataHexByte + "'" + sTextCDP + padNumber(lGlobWriteAddress, 8); 830} 831 832void loadHexDataByte(bool bIncrement) // true = increment address pointer afterwards. 833{ 834 writeDataPort(); 835 836 digitalWrite(PIN_COMMAND_0, HIGH); // Write Data is Command 1 to the 138 837 digitalWrite(PIN_COMMAND_1, LOW); 838 digitalWrite(PIN_COMMAND_2, LOW); 839 840 waitStrobeLatch(); 841 842 if (bIncrement) 843 { 844 incrementAddr(); 845 lGlobWriteAddress += 1; // Keep Rrite Address up to date. 846 if (lGlobWriteAddress > 16777215) 847 lGlobWriteAddress = 0; 848 } 849} 850 851String readDataByte() 852{ 853 String sReturnValue = beginCommand(); 854 if (sReturnValue.length() > 0) 855 return sReturnValue; 856 857 String sDataHexByte = readHexDataByte(false); // true = increment address pointer afterwards. 858 859 endOfCommand(); 860 return "READB-Byte = '" + sDataHexByte + "'" + sTextRDP + padNumber(lGlobWriteAddress, 8); 861} 862 863String readHexDataByte(bool bIncrement) // true = increment address pointer afterwards. 864{ 865 digitalWrite(PIN_COMMAND_0, LOW); // Read Data is Command 0 to the 138 866 digitalWrite(PIN_COMMAND_1, LOW); 867 digitalWrite(PIN_COMMAND_2, LOW); 868 869 readDataPort(); 870 871 if (bIsTESTModeON) 872 waitStrobeLatch(); 873 else 874 NOwaitStrobeLatch(); 875 876 String sDataHexByte = getDataByte(); 877 878 if (bIncrement) 879 { 880 incrementAddr(); 881 lGlobReadAddress += 1; // Keep Read Address up to date. 882 if (lGlobReadAddress > 16777215) 883 lGlobReadAddress = 0; 884 } 885 886 return sDataHexByte; 887} 888 889String beginCommand() 890{ 891 String sReturnValue = isRunning(); 892 if (sReturnValue.length() > 0) 893 return sReturnValue; 894 895 digitalWrite(PIN_CONTROL_0, LOW); 896 digitalWrite(PIN_CONTROL_1, LOW); 897 898 return ""; 899} 900 901String endOfCommand() 902{ 903 digitalWrite(PIN_CONTROL_0, HIGH); 904 digitalWrite(PIN_CONTROL_1, LOW); 905 906 clearCommandPins(); 907 clearDataPort(); 908 909 return ""; 910} 911 912String getDataByte() 913{ 914 byte bbByte = 0; 915 916 if (iaDataByte[7] == HIGH) bbByte = 128; 917 if (iaDataByte[6] == HIGH) bbByte += 64; 918 if (iaDataByte[5] == HIGH) bbByte += 32; 919 if (iaDataByte[4] == HIGH) bbByte += 16; 920 if (iaDataByte[3] == HIGH) bbByte += 8; 921 if (iaDataByte[2] == HIGH) bbByte += 4; 922 if (iaDataByte[1] == HIGH) bbByte += 2; 923 if (iaDataByte[0] == HIGH) bbByte += 1; 924 925 String sReturnValue = convertByteToHexByte(bbByte); 926 927 return sReturnValue; 928} 929 930String setDataByte(String sHexByte) 931{ 932 String sHexNibble = sHexByte.substring(0, 1); 933 String sReturnValue = setDataNibble(4, sHexByte.substring(0, 1)); 934 935 if (sReturnValue.length() > 0) 936 return sReturnValue; 937 938 sHexNibble = sHexByte.substring(1, 2); 939 sReturnValue = setDataNibble(0, sHexNibble); 940 941 return sReturnValue; 942} 943 944String setDataNibble(int idx, String sHexNibble) 945{ 946 int iHexNibble = -1; 947 948 if (sHexNibble == "0") iHexNibble = 0; 949 if (sHexNibble == "1") iHexNibble = 1; 950 if (sHexNibble == "2") iHexNibble = 2; 951 if (sHexNibble == "3") iHexNibble = 3; 952 if (sHexNibble == "4") iHexNibble = 4; 953 if (sHexNibble == "5") iHexNibble = 5; 954 if (sHexNibble == "6") iHexNibble = 6; 955 if (sHexNibble == "7") iHexNibble = 7; 956 if (sHexNibble == "8") iHexNibble = 8; 957 if (sHexNibble == "9") iHexNibble = 9; 958 if (sHexNibble == "A") iHexNibble = 10; 959 if (sHexNibble == "B") iHexNibble = 11; 960 if (sHexNibble == "C") iHexNibble = 12; 961 if (sHexNibble == "D") iHexNibble = 13; 962 if (sHexNibble == "E") iHexNibble = 14; 963 if (sHexNibble == "F") iHexNibble = 15; 964 965 switch (iHexNibble) 966 { 967 case 0: 968 iaDataByte[idx + 3] = LOW; iaDataByte[idx + 2] = LOW; iaDataByte[idx + 1] = LOW; iaDataByte[idx] = LOW; 969 break; 970 case 1: 971 iaDataByte[idx + 3] = LOW; iaDataByte[idx + 2] = LOW; iaDataByte[idx + 1] = LOW; iaDataByte[idx] = HIGH; 972 break; 973 case 2: 974 iaDataByte[idx + 3] = LOW; iaDataByte[idx + 2] = LOW; iaDataByte[idx + 1] = HIGH; iaDataByte[idx] = LOW; 975 break; 976 case 3: 977 iaDataByte[idx + 3] = LOW; iaDataByte[idx + 2] = LOW; iaDataByte[idx + 1] = HIGH; iaDataByte[idx] = HIGH; 978 break; 979 case 4: 980 iaDataByte[idx + 3] = LOW; iaDataByte[idx + 2] = HIGH; iaDataByte[idx + 1] = LOW; iaDataByte[idx] = LOW; 981 break; 982 case 5: 983 iaDataByte[idx + 3] = LOW; iaDataByte[idx + 2] = HIGH; iaDataByte[idx + 1] = LOW; iaDataByte[idx] = HIGH; 984 break; 985 case 6: 986 iaDataByte[idx + 3] = LOW; iaDataByte[idx + 2] = HIGH; iaDataByte[idx + 1] = HIGH; iaDataByte[idx] = LOW; 987 break; 988 case 7: 989 iaDataByte[idx + 3] = LOW; iaDataByte[idx + 2] = HIGH; iaDataByte[idx + 1] = HIGH; iaDataByte[idx] = HIGH; 990 break; 991 case 8: 992 iaDataByte[idx + 3] = HIGH; iaDataByte[idx + 2] = LOW; iaDataByte[idx + 1] = LOW; iaDataByte[idx] = LOW; 993 break; 994 case 9: 995 iaDataByte[idx + 3] = HIGH; iaDataByte[idx + 2] = LOW; iaDataByte[idx + 1] = LOW; iaDataByte[idx] = HIGH; 996 break; 997 case 10: 998 iaDataByte[idx + 3] = HIGH; iaDataByte[idx + 2] = LOW; iaDataByte[idx + 1] = HIGH; iaDataByte[idx] = LOW; 999 break; 1000 case 11: 1001 iaDataByte[idx + 3] = HIGH; iaDataByte[idx + 2] = LOW; iaDataByte[idx + 1] = HIGH; iaDataByte[idx] = HIGH; 1002 break; 1003 case 12: 1004 iaDataByte[idx + 3] = HIGH; iaDataByte[idx + 2] = HIGH; iaDataByte[idx + 1] = LOW; iaDataByte[idx] = LOW; 1005 break; 1006 case 13: 1007 iaDataByte[idx + 3] = HIGH; iaDataByte[idx + 2] = HIGH; iaDataByte[idx + 1] = LOW; iaDataByte[idx] = HIGH; 1008 break; 1009 case 14: 1010 iaDataByte[idx + 3] = HIGH; iaDataByte[idx + 2] = HIGH; iaDataByte[idx + 1] = HIGH; iaDataByte[idx] = LOW; 1011 break; 1012 case 15: 1013 iaDataByte[idx + 3] = HIGH; iaDataByte[idx + 2] = HIGH; iaDataByte[idx + 1] = HIGH; iaDataByte[idx] = HIGH; 1014 break; 1015 default: 1016 return "ERR bad char Hex Data: '" + sHexNibble + "'"; 1017 } 1018 1019 return ""; 1020} 1021 1022void readDataPort() 1023{ 1024 if (bIsTESTModeON) 1025 { 1026 long idx = lGlobReadAddress; 1027 if (lGlobReadAddress >= TEST_BUFFER_SIZE) 1028 idx = lGlobReadAddress % TEST_BUFFER_SIZE; 1029 byte bbByte = baTestData[idx]; 1030 1031 String sHexByte = convertByteToHexByte(bbByte); 1032 setDataByte(sHexByte); 1033 1034 digitalWrite(PIN_DATAPORT_0, (bbByte & 1) ? HIGH : LOW); 1035 digitalWrite(PIN_DATAPORT_1, (bbByte & 2) ? HIGH : LOW); 1036 digitalWrite(PIN_DATAPORT_2, (bbByte & 4) ? HIGH : LOW); 1037 digitalWrite(PIN_DATAPORT_3, (bbByte & 8) ? HIGH : LOW); 1038 digitalWrite(PIN_DATAPORT_4, (bbByte & 16) ? HIGH : LOW); 1039 digitalWrite(PIN_DATAPORT_5, (bbByte & 32) ? HIGH : LOW); 1040 digitalWrite(PIN_DATAPORT_6, (bbByte & 64) ? HIGH : LOW); 1041 digitalWrite(PIN_DATAPORT_7, (bbByte & 128) ? HIGH : LOW); 1042 return; 1043 } 1044 1045 // This is the code for production version (not testing/simulating)... 1046 iaDataByte[0] = digitalRead(PIN_DATAPORT_0); 1047 iaDataByte[1] = digitalRead(PIN_DATAPORT_1); 1048 iaDataByte[2] = digitalRead(PIN_DATAPORT_2); 1049 iaDataByte[3] = digitalRead(PIN_DATAPORT_3); 1050 iaDataByte[4] = digitalRead(PIN_DATAPORT_4); 1051 iaDataByte[5] = digitalRead(PIN_DATAPORT_5); 1052 iaDataByte[6] = digitalRead(PIN_DATAPORT_6); 1053 iaDataByte[7] = digitalRead(PIN_DATAPORT_7); 1054} 1055 1056void writeDataPort() 1057{ 1058 if (bIsTESTModeON) 1059 { 1060 long idx = lGlobWriteAddress; 1061 if (lGlobWriteAddress >= TEST_BUFFER_SIZE) 1062 idx = lGlobWriteAddress % TEST_BUFFER_SIZE; 1063 1064 byte bbByte = (iaDataByte[0] > 0) ? 1 : 0; 1065 bbByte += (iaDataByte[1] > 0) ? 2 : 0; 1066 bbByte += (iaDataByte[2] > 0) ? 4 : 0; 1067 bbByte += (iaDataByte[3] > 0) ? 8 : 0; 1068 bbByte += (iaDataByte[4] > 0) ? 16 : 0; 1069 bbByte += (iaDataByte[5] > 0) ? 32 : 0; 1070 bbByte += (iaDataByte[6] > 0) ? 64 : 0; 1071 bbByte += (iaDataByte[7] > 0) ? 128 : 0; 1072 } 1073 1074 digitalWrite(PIN_DATAPORT_0, iaDataByte[0]); 1075 digitalWrite(PIN_DATAPORT_1, iaDataByte[1]); 1076 digitalWrite(PIN_DATAPORT_2, iaDataByte[2]); 1077 digitalWrite(PIN_DATAPORT_3, iaDataByte[3]); 1078 digitalWrite(PIN_DATAPORT_4, iaDataByte[4]); 1079 digitalWrite(PIN_DATAPORT_5, iaDataByte[5]); 1080 digitalWrite(PIN_DATAPORT_6, iaDataByte[6]); 1081 digitalWrite(PIN_DATAPORT_7, iaDataByte[7]); 1082} 1083 1084void clearDataPort() 1085{ 1086 digitalWrite(PIN_DATAPORT_0, LOW); 1087 digitalWrite(PIN_DATAPORT_1, LOW); 1088 digitalWrite(PIN_DATAPORT_2, LOW); 1089 digitalWrite(PIN_DATAPORT_3, LOW); 1090 digitalWrite(PIN_DATAPORT_4, LOW); 1091 digitalWrite(PIN_DATAPORT_5, LOW); 1092 digitalWrite(PIN_DATAPORT_6, LOW); 1093 digitalWrite(PIN_DATAPORT_7, LOW); 1094} 1095 1096void setDataPortDirection(bool bWrite) // IF bWrite is TRUE THEN OUTPUT ELSE INPUT 1097{ 1098 if (bWrite || bIsTESTModeON) 1099 { 1100 pinMode(PIN_DATAPORT_0, OUTPUT); 1101 pinMode(PIN_DATAPORT_1, OUTPUT); 1102 pinMode(PIN_DATAPORT_2, OUTPUT); 1103 pinMode(PIN_DATAPORT_3, OUTPUT); 1104 pinMode(PIN_DATAPORT_4, OUTPUT); 1105 pinMode(PIN_DATAPORT_5, OUTPUT); 1106 pinMode(PIN_DATAPORT_6, OUTPUT); 1107 pinMode(PIN_DATAPORT_7, OUTPUT); 1108 } 1109 else 1110 { 1111 pinMode(PIN_DATAPORT_0, INPUT); 1112 pinMode(PIN_DATAPORT_1, INPUT); 1113 pinMode(PIN_DATAPORT_2, INPUT); 1114 pinMode(PIN_DATAPORT_3, INPUT); 1115 pinMode(PIN_DATAPORT_4, INPUT); 1116 pinMode(PIN_DATAPORT_5, INPUT); 1117 pinMode(PIN_DATAPORT_6, INPUT); 1118 pinMode(PIN_DATAPORT_7, INPUT); 1119 } 1120} 1121 1122void clearCommandPins() 1123{ 1124 digitalWrite(PIN_COMMAND_0, LOW); 1125 digitalWrite(PIN_COMMAND_1, LOW); 1126 digitalWrite(PIN_COMMAND_2, LOW); 1127} 1128 1129String isRunning() 1130{ 1131 bool bRunning = digitalRead(PIN_CRUN); 1132 1133 if (bRunning) 1134 return "ERR: Computer is running"; 1135 1136 return ""; 1137} 1138 1139void waitStrobeLatch() 1140{ 1141 if (bExecSpeedSlow) 1142 delay(SLOW_STROBE_WAIT); 1143 //else 1144 //{ iTestTime = 0; } 1145 //for (int i = 0; i < 3; i++) {} 1146 //delayMicroseconds(FAST_STROBE_WAIT); 1147 1148 strobeLatch(); 1149} 1150 1151void NOwaitStrobeLatch() 1152{ 1153 if (bExecSpeedSlow) 1154 delay(SLOW_STROBE_WAIT); 1155 else 1156 { iTestTime = 0; iTestTime = 0; } 1157 //for (int i = 0; i < 3; i++) {} 1158 //delayMicroseconds(FAST_STROBE_WAIT); 1159 1160 //if (bExecSpeedSlow) 1161 // delay(SLOW_STROBE_LATCH); 1162 //else 1163 // { iTestTime = 0; } 1164 //for (int i = 0; i < 1; i++) {} 1165 //delayMicroseconds(FAST_STROBE_LATCH); 1166 1167 if (bExecSpeedSlow) 1168 delay(SLOW_STROBE_LATCH * 4); 1169} 1170 1171void strobeLatch() 1172{ 1173 if (bIsTESTModeON) 1174 digitalWrite(PIN_TESTMODE, LOW); 1175 else 1176 digitalWrite(PIN_STROBE, LOW); 1177 1178 if (bExecSpeedSlow) 1179 delay(SLOW_STROBE_LATCH); 1180 else 1181 { iTestTime = 0; } 1182 //for (int i = 0; i < 1; i++) {} 1183 //delayMicroseconds(FAST_STROBE_LATCH); 1184 1185 if (bIsTESTModeON) 1186 digitalWrite(PIN_TESTMODE, HIGH); 1187 else 1188 digitalWrite(PIN_STROBE, HIGH); 1189 1190 if (bExecSpeedSlow) 1191 delay(SLOW_STROBE_LATCH * 4); 1192} 1193 1194String convertByteToHexByte(byte cByte) 1195{ 1196 int iLowNibble = (int)(cByte & 0x0F); 1197 String sLowNibble = conovertIntToHexNibble(iLowNibble); 1198 1199 int iHighNibble = (int)(cByte & 0xF0) / 16; 1200 String sHighNibble = conovertIntToHexNibble(iHighNibble); 1201 1202 return (sHighNibble + sLowNibble); 1203} 1204 1205String conovertIntToHexNibble(int iNibble) 1206{ 1207 String sRetVal = "X"; 1208 1209 switch (iNibble) 1210 { 1211 case 0: sRetVal = "0"; break; 1212 case 1: sRetVal = "1"; break; 1213 case 2: sRetVal = "2"; break; 1214 case 3: sRetVal = "3"; break; 1215 case 4: sRetVal = "4"; break; 1216 case 5: sRetVal = "5"; break; 1217 case 6: sRetVal = "6"; break; 1218 case 7: sRetVal = "7"; break; 1219 case 8: sRetVal = "8"; break; 1220 case 9: sRetVal = "9"; break; 1221 case 10: sRetVal = "A"; break; 1222 case 11: sRetVal = "B"; break; 1223 case 12: sRetVal = "C"; break; 1224 case 13: sRetVal = "D"; break; 1225 case 14: sRetVal = "E"; break; 1226 case 15: sRetVal = "F"; break; 1227 } 1228 1229 return sRetVal; 1230} 1231 1232String padNumber(long iNumber, int iDigits) 1233{ 1234 String sRetVal = String(iNumber); 1235 1236 while (sRetVal.length() < iDigits) 1237 sRetVal = "0" + sRetVal; 1238 1239 return sRetVal; 1240} 1241 1242String eraseTESTRAM() 1243{ 1244 for (int i = 0; i < TEST_BUFFER_SIZE; i++) 1245 baTestData[i] = 0; 1246 1247 return "TEST RAM Cleared"; 1248}
Documentation
Arduino-WinForms_Workstation
Documentation in Workstation Project
Arduino-WinForms_Workstation.pdf
Comments
Only logged in users can leave comments