Skip to content

Commit

Permalink
Add a new IMG command (bitmap->OLED).
Browse files Browse the repository at this point in the history
  • Loading branch information
jose1711 committed Mar 9, 2023
1 parent 93dfedb commit 0fd8e1c
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 11 deletions.
Binary file added firmware/beta_1.1.2_duckyscript3img.dfu
Binary file not shown.
71 changes: 63 additions & 8 deletions firmware/code_duckyscript3/Src/ds3_vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -536,14 +536,69 @@ void execute_instruction(uint16_t curr_pc, ds3_exe_result* exe, uint8_t keynum)
}
else if(this_opcode == OP_HID)
{
char* str_buf = make_str(op_data);
memset(hid_tx_buf, 0, HID_TX_BUF_SIZE);
hid_tx_buf[0] = 4;
hid_tx_buf[1] = 0;
hid_tx_buf[2] = HID_RESPONSE_OK;
memcpy(hid_tx_buf + 3, str_buf, strlen(str_buf)+1);
USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, hid_tx_buf, HID_TX_BUF_SIZE);
}
char* str_buf = make_str(op_data);
memset(hid_tx_buf, 0, HID_TX_BUF_SIZE);
hid_tx_buf[0] = 4;
hid_tx_buf[1] = 0;
hid_tx_buf[2] = HID_RESPONSE_OK;
memcpy(hid_tx_buf + 3, str_buf, strlen(str_buf)+1);
USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, hid_tx_buf, HID_TX_BUF_SIZE);
osDelay(50);
}
else if(this_opcode == OP_IMG)
{
char* str_buf = make_str(op_data);

FIL image_file;
uint8_t ret = 1;
UINT rc = 0;
uint8_t data_pos;

char temp_buf[PATH_SIZE];
char read_buffer[READ_BUF_SIZE];
memset(read_buffer, 0, READ_BUF_SIZE);
memset(temp_buf, 0, PATH_SIZE);
sprintf(temp_buf, "/img/%s", str_buf);
ret = f_open(&image_file, temp_buf, FA_READ);
if (ret != FR_OK) {
ssd1306_Fill(Black);
ssd1306_SetCursor(10, 13);
ssd1306_WriteString("Read error:", Font_6x10, White);
ssd1306_SetCursor(10, 20);
ssd1306_WriteString(str_buf, Font_6x10, White);
ssd1306_UpdateScreen();
osDelay(1000);
return;
}

for (int column=0; column<4; column++) {
data_pos = 0;
f_read(&image_file, read_buffer, READ_BUF_SIZE, &rc);

if (rc != READ_BUF_SIZE) {
ssd1306_Fill(Black);
ssd1306_SetCursor(10, 13);
ssd1306_WriteString("Incomplete read", Font_6x10, White);
ssd1306_UpdateScreen();
osDelay(1000);
return;
}

for (int y=column*16; y<16*(column+1); y++) {
for (int xshift=0; xshift<=120; xshift+=8) {
for (int x=0; x<8; x++) {
if ((read_buffer[data_pos] >> (7 - x)) & 0x1) {
ssd1306_DrawPixel(x+xshift, y, White);
}
}
data_pos++;
}
}
}
ssd1306_UpdateScreen();
f_close(&image_file);
}

else if(this_opcode == OP_OLU)
{
ssd1306_UpdateScreen();
Expand Down
54 changes: 54 additions & 0 deletions img2bits.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env python
'''
convert image file to a monochromatic 1-bit per pixel file for use
with DuckyPad (v3).
'''
from PIL import Image
import argparse
import os
import sys


def image_to_bits(image_file, output_file):
image = Image.open(image_file)

width, height = image.size
if display_width != width or display_height != height:
raise Exception(f'Image dimensions do not match the OLED display ({width}x{height} vs {display_width}x{display_height}')

with open(output_file, 'wb') as f:
for y in range(height):
for x in range(0, width, 8):
byte = 0
for i in range(8):
if isinstance(image.getpixel((x+i, y)), tuple):
pixel_value = sum(image.getpixel((x+i, y))) != 0
else:
pixel = image.getpixel((x+i, y)) != 0
byte |= (pixel << (7 - i))
f.write(bytes([byte]))


display_width = 128
display_height = 64

parser = argparse.ArgumentParser(description='Convert image for duckyPad')
parser.add_argument('-o', nargs=1, metavar='OUTPUT_FILE', dest='outfile',
help='Output file (defaults to input file without extension)')
parser.add_argument('image',
help='Image file to convert')
args = parser.parse_args()

if not os.path.splitext(args.image)[1]:
raise ValueError('input file must have an extension!')

if not args.outfile:
outfile = os.path.splitext(args.image)[0]
else:
outfile = args.outfile

if os.path.exists(outfile):
print(f'Output file {outfile} already exists!')
sys.exit(1)

image_to_bits(args.image, outfile)
2 changes: 1 addition & 1 deletion pc_software/duckyscript3/ds_syntax_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~']

mouse_commands = [cmd_LMOUSE, cmd_RMOUSE, cmd_MMOUSE, cmd_MOUSE_MOVE, cmd_MOUSE_WHEEL]
ignored_but_valid_commands = [cmd_UARTPRINT, cmd_LCR, cmd_REM, cmd_DP_SLEEP, cmd_PREV_PROFILE, cmd_NEXT_PROFILE, cmd_INJECT_MOD, cmd_SEND_HID]
ignored_but_valid_commands = [cmd_UARTPRINT, cmd_LCR, cmd_REM, cmd_DP_SLEEP, cmd_PREV_PROFILE, cmd_NEXT_PROFILE, cmd_INJECT_MOD, cmd_SEND_HID, cmd_IMG]

def is_ignored_but_valid_command(ducky_line):
for item in ignored_but_valid_commands:
Expand Down
1 change: 1 addition & 0 deletions pc_software/duckyscript3/keywords.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
cmd_LCR = "LCR"
cmd_DP_SLEEP = "DP_SLEEP"
cmd_SEND_HID = "SEND_HID"
cmd_IMG = "IMG"
cmd_PREV_PROFILE = "PREV_PROFILE"
cmd_NEXT_PROFILE = "NEXT_PROFILE"
cmd_GOTO_PROFILE = "GOTO_PROFILE"
Expand Down
7 changes: 5 additions & 2 deletions pc_software/duckyscript3/make_bytecode.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
OP_GOTOP = ("GOTOP", 46)
OP_SLEEP = ("SLEEP", 47)
OP_HID = ("HID", 48)
OP_IMG = ("IMG", 49)

arith_lookup = {
"Eq" : OP_EQ,
Expand Down Expand Up @@ -532,7 +533,7 @@ def make_dsb(program_listing):
this_instruction['opcode'] = OP_CALL
this_instruction['oparg'] = label_dict[func_lookup[fun_name]['fun_start']]
assembly_listing.append(this_instruction)
elif this_line.startswith(cmd_STRING) or first_word == cmd_OLED_PRINT or first_word == cmd_SEND_HID:
elif this_line.startswith(cmd_STRING) or first_word == cmd_OLED_PRINT or first_word == cmd_SEND_HID or first_word == cmd_IMG:
str_content = this_line.split(' ', 1)[-1]
if str_content not in str_lookup:
str_lookup[str_content] = lnum
Expand All @@ -544,6 +545,8 @@ def make_dsb(program_listing):
this_instruction['opcode'] = OP_OLP
elif first_word == cmd_SEND_HID:
this_instruction['opcode'] = OP_HID
elif first_word == cmd_IMG:
this_instruction['opcode'] = OP_IMG
this_instruction['oparg'] = f"STR@{str_lookup[str_content]}"
assembly_listing.append(this_instruction)
elif first_word == cmd_DELAY:
Expand Down Expand Up @@ -692,7 +695,7 @@ def make_dsb(program_listing):
label_to_addr_dict[item['label']] = item['addr']

for item in assembly_listing:
if item['opcode'] == OP_STR or item['opcode'] == OP_STRLN or item['opcode'] == OP_OLP or item['opcode'] == OP_HID:
if item['opcode'] == OP_STR or item['opcode'] == OP_STRLN or item['opcode'] == OP_OLP or item['opcode'] == OP_HID or item['opcode'] == OP_IMG:
str_lnum = int(item['oparg'].replace('STR@', ''))
for sssss in str_list:
if sssss['lnum'] == str_lnum:
Expand Down

0 comments on commit 0fd8e1c

Please sign in to comment.