Skip to content

Commit 9a6ae38

Browse files
scottrfrancisclaude
andcommitted
feat: Enhance OpenCV DNN support and add YOLOX integration
Major changes: - Enhanced OpenCV 4.5.5 recipe with DNN module and protobuf support - Added comprehensive artifact capture for debugging DictValue issues - Implemented YOLOX example integration in package script - Updated setup script with improved error handling and toolkit paths - Added protobuf packages to SDK build dependencies OpenCV enhancements: - Enabled DNN module with proper protobuf linking - Added build-time verification of DNN module compilation - Implemented artifact capture mechanism for debugging - Fixed Python3 bindings configuration Package script improvements: - Added --yolox flag to include YOLOX examples and test data - Implemented comprehensive YOLOX file copying from rknn_model_zoo - Created wrapper scripts for running YOLOX tests - Added validation for YOLOX dependencies Build system updates: - Added python3-opencv and python3-protobuf to SDK - Updated requirements templates with correct versions - Improved error handling in setup script - Added player/ directory to .gitignore Documentation: - Added notes about bsbb command usage in containers - Clarified BrightSign source tree locations - Updated test and validation guidelines 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 7e5c8bc commit 9a6ae38

File tree

14 files changed

+913
-11
lines changed

14 files changed

+913
-11
lines changed

.claude/commands/commit.yml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
name: "Git Commit with Conventional Commits"
2+
description: "Commit the current git tree with a Conventional Commits style message"
3+
4+
args:
5+
- name: "skip_confirmation"
6+
short: "y"
7+
description: "Skip confirmation prompt and commit automatically"
8+
type: "flag"
9+
10+
steps:
11+
- name: "Check git status"
12+
run: |
13+
git status --porcelain
14+
15+
- name: "Generate conventional commit message"
16+
ask_claude: |
17+
Based on the git status output above, please analyze the changes and generate a commit message following the Conventional Commits specification.
18+
19+
The format should be:
20+
<type>[optional scope]: <description>
21+
22+
[optional body]
23+
24+
[optional footer(s)]
25+
26+
Common types:
27+
- feat: A new feature
28+
- fix: A bug fix
29+
- docs: Documentation only changes
30+
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
31+
- refactor: A code change that neither fixes a bug nor adds a feature
32+
- perf: A code change that improves performance
33+
- test: Adding missing tests or correcting existing tests
34+
- build: Changes that affect the build system or external dependencies
35+
- ci: Changes to our CI configuration files and scripts
36+
- chore: Other changes that don't modify src or test files
37+
- revert: Reverts a previous commit
38+
39+
Please provide just the commit message, nothing else.
40+
save_to_var: "commit_message"
41+
42+
- name: "Show proposed commit message"
43+
run: |
44+
echo "Proposed commit message:"
45+
echo "======================="
46+
echo "$commit_message"
47+
echo "======================="
48+
49+
- name: "Confirm and commit"
50+
run: |
51+
if [ "$skip_confirmation" = "true" ]; then
52+
echo "Auto-committing with -y flag..."
53+
git add .
54+
git commit -m "$commit_message"
55+
echo "✅ Committed successfully!"
56+
else
57+
read -p "Do you want to proceed with this commit message? (y/n): " confirm
58+
if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
59+
git add .
60+
git commit -m "$commit_message"
61+
echo "✅ Committed successfully!"
62+
else
63+
echo "❌ Commit cancelled."
64+
fi
65+
fi

.claude/commands/deploy.yml

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
name: "Deploy BrightSign Python Extension"
2+
description: "Deploy latest pydev package to BrightSign player with automatic package detection and user preference memory"
3+
4+
args:
5+
- name: "player_ip"
6+
description: "IP address of BrightSign player"
7+
type: "string"
8+
- name: "password"
9+
description: "SSH password (default: password)"
10+
type: "string"
11+
- name: "destination_path"
12+
description: "Destination path on player (default: /storage/sd/)"
13+
type: "string"
14+
15+
steps:
16+
- name: "Load configuration and find latest package"
17+
run: |
18+
# Load existing configuration
19+
CONFIG_FILE=".deploy_config"
20+
SAVED_IP=""
21+
SAVED_DEST=""
22+
23+
if [ -f "$CONFIG_FILE" ]; then
24+
source "$CONFIG_FILE"
25+
echo "📁 Loaded saved configuration"
26+
fi
27+
28+
# Find latest pydev package
29+
LATEST_PYDEV=$(ls -t pydev-*.zip 2>/dev/null | head -1)
30+
if [ -z "$LATEST_PYDEV" ]; then
31+
echo "❌ No pydev-*.zip files found. Run './package' first."
32+
exit 1
33+
fi
34+
35+
PACKAGE_SIZE=$(ls -lh "$LATEST_PYDEV" | awk '{print $5}')
36+
PACKAGE_DATE=$(ls -l "$LATEST_PYDEV" | awk '{print $6, $7, $8}')
37+
38+
echo "📦 Found latest package: $LATEST_PYDEV"
39+
echo " Size: $PACKAGE_SIZE"
40+
echo " Date: $PACKAGE_DATE"
41+
echo ""
42+
save_to_var: "package_info"
43+
44+
- name: "Handle IP address argument"
45+
run: |
46+
# Determine IP address to use
47+
if [ -n "$player_ip" ]; then
48+
DEPLOY_IP="$player_ip"
49+
echo "🌐 Using provided IP: $DEPLOY_IP"
50+
elif [ -n "$SAVED_IP" ]; then
51+
echo "🌐 Found saved IP: $SAVED_IP"
52+
read -p "Use saved IP $SAVED_IP? (Y/n): " -n 1 -r
53+
echo
54+
if [[ $REPLY =~ ^[Nn]$ ]]; then
55+
read -p "Enter BrightSign player IP: " DEPLOY_IP
56+
else
57+
DEPLOY_IP="$SAVED_IP"
58+
fi
59+
else
60+
read -p "Enter BrightSign player IP: " DEPLOY_IP
61+
fi
62+
63+
# Validate IP format
64+
if ! echo "$DEPLOY_IP" | grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' > /dev/null; then
65+
echo "❌ Invalid IP format: $DEPLOY_IP"
66+
exit 1
67+
fi
68+
69+
echo "✅ Using IP: $DEPLOY_IP"
70+
save_to_var: "ip_handling"
71+
72+
- name: "Handle destination path argument"
73+
run: |
74+
# Determine destination path to use
75+
if [ -n "$destination_path" ]; then
76+
DEPLOY_DEST="$destination_path"
77+
echo "📂 Using provided destination: $DEPLOY_DEST"
78+
elif [ -n "$SAVED_DEST" ]; then
79+
echo "📂 Found saved destination: $SAVED_DEST"
80+
read -p "Use saved destination $SAVED_DEST? (Y/n): " -n 1 -r
81+
echo
82+
if [[ $REPLY =~ ^[Nn]$ ]]; then
83+
read -p "Enter destination path (/storage/sd/): " DEPLOY_DEST
84+
DEPLOY_DEST=${DEPLOY_DEST:-/storage/sd/}
85+
else
86+
DEPLOY_DEST="$SAVED_DEST"
87+
fi
88+
else
89+
read -p "Enter destination path (/storage/sd/): " DEPLOY_DEST
90+
DEPLOY_DEST=${DEPLOY_DEST:-/storage/sd/}
91+
fi
92+
93+
# Ensure destination ends with /
94+
if [[ ! "$DEPLOY_DEST" =~ /$ ]]; then
95+
DEPLOY_DEST="$DEPLOY_DEST/"
96+
fi
97+
98+
echo "✅ Using destination: $DEPLOY_DEST"
99+
save_to_var: "dest_handling"
100+
101+
- name: "Handle password"
102+
run: |
103+
# Set password with default
104+
DEPLOY_PASSWORD="${password:-password}"
105+
echo "🔐 Using password: [hidden]"
106+
save_to_var: "password_handling"
107+
108+
- name: "Check prerequisites and connectivity"
109+
run: |
110+
echo "🔍 Checking prerequisites..."
111+
112+
# Check for sshpass
113+
if ! command -v sshpass &> /dev/null; then
114+
echo "❌ sshpass is required but not installed."
115+
echo " Install with: sudo apt-get install sshpass"
116+
exit 1
117+
fi
118+
119+
# Test connectivity
120+
echo "🏓 Testing connectivity to $DEPLOY_IP..."
121+
if ! ping -c 1 -W 3 "$DEPLOY_IP" &> /dev/null; then
122+
echo "⚠️ Player at $DEPLOY_IP is not responding to ping"
123+
read -p "Continue anyway? (y/N): " -n 1 -r
124+
echo
125+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
126+
echo "❌ Deployment cancelled"
127+
exit 1
128+
fi
129+
else
130+
echo "✅ Player is reachable"
131+
fi
132+
133+
- name: "Deploy package to player"
134+
run: |
135+
echo ""
136+
echo "🚀 Deploying $LATEST_PYDEV to brightsign@$DEPLOY_IP:$DEPLOY_DEST"
137+
echo " Package size: $PACKAGE_SIZE"
138+
echo ""
139+
140+
# Perform the deployment
141+
echo "📤 Starting file transfer..."
142+
if sshpass -p "$DEPLOY_PASSWORD" scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
143+
"$LATEST_PYDEV" brightsign@"$DEPLOY_IP":"$DEPLOY_DEST" 2>/dev/null; then
144+
echo "✅ Package transfer completed successfully!"
145+
else
146+
echo "❌ File transfer failed!"
147+
echo " Check that:"
148+
echo " - Player IP is correct: $DEPLOY_IP"
149+
echo " - Password is correct"
150+
echo " - Player is powered on and connected"
151+
echo " - Destination path exists: $DEPLOY_DEST"
152+
exit 1
153+
fi
154+
155+
- name: "Deploy user-init examples"
156+
run: |
157+
echo ""
158+
echo "📁 Deploying user-init/examples directory..."
159+
160+
# Check if examples directory exists
161+
if [ ! -d "user-init/examples" ]; then
162+
echo "⚠️ user-init/examples directory not found, skipping..."
163+
else
164+
# Count files to be copied
165+
FILE_COUNT=$(find user-init/examples -type f | wc -l)
166+
echo " Found $FILE_COUNT files to copy"
167+
168+
# Create remote directory structure
169+
# First create a marker file to ensure directory creation
170+
echo "# Directory marker" > /tmp/.deploy_marker
171+
REMOTE_INIT_DIR="${DEPLOY_DEST}user-init"
172+
173+
# Try to create the directory by copying marker file
174+
sshpass -p "$DEPLOY_PASSWORD" scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
175+
/tmp/.deploy_marker brightsign@"$DEPLOY_IP":"$REMOTE_INIT_DIR/.marker" 2>/dev/null || {
176+
echo " Creating user-init directory..."
177+
}
178+
rm -f /tmp/.deploy_marker
179+
180+
# Copy all files from examples directory
181+
echo "📤 Copying example files..."
182+
if sshpass -p "$DEPLOY_PASSWORD" scp -r -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
183+
user-init/examples brightsign@"$DEPLOY_IP":"$REMOTE_INIT_DIR/" 2>/dev/null; then
184+
echo "✅ Example files deployed successfully!"
185+
echo " Location: $REMOTE_INIT_DIR/examples/"
186+
187+
# List some of the key files copied
188+
echo ""
189+
echo " Key files deployed:"
190+
echo " - test_cv2_dnn.py (OpenCV DNN test script)"
191+
echo " - debug_cv2_dnn.py (DNN debugging script)"
192+
if [ -f "user-init/examples/requirements.txt" ]; then
193+
echo " - requirements.txt (Python dependencies)"
194+
fi
195+
if [ -f "user-init/examples/01_validate_cv.sh" ]; then
196+
echo " - 01_validate_cv.sh (CV validation script)"
197+
fi
198+
else
199+
echo "⚠️ Failed to copy example files"
200+
echo " This is non-fatal - package was deployed successfully"
201+
echo " You may need to manually copy the examples"
202+
fi
203+
fi
204+
205+
- name: "Save configuration for future use"
206+
run: |
207+
# Save IP and destination for next time
208+
echo "💾 Saving configuration for future use..."
209+
cat > "$CONFIG_FILE" << EOF
210+
# BrightSign Deploy Configuration
211+
# Automatically generated - safe to edit
212+
SAVED_IP="$DEPLOY_IP"
213+
SAVED_DEST="$DEPLOY_DEST"
214+
EOF
215+
echo "✅ Configuration saved to $CONFIG_FILE"
216+
217+
- name: "Show deployment summary and next steps"
218+
run: |
219+
echo ""
220+
echo "🎉 Deployment completed successfully!"
221+
echo ""
222+
echo "=== Deployment Summary ==="
223+
echo "Package: $LATEST_PYDEV ($PACKAGE_SIZE)"
224+
echo "Player: brightsign@$DEPLOY_IP"
225+
echo "Location: $DEPLOY_DEST$(basename $LATEST_PYDEV)"
226+
if [ -d "user-init/examples" ]; then
227+
echo "Examples: ${DEPLOY_DEST}user-init/examples/"
228+
fi
229+
echo ""
230+
echo "=== Next Steps ==="
231+
echo ""
232+
echo "1. SSH to the player:"
233+
echo " ssh brightsign@$DEPLOY_IP"
234+
echo ""
235+
echo "2. Extract the development package:"
236+
echo " cd /usr/local"
237+
echo " unzip $DEPLOY_DEST$(basename $LATEST_PYDEV)"
238+
echo ""
239+
echo "3. Activate the Python environment:"
240+
echo " source sh/pydev-env"
241+
echo " # OR: source sh/setup_python_env"
242+
echo ""
243+
echo "4. Test OpenCV DNN functionality:"
244+
echo " python3 ${DEPLOY_DEST}user-init/examples/test_cv2_dnn.py"
245+
echo " python3 ${DEPLOY_DEST}user-init/examples/debug_cv2_dnn.py"
246+
echo ""
247+
echo "5. Run other example scripts:"
248+
echo " cd ${DEPLOY_DEST}user-init/examples"
249+
echo " ls -la # See all available examples"
250+
echo ""
251+
echo "💡 Note: Development installation is volatile (lost on reboot)"
252+
echo " For permanent installation, use ext_pydev-*.zip instead"
253+
echo ""

.claude/settings.local.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,13 @@
7272
"Bash(diff:*)",
7373
"Bash(sh:*)",
7474
"Bash(git reset:*)",
75-
"Bash(git branch:*)"
75+
"Bash(git branch:*)",
76+
"WebFetch(domain:docs.anthropic.com)",
77+
"Bash(export:*)",
78+
"Bash(source:*)",
79+
"Bash(./run_yolox_test.sh:*)",
80+
"Bash(./brightsign-x86_64-cobra-toolchain-9.1.52.sh:*)",
81+
"Bash(nm:*)"
7682
],
7783
"deny": []
7884
}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ yolo-dev*.zip
1111
brightsign-*-src-*.tar.gz
1212
srv/
1313
tk/
14+
player/
1415

1516
*_requirements.txt
1617

BUGS.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# BUGS in current pydev environment
2+
3+
list of bugs obseved through manual testing. Each bug is prefixed with **BUG**.
4+
5+
## general test setup
6+
7+
1. build and package lastest extension
8+
2. copy to player, expand and install (`bsext_init run`)
9+
3. open a shell and run commands
10+
11+
### Python package import errors
12+
13+
from the shell (busybox) on the player, open the Python interpreter with
14+
15+
```
16+
python3
17+
```
18+
19+
then import packages
20+
21+
**BUG** opencv
22+
23+
```
24+
>>> import cv2
25+
Traceback (most recent call last):
26+
File "<stdin>", line 1, in <module>
27+
File "/usr/local/usr/lib/python3.8/site-packages/cv2/__init__.py", line 181, in <module>
28+
bootstrap()
29+
File "/usr/local/usr/lib/python3.8/site-packages/cv2/__init__.py", line 175, in bootstrap
30+
if __load_extra_py_code_for_module("cv2", submodule, DEBUG):
31+
File "/usr/local/usr/lib/python3.8/site-packages/cv2/__init__.py", line 28, in __load_extra_py_code_for_module
32+
py_module = importlib.import_module(module_name)
33+
File "/usr/local/usr/lib/python3.8/importlib/__init__.py", line 127, in import_module
34+
return _bootstrap._gcd_import(name[level:], package, level)
35+
File "/usr/local/usr/lib/python3.8/site-packages/cv2/typing/__init__.py", line 162, in <module>
36+
LayerId = cv2.dnn.DictValue
37+
AttributeError: module 'cv2.dnn' has no attribute 'DictValue'
38+
>>>
39+
```

0 commit comments

Comments
 (0)