diff --git a/.github/.gitignore b/.github/.gitignore deleted file mode 100644 index 8b13789..0000000 --- a/.github/.gitignore +++ /dev/null @@ -1 +0,0 @@ - diff --git a/.github/actions/avr_setup/action.yml b/.github/actions/avr_setup/action.yml new file mode 100644 index 0000000..3b92db0 --- /dev/null +++ b/.github/actions/avr_setup/action.yml @@ -0,0 +1,18 @@ +name: "Get changed files list" +description: "Setup Node with caching for dependencies" +runs: + using: "composite" + steps: + - name: Set up Arduino CLI + uses: arduino/setup-arduino-cli@v2 + + - name: Install platform + run: | + arduino-cli core update-index + arduino-cli core install ${{ env.platform }} + shell: bash + + - name: Install popular libs + run: | + arduino-cli lib install LiquidCrystal + shell: bash \ No newline at end of file diff --git a/.github/actions/get_changed_files/action.yml b/.github/actions/get_changed_files/action.yml new file mode 100644 index 0000000..ecf73ac --- /dev/null +++ b/.github/actions/get_changed_files/action.yml @@ -0,0 +1,13 @@ +name: "Get changed files list" +description: "Setup Node with caching for dependencies" +runs: + using: "composite" + steps: + - name: Get changed files list + id: get_changed_files + run: | + echo "Changed files:" + git diff --name-only ${{ github.event.pull_request.base.sha }} > changed_files.txt + cat changed_files.txt + echo "The list is saved to changed_files.txt" + shell: bash \ No newline at end of file diff --git a/.github/workflows/Lab_01_CI.yml b/.github/workflows/Lab_01_CI.yml deleted file mode 100644 index 985573b..0000000 --- a/.github/workflows/Lab_01_CI.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Cheking of compile Arduino sketch for AVR/AtMega and ESP8266 - -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - -jobs: - test-matrix: - strategy: - matrix: - arduino-platform: - - "arduino:avr" - - "esp8266:esp8266" - include: - - arduino-platform: "arduino:avr" - fqbn: "arduino:avr:mega" - - arduino-platform: "esp8266:esp8266" - fqbn: "esp8266:esp8266:generic" - - runs-on: ubuntu-22.04 - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Arduino CLI - uses: arduino/setup-arduino-cli@v2 - - - name: Install platform - run: | - arduino-cli core update-index - arduino-cli core install ${{ matrix.arduino-platform }} - - - name: Compile Sketch - run: arduino-cli compile --fqbn ${{ matrix.fqbn }} ./mc_labs/mc_lab_01/*.ino diff --git a/.github/workflows/lab-validation.yml b/.github/workflows/lab-validation.yml new file mode 100644 index 0000000..059343b --- /dev/null +++ b/.github/workflows/lab-validation.yml @@ -0,0 +1,114 @@ +name: Cheking of compile Arduino sketch for AVR/AtMega + +on: + pull_request: + branches: [main, master] + +env: + platform: "arduino:avr" + fqbn_master: "arduino:avr:mega" + COMMIT_COUNT: $(( ${{ github.event_name == 'pull_request' && github.event.pull_request.commits || 0 }} + 1 )) + +jobs: + handle_bad_branch_name: + runs-on: ubuntu-22.04 + if: (contains(github.head_ref, 'mc_lab_1') || contains(github.head_ref, 'mc_lab_2') || contains(github.head_ref, 'mc_lab_3') || contains(github.head_ref, 'mc_lab_4') || contains(github.head_ref, 'mc_lab_5') || contains(github.head_ref, 'mc_lab_6') || contains(github.head_ref, 'mc_lab_7')) == false + steps: + - name: Fail the build + run: | + echo "The branch name is not correct. It should contain 'mc_lab_' prefix" + exit 1 + build_labs_1_to_4: + runs-on: ubuntu-22.04 + if: contains(github.head_ref, 'mc_lab_1') || contains(github.head_ref, 'mc_lab_2') || contains(github.head_ref, 'mc_lab_3') || contains(github.head_ref, 'mc_lab_4') + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: ${{ env.COMMIT_COUNT }} + + - name: Get changed files list + uses: ./.github/actions/get_changed_files + + - name: Set up Arduino CLI + uses: ./.github/actions/avr_setup + + - name: Compile Sketch + run: arduino-cli compile --fqbn ${{ env.fqbn_master }} $(grep -E '\.ino$' changed_files.txt | xargs) + build_lab_5: + runs-on: ubuntu-22.04 + if: contains(github.head_ref, 'mc_lab_5') + env: + fqbn_slave: "arduino:avr:nano" + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: ${{ env.COMMIT_COUNT }} + + - name: Get changed files list + uses: ./.github/actions/get_changed_files + + - name: Get master folder + run: | + cat changed_files.txt | xargs dirname | grep 'master' | grep -m 1 -vE '/(.*master.*|.*slave.*)/' > master_project.txt + echo "Master project:" + cat master_project.txt + + - name: Get slave folders + run: | + cat changed_files.txt | xargs dirname | grep 'slave' | grep -vE '/(.*master.*|.*slave.*)/' > slave_projects.txt + echo "Slave projects:" + cat slave_projects.txt + + - name: Check if there is at least one master and one slave project + run: | + if [ ! -s master_project.txt ] || [ ! -s slave_projects.txt ]; then + echo "There is no master or slave project" + exit 1 + fi + + - name: Set up Arduino CLI + uses: ./.github/actions/avr_setup + + - name: Compile master + run: while read master_folder; do arduino-cli compile --fqbn ${{ env.fqbn_master }} $master_folder/*.ino; done < master_project.txt + + - name: Compile slaves + run: while read slave_folder; do arduino-cli compile --fqbn ${{ env.fqbn_slave }} $slave_folder/*.ino; done < slave_projects.txt + build_lab_6: + runs-on: ubuntu-22.04 + if: contains(github.head_ref, 'mc_lab_6') + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: ${{ env.COMMIT_COUNT }} + + - name: It just passes + run: echo "It just passes. It's too complex" + build_lab_7: + runs-on: ubuntu-22.04 + if: contains(github.head_ref, 'mc_lab_7') + env: + register-bindings: "m2560def.inc" + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: ${{ env.COMMIT_COUNT }} + + - name: Get changed files list + uses: ./.github/actions/get_changed_files + + - name: Setup AVRA Assembler + run: | + git clone https://github.com/Ro5bert/avra.git + cd avra + sudo make install + + - name: Preprocess sketch - append register bindings to the top of the file + run: printf ".include \"${{ env.register-bindings }}\"\n\n" | cat - $(grep -m 1 -E '\.(asm|S)$' changed_files.txt | xargs) > pipeline_main_assembly_source_file.asm + + - name: Compile Sketch + run: avra pipeline_main_assembly_source_file.asm diff --git a/mc_labs/mc_lab_03/lab3-mko/keypad4x4.h b/mc_labs/mc_lab_03/lab3-mko/keypad4x4.h new file mode 100644 index 0000000..c8595d3 --- /dev/null +++ b/mc_labs/mc_lab_03/lab3-mko/keypad4x4.h @@ -0,0 +1,184 @@ +#define DDR_KEYPAD DDRK +#define PORT_KEYPAD PORTK +#define PIN_KEYPAD PINK + + +class Keypad { +public: + bool pressed = false; + char d1, d2, d3, d4, dA, dB, dC, dD; + char columns[4]; + char rows[4]; + Keypad(char d1, char d2, char d3, char d4, char dA, char dB, char dC, char dD) + : columns({ d1, d2, d3, d4 }), + rows({ dA, dB, dC, dD }) { + this->d1 = d1; + this->d2 = d2; + this->d3 = d3; + this->d4 = d4; + this->dA = dA; + this->dB = dB; + this->dC = dC; + this->dD = dD; + } + + bool init() { + for (char row : rows) + pinMode(row, OUTPUT); + + + for (char column : columns) + pinMode(column, INPUT); + } + + bool isPressed() { + return pressed; + } + + char readKey() { + char* location = getPressedButtonLocation(); + + if (!pressed) + return '?'; + + delay(200); + return getKeyByLocation(location); + } + +private: + char* getPressedButtonLocation() { + char result[] = { 0, 0 }; + for (char rowToRead : rows) { + for (char row : rows) { + digitalWrite(row, HIGH); + asm("nop"); + } + char activeColumn; + for (char column : columns) { + pressed = digitalRead(column) == HIGH; + if (pressed) + activeColumn = column; + } + + + if (pressed) { + result[0] = rowToRead; + result[1] = activeColumn; + } + } + + return result; + } + + char getKeyByLocation(char location[2]) { + char key = '?'; + if (location[0] == dA && location[2] == d1) key = '7'; + if (location[0] == dB && location[2] == d1) key = '4'; + if (location[0] == dC && location[2] == d1) key = '1'; + if (location[0] == dD && location[2] == d1) key = 'F'; + if (location[0] == dA && location[2] == d2) key = '8'; + if (location[0] == dB && location[2] == d2) key = '5'; + if (location[0] == dC && location[2] == d2) key = '2'; + if (location[0] == dD && location[2] == d2) key = '0'; + if (location[0] == dD && location[2] == d3) key = '9'; + if (location[0] == dA && location[2] == d3) key = '6'; + if (location[0] == dB && location[2] == d3) key = '3'; + if (location[0] == dC && location[2] == d3) key = 'E'; + if (location[0] == dD && location[2] == d4) key = 'A'; + if (location[0] == dA && location[2] == d4) key = 'B'; + if (location[0] == dB && location[2] == d4) key = 'C'; + if (location[0] == dC && location[2] == d4) key = 'D'; + return key; + } +}; + +const int Key_1 = B10111110; +const int Key_2 = B10111101; +const int Key_3 = B10111011; +const int Key_A = B11100111; + +const int Key_4 = B11011110; +const int Key_5 = B11011101; +const int Key_6 = B11011011; +const int Key_B = B11010111; + +const int Key_7 = B11101110; +const int Key_8 = B11101101; +const int Key_9 = B11101011; +const int Key_C = B10110111; + +const int Key_F = B01111110; +const int Key_0 = B01111101; +const int Key_E = B01111011; +const int Key_D = B01110111; + +unsigned char freePinFromKeyPad = 1; +unsigned char keyFromKeyPad = 1; +char pressedButton = 0; +bool logicPressed = false; + +void initKeyPad() { + DDR_KEYPAD = 0x0F; + PORT_KEYPAD = 0xF0; +} + +char readKeyFromPad4x4() { + logicPressed = false; + return pressedButton; +} + +bool isButtonPressed() { + if (freePinFromKeyPad == 1) //перевірка чи була натиснута кнопка + { //якщо =1, тоді ще не натискалася + if (PIN_KEYPAD != 0xF0) { + delay(50); + freePinFromKeyPad = 0; + keyFromKeyPad = 1; + // Визначення натиснутої клавіші + // почергова подача 0V на рядки клавіатури A,B,C,D + PORT_KEYPAD = B11111110; // A-рядок + asm("nop"); + if (PORT_KEYPAD == PIN_KEYPAD) { + PORT_KEYPAD = B11111101; // B-рядок + asm("nop"); + if (PORT_KEYPAD == PIN_KEYPAD) { + PORT_KEYPAD = B11111011; // C-рядок + asm("nop"); + if (PORT_KEYPAD == PIN_KEYPAD) { + PORT_KEYPAD = B11110111; // D-рядок + asm("nop"); + if (PORT_KEYPAD == PIN_KEYPAD) + keyFromKeyPad = 0; // жодна клавіша не натиснута + } + } + } + if (keyFromKeyPad == 1) //визначення натиснутої клавіші + { + if (PIN_KEYPAD == Key_1) pressedButton = '1'; + else if (PIN_KEYPAD == Key_2) pressedButton = '2'; + else if (PIN_KEYPAD == Key_3) pressedButton = '3'; + else if (PIN_KEYPAD == Key_4) pressedButton = '4'; + else if (PIN_KEYPAD == Key_5) pressedButton = '5'; + else if (PIN_KEYPAD == Key_6) pressedButton = '6'; + else if (PIN_KEYPAD == Key_7) pressedButton = '7'; + else if (PIN_KEYPAD == Key_8) pressedButton = '8'; + else if (PIN_KEYPAD == Key_9) pressedButton = '9'; + else if (PIN_KEYPAD == Key_0) pressedButton = '0'; + else if (PIN_KEYPAD == Key_A) pressedButton = 'A'; + else if (PIN_KEYPAD == Key_B) pressedButton = 'B'; + else if (PIN_KEYPAD == Key_C) pressedButton = 'C'; + else if (PIN_KEYPAD == Key_D) pressedButton = 'D'; + else if (PIN_KEYPAD == Key_E) pressedButton = 'E'; + else if (PIN_KEYPAD == Key_F) pressedButton = 'F'; + logicPressed = true; + } + + PORT_KEYPAD = 0xF0; //відновлюємо порт + } + } else if (PIN_KEYPAD == 0xF0) //перевіряємо чи кнопка відпущена + { + delay(200); + freePinFromKeyPad = 1; + } + return logicPressed; +} diff --git a/mc_labs/mc_lab_03/lab3-mko/lab3-mko.ino b/mc_labs/mc_lab_03/lab3-mko/lab3-mko.ino new file mode 100644 index 0000000..f1c42c1 --- /dev/null +++ b/mc_labs/mc_lab_03/lab3-mko/lab3-mko.ino @@ -0,0 +1,203 @@ + + +// include the library code: +#include "keypad4x4.h" +#include + +#define RESET -1 +#define RETRIEVE -2 + +enum ClockMode { + Time, + Alarm, + AlarmSetup, + TimeSetup +}; + +const PROGMEM char sixty[60][2] = { + "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", + "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", + "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", + "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", + "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", + "50", "51", "52", "53", "54", "55", "56", "57", "58", "59" +}; + + +// initialize the library by associating any needed LCD interface pin +// with the arduino pin number it is connected to +const int padPins[] = { 62, 63, 64, 65, 66, 67, 98, 69 }; +const int rs = 22, rw = PJ6, en = 23; +const int ds[] = { 49, 48, 47, 46, 45, 44, 43, 42 }; +const int buzzerPin = 24; + +long time = 0; +long alarm = 0; +bool alarmActive = false; +bool previousAlarmSetFailed = false; +char mode = ClockMode::Time; +int inputData = 0; + +LiquidCrystal lcd(rs, en, ds[0], ds[1], ds[2], ds[3], ds[4], ds[5], ds[6], ds[7]); + +ISR(TIMER1_COMPA_vect) { + time++; +} + +String makeStr(String str) { + while(str.length() < 16) { + str += ' '; + } + return str; +} + +String secondsToTime(long time) { + String timeFormat = "00:00:00"; + + long hoursMinutesSeconds[] = { (time / (60 * 60)) % 24, (time / 60) % 60, time % 60 }; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 2; j++) { + timeFormat[i * 3 + j] = (char)pgm_read_byte(&(sixty[hoursMinutesSeconds[i]][j])); + } + } + + return timeFormat; +} + +void handleButtonPress() { + if (isButtonPressed()) { + char value = readKeyFromPad4x4(); + switch (value) { + case 'A': + mode = ClockMode::TimeSetup; + getTime(RESET); + break; + case 'B': + mode = ClockMode::AlarmSetup; + getTime(RESET); + break; + case 'C': + mode = ClockMode::Alarm; + break; + case 'D': + if( mode == ClockMode::Alarm) + alarmActive = !alarmActive; + break; + case 'E': + if(mode == ClockMode::TimeSetup) { + mode = ClockMode::Time; + time = getTime(RETRIEVE); + } else if(mode == ClockMode::AlarmSetup) { + mode = ClockMode::Alarm; + alarm = getTime(RETRIEVE); + } + break; + case 'F': + mode = ClockMode::Time; + break; + default: + if(mode != ClockMode::TimeSetup && + mode != ClockMode::AlarmSetup) break; + + getTime(int(value - '0')); + break; + } + } +} + +void displayTime(long seconds) { + lcd.setCursor(0, 1); + + // print the number of seconds since reset: + lcd.print(makeStr(secondsToTime(seconds))); +} + + +long getTime(int inputNumber) { + static int currentValue[] = { 0, 0, 0, 0, 0, 0 }; + static int currentSymbol = 0; + + if(inputNumber == RESET) { + currentSymbol = 0; + for(int i = 0; i < 6; i++) + currentValue[i] = 0; + + displayTime(0); + return 0; + } + + int previousNumber = currentValue[currentSymbol]; + if(inputNumber != RETRIEVE) + currentValue[currentSymbol] = inputNumber; + + + long hours = (currentValue[0] * 10 + currentValue[1]); + long minutes = (currentValue[2] * 10 + currentValue[3]); + long seconds = (currentValue[4] * 10 + currentValue[5]); + + if(hours >= 24 || minutes >= 60 || seconds >= 60) { + currentValue[currentSymbol] = previousNumber; + return -1; + } + + long currentTime = (hours * 3600) + (minutes * 60) + seconds; + + if(inputNumber != RETRIEVE) { + displayTime(currentTime); + currentSymbol = (++currentSymbol) % 6; + } + + return currentTime; +} + +void checkAlarm() { + digitalWrite(buzzerPin, (alarmActive && ((time - alarm) % 2 == 0) && ((time - alarm) < 30) && ((time - alarm) > 0)) ? HIGH : LOW); +} + +void handleCurrentMode() { + lcd.setCursor(0, 0); + switch (mode) { + case ClockMode::TimeSetup: + lcd.print(makeStr("set time:")); + break; + case ClockMode::AlarmSetup: + lcd.print(makeStr("set alarm:")); + break; + case ClockMode::Alarm: + lcd.print(makeStr("alarm" + String(alarmActive ? " on" : " off") + ":")); + displayTime(alarm); + break; + case ClockMode::Time: + lcd.print(makeStr("time" + String(alarmActive ? ", alarm on" : "") + ":")); + displayTime(time); + break; + } +} + + +void setup() { + + initKeyPad(); + + noInterrupts(); + + // Таймер#1: Скид при співпадінні OCR1A (1sec) + TCCR1A = 0x00; + TCCR1B = (1 << WGM12) | (1 << CS12) | (1 << CS10); //CTC mode & Prescaler @ 1024 + TIMSK1 = (1 << OCIE1A); // дозвіл на переривання по співпадінню + OCR1A = 0x3D08; // compare value = 1 sec (16MHz AVR) + + interrupts(); + + // set up the LCD's number of columns and rows: + lcd.begin(16, 2); + + pinMode(buzzerPin, OUTPUT); +} + +void loop() { + checkAlarm(); + handleButtonPress(); + handleCurrentMode(); +} \ No newline at end of file diff --git a/mc_labs/mc_lab_03/lab3-mko/lab3.pdsprj b/mc_labs/mc_lab_03/lab3-mko/lab3.pdsprj new file mode 100644 index 0000000..c7b869f Binary files /dev/null and b/mc_labs/mc_lab_03/lab3-mko/lab3.pdsprj differ