diff --git a/README.rst b/README.rst index 344ddbf..bf89cfe 100644 --- a/README.rst +++ b/README.rst @@ -78,6 +78,11 @@ Allowing non-root access to the device The file ``udev/99-nuvoton-hid.rules`` contains an example set of rules for setting the device permissions to ``0666``. Copy the file to the directory ``/etc/udev/rules.d/`` to use it. +Autosync time when device connected +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The file ``scripts/evic-usb-rtc-sync.service`` + ``udev/99-nuvoton-hid.rules`` is a example of how to auto sync time + Usage ------- See ``--help`` for more information on a given command. @@ -124,3 +129,33 @@ Use ``--no-verify`` to disable verification for APROM or data flash. To disable :: $ evic-usb upload --no-verify aprom --no-verify dataflash firmware.bin + +Reset the device: + +:: + + $ evic-usb reset + +Dump any part of the flash memory: + +:: + + $ evic-usb fmc-read -o out.bin -s startaddr -l length + +Example to read the parameters flash memory: + +:: + + $ evic-usb fmc-read -o out.bin -s 122880 -l 4096 + +Setup date and time of the device to the current time: + +:: + + $ evic-usb time + +Take a screenshot of the device display: + +:: + + $ evic-usb screenshot -o outfile.[png|jpg|...] diff --git a/evic/cli.py b/evic/cli.py index 9d81038..607e97d 100644 --- a/evic/cli.py +++ b/evic/cli.py @@ -24,6 +24,8 @@ import struct from time import sleep from contextlib import contextmanager +from datetime import datetime +from PIL import Image import click @@ -31,6 +33,7 @@ from .device import DeviceInfo + @contextmanager def handle_exceptions(*exceptions): """Context for handling exceptions.""" @@ -108,6 +111,42 @@ def read_dataflash(dev, verify): return dataflash +def fmc_read(dev, start, len): + """Reads the device data flash. + + Args: + dev: evic.HIDTransfer object. + + Returns: + evic.DataFlash object containing the device data flash. + """ + + # Read the data flash + with handle_exceptions(IOError): + click.echo("Reading data flash...", nl=False) + fmemory = dev.fmc_read(start, len) + + return fmemory + + +def hid_command(dev, cmd, start, len): + """Sends a HID command. + + Args: + dev: evic.HIDTransfer object. + + Returns: + evic.DataFlash object containing the device data flash. + """ + + # Send the command + with handle_exceptions(IOError): + click.echo("Sending command...", nl=False) + fmemory = dev.hid_command(cmd, start, len) + + return fmemory + + def print_device_info(device_info, dataflash): """Prints the device information found from data flash. @@ -237,6 +276,89 @@ def upload(inputfile, encrypted, dataflashfile, noverify): dev.write_aprom(aprom) +@usb.command('upload-ldrom') +@click.argument('inputfile', type=click.File('rb')) +def upload_ldrom(inputfile): + """Upload an LDROM image to the device.""" + + dev = evic.HIDTransfer() + + # Connect the device + connect(dev) + + # Print the USB info of the device + print_usb_info(dev) + + # Read the data flash + dataflash = read_dataflash(dev, False) + + # Get the device info + device_info = dev.devices.get(dataflash.product_id, + DeviceInfo("Unknown device", None, None)) + + # Print the device information + print_device_info(device_info, dataflash) + + # Read the LDROM image + ldrom = evic.APROM(inputfile.read()) + + # Write data flash to the device + with handle_exceptions(IOError): + # Write LDROM to the device + click.echo("Writing LDROM...", nl=False) + dev.write_ldrom(ldrom) + + +@usb.command('reset') +def reset(): + """Resets the device.""" + + dev = evic.HIDTransfer() + + # Connect the device + connect(dev) + + # Restart + click.echo("Restarting the device...", nl=False) + dev.reset() + sleep(2) + click.secho("OK", fg='green', nl=False, bold=True) + + +@usb.command('time') +def time(): + """Sets the device date/time to now.""" + + dev = evic.HIDTransfer() + + # Connect the device + connect(dev) + + # Read the data flash + dataflash = read_dataflash(dev, 1) + + # Get the device info + device_info = dev.devices.get(dataflash.product_id, + DeviceInfo("Unknown device", None, None)) + + # Print the device information + print_device_info(device_info, dataflash) + + # Write data flash to the device + with handle_exceptions(IOError): + click.echo("Writing data flash...", nl=False) + sleep(0.1) + dt = datetime.now() + dataflash.df_year = dt.year + dataflash.df_month = dt.month + dataflash.df_day = dt.day + dataflash.df_hour = dt.hour + dataflash.df_minute = dt.minute + dataflash.df_second = dt.second + dev.write_dataflash(dataflash) + click.secho("OK", fg='green', bold=True) + + @usb.command('upload-logo') @click.argument('inputfile', type=click.File('rb')) @click.option('--invert', '-i', is_flag=True, @@ -329,6 +451,7 @@ def dumpdataflash(output, noverify): device_info = dev.devices.get(dataflash.product_id, DeviceInfo("Unknown device", None, None)) + # Print the device information print_device_info(device_info, dataflash) @@ -338,6 +461,77 @@ def dumpdataflash(output, noverify): output.write(dataflash.array) +@usb.command('fmcread') +@click.option('--output', '-o', type=click.File('wb'), required=True) +@click.option('--start', '-s', type=click.INT, required=True) +@click.option('--length', '-l', type=click.INT, required=True) +def fmcread(output, start, length): + """Write device flash memory to a file.""" + + dev = evic.HIDTransfer() + + # Connect the device + connect(dev) + + # Print the USB info of the device + print_usb_info(dev) + + # Read the data flash + fmemory = fmc_read(dev, start, length) + + # Write the data flash to the file + with handle_exceptions(IOError): + click.echo("Writing flash memory to the file...", nl=False) + output.write(fmemory) + + +@usb.command('hidcmd') +@click.option('--output', '-o', type=click.File('wb'), required=True) +@click.option('--command', '-c', type=click.INT, required=True) +@click.option('--start', '-s', type=click.INT, required=True) +@click.option('--length', '-l', type=click.INT, required=True) +def hidcmd(command, output, start, length): + """Send a HID command to the device.""" + + dev = evic.HIDTransfer() + + # Connect the device + connect(dev) + + # Print the USB info of the device + print_usb_info(dev) + + # Send the command + response = hid_command(dev, command, start, length) + + # Write the data flash to the file + with handle_exceptions(IOError): + click.echo("Writing command response to the file...", nl=False) + output.write(response) + + +@usb.command('screenshot') +@click.option('--output', '-o', type=click.File('wb'), required=True) +def screenshot(output): + """Take a screenshot.""" + + dev = evic.HIDTransfer() + + # Connect the device + connect(dev) + + # Read the screen data + data = dev.read_screen() + + # create the image from screen data + im = Image.fromstring("1",(64,128),bytes(data)) + + # Write the image to the file + with handle_exceptions(IOError): + click.echo("Writing image to the file...", nl=False) + im.save(output,"PNG") + + @usb.command('reset-dataflash') def resetdataflash(): """Reset device data flash.""" diff --git a/evic/dataflash.py b/evic/dataflash.py index 31abb2a..0c61651 100644 --- a/evic/dataflash.py +++ b/evic/dataflash.py @@ -46,6 +46,13 @@ class DataFlash(binstruct.StructTemplate): fw_version = binstruct.Int32Field(256) ldrom_version = binstruct.Int32Field(260) + df_year = binstruct.Int16Field(320) + df_month = binstruct.Int8Field(322) + df_day = binstruct.Int8Field(323) + df_hour = binstruct.Int8Field(324) + df_minute = binstruct.Int8Field(325) + df_second = binstruct.Int8Field(326) + def verify(self, checksum): """Verifies the data flash against given checksum. diff --git a/evic/device.py b/evic/device.py index 0d94545..a5764b7 100644 --- a/evic/device.py +++ b/evic/device.py @@ -56,13 +56,15 @@ class HIDTransfer(object): 'E083': DeviceInfo("eGrip II", None, (64, 40)), 'E092': DeviceInfo("eVic AIO", None, (64, 40)), 'E115': DeviceInfo("eVic VTwo mini", None, (64, 40)), + 'E079': DeviceInfo("eVic VTC Dual", None, (64, 40)), 'E150': DeviceInfo("eVic Basic", None, (64, 40)), + 'E196': DeviceInfo("eVic Primo Mini", None, (64, 40)), 'M011': DeviceInfo("iStick TC100W", None, None), 'M037': DeviceInfo("ASTER", None, (96, 16)), 'M041': DeviceInfo("iStick Pico", None, (96, 16)), 'M045': DeviceInfo("iStick Pico Mega", None, (96, 16)), 'M046': DeviceInfo("iPower", None, (96, 16)), - 'W007': DeviceInfo("Presa TC75W", ['E052'], None), + 'W007': DeviceInfo("Presa TC75W", ['E052'], (64,40)), 'W010': DeviceInfo("Classic", None, None), 'W011': DeviceInfo("Lite", None, None), 'W013': DeviceInfo("Stout", None, None), @@ -161,6 +163,48 @@ def read_dataflash(self): return (dataflash, checksum) + def fmc_read(self, start, length): + """Reads the device flash memory. + + Returns: + An array containing the data flash memory content. + """ + + # Send the command for reading the data flash + self.send_command(0xC0, start, length) + + # Read the dataflash + buf = self.read(length) + return (buf) + + def hid_command(self, cmd, start, length): + """Send a HID command to the device. + + Returns: + An array containing command response. + """ + + # Send the command for reading the data flash + self.send_command(cmd, start, length) + + # Read the response + buf = self.read(length) + return (buf) + + def read_screen(self): + """Reads the screen memory. + + Returns: + An array containing the screen. + """ + + # Send the command for reading the screen buffer + self.send_command(0xC1, 0, 0x400) + + # Read the data + buf = self.read(0x400) + return (buf) + def write(self, data): """Writes data to the device. @@ -266,6 +310,17 @@ def write_flash(self, data, start): self.write(data) + def write_ldflash(self, data): + """Writes data to the flash memory. + """ + + end = len(data) + + # Send the command for writing the data + self.send_command(0x3C, 0x100000, end) + + self.write(data) + def write_aprom(self, aprom): """Writes the APROM to the device. @@ -275,6 +330,15 @@ def write_aprom(self, aprom): self.write_flash(aprom.data, 0) + def write_ldrom(self, ldrom): + """Writes the LDROM to the device. + + Args: + aprom: A BinFile object containing an unencrypted LDROM image. + """ + + self.write_ldflash(ldrom.data) + def write_logo(self, logo): """Writes the logo to the the device. diff --git a/scripts/evic-usb-rtc-sync.service b/scripts/evic-usb-rtc-sync.service new file mode 100644 index 0000000..e756dd2 --- /dev/null +++ b/scripts/evic-usb-rtc-sync.service @@ -0,0 +1,6 @@ +[Unit] +Description=Evic RTC sync + +[Service] +ExecStart=/bin/bash -c 'lsusb -d 0416:5020 && evic-usb time' +RemainAfterExit=yes diff --git a/udev/99-nuvoton-hid.rules b/udev/99-nuvoton-hid.rules index 0ee1b6f..6c6a9bb 100644 --- a/udev/99-nuvoton-hid.rules +++ b/udev/99-nuvoton-hid.rules @@ -3,3 +3,6 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="0416", ATTRS{idProduct}=="5020", MODE="0666" # HIDAPI/hidraw KERNEL=="hidraw*", ATTRS{busnum}=="1", ATTRS{idVendor}=="0416", ATTRS{idProduct}=="5020", MODE="0666" + +# HIDAPI/libusb RTC Sync +ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="0416", ATTRS{idProduct}=="5020", RUN+="/usr/bin/systemctl restart evic-usb-rtc-sync"