├── .gitignore ├── README.md ├── arduino_libs ├── c2_prog │ ├── c2.cpp │ └── c2.h └── httpd │ ├── examples │ └── HelloWorld │ │ └── helloworld.ino │ ├── httpServer.h │ ├── httpServerPage.cpp │ └── httpServerPage.h ├── c2_prog_wifi.ino ├── ihx.cpp ├── ihx.h ├── platformio.ini └── serialServer.h /.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # c2_prog_wifi 2 | WiFi-enabled programmer for Silicon Labs microcontrollers using the C2 programmer protocol, and to act as a serial-wifi bridge. 3 | 4 | Designed to run in the Arduino environment for ESP8266 module: https://github.com/esp8266/Arduino 5 | 6 | New programs can be loaded sending .hex files through the web-interface. You will have to edit the .ino file to set the password. 7 | 8 | Serial bridge can be accessed through port 9600, but the baud-rate is actually 115200. Try 'nc esp8266 9600' on linux, or any other TCP/IP terminal program (maybe telnet on windows?). 9 | 10 | Everything is still alpha. Currently tested with EFM8BB10F2G-A-QFN20 and ESP-01 module. 11 | 12 | LICENSE: GPLv3 or newer. 13 | -------------------------------------------------------------------------------- /arduino_libs/c2_prog/c2.cpp: -------------------------------------------------------------------------------- 1 | #include "c2.h" 2 | 3 | ///////////////////////////////////////////// 4 | // Nothing should need change on this file // 5 | ///////////////////////////////////////////// 6 | 7 | // Times in microseconds 8 | #define T_RD (20+5) 9 | #define T_SD ( 2+5) 10 | 11 | // Layer 0: Bit shifter 12 | static bool c2_bit(bool b) { 13 | C2D(b); 14 | // C2_DELAY_US(1); 15 | C2CK(0); 16 | // C2_DELAY_US(1); 17 | b = C2D(); 18 | C2CK(1); 19 | return b; 20 | } 21 | 22 | // Layer 1: C2D Register read/write 23 | void c2_address_write(uint8_t address) { 24 | Serial.print("AW"); 25 | Serial.println(address, HEX); 26 | 27 | // start 28 | c2_bit(true); 29 | C2D_enable(true); 30 | 31 | // instruction 32 | c2_bit(1); 33 | c2_bit(1); 34 | 35 | // Address 36 | for (int i = 0; i < 8; ++i) { 37 | c2_bit(address & 1); 38 | address >>= 1; 39 | } 40 | 41 | // Stop 42 | C2D_enable(false); 43 | c2_bit(1); 44 | } 45 | 46 | uint8_t c2_address_read() { 47 | // start 48 | c2_bit(true); 49 | C2D_enable(true); 50 | 51 | // instruction 52 | c2_bit(0); 53 | c2_bit(1); 54 | 55 | // Change C2D direction 56 | C2D_enable(false); 57 | c2_bit(0); 58 | 59 | // Address 60 | uint8_t a = 0, m = 1; 61 | for (int i = 0; i < 8; ++i) { 62 | if (c2_bit(a & 1)) { 63 | a |= m; 64 | } 65 | m <<= 1; 66 | } 67 | 68 | // Stop is implied 69 | 70 | Serial.print("AR"); 71 | Serial.println(a, HEX); 72 | 73 | return a; 74 | } 75 | 76 | uint8_t c2_data_write(uint32_t d, uint8_t bytes) { 77 | Serial.print("DW"); 78 | Serial.println(d, HEX); 79 | 80 | // start 81 | c2_bit(true); 82 | C2D_enable(true); 83 | 84 | // instruction 85 | c2_bit(1); 86 | c2_bit(0); 87 | 88 | // Length 89 | bytes--; 90 | c2_bit(bytes & 1); 91 | c2_bit(bytes & 2); 92 | bytes++; 93 | 94 | // Data 95 | for (int i = 0; i < 8 * bytes; ++i) { 96 | c2_bit(d & 1); 97 | d >>= 1; 98 | } 99 | 100 | // Reverse C2D direction 101 | C2D_enable(false); 102 | c2_bit(0); 103 | 104 | // Wait 105 | uint8_t to = 128; 106 | while (!c2_bit(0)) if (!--to) return C2_SHIFT_TIMEOUT; 107 | 108 | // Stop 109 | //c2_bit(0); implied 110 | 111 | return C2_SUCCESS; 112 | } 113 | 114 | uint8_t c2_data_read(uint32_t &d, uint8_t bytes) { 115 | // start 116 | c2_bit(true); 117 | C2D_enable(true); 118 | 119 | // instruction 120 | c2_bit(0); 121 | c2_bit(0); 122 | 123 | // Length 124 | bytes--; 125 | c2_bit(bytes & 1); 126 | c2_bit(bytes & 2); 127 | bytes++; 128 | 129 | // Reverse C2D direction 130 | C2D_enable(false); 131 | c2_bit(0); 132 | 133 | // Wait 134 | uint8_t to = 128; 135 | while (!c2_bit(0)) if (!--to) return C2_SHIFT_TIMEOUT; 136 | 137 | // Data 138 | d = 0; 139 | uint32_t m = 1; 140 | for (int i = 0; i < 8 * bytes; ++i) { 141 | if (c2_bit(d & 1)) { 142 | d |= m; 143 | } 144 | m <<= 1; 145 | } 146 | 147 | // Stop is implied 148 | 149 | Serial.print("DR"); 150 | Serial.println(d, HEX); 151 | return C2_SUCCESS; 152 | } 153 | 154 | // Layer 2: Operations 155 | #define C2_POLL_INBUSY() { \ 156 | uint16_t to = 1000; \ 157 | uint8_t a; \ 158 | while (1) { \ 159 | a = c2_address_read(); \ 160 | if (a == 0xFF) return C2_BROKEN_LINK; \ 161 | if (~a & C2_INBUSY) break; \ 162 | if (--to == 0) return C2_POLL_TIMEOUT; \ 163 | C2_DELAY_MS(1); \ 164 | }; \ 165 | } 166 | 167 | #define C2_POLL_OUTREADY() { \ 168 | uint16_t to = 10000; \ 169 | uint8_t a; \ 170 | while (1) { \ 171 | a = c2_address_read(); \ 172 | if (a == 0xFF) return C2_BROKEN_LINK; \ 173 | if (a & C2_OUTREADY) break; \ 174 | if (--to == 0) return C2_POLL_TIMEOUT; \ 175 | C2_DELAY_MS(1); \ 176 | }; \ 177 | } 178 | 179 | #define C2_DATA_WRITE_AND_CHECK(v, s) { \ 180 | uint8_t r = c2_data_write(v, s); \ 181 | if (r != C2_SUCCESS) return r; \ 182 | } 183 | 184 | #define C2_DATA_READ_AND_CHECK(v, s) { \ 185 | uint8_t r = c2_data_read(v, s); \ 186 | if (r != C2_SUCCESS) return r; \ 187 | } 188 | 189 | #define C2_EXPECT_DATA(value) { \ 190 | uint8_t d; \ 191 | C2_DATA_READ_AND_CHECK(d, 1); \ 192 | if (d != (value)) return C2_CMD_ERROR; \ 193 | } 194 | 195 | uint8_t c2_reset() { 196 | C2CK(false); 197 | C2_DELAY_US(T_RD); 198 | C2CK(true); 199 | C2_DELAY_US(T_SD); 200 | return C2_SUCCESS; 201 | } 202 | 203 | uint8_t c2_programming_init(uint8_t devid) { 204 | c2_reset(); 205 | c2_address_write(C2FPCTL); 206 | C2_DATA_WRITE_AND_CHECK(C2FPCTL_ENABLE0, 1); 207 | C2_DATA_WRITE_AND_CHECK(C2FPCTL_CORE_HALT, 1); 208 | C2_DATA_WRITE_AND_CHECK(C2FPCTL_ENABLE1, 1) 209 | C2_DELAY_MS(21); 210 | 211 | // device specific initialization, see https://www.silabs.com/documents/public/application-notes/AN127.pdf 212 | switch (devid) { 213 | case C2_DEVID_UNKNOWN: 214 | break; 215 | case C2_DEVID_EFM8BB1: 216 | case C2_DEVID_EFM8BB2: 217 | case C2_DEVID_EFM8BB3: // C2_DEVID_EFM8LB1 is the same 218 | c2_address_write(0xFF); 219 | C2_DATA_WRITE_AND_CHECK(0x80, 1); 220 | C2_DELAY_US(5); 221 | c2_address_write(0xEF); 222 | C2_DATA_WRITE_AND_CHECK(0x02, 1); 223 | c2_address_write(0xA9); 224 | C2_DATA_WRITE_AND_CHECK(0x00, 1); 225 | break; 226 | default: 227 | return C2_BROKEN_LINK; 228 | } 229 | 230 | return C2_SUCCESS; 231 | } 232 | 233 | uint8_t c2_block_write(uint32_t address, uint8_t *data, uint8_t len) { 234 | // 1. Perform an Address Write with a value of FPDAT 235 | c2_address_write(C2FPDAT); 236 | 237 | // 2. Perform a Data Write with the Block Write command. 238 | C2_DATA_WRITE_AND_CHECK(C2FPDAT_BLOCK_WRITE, 1); 239 | 240 | // 3. Poll on InBusy using Address Read until the bit clears. 241 | C2_POLL_INBUSY(); 242 | 243 | // 4. Poll on OutReady using Address Read until the bit set. 244 | C2_POLL_OUTREADY(); 245 | 246 | // 5. Perform a Data Read instruction. A value of 0x0D is okay. 247 | C2_EXPECT_DATA(0x0D); 248 | 249 | // 6. Perform a Data Write with the high byte of the address. 250 | C2_DATA_WRITE_AND_CHECK(address >> 8, 1); 251 | 252 | // 7. Poll on InBusy using Address Read until the bit clears. 253 | C2_POLL_INBUSY(); 254 | 255 | // 8. Perform a Data Write with the low byte of the address. 256 | C2_DATA_WRITE_AND_CHECK(address & 255, 1); 257 | 258 | // 9. Poll on InBusy using Address Read until the bit clears. 259 | C2_POLL_INBUSY(); 260 | 261 | // 10. Perform a Data Write with the length. 262 | C2_DATA_WRITE_AND_CHECK(len, 1); 263 | 264 | // 12a. Repeat steps 11 and 12 for each byte specified by the length field. 265 | uint8_t i = 0; 266 | do { 267 | // 11. Poll on InBusy using Address Read until the bit clears. 268 | C2_POLL_INBUSY(); 269 | 270 | // 12. Perform a Data Write with the data. This will write the data to the flash. 271 | C2_DATA_WRITE_AND_CHECK(data[i], 1); 272 | } while (++i != len); 273 | 274 | // 13. Poll on OutReady using Address Read until the bit set. 275 | C2_POLL_OUTREADY(); 276 | 277 | // 14. Perform a Data Read instruction. A value of 0x0D is okay. write to an EPROM block: 278 | C2_EXPECT_DATA(0x0D); 279 | 280 | return C2_SUCCESS; 281 | } 282 | 283 | uint8_t c2_eeprom_write(uint32_t address, uint8_t *data, uint8_t len) { 284 | // 1. Write 0x04 to the FPCTL register. 285 | c2_address_write(C2FPCTL); 286 | C2_DATA_WRITE_AND_CHECK(0x04, 1); 287 | 288 | // 2. Write 0x40 to EPCTL. 289 | c2_address_write(C2EPCTL); 290 | C2_DATA_WRITE_AND_CHECK(0x40, 1); 291 | 292 | // 3. Write 0x58 to EPCTL. 293 | C2_DATA_WRITE_AND_CHECK(0x58, 1); 294 | 295 | // 4. Write the high byte of the address to EPADDRH. 296 | c2_address_write(C2EPADDRH); 297 | C2_DATA_WRITE_AND_CHECK(address >> 8, 1); 298 | 299 | // 5. Write the low byte of the address to address EPADDRL. 300 | c2_address_write(C2EPADDRL); 301 | C2_DATA_WRITE_AND_CHECK(address, 1); 302 | 303 | // 6. Perform an Address Write with a value of EPDAT. 304 | c2_address_write(C2EPDAT); 305 | 306 | // 7. Turn on VPP. 307 | 308 | // 8. Wait for the VPP settling time. 309 | 310 | // 10a. Repeat steps 9 and 10 until all bytes are written. 311 | uint8_t i = 0; 312 | do { 313 | // 9. Write the data to the device using a Data Write. 314 | C2_DATA_WRITE_AND_CHECK(data[i], 1); 315 | 316 | // 10. Perform Address Read instructions until the value returned is not 0x80 and the EPROM is no longer busy. 317 | C2_POLL_INBUSY(); 318 | } while (++i != len); 319 | 320 | // 12. Turn off VPP. Note that VPP can only be applied for a maximum lifetime amount, and this value is specified in the device data sheet. 321 | 322 | // 13. Write 0x40 to EPCTL. 323 | c2_address_write(C2EPCTL); 324 | C2_DATA_WRITE_AND_CHECK(0x40, 1); 325 | 326 | // 14. Write 0x00 to EPCTL. 327 | C2_DATA_WRITE_AND_CHECK(0x00, 1); 328 | 329 | // 15. Write 0x02 to FPCTL. 330 | c2_address_write(C2FPCTL); 331 | C2_DATA_WRITE_AND_CHECK(0x02, 1); 332 | 333 | // 16. Write 0x04 to FPCTL. 334 | C2_DATA_WRITE_AND_CHECK(0x04, 1); 335 | 336 | // 17. Write 0x01 to FPCTL. 337 | C2_DATA_WRITE_AND_CHECK(0x01, 1); 338 | 339 | return C2_SUCCESS; 340 | } 341 | 342 | uint8_t c2_block_read(uint32_t address, uint8_t *data, uint8_t len) { 343 | // 1. Perform an Address Write with a value of FPDAT. 344 | c2_address_write(C2FPDAT); 345 | 346 | // 2. Perform a Data Write with the Block Read command. 347 | C2_DATA_WRITE_AND_CHECK(C2FPDAT_BLOCK_READ, 1); 348 | 349 | // 3. Poll on InBusy using Address Read until the bit clears. 350 | C2_POLL_INBUSY(); 351 | 352 | // 4. Poll on OutReady using Address Read until the bit set. 353 | C2_POLL_OUTREADY(); 354 | 355 | // 5. Perform a Data Read instruction. A value of 0x0D is okay. 356 | C2_EXPECT_DATA(0x0D); 357 | 358 | // 6. Perform a Data Write with the high byte of the address. 359 | C2_DATA_WRITE_AND_CHECK(address >> 8, 1); 360 | 361 | // 7. Poll on InBusy using Address Read until the bit clears. 362 | C2_POLL_INBUSY(); 363 | 364 | // 8. Perform a Data Write with the low byte of the address. 365 | C2_DATA_WRITE_AND_CHECK(address, 1); 366 | 367 | // 9. Poll on InBusy using Address Read until the bit clears. 368 | C2_POLL_INBUSY(); 369 | 370 | // 10. Perform a Data Write with the length. 371 | C2_DATA_WRITE_AND_CHECK(len, 1); 372 | 373 | // 11. Poll on InBusy using Address Read until the bit clears. 374 | C2_POLL_INBUSY(); 375 | 376 | // 12. Poll on OutReady using Address Read until the bit set. 377 | C2_POLL_OUTREADY(); 378 | 379 | // 13. Read FPI Command Status. Abort if Status != 0x0D. 380 | C2_EXPECT_DATA(0x0D); 381 | 382 | // 15a. Repeat step 14 and 15 for each byte specified by the length field. 383 | uint8_t i = 0; 384 | do { 385 | // 14. Poll on OutReady using Address Read until the bit set. 386 | C2_POLL_OUTREADY(); 387 | 388 | // 15. Perform a Data Read instruction. This will read the data from the flash. 389 | C2_DATA_READ_AND_CHECK(data[i], 1); 390 | } while (++i != len); 391 | 392 | return C2_SUCCESS; 393 | } 394 | 395 | uint8_t c2_eeprom_read(uint32_t address, uint8_t *data, uint8_t len) { 396 | // 1. Write 0x04 to the FPCTL register. 397 | c2_address_write(C2FPCTL); 398 | C2_DATA_WRITE_AND_CHECK(0x04, 1); 399 | 400 | // 2. Write 0x00 to EPCTL. 401 | c2_address_write(C2EPCTL); 402 | C2_DATA_WRITE_AND_CHECK(0x00, 1); 403 | 404 | // 3. Write 0x58 to EPCTL. 405 | C2_DATA_WRITE_AND_CHECK(0x58, 1); 406 | 407 | // 4. Write the high byte of the address to EPADDRH. 408 | c2_address_write(C2EPADDRH); 409 | C2_DATA_WRITE_AND_CHECK(address >> 8, 1); 410 | 411 | // 5. Write the low byte of the address to address EPADDRL. 412 | c2_address_write(C2EPADDRL); 413 | C2_DATA_WRITE_AND_CHECK(address, 1); 414 | 415 | // 6. Perform an Address Write with a value of EPDAT. 416 | c2_address_write(C2EPDAT); 417 | 418 | // 9. Repeat steps 7 and 8 until all bytes are read. 419 | uint8_t i = 0; 420 | do { 421 | // 7.1. Perform an Address Write operation with a value of EPSTAT. 422 | c2_address_write(C2EPSTAT); 423 | 424 | // 7.2. Perform a Data Read operation and check the bits of the EPSTAT register. 425 | uint8_t err; 426 | C2_DATA_READ_AND_CHECK(err, 1); 427 | if (err & C2EPSTAT_ERROR) return C2_CMD_ERROR; 428 | 429 | // 7.3. Perform an Address Write operation with a value of EPDAT. 430 | c2_address_write(C2EPDAT); 431 | 432 | // 7. Perform Address Read instructions until the value returned is not 0x80 and the EPROM is no longer busy. 433 | C2_POLL_INBUSY(); 434 | 435 | // 8.1. Perform an Address Write operation with a value of EPSTAT. 436 | c2_address_write(C2EPSTAT); 437 | 438 | // 8.2. Perform a Data Read operation and check the ERROR bit in the EPSTAT register. 439 | C2_DATA_READ_AND_CHECK(err, 1); 440 | if (err & C2EPSTAT_ERROR) return C2_CMD_ERROR; 441 | 442 | // 8.3. Perform an Address Write operation with a value of EPDAT. 443 | C2_DATA_WRITE_AND_CHECK(C2EPDAT, 1); 444 | 445 | // 8. Read the byte using the Data Read instruction. 446 | C2_DATA_READ_AND_CHECK(data[i], 1); 447 | } while (++i != len); 448 | 449 | // 10. Write 0x40 to EPCTL. 450 | c2_address_write(C2EPCTL); 451 | C2_DATA_WRITE_AND_CHECK(0x40, 1); 452 | 453 | // 11. Write 0x00 to EPCTL. 454 | C2_DATA_WRITE_AND_CHECK(0x00, 1); 455 | 456 | // 12. Write 0x02 to FPCTL. 457 | c2_address_write(C2FPCTL); 458 | C2_DATA_WRITE_AND_CHECK(0x02, 1); 459 | 460 | // 13. Write 0x04 to FPCTL. 461 | C2_DATA_WRITE_AND_CHECK(0x04, 1); 462 | 463 | // 14. Write 0x01 to FPCTL. 464 | C2_DATA_WRITE_AND_CHECK(0x01, 1); 465 | 466 | return C2_SUCCESS; 467 | } 468 | 469 | uint8_t c2_page_erase(uint8_t page) { 470 | // 1. Perform an Address Write with a value of FPDAT. 471 | c2_address_write(C2FPDAT); 472 | 473 | // 2. Perform a Data Write with the Page Erase command. 474 | c2_data_write(C2FPDAT_FLASH_PAGE_ERASE, 1); 475 | 476 | // 3. Poll on InBusy using Address Read until the bit clears. 477 | C2_POLL_INBUSY(); 478 | 479 | // 4. Poll on OutReady using Address Read until the bit set. 480 | C2_POLL_OUTREADY(); 481 | 482 | // 5. Perform a Data Read instruction. A value of 0x0D is okay. 483 | C2_EXPECT_DATA(0x0D); 484 | 485 | // 6. Perform a Data Write with the page number. 486 | c2_data_write(page, 1); 487 | 488 | // 7. Poll on InBusy using Address Read until the bit clears. 489 | C2_POLL_INBUSY(); 490 | 491 | // 8. Poll on OutReady using Address Read until the bit clears. 492 | C2_POLL_OUTREADY(); 493 | 494 | // 9. Perform a Data Read instruction. A value of 0x0D is okay. 495 | C2_EXPECT_DATA(0x0D); 496 | 497 | // 10. Perform a Data Write with the a value of 0x00. 498 | c2_data_write(0x00, 1); 499 | 500 | // 11. Poll on InBusy using Address Read until the bit clears. 501 | C2_POLL_INBUSY(); 502 | 503 | // 12. Poll on OutReady using Address Read until the bit set. 504 | C2_POLL_OUTREADY(); 505 | 506 | // 13. Perform a Data Read instruction. A value of 0x0D is okay. 507 | C2_EXPECT_DATA(0x0D); 508 | 509 | return C2_SUCCESS; 510 | } 511 | 512 | uint8_t c2_device_erase() { 513 | // 1. Perform an Address Write with a value of FPDAT. 514 | c2_address_write(C2FPDAT); 515 | 516 | // 2. Perform a Data Write with the Device Erase command. 517 | C2_DATA_WRITE_AND_CHECK(C2FPDAT_DEVICE_ERASE, 1); 518 | 519 | // 3. Poll on InBusy using Address Read until the bit clears. 520 | C2_POLL_INBUSY(); 521 | 522 | // 4. Poll on OutReady using Address Read until the bit set. 523 | C2_POLL_OUTREADY(); 524 | 525 | // 5. Perform a Data Read instruction. A value of 0x0D is okay. 526 | C2_EXPECT_DATA(0x0D); 527 | 528 | // 6. Perform a Data Write with a value of 0xDE. 529 | C2_DATA_WRITE_AND_CHECK(0xDE, 1); 530 | 531 | // 7. Poll on InBusy using Address Read until the bit clears. 532 | C2_POLL_INBUSY(); 533 | 534 | // 8. Perform a Data Write with a value of 0xAD. 535 | C2_DATA_WRITE_AND_CHECK(0xAD, 1); 536 | 537 | // 9. Poll on InBusy using Address Read until the bit clears. 538 | C2_POLL_INBUSY(); 539 | 540 | // 10. Perform a Data Write with a value of 0xA5. 541 | C2_DATA_WRITE_AND_CHECK(0xA5, 1); 542 | 543 | // 11. Poll on InBusy using Address Read until the bit clears. 544 | C2_POLL_INBUSY(); 545 | 546 | // 12. Poll on OutReady using Address Read until the bit set. 547 | C2_POLL_OUTREADY(); 548 | 549 | // 13. Perform a Data Read instruction. A value of 0x0D is okay. 550 | C2_EXPECT_DATA(0x0D); 551 | 552 | return C2_SUCCESS; 553 | } 554 | 555 | uint8_t c2_sfr_write_non_paged(uint8_t address, uint8_t data) { 556 | // 1. Write the SFR address to the device using the Address Write instruction. 557 | c2_address_write(address); 558 | 559 | // 2. Write the SFR value to the device using the Data Write instruction. 560 | C2_DATA_WRITE_AND_CHECK(data, 1); 561 | 562 | return C2_SUCCESS; 563 | } 564 | 565 | uint8_t c2_sfr_write_paged(uint8_t address, uint8_t data) { 566 | // 1. Perform an Address Write with a value of FPDAT. 567 | c2_address_write(C2FPDAT); 568 | 569 | // 2. Write the Direct Write command (0x0A) using a Data Write 570 | C2_DATA_WRITE_AND_CHECK(C2FPDAT_DIRECT_WRITE, 1); 571 | 572 | // 3. Poll InBusy until the data is processed by the PI. 573 | C2_POLL_INBUSY(); 574 | 575 | // 4. Poll OutReady it sets to 1. 576 | C2_POLL_OUTREADY(); 577 | 578 | // 5. Perform a Data Read to ensure a return value of 0x0D (no errors). 579 | C2_EXPECT_DATA(0x0D); 580 | 581 | // 6. Perform a Data Write with a value of the SFR address. 582 | C2_DATA_WRITE_AND_CHECK(address, 1); 583 | 584 | // 7. Poll InBusy until the data is processed by the PI. 585 | C2_POLL_INBUSY(); 586 | 587 | // 8. Perform a Data Write with a value of 0x01. 588 | C2_DATA_WRITE_AND_CHECK(0x01, 1); 589 | 590 | // 9. Poll InBusy until the data is processed by the PI. 591 | C2_POLL_INBUSY(); 592 | 593 | // 10. Perform a Data Write with the new SFR value. 594 | C2_DATA_WRITE_AND_CHECK(data, 1); 595 | 596 | // 11. Poll InBusy until the data is processed by the PI. 597 | C2_POLL_INBUSY(); 598 | 599 | return C2_SUCCESS; 600 | } 601 | 602 | // 4.6. Reading from an SFR 603 | // To read from an SFR on a device that does not have SFR paging: 604 | uint8_t c2_sfr_read_non_paged(uint8_t address, uint8_t &v) { 605 | // 1. Write the SFR address to the device using the Address Write instruction. 606 | c2_address_write(address); 607 | 608 | // 2. Read the SFR value from the device using the Data Read instruction. 609 | C2_DATA_READ_AND_CHECK(v, 1); 610 | 611 | return C2_SUCCESS; 612 | } 613 | 614 | // For devices with SFR paging, direct reads through the PI using the Direct Read command are recommended to ensure the SFR Page is managed properly. 615 | // To read an SFR from a device with SFR paging: 616 | uint8_t c2_sfr_read_paged(uint8_t address, uint8_t &v) { 617 | // 1. Perform an Address Write with a value of FPDAT. 618 | c2_address_write(C2FPDAT); 619 | 620 | // 2. Write the Direct Read command (0x09) using a Data Write. 621 | C2_DATA_WRITE_AND_CHECK(C2FPDAT_DIRECT_READ, 1); 622 | 623 | // 3. Poll InBusy until the data is processed by the PI. 624 | C2_POLL_INBUSY(); 625 | 626 | // 4. Poll OutReady until it sets to 1. 627 | C2_POLL_OUTREADY(); 628 | 629 | // 5. Perform a Data Read to ensure a return value of 0x0D (no errors). 630 | C2_EXPECT_DATA(0x0D); 631 | 632 | // 6. Perform a Data Write with a value of the SFR address. 633 | C2_DATA_WRITE_AND_CHECK(address, 1); 634 | 635 | // 7. Poll InBusy until the data is processed by the PI. 636 | C2_POLL_INBUSY(); 637 | 638 | // 8. Perform a Data Write with a value of 0x01. 639 | C2_DATA_WRITE_AND_CHECK(0x01, 1); 640 | 641 | // 9. Poll InBusy until the data is processed by the PI. 642 | C2_POLL_INBUSY(); 643 | 644 | // 10. Poll OutReady until it sets to 0. 645 | C2_POLL_OUTREADY(); 646 | 647 | // 11. Read the SFR value from the device using the Data Read instruction. 648 | C2_DATA_READ_AND_CHECK(v, 1); 649 | 650 | return C2_SUCCESS; 651 | } 652 | 653 | // This is to enforce arduino-like formatting in kate 654 | // kate: space-indent on; indent-width 2; mixed-indent off; indent-mode cstyle; 655 | -------------------------------------------------------------------------------- /arduino_libs/c2_prog/c2.h: -------------------------------------------------------------------------------- 1 | #ifndef C2_H 2 | #define C2_H 3 | 4 | #include 5 | #include 6 | 7 | //////////////////////////////// 8 | // Hardware Abstraction Layer // 9 | //////////////////////////////// 10 | 11 | // Rewrite these for your hardware 12 | #define PIN_C2CK 0 13 | #define PIN_C2D 2 14 | 15 | // Set C2CK state 16 | inline void C2CK(bool ck) { 17 | digitalWrite(PIN_C2CK, ck); 18 | } 19 | 20 | // get C2CK state 21 | inline bool C2CK() { 22 | return digitalRead(PIN_C2CK); 23 | } 24 | 25 | // Set C2D state 26 | inline void C2D(bool d) { 27 | digitalWrite(PIN_C2D, d); 28 | } 29 | 30 | // Get C2D state 31 | inline bool C2D() { 32 | return digitalRead(PIN_C2D); 33 | } 34 | 35 | // Enable/disable C2D output butter 36 | inline void C2D_enable(bool oe) { 37 | if (oe) pinMode(PIN_C2D, OUTPUT); 38 | else pinMode(PIN_C2D, INPUT); 39 | } 40 | 41 | // Delay functions 42 | #define C2_DELAY_US(n) delayMicroseconds(n) 43 | #define C2_DELAY_MS(n) delay(n) 44 | 45 | //////////////////////////////////////////// 46 | // Nothing should need change from now on // 47 | //////////////////////////////////////////// 48 | 49 | // Exceptions: 50 | #define C2_SUCCESS 0x00 // Compare for success 51 | #define C2_ERROR 0xFF // Mask for all errors 52 | #define C2_TIMEOUT 0x03 // Mask for timeouts 53 | #define C2_SHIFT_TIMEOUT 0x01 // Shift wait 54 | #define C2_POLL_TIMEOUT 0x02 // Register poll 55 | #define C2_CMD_ERROR 0x04 // In-command Error 56 | #define C2_BROKEN_LINK 0x08 // Address read returned 0xFF, comms disabled 57 | 58 | // Register Addresses 59 | #define C2DEVID 0x00 60 | #define C2REVID 0x01 61 | #define C2FPCTL 0x02 62 | #define C2FPDAT 0xB4 63 | 64 | #define C2EPCTL 0x00 65 | #define C2EPDAT 0x00 66 | #define C2EPDAT 0x00 67 | #define C2EPADDRH 0x00 68 | #define C2EPADDRL 0x00 69 | #define C2EPSTAT 0x00 70 | 71 | // Commands for FPCTL register 72 | #define C2FPCTL_ENABLE0 0x02 73 | #define C2FPCTL_CORE_HALT 0x04 74 | #define C2FPCTL_ENABLE1 0x01 75 | 76 | // Commands for FPDAT register 77 | #define C2FPDAT_DEVICE_ERASE 0x03 78 | #define C2FPDAT_FLASH_BLOCK_READ 0x06 79 | #define C2FPDAT_BLOCK_WRITE 0x07 80 | #define C2FPDAT_FLASH_PAGE_ERASE 0x08 81 | #define C2FPDAT_BLOCK_READ 0x06 82 | #define C2FPDAT_GET_VERSION 0x01 83 | #define C2FPDAT_GET_DERIVATIVE 0x02 84 | #define C2FPDAT_DIRECT_READ 0x09 85 | #define C2FPDAT_DIRECT_WRITE 0x0A 86 | #define C2FPDAT_INDIRECT_READ 0x0B 87 | #define C2FPDAT_INDIRECT_WRITE 0x0C 88 | 89 | // Commands for EPCTL register 90 | #define C2EPCTL_ENABLE0 0x40 91 | #define C2EPCTL_ENABLE1 0x58 92 | 93 | // EPSTAT status bits 94 | #define C2EPSTAT_WLOCK 0x80 95 | #define C2EPSTAT_RLOCK 0x40 96 | #define C2EPSTAT_ERROR 0x01 97 | 98 | // 'Address read' status bits 99 | #define C2_FLBUSY 0x08 100 | #define C2_EEBUSY C2_FLBUSY 101 | #define C2_EEERROR 0x04 102 | #define C2_INBUSY 0x02 103 | #define C2_OUTREADY 0x01 104 | 105 | // Device families (https://www.silabs.com/documents/public/application-notes/AN127.pdf) 106 | #define C2_DEVID_UNKNOWN 0x00 107 | #define C2_DEVID_EFM8BB1 0x30 108 | #define C2_DEVID_EFM8BB2 0x32 109 | #define C2_DEVID_EFM8BB3 0x34 110 | #define C2_DEVID_EFM8LB1 0x34 111 | 112 | // Layer 1: C2 Programmig Interface (PI) Register access 113 | void c2_address_write(uint8_t address); 114 | uint8_t c2_address_read(); 115 | uint8_t c2_data_write(uint32_t d, uint8_t bytes); 116 | uint8_t c2_data_read(uint32_t &d, uint8_t bytes=4); 117 | 118 | // Shorcuts for smaller words 119 | inline uint8_t c2_data_read(uint16_t &d, uint8_t bytes=2) { 120 | uint32_t dd; 121 | uint8_t r = c2_data_read(dd, 2); 122 | d = dd; 123 | return r; 124 | } 125 | inline uint8_t c2_data_read(uint8_t &d, uint8_t bytes=1) { 126 | uint32_t dd; 127 | uint8_t r = c2_data_read(dd, 1); 128 | d = dd; 129 | return r; 130 | } 131 | 132 | // Layer 2: Operations 133 | uint8_t c2_reset(); 134 | uint8_t c2_programming_init(uint8_t devid); 135 | uint8_t c2_block_write(uint32_t address, uint8_t *data, uint8_t len); 136 | uint8_t c2_block_read(uint32_t address, uint8_t *data, uint8_t len); 137 | uint8_t c2_eeprom_read(uint32_t address, uint8_t *data, uint8_t len); 138 | uint8_t c2_page_erase(uint8_t page); 139 | uint8_t c2_device_erase(); 140 | uint8_t c2_sfr_write_non_paged(uint8_t address, uint8_t data); 141 | uint8_t c2_sfr_write_paged(uint8_t address, uint8_t data); 142 | uint8_t c2_sfr_read_non_paged(uint8_t address, uint8_t &data); 143 | uint8_t c2_sfr_read_paged(uint8_t address, uint8_t &data); 144 | 145 | #endif // C2_H 146 | -------------------------------------------------------------------------------- /arduino_libs/httpd/examples/HelloWorld/helloworld.ino: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | * (C)2015 Lucas V. Hartmann * 3 | * * 4 | * This program is free software: you can redistribute it and/or modify * 5 | * it under the terms of the GNU General Public License as published by * 6 | * the Free Software Foundation, either version 3 of the License, or * 7 | * (at your option) any later version. * 8 | * * 9 | * This program is distributed in the hope that it will be useful, * 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 12 | * GNU General Public License for more details. * 13 | * * 14 | * You should have received a copy of the GNU General Public License * 15 | * along with this program. If not, see . * 16 | *************************************************************************/ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #define WIFI_NAME "" 26 | #define WIFI_PASSWORD "" 27 | 28 | ////////////////////// 29 | // Hello World Page // 30 | ////////////////////// 31 | class HelloWorldPage : public HttpServerPage { 32 | void onEndOfHeader() { 33 | c->write("\ 34 | \ 35 | \ 36 | \ 37 |
\ 38 | Select image to upload:\ 39 | \ 40 | \ 41 |
\ 42 | \ 43 | \ 44 | "); 45 | c->stop(); 46 | } 47 | } helloWorldPage; 48 | 49 | //////////////////////////////////////////////////////////////////////////// 50 | // Error Page // 51 | // You may choose to look for files in filesystem instead of just // 52 | // printing an error message. This would allow for a file-based server. // 53 | //////////////////////////////////////////////////////////////////////////// 54 | class ErrorPage : public HttpServerPage { 55 | void onEndOfHeader() { 56 | c->write("HTTP/1.1 404 Not Found\r\n\r\n"); 57 | c->write("

Page Not Found.

"); 58 | c->stop(); 59 | } 60 | } errorPage; 61 | 62 | ///////////////////// 63 | // Echo Page // 64 | ///////////////////// 65 | class EchoPage : public HttpServerPage { 66 | bool headerprinted; 67 | void onConnect(WiFiClient &client, const char *sub, const char *hash) { 68 | HttpServerPage::onConnect(client,sub,hash); 69 | c->print("HTTP/1.1 200 OK\r\n"); 70 | c->print("Content-Type: text/html\r\n\r\n"); 71 | c->print("Subpath: "); 72 | c->print("sub"); 73 | c->print("Hash tag: "); 74 | c->println(hash); 75 | headerprinted = false; 76 | } 77 | void onQueryVar(char *var, char *value) { 78 | HttpServerPage::onQueryVar(var, value); 79 | c->print(var); 80 | c->print(" = "); 81 | c->print(value); 82 | c->print("
"); 83 | } 84 | void onHeader(char *str) { 85 | HttpServerPage::onHeader(str); 86 | if (!headerprinted) c->print("

Echo Page

Headers:

");
 87 |       headerprinted = true;
 88 |       c->println(str);
 89 |     }
 90 |     void onEndOfHeader() {
 91 |       //      HttpServerPage::onEndOfHeader();
 92 |       c->print("

Body

");
 93 |     }
 94 |     int onData(char *buff, int count) {
 95 |       HttpServerPage::onData(buff, count);
 96 |       c->println(buff);
 97 |       return count;
 98 |     }
 99 | } echoPage;
100 | 
101 | //////////////
102 | // Page Map //
103 | //////////////
104 | HttpServer::PageMap pageMap[] = {
105 |   { "/", &helloWorldPage },
106 |   { "/echo", &echoPage },
107 |   { 0, &errorPage } // End of list and Page-Not-Found handler
108 | };
109 | 
110 | // Servers
111 | HttpServer httpServer(pageMap);
112 | 
113 | // Setup
114 | MDNSResponder mdns;
115 | 
116 | void setup() {
117 |   // put your setup code here, to run once:
118 |   Serial.begin(115200);
119 | 
120 |   // Wifi Setup
121 |   WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
122 | }
123 | 
124 | bool online = false;
125 | void loop() {
126 |   if (WiFi.status() != WL_CONNECTED) {
127 |     if (online) {
128 |       httpServer.stop();
129 |       online = false;
130 |     }
131 |   } else {
132 |     if (!online) {
133 |       // Network reconnect
134 |       online = true;
135 |       
136 |       // Reconfigure HTTP server
137 |       httpServer.begin();
138 | 
139 |       // Allows http://esp8266.local to be used instead of IP.
140 |       mdns.begin("esp8266", WiFi.localIP(), 5*60);
141 |     }
142 |     
143 |     // Network is online, do the polling
144 |     httpServer.loop();
145 |     mdns.update();
146 |   }
147 | }
148 | 
149 | // This is to enforce arduino-like formatting in kate-editor.
150 | // kate: space-indent on; indent-width 2; mixed-indent off; indent-mode cstyle;
151 | 


--------------------------------------------------------------------------------
/arduino_libs/httpd/httpServer.h:
--------------------------------------------------------------------------------
  1 | /**************************************************************************
  2 |  * (C)2015 Lucas V. Hartmann                        *
  3 |  *                                                                        *
  4 |  * This program is free software: you can redistribute it and/or modify   *
  5 |  * it under the terms of the GNU General Public License as published by   *
  6 |  * the Free Software Foundation, either version 3 of the License, or      *
  7 |  * (at your option) any later version.                                    *
  8 |  *                                                                        *
  9 |  * This program is distributed in the hope that it will be useful,        *
 10 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 11 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 12 |  * GNU General Public License for more details.                           *
 13 |  *                                                                        *
 14 |  * You should have received a copy of the GNU General Public License      *
 15 |  * along with this program.  If not, see .  *
 16 |  *************************************************************************/
 17 | 
 18 | #ifndef HTTPSERVER_H
 19 | #define HTTPSERVER_H
 20 | 
 21 | #ifdef ARDUINO_ARCH_ESP32
 22 | #include 
 23 | #else
 24 | #include 
 25 | #endif
 26 | #include 
 27 | #include "string.h"
 28 | #include 
 29 | 
 30 | #define DEBUG(x) (x)
 31 | #define DEBUG_DUMP(x) { Serial.print( #x " = " ); Serial.println(x); }
 32 | 
 33 | struct HttpServer {
 34 |   WiFiServer s;
 35 |   WiFiClient c;
 36 |   char buff[256];
 37 |   uint8_t bp;
 38 | 
 39 |   const struct PageMap {
 40 |     const char *target;
 41 |     HttpServerPage *page;
 42 |   } *pages;
 43 |   HttpServerPage *page;
 44 | 
 45 |   enum {
 46 |     stRequest, // First line, HTTP request "GET / HTTP/1.1"
 47 |     stHeaders, // HTTP Headers "Content-Type: crazy/stuff"
 48 |     stData     // Data segment
 49 |   } state;
 50 | 
 51 |   HttpServer(const PageMap *pm) : s(80), pages(pm) {}
 52 |   void setPageMap(const PageMap *pm) { pages = pm; }
 53 | 
 54 |   void begin();
 55 |   void stop();
 56 |   void loop();
 57 | 
 58 |   // Auxiliary function blanks removal
 59 |   static char *clean(char *p);
 60 |   static void urldecode(const char *in, char *out);
 61 | 
 62 |   // Handlers
 63 |   void handleRequest(char *str);
 64 | };
 65 | 
 66 | void HttpServer::begin() {
 67 |   s.begin();
 68 |   page = 0;
 69 |   bp = 0;
 70 | }
 71 | 
 72 | void HttpServer::stop() {
 73 |   c.stop();
 74 |   //	s.end();
 75 | }
 76 | 
 77 | void HttpServer::loop() {
 78 |   char *str;
 79 | 
 80 |   // Handle disconnects
 81 |   if (c && !c.connected()) {
 82 |     DEBUG(Serial.println("Client disconnected."));
 83 |     if (page) page->onClose();
 84 |     c.stop();
 85 |   }
 86 | 
 87 |   // Accept incoming connections
 88 |   if (!c) {
 89 |     c = s.available();
 90 |     state = stRequest;
 91 |     if (c) DEBUG(Serial.println("Client connected."));
 92 |     bp = 0;
 93 |   }
 94 | 
 95 |   // Handle communicatons
 96 |   if (!c) return;
 97 | 
 98 |   char ch;
 99 |   do {
100 |     if (!c.available()) return;
101 |     ch = c.read();
102 |     buff[bp++] = ch;
103 |   } while (ch != '\n');
104 | 
105 |   buff[--bp] = 0;
106 |   DEBUG_DUMP(buff);
107 | 
108 |   switch (state) {
109 |     case stRequest:
110 |       str = clean(buff);
111 |       handleRequest(str);
112 |       state = stHeaders;
113 |       break;
114 | 
115 |     case stHeaders:
116 |       str = clean(buff);
117 |       if (strlen(str) == 0) {
118 |         state = stData;
119 |         page->onEndOfHeader();
120 |         break;
121 |       }
122 |       page->onHeader(str);
123 |       break;
124 | 
125 |     case stData:
126 |       page->onData(buff, bp);
127 |       break;
128 |   }
129 | 
130 |   bp = 0;
131 | 
132 |   return;
133 | 
134 | 
135 | 
136 | 
137 | 
138 | 
139 |   int av = c.available();
140 |   if (!av) return;
141 | 
142 |   // Read data up to buffer length
143 |   DEBUG_DUMP(bp);
144 |   bp += c.readBytes(buff + bp, _min(sizeof(buff) - bp, av));
145 |   DEBUG(Serial.print("Buffer state ["));
146 |   DEBUG(Serial.write(buff, bp));
147 |   DEBUG(Serial.println("]"));
148 |   DEBUG_DUMP(bp);
149 | 
150 |   // Data passthru during data stage
151 |   if (state == stData && page) {
152 |     DEBUG(Serial.print("Data passthru ["));
153 |     DEBUG(Serial.write(buff, bp));
154 |     DEBUG(Serial.println("]"));
155 | 
156 |     // Feed data to the page
157 |     int used = page->onData(buff, bp);
158 | 
159 |     // Save unused data for next time
160 |     for (int i = used; i < bp; ++i) buff[i - used] = buff[i];
161 | 
162 |     return;
163 |   }
164 | 
165 |   int sos = 0, eos = -1;
166 |   while (1) {
167 |     // Search for line termination
168 |     while (eos < bp)
169 |       if (buff[++eos] == '\n') break;
170 | 
171 |     if (eos == bp) break; // Not found
172 | 
173 |     // Line terminator found at buff[eos]
174 |     buff[eos] = 0;
175 | 
176 |     DEBUG(Serial.print("Data received ["));
177 |     DEBUG(Serial.print(buff + sos));
178 |     DEBUG(Serial.println("]"));
179 | 
180 |     // Call appropriate handler
181 |     switch (state) {
182 |       case stRequest:
183 |         str = clean(buff + sos);
184 |         handleRequest(str);
185 |         state = stHeaders;
186 |         break;
187 | 
188 |       case stHeaders:
189 |         str = clean(buff + sos);
190 |         if (strlen(str) == 0) {
191 |           state = stData;
192 |           page->onEndOfHeader();
193 |           break;
194 |         }
195 |         page->onHeader(str);
196 |         break;
197 |     }
198 |   }
199 | 
200 |   // Save unused data for next round
201 |   DEBUG(Serial.print("buffer shifting "));
202 |   DEBUG(Serial.print(bp - eos));
203 |   DEBUG(Serial.println(" bytes."));
204 |   sos = 0;
205 |   while (eos < bp) buff[sos++] = buff[eos++];
206 |   bp = sos;
207 | 
208 | }
209 | 
210 | char *HttpServer::clean(char *str) {
211 |   // Skip non-graphical chars at start of line
212 |   while (*str && !isgraph(*str)) str++;
213 | 
214 |   // Find end-of-string
215 |   char *eos = str;
216 |   while (*eos) eos++;
217 | 
218 |   // Erase non-graphical chars at enf of line
219 |   eos--;
220 |   while (*eos && !isgraph(*eos)) *eos-- = 0;
221 | 
222 |   //  DEBUG(Serial.print("clean["));
223 |   //  DEBUG(Serial.print(str));
224 |   //  DEBUG(Serial.println("]"));
225 | 
226 |   // Return clean string
227 |   return str;
228 | }
229 | 
230 | void HttpServer::handleRequest(char *str) {
231 |   // HTTP header is expected to have 3 fields
232 |   // METHOD target?var=value PROTOCOL
233 |   // We care about targets and query vars.
234 |   DEBUG(Serial.print("handleRequest("));
235 |   DEBUG(Serial.print(str));
236 |   DEBUG(Serial.println(")"));
237 | 
238 |   // Skip over METHOD
239 |   while (*str && *str != ' ') str++;
240 |   if (!*str) return; // Bad header, no space found
241 |   str++; // Skip space
242 | 
243 |   // Seek to end of target
244 |   char *p = str;
245 |   while (*p && *p != ' ') p++;
246 |   if (!*p) return; // Bad header, no space found
247 |   *p = 0; // mark as end of string
248 | 
249 |   // Search for query string
250 |   char *query = str;
251 |   while (*query && *query != '?') query++;
252 |   if (*query) *query++ = 0; // Found, separate from target
253 |   else query = 0; // No query string
254 | 
255 |   // Search for hash string
256 |   char *hash = str;
257 |   while (*hash && *hash != '#') hash++;
258 |   if (*hash && (!query || hash < query)) *hash++ = 0; // Found, separate from target
259 |   else hash = 0; // No query string
260 | 
261 |   // Check for a matching page on the list
262 |   char *subpath = str; // Defaults to full path for use on page-not-found handler
263 |   int pageno = -1;
264 |   while (pages[++pageno].target) {
265 |     // Compare up to listed target's length
266 |     size_t n = strlen(pages[pageno].target);
267 |     if (strncmp(pages[pageno].target, str, n) != 0) continue;
268 | 
269 |     // Exact target match
270 |     if (str[n] == 0) {
271 |       subpath = 0; // No subpath
272 |       break;
273 |     }
274 | 
275 |     // Subpath match
276 |     if (str[n] == '/') {
277 |       subpath = str + n + 1;
278 |       break;
279 |     }
280 |   }
281 |   page = pages[pageno].page; // Set current page
282 |   // Please notice that 404 page must be last in the list with target=NULL
283 | 
284 |   if (pages[pageno].target) DEBUG_DUMP(pages[pageno].target);
285 | 
286 |   // Message about connection established
287 |   page->onConnect(c, subpath, hash);
288 | 
289 |   // Iterate query strings
290 |   while (query) {
291 |     // Variable name is the first thing
292 |     char *var = query;
293 | 
294 |     // Search equals sign
295 |     char *eq = var;
296 |     while (*eq && *eq != '=') eq++;
297 | 
298 |     // Search end of variable
299 |     char *end = var;
300 |     while (*end && *end != '?' && *end != '&') end++;
301 | 
302 |     // Mark query var as read
303 |     if (*end) query = end + 1;
304 |     else      query = 0;
305 | 
306 |     // Correct eq for cases like "var1&var2=3"
307 |     if (eq > end) eq = 0;
308 | 
309 |     // Set eq to null pointer if no value has been set
310 |     if (!*eq) eq = 0;
311 | 
312 |     // Separate substrings and decode
313 |     *end  = 0;
314 |     if (eq) {
315 |       *eq++ = 0; // Mark end of var name
316 | 
317 |       // UrlDecode value in place
318 |       urldecode(eq, eq);
319 |     }
320 | 
321 |     // UrlDecode variable name in place
322 |     urldecode(var, var);
323 | 
324 |     // Feed variable to the selected page handler
325 |     page->onQueryVar(var, eq);
326 |   }
327 | }
328 | 
329 | void HttpServer::urldecode(const char *in, char *out) {
330 |   return;
331 | }
332 | 
333 | #endif
334 | 
335 | // This is to enforce arduino-like formatting in kate
336 | // kate: space-indent on; indent-width 2; mixed-indent off; indent-mode cstyle;
337 | 


--------------------------------------------------------------------------------
/arduino_libs/httpd/httpServerPage.cpp:
--------------------------------------------------------------------------------
 1 | /**************************************************************************
 2 |  * (C)2015 Lucas V. Hartmann                        *
 3 |  *                                                                        *
 4 |  * This program is free software: you can redistribute it and/or modify   *
 5 |  * it under the terms of the GNU General Public License as published by   *
 6 |  * the Free Software Foundation, either version 3 of the License, or      *
 7 |  * (at your option) any later version.                                    *
 8 |  *                                                                        *
 9 |  * This program is distributed in the hope that it will be useful,        *
10 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of         *
11 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
12 |  * GNU General Public License for more details.                           *
13 |  *                                                                        *
14 |  * You should have received a copy of the GNU General Public License      *
15 |  * along with this program.  If not, see .  *
16 |  *************************************************************************/
17 | 
18 | #include 
19 | #include "httpServerPage.h"
20 | 
21 | #define DEBUG(x) (x)
22 | 
23 | void HttpServerPage::onConnect(WiFiClient &client, const char *sub, const char *hash) {
24 |   DEBUG(Serial.print("onConnect(client,\""));
25 |   DEBUG(Serial.print(sub));
26 |   DEBUG(Serial.print("\",\""));
27 |   DEBUG(Serial.print(hash));
28 |   DEBUG(Serial.println("\")"));
29 |   c = &client;
30 | }
31 | 
32 | void HttpServerPage::onQueryVar(char *var, char *value) {
33 |   DEBUG(Serial.print("onQueryVar("));
34 |   DEBUG(Serial.print(var));
35 |   DEBUG(Serial.print(","));
36 |   DEBUG(Serial.print(value));
37 |   DEBUG(Serial.println(")"));
38 | }
39 | 
40 | void HttpServerPage::onHeader(char *str) {
41 |   DEBUG(Serial.print("onHeader("));
42 |   DEBUG(Serial.print(str));
43 |   DEBUG(Serial.println(")"));
44 | }
45 | 
46 | void HttpServerPage::onEndOfHeader() {
47 |   DEBUG(Serial.println("onEndOfHeader(...)"));
48 |   c->stop();
49 | }
50 | 
51 | int HttpServerPage::onData(char *str, int size) {
52 |   DEBUG(Serial.print("onData(\""));
53 |   DEBUG(Serial.write(str,size));
54 |   DEBUG(Serial.print("\","));
55 |   DEBUG(Serial.print(size));
56 |   DEBUG(Serial.println(")"));
57 |   return size;
58 | }
59 | 
60 | void HttpServerPage::onClose() {
61 |   DEBUG(Serial.println("onClose()"));
62 | }
63 | 
64 | // This is to enforce arduino-like formatting in kate
65 | // kate: space-indent on; indent-width 2; mixed-indent off; indent-mode cstyle;
66 | 


--------------------------------------------------------------------------------
/arduino_libs/httpd/httpServerPage.h:
--------------------------------------------------------------------------------
 1 | /**************************************************************************
 2 |  * (C)2015 Lucas V. Hartmann                        *
 3 |  *                                                                        *
 4 |  * This program is free software: you can redistribute it and/or modify   *
 5 |  * it under the terms of the GNU General Public License as published by   *
 6 |  * the Free Software Foundation, either version 3 of the License, or      *
 7 |  * (at your option) any later version.                                    *
 8 |  *                                                                        *
 9 |  * This program is distributed in the hope that it will be useful,        *
10 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of         *
11 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
12 |  * GNU General Public License for more details.                           *
13 |  *                                                                        *
14 |  * You should have received a copy of the GNU General Public License      *
15 |  * along with this program.  If not, see .  *
16 |  *************************************************************************/
17 | 
18 | #ifndef HTTPSERVERPAGE_H
19 | #define HTTPSERVERPAGE_H
20 | 
21 | #include 
22 | 
23 | // Http Server metapage
24 | 
25 | struct HttpServerPage {
26 |   WiFiClient *c;
27 |   virtual void onConnect(WiFiClient &client, const char *sub, const char *hash);
28 |   virtual void onQueryVar(char *var, char *value);
29 |   virtual void onHeader(char *str);
30 |   virtual void onEndOfHeader();
31 |   virtual int onData(char *str, int size);
32 |   virtual void onClose();
33 | };
34 | 
35 | #endif // HTTPSERVERPAGE_H
36 | 
37 | // This is to enforce arduino-like formatting in kate
38 | // kate: space-indent on; indent-width 2; mixed-indent off; indent-mode cstyle;
39 | 


--------------------------------------------------------------------------------
/c2_prog_wifi.ino:
--------------------------------------------------------------------------------
  1 | #include 
  2 | #include 
  3 | #include 
  4 | #ifdef ARDUINO_ARCH_ESP32
  5 | #include 
  6 | #include 
  7 | #else
  8 | #include 
  9 | #include 
 10 | #endif
 11 | #include 
 12 | #include 
 13 | #include "serialServer.h"
 14 | #include "ihx.h"
 15 | 
 16 | #define WIFI_NAME     ""
 17 | #define WIFI_PASSWORD ""
 18 | 
 19 | const char *c2_print_status_by_name(uint8_t ch) {
 20 |   switch (ch) {
 21 |     case C2_SUCCESS:       return "Success";
 22 |     case C2_SHIFT_TIMEOUT: return "Shift wait timeout error";
 23 |     case C2_POLL_TIMEOUT:  return "Register poll timeout error";
 24 |     case C2_CMD_ERROR:     return "In-command error";
 25 |     case C2_BROKEN_LINK:   return "Broken link, address read failed";
 26 |     default:               return "unknown error";
 27 |   }
 28 | }
 29 | 
 30 | //////////////////////
 31 | // Hello World Page //
 32 | //////////////////////
 33 | class HelloWorldPage : public HttpServerPage {
 34 |     void onEndOfHeader() {
 35 |       c->write(""
 36 |                ""
 37 |                ""
 38 |                "
" 39 | "Select image to upload:" 40 | "" 41 | "" 42 | "
" 43 | "" 44 | ""); 45 | c->stop(); 46 | } 47 | } helloWorldPage; 48 | 49 | ////////////////////// 50 | // Error Page // 51 | ////////////////////// 52 | class ErrorPage : public HttpServerPage { 53 | void onEndOfHeader() { 54 | c->write("HTTP/1.1 404 Not Found\r\n\r\n"); 55 | c->write("

Page Not Found.

"); 56 | c->stop(); 57 | } 58 | } errorPage; 59 | 60 | class EchoPage : public HttpServerPage { 61 | bool headerprinted; 62 | void onConnect(WiFiClient &client, const char *sub, const char *hash) { 63 | HttpServerPage::onConnect(client,sub,hash); 64 | c->print("HTTP/1.1 200 OK\r\n"); 65 | c->print("Content-Type: text/html\r\n\r\n"); 66 | c->print("Subpath: "); 67 | c->print("sub"); 68 | c->print("Hash tag: "); 69 | c->println(hash); 70 | headerprinted = false; 71 | } 72 | void onQueryVar(char *var, char *value) { 73 | HttpServerPage::onQueryVar(var, value); 74 | c->print(var); 75 | c->print(" = "); 76 | c->print(value); 77 | c->print("
"); 78 | } 79 | void onHeader(char *str) { 80 | HttpServerPage::onHeader(str); 81 | if (!headerprinted) c->print("

Echo Page

Headers:

");
 82 |       headerprinted = true;
 83 |       c->println(str);
 84 |     }
 85 |     void onEndOfHeader() {
 86 |       //      HttpServerPage::onEndOfHeader();
 87 |       c->print("

Body

");
 88 |     }
 89 |     int onData(char *buff, int count) {
 90 |       HttpServerPage::onData(buff, count);
 91 |       c->println(buff);
 92 |       return count;
 93 |     }
 94 | } echoPage;
 95 | 
 96 | //////////////////////
 97 | // Upload Page      //
 98 | //////////////////////
 99 | class UploadPage : public HttpServerPage {
100 |     bool headerprinted;
101 |     uint8_t devid;
102 |     uint8_t revid;
103 |     void onConnect(WiFiClient &client, const char *sub, const char *hash) {
104 |       HttpServerPage::onConnect(client,sub,hash);
105 |       c->print("HTTP/1.1 200 OK\r\n");
106 |       c->print("Content-Type: text/html, charset=utf8\r\n\r\n");
107 |       c->println("

Lucas Hartmann's EFM8BB1 HTTP Programmer

"); 108 | headerprinted = false; 109 | } 110 | void onEndOfHeader() { 111 | uint8_t err; 112 | c->print("
Enable programming mode: ");
113 |       err = c2_programming_init(C2_DEVID_UNKNOWN);
114 |       c->println(c2_print_status_by_name(err));
115 |       if (err != C2_SUCCESS) {
116 |         c->stop();
117 |         return;
118 |       }
119 | 
120 |       c->print("Device ID: ");
121 |       err = c2_programming_init(C2_DEVID_UNKNOWN);
122 |       c2_address_write(C2DEVID);
123 |       err = c2_data_read(devid, 1);
124 |       if (err != C2_SUCCESS) {
125 |         c->println(c2_print_status_by_name(err));
126 |         c->stop();
127 |         return;
128 |       }
129 |       c->print  ("0x");
130 |       c->println(devid, HEX);
131 | 
132 |       c->print("Revision ID: ");
133 |       err = c2_programming_init(C2_DEVID_UNKNOWN);
134 |       c2_address_write(C2REVID);
135 |       err = c2_data_read(revid, 1);
136 |       if (err != C2_SUCCESS) {
137 |         c->println(c2_print_status_by_name(err));
138 |         c->stop();
139 |         return;
140 |       }
141 |       c->print  ("0x");
142 |       c->println(revid, HEX);
143 | 
144 |       c->print("Erase flash: ");
145 |       err = c2_programming_init(devid);
146 |       err = c2_device_erase();
147 |       c->println(c2_print_status_by_name(err));
148 |       if (err != C2_SUCCESS) {
149 |         c->stop();
150 |         return;
151 |       }
152 |     }
153 |     int onData(char *buff, int count) {
154 |       HttpServerPage::onData(buff, count);
155 | 
156 |       uint8_t err = ihx_decode((uint8_t*)buff);
157 |       if (err != IHX_SUCCESS) return count;
158 | 
159 |       ihx_t *h = (ihx_t*)buff;
160 |       uint16_t address = h->address_high * 0x100 + h->address_low;
161 | /*      c->print("Packet: type[");
162 |       c->print(h->record_type, HEX);
163 |       c->print("] address[");
164 |       c->print(address, HEX);
165 |       c->print("] len[");
166 |       c->print(h->len, HEX);
167 |       c->println("]"); */
168 | 
169 |       // Write data records
170 |       if (h->record_type == IHX_RT_DATA) {
171 |         c->print  ("Programming 0x");
172 |         c->print  (address, HEX);
173 |         c->print  (": ");
174 |         int retries = 5;
175 |         do {
176 |           err = c2_programming_init(devid);
177 |           err = c2_block_write(address, h->data, h->len);
178 |         } while (err != C2_SUCCESS && retries--);
179 |         c->println(c2_print_status_by_name(err));
180 |       }
181 | 
182 |       // Reset on end-of-file
183 |       if (h->record_type == IHX_RT_END_OF_FILE) {
184 |         c->println("End of file, resetting target.");
185 |         err = c2_reset();
186 |         c->println(c2_print_status_by_name(err));
187 |         c->stop();
188 |       }
189 | 
190 |       return count;
191 |     }
192 | } uploadPage;
193 | 
194 | HttpServer::PageMap pageMap[] = {
195 |   { "/", &helloWorldPage },
196 |   { "/upload", &uploadPage },
197 |   { "/echo", &echoPage },
198 |   { 0, &errorPage } // End of list and Page-Not-Found handler
199 | };
200 | 
201 | // Looper
202 | uint8_t i, ch;
203 | 
204 | // Servers
205 | HttpServer httpServer(pageMap);
206 | 
207 | class EFM8HttpBurner_t {
208 |     // Intel Hex data buffer
209 |     union {
210 |       uint8_t b[256];
211 |       ihx_t h;
212 |     } buff;
213 | };
214 | 
215 | // Setup
216 | MDNSResponder mdns;
217 | 
218 | void setup() {
219 |   // put your setup code here, to run once:
220 |   pinMode(PIN_C2CK, OUTPUT);
221 |   pinMode(PIN_C2D,  INPUT);
222 | 
223 |   Serial.begin(115200);
224 | 
225 |   // Wifi Setup
226 |   WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
227 | }
228 | 
229 | bool online = false;
230 | void loop() {
231 |   if (WiFi.status() != WL_CONNECTED) {
232 |     if (online) {
233 |       httpServer.stop();
234 |       //      serialServer.stop();
235 |       online = false;
236 |     }
237 |   } else {
238 |     if (!online) {
239 |       httpServer.begin();
240 |       //      serialServer.begin(115200);
241 |       online = true;
242 | #ifdef ARDUINO_ARCH_ESP32
243 |       mdns.begin("esp32");
244 | #else
245 |       mdns.begin("esp8266", WiFi.localIP(), 5*60);
246 | #endif
247 |     }
248 |     httpServer.loop();
249 |     serialServer.loop();
250 | #ifndef ARDUINO_ARCH_ESP32
251 |     mdns.update();
252 | #endif
253 |   }
254 | }
255 | 
256 | // This is to enforce arduino-like formatting in kate
257 | // kate: space-indent on; indent-width 2; mixed-indent off; indent-mode cstyle;
258 | 


--------------------------------------------------------------------------------
/ihx.cpp:
--------------------------------------------------------------------------------
 1 | #include "ihx.h"
 2 | #include 
 3 | 
 4 | static const char *conv = "0123456789ABCDEFabcdef";
 5 | static uint8_t value_of_hex(uint8_t ch) {
 6 |   uint8_t i = 0;
 7 |   while (conv[i] && ch != conv[i]) i++;
 8 | 
 9 |   if (!conv[i]) return 0;
10 |   if (i >= 16) return i - 6; // lowercase
11 |   return i;
12 | }
13 | 
14 | uint8_t ihx_decode(uint8_t *buff) {
15 |   // Make sure the line looks like intel
16 |   if (buff[0] != ':') {
17 |     Serial.println("IHX: Bad start");
18 |     return IHX_ERROR; // Bad start
19 |   }
20 | 
21 |   // Get buffer length
22 |   uint8_t slen = strlen((char*)buff);
23 | 
24 |   // Remove strayline terminators
25 |   while (buff[slen - 1] == '\n' || buff[slen - 1] == '\r') slen--;
26 | 
27 |   // Length must be odd: start followed by hex pairs
28 |   if (slen < 11) {
29 |     Serial.println("IHX: Short read");
30 |     return IHX_ERROR;
31 |   }
32 |   if (slen % 2 != 1) {
33 |     Serial.println("IHX: Length not odd");
34 |     return IHX_ERROR;
35 |   }
36 | 
37 |   // Decode
38 |   uint8_t cs = 0;
39 |   for (int i = 0; i < (slen - 1) / 2; ++i) {
40 |     buff[i] =
41 |       (value_of_hex(buff[2 * i + 1]) << 4) |
42 |       value_of_hex(buff[2 * i + 2])       ;
43 |     cs += buff[i];
44 |   }
45 | 
46 |   // Validate checksum
47 |   if (cs) {
48 |     Serial.println("IHX: Bad checksum");
49 |     return IHX_ERROR;
50 |   }
51 | 
52 |   // Check is lengths match
53 |   if (buff[0] * 2 + 11 != slen) {
54 |     Serial.println("IHX: Length mismatch");
55 |     return IHX_ERROR;
56 |   }
57 | 
58 |   return IHX_SUCCESS;
59 | }
60 | 


--------------------------------------------------------------------------------
/ihx.h:
--------------------------------------------------------------------------------
 1 | #ifndef IHX_H
 2 | #define IHX_H
 3 | 
 4 | #include 
 5 | 
 6 | // Decoded
 7 | // Intel HEX file format:
 8 | // 1B - Start ':'
 9 | // 2B - data bytes
10 | // 4B - address
11 | // 2B - record type
12 | // ?B - data
13 | // 2B - checksum
14 | 
15 | // 01234567890123
16 | // :NNAAAATTDDSS
17 | struct ihx_t {
18 |   uint8_t  len;
19 |   uint8_t  address_high;
20 |   uint8_t  address_low;
21 |   uint8_t  record_type; // See IHX_RT_* below
22 |   uint8_t  data[];
23 | };
24 | #define IHX_RT_DATA                     0x00
25 | #define IHX_RT_END_OF_FILE              0x01
26 | #define IHX_RT_EXTENDED_SEGMENT_ADDRESS 0x02
27 | #define IHX_RT_START_SEGMENT_ADDRESS    0x03
28 | #define IHX_RT_EXTENDED_LINEAR_ADDRESS  0x04
29 | #define IHX_RT_START_LINEAR_ADDRESS     0x05
30 | 
31 | #define IHX_SUCCESS 0x00
32 | #define IHX_ERROR   0xFF
33 | 
34 | extern uint8_t ihx_decode(uint8_t *buff);
35 | 
36 | #endif // IHX_H
37 | 
38 | // This is to enforce arduino-like formatting in kate
39 | // kate: space-indent on; indent-width 2; mixed-indent off; indent-mode cstyle;
40 | 


--------------------------------------------------------------------------------
/platformio.ini:
--------------------------------------------------------------------------------
 1 | ; PlatformIO Project Configuration File
 2 | ;
 3 | ;   Build options: build flags, source filter
 4 | ;   Upload options: custom upload port, speed and extra flags
 5 | ;   Library options: dependencies, extra library storages
 6 | ;   Advanced options: extra scripting
 7 | ;
 8 | ; Please visit documentation for the other options and examples
 9 | ; https://docs.platformio.org/page/projectconf.html
10 | [platformio]
11 | src_dir = .
12 | lib_dir = arduino_libs
13 | 
14 | [env:esp8266]
15 | platform = espressif8266
16 | board = esp01
17 | framework = arduino
18 | 
19 | [env:esp32]
20 | build_flags = -fpermissive
21 | platform = espressif32
22 | board = esp32doit-devkit-v1
23 | framework = arduino
24 | 


--------------------------------------------------------------------------------
/serialServer.h:
--------------------------------------------------------------------------------
 1 | #ifndef SERIALSERVER_H
 2 | #define SERIALSERVER_H
 3 | 
 4 | #include 
 5 | #ifdef ARDUINO_ARCH_ESP32
 6 | #include 
 7 | #else
 8 | #include 
 9 | #endif
10 | #include 
11 | 
12 | struct SerialServer {
13 | 	WiFiServer s;
14 | 	WiFiClient c;
15 | 	
16 | 	SerialServer(int port) : s(port) {};
17 | 	
18 | 	void begin(int baud);
19 | 	void stop();
20 | 	void loop();
21 | 	
22 | } serialServer(9600);
23 | 
24 | void SerialServer::begin(int baud) {
25 | 	s.begin();
26 | 	Serial.begin(baud);
27 | }
28 | 
29 | void SerialServer::stop() {
30 | 	c.stop();
31 | //	s.end();
32 | 	Serial.end();
33 | }
34 | 
35 | void SerialServer::loop() {
36 | 	// Handle disconnects
37 | 	if (!c.connected()) {
38 | 		c.stop();
39 | 	}
40 | 	
41 | 	// Accept incoming connections
42 | 	if (!c) {
43 | 		c = s.available();
44 | 	}
45 | 	
46 | 	// Handle communicatons
47 | 	if (c) {
48 | 		size_t bytes;
49 | 		int maxbytes = 128;
50 | 		uint8_t buff[maxbytes];
51 | 
52 | 		// Network to serial
53 | 		bytes = c.available();
54 | 		if (bytes) {
55 | 			if (bytes > maxbytes) bytes = maxbytes;
56 | 			c.read(buff, bytes);
57 | 			Serial.write(buff, bytes);
58 | 			Serial.write((char*)0, 0);
59 | 		}
60 | 
61 | 		// Serial to network
62 | 		bytes = 0;
63 | 		while (Serial.available() && bytes < maxbytes) {
64 | 			buff[bytes++] = Serial.read();
65 | 		}
66 | 		c.write(buff,bytes);
67 | 	}
68 | }
69 | 
70 | #endif
71 | 
72 | // This is to enforce arduino-like formatting in kate
73 | // kate: space-indent on; indent-width 2; mixed-indent off; indent-mode cstyle;
74 | 


--------------------------------------------------------------------------------