Skip to content

Commit 830cb49

Browse files
authored
Code refactor and fix for #41 (#42)
1 parent e22065e commit 830cb49

File tree

10 files changed

+778
-360
lines changed

10 files changed

+778
-360
lines changed

.gitignore

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,12 @@
1-
*~
2-
/m1ddc
1+
# IDE related files
2+
.idea/
3+
.vscode/
4+
5+
# Default C exclusions
6+
*.o
7+
*.a
8+
9+
# Project specific files & directories
10+
.objects/
11+
library/
12+
m1ddc

Makefile

+128-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,128 @@
1-
all: $
2-
clang -fmodules -o m1ddc m1ddc.m
1+
# -- VARIABLES
2+
3+
# Project name
4+
NAME = m1ddc
5+
LIB = lib$(NAME)
6+
7+
# Compiler
8+
CC = clang
9+
CFLAGS = -Wall -Werror -Wextra -fmodules
10+
CPPFLAGS = -I $(INC_DIR)
11+
DEPFLAGS = -MMD
12+
13+
# Libraries
14+
LDLIBS = -framework CoreDisplay
15+
16+
# Commands
17+
RM = rm -f
18+
RMDIR = rm -rf
19+
MKDIR = mkdir -p
20+
MAKE = make -C
21+
AR = ar -rcs
22+
23+
# Paths
24+
INC_DIR = headers
25+
SRC_DIR = sources
26+
LIB_DIR = library
27+
BIN_DIR = /usr/local/bin
28+
29+
# Sources & Objects - Binary
30+
SOURCES = i2c \
31+
ioregistry \
32+
m1ddc \
33+
34+
OBJ_DIR = .objects
35+
OBJECTS = $(patsubst %,$(OBJ_DIR)/%,$(SOURCES:=.o))
36+
37+
# Sources & Objects - Library
38+
LIB_SRCS = $(filter-out m1ddc, $(SOURCES))
39+
LIB_OBJS = $(patsubst %,$(OBJ_DIR)/%,$(LIB_SRCS:=.o))
40+
LIB_HDRS = $(patsubst %,$(INC_DIR)/%,$(LIB_SRCS:=.h))
41+
42+
# -- IMPLICIT RULES / LINKING
43+
44+
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.m Makefile
45+
@$(CC) -c $< -o $@ $(CPPFLAGS) $(CFLAGS) $(DEPFLAGS)
46+
47+
$(OBJ_DIR):
48+
@$(MKDIR) $(OBJ_DIR)
49+
50+
$(LIB_DIR):
51+
@$(MKDIR) $(LIB_DIR)
52+
53+
$(NAME): $(OBJ_DIR) $(OBJECTS)
54+
@$(CC) $(LDLIBS) $(OBJECTS) -o $@
55+
@printf "Created binary \"$(NAME)\"\n"
56+
57+
$(LIB).a: $(LIB_DIR) $(OBJ_DIR) $(LIB_OBJS)
58+
@$(AR) $(LIB_DIR)/$@ $(LIB_OBJS)
59+
@printf "Created library \"$(LIB_DIR)/$@\"\n"
60+
61+
# For each header file, we do the following, using regular expressions:
62+
# - Ignore the #ifndef _FILE/# define _FILE/#endif directives that begin/end the file
63+
# - Extract the #import directives
64+
# - Extract all the remaining # directives
65+
# - Extract the rest: types and functions declarations.
66+
# All the extracted lines are then appendend to the final header file.
67+
$(LIB).h: $(LIB_DIR) $(LIB_HDRS)
68+
@imports=""; \
69+
directives=""; \
70+
declarations=""; \
71+
for file in $(LIB_HDRS); do \
72+
declarations="$$declarations\n\n/*\n * -- $$(basename $$file .h | tr '[:lower:]' '[:upper:]')\n*/\n"; \
73+
fileguard=$$(echo "_$$(basename $$file .h | tr '[:lower:]' '[:upper:]')_H"); \
74+
if [ "$$(head -n 1 $$file)" = "#ifndef $$fileguard" ]; then \
75+
filecontent=$$(sed -e '1,2d' -e '$$d' $$file); \
76+
else \
77+
filecontent=$$(cat $$file); \
78+
fi; \
79+
imports="$$imports\n$$(echo "$$filecontent" | grep -E "^#\s*import" | sort | uniq)"; \
80+
directives="$$directives\n$$(echo "$$filecontent" | grep -E "^#" | grep -vE "^#\s*import" | grep -vE "^#\s*include\s*\".*.h\"$$" )"; \
81+
declarations="$$declarations\n$$(echo "$$filecontent" | grep -vE "^#" )"; \
82+
done; \
83+
guard=$$(echo "_$(LIB)_H" | tr '[:lower:]' '[:upper:]'); \
84+
printf "#ifndef $$guard\n# define $$guard\n\n" > $(LIB_DIR)/$@; \
85+
printf "$$directives\n\n" >> $(LIB_DIR)/$@; \
86+
printf "$$imports\n\n" >> $(LIB_DIR)/$@; \
87+
printf "$$declarations\n\n" >> $(LIB_DIR)/$@; \
88+
printf "#endif" >> $(LIB_DIR)/$@; \
89+
sed -i '' -e '/^$$/N;/^\n$$/D' $(LIB_DIR)/$@; \
90+
91+
@printf "Created header \"$(LIB_DIR)/$@\"\n"
92+
93+
# -- RULES
94+
95+
.DEFAULT_GOAL := binary
96+
97+
all: binary lib
98+
99+
binary: $(NAME)
100+
101+
lib: $(LIB).a $(LIB).h
102+
103+
clean:
104+
@if [ -e $(OBJ_DIR) ]; then \
105+
$(RMDIR) $(OBJ_DIR); \
106+
printf "Objects deleted\n"; \
107+
fi;
108+
109+
fclean: clean
110+
@if [ -e $(NAME) ]; then \
111+
$(RM) $(NAME); \
112+
printf "Binary deleted\n"; \
113+
fi;
114+
@if [ -e $(LIB_DIR) ]; then \
115+
$(RMDIR) $(LIB_DIR); \
116+
printf "Library deleted\n"; \
117+
fi;
118+
119+
re: fclean all
120+
121+
install:
122+
/bin/mkdir -p $(BIN_DIR)
123+
sudo /usr/bin/install -s -m 0755 $(NAME) $(BIN_DIR)
124+
125+
.PHONY: all lib clean fclean re install
126+
127+
-include $(OBJECTS:.o=.d)
128+

README.md

+19-1
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,28 @@ DisplayPort 1: 15, DisplayPort 2: 16, HDMI 1: 17, HDMI 2: 18.
8686

8787
`display list` - Lists displays.
8888

89-
`display n` - Chooses which display to control (use number 1, 2 etc.)
89+
`display list detailed` - Lists displays and prints extra display attributes.
90+
91+
`display n` - Chooses which display to control using the number (1, 2 etc.) provided by `display list`
92+
93+
`display (id,uuid,edid,seid,basic,ext,full)=<identifier>` - Chooses which display to control using the number using a specific identification method. (If not set, it defaults to `uuid`). See identications methods for more details.
9094

9195
You can also use 'l', 'v' instead of 'luminance', 'volume' etc.
9296

97+
## Identification methods
98+
99+
The following display identifcation methods are supported, and corresponds to the following strings
100+
101+
- `id`: `<display_id>`
102+
- `uuid`: `<system_uuid>`
103+
- `edid`: `<edid_uuid>`
104+
- `seid`: `<alphnum_serial>:<edid_uuid>`.
105+
- `basic`: `<vendor>:<model>:<serial>`.
106+
- `ext`: `<vendor>:<model>:<serial>:<manufacturer>:<alphnum_serial>:<product_name>`.
107+
- `full`: `<vendor>:<model>:<serial>:<manufacturer>:<alphnum_serial>:<product_name>:<io_location>`.
108+
109+
Required identifiers can be obtained using the `display list detailed` command
110+
93111
## Example use in a script
94112

95113
Check out the following [hammerspoon](https://github.com/Hammerspoon/hammerspoon) script.

headers/i2c.h

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#ifndef _I2C_H
2+
# define _I2C_H
3+
4+
# include "ioregistry.h"
5+
6+
# define DEFAULT_INPUT_ADDRESS 0x51
7+
# define ALTERNATE_INPUT_ADDRESS 0x50
8+
9+
# define LUMINANCE 0x10
10+
# define CONTRAST 0x12
11+
# define VOLUME 0x62
12+
# define MUTE 0x8D
13+
# define INPUT 0x60
14+
# define INPUT_ALT 0xF4 // Alternate address, used for LG exclusively?
15+
# define STANDBY 0xD6
16+
# define RED 0x16 // VCP Code - Video Gain (Drive): Red
17+
# define GREEN 0x18 // VCP Code - Video Gain (Drive): Green
18+
# define BLUE 0x1A // VCP Code - Video Gain (Drive): Blue
19+
# define PBP_INPUT 0xE8
20+
# define PBP 0xE9
21+
22+
# define DDC_WAIT 10000 // Depending on display this must be set to as high as 50000
23+
# define DDC_ITERATIONS 2 // Depending on display this must be set higher
24+
# define DDC_BUFFER_SIZE 256
25+
26+
27+
typedef struct {
28+
UInt8 data[DDC_BUFFER_SIZE];
29+
UInt8 inputAddr;
30+
} DDCPacket;
31+
32+
typedef struct {
33+
signed char curValue;
34+
signed char maxValue;
35+
} DDCValue;
36+
37+
38+
DDCPacket createDDCPacket(UInt8 attrCode);
39+
40+
void prepareDDCRead(UInt8 *data);
41+
void prepareDDCWrite(UInt8 *data, UInt8 setValue);
42+
43+
IOReturn performDDCWrite(IOAVServiceRef avService, DDCPacket *packet);
44+
IOReturn performDDCRead(IOAVServiceRef avService, DDCPacket *packet);
45+
46+
DDCValue convertI2CtoDDC(char *i2cBytes);
47+
48+
// External functions
49+
50+
extern IOReturn IOAVServiceReadI2C(IOAVServiceRef service, uint32_t chipAddress, uint32_t offset, void *outputBuffer, uint32_t outputBufferSize);
51+
extern IOReturn IOAVServiceWriteI2C(IOAVServiceRef service, uint32_t chipAddress, uint32_t dataAddress, void *inputBuffer, uint32_t inputBufferSize);
52+
53+
#endif

headers/ioregistry.h

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#ifndef _IOREGISTRY_H
2+
# define _IOREGISTRY_H
3+
4+
# import <CoreGraphics/CoreGraphics.h>
5+
6+
# ifndef MAX_DISPLAYS
7+
# define MAX_DISPLAYS 4 // Set this to 2 or 4 depending on the Apple Silicon Mac you're using
8+
# endif
9+
10+
# define UUID_SIZE 37
11+
12+
// IOAVServiceRef is a private class, so we need to define it here
13+
typedef CFTypeRef IOAVServiceRef;
14+
15+
// Base structure for display infos
16+
typedef struct
17+
{
18+
CGDirectDisplayID id;
19+
io_service_t adapter;
20+
NSString *ioLocation;
21+
NSString *uuid;
22+
NSString *edid;
23+
NSString *productName;
24+
NSString *manufacturer;
25+
NSString *alphNumSerial;
26+
UInt32 serial;
27+
UInt32 model;
28+
UInt32 vendor;
29+
} DisplayInfos;
30+
31+
CGDisplayCount getOnlineDisplayInfos(DisplayInfos* displayInfos);
32+
DisplayInfos* selectDisplay(DisplayInfos *displays, int connectedDisplays, char *displayIdentifier);
33+
34+
IOAVServiceRef getDefaultDisplayAVService();
35+
IOAVServiceRef getDisplayAVService(DisplayInfos* displayInfos);
36+
37+
// External functions
38+
extern IOAVServiceRef IOAVServiceCreate(CFAllocatorRef allocator);
39+
extern IOAVServiceRef IOAVServiceCreateWithService(CFAllocatorRef allocator, io_service_t service);
40+
extern CFDictionaryRef CoreDisplay_DisplayCreateInfoDictionary(CGDirectDisplayID);
41+
42+
#endif

headers/utils.h

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef _UTILS_H_
2+
# define _UTILS_H_
3+
4+
# define STR_EQ(s1, s2) (strcmp(s1, s2) == 0)
5+
6+
#endif

0 commit comments

Comments
 (0)