g29py 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
g29py-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,53 @@
1
+ Metadata-Version: 2.1
2
+ Name: g29py
3
+ Version: 0.0.1
4
+ Summary: python driver for g29 wheel/pedals
5
+ Author: sean pollock
6
+ Author-email: seanap@protonmail.com
7
+ Requires-Python: >=3.8,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.8
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Requires-Dist: hid (==1.0.4)
14
+ Description-Content-Type: text/markdown
15
+
16
+ # g29py
17
+ > python driver for logitech g29 wheel/pedals
18
+
19
+ #### install
20
+ `$ pip install g29py`
21
+
22
+ ```
23
+ from g29py import G29
24
+ g29 = G29()
25
+ g29.reset() # wheel cal
26
+ ```
27
+
28
+ ```
29
+ # write
30
+ g29.set_range(500)
31
+ g29.set_friction(0.5)
32
+ ```
33
+
34
+ ```
35
+ #read
36
+ g29.start_pumping() # thread
37
+ while 1:
38
+ state = g29.get_state()
39
+ print("steering:", state["steering"])
40
+ print("brake:", state["brake"])
41
+ ```
42
+
43
+ #### sources
44
+
45
+ - Write.md Read.md
46
+ - Commands based on nightmode's [logitech-g29](https://github.com/nightmode/logitech-g29) node.js driver.
47
+ - Interface uses libhidapi ctype bindings from apmorton's [pyhidapi](https://github.com/apmorton/pyhidapi).
48
+
49
+
50
+ ### support
51
+
52
+ Only Logitech G29 Driving Force Racing Wheels & Pedals kit supported on linux in ps3 mode.
53
+
g29py-0.0.1/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # g29py
2
+ > python driver for logitech g29 wheel/pedals
3
+
4
+ #### install
5
+ `$ pip install g29py`
6
+
7
+ ```
8
+ from g29py import G29
9
+ g29 = G29()
10
+ g29.reset() # wheel cal
11
+ ```
12
+
13
+ ```
14
+ # write
15
+ g29.set_range(500)
16
+ g29.set_friction(0.5)
17
+ ```
18
+
19
+ ```
20
+ #read
21
+ g29.start_pumping() # thread
22
+ while 1:
23
+ state = g29.get_state()
24
+ print("steering:", state["steering"])
25
+ print("brake:", state["brake"])
26
+ ```
27
+
28
+ #### sources
29
+
30
+ - Write.md Read.md
31
+ - Commands based on nightmode's [logitech-g29](https://github.com/nightmode/logitech-g29) node.js driver.
32
+ - Interface uses libhidapi ctype bindings from apmorton's [pyhidapi](https://github.com/apmorton/pyhidapi).
33
+
34
+
35
+ ### support
36
+
37
+ Only Logitech G29 Driving Force Racing Wheels & Pedals kit supported on linux in ps3 mode.
@@ -0,0 +1,3 @@
1
+ from .g29 import G29
2
+
3
+ __all__ = ['G29']
@@ -0,0 +1,157 @@
1
+ import hid
2
+ import time
3
+ import threading
4
+ import logging as log
5
+
6
+ NAME = "Logitech G29 Driving Force Racing Wheel"
7
+ GUID = "030000006d0400004fc2000011010000"
8
+ VENDOR_ID = 1133
9
+ PRODUCT_ID = 49743
10
+
11
+ STEERING_COARSE_AXIS = 4
12
+ STEERING_FINE_AXIS = 5
13
+ ACCELERATOR_AXIS = 6
14
+ BRAKE_AXIS = 7
15
+ CLUTCH_AXIS = 8
16
+
17
+ class G29:
18
+ cache = None
19
+ state = {
20
+ "steering": int,
21
+ "accelerator": int,
22
+ "brake": int,
23
+ "clutch": int,
24
+ }
25
+ def __init__(self):
26
+ try:
27
+ device = hid.Device(VENDOR_ID, PRODUCT_ID)
28
+ except:
29
+ raise Exception("Device not found. Is it plugged in?")
30
+ log.debug(f'Device manufacturer: {device.manufacturer}')
31
+ log.debug(f'Product: {device.product}')
32
+ self.device = device
33
+
34
+ def connect(self):
35
+ self.pump() # load cache
36
+ self.reset()
37
+
38
+ def reset(self):
39
+ # wheel calibration
40
+ self.device.write(bytes([0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00]))
41
+ self.device.write(bytes([0xf8, 0x09, 0x05, 0x01, 0x01, 0x00, 0x00]))
42
+ time.sleep(10) # wait for calibration
43
+
44
+ # WRITE
45
+
46
+ def force_constant(self, val=0.5):
47
+ if val < 0 or val > 1:
48
+ raise ValueError("force_constant val must be between 0 and 1")
49
+ # normalze to 0-255
50
+ val = round(int(val * 255))
51
+ log.debug(f'force_constant: {val}')
52
+ msg = [0x11, 0x00, val, 0x00, 0x00, 0x00, 0x00]
53
+ self.device.write(bytes(msg))
54
+
55
+ def force_friction(self, val=0.5):
56
+ if val < 0 or val > 1:
57
+ raise ValueError("force_fricion val must be between 0 and 1")
58
+ # normalze to 0-8
59
+ val = round(int(val * 8))
60
+ log.debug(f'force_friction: {val}')
61
+ msg = [0x21, 0x02, val, 0x00, val, 0x00, 0x00]
62
+ self.device.write(bytes(msg))
63
+
64
+ def set_range(self, val=400):
65
+ if val < 400 or val > 900:
66
+ raise ValueError("set_range val must be between 400 and 900")
67
+ range1 = val & 0x00ff
68
+ range2 = (val & 0xff00) >> 8
69
+ log.debug(f'range: {range1},{range2}')
70
+ msg = [0xf8, 0x81, range1, range2, 0x00, 0x00, 0x00]
71
+ self.device.write(bytes(msg))
72
+
73
+ def set_autocenter(self, strength=0.5, rate=0.05):
74
+ if strength < 0 or strength > 1:
75
+ raise ValueError("force_constant val must be between 0 and 1")
76
+ if rate < 0 or rate > 1:
77
+ raise ValueError("force_constant val must be between 0 and 1")
78
+ # autocenter up
79
+ up_msg = [0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
80
+ self.device.write(bytes(up_msg))
81
+ # normalze strength to 0-15
82
+ strength = round(int(strength * 15))
83
+ # normalze rate to 0-255
84
+ rate = round(int(rate * 255))
85
+ log.debug(f'autocenter: {strength} {rate}')
86
+ msg = [0xfe, 0x0d, strength, strength, rate, 0x00, 0x00, 0x00]
87
+ self.device.write(bytes(msg))
88
+
89
+ def autocenter_off(self):
90
+ msg = [0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
91
+ self.device.write(bytes(msg))
92
+
93
+ # slot 0-4, or 0xf3 for all
94
+ def force_off(self, slot=0xf3):
95
+ if slot < 0 or slot > 4 and slot !=0xf3:
96
+ raise ValueError("force_off slot must be between 0 and 4 or 0xf3")
97
+ log.debug(f'force_off: {slot}')
98
+ msg = [slot, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
99
+ self.device.write(bytes(msg))
100
+
101
+ # READ
102
+
103
+ def pump(self, timeout=10):
104
+ dat = self.device.read(16, timeout)
105
+
106
+ # only handle 12 byte msgs
107
+ byte_array = bytearray(dat)
108
+ if len(byte_array) >= 12:
109
+ self.update_state(byte_array)
110
+ self.cache = byte_array
111
+
112
+ return dat
113
+
114
+ def start_pumping(self, timeout=10):
115
+ self.pump_thread = threading.Thread(target=self.pump_forever, args=(timeout,))
116
+ self.pump_thread.start()
117
+
118
+ def pump_forever(self, timeout=10):
119
+ while 1:
120
+ self.pump(timeout)
121
+
122
+ def stop_pumping(self):
123
+ if self.thread is not None:
124
+ self.pump_thread.join()
125
+
126
+ def get_state(self):
127
+ return self.state
128
+
129
+ def update_state(self, byte_array):
130
+ if self.cache is None:
131
+ log.warn("cache not available")
132
+ return
133
+
134
+ # update only diffs
135
+ # steering
136
+ if byte_array[4] != self.cache[4] or byte_array[5] != self.cache[5]:
137
+ steering_val = self.calc_steering(byte_array[5], byte_array[4])
138
+ self.state["steering"] = steering_val
139
+ # accelerator
140
+ if byte_array[6] != self.cache[6]:
141
+ self.state["accelerator"] = byte_array[6]
142
+ # brake
143
+ if byte_array[7] != self.cache[7]:
144
+ self.state["brake"] = byte_array[7]
145
+ # clutch
146
+ if byte_array[8] != self.cache[8]:
147
+ self.state["clutch"] = byte_array[8]
148
+
149
+ def calc_steering(self, coarse, fine):
150
+ # coarse 0-255
151
+ # fine 0-255
152
+ # normalize to 0-100
153
+ coarse = (coarse/256) * (100-(100/256))
154
+ # normalize to 0-3
155
+ fine = (fine/256) * (100/256)
156
+ # add together
157
+ return round(coarse + fine)
@@ -0,0 +1,19 @@
1
+ [tool.poetry]
2
+ name = "g29py"
3
+ version = "0.0.1"
4
+ description = "python driver for g29 wheel/pedals"
5
+ authors = ["sean pollock <seanap@protonmail.com>"]
6
+ readme = "README.md"
7
+ packages = [{include = "g29py"}]
8
+
9
+ [tool.poetry.dependencies]
10
+ python = "^3.8"
11
+ hid = "1.0.4"
12
+
13
+
14
+ [tool.poetry.group.dev.dependencies]
15
+ pytest = "^7.3.2"
16
+
17
+ [build-system]
18
+ requires = ["poetry-core", "libhidapi-hidraw0"]
19
+ build-backend = "poetry.core.masonry.api"
g29py-0.0.1/setup.py ADDED
@@ -0,0 +1,30 @@
1
+ # -*- coding: utf-8 -*-
2
+ from setuptools import setup
3
+
4
+ packages = \
5
+ ['g29py']
6
+
7
+ package_data = \
8
+ {'': ['*']}
9
+
10
+ install_requires = \
11
+ ['hid==1.0.4']
12
+
13
+ setup_kwargs = {
14
+ 'name': 'g29py',
15
+ 'version': '0.0.1',
16
+ 'description': 'python driver for g29 wheel/pedals',
17
+ 'long_description': '# g29py\n> python driver for logitech g29 wheel/pedals\n\n#### install\n`$ pip install g29py`\n\n```\nfrom g29py import G29\ng29 = G29()\ng29.reset() # wheel cal\n```\n\n```\n# write \ng29.set_range(500)\ng29.set_friction(0.5)\n```\n\n```\n#read\ng29.start_pumping() # thread\nwhile 1:\n state = g29.get_state()\n print("steering:", state["steering"])\n print("brake:", state["brake"])\n```\n\n#### sources\n\n- Write.md Read.md \n- Commands based on nightmode\'s [logitech-g29](https://github.com/nightmode/logitech-g29) node.js driver.\n- Interface uses libhidapi ctype bindings from apmorton\'s [pyhidapi](https://github.com/apmorton/pyhidapi).\n\n\n### support\n\nOnly Logitech G29 Driving Force Racing Wheels & Pedals kit supported on linux in ps3 mode.\n',
18
+ 'author': 'sean pollock',
19
+ 'author_email': 'seanap@protonmail.com',
20
+ 'maintainer': 'None',
21
+ 'maintainer_email': 'None',
22
+ 'url': 'None',
23
+ 'packages': packages,
24
+ 'package_data': package_data,
25
+ 'install_requires': install_requires,
26
+ 'python_requires': '>=3.8,<4.0',
27
+ }
28
+
29
+
30
+ setup(**setup_kwargs)