From 19c923ce69878795c42357d30351f45550a211ba Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 22 Sep 2025 01:57:51 +0200 Subject: [PATCH] init --- .clang-format | 3 + .clang-tidy | 4 + .gitignore | 5 + .vscode/launch.json | 25 ++ .vscode/tasks.json | 13 + disk/userport_tester.d64 | Bin 0 -> 174848 bytes nano/sketch_sep20a/sketch_sep20a.ino | 153 ++++++++++++ project-config.json | 15 ++ src/input.c | 52 ++++ src/input.h | 16 ++ src/main.c | 358 +++++++++++++++++++++++++++ src/menu/menu.c | 159 ++++++++++++ src/menu/menu.h | 7 + 13 files changed, 810 insertions(+) create mode 100644 .clang-format create mode 100644 .clang-tidy create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 disk/userport_tester.d64 create mode 100644 nano/sketch_sep20a/sketch_sep20a.ino create mode 100644 project-config.json create mode 100644 src/input.c create mode 100644 src/input.h create mode 100644 src/main.c create mode 100644 src/menu/menu.c create mode 100644 src/menu/menu.h diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..247acf1 --- /dev/null +++ b/.clang-format @@ -0,0 +1,3 @@ +# clang format config +BasedOnStyle: Google +IndentWidth: 4 diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..293d63b --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,4 @@ +# clang tidy config +Checks: 'clang-diagnostic-*,clang-analyzer-*,bugprone-*' +WarningsAsErrors: 'true' +HeaderFilterRegex: 'include/\*\.h' diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b881cb0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# git ignores +*~ +build +.vscode/c_cpp_properties.json +.vscode/settings.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..695296e --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,25 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "vice", + "request": "launch", + "name": "Launch Vice", + "preLaunchTask": "${defaultBuildTask}" + }, + { + "type": "vice", + "request": "attach", + "name": "Attach Vice", + "hostname": "localhost", + "port": 6502, + "preLaunchTask": "${defaultBuildTask}" + }, + { + "type": "6502", + "request": "launch", + "name": "Launch 6502", + "preLaunchTask": "${defaultBuildTask}" + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..cc11806 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,13 @@ +{ + "tasks": [ + { + "type": "vs64", + "action": "build", + "group": { + "kind": "build", + "isDefault": true + }, + "label": "build project" + } + ] +} diff --git a/disk/userport_tester.d64 b/disk/userport_tester.d64 new file mode 100644 index 0000000000000000000000000000000000000000..5192eecdded1219f9afe52a662528ff7bb026529 GIT binary patch literal 174848 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 literal 0 HcmV?d00001 diff --git a/nano/sketch_sep20a/sketch_sep20a.ino b/nano/sketch_sep20a/sketch_sep20a.ino new file mode 100644 index 0000000..5317eb2 --- /dev/null +++ b/nano/sketch_sep20a/sketch_sep20a.ino @@ -0,0 +1,153 @@ +#define DP_0 2 +#define DP_1 3 +#define DP_2 4 +#define DP_3 5 +#define AR 6 +#define CR 7 + +#define STANDBY 0 +#define READ 1 +#define WRITE 2 + + +char count = 0; +char delayAmount = 100; +char textToSent[] = "Hallo vom Arduino Nano!"; + +char mode; + +char getScreenCode(char c) { + if (c >= 32 && c <= 63) { + return c; + } else if (c == 64) { + return 0; + } else if (c >= 65 && c <= 90) { + return c; + } else if (c == 91 || c == 93) { + return c - 64; + } else if (c == 95) { + return 111; + } else if (c >= 97 && c <= 122) { + return c - 96; + } else if (c == 124) { + return 93; + } else { + return 63; + } +} + +void initMode(char mode) { + + switch (mode) { + case WRITE: + pinMode(DP_0, OUTPUT); + pinMode(DP_1, OUTPUT); + pinMode(DP_2, OUTPUT); + pinMode(DP_3, OUTPUT); + break; + case STANDBY: + default: + pinMode(DP_0, INPUT); + pinMode(DP_1, INPUT); + pinMode(DP_2, INPUT); + pinMode(DP_3, INPUT); + } + + pinMode(AR, OUTPUT); + pinMode(CR, INPUT); + + digitalWrite(DP_0, LOW); + digitalWrite(DP_1, LOW); + digitalWrite(DP_2, LOW); + digitalWrite(DP_3, LOW); + digitalWrite(AR, LOW); + digitalWrite(CR, LOW); + +} + +void setup() { + delay(2000); + mode = STANDBY; + initMode(mode); + + Serial.begin(9600); + +} + +void send4Bit(char c) { + + for (char i = 3; i >= 0; i--) { + char d = c >> i & 1; + Serial.print(d, DEC); + } + + for (char i = 0; i < 4; i++) { + char d = c >> i & 1; + digitalWrite(i+2, d); + } + Serial.print(" "); + digitalWrite(AR, HIGH); + + while (digitalRead(CR) == LOW) {} + + while (digitalRead(CR) == HIGH) {} + digitalWrite(AR, LOW); + + //delay(500); +} + +void sendByte(char a, char byte) { + char upper = byte >> 4; + char lower = byte & 0b00001111; + + + Serial.print(a); + Serial.print(" "); + Serial.print(a, DEC); + Serial.print(" "); + Serial.print(byte, DEC); + Serial.print(" "); + send4Bit(upper); + send4Bit(lower); +} + +void startWrite() { + Serial.print("start\n"); + mode = WRITE; + initMode(mode); + digitalWrite(AR, LOW); + + int i = 0; + char c, sc; + do { + c = textToSent[i]; + sc = getScreenCode(c); + i++; + sendByte(c, sc); + //Serial.print(c, DEC); + } while (c != 0); + + Serial.print("\n"); + + for (char i = 2; i < 8; i++) { + digitalWrite(i, LOW); + } + + mode = STANDBY; +} + +void loop() { + + if (mode == WRITE) { + + } else if (mode == READ) { + + } else { + startWrite(); + } + + Serial.print("\nAAAAAAAA\n"); + + delay(20000); + +} diff --git a/project-config.json b/project-config.json new file mode 100644 index 0000000..e1b3c3c --- /dev/null +++ b/project-config.json @@ -0,0 +1,15 @@ +{ + "name": "c64_c_userport", + "description": "Project c64_c_userport", + "toolkit": "cc65", + "sources": [ + "src/main.c", + "src/menu/menu.c", + "src/input.c" + ], + "build": "debug", + "definitions": [], + "includes": [], + "args": [], + "compiler": "" +} diff --git a/src/input.c b/src/input.c new file mode 100644 index 0000000..af688e1 --- /dev/null +++ b/src/input.c @@ -0,0 +1,52 @@ +#include "input.h" + +unsigned short* PEVIOUS_KEY_MATRIX_CODE_PTR = (unsigned short*)0x00C5; +unsigned short* CURRENT_KEY_MATRIX_CODE_PTR = (unsigned short*)0x00CB; +unsigned char C_64_KEYBOARD_MATRIX[8][8] = { + {20 /*DEL*/, 13 /*RETURN*/, 29 /*CURSOR RIGHT*/, 136 /*F7*/, 133 /*F1*/, 134 /*F3*/, 135 /*F5*/, 145 /*CURSOR UP*/}, + {'3' , 'w' , 'a', '4', 'z', 's', 'e', 255 /*LEFT SHIFT*/}, + {'5' , 'r' , 'd', '6', 'c', 'f', 't', 'x'}, + {'7' , 'y' , 'g', '8', 'b', 'h', 'u', 'v'}, + {'9' , 'i' , 'j', '0', 'm', 'k', 'o', 'n'}, + {'+' , 'p' , 'l', '-', '.', ':', '@', ','}, + {92 /*₤*/ , '*' , ';', 147 /*CLR*/, 255 /*RIGHT SHIFT*/, '=', 94 /*↑*/, '/'}, + {'1' , 95 /*←*/ , 255 /*CTRL*/, '2', ' ', 255 /*COMODORE*/, 'q', 3 /*RUN / STOP*/}, +}; + +unsigned char getCurrentKeyMatrixCode() { + return *CURRENT_KEY_MATRIX_CODE_PTR; +} + +unsigned char getPreviousKeyMatrixCode() { + return *PEVIOUS_KEY_MATRIX_CODE_PTR; +} + +unsigned char matrixCodeToPetscii(unsigned char code) { + char x, y; + + if (code == 64) + return 32; + + x = code % 8; + y = code / 8; + + return C_64_KEYBOARD_MATRIX[y][x]; +} + +unsigned char getInputChar() { + char code = getCurrentKeyMatrixCode(); + + // wait until no key is pressed + while (code != KEY_NONE) + { + code = getCurrentKeyMatrixCode(); + } + + // wait until key is pressed + while (code == KEY_NONE) + { + code = getCurrentKeyMatrixCode(); + } + + return code; +} diff --git a/src/input.h b/src/input.h new file mode 100644 index 0000000..4657905 --- /dev/null +++ b/src/input.h @@ -0,0 +1,16 @@ +#define KEY_RETURN 1 +#define KEY_W 9 +#define KEY_S 13 +#define KEY_PLUS 40 +#define KEY_MINUS 43 +#define KEY_SPACE 60 +#define KEY_NONE 64 + +extern unsigned short* PEVIOUS_KEY_MATRIX_CODE_PTR; +extern unsigned short* CURRENT_KEY_MATRIX_CODE_PTR; +extern unsigned char C_64_KEYBOARD_MATRIX[8][8]; + +extern unsigned char getCurrentKeyMatrixCode(); +extern unsigned char getPreviousKeyMatrixCode(); +extern unsigned char matrixCodeToPetscii(unsigned char code); +extern unsigned char getInputChar(); \ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..9104f49 --- /dev/null +++ b/src/main.c @@ -0,0 +1,358 @@ +#include +#include +#include +#include +#include +#include "input.h" +#include "menu/menu.h" + +#define DATA_ADDR 0xdd01 +#define DIR_ADDR 0xdd03 +#define SCREEN_ADDR 0x0400 +#define COLOR_ADDR 0xD800 + +signed char NOT_STOP = 1; +char mode = 0; +char itr = 0; + +volatile char* dataPtr = (volatile char*)DATA_ADDR; +volatile char* dirPtr = (volatile char*)DIR_ADDR; + + +char* version = "0.5"; +char* creator = "Christian Werner"; +unsigned char original_background_color, original_border_color, original_text_color = 0; + + +char* menu_items[] = { + "Output", + "Input" +}; + +char menu_items_len = sizeof(menu_items)/sizeof(menu_items[0]); + +char dirBuff[8]; +char dataBuff[8]; + +char dataState = 255; +char previousKey = 0; + +void writeToScreen(char x, char y, char c, char color) { + unsigned short offset = y * 40 + x; + *(char*)(SCREEN_ADDR + offset) = c; + *(char*)(COLOR_ADDR + offset) = color; +} + +int getNumber(char* promt, int min, int max) { + int n; + printf("%s [%d-%d]: ", promt, min, max); + cursor(1); + cscanf("%d", &n); + cursor(0); + + if (n > max) { + n = max; + } + + if (n < min) { + n = min; + } + return n; +} + +void resetScreen() { + clrscr(); + textcolor(COLOR_GRAY1); + printf("Userport Playground v%s\ncreated by ", version); + textcolor(COLOR_LIGHTBLUE); + printf("%s\n", creator); + textcolor(COLOR_GRAY1); + chline(40); + textcolor(COLOR_WHITE); +} + +void toBinaryArray(char *buff , char value) { + char mask = 1; + char i; + for(i = 0; i < 8; i++) { + buff[i] = value & mask; + value = value >> 1; + } +} + +void drawBinary(char low, char high, char* buff, char x, char y, char c_low, char c_high) { + char i; + char c; + char col; + + for(i = 0; i < 8; i++) { + if (buff[i] == 0) { + c = low; + col = c_low; + } else { + c = high; + col = c_high; + } + writeToScreen(x + i * 2, y, c, col); + } +} + +void userport() { + char direction = *(char*)0xdd03; + char data = *(char*)0xdd01; + char key_cur, key_prev, pet_code, p_c, p_p, x, y; + + toBinaryArray(dirBuff, direction); + toBinaryArray(dataBuff, data); + + gotoxy(0,3); + printf("dir: %03d ", direction); + drawBinary(73+128, 79+128, dirBuff, 10, 3, COLOR_ORANGE, COLOR_GREEN); + + gotoxy(0,5); + printf("data: %03d ", data); + drawBinary(160, 160, dataBuff, 10, 5, COLOR_GRAY1, COLOR_RED); + + key_cur = getCurrentKeyMatrixCode(); + key_prev = getPreviousKeyMatrixCode(); + + p_c = matrixCodeToPetscii(key_cur); + p_p = matrixCodeToPetscii(key_prev); + + + writeToScreen(5,10, p_c, COLOR_GREEN); + gotoxy(7,10); + printf("%02d, %03d", key_cur, p_c); + + x = key_cur % 8; + y = key_cur / 8; + + printf(" %02d, %02d", x, y); + +} + +void init() { + original_background_color = bgcolor(COLOR_BLACK); + original_border_color = bordercolor(COLOR_BLACK); + original_text_color = textcolor(COLOR_GRAY1); + resetScreen(); +} + +int menu() { + char i; + int index; + resetScreen(); + for(i = 0; i < menu_items_len; i++) { + printf("%d. %s\n", i+1, menu_items[i]); + } + index = getNumber("Pick mode", 1, menu_items_len) - 1; + return index; +} + +void restore() { + bgcolor(original_background_color); + bordercolor(original_border_color); + textcolor(original_text_color); + clrscr(); + // set char set to upper case + *(char*)0xd018 = 0x14; + *(char*)DIR_ADDR = 255; + *(char*)DATA_ADDR = 0; +} + +void defaultLoop() { + + while(1) { + char key = matrixCodeToPetscii(getCurrentKeyMatrixCode()); + + if (key == 3) { + mode = 2; + break; + } + + if (key == 95) { + mode = 1; + break; + } + + if (previousKey != key && key > '0' && key < '9') { + dataState = dataState ^ (1 << key - 49); + *(char*)0xdd03 = dataState; + } + + *(char*)0xdd01 = itr; + userport(); + itr++; + previousKey = key; + } +} + +void fast() { + while(1) { + char key = matrixCodeToPetscii(getCurrentKeyMatrixCode()); + + if (key == 3) { + mode = 2; + break; + } + + if (key == 95) { + mode = 0; + break; + } + + if (previousKey != key && key > '0' && key < '9') { + dataState = dataState ^ (1 << key - 49); + *(char*)0xdd03 = dataState; + } + + *(char*)0xdd01 = itr; + itr++; + previousKey = key; + } +} + +void dod(char* title) { + char i = 0; + *(char*)0xdd03 = dataState; + while (1) { + + + switch (mode) + { + case 0: + defaultLoop(); + break; + case 1: + fast(); + break; + default: + mode = 0; + dataState = 255; + itr = 0; + return; + } + } +} + +void writeAllCharsToScreen() { + char x, y, c; + + for (y = 0; y < 7; y++) { + for (x = 0; x < 40; x++) { + c = y * 40 + x; + writeToScreen(x, y, c, COLOR_GREEN); + } + } +} + +void notImplemented(char* title) { + char origCol; + origCol = textcolor(COLOR_YELLOW); + printf("\"%s\" is not implemented :(", title); + textcolor(origCol); + printf("\nPress any key to continiue..."); + getInputChar(); +} + +void exitProgram(char* title) { + NOT_STOP = 0; +} + + +void recieveTest(char* title) { + unsigned short screenStart = SCREEN_ADDR + 40 * 3 ; + volatile char* screen = (volatile char*)screenStart; + unsigned short screenEnd = SCREEN_ADDR + 40*25; + char d, isArduinoReady, buff; + char lower, upper, fullByte; + short i = 0; + lower = 16; + upper = 16; + + *dirPtr = 0b11110000; + *dataPtr = 0; + + while (1) { + + char key = matrixCodeToPetscii(getCurrentKeyMatrixCode()); + + if (key == 3) { + break; + } + + d = *dataPtr; + + isArduinoReady = (d >> 4) & 1; + buff = d & 15; + + if (isArduinoReady) { + if (upper == 16) { + upper = buff; + } else if (lower == 16) + { + lower = buff; + } + } else { + continue; + } + + if (upper != 16 && lower != 16) { + fullByte = (upper << 4) + lower; + if (fullByte > 0) { + *screen = fullByte; + screen++; + } + if (screen == screenEnd) { + screen = (volatile char*)screenStart; + } + upper = 16; + lower = 16; + } + + //set comodore ready + for (i = 0; i < 100; i++) {} + *dataPtr = d | 0b00100000; + + for (i = 0; i < 100; i++) {} + *dataPtr = d & 0b11011111; + } +} + + +void main() { + // int selection; + char huh; + + Menu* menu = createMenu(4, "Main Menu", COLOR_LIGHTGREEN, 0, 3); + addMenuEntry(menu, "Userport Test", 0, dod); + addMenuEntry(menu, "Recieve Test", 1, recieveTest); + addMenuEntry(menu, "Test", 2, notImplemented); + addMenuEntry(menu, "EXIT", 3, exitProgram); + + init(); + + while (NOT_STOP) + { + awaitMenuSelect(menu); + } + + //selection = menu(); + // selection = 1; + // resetScreen(); + + // if (selection == 0) { + // userport(); + // } else { + // userport(); + // } + + //*(char*)0xd018 = 0x14; + + // dod(); + + free(menu); + restore(); + exit(0); +} + diff --git a/src/menu/menu.c b/src/menu/menu.c new file mode 100644 index 0000000..aae3589 --- /dev/null +++ b/src/menu/menu.c @@ -0,0 +1,159 @@ +#include "menu.h" +#include "../input.h" +#include +#include +#include +#include + +struct MenuEntry { + char* name; + void (*callback)(char*); +}; + +struct Menu { + char* title; + unsigned char size; + short selected_index; + unsigned char selected_color; + char posX; + char posY; + MenuEntry entries[]; +}; + +short MENU_ENTRY_SIZE = sizeof(MenuEntry); +short MENU_SIZE = sizeof(Menu); + +Menu* createMenu(char size, char* title, char selected_color, char x, char y) { + + Menu* menu = malloc(MENU_SIZE + size * MENU_ENTRY_SIZE); + + if (!menu) return NULL; + + menu->selected_index = 0; + menu->title = title; + menu->size = size; + menu->selected_color = selected_color; + menu->posX = x; + menu->posY = y; + + return menu; +} + +void addMenuEntry(Menu* menu, char* name, char index, void (*callback)(char*)) { + menu->entries[index].name = name; + menu->entries[index].callback = callback; +} + +void drawMenuEntires(Menu* menu) { + char i; + MenuEntry e; + for (i = 1; i < menu->size + 1; i++) + { + gotoxy(menu->posX, menu->posY + i); + e = menu->entries[i-1]; + + if (i == menu->selected_index + 1) { + textcolor(menu->selected_color); + printf("%s", e.name); + textcolor(COLOR_WHITE); + } else { + printf("%s", e.name); + } + } +} + +void drawMenu(Menu* menu) { + unsigned char origtextColor; + + origtextColor = textcolor(COLOR_WHITE); + + gotoxy(menu->posX, menu->posY); + printf("[%s]", menu->title); + + drawMenuEntires(menu); + + gotoxy(menu->posX, 21); + textcolor(COLOR_GRAY1); + chline(40); + gotoxy(40 - 10, 21); + printf("Controls"); + textcolor(COLOR_WHITE); + + gotoxy(menu->posX, 22); + printf(": Up\n"); + printf(": Down\n"); + printf(": Select"); + + gotoxy(menu->posX, menu->posY); + + textcolor(origtextColor); +} + +void unDrawMenu(Menu* menu) { + unsigned char i; + for (i = 0; i < 25 - menu->posY; i++) + { + gotoxy(menu->posX, menu->posY + i); + cclear(40 - menu->posX); + } + gotoxy(menu->posX, menu->posY); +} + +void clear() { + unsigned char i; + for (i = 3; i < 25; i++) + { + gotoxy(0, i); + cclear(40); + } + gotoxy(0, 3); +} + +void awaitMenuSelect(Menu* menu) { + char current_key; + signed short pressedKey; + MenuEntry slectedEntry; + + clear(); + drawMenu(menu); + pressedKey = -1; + + while(1) { + current_key = getCurrentKeyMatrixCode(); + + if (pressedKey == KEY_SPACE && current_key == KEY_NONE) { + break; + } + + if (pressedKey == KEY_W && current_key == KEY_NONE) { + + menu->selected_index--; + if (menu->selected_index < 0) { + menu->selected_index = menu->size -1; + } + + drawMenuEntires(menu); + pressedKey = -1; + } + + if (pressedKey == KEY_S && current_key == KEY_NONE) { + + menu->selected_index++; + if (menu->selected_index > menu->size -1) { + menu->selected_index = 0; + } + + drawMenuEntires(menu); + pressedKey = -1; + } + + if (current_key != KEY_NONE) { + pressedKey = current_key; + } + } + + unDrawMenu(menu); + + slectedEntry = menu->entries[menu->selected_index]; + slectedEntry.callback(slectedEntry.name); +} diff --git a/src/menu/menu.h b/src/menu/menu.h new file mode 100644 index 0000000..9c07db0 --- /dev/null +++ b/src/menu/menu.h @@ -0,0 +1,7 @@ +typedef struct Menu Menu; +typedef struct MenuEntry MenuEntry; + + +extern Menu* createMenu(char size, char* title, char selected_color, char x, char y); +extern void addMenuEntry(Menu* menu, char* name, char index, void (*callback)(char*)); +extern void awaitMenuSelect(Menu* menu); \ No newline at end of file