Friday, June 21, 2024

Program for D-Link DCS-5010L

 D-Link DCS-5010L is a pretty old generation Pan & Tilt WIFI network camera. It is so old, only can be accessed with old IE web browser as it needs ActiveX. For Edge, may work by using IE mode. And almost impossible to use Firefox or Chrome browser. And for some feature and function, would need java installed. And it might not work due to old firmware and interface.

D-Link's Android app even cannot connect to the camera. Give up on that as so frustrate. The TinyCam app can view and control the movement of the camera, but cannot change video resolution, codec type, and motion detection setting.

So come to the idea to use Python script to control and view the camera, more flexibility. Later, may think to make my own Android app for the camera. There is github dlink-dcs-python-lib can be used as lib or reference. This lib has unit test code, but does not have stream video viewer code. Github copilot suggests to use opencv-python for video processing and use requests for handling HTTP requests. Code like below, worked quite well:

import cv2
import requests
import numpy as np
import os

CAM_HOST = os.environ.get('CAM_HOST') or ''
CAM_PORT = os.environ.get('CAM_PORT', 80)
CAM_USER = os.getenv('CAM_USER', 'admin')
CAM_PASS = os.getenv('CAM_PASS', '')

# URL of the video stream
stream_url = f'http://{CAM_HOST}:{CAM_PORT}/video.cgi'

# Start a session
session = requests.Session()
response = session.get(stream_url, stream=True, auth=(CAM_USER, CAM_PASS))

# Check if the connection to the stream is successful
if response.status_code == 200:
    bytes_data = bytes()
    for chunk in response.iter_content(chunk_size=1024):
        bytes_data += chunk
        a = bytes_data.find(b'\xff\xd8')  # JPEG start
        b = bytes_data.find(b'\xff\xd9')  # JPEG end
        if a != -1 and b != -1:
            jpg = bytes_data[a:b+2]  # Extract the JPEG image
            bytes_data = bytes_data[b+2:]  # Remove the processed bytes
            frame = cv2.imdecode(np.frombuffer(jpg, dtype=np.uint8), cv2.IMREAD_COLOR)
            if frame is not None:
                cv2.imshow('Video Stream', frame)
                if cv2.waitKey(1) & 0xFF == ord('q'):  # Exit loop if 'q' is pressed
                    break
    cv2.destroyAllWindows()
else:
    print("Failed to connect to the stream.")

Above code is for viewing Motion Jpeg. To view h.264 stream, can use below code:

import cv2
import os

# URL of the H.264 video stream
CAM_HOST = os.environ.get('CAM_HOST') or ''
CAM_PORT = os.environ.get('CAM_PORT', 80)
CAM_USER = os.getenv('CAM_USER', 'admin')
CAM_PASS = os.getenv('CAM_PASS', '')

# URL of the video stream
stream_url = f'http://{CAM_USER}:{CAM_PASS}@{CAM_HOST}:{CAM_PORT}/video.cgi'

# Create a VideoCapture object
cap = cv2.VideoCapture(stream_url)

# Check if camera opened successfully
if not cap.isOpened():
    print("Error: Could not open video stream.")
else:
    # Read until video is completed
    while cap.isOpened():
        # Capture frame-by-frame
        ret, frame = cap.read()
        if ret:
            # Display the resulting frame
            cv2.imshow('Video Stream', frame)

            # Press Q on keyboard to exit
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
        else:
            break

# When everything done, release the video capture object
cap.release()

# Closes all the frames
cv2.destroyAllWindows()

Wednesday, June 19, 2024

Revisit 坦克大战编程

In 2021 I posted two blog regarding building Tank natively with Visual Studio Build tools:

When I trying to redo the build from scratch, I noticed some is missing in my post, for example, there is no 'Build' folder by default. No need of Cygwin. Also, I'm planning to add network support, so player can play the game over internet. So I decide to make another blog to explore this. So here is a complete step by step for creating the build:

  1. Download Visual Studio Build Tools. Go to https://visualstudio.microsoft.com/downloads/?q=build+tools, scroll down and looking for something like Build Tools for Visual Studio 2022. When install, only need select "Desktop Develoment with C++", and for optional modules, the build environment such as MSVC v143 and C++ CMake tools for Windows are needed. All other can be deselected to save some space.
  2. Run "git clone https://github.com/quyq/Tanks.git" in working directory to pull the source code
  3. Install SDL2 header file and lib. SDL2 binary can be download from:
  4. Start a Visual Studio Build Tools environment, and do:
    • create 'build' folder (such as 'mkdir build') under project root
    • change working directory to 'build' (i.e. run 'cd build'), then run:
      • cmake -G "NMake Makefiles" ..
      • Note: the two dots is a must which set the source folder as one level up, and this will create Makefile, out folder and several other files/folder under 'build'
    • Run 'NMake' which should create 'tank.exe' under 'build/out' folder. Resource files would be copied to there too.

For using "NMake Makefiles" generator, update settings.json as:

{
    "terminal.integrated.defaultProfile.windows": "Command Prompt",
    "cmake.generator": "NMake Makefiles",
}

The first line will change default terminal from "Power Shell" to "Command Prompt". The next line select the generator. By default, it will use Visual Studio 16 2019 generator.

Build under WSL might be much easier, just install make/g++ and SDL2 develop package, then run make. If using Win11+WSL2, then no other extra work needed. If running WSL2 on Win10, may need update to latest WSL which has systemd support for GUI. And for audio, may follow instruction from https://x410.dev/cookbook/wsl/enabling-sound-in-wsl-ubuntu-let-it-sing/ which has clear step by step instruction and does not open unnecessary permission for utilizing PulseAudio.

 

Saturday, May 11, 2024

Developing Android App with chart supported by MPAndroidChart

 MPAndroidChart (https://github.com/PhilJay/MPAndroidChart) is a powerful Android chart view / graph view library, supporting line- bar- pie- radar- bubble- and candlestick charts as well as scaling, panning and animations. As Open Source Project, the source code is free available from GitHub. There is general introduction, javadocs, and example code. But I cannot find a user guide document for how to use this lib from an Android project. This project was actively development several years ago. So it is using Java and Gradle Groovy. Unfortunately, latest Android Studio only support Gradle Kotlin, and no longer provides option to select java as language. I was having a lot of problem to run the example code. Also tried following other online example/tutorial using MPAndroidChart, but no luck either. That makes me decide to make this post to write down notes I have.

First, as mentioned here and several other posts, you would need to add 'jitpack.io' to your Project level Gradle file like this:

repositories {
maven { url 'https://jitpack.io' }
}

However, with recent Android Studio created project, if you add above to your root build.gradle file, you will get error like "Build was configured to prefer settings repositories over project repositories but repository 'maven' was added by build file 'build.gradle'". The correct way is adding it to the settings.gradle file like this:

dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}

Second, if the project is using Gradle Kotlin, then would need to update settings.gradle.kts like this:

dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { setUrl("https://jitpack.io") }
}
}

Note, the syntax is different for the two types gradle file.

Wednesday, February 7, 2024

RISC-v on ZC706 Evaluation Board - Part VI: Building fesvr-zynq with Petalinux

 As of RISC-v on ZC706 Evaluation Board - Part V: Running Petalinux, I'm back to square one, need to figure out how to build fesvr-zynq with Petalinux. First, set all environment as I can:

source <path-to-installed-PetaLinux>/settings.sh
source <path-to-installed-PetaLinux>/components/yocto/buildtools/environment-setup-x86_64-petalinux-linux
source <path-to-installed-Xilinx>/Vitis/2022.1/settings64.sh
export PATH=$PATH:<path-to-installed-Xilinx>/Vitis/2022.1/gnu/aarch32/lin/gcc-arm-linux-gnueabi/x86_64-petalinux-linux/usr/bin/arm-xilinx-linux-gnueabi
cd <path-to-fpga-zynq>/zc706 && make fesvr-zynq

Now, it complain:
arm-xilinx-linux-gnueabi-g++ -O2 -std=c++11 -Wall -L fpga-zynq/common/build -lfesvr -Wl,-rpath,/usr/local/lib -I fpga-zynq/common/csrc -I fpga-zynq/testchipip/csrc -I fpga-zynq/rocket-chip/riscv-tools/riscv-fesvr/ -Wl,-rpath,/usr/local/lib  -o fpga-zynq/common/build/fesvr-zynq /mnt/ext4/fpga-zynq/common/csrc/fesvr_zynq.cc fpga-zynq/common/csrc/zynq_driver.cc fpga-zynq/testchipip/csrc/blkdev.cc

Vitis/2022.1/gnu/aarch32/lin/gcc-arm-linux-gnueabi/x86_64-petalinux-linux/usr/lib/arm-xilinx-linux-gnueabi/gcc/arm-xilinx-linux-gnueabi/11.2.0/include/stdint.h:9:16: fatal error: stdint.h: No such file or directory

   9 | # include_next <stdint.h>
     |                ^~~~~~~~~~

Still sounds like some configuration is missing for the build. With export CFLAGS/CPPFLAGS/CXXFLAGS or set them in make cmdline to "-I<path-to-Xilinx>/Vitis/2022.1/gnu/aarch32/lin/gcc-arm-linux-gnueabi/x86_64-petalinux-linux/usr/include" doesn't help either.

Search shows me a link from lowRISC as Building the front-end server:

# set up the RISCV environment variables
# set up the Xilinx environment variables
cd $TOP/riscv-tools/riscv-fesvr
mkdir build_fpga
cd build_fpga
../configure --host=arm-xilinx-linux-gnueabi
make -j$(nproc)

Once compilation has completed, you should find the following files:

ls -l fesvr-zedboard
ls -l libfesvr.so

To copy your new front-end server to the FPGA image:

cd $TOP/fpga-zynq/zedboard
make ramdisk-open
sudo cp $TOP/riscv-tools/riscv-fesvr/build_fpga/fesvr-zedboard \
  ramdisk/home/root/fesvr-zynq
sudo cp $TOP/riscv-tools/riscv-fesvr/build_fpga/libfesvr.so \
  ramdisk/usr/local/lib/libfesvr.so
make ramdisk-close
sudo rm -fr ramdisk

The proxy kernel (pk) used by the FPGA is the same one used in simulation. While not normally necessary, the proxy kernel can be recompiled using the following commands:

cd $TOP/fpga-zynq/zedboard
make ramdisk-open
sudo cp $TOP/riscv-tools/riscv-pk/build/pk ramdisk/home/root/pk
make ramdisk-close
sudo rm -fr ramdisk

lowRISC also has its risc-fesvr build instruction at fpga-zynq/README.md, slightly different from https://github.com/ucb-bar/fpga-zynq. And actually the two would behave same, if I use Xilinx 2016, which create a 'SDK' folder, and after run 'source SDK/2016.2/settings64.sh', 'make fesvr-zynq':

mkdir -p fpga-zynq/common/build
cd fpga-zynq/common/build && \
fpga-zynq/rocket-chip/riscv-tools/riscv-fesvr/configure \
        --host=arm-xilinx-linux-gnueabi
&& \
make libfesvr.so
checking build system type... x86_64-unknown-linux-gnu
checking host system type... arm-xilinx-linux-gnueabi
checking for arm-xilinx-linux-gnueabi-gcc... arm-xilinx-linux-gnueabi-gcc
checking whether the C compiler works... no
configure: error: in `fpga-zynq/common/build':
configure: error: C compiler cannot create executables
See `config.log' for more details

same error as following the lowRISC instructions. Now need to figure out the problem from the config.log file. The log file indicates several warnings for same thing:

fpga-zynq/rocket-chip/riscv-tools/riscv-fesvr/configure: line 2365: ~/SDK/2016.2/gnu/arm/lin/bin/arm-xilinx-linux-gnueabi-gcc: No such file or directory

The gcc compiler does exist, but file ./arm-xilinx-linux-gnueabi-gcc shows:
./arm-xilinx-linux-gnueabi-gcc: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.16, stripped

which means I need to enable 32bit support in WSL as I mentioned in Run Linux on Windows - WSL, by doing:

sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt install gcc:i386 gcc-multilib g++-multilib libc6:i386

With that, finally I'm able to do make fesvr-zynq, fesvr-zynq and libfesvr.so would be generated under fpga-zynq/common/build folder. When copying fesvr-zynq, also need to copy common/build/libfesvr.so to /usr/local/lib on the board. As mentioned in above lowRISC instructions and fpga-zynq, it is possible to recreate the ram disk, however, I'm getting this when trying the commands under WSL: cpio: dev/console: Cannot mknod: Operation not supported. Not sure whether this is WSL limitation or something I have missed. Give up on this for now. So I tried to copy the new executable. For that, might need to get IP from dhcp server if the board is connected to a network. Modifying /etc/network/interfaces with line 'iface eth0 inet dhcp', then do 'ifdown eth0' and 'ifup eth0' will temporarily work as the change of the interfaces file won't survive of a reboot. After successfully get IP from dhcp server, ssh may still not work with error: Unable to negotiate with a.b.c.d port 22: no matching key exchange method found. Their offer: diffie-hellman-group1-sha1,diffie-hellman-group14-sha1. Can try tftp as:

cd ~
tftp -g -r fesvr-zynq tftp_server
cd  /usr/local/lib
tftp -g -r libfesvr.so tftp_server

Now, run fesvr-zynq without argument would get usage print out (with the original fesvr-zynq executable, used to get "ERROR: No cores found" error, same error as running 'fesvr-zynq pk hello'), but still not able to load the bbl or run the hello code.

PS: README.md in fpga-zynq/rocket-chip/riscv-tools/fpga-fesvr shows:

This repository is deprecated; it has been absorbed into the Spike repository (https://github.com/riscv/riscv-isa-sim).


Sunday, February 4, 2024

Use Blink Mini camera without Amazon subscription

Blink Mini is a cheap camera. Auto detection is a bit awkward to me as it always detected change out of the region I set for motion detecting. And after one year, recording video stop working without subscription.

Luckily, there are Open Source solution, using Python, likely are all based off the documentation at: https://github.com/MattTW/BlinkMonitorProtocol

1) https://pypi.org/project/blink-cameras/ I didn't try it as likely the development was paused since May 2019

2) https://pypi.org/project/blinkpy, github: https://github.com/fronzbot/blinkpy.  This library was built with the intention of allowing easy communication with Blink camera systems, specifically to support the Blink component in homeassistant.

Following is note for using blinkpy.

The blinkpy github site has a brief introduction for how to use it. Information at the pypi.org page likely is out-of date, as module 'blinkpy' has no attribute 'Blink'.

When I try the example code from the Readme, I got this: 

Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x00000201A7EE2310>
Unclosed connector
connections: ['[(<aiohttp.client_proto.ResponseHandler object at 0x00000201A7EE6040>, 57822.015)]', '[(<aiohttp.client_proto.ResponseHandler object at 0x00000201A7F22460>, 57822.593)]']
connector: <aiohttp.connector.TCPConnector object at 0x00000201A7EE2370>
Fatal error on SSL transport
protocol: <asyncio.sslproto.SSLProtocol object at 0x00000201A7EE2970>
transport: <_ProactorSocketTransport fd=844 read=<_OverlappedFuture cancelled>>
Traceback (most recent call last):
  File "C:\miniconda3\lib\asyncio\sslproto.py", line 684, in _process_write_backlog
    self._transport.write(chunk)
  File "C:\miniconda3\lib\asyncio\proactor_events.py", line 359, in write
    self._loop_writing(data=bytes(data))
  File "C:\miniconda3\lib\asyncio\proactor_events.py", line 395, in _loop_writing
    self._write_fut = self._loop._proactor.send(self._sock, data)
AttributeError: 'NoneType' object has no attribute 'send'

Sounds like the connection isn't successfully established? Actually it isn't. I added more code to read the camera name and attribute, and all these information can be read back correctly before above error showing up. Likely, above error raised at the closing or exiting. As a comment for aiohttp issues 5941, loop._proactor is None means loop.close() was called before session.close() call.
This is incorrect; and not aiohttp problem.