Skip to content

Instantly share code, notes, and snippets.

@rikka0w0
Last active April 30, 2023 02:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rikka0w0/9d134cfd9e68ea772995d876a3363797 to your computer and use it in GitHub Desktop.
Save rikka0w0/9d134cfd9e68ea772995d876a3363797 to your computer and use it in GitHub Desktop.
Use Saleae 16 in Sigrok Pulseview

Use Saleae 16 in Sigrok Pulseview

Ubuntu (Tested on Kubuntu 20.04): sudo apt install -y sigrok pulseview

Steps

  1. Go to http://sigrok.org/gitweb/?p=sigrok-util.git;a=tree;f=firmware/saleae-logic16
  2. Download parseelf.py and sigrok-fwextract-saleae-logic16
  3. Download "Logic 1.2.10 Linux 64-bit"from Saleae and extract the file Logic from the archive to the same folder as the above two files.
  4. (Make sure you have python installed) ./sigrok-fwextract-saleae-logic16 Logic
  5. Copy the generated ".bitstream" and ".fw" files to /usr/share/sigrok-firmware or any other firmware search paths.
  6. Done

Other firmware search paths:

~/.local/share/sigrok-firmware
/usr/share/sigrok-firmware
/usr/share/plasma/sigrok-firmware
/usr/local/share/sigrok-firmware
/usr/share/sigrok-firmware
/var/lib/snapd/desktop/sigrok-firmware

Note

Pulseview does not check the validity of the combination of the sampling rate and the number of enabled channels. It may prompt you with an error when the configuration is invalid, either reducing the sampling frequency or disabling some channels.

References

  1. https://sigrok.org/wiki/WayEngineer_Saleae16
  2. https://sigrok.org/wiki/Saleae_Logic16#Firmware
  3. http://sigrok.org/gitweb/?p=sigrok-util.git;a=tree;f=firmware/saleae-logic16
  4. https://support.saleae.com/logic-software/legacy-software/older-software-releases#1.2.10-download
#!/usr/bin/python3
##
## This file is part of the sigrok-util project.
##
## Copyright (C) 2013 Marcus Comstedt <marcus@mc.pp.se>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, see <http://www.gnu.org/licenses/>.
##
import struct
class elf:
def read_struct(this, struct_fmt, struct_fields):
fmt = this.elf_endianprefix+str.translate(struct_fmt, this.elf_format);
fields = struct.unpack(fmt, this.file.read(struct.calcsize(fmt)))
return dict(zip(struct_fields, fields))
def read_ehdr(this):
return this.read_struct('16sHHWNNNWHHHHHH',
('e_ident', 'e_type', 'e_machine', 'e_version',
'e_entry', 'e_phoff', 'e_shoff', 'e_flags',
'e_ehsize', 'e_phentsize', 'e_phnum',
'e_shentsize', 'e_shnum', 'e_shstrndx'))
def read_shdr(this):
return this.read_struct('WWNNNNWWNN',
('sh_name', 'sh_type', 'sh_flags', 'sh_addr',
'sh_offset', 'sh_size', 'sh_link', 'sh_info',
'sh_addralign', 'sh_entsize'))
def read_section(this, shdr):
this.file.seek(shdr['sh_offset'])
return this.file.read(shdr['sh_size'])
def get_name(this, name, strtab=None):
strtab = strtab or this.strtab
nul = strtab.find(b'\0', name)
if nul < 0:
return bytes.decode(strtab[name:])
else:
return bytes.decode(strtab[name:nul])
def find_section(this, name):
for section in this.shdrs:
if this.get_name(section['sh_name']) == name:
return section
raise KeyError(name)
def parse_symbol(this):
if this.elf_wordsize == 64:
return this.read_struct('WBBHNX',
('st_name', 'st_info', 'st_other',
'st_shndx', 'st_value', 'st_size'))
else:
return this.read_struct('WNWBBH',
('st_name', 'st_value', 'st_size',
'st_info', 'st_other', 'st_shndx'))
def parse_rela(this):
return this.read_struct('NNn', ('r_offset', 'r_info', 'r_addend'))
def parse_rel(this):
return this.read_struct('NN', ('r_offset', 'r_info'))
def fixup_reloc(this, reloc):
if not 'r_addend' in reloc:
reloc['r_addend'] = 0
if this.elf_wordsize == 64:
reloc['r_sym'] = reloc['r_info'] >> 32
reloc['r_type'] = reloc['r_info'] & 0xffffffff
else:
reloc['r_sym'] = reloc['r_info'] >> 8
reloc['r_type'] = reloc['r_info'] & 0xff
return reloc
def parse_symbols(this, symsecname, strsecname):
try:
symsechdr = this.find_section(symsecname)
strsechdr = this.find_section(strsecname)
except KeyError:
return {}
strsec = this.read_section(strsechdr)
this.file.seek(symsechdr['sh_offset'])
syms = [dict(this.parse_symbol(),number=i) for i in
range(0, symsechdr['sh_size'] // symsechdr['sh_entsize'])]
return {this.get_name(sym['st_name'], strsec): sym for sym in syms}
def parse_relocs(this, section):
this.file.seek(section['sh_offset'])
if section['sh_type'] == 4:
relocs = [this.fixup_reloc(this.parse_rela()) for i in
range(0, section['sh_size'] // section['sh_entsize'])]
else:
relocs = [this.fixup_reloc(this.parse_rel()) for i in
range(0, section['sh_size'] // section['sh_entsize'])]
return relocs
def address_to_offset(this, addr):
for section in this.shdrs:
if (section['sh_addr'] <= addr and
section['sh_addr']+section['sh_size'] > addr):
return section['sh_offset']+(addr-section['sh_addr'])
raise IndexError('address out of range')
def load_symbol(this, sym):
this.file.seek(this.address_to_offset(sym['st_value']))
return this.file.read(sym['st_size'])
def __init__(this, filename):
this.file = open(filename, 'rb')
magic = this.file.read(16)
if magic[:4] != b'\x7fELF':
raise Exception("ELF signature not found")
if magic[4] == 1:
this.elf_wordsize = 32
nativeint = 'Ii'
elif magic[4] == 2:
this.elf_wordsize = 64
nativeint = 'Qq'
else:
raise Exception("Invalid ELF file class")
if magic[5] == 1:
this.elf_endianprefix = '<'
elif magic[5] == 2:
this.elf_endianprefix = '>'
else:
raise Exception("Invalid ELF data encoding")
this.elf_format = str.maketrans('HWwXxNn', 'HIiQq'+nativeint)
this.file.seek(0)
this.ehdr = this.read_ehdr()
this.file.seek(this.ehdr['e_shoff'])
this.shdrs = [this.read_shdr() for i in range(this.ehdr['e_shnum'])]
this.strtab = this.read_section(this.shdrs[this.ehdr['e_shstrndx']])
this.symtab = this.parse_symbols('.symtab', '.strtab')
this.dynsym = this.parse_symbols('.dynsym', '.dynstr')
this.relocs = {}
for section in this.shdrs:
if section['sh_type'] == 4 or section['sh_type'] == 9:
rels = {}
symsec = this.shdrs[section['sh_link']]
if this.get_name(symsec['sh_name']) == '.symtab':
rels['symbols'] = this.symtab
elif this.get_name(symsec['sh_name']) == '.dynsym':
rels['symbols'] = this.dynsym
rels['relocs'] = this.parse_relocs(section)
this.relocs[this.get_name(section['sh_name'])] = rels
def __del__(this):
try:
this.file.close()
except AttributeError:
pass
This file has been truncated, but you can view the full file.
View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment