commit 93a34e291843c7debd24eabf6bfe48d9170867a5 Author: Dirk Jahnke Date: Fri Jan 25 13:14:52 2019 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..addf833 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.pio +.pioenvs +.piolibdeps +.clang_complete +.gcc-flags.json +firmware.bin diff --git a/include/README b/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..efbba14 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,24 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:d1_mini] +platform = espressif8266 +board = d1_mini +framework = arduino + +lib_deps = + # Using a library name + MD_Parola + MD_MAX72XX + IOTAppStory-ESP + NTPClient + +upload_port = /dev/cu.wchusbserial1420 +upload_speed = 921600 diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..b6c42c2 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,373 @@ +/* Wemos8266RelaysLedDisplay/main.cpp + */ + +#define COMPDATE __DATE__ __TIME__ +// Button pin on the esp for selecting modes. 0 for Generic devices! +#define MODEBUTTON D3 + +#define RELAY1_PIN D1 +#define RELAY2_PIN D2 +#define DISPLAY_CLK_PIN D5 +#define DISPLAY_DATA_PIN D7 +#define DISPLAY_CS_PIN D6 +#define VERTICAL_BAR_STARTS_TOP false +#define DEBUG_RELAYS false + +#include +#include +#include +#include +#include +#include +#include +#include + + +IOTAppStory IAS(COMPDATE, MODEBUTTON); +String deviceName = "wemosMatrixDisplay"; +String chipId; +const uint16_t WAIT_TIME = 1000; + +// Define the number of devices we have in the chain and the hardware interface +// NOTE: These pin numbers will probably not work with your hardware and may +// need to be adapted + +/* Mapper result, connector to ESP is at right (backside): +Your responses produce these hardware parameters + +HW_DIG_ROWS 1 +HW_REV_COLS 0 +HW_REV_ROWS 0 + +Your hardware matches the setting for FC-16 modules. Please set FC16_HW. + +*/ + +#define HARDWARE_TYPE MD_MAX72XX::FC16_HW +#define MAX_DEVICES 4 +#define CLK_PIN DISPLAY_CLK_PIN +#define DATA_PIN DISPLAY_DATA_PIN +#define CS_PIN DISPLAY_CS_PIN + +// Hardware SPI connection +// MD_Parola P = MD_Parola(HARDWARE_TYPE, DISPLAY_CS_PIN, MAX_DEVICES); +// Arbitrary output pins +MD_Parola P = MD_Parola(HARDWARE_TYPE, DISPLAY_DATA_PIN, DISPLAY_CLK_PIN, DISPLAY_CS_PIN, MAX_DEVICES); + +WiFiUDP ntpUDP; +NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000); + +// Field default values +char *clockName = "FastClk "; +char *clockSpeed_modelMsPerRealSec_String = "250"; +int clockSpeed_modelMsPerRealSec = 250; +char *relay1Pin_String = "D1"; +char *relay2Pin_String = "D2"; +int relay1Pin = D1, relay2Pin = D2; +char *relayHoldTime_ms_String = "200"; +int relayHoldTime_ms = 200; +char *relayMinOffTime_ms_String = "100"; +int relayMinOffTime_ms = 100; + + +void setupIAS(void) { + #if defined ESP8266 + // creat a unique deviceName for classroom situations (deviceName-123) + chipId = String(ESP.getChipId()); + chipId = "-"+chipId.substring(chipId.length()-3); + deviceName += chipId; + #endif + + // preset deviceName this is also your MDNS responder: http://deviceName.local + IAS.preSetDeviceName(deviceName); + IAS.preSetAppName(F("Wemos2RelaysMatrixDisplays")); + IAS.preSetAppVersion(F("0.0.1")); + IAS.preSetAutoUpdate(true); + + // define fields + IAS.addField(clockName, "Clock Name", 8, 'T'); + IAS.addField(clockSpeed_modelMsPerRealSec_String, "Model MilliSec per Real Sec", 8, 'N'); + IAS.addField(relay1Pin_String, "Pin Relay 1", 2, 'P'); + IAS.addField(relay2Pin_String, "Pin Relay 2", 2, 'P'); + IAS.addField(relayHoldTime_ms_String, "Relay hold time (ms)", 3, 'N'); + IAS.addField(relayMinOffTime_ms_String, "Relay min off time (ms)", 3, 'N'); + + IAS.onModeButtonShortPress([]() { + Serial.println(F(" If mode button is released, I will enter in firmware update mode.")); + Serial.println(F("*-------------------------------------------------------------------------*")); + P.print("|updt"); + }); + + IAS.onModeButtonLongPress([]() { + Serial.println(F(" If mode button is released, I will enter in configuration mode.")); + Serial.println(F("*-------------------------------------------------------------------------*")); + P.print("|cfg"); + }); + + IAS.onFirstBoot([]() { + Serial.println(F(" Manual reset necessary after serial upload!")); + Serial.println(F("*-------------------------------------------------------------------------*")); + P.print("|rst"); + ESP.reset(); + }); + + IAS.onConfigMode([]() { + P.print("WiFi"); + delay(400); + P.print("*" + chipId); + Serial.print(F("Entered config mode for Wifi, device=")); Serial.println(chipId); + }); + + IAS.onFirmwareUpdateCheck([]() { + P.print("chk upd"); + Serial.println(F("Firmware update check")); + }); + + IAS.onFirmwareUpdateDownload([]() { + P.print("dl&instl"); + Serial.println(F("Download and install new firmware")); + }); + + IAS.onFirmwareUpdateError([]() { + P.print("Err fwu"); + Serial.println(F("Firmware update error")); + }); + + // Optional parameter: What to do with EEPROM on First boot of the app? + // 'F' Fully erase | 'P' Partial erase(default) | 'L' Leave intact + IAS.begin('L'); + delay(500); + // Set to true to enable calling home frequently (disabled by default) + IAS.setCallHome(true); + // Call home interval in seconds, use 60s only for development. + // Please change it to at least 2 hours in production + IAS.setCallHomeInterval(120); + //IAS.callHome(false /*SPIFFS-check*/); + clockSpeed_modelMsPerRealSec = atoi(clockSpeed_modelMsPerRealSec_String); + relay1Pin = IAS.dPinConv(relay1Pin_String); + relay2Pin = IAS.dPinConv(relay2Pin_String); + relayHoldTime_ms = atoi(relayHoldTime_ms_String); + relayMinOffTime_ms = atoi(relayMinOffTime_ms_String); + + Serial.println(F("Configuration used:")); + Serial.print(F("Relay1 Pin: ")); Serial.println(relay1Pin); + Serial.print(F("Relay2 Pin: ")); Serial.println(relay2Pin); + Serial.print(F("Clock speed: ")); Serial.print(clockSpeed_modelMsPerRealSec); Serial.println(F(" model ms per real sec")); + Serial.print(F("Relay hold time (ms): ")); Serial.println(relayHoldTime_ms); + Serial.print(F("Relay min off time (ms): ")); Serial.println(relayMinOffTime_ms); +} + +void setupRelays(int relay1Pin, int relay2Pin) { + pinMode(relay1Pin, OUTPUT); + pinMode(relay2Pin, OUTPUT); + digitalWrite(relay1Pin, LOW); + digitalWrite(relay2Pin, LOW); +} + +void setupDisplay() { + int charCode; +#if VERTICAL_BAR_STARTS_TOP + static uint8_t verticalBarFont[] = { + 1, 0x00, /* blank */ + 1, 0x01, /* 1 dot */ + 1, 0x03, /* 2 dots */ + 1, 0x07, + 1, 0x0f, + 1, 0x1f, + 1, 0x3f, + 1, 0x7f, + 1, 0xff, /* vertical bar completely set */ + }; // columns from right to left, each byte is a single column +#else + static uint8_t verticalBarFont[] = { + 1, 0x00, /* blank */ + 1, 0x80, /* 1 dot */ + 1, 0xc0, /* 2 dots */ + 1, 0xe0, + 1, 0xf0, + 1, 0xf8, + 1, 0xfc, + 1, 0xfe, + 1, 0xff, /* vertical bar completely set */ + }; // columns from right to left, each byte is a single column +#endif + + P.begin(); + // P.setZoneEffect(0, true, PA_FLIP_LR); + P.setIntensity(1); + for (charCode=1; charCode<=8; ++charCode) { + P.addChar(charCode, verticalBarFont+2*(charCode-1)); + } + char intro[] = {':', '-', ')', ' ', 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00}; + P.print(intro); +} +void setup(void) +{ + Serial.println(F("setup():")); + setupDisplay(); + setupIAS(); + delay(500); + setupRelays(relay1Pin, relay2Pin); + delay(500); + + timeClient.begin(); + Serial.println(F("setup() finished")); +} + + +static bool timeClientInitialized = false; +static unsigned long lastTimeOutput_ms = 0; +#define TIME_BETWEEN_TIME_REPORTS_ms 60000 + +static unsigned long last_relay_off_ts=0, last_relay_hold_ts=0; +enum RelayState { RELAY_STATE_OFF=0, RELAY_STATE_ON_EVEN_MINUTE, RELAY_STATE_ON_ODD_MINUTE }; +static RelayState relaysState = RELAY_STATE_OFF; +static RelayState lastRelayOnState = RELAY_STATE_ON_EVEN_MINUTE; +static bool relayCanSwitch=true; + +void toggleRelays() { + if (relayCanSwitch) { + if (lastRelayOnState == RELAY_STATE_ON_EVEN_MINUTE) { + digitalWrite(relay1Pin, HIGH); + digitalWrite(relay2Pin, LOW); + relaysState = RELAY_STATE_ON_ODD_MINUTE; + // P.print("R-OEv"); + } else { + digitalWrite(relay1Pin, LOW); + digitalWrite(relay2Pin, HIGH); + relaysState = RELAY_STATE_ON_EVEN_MINUTE; + // P.print("R-OOd"); + } + lastRelayOnState = relaysState; + } // else P.print("R-OErr"); + relayCanSwitch = false; + last_relay_hold_ts = millis(); + Serial.println(F("Toggle Relays")); +} + +void relaysOff(void) { + digitalWrite(relay1Pin, LOW); + digitalWrite(relay2Pin, LOW); + last_relay_off_ts = millis(); + relaysState = RELAY_STATE_OFF; + // P.print("R-Off"); +} + +void loopRelays(void) { + if (relaysState == RELAY_STATE_OFF) { + if (millis() - last_relay_off_ts > relayMinOffTime_ms) { + relayCanSwitch = true; + } + } else { + if (millis() - last_relay_hold_ts > relayHoldTime_ms) { + relaysOff(); + } + } +} + + +void loop(void) +{ + int currentDisplayState; + int hours, minutes, seconds; + char minuteProgressIndicator; + static int lastMinutes = 0; + static int lastSeconds = 0; + static char timeBuffer[10]; + #define MsgSize 10 + static char debugMsg[MsgSize+1]; + static int recentDisplayState = -1; + + if (!timeClientInitialized && WiFi.status() == WL_CONNECTED) { + timeClient.begin(); + timeClientInitialized = true; + } + IAS.loop(); + + if (timeClientInitialized && millis()-lastTimeOutput_ms > TIME_BETWEEN_TIME_REPORTS_ms) { + timeClient.update(); + Serial.println(timeClient.getFormattedTime()); + lastTimeOutput_ms = millis(); + } + + if (timeClientInitialized) { + hours = timeClient.getHours(); + minutes = timeClient.getMinutes(); + seconds = timeClient.getSeconds(); + } else { + hours = (millis() / 60 * 60 * 1000) % 24; + minutes = (millis() / 60 * 1000) % 60; + seconds = (millis() / 1000) % 60; + } + minuteProgressIndicator = seconds/7.5 + 1; // char code 1-8 show vertical bar + snprintf(timeBuffer, 10, "%c %02d:%02d", minuteProgressIndicator, hours, minutes); + + /* DEBUG */ + #if DEBUG_RELAYS + if (seconds != lastSeconds) { + switch (seconds % 4) { + case 0: + digitalWrite(relay1Pin, HIGH); + break; + case 1: + digitalWrite(relay1Pin, LOW); + break; + case 2: + digitalWrite(relay2Pin, HIGH); + break; + case 3: + digitalWrite(relay2Pin, LOW); + break; + } + Serial.print("Rel dbg: "); Serial.println(seconds, HEX); + delay(5); + } + #endif + /* END DEBUG */ + + currentDisplayState = seconds / 5; // Value 0..11 + + static bool executed = false; + if (recentDisplayState != currentDisplayState) executed = false; + + #define ExecOnce(p) {if (!executed) {executed=true; p;}} + + switch (currentDisplayState) { + case 0: ExecOnce(P.print(timeBuffer)); break; + case 1: + snprintf(debugMsg, MsgSize, "%c t%cr%c", minuteProgressIndicator, timeClientInitialized ? 'x':'-', (relaysState == RELAY_STATE_OFF)?'-':(relaysState == RELAY_STATE_ON_EVEN_MINUTE?'e':'o')); + ExecOnce(P.print(debugMsg)); + break; + case 2: ExecOnce(P.print(timeBuffer)); break; + case 3: // if (lastSeconds != seconds) P.print(seconds); break; + case 4: ExecOnce(P.print(timeBuffer)); break; + case 5: ExecOnce(P.print(timeBuffer)); break; + case 6: + switch (minutes % 3) { + case 0: snprintf(debugMsg, MsgSize, "%c s%d", minuteProgressIndicator, clockSpeed_modelMsPerRealSec); break; + case 1: snprintf(debugMsg, MsgSize, "%c h%d", minuteProgressIndicator, relayHoldTime_ms); break; + case 2: snprintf(debugMsg, MsgSize, "%c o%d", minuteProgressIndicator, relayMinOffTime_ms); break; + } + ExecOnce(P.print(debugMsg)); + break; + case 7: ExecOnce(P.print(timeBuffer)); break; + case 8: + /*snprintf(debugMsg, MsgSize, "t%cr%c", timeClientInitialized ? 'x':'-', (relaysState == RELAY_STATE_OFF)?'-':(relaysState == RELAY_STATE_ON_EVEN_MINUTE?'e':'o')); + ExecOnce(P.print(debugMsg)); + break;*/ + case 9: ExecOnce(P.print(timeBuffer)); break; + case 10: if (lastSeconds != seconds) P.printf("%c %d", minuteProgressIndicator, seconds); break; + case 11: ExecOnce(P.print(timeBuffer)); break; + default: ExecOnce(P.print("default")); break; + } + recentDisplayState = currentDisplayState; + + // toggle relays + if (lastMinutes != minutes) { + toggleRelays(); + lastMinutes = minutes; + } + lastSeconds = seconds; + + loopRelays(); +} diff --git a/src/mapper_main.txt b/src/mapper_main.txt new file mode 100644 index 0000000..5e8bccd --- /dev/null +++ b/src/mapper_main.txt @@ -0,0 +1,236 @@ + + +// Test software to map display hardware rows and columns +// Generic SPI interface and only one MAX72xx/8x8 LED module required +// +// Does not use any libraries as the code is used to directly map the display orientation +// Observe the display and relate it to the MAX7219 hardware being exercised through the +// instructions and output on the serial monitor. +// +// NOTE: You need to change the hardware pins to match your specific setup + +#include +#include + +#define SERIAL_SPEED 115200 +// Hardware definition +#define CLK_PIN D5 // or SCK +#define DATA_PIN D7 // or MOSI +#define CS_PIN D6 // or SS + +// Opcodes for the MAX7221 and MAX7219 +// All OP_DIGITn are offsets from OP_DIGIT0 +#define OP_NOOP 0 ///< MAX72xx opcode for NO OP +#define OP_DIGIT0 1 ///< MAX72xx opcode for DIGIT0 +#define OP_DIGIT1 2 ///< MAX72xx opcode for DIGIT1 +#define OP_DIGIT2 3 ///< MAX72xx opcode for DIGIT2 +#define OP_DIGIT3 4 ///< MAX72xx opcode for DIGIT3 +#define OP_DIGIT4 5 ///< MAX72xx opcode for DIGIT4 +#define OP_DIGIT5 6 ///< MAX72xx opcode for DIGIT5 +#define OP_DIGIT6 7 ///< MAX72xx opcode for DIGIT6 +#define OP_DIGIT7 8 ///< MAX72xx opcode for DIGIT7 +#define OP_DECODEMODE 9 ///< MAX72xx opcode for DECODE MODE +#define OP_INTENSITY 10 ///< MAX72xx opcode for SET INTENSITY +#define OP_SCANLIMIT 11 ///< MAX72xx opcode for SCAN LIMIT +#define OP_SHUTDOWN 12 ///< MAX72xx opcode for SHUT DOWN +#define OP_DISPLAYTEST 15 ///< MAX72xx opcode for DISPLAY TEST + +#define MAX_DIG 8 +#define MAX_SEG 8 + +#define USER_DELAY 1000 // ms + +void spiTransmit(uint8_t opCode, uint8_t data) +{ + // enable the devices to receive data + digitalWrite(CS_PIN, LOW); + + // shift out the data + shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, opCode); + shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, data); + + // latch the data onto the display + digitalWrite(CS_PIN, HIGH); +} + +void instructions(void) +{ + Serial.print(F("\nINTRODUCTION\n------------")); + Serial.print(F("\nHow the LED matrix is wired is important for the MD_MAX72xx library as different")); + Serial.print(F("\nLED modules are wired differently. The library can accommodate these, but it")); + Serial.print(F("\nneeds to know what transformations need to be carried out to map your board to the")); + Serial.print(F("\nstandard coordinate system. This utility shows you how the matrix is wired so that")); + Serial.print(F("\nyou can set the correct *_HW module type for your application.")); + Serial.print(F("\n\nThe standard functions in the library expect that:")); + Serial.print(F("\no COLUMNS are addressed through the SEGMENT selection lines, and")); + Serial.print(F("\no ROWS are addressed through the DIGIT selection lines.")); + Serial.print(F("\n\nThe DISPLAY always has its origin in the top right corner of a display:")); + Serial.print(F("\no LED matrix module numbers increase from right to left,")); + Serial.print(F("\no Column numbers (ie, the hardware segment numbers) increase from right to left (0..7), and ")); + Serial.print(F("\no Row numbers (ie, the hardware digit numbers) increase down (0..7).")); + Serial.print(F("\n\nThere are three hardware setting that describe your hardware configuration:")); + Serial.print(F("\n- HW_DIG_ROWS - HardWare DIGits are ROWS. This will be 1 if the digits map to the rows")); + Serial.print(F("\n of the matrix, 0 otherwise")); + Serial.print(F("\n- HW_REV_COLS - HardWare REVerse COLumnS. The normal column coordinates orientation")); + Serial.print(F("\n is col 0 on the right side of the display. This will be 1 if reversed.")); + Serial.print(F("\n (ie, hardware 0 is on the left).")); + Serial.print(F("\n- HW_REV_ROWS - HardWare REVerse ROWS. The normal row coordinates orientation is row")); + Serial.print(F("\n 0 at top of the display. This will be 1 if reversed (ie, row 0")); + Serial.print(F("\n is at the bottom).")); + Serial.print(F("\n\nThese individual setting then determine the model type of the hardware you are using.")); + Serial.print(F("\n\nINSTRUCTIONS\n------------")); + Serial.print(F("\n1. Wire up one matrix only, or cover up the other modules, to avoid confusion.")); + Serial.print(F("\n2. Enter the answers to the question in the edit field at the top of Serial Monitor.")); +} + +void setup(void) +{ + Serial.begin(SERIAL_SPEED); + Serial.print(F("\n\n[MD_MAX72xx Hardware mapping utility]\n")); + instructions(); + + // Initialize comms hardware + digitalWrite(CS_PIN, HIGH); + pinMode(CS_PIN, OUTPUT); + pinMode(DATA_PIN, OUTPUT); + pinMode(CLK_PIN, OUTPUT); +} + +void initialize(void) +// Initialize the display devices. +// On initial power-up, all control registers are reset, the +// display is blanked, and the MAX7219/MAX7221 enters shutdown +// mode. +{ + spiTransmit(OP_SHUTDOWN, 1); // wake up + spiTransmit(OP_SCANLIMIT, 7); // all on + spiTransmit(OP_INTENSITY, 7); // mid intensity + spiTransmit(OP_DISPLAYTEST, 0); // no test + spiTransmit(OP_DECODEMODE, 0); // no decode +} + +void mapSegment(char *label, uint8_t data) +{ + Serial.print(F("-")); + Serial.print(label); + spiTransmit(OP_DIGIT0, data); + delay(USER_DELAY); +} + +void mapDigit(uint8_t opCode) +{ + Serial.print(F("-")); + Serial.print(opCode - OP_DIGIT0); + spiTransmit(opCode, 0xff); + delay(USER_DELAY); + spiTransmit(opCode, 0x0); +} + +void clear(void) +{ + for (uint8_t i=0; i> Enter Y when you are ready to start: ")); + getResponse("Yy"); + + initialize(); + + Serial.print("\nDig"); + for (uint8_t i=0; i> Enter Y if you saw ROWS animated, N if you saw COLUMNS animated: ")); + def_dig_rows = (getResponse("YyNn") == 'Y'); + + if (def_dig_rows) + Serial.print(F("\n>> Enter Y if you saw the line moving BOTTOM to TOP, or enter N otherwise: ")); + else + Serial.print(F("\n>> Enter Y if you saw the line moving LEFT to RIGHT, or enter N otherwise: ")); + def_rev_rows = (getResponse("YyNn") == 'Y'); + + Serial.print(F("\n\nSTEP 2 - SEGMENT MAPPING (columns)\n----------------------------------")); + Serial.print(F("\nIn this step you will see a dot moving along one edge of the LED matrix.")); + Serial.print(F("\nYou need to observe the direction it is moving.")); + Serial.print(F("\n>> Enter Y when you are ready to start: ")); + getResponse ("Yy"); + + Serial.print(F("\nSeg")); + mapSegment("G", 1); + mapSegment("F", 2); + mapSegment("E", 4); + mapSegment("D", 8); + mapSegment("C", 16); + mapSegment("B", 32); + mapSegment("A", 64); + mapSegment("DP", 128); + + clear(); + + if (def_dig_rows) + Serial.print(F("\n>> Enter Y if you saw the LED moving LEFT to RIGHT, or enter N otherwise: ")); + else + Serial.print(F("\n>> Enter Y if you saw the LED moving BOTTOM to TOP, or enter N otherwise: ")); + def_rev_cols = (getResponse("YyNn") == 'Y'); + + Serial.print(F("\n\nSTEP 3 - RESULTS\n----------------")); + Serial.print(F("\nYour responses produce these hardware parameters\n")); + Serial.print(F("\nHW_DIG_ROWS\t")); Serial.print(def_dig_rows ? 1 : 0 ); + Serial.print(F("\nHW_REV_COLS\t")); Serial.print(def_rev_cols ? 1 : 0 ); + Serial.print(F("\nHW_REV_ROWS\t")); Serial.print(def_rev_rows ? 1 : 0 ); + + Serial.print(F("\n\nYour hardware matches the setting for ")); + if (def_dig_rows && def_rev_cols && !def_rev_rows) + Serial.print(F("Parola modules. Please set PAROLA_HW.")); + else if (!def_dig_rows && def_rev_cols && !def_rev_rows) + Serial.print(F("Generic modules. Please set GENERIC_HW.")); + else if (def_dig_rows && def_rev_cols && def_rev_rows) + Serial.print(F("IC Station modules. Please set ICSTATION_HW.")); + else if (def_dig_rows && !def_rev_cols && !def_rev_rows) + Serial.print(F("FC-16 modules. Please set FC16_HW.")); + else + { + Serial.print(F("none of the preconfigured module types.")); + Serial.print(F("\nYou should try rotating the matrix by 180 degrees and re-running this utility.")); + Serial.print(F("\n\nIf that still fails to provide a solution - congratulations! You have discovered")); + Serial.print(F("\na new type of hardware module! Please contact the author of the libraries so that")); + Serial.print(F("\nthese can be included in the next official release.")); + } +} diff --git a/test/README b/test/README new file mode 100644 index 0000000..df5066e --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html