You can subscribe to this list here.
2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(11) |
Jul
(15) |
Aug
(2) |
Sep
(14) |
Oct
(9) |
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2009 |
Jan
(2) |
Feb
(3) |
Mar
(6) |
Apr
|
May
(2) |
Jun
(5) |
Jul
|
Aug
(2) |
Sep
|
Oct
|
Nov
|
Dec
(2) |
2010 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
(3) |
Sep
|
Oct
|
Nov
|
Dec
(2) |
From: <srw...@us...> - 2010-12-26 05:36:41
|
Revision: 83 http://congruity.svn.sourceforge.net/congruity/?rev=83&view=rev Author: srwarren Date: 2010-12-26 05:36:33 +0000 (Sun, 26 Dec 2010) Log Message: ----------- Tag congruity-15; forgot to actually check in the tag when the release was made Added Paths: ----------- tags/congruity-15/ tags/congruity-15/Changelog tags/congruity-15/congruity Removed Paths: ------------- tags/congruity-15/Changelog tags/congruity-15/congruity Deleted: tags/congruity-15/Changelog =================================================================== --- trunk/Changelog 2009-12-17 04:14:53 UTC (rev 77) +++ tags/congruity-15/Changelog 2010-12-26 05:36:33 UTC (rev 83) @@ -1,151 +0,0 @@ -* 2009-12-16 Stephen Warren <s-t...@ww...> -- congruity-14 is released -- replace remote.png with a GPL-licensed version provided by - Mathieu Trudel-Lapierre <mat...@gm...> -- Tweak WrappedStaticText.UpdateText so it shows all text and doesn't wrap it - strangely, at least with Jaunty's wxpython 2.8.9.1-0ubuntu6. - -* 2009-08-04 Stephen Warren <s-t...@ww...> -- congruity-13 is released -- Update MIME types in .desktop file - Patch by Adam Williamson <awi...@re...> - - Apparently, these new MIME types match what the Logitech server sends - when you perform a download: - https://bugzilla.redhat.com/show_bug.cgi?id=506536#c12 - - However, Fedora still packages definitions of these MIME types as part of - libconcord. Packagers for other distributions should double-check the - Fedora packaging of libconcord; see file libconcord-0.21-mime-type-def.patch - which adds file concordance-0.21/libconcord/libconcord.xml to the - libconcord sources. - -* 2009-06-17 Stephen Warren <s-t...@ww...> -- congruity-12 is released -- Add congruity.desktop to release script - -* 2009-06-17 Stephen Warren <s-t...@ww...> -- congruity-11 is released -- Fix Pronto hex import - Patch by Andreas Schulz <And...@gm...> -- Throw runtime error dialog if wxPython version is not at least 2.8 -- Add .desktop file - Patch by Adam Williamson <awi...@re...> - -* 2009-03-09 Stephen Warren <s-t...@ww...> -- congruity-10 is released -- Implement IR learning feature, with support for learning from the original - remote using the Harmony, or reading the signal from a "Pronto Hex" file. - (Merge of /branches/irlean) - Parts based on code by Andreas Schulz <And...@gm...> -- Various internal code changes to support IR learning and general cleanup. -- Implement --no-web command-line option, which prevents posting any data - to the Harmony website. This can be useful when testing congruity. -- Change default install prefix to /usr/local; this makes typical end-user - manual installs slightly simpler. Also, automatically patch install location - into the app during installation. -- If libconcord import fails, display the entire backtrace information, to - enable easier debugging of the issue. -- Enhance README - -* 2008-09-07 Stephen Warren <s-t...@ww...> -- congruity-9 is released -- Use a different remote.png, with a known free license. - -* 2008-07-03 Stephen Warren <s-t...@ww...> -- congruity-8 is released -- Centralize cancel/exit handling, - and clean up any libconcord resources when exiting the application. -- Add thread-safe cancelling to ConnectPanel. -- Work around a typo in libconcord 0.20's Python bindings. -- Provide a GUI message if libconcord can't be loaded, in case congruity - wasn't run from a terminal. - -* 2008-07-02 Stephen Warren <s-t...@ww...> -- Increase connect timeout after a reset operation, just to make sure - we don't miss the remote coming back. -- Fix Makefile to create all directories files are written to, and add - a few more variables that can be tweaked e.g. by packaging scripts. -* On behalf of Andreas Schulz <And...@gm...> -- Use a simpler and potentially more reliable fix for GTK buttons not - accepting clicks if the mouse was inside the widget when enabled. - -* 2008-07-01 Stephen Warren <s-t...@ww...> -- Command-line parsing errors are displayed by the GUI, instead of being - echo'd to stdout. This makes errors visible when congruity is launched - without a terminal - -* 2008-06-25..2008-07-01 Stephen Warren <s-t...@ww...> -* Inspired by Andreas Schulz <And...@gm...> -- Significant internal structural changes to the implementation, which - simplify things a lot, and make program flow far more obvious, localized, - and correctly polymorphic. -- Add a separate "connect" page, so that the other pages don't have to - re-implement this common function. - -* 2008-06-17 Stephen Warren <s-t...@ww...> -* On behalf of Andreas Schulz <And...@gm...> -- Fix issue where next button wouldn't respond to clicks if the pointer was - already within the button when it was re-enabled. - -* 2008-04-14 Stephen Warren <s-t...@ww...> -- congruity-7 is released -- Switched license to GPLv3+ to be compatible with libconcord by default. - Contact me if you want the code under a different license, but please - note that you won't be able to use relicensed code with libconcord. -- Added a Makefile for easy installation. - Thanks to Phil Dibowitz for the contribution. -- Added a manual page. -- Added a few useful URLs to README.txt. -- Fixed reliance on syntax specific to Python 2.5. - -* 2008-04-13 Stephen Warren <s-t...@ww...> -- congruity-6 is released -- Search for images in /usr/share/congruity, the source directory, then - CWD. This should allow easy system-wide installation of congruity. -- libconcord.py is no longer distributed with congruity; it is now part - of libconcord itself (see libconcord/bindings/python/). -- Apparently forgot to release LICENSE.txt before. - -* 2008-04-07 Stephen Warren <s-t...@ww...> -- congruity-5 is released -- This release solely operates using libconcord; "screen-scraping" the output - from the concordance application is no longer supported. -- Implement firmware upgrade. -- Minor tweaks for operation on MS-Windows. -- congruity now sets the time on the remote after any reboot. - -* 2008-03-29 Stephen Warren <s-t...@ww...> -- congruity-4 is released -- Renamed package from harmonygui to congruity, in line with the - coming rename of the harmonycontrol project to concordance/libconcord. -- Changes to match latest CVS libconcord API changes - -* 2008-02-24 Stephen Warren <s-t...@ww...> -- harmonygui-3 is released -- Added README.txt. -- Added LICENSING.txt, to account for images too. -- Remove GUI for initial web connection in update mode; the libharmony - branch code doesn't print this status information, so now we act like - it was never there. -- Code re-org, to allow for multiple back-ends. -- Added a back-end that calls libharmony.so directly using ctypes. - -* 2008-02-10 Stephen Warren <s-t...@ww...> -- harmonygui-2 is released -- Updated ezhexparser to recognize firmware update files. -- Updated GUI to handle firmware updates, by informing user its - not yet supported. -- Separated ezhexparser and tuiparser operation mode enumerations. -- Enhanced ptyrun error handling, so it's more obvious what happened - when the harmony application can't be found in the $PATH. -- Updated harmonyfake to use ^H characters to re-write output, not - \r. This matches the real harmony app. -- Minor typo cleanups in messages. -- Added licensing information. -- Added this Changelog - -* 2008-02-05 Stephen Warren <s-t...@ww...> -- harmonygui-1 is released -- Initial release. - Copied: tags/congruity-15/Changelog (from rev 79, trunk/Changelog) =================================================================== --- tags/congruity-15/Changelog (rev 0) +++ tags/congruity-15/Changelog 2010-12-26 05:36:33 UTC (rev 83) @@ -0,0 +1,157 @@ +* 2010-08-01 Stephen Warren <s-t...@ww...> +- congruity-15 is released +- Call new APIs in libconcord-0.22, for Harmony 700 support. +- Tweak WrappedStaticText.UpdateText again, so it shows all text and doesn't + wrap it strangely, at least with Lucids's wxpython 2.8.10.1-0ubuntu1. + +* 2009-12-16 Stephen Warren <s-t...@ww...> +- congruity-14 is released +- replace remote.png with a GPL-licensed version provided by + Mathieu Trudel-Lapierre <mat...@gm...> +- Tweak WrappedStaticText.UpdateText so it shows all text and doesn't wrap it + strangely, at least with Jaunty's wxpython 2.8.9.1-0ubuntu6. + +* 2009-08-04 Stephen Warren <s-t...@ww...> +- congruity-13 is released +- Update MIME types in .desktop file + Patch by Adam Williamson <awi...@re...> + + Apparently, these new MIME types match what the Logitech server sends + when you perform a download: + https://bugzilla.redhat.com/show_bug.cgi?id=506536#c12 + + However, Fedora still packages definitions of these MIME types as part of + libconcord. Packagers for other distributions should double-check the + Fedora packaging of libconcord; see file libconcord-0.21-mime-type-def.patch + which adds file concordance-0.21/libconcord/libconcord.xml to the + libconcord sources. + +* 2009-06-17 Stephen Warren <s-t...@ww...> +- congruity-12 is released +- Add congruity.desktop to release script + +* 2009-06-17 Stephen Warren <s-t...@ww...> +- congruity-11 is released +- Fix Pronto hex import + Patch by Andreas Schulz <And...@gm...> +- Throw runtime error dialog if wxPython version is not at least 2.8 +- Add .desktop file + Patch by Adam Williamson <awi...@re...> + +* 2009-03-09 Stephen Warren <s-t...@ww...> +- congruity-10 is released +- Implement IR learning feature, with support for learning from the original + remote using the Harmony, or reading the signal from a "Pronto Hex" file. + (Merge of /branches/irlean) + Parts based on code by Andreas Schulz <And...@gm...> +- Various internal code changes to support IR learning and general cleanup. +- Implement --no-web command-line option, which prevents posting any data + to the Harmony website. This can be useful when testing congruity. +- Change default install prefix to /usr/local; this makes typical end-user + manual installs slightly simpler. Also, automatically patch install location + into the app during installation. +- If libconcord import fails, display the entire backtrace information, to + enable easier debugging of the issue. +- Enhance README + +* 2008-09-07 Stephen Warren <s-t...@ww...> +- congruity-9 is released +- Use a different remote.png, with a known free license. + +* 2008-07-03 Stephen Warren <s-t...@ww...> +- congruity-8 is released +- Centralize cancel/exit handling, + and clean up any libconcord resources when exiting the application. +- Add thread-safe cancelling to ConnectPanel. +- Work around a typo in libconcord 0.20's Python bindings. +- Provide a GUI message if libconcord can't be loaded, in case congruity + wasn't run from a terminal. + +* 2008-07-02 Stephen Warren <s-t...@ww...> +- Increase connect timeout after a reset operation, just to make sure + we don't miss the remote coming back. +- Fix Makefile to create all directories files are written to, and add + a few more variables that can be tweaked e.g. by packaging scripts. +* On behalf of Andreas Schulz <And...@gm...> +- Use a simpler and potentially more reliable fix for GTK buttons not + accepting clicks if the mouse was inside the widget when enabled. + +* 2008-07-01 Stephen Warren <s-t...@ww...> +- Command-line parsing errors are displayed by the GUI, instead of being + echo'd to stdout. This makes errors visible when congruity is launched + without a terminal + +* 2008-06-25..2008-07-01 Stephen Warren <s-t...@ww...> +* Inspired by Andreas Schulz <And...@gm...> +- Significant internal structural changes to the implementation, which + simplify things a lot, and make program flow far more obvious, localized, + and correctly polymorphic. +- Add a separate "connect" page, so that the other pages don't have to + re-implement this common function. + +* 2008-06-17 Stephen Warren <s-t...@ww...> +* On behalf of Andreas Schulz <And...@gm...> +- Fix issue where next button wouldn't respond to clicks if the pointer was + already within the button when it was re-enabled. + +* 2008-04-14 Stephen Warren <s-t...@ww...> +- congruity-7 is released +- Switched license to GPLv3+ to be compatible with libconcord by default. + Contact me if you want the code under a different license, but please + note that you won't be able to use relicensed code with libconcord. +- Added a Makefile for easy installation. + Thanks to Phil Dibowitz for the contribution. +- Added a manual page. +- Added a few useful URLs to README.txt. +- Fixed reliance on syntax specific to Python 2.5. + +* 2008-04-13 Stephen Warren <s-t...@ww...> +- congruity-6 is released +- Search for images in /usr/share/congruity, the source directory, then + CWD. This should allow easy system-wide installation of congruity. +- libconcord.py is no longer distributed with congruity; it is now part + of libconcord itself (see libconcord/bindings/python/). +- Apparently forgot to release LICENSE.txt before. + +* 2008-04-07 Stephen Warren <s-t...@ww...> +- congruity-5 is released +- This release solely operates using libconcord; "screen-scraping" the output + from the concordance application is no longer supported. +- Implement firmware upgrade. +- Minor tweaks for operation on MS-Windows. +- congruity now sets the time on the remote after any reboot. + +* 2008-03-29 Stephen Warren <s-t...@ww...> +- congruity-4 is released +- Renamed package from harmonygui to congruity, in line with the + coming rename of the harmonycontrol project to concordance/libconcord. +- Changes to match latest CVS libconcord API changes + +* 2008-02-24 Stephen Warren <s-t...@ww...> +- harmonygui-3 is released +- Added README.txt. +- Added LICENSING.txt, to account for images too. +- Remove GUI for initial web connection in update mode; the libharmony + branch code doesn't print this status information, so now we act like + it was never there. +- Code re-org, to allow for multiple back-ends. +- Added a back-end that calls libharmony.so directly using ctypes. + +* 2008-02-10 Stephen Warren <s-t...@ww...> +- harmonygui-2 is released +- Updated ezhexparser to recognize firmware update files. +- Updated GUI to handle firmware updates, by informing user its + not yet supported. +- Separated ezhexparser and tuiparser operation mode enumerations. +- Enhanced ptyrun error handling, so it's more obvious what happened + when the harmony application can't be found in the $PATH. +- Updated harmonyfake to use ^H characters to re-write output, not + \r. This matches the real harmony app. +- Minor typo cleanups in messages. +- Added licensing information. +- Added this Changelog + +* 2008-02-05 Stephen Warren <s-t...@ww...> +- harmonygui-1 is released +- Initial release. + Deleted: tags/congruity-15/congruity =================================================================== --- trunk/congruity 2009-12-17 04:14:53 UTC (rev 77) +++ tags/congruity-15/congruity 2010-12-26 05:36:33 UTC (rev 83) @@ -1,1959 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2008 Stephen Warren -# -# This file is part of congruity. -# -# congruity 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. -# -# congruity 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 congruity. If not, see <http://www.gnu.org/licenses/>. - -from ctypes import * -import os -import os.path -import sys -import thread -import time -import traceback - -import wxversion -wxversion.ensureMinimal('2.8') -import wx -import wx.lib.dialogs - -version = "14" - -try: - import libconcord -except: - str = traceback.format_exc() - app = wx.PySimpleApp() - dlg = wx.MessageDialog( - None, - "Could not load libconcord; please ensure it, and the Python " - "bindings, are installed and in the relevant search paths.\n\n" + str, - "congruity: Dependency Error", - wx.OK | wx.ICON_ERROR - ) - dlg.ShowModal() - os._exit(1) - -# Fix typo in libconcord 0.20 Python bindings -try: - libconcord.delete_blob -except: - libconcord.delete_blob = libconcord.delete_block - -# Ensure error constants are available -try: - libconcord.LC_ERROR_INVALID_CONFIG -except: - libconcord.LC_ERROR_INVALID_CONFIG = 16 - -# Detect new IR learning API -try: - libconcord.get_key_names - libconcord.delete_key_names - libconcord.learn_from_remote - libconcord.delete_ir_signal - libconcord.encode_for_posting - libconcord.delete_encoded_signal - libconcord.post_new_code - libconcord.LC_FILE_TYPE_LEARN_IR - can_learn_ir = True -except: - can_learn_ir = False - -def counter(): - i=0 - while True: - yield i - i += 1 - -def program_callback_imp(count, current, total, context): - if not context: - return - - try: - (f, fcontext) = context - percent = (current * 100) / total - f(False, percent, fcontext) - except: - print - traceback.print_exc() - -class CmdLineException(Exception): - pass - -def exception_message(): - msg = '' - if type(sys.exc_value) == libconcord.LibConcordException: - try: - msg += '%s\n (libconcord function %s error %d)\n\n' % ( - sys.exc_value.result_str, - sys.exc_value.func, - sys.exc_value.result - ) - except: - pass - if type(sys.exc_value) == CmdLineException: - try: - msg += '%s\n\n' % ( - str(sys.exc_value) - ) - except: - pass - msg += traceback.format_exc() - return msg - -def worker_body_connect( - resources, - on_progress, - cb_context, - cancel_check, - after_reset -): - program_callback = libconcord.callback_type(program_callback_imp) - - max_attempts = after_reset and 180 or 60 - for attempt in range(max_attempts): - on_progress( - False, - (attempt * 100) / max_attempts, - cb_context - ) - try: - libconcord.init_concord() - resources.SetConnected(True) - try: - libconcord.get_identity( - program_callback, - None - ) - except: - ignore = False - if type(sys.exc_value) == libconcord.LibConcordException: - ignore = sys.exc_value.result == libconcord.LC_ERROR_INVALID_CONFIG - if not ignore: - raise - break - except: - if cancel_check() or (attempt == max_attempts - 1): - raise - time.sleep(1) - on_progress( - True, - 100, - cb_context - ) - -def show_modal_scrolled_msgbox(parent, title, text): - size = parent.GetClientSizeTuple() - size = (size[0] * 90 / 100, size[1] * 90 / 100) - wx.lib.dialogs.ScrolledMessageDialog( - parent, - text, - title, - (-1, -1), - size - ).ShowModal() - -ALIGN_LTA = wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.ALL -ALIGN_XTA = wx.EXPAND | wx.ALIGN_TOP | wx.ALL -ALIGN_LCA = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL -ALIGN_RCA = wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.ALL -ALIGN_XCA = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL -ALIGN_LBA = wx.ALIGN_LEFT | wx.ALIGN_BOTTOM | wx.ALL -ALIGN_XBA = wx.EXPAND | wx.ALIGN_BOTTOM | wx.ALL - -class WrappedStaticText(wx.StaticText): - def __init__(self, parent): - self.parent = parent - wx.StaticText.__init__(self, parent, -1, "") - - def UpdateText(self, new_label): - cur_width = self.parent.GetSize().GetWidth() - self.SetLabel(new_label) - self.Wrap(cur_width) - self.Layout() - -class DecoratedContainer(wx.Panel): - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.GridBagSizer(5, 5) - self.sizer.AddGrowableCol(2) - self.SetSizer(self.sizer) - - self.last_updated_dg = None - - def _DgStart(self, dg): - self._OnProgressGauge(False, 0, dg) - - def _DgUpdate(self, is_done, percent, dg): - self._OnProgressGauge(is_done, percent, dg) - - def _DgEnd(self, dg): - self._OnProgressGauge(True, 100, dg) - - def _DgFailure(self): - if self.last_updated_dg: - self.last_updated_dg.SetBitmap(self.resources.icon_failed) - - def _OnProgressGauge(self, is_done, percent, dg): - if is_done: - new_bitmap = self.resources.icon_complete - else: - new_bitmap = self.resources.icon_in_progress - dg.SetBitmap(new_bitmap) - dg.gauge.SetValue(percent) - self.last_updated_dg = dg - -class DecoratedContainerThreadMixin(object): - def __init__(self, dc): - self.dc = dc - - def _DgStart(self, dg): - wx.CallAfter(self.dc._DgStart, dg) - - def _DgUpdate(self, is_done, percent, dg): - wx.CallAfter(self.dc._DgUpdate, is_done, percent, dg) - - def _DgEnd(self, dg): - wx.CallAfter(self.dc._DgEnd, dg) - - def _DgFailure(self): - wx.CallAfter(self.dc._DgFailure) - -class DecoratedGauge(object): - def __init__(self, parent, caption, vpos): - self.current_bitmap = parent.resources.icon_unstarted - self.bitmap = wx.StaticBitmap( - parent, - -1, - self.current_bitmap, - None, - parent.resources.iwh - ) - self.text = wx.StaticText(parent, -1, caption) - self.gauge = wx.Gauge( - parent, - -1, - 100, - None, - (250, parent.resources.iwh[1]) - ) - parent.sizer.Add(self.bitmap, (vpos, 0), (1, 1), ALIGN_LBA, 5) - parent.sizer.Add(self.text, (vpos, 1), (1, 1), ALIGN_LCA, 5) - parent.sizer.Add(self.gauge, (vpos, 2), (1, 1), ALIGN_XBA, 5) - - def SetBitmap(self, new_bitmap): - if self.current_bitmap == new_bitmap: - return - self.current_bitmap = new_bitmap - self.bitmap.SetBitmap(self.current_bitmap) - -class WizardPanelBase(wx.Panel): - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - def OnActivated(self, prev_page, data): - return (None, None) - - def OnCancel(self): - self.parent.OnExit(1) - - def GetTitle(self): - return "Base" - - def IsTerminal(self): - return False - - def IsBackInitiallyDisabled(self): - return True - - def IsNextInitiallyDisabled(self): - return True - - def IsCloseInitiallyDisabled(self): - return True - - def IsCancelInitiallyDisabled(self): - return True - - def GetExitCode(self): - return 0 - - def GetBack(self): - return (None, None) - - def GetNext(self): - return (None, None) - -class MessagePanelBase(WizardPanelBase): - def __init__(self, parent, resources): - WizardPanelBase.__init__(self, parent, resources) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.text_message = WrappedStaticText(self) - self.sizer.Add(self.text_message, 0, ALIGN_XTA, 5) - self.SetSizerAndFit(self.sizer) - -class WelcomePanel(MessagePanelBase): - _msg_welcome = ( - "Welcome to congruity; a programming application " + - "for Logitech Harmony remote controls.\n\n" - ) - - _msg_progress_parsing = ( - "Please wait while the configuration file is parsed." - ) - - _msg_status_ok = ( - "Please ensure the remote control is connected " + - "before proceeding.\n\n" + - "Click next to begin operation." - ) - - _msg_status_failure = ( - "A problem occurred. Click next for details." - ) - - _msg_failure_explanation = ( - "The configuration file cannot be read, or parsing failed.\n\n" + - "Operation cannot continue." - ) - - _msg_failure_details_unknown_op = ( - "Unrecognized file type '%d' returned by libconcord" - ) - - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - MessagePanelBase.__init__(self, parent, resources) - - self.next = None - self.initial_exception = None - - def _WorkerFunction(self): - try: - wx.CallAfter( - self.text_message.UpdateText, - self._msg_welcome + self._msg_progress_parsing - ) - - if self.initial_exception: - wx.CallAfter( - self._OnStatusFailure, - *self.initial_exception - ) - return - - self.next = self.resources.page_connect - - xml = POINTER(c_ubyte)() - xml_size = c_uint() - libconcord.read_file( - self.resources.ezhex_filename, - byref(xml), - byref(xml_size) - ) - self.resources.SetXmlData(xml, xml_size) - - type = c_int() - libconcord.identify_file(xml, xml_size, byref(type)) - - next_map = { - libconcord.LC_FILE_TYPE_CONNECTIVITY: - ( - self.resources.page_check_connectivity, - "Connectivity Check" - ), - libconcord.LC_FILE_TYPE_CONFIGURATION: - ( - self.resources.page_write_configuration, - "Update Configuration" - ), - libconcord.LC_FILE_TYPE_FIRMWARE: - ( - self.resources.page_update_firmware, - "Update Firmware" - ) - } - if can_learn_ir: - next_map[libconcord.LC_FILE_TYPE_LEARN_IR] = ( - self.resources.page_learn_ir_prep, - "Learn IR Codes" - ) - - (next_page, type_text) = next_map.get(type.value, (None, None)) - - if not next_page: - wx.CallAfter( - self._OnStatusFailure, - self._msg_failure_explanation, - self._msg_failure_details_unknown_op % type.value - ) - return - - next_page.DoParsing() - - wx.CallAfter(self._OnStatusOk, next_page, type_text) - except: - wx.CallAfter( - self._OnStatusFailure, - self._msg_failure_explanation, - exception_message() - ) - - def _OnStatusOk(self, next_page, type_text): - self.resources.page_connect.SetNext(next_page) - self._OnStatusCommon(self._msg_status_ok) - - def _OnStatusFailure(self, failure_msg, details): - self.resources.page_failure.SetMessages( - failure_msg, - details - ) - self.next = self.resources.page_failure - self._OnStatusCommon(self._msg_status_failure) - - def _OnStatusCommon(self, message): - self.text_message.UpdateText(self._msg_welcome + message) - self.parent.ReenableCancel() - self.parent.ReenableNext() - - def SetInitialException(self, initial_exception): - self.initial_exception = initial_exception - - def OnActivated(self, prev_page, data): - thread.start_new_thread(self._WorkerFunction, ()) - return (None, None) - - def GetTitle(self): - return "Welcome" - - def IsCancelInitiallyDisabled(self): - return False - - def GetNext(self): - return (self.next, None) - -class ConnectPanel(WizardPanelBase, DecoratedContainerThreadMixin): - _msg_ensure_connected = ( - "Please ensure your remote is correctly connected to your computer." - ) - - _msg_status_ok = ( - "Successfully connected to a remote:\n%s" - ) - - _msg_status_failure = ( - "A problem occurred. Click next for details." - ) - - _msg_failure_explanation = ( - "No remote could be found." - ) - - def __init__(self, parent, resources): - WizardPanelBase.__init__(self, parent, resources) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - - self.text_help = WrappedStaticText(self) - self.sizer.Add(self.text_help, 0, wx.EXPAND | wx.ALL, 5) - - self.dc = DecoratedContainer(self, self.resources) - DecoratedContainerThreadMixin.__init__(self, self.dc) - self.dg_connect = DecoratedGauge(self.dc, "Detect Remote", 0) - self.sizer.Add(self.dc, 0, wx.EXPAND | wx.ALL, 5) - - self.text_info = WrappedStaticText(self) - self.sizer.Add(self.text_info, 0, wx.EXPAND | wx.ALL, 5) - - self.btn_details = wx.Button(self, -1, "&Details...") - self.sizer.Add(self.btn_details, 0, ALIGN_LTA, 5) - self.Bind(wx.EVT_BUTTON, self._OnDetails, self.btn_details) - - self.text_full_details = wx.TextCtrl( - self, - -1, - style = wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL - ) - self.sizer.Add(self.text_full_details, 1, ALIGN_XTA, 5) - - self.SetSizerAndFit(self.sizer) - - self.next = None - self.finished = False - self.cancelled = False - - self.lock = thread.allocate_lock() - - def _WorkerFunction(self): - try: - wx.CallAfter( - self.text_help.UpdateText, - self._msg_ensure_connected - ) - - self._DgStart(self.dg_connect) - worker_body_connect( - self.resources, - self._DgUpdate, - self.dg_connect, - lambda: self.cancelled, - False - ) - self._DgEnd(self.dg_connect) - - mfg = libconcord.get_mfg() - model = libconcord.get_model() - - mfg_model = mfg + " " + model - wx.CallAfter(self._OnStatusOk, mfg_model) - except: - wx.CallAfter( - self._OnStatusFailure, - self._msg_failure_explanation, - exception_message() - ) - - self.lock.acquire() - self.finished = True - if self.cancelled: - wx.CallAfter(self.OnCancel) - self.lock.release() - - def _OnStatusOk(self, mfg_model): - self.btn_details.Show() - self._OnStatusCommon(self._msg_status_ok % mfg_model) - - def _OnStatusFailure(self, failure_msg, details): - self.dc._DgFailure() - self.resources.page_failure.SetMessages( - failure_msg, - details - ) - self.SetNext(self.resources.page_failure) - self._OnStatusCommon(self._msg_status_failure) - - def _OnStatusCommon(self, message): - self.text_info.UpdateText(message) - self.parent.ReenableNext() - - def _OnDetails(self, event): - try: - msg = "" - - mfg = libconcord.get_mfg() - model = libconcord.get_model() - codename = libconcord.get_codename() - msg += "Model: %s %s (%s)\n" % (msg, model, codename) - - hid_mfg = libconcord.get_hid_mfg_str() - hid_prod = libconcord.get_hid_prod_str() - msg += "USB HID Model: %s %s\n" % (hid_mfg, hid_prod) - - ser_1 = libconcord.get_serial(libconcord.SERIAL_COMPONENT_1) - ser_2 = libconcord.get_serial(libconcord.SERIAL_COMPONENT_2) - ser_3 = libconcord.get_serial(libconcord.SERIAL_COMPONENT_3) - msg += "Serial:\n %s\n %s\n %s\n" % (ser_1, ser_2, ser_3) - - arch = libconcord.get_arch() - proto = libconcord.get_proto() - skin = libconcord.get_skin() - msg += "Arch:%d Proto:%d Skin:%d\n" % (arch, proto, skin) - - fw_type = libconcord.get_fw_type() - fw_ver_maj = libconcord.get_fw_ver_maj() - fw_ver_min = libconcord.get_fw_ver_min() - msg += "Firmware type:%d, version %d.%d\n" % ( - fw_type, fw_ver_maj, fw_ver_min - ) - - hw_ver_maj = libconcord.get_hw_ver_maj() - hw_ver_min = libconcord.get_hw_ver_min() - msg += "HW version %d.%d\n" % (hw_ver_maj, hw_ver_min) - - flash_mfg = libconcord.get_flash_mfg() - flash_id = libconcord.get_flash_id() - flash_part_num = libconcord.get_flash_part_num() - flash_size = libconcord.get_flash_size() - msg += "Flash Manufacturer:%d ID:%d Part:%s Size:%dK\n" % ( - flash_mfg, flash_id, flash_part_num, flash_size - ) - - hid_irl = libconcord.get_hid_irl() - hid_orl = libconcord.get_hid_orl() - hid_frl = libconcord.get_hid_frl() - msg += "USB HID Irl:%d Orl:%d Frl:%d\n" % (hid_irl, hid_orl, hid_frl) - - usb_vid = libconcord.get_usb_vid() - usb_pid = libconcord.get_usb_pid() - usb_bcd = libconcord.get_usb_bcd() - msg += "USB VID:%04x PID:%04x BCD:%04x\n" % (usb_vid, usb_pid, usb_bcd) - - config_bytes_used = libconcord.get_config_bytes_used() - config_bytes_total = libconcord.get_config_bytes_total() - config_pct_used = (config_bytes_used * 100) / config_bytes_total - msg += "Config used %d / total %d = %d%%\n" % ( - config_bytes_used, config_bytes_total, config_pct_used - ) - - fw_nondirect = libconcord.is_fw_update_supported(0) == 0 - fw_direct = libconcord.is_fw_update_supported(1) == 0 - if fw_nondirect or fw_direct: - config_safe = libconcord.is_config_safe_after_fw() == 0 - msg += "Firmware updates: Supported (%s), config%ssafe\n" % ( - fw_direct and "Direct" or "Not direct", - config_safe and " " or " NOT " - ) - else: - msg += "Firmware updates: NOT supported\n" - except: - msg = ( - "Error retrieving remote information:\n" + - exception_message() - ) - - self.text_info.Hide() - self.btn_details.Hide() - self.text_full_details.Show() - self.text_full_details.SetValue(msg) - self.Layout() - - def SetNext(self, next): - self.next = next - - def OnActivated(self, prev_page, data): - self.btn_details.Hide() - self.text_full_details.Hide() - thread.start_new_thread(self._WorkerFunction, ()) - return (None, None) - - def OnCancel(self): - self.lock.acquire() - if self.finished: - self.lock.release() - self.parent.OnExit(1) - else: - self.cancelled = True - self.lock.release() - - def GetTitle(self): - return "Connecting" - - def IsCancelInitiallyDisabled(self): - return False - - def GetNext(self): - return (self.next, None) - -class ProgramRemotePanelBase(WizardPanelBase, DecoratedContainerThreadMixin): - def __init__(self, parent, resources, file_type): - WizardPanelBase.__init__(self, parent, resources) - self.file_type = file_type - - self.sizer = wx.BoxSizer(wx.VERTICAL) - - self.dc = DecoratedContainer(self, self.resources) - DecoratedContainerThreadMixin.__init__(self, self.dc) - self._AddWidgets() - self.sizer.Add(self.dc, 0, wx.EXPAND | wx.ALL, 5) - - self.SetSizerAndFit(self.sizer) - - self.next = None - self.finished = False - - def _WorkerFunction(self): - try: - try: - self._WorkerFunctionBody() - wx.CallAfter(self._OnStatusOk) - return - except: - wx.CallAfter( - self._OnStatusFailure, - "Operation Failed", - exception_message() - ) - finally: - try: - if self.resources.connected: - self.resources.SetConnected(False) - libconcord.deinit_concord() - except: - pass - - def _OnStatusOk(self): - self.next = self.resources.page_success - self._OnStatusCommon() - - def _OnStatusFailure(self, failure_msg, details): - self.dc._DgFailure() - self.next = self.resources.page_failure - self.resources.page_failure.SetMessages( - failure_msg, - details - ) - self._OnStatusCommon() - - def _OnStatusCommon(self): - self.finished = True - self.parent.ReenableCancel() - self.parent.ReenableNext() - - def OnActivated(self, prev_page, data): - thread.start_new_thread(self._WorkerFunction, ()) - return (None, None) - - def OnCancel(self): - if self.finished: - self.parent.OnExit(1) - show_modal_scrolled_msgbox( - self.parent, - "Cannot Cancel", - "Cancel is disabled during programming operations, " + - "to prevent placing the remote into a state that will " + - "potentially be difficult to recover from." - ) - - def GetNext(self): - return (self.next, None) - -class CheckConnectivityPanel(ProgramRemotePanelBase): - def __init__(self, parent, resources): - ProgramRemotePanelBase.__init__( - self, - parent, - resources, - libconcord.LC_FILE_TYPE_CONNECTIVITY - ) - - def _AddWidgets(self): - vpos = counter() - self.dg_notify_website = DecoratedGauge(self.dc, "Notify Website", vpos.next()) - - def DoParsing(self): - pass - - def _WorkerFunctionBody(self): - self._DgUpdate( - False, - 0, - self.dg_notify_website - ) - if not self.resources.no_web: - libconcord.post_connect_test_success( - self.resources.xml, - self.resources.xml_size - ) - self._DgUpdate( - True, - 100, - self.dg_notify_website - ) - - def GetTitle(self): - return "Checking Connectivity" - -class WriteConfigurationPanel(ProgramRemotePanelBase): - def __init__(self, parent, resources): - ProgramRemotePanelBase.__init__( - self, - parent, - resources, - libconcord.LC_FILE_TYPE_CONFIGURATION - ) - - def _AddWidgets(self): - vpos = counter() - self.dg_check_website = DecoratedGauge(self.dc, "Check Website", vpos.next()) - self.dg_prepare = DecoratedGauge(self.dc, "Prepare Remote", vpos.next()) - self.dg_erase = DecoratedGauge(self.dc, "Erase Flash", vpos.next()) - self.dg_write = DecoratedGauge(self.dc, "Write Configuration", vpos.next()) - self.dg_verify = DecoratedGauge(self.dc, "Verify Upgrade", vpos.next()) - self.dg_reconnect = DecoratedGauge(self.dc, "Reconnect to Remote", vpos.next()) - self.dg_set_time = DecoratedGauge(self.dc, "Set Time", vpos.next()) - self.dg_notify_website = DecoratedGauge(self.dc, "Notify Website", vpos.next()) - - def DoParsing(self): - self.bin_data = POINTER(c_ubyte)() - self.bin_size = c_uint() - libconcord.find_config_binary( - self.resources.xml, - self.resources.xml_size, - byref(self.bin_data), - byref(self.bin_size) - ) - - def _WorkerFunctionBody(self): - program_callback = libconcord.callback_type(program_callback_imp) - - self._DgStart(self.dg_check_website) - if not self.resources.no_web: - libconcord.post_preconfig(self.resources.xml, self.resources.xml_size) - self._DgEnd(self.dg_check_website) - - self._DgStart(self.dg_prepare) - libconcord.invalidate_flash() - self._DgEnd(self.dg_prepare) - - self._DgStart(self.dg_erase) - libconcord.erase_config( - self.bin_size, - program_callback, - py_object((self._DgUpdate, self.dg_erase)) - ) - self._DgEnd(self.dg_erase) - - self._DgStart(self.dg_write) - libconcord.write_config_to_remote( - self.bin_data, - self.bin_size, - program_callback, - py_object((self._DgUpdate, self.dg_write)) - ) - self._DgEnd(self.dg_write) - - self._DgStart(self.dg_verify) - libconcord.verify_remote_config( - self.bin_data, - self.bin_size, - program_callback, - py_object((self._DgUpdate, self.dg_verify)) - ) - self._DgEnd(self.dg_verify) - - self._DgStart(self.dg_reconnect) - libconcord.reset_remote() - worker_body_connect( - self.resources, - self._DgUpdate, - self.dg_reconnect, - lambda: False, - True - ) - - self._DgStart(self.dg_set_time) - libconcord.set_time() - self._DgEnd(self.dg_set_time) - - self._DgStart(self.dg_notify_website) - if not self.resources.no_web: - libconcord.post_postconfig(self.resources.xml, self.resources.xml_size) - self._DgEnd(self.dg_notify_website) - - def GetTitle(self): - return "Updating Configuration" - -class UpdateFirmwarePanel(ProgramRemotePanelBase): - def __init__(self, parent, resources): - ProgramRemotePanelBase.__init__( - self, - parent, - resources, - libconcord.LC_FILE_TYPE_FIRMWARE - ) - - def _AddWidgets(self): - vpos = counter() - self.dg_prepare = DecoratedGauge(self.dc, "Prepare Remote", vpos.next()) - self.dg_erase = DecoratedGauge(self.dc, "Erase Flash", vpos.next()) - self.dg_write = DecoratedGauge(self.dc, "Write Firmware", vpos.next()) - self.dg_finalize = DecoratedGauge(self.dc, "Finalize Programming", vpos.next()) - self.dg_reconnect = DecoratedGauge(self.dc, "Reconnect to Remote", vpos.next()) - self.dg_set_time = DecoratedGauge(self.dc, "Set Time", vpos.next()) - self.dg_notify_website = DecoratedGauge(self.dc, "Notify Website", vpos.next()) - - def DoParsing(self): - self.bin_data = POINTER(c_ubyte)() - self.bin_size = c_uint() - libconcord.extract_firmware_binary( - self.resources.xml, - self.resources.xml_size, - byref(self.bin_data), - byref(self.bin_size) - ) - - def _WorkerFunctionBody(self): - program_callback = libconcord.callback_type(program_callback_imp) - - self._DgStart(self.dg_prepare) - - # is_fw_update_supported returns error code; 0 OK, otherwise failure - if libconcord.is_fw_update_supported(0) == 0: - is_direct = False - elif libconcord.is_fw_update_supported(1) == 0: - is_direct = True - else: - raise Exception( - "Sorry, congruity doesn't yet support firmware update " + - "on this remote model." - ) - - if not is_direct: - libconcord.prep_firmware() - - self._DgUpdate(False, 50, self.dg_prepare) - - libconcord.invalidate_flash() - - self._DgEnd(self.dg_prepare) - - self._DgStart(self.dg_erase) - libconcord.erase_firmware( - is_direct, - program_callback, - py_object((self._DgUpdate, self.dg_erase)) - ) - self._DgEnd(self.dg_erase) - - self._DgStart(self.dg_write) - libconcord.write_firmware_to_remote( - self.bin_data, - self.bin_size, - c_int(is_direct and 1 or 0), - program_callback, - py_object((self._DgUpdate, self.dg_write)) - ) - self._DgEnd(self.dg_write) - - self._DgStart(self.dg_finalize) - if not is_direct: - libconcord.finish_firmware() - self._DgEnd(self.dg_finalize) - - self._DgStart(self.dg_reconnect) - libconcord.reset_remote() - worker_body_connect( - self.resources, - self._DgUpdate, - self.dg_reconnect, - lambda: False, - True - ) - - self._DgStart(self.dg_set_time) - libconcord.set_time() - self._DgEnd(self.dg_set_time) - - self._DgStart(self.dg_notify_website) - if not self.resources.no_web: - libconcord.post_postfirmware(self.resources.xml, self.resources.xml_size) - self._DgEnd(self.dg_notify_website) - - def GetTitle(self): - return "Updating Firmware" - -class LearnIrPrepPanel(WizardPanelBase): - def __init__(self, parent, resources): - WizardPanelBase.__init__(self, parent, resources) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - - self.text_top_message = WrappedStaticText(self) - self.sizer.Add(self.text_top_message, 0, ALIGN_XTA, 5) - - self.source_radio = wx.RadioBox( - self, - -1, - "Select Learning Source", - wx.DefaultPosition, - wx.DefaultSize, - [ - "Learn from original remote ", - "Enter Pronto Hex ", - "Skip learning key " - ], - 1, - wx.RA_SPECIFY_COLS - ) - self.Bind(wx.EVT_RADIOBOX, self.OnSourceSelect, self.source_radio) - self.sizer.Add(self.source_radio, 0, ALIGN_LTA, 20) - - self.text_bottom_message = WrappedStaticText(self) - self.sizer.Add(self.text_bottom_message, 0, ALIGN_XTA, 5) - - self.SetSizerAndFit(self.sizer) - - self.sel = 0 - - def DoParsing(self): - key_names = POINTER(c_char_p)() - key_names_length = c_uint() - libconcord.get_key_names( - self.resources.xml, - self.resources.xml_size, - byref(key_names), - byref(key_names_length) - ) - try: - self.resources.key_names = [] - self.resources.key_names_index = -1 - for i in range(key_names_length.value): - self.resources.key_names.append(key_names[i] + '') - finally: - libconcord.delete_key_names(key_names, key_names_length) - - def OnActivated(self, prev_page, is_back): - if not is_back: - self.resources.key_names_index += 1 - if self.resources.key_names_index == len(self.resources.key_names): - return (self.resources.page_success, None) - self.text_top_message.UpdateText( - "About to learn key '%s' (%d of %d)." % ( - self.resources.key_names[self.resources.key_names_index], - self.resources.key_names_index + 1, - len(self.resources.key_names) - ) - ) - self._SetSelect(self.sel) - return (None, None) - - def OnSourceSelect(self, event): - self._SetSelect(event.GetInt()) - - def GetTitle(self): - return "IR Learning" - - def IsNextInitiallyDisabled(self): - return False - - def IsCancelInitiallyDisabled(self): - return False - - def GetNext(self): - if self.sel == 0: - return (self.resources.page_learn_ir_learn, None) - if self.sel == 1: - return (self.resources.page_learn_ir_enter_pronto_hex, None) - if self.sel == 2: - return (self, False) - return (None, None) - - def _SetSelect(self, sel): - self.sel = sel - if self.sel == 0: - self.text_bottom_message.UpdateText( - ( - "INSTRUCTIONS:\n\n" + - "Please point your original remote at the IR receiver of " + - "your Harmony remote. The IR receiver is typically at the " + - "end of the Harmony that you hold closest to you.\n\n" + - "The remotes should be placed approximately 2-5 inches " + - "(5-10 cm) apart.\n\n" + - "Please locate the '%s' button on your original remote, " + - "and be prepared to press and hold that button after " + - "you have clicked Next." - ) % self.resources.key_names[self.resources.key_names_index] - ) - if self.sel == 1: - self.text_bottom_message.UpdateText( - "INSTRUCTIONS:\n\n" + - "Press Next to type/paste in the Pronto hex codes." - ) - if self.sel == 2: - self.text_bottom_message.UpdateText( - "INSTRUCTIONS:\n\n" + - "This will skip learning this key." - ) - -class IRSignalCanvas(wx.ScrolledWindow): - def __init__(self, parent, id = -1, size = wx.DefaultSize): - wx.ScrolledWindow.__init__( - self, - parent, - -1, - size=(300, 100), - style=wx.SUNKEN_BORDER - ) - self.SetBackgroundColour("BLACK") - self.SetScrollbars(10, 0, 32767, 0) - self.Bind(wx.EVT_PAINT, self.OnPaint) - - self.pulses = [] - self.scale = 20000 - - def OnPaint(self, event): - if not len(self.pulses): - return - - ytotal = self.GetClientSize()[1] - ytop = ytotal / 4 - ybottom = ytotal - ytop - yoffsetmax = ytotal - (ybottom - ytop) - - dc = wx.PaintDC(self) - self.PrepareDC(dc) - dc.SetBackground(wx.Brush("black")) - dc.SetPen(wx.Pen("GREEN")) - dc.Clear() - - dc.BeginDrawing() - - x = 16 - yoffset = 0 - - for pulse in self.pulses: - y = ytop + yoffset - xe = x + (pulse / self.scale) - - dc.DrawLine(x, ytop, x, ybottom - 1) - dc.DrawLine(x, y, xe, y) - - x = xe - yoffset = yoffsetmax - yoffset - - dc.EndDrawing() - - def SetSignal(self, pulses, pulse_count): - if pulse_count == 0: - return - self.pulses = [] - self.pulses_sum = 0 - for i in range(pulse_count.value): - pulse = pulses[i] - self.pulses_sum = self.pulses_sum + pulse - self.pulses.append(pulse) - self.min_scale = (self.pulses_sum / (32767 - 32)) + 1 - self.max_scale = (self.pulses_sum / (self.GetClientSize()[0] - 32)) - 1 - self.max_scale = max(self.max_scale, 1) - - self.scale = self.max_scale - self._OnSetScale() - - def OnZoomIn(self): - if not self.pulses: - return - self.scale = max(self.scale / 2, self.min_scale) - self._OnSetScale() - - def OnZoomOut(self): - if not self.pulses: - return - self.scale = min(self.scale * 2, self.max_scale) - self._OnSetScale() - - def _OnSetScale(self): - pix_per_unit = 10 - units = (32 + (self.pulses_sum / self.scale)) / pix_per_unit - pix_to_scroll = pix_per_unit * units - if pix_to_scroll <= self.GetClientSize()[0]: - units += 1 - self.SetScrollbars(pix_per_unit, 0, units, 0) - self.OnPaint(None) - -class IRSignalPanel(wx.Panel): - def __init__(self, parent): - wx.Panel.__init__(self, parent) - - sizer = wx.BoxSizer(wx.HORIZONTAL) - - self.canvas = IRSignalCanvas(self) - sizer.Add(self.canvas, 1, wx.EXPAND | wx.ALL, 0) - - sizer_buttons = wx.BoxSizer(wx.VERTICAL) - - btn_zi = wx.Button(self, -1, "+") - sizer_buttons.Add(btn_zi, 0, ALIGN_RCA, 5) - self.Bind(wx.EVT_BUTTON, self.OnZoomIn, btn_zi) - - btn_zo = wx.Button(self, -1, "-") - sizer_buttons.Add(btn_zo, 0, ALIGN_RCA, 5) - self.Bind(wx.EVT_BUTTON, self.OnZoomOut, btn_zo) - - sizer.Add(sizer_buttons, 0, ALIGN_RCA, 0) - - self.SetSizer(sizer) - - def OnZoomIn(self, event): - self.canvas.OnZoomIn() - - def OnZoomOut(self, event): - self.canvas.OnZoomOut() - -class LearnIrLearnPanel(WizardPanelBase, DecoratedContainerThreadMixin): - def __init__(self, parent, resources): - WizardPanelBase.__init__(self, parent, resources) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - - self.text_top_message = WrappedStaticText(self) - self.sizer.Add(self.text_top_message, 0, ALIGN_XTA, 5) - - self.dc = DecoratedContainer(self, self.resources) - DecoratedContainerThreadMixin.__init__(self, self.dc) - - vpos = counter() - self.dg_learn = DecoratedGauge(self.dc, "Learn IR", vpos.next()) - - self.sizer.Add(self.dc, 0, wx.EXPAND | wx.ALL, 5) - - self.btn_details = wx.Button(self, -1, "&Details...") - self.sizer.Add(self.btn_details, 0, wx.ALIGN_LEFT | wx.ALL, 5) - self.Bind(wx.EVT_BUTTON, self._OnDetails, self.btn_details) - - self.divider = wx.StaticLine(self, -1, None, None, wx.LI_HORIZONTAL) - self.sizer.Add(self.divider, 0, wx.EXPAND) - - self.text_results = WrappedStaticText(self) - self.sizer.Add(self.text_results, 0, ALIGN_XTA, 5) - - self.signal = IRSignalPanel(self) - self.sizer.Add(self.signal, 0, wx.EXPAND | wx.ALL, 5) - - self.SetSizerAndFit(self.sizer) - - def _WorkerFunction(self): - try: - program_callback = libconcord.callback_type(program_callback_imp) - - self._DgStart(self.dg_learn) - - self.resources.cur_ir_allocated_by_libconcord = True - self.resources.cur_ir_carrier_clock = c_uint() - self.resources.cur_ir_signal = POINTER(c_uint)() - self.resources.cur_ir_signal_length = c_uint() - libconcord.learn_from_remote( - byref(self.resources.cur_ir_carrier_clock), - byref(self.resources.cur_ir_signal), - byref(self.resources.cur_ir_signal_length), - program_callback, - py_object((self._DgUpdate, self.dg_learn)) - ) - - self._DgEnd(self.dg_learn) - - wx.CallAfter(self._OnStatusOk) - return - except: - wx.CallAfter( - self._OnStatusFailure, - "IR learning failure", - exception_message() - ) - - def _OnStatusOk(self): - self.btn_details.Show() - self.parent.ReenableBack() - self.next = self.resources.page_learn_ir_upload - self._OnStatusCommon() - - def _OnStatusFailure(self, failure_msg, details): - self.dc._DgFailure() - self.next = self.resources.page_failure - self.resources.page_failure.SetMessages( - failure_msg, - details - ) - self._OnStatusCommon() - self.text_results.Show() - self.text_results.UpdateText( - "\nRESULTS:\n\n" + - "Learning failed; perhaps you did not press a key on the original " + - "remote, or you held the key for too long." - ) - self.parent.ReenableBack() - - def _OnStatusCommon(self): - self.parent.ReenableCancel() - self.parent.ReenableNext() - - def _OnDetails(self, event): - self.btn_details.Hide() - self.divider.Show() - self.text_results.Show() - self.signal.Show() - self.text_results.UpdateText( - "\nRESULTS:\n\n" + - "Carrier Frequency: %d" % self.resources.cur_ir_carrier_clock.value - ) - self.signal.canvas.SetSignal( - self.resources.cur_ir_signal, - self.resources.cur_ir_signal_length - ) - - def OnActivated(self, prev_page, data): - self.btn_details.Hide() - self.divider.Hide() - self.text_results.Hide() - self.signal.Hide() - self.text_top_message.UpdateText( - "Please press and hold the button on your original remote now." - ) - thread.start_new_thread(self._WorkerFunction, ()) - return (None, None) - - def GetTitle(self): - return "IR Learning" - - def GetBack(self): - return (self.resources.page_learn_ir_prep, True) - - def GetNext(self): - return (self.next, None) - -class LearnIrEnterProntoHexPanel(WizardPanelBase): - def __init__(self, parent, resources): - WizardPanelBase.__init__(self, parent, resources) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - - self.text_top_message = WrappedStaticText(self) - self.sizer.Add(self.text_top_message, 0, ALIGN_XTA, 5) - - self.edit_hex = wx.TextCtrl( - self, - -1, - style = wx.TE_MULTILINE | wx.HSCROLL - ) - self.sizer.Add(self.edit_hex, 1, ALIGN_XTA, 5) - - self.btn_validate = wx.Button(self, -1, "&Validate...") - self.sizer.Add(self.btn_validate, 0, wx.ALIGN_LEFT | wx.ALL, 5) - self.Bind(wx.EVT_BUTTON, self._OnValidate, self.btn_validate) - - self.text_results = WrappedStaticText(self) - self.sizer.Add(self.text_results, 0, ALIGN_XTA, 5) - - self.signal = IRSignalPanel(self) - self.sizer.Add(self.signal, 0, wx.EXPAND | wx.ALL, 5) - - self.SetSizerAndFit(self.sizer) - - def _OnValidate(self, event): - try: - bin = [] - str = "" - str_idx = 0 - - hex = self.edit_hex.GetValue().strip().split(' ') - for h in hex: - b = int(h, 16) - bin.append(b) - - str += "%04x " % b - str_idx += 1 - if str_idx == 12: - str += "\n" - str_idx = 0 - - self.edit_hex.SetValue(str) - - if len(bin) < 4: - raise Exception('Pronto code too short (missing header)') - - if bin[0] != 0: - raise Exception('Not RAW') - - pronto_clock = 4145146 - # IR carrier frequency is given as number of Pronto clock cycles - frequency = int(pronto_clock / bin[1]) - # Mark/space durations are given as a count of IR carrier cycles, - # but we need them in microseconds - carrier_cycle_us = 1000000.0 / frequency - - count_1 = 2 * bin[2] - count_2 = 2 * bin[3] - - if len(bin) < 4 + count_1 + count_2: - raise Exception('Pronto code too short (missing pulsetrain)') - - start_1 = 4 - start_2 = 4 + count_1 - - repeats = 4 - count = count_1 + (repeats * count_2) - - self.resources.cur_ir_allocated_by_libconcord = False - self.resources.cur_ir_carrier_clock = c_uint(frequency) - cur_ir_signal_type = c_uint * count - self.resources.cur_ir_signal = cur_ir_signal_type() - self.resources.cur_ir_signal_length = c_uint(count) - - idx = 0 - - for i in range(count_1): - se... [truncated message content] |
From: <srw...@us...> - 2010-12-06 05:11:24
|
Revision: 82 http://congruity.svn.sourceforge.net/congruity/?rev=82&view=rev Author: srwarren Date: 2010-12-06 05:11:18 +0000 (Mon, 06 Dec 2010) Log Message: ----------- Detect at least some bad IR learning results Modified Paths: -------------- trunk/Changelog trunk/congruity Modified: trunk/Changelog =================================================================== --- trunk/Changelog 2010-08-14 02:45:23 UTC (rev 81) +++ trunk/Changelog 2010-12-06 05:11:18 UTC (rev 82) @@ -1,6 +1,7 @@ -* 2010-08-13 Stephen Warren <s-t...@ww...> +* 2010-??-?? Stephen Warren <s-t...@ww...> - Fixed messages to refer to a "finish" button instead of a "next" button. Related: Refer to "clicking" this button instead of "pressing" it. +- Detect at least some bad IR learning results. * 2010-08-01 Stephen Warren <s-t...@ww...> - congruity-15 is released Modified: trunk/congruity =================================================================== --- trunk/congruity 2010-08-14 02:45:23 UTC (rev 81) +++ trunk/congruity 2010-12-06 05:11:18 UTC (rev 82) @@ -1255,6 +1255,8 @@ program_callback, py_object((self._DgUpdate, self.dg_learn)) ) + if self.resources.cur_ir_carrier_clock.value < 1000: + raise Exception('Carrier frequency too low') self._DgEnd(self.dg_learn) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2010-08-14 02:45:29
|
Revision: 81 http://congruity.svn.sourceforge.net/congruity/?rev=81&view=rev Author: srwarren Date: 2010-08-14 02:45:23 +0000 (Sat, 14 Aug 2010) Log Message: ----------- s/Next/Forward/ in text. Fixes sf.net bug 3043772 Modified Paths: -------------- trunk/Changelog trunk/congruity Modified: trunk/Changelog =================================================================== --- trunk/Changelog 2010-08-14 02:41:12 UTC (rev 80) +++ trunk/Changelog 2010-08-14 02:45:23 UTC (rev 81) @@ -1,3 +1,7 @@ +* 2010-08-13 Stephen Warren <s-t...@ww...> +- Fixed messages to refer to a "finish" button instead of a "next" button. + Related: Refer to "clicking" this button instead of "pressing" it. + * 2010-08-01 Stephen Warren <s-t...@ww...> - congruity-15 is released - Call new APIs in libconcord-0.22, for Harmony 700 support. Modified: trunk/congruity =================================================================== --- trunk/congruity 2010-08-14 02:41:12 UTC (rev 80) +++ trunk/congruity 2010-08-14 02:45:23 UTC (rev 81) @@ -338,11 +338,11 @@ _msg_status_ok = ( "Please ensure the remote control is connected " + "before proceeding.\n\n" + - "Click next to begin operation." + "Click 'forward' to begin operation." ) _msg_status_failure = ( - "A problem occurred. Click next for details." + "A problem occurred. Click 'forward' for details." ) _msg_failure_explanation = ( @@ -477,7 +477,7 @@ ) _msg_status_failure = ( - "A problem occurred. Click next for details." + "A problem occurred. Click 'forward' for details." ) _msg_failure_explanation = ( @@ -1078,13 +1078,13 @@ "(5-10 cm) apart.\n\n" + "Please locate the '%s' button on your original remote, " + "and be prepared to press and hold that button after " + - "you have clicked Next." + "you have clicked 'forward'." ) % self.resources.key_names[self.resources.key_names_index] ) if self.sel == 1: self.text_bottom_message.UpdateText( "INSTRUCTIONS:\n\n" + - "Press Next to type/paste in the Pronto hex codes." + "Click 'forward' to type/paste in the Pronto hex codes." ) if self.sel == 2: self.text_bottom_message.UpdateText( This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2010-08-14 02:41:18
|
Revision: 80 http://congruity.svn.sourceforge.net/congruity/?rev=80&view=rev Author: srwarren Date: 2010-08-14 02:41:12 +0000 (Sat, 14 Aug 2010) Log Message: ----------- Uggh. Fix trailing whitespace. Modified Paths: -------------- trunk/congruity Modified: trunk/congruity =================================================================== --- trunk/congruity 2010-08-02 00:32:30 UTC (rev 79) +++ trunk/congruity 2010-08-14 02:41:12 UTC (rev 80) @@ -30,7 +30,7 @@ import wx import wx.lib.dialogs -version = "15" +version = "15+" try: import libconcord @@ -179,9 +179,9 @@ ALIGN_LTA = wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.ALL ALIGN_XTA = wx.EXPAND | wx.ALIGN_TOP | wx.ALL -ALIGN_LCA = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL -ALIGN_RCA = wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.ALL -ALIGN_XCA = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL +ALIGN_LCA = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL +ALIGN_RCA = wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.ALL +ALIGN_XCA = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL ALIGN_LBA = wx.ALIGN_LEFT | wx.ALIGN_BOTTOM | wx.ALL ALIGN_XBA = wx.EXPAND | wx.ALIGN_BOTTOM | wx.ALL @@ -192,7 +192,7 @@ def UpdateText(self, new_label): cur_width = self.parent.GetSize().GetWidth() - self.SetLabel(new_label) + self.SetLabel(new_label) self.Wrap(cur_width) self.Layout() self.parent.Layout() @@ -327,7 +327,7 @@ class WelcomePanel(MessagePanelBase): _msg_welcome = ( - "Welcome to congruity; a programming application " + + "Welcome to congruity; a programming application " + "for Logitech Harmony remote controls.\n\n" ) @@ -337,7 +337,7 @@ _msg_status_ok = ( "Please ensure the remote control is connected " + - "before proceeding.\n\n" + + "before proceeding.\n\n" + "Click next to begin operation." ) @@ -1107,7 +1107,7 @@ self.pulses = [] self.scale = 20000 - + def OnPaint(self, event): if not len(self.pulses): return @@ -1139,7 +1139,7 @@ yoffset = yoffsetmax - yoffset dc.EndDrawing() - + def SetSignal(self, pulses, pulse_count): if pulse_count == 0: return @@ -1155,7 +1155,7 @@ self.scale = self.max_scale self._OnSetScale() - + def OnZoomIn(self): if not self.pulses: return @@ -1948,7 +1948,7 @@ except: ezhex_filename = None initial_exception = ("Command-line error", exception_message()) - + app = wx.PySimpleApp() wx.InitAllImageHandlers() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2010-08-02 00:32:36
|
Revision: 79 http://congruity.svn.sourceforge.net/congruity/?rev=79&view=rev Author: srwarren Date: 2010-08-02 00:32:30 +0000 (Mon, 02 Aug 2010) Log Message: ----------- Tweak WrappedStaticText.UpdateText() so wrapping works. Add changelog for congruity-15. Bump version to 15 for release. Modified Paths: -------------- trunk/Changelog trunk/congruity Modified: trunk/Changelog =================================================================== --- trunk/Changelog 2010-07-29 23:13:55 UTC (rev 78) +++ trunk/Changelog 2010-08-02 00:32:30 UTC (rev 79) @@ -1,3 +1,9 @@ +* 2010-08-01 Stephen Warren <s-t...@ww...> +- congruity-15 is released +- Call new APIs in libconcord-0.22, for Harmony 700 support. +- Tweak WrappedStaticText.UpdateText again, so it shows all text and doesn't + wrap it strangely, at least with Lucids's wxpython 2.8.10.1-0ubuntu1. + * 2009-12-16 Stephen Warren <s-t...@ww...> - congruity-14 is released - replace remote.png with a GPL-licensed version provided by Modified: trunk/congruity =================================================================== --- trunk/congruity 2010-07-29 23:13:55 UTC (rev 78) +++ trunk/congruity 2010-08-02 00:32:30 UTC (rev 79) @@ -30,7 +30,7 @@ import wx import wx.lib.dialogs -version = "14+" +version = "15" try: import libconcord @@ -195,6 +195,7 @@ self.SetLabel(new_label) self.Wrap(cur_width) self.Layout() + self.parent.Layout() class DecoratedContainer(wx.Panel): def __init__(self, parent, resources): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2010-07-29 23:14:01
|
Revision: 78 http://congruity.svn.sourceforge.net/congruity/?rev=78&view=rev Author: srwarren Date: 2010-07-29 23:13:55 +0000 (Thu, 29 Jul 2010) Log Message: ----------- Add support for new libconcord APIs to support Harmony 700 Modified Paths: -------------- trunk/congruity Modified: trunk/congruity =================================================================== --- trunk/congruity 2009-12-17 04:14:53 UTC (rev 77) +++ trunk/congruity 2010-07-29 23:13:55 UTC (rev 78) @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright 2008 Stephen Warren +# Copyright 2008-2010 Stephen Warren # # This file is part of congruity. # @@ -30,7 +30,7 @@ import wx import wx.lib.dialogs -version = "14" +version = "14+" try: import libconcord @@ -73,6 +73,16 @@ except: can_learn_ir = False +# APIs not available in all versions of libconcord +try: + libconcord.prep_config + libconcord.finish_config +except: + def dummy_lc_function(): + pass + libconcord.prep_config = dummy_lc_function + libconcord.finish_config = dummy_lc_function + def counter(): i=0 while True: @@ -816,6 +826,7 @@ self._DgEnd(self.dg_check_website) self._DgStart(self.dg_prepare) + libconcord.prep_config() libconcord.invalidate_flash() self._DgEnd(self.dg_prepare) @@ -846,6 +857,7 @@ self._DgEnd(self.dg_verify) self._DgStart(self.dg_reconnect) + libconcord.finish_config() libconcord.reset_remote() worker_body_connect( self.resources, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2009-12-17 04:15:03
|
Revision: 77 http://congruity.svn.sourceforge.net/congruity/?rev=77&view=rev Author: srwarren Date: 2009-12-17 04:14:53 +0000 (Thu, 17 Dec 2009) Log Message: ----------- Tag congruity-14 Added Paths: ----------- tags/congruity-14/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2009-12-17 04:14:14
|
Revision: 76 http://congruity.svn.sourceforge.net/congruity/?rev=76&view=rev Author: srwarren Date: 2009-12-17 04:14:05 +0000 (Thu, 17 Dec 2009) Log Message: ----------- Changes for congruity-14 Modified Paths: -------------- trunk/Changelog trunk/LICENSE.txt trunk/congruity trunk/remote.png Modified: trunk/Changelog =================================================================== --- trunk/Changelog 2009-08-05 05:20:29 UTC (rev 75) +++ trunk/Changelog 2009-12-17 04:14:05 UTC (rev 76) @@ -1,3 +1,10 @@ +* 2009-12-16 Stephen Warren <s-t...@ww...> +- congruity-14 is released +- replace remote.png with a GPL-licensed version provided by + Mathieu Trudel-Lapierre <mat...@gm...> +- Tweak WrappedStaticText.UpdateText so it shows all text and doesn't wrap it + strangely, at least with Jaunty's wxpython 2.8.9.1-0ubuntu6. + * 2009-08-04 Stephen Warren <s-t...@ww...> - congruity-13 is released - Update MIME types in .desktop file Modified: trunk/LICENSE.txt =================================================================== --- trunk/LICENSE.txt 2009-08-05 05:20:29 UTC (rev 75) +++ trunk/LICENSE.txt 2009-12-17 04:14:05 UTC (rev 76) @@ -24,6 +24,5 @@ GPL (sourced from f-spot and Gnome icon sets on Fedora 8) Licensing for remote.png: -CC-BY-SA-2.5 -Downloaded from the URL below, resized, and made transparent: -http://commons.wikimedia.org/wiki/Image:Harmony670.jpg +GPL v2 or later +Created by Mathieu Trudel-Lapierre <mat...@gm...> Modified: trunk/congruity =================================================================== --- trunk/congruity 2009-08-05 05:20:29 UTC (rev 75) +++ trunk/congruity 2009-12-17 04:14:05 UTC (rev 76) @@ -30,7 +30,7 @@ import wx import wx.lib.dialogs -version = "13" +version = "14" try: import libconcord @@ -184,7 +184,7 @@ cur_width = self.parent.GetSize().GetWidth() self.SetLabel(new_label) self.Wrap(cur_width) - self.parent.Layout() + self.Layout() class DecoratedContainer(wx.Panel): def __init__(self, parent, resources): Modified: trunk/remote.png =================================================================== (Binary files differ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2009-08-05 05:20:39
|
Revision: 75 http://congruity.svn.sourceforge.net/congruity/?rev=75&view=rev Author: srwarren Date: 2009-08-05 05:20:29 +0000 (Wed, 05 Aug 2009) Log Message: ----------- Tag congruity-13 Added Paths: ----------- tags/congruity-13/ Property changes on: tags/congruity-13 ___________________________________________________________________ Added: svn:mergeinfo + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2009-08-05 05:15:16
|
Revision: 74 http://congruity.svn.sourceforge.net/congruity/?rev=74&view=rev Author: srwarren Date: 2009-08-05 05:15:09 +0000 (Wed, 05 Aug 2009) Log Message: ----------- Modify MIME types to match Logitech website, and Fedora libconcord packaging. Modified Paths: -------------- trunk/Changelog trunk/congruity trunk/congruity.desktop Modified: trunk/Changelog =================================================================== --- trunk/Changelog 2009-06-19 02:37:58 UTC (rev 73) +++ trunk/Changelog 2009-08-05 05:15:09 UTC (rev 74) @@ -1,3 +1,18 @@ +* 2009-08-04 Stephen Warren <s-t...@ww...> +- congruity-13 is released +- Update MIME types in .desktop file + Patch by Adam Williamson <awi...@re...> + + Apparently, these new MIME types match what the Logitech server sends + when you perform a download: + https://bugzilla.redhat.com/show_bug.cgi?id=506536#c12 + + However, Fedora still packages definitions of these MIME types as part of + libconcord. Packagers for other distributions should double-check the + Fedora packaging of libconcord; see file libconcord-0.21-mime-type-def.patch + which adds file concordance-0.21/libconcord/libconcord.xml to the + libconcord sources. + * 2009-06-17 Stephen Warren <s-t...@ww...> - congruity-12 is released - Add congruity.desktop to release script Modified: trunk/congruity =================================================================== --- trunk/congruity 2009-06-19 02:37:58 UTC (rev 73) +++ trunk/congruity 2009-08-05 05:15:09 UTC (rev 74) @@ -30,7 +30,7 @@ import wx import wx.lib.dialogs -version = "12" +version = "13" try: import libconcord Modified: trunk/congruity.desktop =================================================================== --- trunk/congruity.desktop 2009-06-19 02:37:58 UTC (rev 73) +++ trunk/congruity.desktop 2009-08-05 05:15:09 UTC (rev 74) @@ -3,5 +3,5 @@ Exec=congruity %f NoDisplay=true Type=Application -MimeType=application/x-libconcord; +MimeType=application/x-easyzapper-hex;application/x-easyzapper-upgrade;application/x-easyzapper-tutor; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2009-06-19 02:38:00
|
Revision: 73 http://congruity.svn.sourceforge.net/congruity/?rev=73&view=rev Author: srwarren Date: 2009-06-19 02:37:58 +0000 (Fri, 19 Jun 2009) Log Message: ----------- Tag congruity-12 Added Paths: ----------- tags/congruity-12/ tags/congruity-12/Changelog tags/congruity-12/Makefile tags/congruity-12/README.txt tags/congruity-12/congruity tags/congruity-12/congruity.desktop tags/congruity-12/icon-sources.txt tags/congruity-12/mkrelease.sh Removed Paths: ------------- tags/congruity-12/Changelog tags/congruity-12/Makefile tags/congruity-12/README.txt tags/congruity-12/congruity tags/congruity-12/mkrelease.sh Property changes on: tags/congruity-12 ___________________________________________________________________ Added: svn:mergeinfo + Deleted: tags/congruity-12/Changelog =================================================================== --- trunk/Changelog 2008-10-13 00:13:29 UTC (rev 47) +++ tags/congruity-12/Changelog 2009-06-19 02:37:58 UTC (rev 73) @@ -1,101 +0,0 @@ -* 2008-09-07 Stephen Warren <s-t...@ww...> -- congruity-9 is released -- Use a different remote.png, with a known free license. - -* 2008-07-03 Stephen Warren <s-t...@ww...> -- congruity-8 is released -- Centralize cancel/exit handling, - and clean up any libconcord resources when exiting the application. -- Add thread-safe cancelling to ConnectPanel. -- Work around a typo in libconcord 0.20's Python bindings. -- Provide a GUI message if libconcord can't be loaded, in case congruity - wasn't run from a terminal. - -* 2008-07-02 Stephen Warren <s-t...@ww...> -- Increase connect timeout after a reset operation, just to make sure - we don't miss the remote coming back. -- Fix Makefile to create all directories files are written to, and add - a few more variables that can be tweaked e.g. by packaging scripts. -* On behalf of Andreas Schulz <And...@gm...> -- Use a simpler and potentially more reliable fix for GTK buttons not - accepting clicks if the mouse was inside the widget when enabled. - -* 2008-07-01 Stephen Warren <s-t...@ww...> -- Command-line parsing errors are displayed by the GUI, instead of being - echo'd to stdout. This makes errors visible when congruity is launched - without a terminal - -* 2008-06-25..2008-07-01 Stephen Warren <s-t...@ww...> -* Inspired by Andreas Schulz <And...@gm...> -- Significant internal structural changes to the implementation, which - simplify things a lot, and make program flow far more obvious, localized, - and correctly polymorphic. -- Add a separate "connect" page, so that the other pages don't have to - re-implement this common function. - -* 2008-06-17 Stephen Warren <s-t...@ww...> -* On behalf of Andreas Schulz <And...@gm...> -- Fix issue where next button wouldn't respond to clicks if the pointer was - already within the button when it was re-enabled. - -* 2008-04-14 Stephen Warren <s-t...@ww...> -- congruity-7 is released -- Switched license to GPLv3+ to be compatible with libconcord by default. - Contact me if you want the code under a different license, but please - note that you won't be able to use relicensed code with libconcord. -- Added a Makefile for easy installation. - Thanks to Phil Dibowitz for the contribution. -- Added a manual page. -- Added a few useful URLs to README.txt. -- Fixed reliance on syntax specific to Python 2.5. - -* 2008-04-13 Stephen Warren <s-t...@ww...> -- congruity-6 is released -- Search for images in /usr/share/congruity, the source directory, then - CWD. This should allow easy system-wide installation of congruity. -- libconcord.py is no longer distributed with congruity; it is now part - of libconcord itself (see libconcord/bindings/python/). -- Apparently forgot to release LICENSE.txt before. - -* 2008-04-07 Stephen Warren <s-t...@ww...> -- congruity-5 is released -- This release solely operates using libconcord; "screen-scraping" the output - from the concordance application is no longer supported. -- Implement firmware upgrade. -- Minor tweaks for operation on MS-Windows. -- congruity now sets the time on the remote after any reboot. - -* 2008-03-29 Stephen Warren <s-t...@ww...> -- congruity-4 is released -- Renamed package from harmonygui to congruity, in line with the - coming rename of the harmonycontrol project to concordance/libconcord. -- Changes to match latest CVS libconcord API changes - -* 2008-02-24 Stephen Warren <s-t...@ww...> -- harmonygui-3 is released -- Added README.txt. -- Added LICENSING.txt, to account for images too. -- Remove GUI for initial web connection in update mode; the libharmony - branch code doesn't print this status information, so now we act like - it was never there. -- Code re-org, to allow for multiple back-ends. -- Added a back-end that calls libharmony.so directly using ctypes. - -* 2008-02-10 Stephen Warren <s-t...@ww...> -- harmonygui-2 is released -- Updated ezhexparser to recognize firmware update files. -- Updated GUI to handle firmware updates, by informing user its - not yet supported. -- Separated ezhexparser and tuiparser operation mode enumerations. -- Enhanced ptyrun error handling, so it's more obvious what happened - when the harmony application can't be found in the $PATH. -- Updated harmonyfake to use ^H characters to re-write output, not - \r. This matches the real harmony app. -- Minor typo cleanups in messages. -- Added licensing information. -- Added this Changelog - -* 2008-02-05 Stephen Warren <s-t...@ww...> -- harmonygui-1 is released -- Initial release. - Copied: tags/congruity-12/Changelog (from rev 72, trunk/Changelog) =================================================================== --- tags/congruity-12/Changelog (rev 0) +++ tags/congruity-12/Changelog 2009-06-19 02:37:58 UTC (rev 73) @@ -0,0 +1,129 @@ +* 2009-06-17 Stephen Warren <s-t...@ww...> +- congruity-12 is released +- Add congruity.desktop to release script + +* 2009-06-17 Stephen Warren <s-t...@ww...> +- congruity-11 is released +- Fix Pronto hex import + Patch by Andreas Schulz <And...@gm...> +- Throw runtime error dialog if wxPython version is not at least 2.8 +- Add .desktop file + Patch by Adam Williamson <awi...@re...> + +* 2009-03-09 Stephen Warren <s-t...@ww...> +- congruity-10 is released +- Implement IR learning feature, with support for learning from the original + remote using the Harmony, or reading the signal from a "Pronto Hex" file. + (Merge of /branches/irlean) + Parts based on code by Andreas Schulz <And...@gm...> +- Various internal code changes to support IR learning and general cleanup. +- Implement --no-web command-line option, which prevents posting any data + to the Harmony website. This can be useful when testing congruity. +- Change default install prefix to /usr/local; this makes typical end-user + manual installs slightly simpler. Also, automatically patch install location + into the app during installation. +- If libconcord import fails, display the entire backtrace information, to + enable easier debugging of the issue. +- Enhance README + +* 2008-09-07 Stephen Warren <s-t...@ww...> +- congruity-9 is released +- Use a different remote.png, with a known free license. + +* 2008-07-03 Stephen Warren <s-t...@ww...> +- congruity-8 is released +- Centralize cancel/exit handling, + and clean up any libconcord resources when exiting the application. +- Add thread-safe cancelling to ConnectPanel. +- Work around a typo in libconcord 0.20's Python bindings. +- Provide a GUI message if libconcord can't be loaded, in case congruity + wasn't run from a terminal. + +* 2008-07-02 Stephen Warren <s-t...@ww...> +- Increase connect timeout after a reset operation, just to make sure + we don't miss the remote coming back. +- Fix Makefile to create all directories files are written to, and add + a few more variables that can be tweaked e.g. by packaging scripts. +* On behalf of Andreas Schulz <And...@gm...> +- Use a simpler and potentially more reliable fix for GTK buttons not + accepting clicks if the mouse was inside the widget when enabled. + +* 2008-07-01 Stephen Warren <s-t...@ww...> +- Command-line parsing errors are displayed by the GUI, instead of being + echo'd to stdout. This makes errors visible when congruity is launched + without a terminal + +* 2008-06-25..2008-07-01 Stephen Warren <s-t...@ww...> +* Inspired by Andreas Schulz <And...@gm...> +- Significant internal structural changes to the implementation, which + simplify things a lot, and make program flow far more obvious, localized, + and correctly polymorphic. +- Add a separate "connect" page, so that the other pages don't have to + re-implement this common function. + +* 2008-06-17 Stephen Warren <s-t...@ww...> +* On behalf of Andreas Schulz <And...@gm...> +- Fix issue where next button wouldn't respond to clicks if the pointer was + already within the button when it was re-enabled. + +* 2008-04-14 Stephen Warren <s-t...@ww...> +- congruity-7 is released +- Switched license to GPLv3+ to be compatible with libconcord by default. + Contact me if you want the code under a different license, but please + note that you won't be able to use relicensed code with libconcord. +- Added a Makefile for easy installation. + Thanks to Phil Dibowitz for the contribution. +- Added a manual page. +- Added a few useful URLs to README.txt. +- Fixed reliance on syntax specific to Python 2.5. + +* 2008-04-13 Stephen Warren <s-t...@ww...> +- congruity-6 is released +- Search for images in /usr/share/congruity, the source directory, then + CWD. This should allow easy system-wide installation of congruity. +- libconcord.py is no longer distributed with congruity; it is now part + of libconcord itself (see libconcord/bindings/python/). +- Apparently forgot to release LICENSE.txt before. + +* 2008-04-07 Stephen Warren <s-t...@ww...> +- congruity-5 is released +- This release solely operates using libconcord; "screen-scraping" the output + from the concordance application is no longer supported. +- Implement firmware upgrade. +- Minor tweaks for operation on MS-Windows. +- congruity now sets the time on the remote after any reboot. + +* 2008-03-29 Stephen Warren <s-t...@ww...> +- congruity-4 is released +- Renamed package from harmonygui to congruity, in line with the + coming rename of the harmonycontrol project to concordance/libconcord. +- Changes to match latest CVS libconcord API changes + +* 2008-02-24 Stephen Warren <s-t...@ww...> +- harmonygui-3 is released +- Added README.txt. +- Added LICENSING.txt, to account for images too. +- Remove GUI for initial web connection in update mode; the libharmony + branch code doesn't print this status information, so now we act like + it was never there. +- Code re-org, to allow for multiple back-ends. +- Added a back-end that calls libharmony.so directly using ctypes. + +* 2008-02-10 Stephen Warren <s-t...@ww...> +- harmonygui-2 is released +- Updated ezhexparser to recognize firmware update files. +- Updated GUI to handle firmware updates, by informing user its + not yet supported. +- Separated ezhexparser and tuiparser operation mode enumerations. +- Enhanced ptyrun error handling, so it's more obvious what happened + when the harmony application can't be found in the $PATH. +- Updated harmonyfake to use ^H characters to re-write output, not + \r. This matches the real harmony app. +- Minor typo cleanups in messages. +- Added licensing information. +- Added this Changelog + +* 2008-02-05 Stephen Warren <s-t...@ww...> +- harmonygui-1 is released +- Initial release. + Deleted: tags/congruity-12/Makefile =================================================================== --- trunk/Makefile 2008-10-13 00:13:29 UTC (rev 47) +++ tags/congruity-12/Makefile 2009-06-19 02:37:58 UTC (rev 73) @@ -1,27 +0,0 @@ -DESTDIR ?= -PREFIX ?= /usr - -BINDIR ?= $(PREFIX)/bin -SHAREDIR ?= $(PREFIX)/share -APPSHAREDIR ?= $(SHAREDIR)/congruity -MANDIR ?= $(SHAREDIR)/man -MAN1DIR ?= $(MANDIR)/man1 - -INSTALL ?= /usr/bin/install - -all: - @echo "Nothing to build, run 'make install' as root" - -install: - mkdir -p --mode=755 $(DESTDIR)$(BINDIR) - $(INSTALL) --mode=755 congruity $(DESTDIR)$(BINDIR)/congruity - mkdir -p --mode=755 $(DESTDIR)$(APPSHAREDIR) - $(INSTALL) --mode=644 *.png $(DESTDIR)$(APPSHAREDIR) - mkdir -p --mode=755 $(DESTDIR)$(MAN1DIR) - $(INSTALL) --mode=644 congruity.1 $(DESTDIR)$(MAN1DIR) - -uninstall: - /bin/rm -f $(DESTDIR)$(BINDIR)/congruity - /bin/rm -rf $(DESTDIR)$(APPSHAREDIR) - /bin/rm -f $(DESTDIR)$(MAN1DIR)/congruity.1 - Copied: tags/congruity-12/Makefile (from rev 69, trunk/Makefile) =================================================================== --- tags/congruity-12/Makefile (rev 0) +++ tags/congruity-12/Makefile 2009-06-19 02:37:58 UTC (rev 73) @@ -0,0 +1,42 @@ +RUN_UPDATE_DESKTOP_DB ?= 1 + +DESTDIR ?= +PREFIX ?= /usr/local + +BINDIR ?= $(PREFIX)/bin +SHAREDIR ?= $(PREFIX)/share +APPSHAREDIR ?= $(SHAREDIR)/congruity +DESKTOPDIR ?= $(SHAREDIR)/applications +MANDIR ?= $(SHAREDIR)/man +MAN1DIR ?= $(MANDIR)/man1 + +INSTALL ?= install +UPDATE_DESKTOP_DB ?= update-desktop-database + +all: + @echo "Nothing to build, run 'make install' as root" + +install: + mkdir -p --mode=755 $(DESTDIR)$(BINDIR) + sed -e "s:/usr/share/congruity:${APPSHAREDIR}:" < congruity > congruity.patched + $(INSTALL) --mode=755 congruity.patched $(DESTDIR)$(BINDIR)/congruity + rm -f congruity.patched + mkdir -p --mode=755 $(DESTDIR)$(APPSHAREDIR) + $(INSTALL) --mode=644 *.png $(DESTDIR)$(APPSHAREDIR) + mkdir -p --mode=755 $(DESTDIR)$(MAN1DIR) + $(INSTALL) --mode=644 congruity.1 $(DESTDIR)$(MAN1DIR) + mkdir -p --mode=755 $(DESTDIR)$(DESKTOPDIR) + $(INSTALL) --mode=644 congruity.desktop $(DESTDIR)$(DESKTOPDIR) +ifeq ($(RUN_UPDATE_DESKTOP_DB),1) + $(UPDATE_DESKTOP_DB) > /dev/null 2>&1 || : +endif + +uninstall: + /bin/rm -f $(DESTDIR)$(BINDIR)/congruity + /bin/rm -rf $(DESTDIR)$(APPSHAREDIR) + /bin/rm -f $(DESTDIR)$(MAN1DIR)/congruity.1 + /bin/rm -f $(DESTDIR)$(DESKTOPDIR)/congruity.desktop +ifeq ($(RUN_UPDATE_DESKTOP_DB),1) + $(UPDATE_DESKTOP_DB) > /dev/null 2>&1 || : +endif + Deleted: tags/congruity-12/README.txt =================================================================== --- trunk/README.txt 2008-10-13 00:13:29 UTC (rev 47) +++ tags/congruity-12/README.txt 2009-06-19 02:37:58 UTC (rev 73) @@ -1,46 +0,0 @@ -Requirements: - -Python (tested with 2.5.1 on Fedora 8) - See http://www.python.org/ -Python ctypes library (included with Python 2.5, separate earlier) - See http://sourceforge.net/projects/ctypes/ -wxPython (tested with wxGTK-2.8.4 on Fedora 8) - See http://www.wxpython.org/ -libconcord (tested with pre-0.20 CVS snapshot on Fedora 8) - See http: http://www.phildev.net/concordance/ - -Installation/Usage: - -You may need to set up udev/similar rules so that the USB device nodes -used by the application are accessible without using root. I use -the following file: - ------ /etc/udev/rules.d/custom-concordance.rules: -SYSFS{idVendor}=="046d", SYSFS{idProduct}=="c110", MODE="666" ------ - -Note that your vendor and product ID may be different. Use lsusb to verify: - ------ -[swarren@esk ~]$ lsusb -... -Bus 005 Device 011: ID 046d:c110 Logitech, Inc. -... ------ - -Remember to differentiate between the Harmony remote and any other Logitech -peripherals you may have! - -Congruity relies on the libconcord library, which must be obtained and -installed separately. Note that you will need to install the Python bindings -for libconcord too; see libconcord/bindings/python/. - -Configure your web browser to open files of type *.EZHex and *.EZUp with the -congruity application. This is typically performed using the dialog box -that appears when a file is about to be downloaded. - -Note that in Firefox, you'll need to change a setting to see the download -action prompt; Otherwise, files will simply be saved to disk without you -being asked. Edit menu -> Preferences menu item -> Main tab -> Select -"Always ask me where to save files." - Copied: tags/congruity-12/README.txt (from rev 59, trunk/README.txt) =================================================================== --- tags/congruity-12/README.txt (rev 0) +++ tags/congruity-12/README.txt 2009-06-19 02:37:58 UTC (rev 73) @@ -0,0 +1,147 @@ +Requirements +============================================================================== + +Python (tested with 2.5.1 on Fedora 9) + See http://www.python.org/ + +Python ctypes library (included with Python 2.5, separate earlier) + See http://sourceforge.net/projects/ctypes/ + +wxPython (tested with wxGTK-2.8.7 on Fedora 9) + See http://www.wxpython.org/ + +libconcord (tested with post-0.20 CVS snapshot on Fedora 9) + See http://www.phildev.net/concordance/ + Note that the python bindings are also required; see + libconcord/bindings/python + +Python, ctypes, and wxPython are typically installed using your distribution's +package management system. If this is not the case, installation instructions +should be located in the documentation accompanying those packages. + +libconcord may be available via your distribution's package management +system. If so, please ensure that you install any sub-packages required to +provide the libconcord Python bindings, e.g. both libconcord and +libconcord-python. + +If installing libconcord from source, please follow the instructions +accompanying the source. Note that the Python bindings must be installed +separately; the bindings are found within the following sub-directory of the +libconcord source package: + + libconcord/bindings/python + +Some versions of libconcord provide a README.txt detailing the installation +process. Otherwise, the basic instructions are to run the following command as +root: + + python setup.py install + +Installation +============================================================================== + +congruity may be installed by running the following command: + + make install + +This command typically requires root access, since the default installation +location is /usr/local. + +Please read Makefile for details of variables that may be set to configure the +installation process, e.g.: + + make install DESTDIR=/tmp/pkgtmp PREFIX=/usr + +Device Node Access Setup +============================================================================== + +You may need to set up udev/similar rules so that the USB device nodes used +by the application are accessible without running congruity as root. Note that +distribution packages of libconcord typically provide these rules, so they may +already be set up for you. + +If you need to manually set up udev rules, the following file should work: + +----- /etc/udev/rules.d/custom-concordance.rules: +SYSFS{idVendor}=="046d", SYSFS{idProduct}=="c110", MODE="666" +----- + +Note that your vendor and product ID may be different. Use lsusb to verify: + +----- +[swarren@esk ~]$ lsusb +... +Bus 005 Device 011: ID 046d:c110 Logitech, Inc. +... +----- + +Remember to differentiate between the Harmony remote and any other Logitech +peripherals you may have! Note that not all Harmony-compatible remotes are +Logitech-branded in the USB listing. + +Usage Model +============================================================================== + +congruity aims to fit into the usage model implemented by the official +Logitech software. The primary differentiation is that congruity is both +open-source and more cross-platform than the official software. + +Harmony remotes are configured using the Logitech website, based at the +following URL: + + http://members.harmonyremote.com/ + +Note that other URLs may be used for remotes that are not branded as +"Harmony". However, the overall process is identical. + +The website provides a database of devices, and a set of wizards to select +which of those are present in your setup. All decisions regarding how the +remote will be configured are made through this website. + +Please note that more recent versions of the Logitech software appear to be +an application that executes locally on the user's computer. However, they are +in fact a simple wrapping of a web-browser, simply hiding the web-based nature +of the configuration process. + +Once the configuration is complete, the website will push various file +downloads to the web browser. These files contain the information required to +program the user's configuration into the remote. For each file downloaded, +the congruity application should be executed to process the instructions in +that file. + +Web Browser Setup +============================================================================== + +Configure your web browser to open files of type *.EZHex, *.EZUp, and *.EZTut +with the congruity application. + +This is typically set up using the dialog box that appears when a file is +about to be downloaded. congruity should be executed once for each file +downloaded, and should be passed the name of the saved download as a command- +line parameter, for example: + + congruity /tmp/Connectivity.EZHex + +If you're confused, the above behavior is most likely what your web browser +will do automatically when configured to open files using congruity. + +Firefox Specific Notes +============================================================================== + +You'll need to change a setting to see the download action prompt; Otherwise, +files will simply be saved to disk without you being asked. On Linux, this may +be achieved from the Edit menu -> Preferences menu item -> Main tab -> Select +"Always ask me where to save files". The exact menu location may vary slightly +on other operating systems. + +When a file download commences, a dialog will appear with the option to "Open +With", or "Save" the file. Select "Open With", and browse for the congruity +executable as the application. You may also want to select "Do this +automatically for files like this from now on". You will need to select the +path to the congruity application once for each file type (*.EZHex, *.EZUp, +*.EZTut). + +If the automatic option is not selected, the dialog will appear for every file +downloaded. Note that Firefox does remember the path to congruity for future +downloads, even though it is not displayed. + Deleted: tags/congruity-12/congruity =================================================================== --- trunk/congruity 2008-10-13 00:13:29 UTC (rev 47) +++ tags/congruity-12/congruity 2009-06-19 02:37:58 UTC (rev 73) @@ -1,1255 +0,0 @@ -#!/usr/bin/python - -# Copyright 2008 Stephen Warren -# -# This file is part of congruity. -# -# congruity 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. -# -# congruity 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 congruity. If not, see <http://www.gnu.org/licenses/>. - -from ctypes import * -import os -import os.path -import sys -import thread -import time -import traceback -import wx -import wx.lib.dialogs - -version = "9+" - -try: - import libconcord - # Fix typo in libconcord 0.20 Python bindings - try: - libconcord.delete_blob - except: - libconcord.delete_blob = libconcord.delete_block -except: - app = wx.PySimpleApp() - dlg = wx.MessageDialog( - None, - "Could not load libconcord; please ensure it, and the Python " - "bindings, are installed and in the relevant search paths.", - "congruity: Dependency Error", - wx.OK | wx.ICON_ERROR - ) - dlg.ShowModal() - os._exit(1) - -def counter(): - i=0 - while True: - yield i - i += 1 - -def program_callback_imp(count, current, total, context): - if not context: - return - - try: - (f, fcontext) = context - percent = (current * 100) / total - f(False, percent, fcontext) - except: - print - traceback.print_exc() - -class CmdLineException(Exception): - pass - -def exception_message(): - msg = '' - if type(sys.exc_value) == libconcord.LibConcordException: - try: - msg += '%s\n (libconcord function %s error %d)\n\n' % ( - sys.exc_value.result_str, - sys.exc_value.func, - sys.exc_value.result - ) - except: - pass - if type(sys.exc_value) == CmdLineException: - try: - msg += '%s\n\n' % ( - str(sys.exc_value) - ) - except: - pass - msg += traceback.format_exc() - return msg - -def worker_body_connect( - resources, - on_progress, - cb_context, - cancel_check, - after_reset -): - program_callback = libconcord.callback_type(program_callback_imp) - - max_attempts = after_reset and 180 or 60 - for attempt in range(max_attempts): - on_progress( - False, - (attempt * 100) / max_attempts, - cb_context - ) - try: - libconcord.init_concord() - resources.SetConnected(True) - try: - libconcord.get_identity( - program_callback, - None - ) - except: - ignore = False - if type(sys.exc_value) == libconcord.LibConcordException: - # FIXME: Expose these constants in libconcord.py - ignore = sys.exc_value.result == 16 #LC_ERROR_INVALID_CONFIG - if not ignore: - raise - break - except: - if cancel_check() or (attempt == max_attempts - 1): - raise - time.sleep(1) - on_progress( - True, - 100, - cb_context - ) - -def show_modal_scrolled_msgbox(parent, title, text): - size = parent.GetClientSizeTuple() - size = (size[0] * 90 / 100, size[1] * 90 / 100) - wx.lib.dialogs.ScrolledMessageDialog( - parent, - text, - title, - (-1, -1), - size - ).ShowModal() - -ALIGN_LTA = wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.ALL -ALIGN_LCA = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL -ALIGN_LBA = wx.ALIGN_LEFT | wx.ALIGN_BOTTOM | wx.ALL - -class WrappedStaticText(wx.StaticText): - def __init__(self, parent): - self.parent = parent - wx.StaticText.__init__(self, parent, -1, "") - - def UpdateText(self, new_label): - cur_width = self.parent.GetSize().GetWidth() - self.SetLabel(new_label) - self.Wrap(cur_width) - self.parent.Layout() - -class DecoratedContainer(wx.Panel): - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.GridBagSizer(5, 5) - self.sizer.AddGrowableCol(2) - self.SetSizer(self.sizer) - - self.last_updated_dg = None - - def _DgStart(self, dg): - self._OnProgressGauge(False, 0, dg) - - def _DgUpdate(self, is_done, percent, dg): - self._OnProgressGauge(is_done, percent, dg) - - def _DgEnd(self, dg): - self._OnProgressGauge(True, 100, dg) - - def _DgFailure(self): - if self.last_updated_dg: - self.last_updated_dg.SetBitmap(self.resources.icon_failed) - - def _OnProgressGauge(self, is_done, percent, dg): - if is_done: - new_bitmap = self.resources.icon_complete - else: - new_bitmap = self.resources.icon_in_progress - dg.SetBitmap(new_bitmap) - dg.gauge.SetValue(percent) - self.last_updated_dg = dg - -class DecoratedContainerThreadMixin(object): - def __init__(self, dc): - self.dc = dc - - def _DgStart(self, dg): - wx.CallAfter(self.dc._DgStart, dg) - - def _DgUpdate(self, is_done, percent, dg): - wx.CallAfter(self.dc._DgUpdate, is_done, percent, dg) - - def _DgEnd(self, dg): - wx.CallAfter(self.dc._DgEnd, dg) - - def _DgFailure(self): - wx.CallAfter(self.dc._DgFailure) - -class DecoratedGauge(object): - def __init__(self, parent, caption, vpos): - self.current_bitmap = parent.resources.icon_unstarted - self.bitmap = wx.StaticBitmap( - parent, - -1, - self.current_bitmap, - None, - parent.resources.iwh - ) - self.text = wx.StaticText(parent, -1, caption) - self.gauge = wx.Gauge( - parent, - -1, - 100, - None, - (250, parent.resources.iwh[1]) - ) - parent.sizer.Add(self.bitmap, (vpos, 0), (1, 1), ALIGN_LBA, 5) - parent.sizer.Add(self.text, (vpos, 1), (1, 1), ALIGN_LCA, 5) - parent.sizer.Add(self.gauge, (vpos, 2), (1, 1), ALIGN_LBA, 5) - - def SetBitmap(self, new_bitmap): - if self.current_bitmap == new_bitmap: - return - self.current_bitmap = new_bitmap - self.bitmap.SetBitmap(self.current_bitmap) - -class MessagePanelBase(wx.Panel): - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.text_message = WrappedStaticText(self) - self.sizer.Add(self.text_message, 0, ALIGN_LTA, 5) - self.SetSizerAndFit(self.sizer) - -class WelcomePanel(MessagePanelBase): - _msg_welcome = ( - "Welcome to congruity; a programming application " + - "for Logitech Harmony remote controls.\n\n" - ) - - _msg_progress_parsing = ( - "Please wait while the configuration file is parsed." - ) - - _msg_status_ok = ( - "Please ensure the remote control is connected " + - "before proceeding.\n\n" + - "Click next to begin operation." - ) - - _msg_status_failure = ( - "A problem occurred. Click next for details." - ) - - _msg_failure_explanation = ( - "The configuration file cannot be read, or parsing failed.\n\n" + - "Operation cannot continue." - ) - - _msg_failure_details_unknown_op = ( - "Unrecognized file type '%d' returned by libconcord" - ) - - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - MessagePanelBase.__init__(self, parent, resources) - - self.next = None - self.initial_exception = None - - def _WorkerFunction(self): - try: - wx.CallAfter( - self.text_message.UpdateText, - self._msg_welcome + self._msg_progress_parsing - ) - - if self.initial_exception: - wx.CallAfter( - self._OnStatusFailure, - *self.initial_exception - ) - return - - self.next = self.resources.page_connect - - xml = POINTER(c_ubyte)() - xml_size = c_uint() - libconcord.read_file( - self.resources.ezhex_filename, - byref(xml), - byref(xml_size) - ) - self.resources.SetXmlData(xml, xml_size) - - type = c_int() - libconcord.identify_file(xml, xml_size, byref(type)) - - (next_page, type_text) = { - libconcord.LC_FILE_TYPE_CONNECTIVITY: - ( - self.resources.page_check_connectivity, - "Connectivity Check" - ), - libconcord.LC_FILE_TYPE_CONFIGURATION: - ( - self.resources.page_write_configuration, - "Update Configuration" - ), - libconcord.LC_FILE_TYPE_FIRMWARE: - ( - self.resources.page_update_firmware, - "Update Firmware" - ) - }.get(type.value, (None, None)) - - if not next_page: - wx.CallAfter( - self._OnStatusFailure, - self._msg_failure_explanation, - self._msg_failure_details_unknown_op % type.value - ) - return - - wx.CallAfter(self._OnStatusOk, next_page, type_text) - except: - wx.CallAfter( - self._OnStatusFailure, - self._msg_failure_explanation, - exception_message() - ) - - def _OnStatusOk(self, next_page, type_text): - self.resources.page_connect.SetNext(next_page) - self._OnStatusCommon(self._msg_status_ok) - - def _OnStatusFailure(self, failure_msg, details): - self.resources.page_failure.SetMessages( - failure_msg, - details - ) - self.next = self.resources.page_failure - self._OnStatusCommon(self._msg_status_failure) - - def _OnStatusCommon(self, message): - self.text_message.UpdateText(self._msg_welcome + message) - self.parent.ReenableCancel() - self.parent.ReenableNext() - - def SetInitialException(self, initial_exception): - self.initial_exception = initial_exception - - def OnActivated(self): - thread.start_new_thread(self._WorkerFunction, ()) - - def OnCancel(self): - self.parent.OnExit(1) - - def GetTitle(self): - return "Welcome" - - def IsTerminal(self): - return False - - def IsNextInitiallyDisabled(self): - return True - - def IsCancelInitiallyDisabled(self): - return False - - def GetNext(self): - return self.next - -class ConnectPanel(wx.Panel, DecoratedContainerThreadMixin): - _msg_ensure_connected = ( - "Please ensure your remote is correctly connected to your computer." - ) - - _msg_status_ok = ( - "Successfully connected to a remote:\n%s" - ) - - _msg_status_failure = ( - "A problem occurred. Click next for details." - ) - - _msg_failure_explanation = ( - "No remote could be found." - ) - - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - - self.text_help = WrappedStaticText(self) - self.sizer.Add(self.text_help, 0, wx.ALIGN_LEFT | wx.ALL, 5) - - self.dc = DecoratedContainer(self, resources) - DecoratedContainerThreadMixin.__init__(self, self.dc) - self.dg_connect = DecoratedGauge(self.dc, "Detect Remote", 0) - self.sizer.Add(self.dc, 0, wx.ALIGN_LEFT | wx.ALL, 5) - - self.text_info = WrappedStaticText(self) - self.sizer.Add(self.text_info, 0, wx.ALIGN_LEFT | wx.ALL, 5) - - self.SetSizerAndFit(self.sizer) - - self.next = None - self.finished = False - self.cancelled = False - - self.lock = thread.allocate_lock() - - def _WorkerFunction(self): - try: - wx.CallAfter( - self.text_help.UpdateText, - self._msg_ensure_connected - ) - - self._DgStart(self.dg_connect) - worker_body_connect( - self.resources, - self._DgUpdate, - self.dg_connect, - lambda: self.cancelled, - False - ) - self._DgEnd(self.dg_connect) - - mfg = libconcord.get_mfg() - model = libconcord.get_model() - - mfg_model = mfg + " " + model - wx.CallAfter(self._OnStatusOk, mfg_model) - except: - wx.CallAfter( - self._OnStatusFailure, - self._msg_failure_explanation, - exception_message() - ) - - self.lock.acquire() - self.finished = True - if self.cancelled: - wx.CallAfter(self.OnCancel) - self.lock.release() - - def _OnStatusOk(self, mfg_model): - self.btn_details = wx.Button(self, -1, "&Details...") - self.sizer.Add(self.btn_details, 0, wx.ALIGN_LEFT | wx.ALL, 5) - self.Bind(wx.EVT_BUTTON, self._OnDetails, self.btn_details) - self._OnStatusCommon(self._msg_status_ok % mfg_model) - - def _OnStatusFailure(self, failure_msg, details): - self.dc._DgFailure() - self.resources.page_failure.SetMessages( - failure_msg, - details - ) - self.SetNext(self.resources.page_failure) - self._OnStatusCommon(self._msg_status_failure) - - def _OnStatusCommon(self, message): - self.text_info.UpdateText(message) - self.parent.ReenableNext() - - def _OnDetails(self, event): - try: - msg = "" - - mfg = libconcord.get_mfg() - model = libconcord.get_model() - codename = libconcord.get_codename() - msg += "Model: %s %s (%s)\n" % (msg, model, codename) - - hid_mfg = libconcord.get_hid_mfg_str() - hid_prod = libconcord.get_hid_prod_str() - msg += "USB HID Model: %s %s\n" % (hid_mfg, hid_prod) - - ser_1 = libconcord.get_serial(libconcord.SERIAL_COMPONENT_1) - ser_2 = libconcord.get_serial(libconcord.SERIAL_COMPONENT_2) - ser_3 = libconcord.get_serial(libconcord.SERIAL_COMPONENT_3) - msg += "Serial:\n %s\n %s\n %s\n" % (ser_1, ser_2, ser_3) - - arch = libconcord.get_arch() - proto = libconcord.get_proto() - skin = libconcord.get_skin() - msg += "Arch:%d Proto:%d Skin:%d\n" % (arch, proto, skin) - - fw_type = libconcord.get_fw_type() - fw_ver_maj = libconcord.get_fw_ver_maj() - fw_ver_min = libconcord.get_fw_ver_min() - msg += "Firmware type:%d, version %d.%d\n" % ( - fw_type, fw_ver_maj, fw_ver_min - ) - - hw_ver_maj = libconcord.get_hw_ver_maj() - hw_ver_min = libconcord.get_hw_ver_min() - msg += "HW version %d.%d\n" % (hw_ver_maj, hw_ver_min) - - flash_mfg = libconcord.get_flash_mfg() - flash_id = libconcord.get_flash_id() - flash_part_num = libconcord.get_flash_part_num() - flash_size = libconcord.get_flash_size() - msg += "Flash Manufacturer:%d ID:%d Part:%s Size:%dK\n" % ( - flash_mfg, flash_id, flash_part_num, flash_size - ) - - hid_irl = libconcord.get_hid_irl() - hid_orl = libconcord.get_hid_orl() - hid_frl = libconcord.get_hid_frl() - msg += "USB HID Irl:%d Orl:%d Frl:%d\n" % (hid_irl, hid_orl, hid_frl) - - usb_vid = libconcord.get_usb_vid() - usb_pid = libconcord.get_usb_pid() - usb_bcd = libconcord.get_usb_bcd() - msg += "USB VID:%04x PID:%04x BCD:%04x\n" % (usb_vid, usb_pid, usb_bcd) - - config_bytes_used = libconcord.get_config_bytes_used() - config_bytes_total = libconcord.get_config_bytes_total() - config_pct_used = (config_bytes_used * 100) / config_bytes_total - msg += "Config used %d / total %d = %d%%\n" % ( - config_bytes_used, config_bytes_total, config_pct_used - ) - - fw_nondirect = libconcord.is_fw_update_supported(0) == 0 - fw_direct = libconcord.is_fw_update_supported(1) == 0 - if fw_nondirect or fw_direct: - config_safe = libconcord.is_config_safe_after_fw() == 0 - msg += "Firmware updates: Supported (%s), config%ssafe\n" % ( - fw_direct and "Direct" or "Not direct", - config_safe and " " or " NOT " - ) - else: - msg += "Firmware updates: NOT supported\n" - except: - msg = ( - "Error retrieving remote information:\n" + - exception_message() - ) - - show_modal_scrolled_msgbox(self.parent, "Remote Information", msg) - - def SetNext(self, next): - self.next = next - - def OnActivated(self): - thread.start_new_thread(self._WorkerFunction, ()) - - def OnCancel(self): - self.lock.acquire() - if self.finished: - self.lock.release() - self.parent.OnExit(1) - else: - self.cancelled = True - self.lock.release() - - def GetTitle(self): - return "Connecting" - - def IsTerminal(self): - return False - - def IsNextInitiallyDisabled(self): - return True - - def IsCancelInitiallyDisabled(self): - return False - - def GetNext(self): - return self.next - -class ProgramRemotePanelBase(wx.Panel, DecoratedContainerThreadMixin): - def __init__(self, parent, resources, file_type): - self.parent = parent - self.resources = resources - self.file_type = file_type - - wx.Panel.__init__(self, parent) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - - self.dc = DecoratedContainer(self, resources) - DecoratedContainerThreadMixin.__init__(self, self.dc) - self._AddWidgets() - self.sizer.Add(self.dc, 0, wx.ALIGN_LEFT | wx.ALL, 5) - - self.SetSizerAndFit(self.sizer) - - self.next = None - self.finished = False - - def _WorkerFunction(self): - try: - try: - self._WorkerFunctionBody() - wx.CallAfter(self._OnStatusOk) - return - except: - wx.CallAfter( - self._OnStatusFailure, - "Operation Failed", - exception_message() - ) - finally: - try: - if self.resources.connected: - self.resources.SetConnected(False) - libconcord.deinit_concord() - except: - pass - - def _OnStatusOk(self): - self.next = self.resources.page_success - self._OnStatusCommon() - - def _OnStatusFailure(self, failure_msg, details): - self.dc._DgFailure() - self.next = self.resources.page_failure - self.resources.page_failure.SetMessages( - failure_msg, - details - ) - self._OnStatusCommon() - - def _OnStatusCommon(self): - self.finished = True - self.parent.ReenableCancel() - self.parent.ReenableNext() - - def OnActivated(self): - thread.start_new_thread(self._WorkerFunction, ()) - - def OnCancel(self): - if self.finished: - self.parent.OnExit(1) - show_modal_scrolled_msgbox( - self.parent, - "Cannot Cancel", - "Cancel is disabled during programming operations, " + - "to prevent placing the remote into a state that will " + - "potentially be difficult to recover from." - ) - - def IsTerminal(self): - return False - - def IsNextInitiallyDisabled(self): - return True - - def IsCancelInitiallyDisabled(self): - return True - - def GetNext(self): - return self.next - -class CheckConnectivityPanel(ProgramRemotePanelBase): - def __init__(self, parent, resources): - ProgramRemotePanelBase.__init__( - self, - parent, - resources, - libconcord.LC_FILE_TYPE_CONNECTIVITY - ) - - def _AddWidgets(self): - vpos = counter() - self.dg_notify_website = DecoratedGauge(self.dc, "Notify Website", vpos.next()) - - def _WorkerFunctionBody(self): - self._DgUpdate( - False, - 0, - self.dg_notify_website - ) - libconcord.post_connect_test_success( - self.resources.xml, - self.resources.xml_size - ) - self._DgUpdate( - True, - 100, - self.dg_notify_website - ) - - def GetTitle(self): - return "Checking Connectivity" - -class WriteConfigurationPanel(ProgramRemotePanelBase): - def __init__(self, parent, resources): - ProgramRemotePanelBase.__init__( - self, - parent, - resources, - libconcord.LC_FILE_TYPE_CONFIGURATION - ) - - def _AddWidgets(self): - vpos = counter() - self.dg_check_website = DecoratedGauge(self.dc, "Check Website", vpos.next()) - self.dg_prepare = DecoratedGauge(self.dc, "Prepare Remote", vpos.next()) - self.dg_erase = DecoratedGauge(self.dc, "Erase Flash", vpos.next()) - self.dg_write = DecoratedGauge(self.dc, "Write Configuration", vpos.next()) - self.dg_verify = DecoratedGauge(self.dc, "Verify Upgrade", vpos.next()) - self.dg_reconnect = DecoratedGauge(self.dc, "Reconnect to Remote", vpos.next()) - self.dg_set_time = DecoratedGauge(self.dc, "Set Time", vpos.next()) - self.dg_notify_website = DecoratedGauge(self.dc, "Notify Website", vpos.next()) - - def _WorkerFunctionBody(self): - program_callback = libconcord.callback_type(program_callback_imp) - - self._DgStart(self.dg_check_website) - libconcord.post_preconfig(self.resources.xml, self.resources.xml_size) - self._DgEnd(self.dg_check_website) - - self._DgStart(self.dg_prepare) - bin_data = POINTER(c_ubyte)() - bin_size = c_uint() - libconcord.find_config_binary( - self.resources.xml, - self.resources.xml_size, - byref(bin_data), - byref(bin_size) - ) - self._DgUpdate(False, 50, self.dg_prepare) - libconcord.invalidate_flash() - self._DgEnd(self.dg_prepare) - - self._DgStart(self.dg_erase) - libconcord.erase_config( - bin_size, - program_callback, - py_object((self._DgUpdate, self.dg_erase)) - ) - self._DgEnd(self.dg_erase) - - self._DgStart(self.dg_write) - libconcord.write_config_to_remote( - bin_data, - bin_size, - program_callback, - py_object((self._DgUpdate, self.dg_write)) - ) - self._DgEnd(self.dg_write) - - self._DgStart(self.dg_verify) - libconcord.verify_remote_config( - bin_data, - bin_size, - program_callback, - py_object((self._DgUpdate, self.dg_verify)) - ) - self._DgEnd(self.dg_verify) - - self._DgStart(self.dg_reconnect) - libconcord.reset_remote() - worker_body_connect( - self.resources, - self._DgUpdate, - self.dg_reconnect, - lambda: False, - True - ) - - self._DgStart(self.dg_set_time) - libconcord.set_time() - self._DgEnd(self.dg_set_time) - - self._DgStart(self.dg_notify_website) - libconcord.post_postconfig(self.resources.xml, self.resources.xml_size) - self._DgEnd(self.dg_notify_website) - - def GetTitle(self): - return "Updating Configuration" - -class UpdateFirmwarePanel(ProgramRemotePanelBase): - def __init__(self, parent, resources): - ProgramRemotePanelBase.__init__( - self, - parent, - resources, - libconcord.LC_FILE_TYPE_FIRMWARE - ) - - def _AddWidgets(self): - vpos = counter() - self.dg_prepare = DecoratedGauge(self.dc, "Prepare Remote", vpos.next()) - self.dg_erase = DecoratedGauge(self.dc, "Erase Flash", vpos.next()) - self.dg_write = DecoratedGauge(self.dc, "Write Firmware", vpos.next()) - self.dg_finalize = DecoratedGauge(self.dc, "Finalize Programming", vpos.next()) - self.dg_reconnect = DecoratedGauge(self.dc, "Reconnect to Remote", vpos.next()) - self.dg_set_time = DecoratedGauge(self.dc, "Set Time", vpos.next()) - self.dg_notify_website = DecoratedGauge(self.dc, "Notify Website", vpos.next()) - - def _WorkerFunctionBody(self): - program_callback = libconcord.callback_type(program_callback_imp) - - self._DgStart(self.dg_prepare) - - # is_fw_update_supported returns error code; 0 OK, otherwise failure - if libconcord.is_fw_update_supported(0) == 0: - is_direct = False - elif libconcord.is_fw_update_supported(1) == 0: - is_direct = True - else: - raise Exception( - "Sorry, congruity doesn't yet support firmware update " + - "on this remote model." - ) - - self._DgUpdate(False, 25, self.dg_prepare) - - bin_data = POINTER(c_ubyte)() - bin_size = c_uint() - libconcord.extract_firmware_binary( - self.resources.xml, - self.resources.xml_size, - byref(bin_data), - byref(bin_size) - ) - - self._DgUpdate(False, 50, self.dg_prepare) - - if not is_direct: - libconcord.prep_firmware() - - self._DgUpdate(False, 75, self.dg_prepare) - - libconcord.invalidate_flash() - - self._DgEnd(self.dg_prepare) - - self._DgStart(self.dg_erase) - libconcord.erase_firmware( - is_direct, - program_callback, - py_object((self._DgUpdate, self.dg_erase)) - ) - self._DgEnd(self.dg_erase) - - self._DgStart(self.dg_write) - libconcord.write_firmware_to_remote( - bin_data, - bin_size, - c_int(is_direct and 1 or 0), - program_callback, - py_object((self._DgUpdate, self.dg_write)) - ) - self._DgEnd(self.dg_write) - - self._DgStart(self.dg_finalize) - if not is_direct: - libconcord.finish_firmware() - self._DgEnd(self.dg_finalize) - - self._DgStart(self.dg_reconnect) - libconcord.reset_remote() - worker_body_connect( - self.resources, - self._DgUpdate, - self.dg_reconnect, - lambda: False, - True - ) - - self._DgStart(self.dg_set_time) - libconcord.set_time() - self._DgEnd(self.dg_set_time) - - self._DgStart(self.dg_notify_website) - libconcord.post_postfirmware(self.resources.xml, self.resources.xml_size) - self._DgEnd(self.dg_notify_website) - - def GetTitle(self): - return "Updating Firmware" - -class SuccessPanel(MessagePanelBase): - def __init__(self, parent, resources): - MessagePanelBase.__init__( - self, - parent, - resources - ) - - def OnActivated(self): - self.text_message.UpdateText("Operation has completed successfully.") - - def OnCancel(self): - self.parent.OnExit(0) - - def GetTitle(self): - return "Success" - - def IsTerminal(self): - return True - - def GetExitCode(self): - return 0 - - def IsNextInitiallyDisabled(self): - return False - - def IsCancelInitiallyDisabled(self): - return True - -class FailurePanel(wx.Panel): - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.text_message = WrappedStaticText(self) - self.sizer.Add(self.text_message, 0, wx.ALIGN_LEFT | wx.ALL, 5) - self.btn_details = wx.Button(self, -1, "&Details...") - self.Bind(wx.EVT_BUTTON, self._OnDetails, self.btn_details) - self.sizer.Add(self.btn_details, 0, wx.ALIGN_LEFT | wx.ALL, 5) - self.SetSizerAndFit(self.sizer) - - self.message = "" - self.log_text = "" - - def _OnDetails(self, event): - show_modal_scrolled_msgbox(self.parent, "Error Log", self.log_text) - self.parent.ReenableNext() - - def SetMessages(self, message, traceback): - self.message = message - if traceback: - self.message += "\n\nSee below for details." - self.log_text = traceback - - def OnActivated(self): - if self.log_text: - self.btn_details.SetFocus() - else: - self.btn_details.Hide() - self.text_message.UpdateText(self.message) - - def OnCancel(self): - self.parent.OnExit(1) - - def GetTitle(self): - return "Failure" - - def IsTerminal(self): - return True - - def GetExitCode(self): - return 1 - - def IsNextInitiallyDisabled(self): - return False - - def IsCancelInitiallyDisabled(self): - return True - -class Wizard(wx.Dialog): - def __init__( - self, - resources, - app_finalizer, - min_page_width = 450, - min_page_height = None - ): - self.app_finalizer = app_finalizer - - self.min_page_width = min_page_width - self.min_page_height = min_page_height - - wx.Dialog.__init__(self, None, -1, 'Congruity version ' + version) - - sizer_main = wx.BoxSizer(wx.VERTICAL) - - sizer_top = wx.BoxSizer(wx.HORIZONTAL) - bitmap = wx.StaticBitmap(self, -1, resources.img_remote) - sizer_top.Add(bitmap, 0, wx.EXPAND | wx.ALL, 5) - - self.sizer_top_right = wx.BoxSizer(wx.VERTICAL) - self.title = wx.StaticText(self, -1, "Title") - font = wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD) - self.title.SetFont(font) - self.sizer_top_right.Add(self.title, 0, wx.EXPAND) - divider_top_right = wx.StaticLine(self, -1, None, None, wx.LI_HORIZONTAL) - self.sizer_top_right.Add(divider_top_right, 0, wx.EXPAND) - spacer = wx.StaticText(self, -1, "") - self.sizer_top_right.Add(spacer, 0, wx.EXPAND) - - sizer_top.Add(self.sizer_top_right, 1, wx.EXPAND | wx.ALL, 5) - sizer_main.Add(sizer_top, 1, wx.EXPAND | wx.ALL, 5) - - divider_main = wx.StaticLine(self, -1, None, None, wx.LI_HORIZONTAL) - sizer_main.Add(divider_main, 0, wx.EXPAND | wx.ALL, 5) - - sizer_buttons = wx.BoxSizer(wx.HORIZONTAL) - panel_btn_dummy = wx.Panel(self) - sizer_buttons.Add(panel_btn_dummy, 1, wx.EXPAND | wx.ALL, 5) - self.btn_next = wx.Button(self, -1, "&Next >") - self.Bind(wx.EVT_BUTTON, self._OnNext, self.btn_next) - sizer_buttons.Add(self.btn_next, 0, wx.EXPAND | wx.ALL, 5) - self.btn_cancel = wx.Button(self, -1, "&Cancel") - self.Bind(wx.EVT_BUTTON, self._OnCancel, self.btn_cancel) - self.Bind(wx.EVT_CLOSE, self._OnCancel) - sizer_buttons.Add(self.btn_cancel, 0, wx.EXPAND | wx.ALL, 5) - sizer_main.Add(sizer_buttons, 0, wx.EXPAND | wx.ALL, 5) - - self.SetSizerAndFit(sizer_main) - - self.cur_page = None - - def SetPages(self, pages): - def tuple_max(a, b): - return (max(a[0], b[0]), max(a[1], b[1])) - - self.pages = pages - - for page in self.pages: - page.Hide() - - size_wiz = self.GetSizeTuple() - for page in self.pages: - page.Show() - self.sizer_top_right.Add(page, 1, wx.EXPAND) - self.Fit() - size_page = self.GetSizeTuple() - size_wiz = tuple_max(size_wiz, size_page) - page.Hide() - self.sizer_top_right.Remove(page) - - if self.min_page_width and (size_wiz[0] < self.min_page_width): - size_wiz = (self.min_page_width, size_wiz[1]) - - if self.min_page_height and (size_wiz[1] < self.min_page_height): - size_wiz = (size_wiz[0], self.min_page_height ) - - self.SetSize(size_wiz) - - def SetInitialPage(self, page): - if self.cur_page: - raise Exception("Current page already set") - self._SetPage(page) - - def OnExit(self, retcode): - if self.app_finalizer: - self.app_finalizer() - os._exit(retcode) - - def _ReenableButton(self, button): - button.Enable(True) - button.Hide() - button.Show() - button.SetFocus() - - def ReenableNext(self): - self._ReenableButton(self.btn_next) - - def ReenableCancel(self): - self._ReenableButton(self.btn_cancel) - - def _OnNext(self, event): - if self.cur_page.IsTerminal(): - self.OnExit(self.cur_page.GetExitCode()) - next_page = self.cur_page.GetNext() - self._SetPage(next_page) - - def _OnCancel(self, event): - self.cur_page.OnCancel() - - def _SetPage(self, page): - if not page in self.pages: - raise Exception("Invalid page") - - if self.cur_page: - self.cur_page.Hide() - self.sizer_top_right.Remove(self.cur_page) - - self.cur_page = page - - self.cur_page.Show() - self.sizer_top_right.Add(self.cur_page, 1, wx.EXPAND) - - self.title.SetLabel(self.cur_page.GetTitle()) - - self.Layout() - - is_terminal = self.cur_page.IsTerminal() - if is_terminal: - self.btn_next.SetLabel("&Finish") - else: - self.btn_next.SetLabel("&Next >") - - self.btn_next.Enable(not self.cur_page.IsNextInitiallyDisabled()) - self.btn_cancel.Enable( - (not is_terminal) - and - (not self.cur_page.IsCancelInitiallyDisabled()) - ) - self.btn_next.SetFocus() - - self.cur_page.OnActivated() - -class Resources(object): - def __init__(self, appdir): - self.appdir = appdir - - self.ezhex_filename = None - self.xml = None - self.xml_size = None - self.connected = False - - def LoadImages(self): - def load(filename, appdir = self.appdir): - dirs = ['/usr/share/congruity', appdir, '.'] - for dir in dirs: - fpath = os.path.join(dir, filename) - if not os.path.isfile(fpath): - continue - return wx.Image(fpath, wx.BITMAP_TYPE_PNG).ConvertToBitmap() - raise Exception("Can't load " + filename) - - self.img_remote = load("remote.png") - self.icon_unstarted = load("icon-unstarted.png") - self.icon_in_progress = load("icon-in-progress.png") - self.icon_complete = load("icon-complete.png") - self.icon_failed = load("icon-failed.png") - - iw = max( - self.icon_in_progress.GetWidth(), - self.icon_complete.GetWidth(), - self.icon_failed.GetWidth() - ) - ih = max( - self.icon_in_progress.GetHeight(), - self.icon_complete.GetHeight(), - self.icon_failed.GetHeight() - ) - self.iwh = (iw, ih) - - def CreatePages(self, wizard): - self.page_welcome = WelcomePanel(wizard, self) - self.page_connect = ConnectPanel(wizard, self) - self.page_check_connectivity = CheckConnectivityPanel(wizard, self) - self.page_write_configuration = WriteConfigurationPanel(wizard, self) - self.page_update_firmware = UpdateFirmwarePanel(wizard, self) - self.page_success = SuccessPanel(wizard, self) - self.page_failure = FailurePanel(wizard, self) - - def SetEzHexFilename(self, ezhex_filename): - self.ezhex_filename = ezhex_filename - - def SetXmlData(self, xml, xml_size): - self.xml = xml - self.xml_size = xml_size - - def SetConnected(self, connected):... [truncated message content] |
From: <srw...@us...> - 2009-06-19 02:36:11
|
Revision: 72 http://congruity.svn.sourceforge.net/congruity/?rev=72&view=rev Author: srwarren Date: 2009-06-19 02:35:57 +0000 (Fri, 19 Jun 2009) Log Message: ----------- Version 12. Add congruity.desktop to release tar file Modified Paths: -------------- trunk/Changelog trunk/congruity trunk/mkrelease.sh Modified: trunk/Changelog =================================================================== --- trunk/Changelog 2009-06-18 03:55:11 UTC (rev 71) +++ trunk/Changelog 2009-06-19 02:35:57 UTC (rev 72) @@ -1,4 +1,8 @@ * 2009-06-17 Stephen Warren <s-t...@ww...> +- congruity-12 is released +- Add congruity.desktop to release script + +* 2009-06-17 Stephen Warren <s-t...@ww...> - congruity-11 is released - Fix Pronto hex import Patch by Andreas Schulz <And...@gm...> Modified: trunk/congruity =================================================================== --- trunk/congruity 2009-06-18 03:55:11 UTC (rev 71) +++ trunk/congruity 2009-06-19 02:35:57 UTC (rev 72) @@ -30,7 +30,7 @@ import wx import wx.lib.dialogs -version = "11" +version = "12" try: import libconcord Modified: trunk/mkrelease.sh =================================================================== --- trunk/mkrelease.sh 2009-06-18 03:55:11 UTC (rev 71) +++ trunk/mkrelease.sh 2009-06-19 02:35:57 UTC (rev 72) @@ -22,6 +22,7 @@ *.png \ Changelog \ congruity.1 \ + congruity.desktop \ COPYING \ LICENSE.txt \ Makefile \ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2009-06-18 03:55:45
|
Revision: 71 http://congruity.svn.sourceforge.net/congruity/?rev=71&view=rev Author: srwarren Date: 2009-06-18 03:55:11 +0000 (Thu, 18 Jun 2009) Log Message: ----------- Tag congruity-11 Added Paths: ----------- tags/congruity-11/ tags/congruity-11/Changelog tags/congruity-11/Makefile tags/congruity-11/README.txt tags/congruity-11/congruity tags/congruity-11/congruity.desktop tags/congruity-11/icon-sources.txt Removed Paths: ------------- tags/congruity-11/Changelog tags/congruity-11/Makefile tags/congruity-11/README.txt tags/congruity-11/congruity Property changes on: tags/congruity-11 ___________________________________________________________________ Added: svn:mergeinfo + Deleted: tags/congruity-11/Changelog =================================================================== --- trunk/Changelog 2008-10-13 00:13:29 UTC (rev 47) +++ tags/congruity-11/Changelog 2009-06-18 03:55:11 UTC (rev 71) @@ -1,101 +0,0 @@ -* 2008-09-07 Stephen Warren <s-t...@ww...> -- congruity-9 is released -- Use a different remote.png, with a known free license. - -* 2008-07-03 Stephen Warren <s-t...@ww...> -- congruity-8 is released -- Centralize cancel/exit handling, - and clean up any libconcord resources when exiting the application. -- Add thread-safe cancelling to ConnectPanel. -- Work around a typo in libconcord 0.20's Python bindings. -- Provide a GUI message if libconcord can't be loaded, in case congruity - wasn't run from a terminal. - -* 2008-07-02 Stephen Warren <s-t...@ww...> -- Increase connect timeout after a reset operation, just to make sure - we don't miss the remote coming back. -- Fix Makefile to create all directories files are written to, and add - a few more variables that can be tweaked e.g. by packaging scripts. -* On behalf of Andreas Schulz <And...@gm...> -- Use a simpler and potentially more reliable fix for GTK buttons not - accepting clicks if the mouse was inside the widget when enabled. - -* 2008-07-01 Stephen Warren <s-t...@ww...> -- Command-line parsing errors are displayed by the GUI, instead of being - echo'd to stdout. This makes errors visible when congruity is launched - without a terminal - -* 2008-06-25..2008-07-01 Stephen Warren <s-t...@ww...> -* Inspired by Andreas Schulz <And...@gm...> -- Significant internal structural changes to the implementation, which - simplify things a lot, and make program flow far more obvious, localized, - and correctly polymorphic. -- Add a separate "connect" page, so that the other pages don't have to - re-implement this common function. - -* 2008-06-17 Stephen Warren <s-t...@ww...> -* On behalf of Andreas Schulz <And...@gm...> -- Fix issue where next button wouldn't respond to clicks if the pointer was - already within the button when it was re-enabled. - -* 2008-04-14 Stephen Warren <s-t...@ww...> -- congruity-7 is released -- Switched license to GPLv3+ to be compatible with libconcord by default. - Contact me if you want the code under a different license, but please - note that you won't be able to use relicensed code with libconcord. -- Added a Makefile for easy installation. - Thanks to Phil Dibowitz for the contribution. -- Added a manual page. -- Added a few useful URLs to README.txt. -- Fixed reliance on syntax specific to Python 2.5. - -* 2008-04-13 Stephen Warren <s-t...@ww...> -- congruity-6 is released -- Search for images in /usr/share/congruity, the source directory, then - CWD. This should allow easy system-wide installation of congruity. -- libconcord.py is no longer distributed with congruity; it is now part - of libconcord itself (see libconcord/bindings/python/). -- Apparently forgot to release LICENSE.txt before. - -* 2008-04-07 Stephen Warren <s-t...@ww...> -- congruity-5 is released -- This release solely operates using libconcord; "screen-scraping" the output - from the concordance application is no longer supported. -- Implement firmware upgrade. -- Minor tweaks for operation on MS-Windows. -- congruity now sets the time on the remote after any reboot. - -* 2008-03-29 Stephen Warren <s-t...@ww...> -- congruity-4 is released -- Renamed package from harmonygui to congruity, in line with the - coming rename of the harmonycontrol project to concordance/libconcord. -- Changes to match latest CVS libconcord API changes - -* 2008-02-24 Stephen Warren <s-t...@ww...> -- harmonygui-3 is released -- Added README.txt. -- Added LICENSING.txt, to account for images too. -- Remove GUI for initial web connection in update mode; the libharmony - branch code doesn't print this status information, so now we act like - it was never there. -- Code re-org, to allow for multiple back-ends. -- Added a back-end that calls libharmony.so directly using ctypes. - -* 2008-02-10 Stephen Warren <s-t...@ww...> -- harmonygui-2 is released -- Updated ezhexparser to recognize firmware update files. -- Updated GUI to handle firmware updates, by informing user its - not yet supported. -- Separated ezhexparser and tuiparser operation mode enumerations. -- Enhanced ptyrun error handling, so it's more obvious what happened - when the harmony application can't be found in the $PATH. -- Updated harmonyfake to use ^H characters to re-write output, not - \r. This matches the real harmony app. -- Minor typo cleanups in messages. -- Added licensing information. -- Added this Changelog - -* 2008-02-05 Stephen Warren <s-t...@ww...> -- harmonygui-1 is released -- Initial release. - Copied: tags/congruity-11/Changelog (from rev 70, trunk/Changelog) =================================================================== --- tags/congruity-11/Changelog (rev 0) +++ tags/congruity-11/Changelog 2009-06-18 03:55:11 UTC (rev 71) @@ -0,0 +1,125 @@ +* 2009-06-17 Stephen Warren <s-t...@ww...> +- congruity-11 is released +- Fix Pronto hex import + Patch by Andreas Schulz <And...@gm...> +- Throw runtime error dialog if wxPython version is not at least 2.8 +- Add .desktop file + Patch by Adam Williamson <awi...@re...> + +* 2009-03-09 Stephen Warren <s-t...@ww...> +- congruity-10 is released +- Implement IR learning feature, with support for learning from the original + remote using the Harmony, or reading the signal from a "Pronto Hex" file. + (Merge of /branches/irlean) + Parts based on code by Andreas Schulz <And...@gm...> +- Various internal code changes to support IR learning and general cleanup. +- Implement --no-web command-line option, which prevents posting any data + to the Harmony website. This can be useful when testing congruity. +- Change default install prefix to /usr/local; this makes typical end-user + manual installs slightly simpler. Also, automatically patch install location + into the app during installation. +- If libconcord import fails, display the entire backtrace information, to + enable easier debugging of the issue. +- Enhance README + +* 2008-09-07 Stephen Warren <s-t...@ww...> +- congruity-9 is released +- Use a different remote.png, with a known free license. + +* 2008-07-03 Stephen Warren <s-t...@ww...> +- congruity-8 is released +- Centralize cancel/exit handling, + and clean up any libconcord resources when exiting the application. +- Add thread-safe cancelling to ConnectPanel. +- Work around a typo in libconcord 0.20's Python bindings. +- Provide a GUI message if libconcord can't be loaded, in case congruity + wasn't run from a terminal. + +* 2008-07-02 Stephen Warren <s-t...@ww...> +- Increase connect timeout after a reset operation, just to make sure + we don't miss the remote coming back. +- Fix Makefile to create all directories files are written to, and add + a few more variables that can be tweaked e.g. by packaging scripts. +* On behalf of Andreas Schulz <And...@gm...> +- Use a simpler and potentially more reliable fix for GTK buttons not + accepting clicks if the mouse was inside the widget when enabled. + +* 2008-07-01 Stephen Warren <s-t...@ww...> +- Command-line parsing errors are displayed by the GUI, instead of being + echo'd to stdout. This makes errors visible when congruity is launched + without a terminal + +* 2008-06-25..2008-07-01 Stephen Warren <s-t...@ww...> +* Inspired by Andreas Schulz <And...@gm...> +- Significant internal structural changes to the implementation, which + simplify things a lot, and make program flow far more obvious, localized, + and correctly polymorphic. +- Add a separate "connect" page, so that the other pages don't have to + re-implement this common function. + +* 2008-06-17 Stephen Warren <s-t...@ww...> +* On behalf of Andreas Schulz <And...@gm...> +- Fix issue where next button wouldn't respond to clicks if the pointer was + already within the button when it was re-enabled. + +* 2008-04-14 Stephen Warren <s-t...@ww...> +- congruity-7 is released +- Switched license to GPLv3+ to be compatible with libconcord by default. + Contact me if you want the code under a different license, but please + note that you won't be able to use relicensed code with libconcord. +- Added a Makefile for easy installation. + Thanks to Phil Dibowitz for the contribution. +- Added a manual page. +- Added a few useful URLs to README.txt. +- Fixed reliance on syntax specific to Python 2.5. + +* 2008-04-13 Stephen Warren <s-t...@ww...> +- congruity-6 is released +- Search for images in /usr/share/congruity, the source directory, then + CWD. This should allow easy system-wide installation of congruity. +- libconcord.py is no longer distributed with congruity; it is now part + of libconcord itself (see libconcord/bindings/python/). +- Apparently forgot to release LICENSE.txt before. + +* 2008-04-07 Stephen Warren <s-t...@ww...> +- congruity-5 is released +- This release solely operates using libconcord; "screen-scraping" the output + from the concordance application is no longer supported. +- Implement firmware upgrade. +- Minor tweaks for operation on MS-Windows. +- congruity now sets the time on the remote after any reboot. + +* 2008-03-29 Stephen Warren <s-t...@ww...> +- congruity-4 is released +- Renamed package from harmonygui to congruity, in line with the + coming rename of the harmonycontrol project to concordance/libconcord. +- Changes to match latest CVS libconcord API changes + +* 2008-02-24 Stephen Warren <s-t...@ww...> +- harmonygui-3 is released +- Added README.txt. +- Added LICENSING.txt, to account for images too. +- Remove GUI for initial web connection in update mode; the libharmony + branch code doesn't print this status information, so now we act like + it was never there. +- Code re-org, to allow for multiple back-ends. +- Added a back-end that calls libharmony.so directly using ctypes. + +* 2008-02-10 Stephen Warren <s-t...@ww...> +- harmonygui-2 is released +- Updated ezhexparser to recognize firmware update files. +- Updated GUI to handle firmware updates, by informing user its + not yet supported. +- Separated ezhexparser and tuiparser operation mode enumerations. +- Enhanced ptyrun error handling, so it's more obvious what happened + when the harmony application can't be found in the $PATH. +- Updated harmonyfake to use ^H characters to re-write output, not + \r. This matches the real harmony app. +- Minor typo cleanups in messages. +- Added licensing information. +- Added this Changelog + +* 2008-02-05 Stephen Warren <s-t...@ww...> +- harmonygui-1 is released +- Initial release. + Deleted: tags/congruity-11/Makefile =================================================================== --- trunk/Makefile 2008-10-13 00:13:29 UTC (rev 47) +++ tags/congruity-11/Makefile 2009-06-18 03:55:11 UTC (rev 71) @@ -1,27 +0,0 @@ -DESTDIR ?= -PREFIX ?= /usr - -BINDIR ?= $(PREFIX)/bin -SHAREDIR ?= $(PREFIX)/share -APPSHAREDIR ?= $(SHAREDIR)/congruity -MANDIR ?= $(SHAREDIR)/man -MAN1DIR ?= $(MANDIR)/man1 - -INSTALL ?= /usr/bin/install - -all: - @echo "Nothing to build, run 'make install' as root" - -install: - mkdir -p --mode=755 $(DESTDIR)$(BINDIR) - $(INSTALL) --mode=755 congruity $(DESTDIR)$(BINDIR)/congruity - mkdir -p --mode=755 $(DESTDIR)$(APPSHAREDIR) - $(INSTALL) --mode=644 *.png $(DESTDIR)$(APPSHAREDIR) - mkdir -p --mode=755 $(DESTDIR)$(MAN1DIR) - $(INSTALL) --mode=644 congruity.1 $(DESTDIR)$(MAN1DIR) - -uninstall: - /bin/rm -f $(DESTDIR)$(BINDIR)/congruity - /bin/rm -rf $(DESTDIR)$(APPSHAREDIR) - /bin/rm -f $(DESTDIR)$(MAN1DIR)/congruity.1 - Copied: tags/congruity-11/Makefile (from rev 69, trunk/Makefile) =================================================================== --- tags/congruity-11/Makefile (rev 0) +++ tags/congruity-11/Makefile 2009-06-18 03:55:11 UTC (rev 71) @@ -0,0 +1,42 @@ +RUN_UPDATE_DESKTOP_DB ?= 1 + +DESTDIR ?= +PREFIX ?= /usr/local + +BINDIR ?= $(PREFIX)/bin +SHAREDIR ?= $(PREFIX)/share +APPSHAREDIR ?= $(SHAREDIR)/congruity +DESKTOPDIR ?= $(SHAREDIR)/applications +MANDIR ?= $(SHAREDIR)/man +MAN1DIR ?= $(MANDIR)/man1 + +INSTALL ?= install +UPDATE_DESKTOP_DB ?= update-desktop-database + +all: + @echo "Nothing to build, run 'make install' as root" + +install: + mkdir -p --mode=755 $(DESTDIR)$(BINDIR) + sed -e "s:/usr/share/congruity:${APPSHAREDIR}:" < congruity > congruity.patched + $(INSTALL) --mode=755 congruity.patched $(DESTDIR)$(BINDIR)/congruity + rm -f congruity.patched + mkdir -p --mode=755 $(DESTDIR)$(APPSHAREDIR) + $(INSTALL) --mode=644 *.png $(DESTDIR)$(APPSHAREDIR) + mkdir -p --mode=755 $(DESTDIR)$(MAN1DIR) + $(INSTALL) --mode=644 congruity.1 $(DESTDIR)$(MAN1DIR) + mkdir -p --mode=755 $(DESTDIR)$(DESKTOPDIR) + $(INSTALL) --mode=644 congruity.desktop $(DESTDIR)$(DESKTOPDIR) +ifeq ($(RUN_UPDATE_DESKTOP_DB),1) + $(UPDATE_DESKTOP_DB) > /dev/null 2>&1 || : +endif + +uninstall: + /bin/rm -f $(DESTDIR)$(BINDIR)/congruity + /bin/rm -rf $(DESTDIR)$(APPSHAREDIR) + /bin/rm -f $(DESTDIR)$(MAN1DIR)/congruity.1 + /bin/rm -f $(DESTDIR)$(DESKTOPDIR)/congruity.desktop +ifeq ($(RUN_UPDATE_DESKTOP_DB),1) + $(UPDATE_DESKTOP_DB) > /dev/null 2>&1 || : +endif + Deleted: tags/congruity-11/README.txt =================================================================== --- trunk/README.txt 2008-10-13 00:13:29 UTC (rev 47) +++ tags/congruity-11/README.txt 2009-06-18 03:55:11 UTC (rev 71) @@ -1,46 +0,0 @@ -Requirements: - -Python (tested with 2.5.1 on Fedora 8) - See http://www.python.org/ -Python ctypes library (included with Python 2.5, separate earlier) - See http://sourceforge.net/projects/ctypes/ -wxPython (tested with wxGTK-2.8.4 on Fedora 8) - See http://www.wxpython.org/ -libconcord (tested with pre-0.20 CVS snapshot on Fedora 8) - See http: http://www.phildev.net/concordance/ - -Installation/Usage: - -You may need to set up udev/similar rules so that the USB device nodes -used by the application are accessible without using root. I use -the following file: - ------ /etc/udev/rules.d/custom-concordance.rules: -SYSFS{idVendor}=="046d", SYSFS{idProduct}=="c110", MODE="666" ------ - -Note that your vendor and product ID may be different. Use lsusb to verify: - ------ -[swarren@esk ~]$ lsusb -... -Bus 005 Device 011: ID 046d:c110 Logitech, Inc. -... ------ - -Remember to differentiate between the Harmony remote and any other Logitech -peripherals you may have! - -Congruity relies on the libconcord library, which must be obtained and -installed separately. Note that you will need to install the Python bindings -for libconcord too; see libconcord/bindings/python/. - -Configure your web browser to open files of type *.EZHex and *.EZUp with the -congruity application. This is typically performed using the dialog box -that appears when a file is about to be downloaded. - -Note that in Firefox, you'll need to change a setting to see the download -action prompt; Otherwise, files will simply be saved to disk without you -being asked. Edit menu -> Preferences menu item -> Main tab -> Select -"Always ask me where to save files." - Copied: tags/congruity-11/README.txt (from rev 59, trunk/README.txt) =================================================================== --- tags/congruity-11/README.txt (rev 0) +++ tags/congruity-11/README.txt 2009-06-18 03:55:11 UTC (rev 71) @@ -0,0 +1,147 @@ +Requirements +============================================================================== + +Python (tested with 2.5.1 on Fedora 9) + See http://www.python.org/ + +Python ctypes library (included with Python 2.5, separate earlier) + See http://sourceforge.net/projects/ctypes/ + +wxPython (tested with wxGTK-2.8.7 on Fedora 9) + See http://www.wxpython.org/ + +libconcord (tested with post-0.20 CVS snapshot on Fedora 9) + See http://www.phildev.net/concordance/ + Note that the python bindings are also required; see + libconcord/bindings/python + +Python, ctypes, and wxPython are typically installed using your distribution's +package management system. If this is not the case, installation instructions +should be located in the documentation accompanying those packages. + +libconcord may be available via your distribution's package management +system. If so, please ensure that you install any sub-packages required to +provide the libconcord Python bindings, e.g. both libconcord and +libconcord-python. + +If installing libconcord from source, please follow the instructions +accompanying the source. Note that the Python bindings must be installed +separately; the bindings are found within the following sub-directory of the +libconcord source package: + + libconcord/bindings/python + +Some versions of libconcord provide a README.txt detailing the installation +process. Otherwise, the basic instructions are to run the following command as +root: + + python setup.py install + +Installation +============================================================================== + +congruity may be installed by running the following command: + + make install + +This command typically requires root access, since the default installation +location is /usr/local. + +Please read Makefile for details of variables that may be set to configure the +installation process, e.g.: + + make install DESTDIR=/tmp/pkgtmp PREFIX=/usr + +Device Node Access Setup +============================================================================== + +You may need to set up udev/similar rules so that the USB device nodes used +by the application are accessible without running congruity as root. Note that +distribution packages of libconcord typically provide these rules, so they may +already be set up for you. + +If you need to manually set up udev rules, the following file should work: + +----- /etc/udev/rules.d/custom-concordance.rules: +SYSFS{idVendor}=="046d", SYSFS{idProduct}=="c110", MODE="666" +----- + +Note that your vendor and product ID may be different. Use lsusb to verify: + +----- +[swarren@esk ~]$ lsusb +... +Bus 005 Device 011: ID 046d:c110 Logitech, Inc. +... +----- + +Remember to differentiate between the Harmony remote and any other Logitech +peripherals you may have! Note that not all Harmony-compatible remotes are +Logitech-branded in the USB listing. + +Usage Model +============================================================================== + +congruity aims to fit into the usage model implemented by the official +Logitech software. The primary differentiation is that congruity is both +open-source and more cross-platform than the official software. + +Harmony remotes are configured using the Logitech website, based at the +following URL: + + http://members.harmonyremote.com/ + +Note that other URLs may be used for remotes that are not branded as +"Harmony". However, the overall process is identical. + +The website provides a database of devices, and a set of wizards to select +which of those are present in your setup. All decisions regarding how the +remote will be configured are made through this website. + +Please note that more recent versions of the Logitech software appear to be +an application that executes locally on the user's computer. However, they are +in fact a simple wrapping of a web-browser, simply hiding the web-based nature +of the configuration process. + +Once the configuration is complete, the website will push various file +downloads to the web browser. These files contain the information required to +program the user's configuration into the remote. For each file downloaded, +the congruity application should be executed to process the instructions in +that file. + +Web Browser Setup +============================================================================== + +Configure your web browser to open files of type *.EZHex, *.EZUp, and *.EZTut +with the congruity application. + +This is typically set up using the dialog box that appears when a file is +about to be downloaded. congruity should be executed once for each file +downloaded, and should be passed the name of the saved download as a command- +line parameter, for example: + + congruity /tmp/Connectivity.EZHex + +If you're confused, the above behavior is most likely what your web browser +will do automatically when configured to open files using congruity. + +Firefox Specific Notes +============================================================================== + +You'll need to change a setting to see the download action prompt; Otherwise, +files will simply be saved to disk without you being asked. On Linux, this may +be achieved from the Edit menu -> Preferences menu item -> Main tab -> Select +"Always ask me where to save files". The exact menu location may vary slightly +on other operating systems. + +When a file download commences, a dialog will appear with the option to "Open +With", or "Save" the file. Select "Open With", and browse for the congruity +executable as the application. You may also want to select "Do this +automatically for files like this from now on". You will need to select the +path to the congruity application once for each file type (*.EZHex, *.EZUp, +*.EZTut). + +If the automatic option is not selected, the dialog will appear for every file +downloaded. Note that Firefox does remember the path to congruity for future +downloads, even though it is not displayed. + Deleted: tags/congruity-11/congruity =================================================================== --- trunk/congruity 2008-10-13 00:13:29 UTC (rev 47) +++ tags/congruity-11/congruity 2009-06-18 03:55:11 UTC (rev 71) @@ -1,1255 +0,0 @@ -#!/usr/bin/python - -# Copyright 2008 Stephen Warren -# -# This file is part of congruity. -# -# congruity 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. -# -# congruity 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 congruity. If not, see <http://www.gnu.org/licenses/>. - -from ctypes import * -import os -import os.path -import sys -import thread -import time -import traceback -import wx -import wx.lib.dialogs - -version = "9+" - -try: - import libconcord - # Fix typo in libconcord 0.20 Python bindings - try: - libconcord.delete_blob - except: - libconcord.delete_blob = libconcord.delete_block -except: - app = wx.PySimpleApp() - dlg = wx.MessageDialog( - None, - "Could not load libconcord; please ensure it, and the Python " - "bindings, are installed and in the relevant search paths.", - "congruity: Dependency Error", - wx.OK | wx.ICON_ERROR - ) - dlg.ShowModal() - os._exit(1) - -def counter(): - i=0 - while True: - yield i - i += 1 - -def program_callback_imp(count, current, total, context): - if not context: - return - - try: - (f, fcontext) = context - percent = (current * 100) / total - f(False, percent, fcontext) - except: - print - traceback.print_exc() - -class CmdLineException(Exception): - pass - -def exception_message(): - msg = '' - if type(sys.exc_value) == libconcord.LibConcordException: - try: - msg += '%s\n (libconcord function %s error %d)\n\n' % ( - sys.exc_value.result_str, - sys.exc_value.func, - sys.exc_value.result - ) - except: - pass - if type(sys.exc_value) == CmdLineException: - try: - msg += '%s\n\n' % ( - str(sys.exc_value) - ) - except: - pass - msg += traceback.format_exc() - return msg - -def worker_body_connect( - resources, - on_progress, - cb_context, - cancel_check, - after_reset -): - program_callback = libconcord.callback_type(program_callback_imp) - - max_attempts = after_reset and 180 or 60 - for attempt in range(max_attempts): - on_progress( - False, - (attempt * 100) / max_attempts, - cb_context - ) - try: - libconcord.init_concord() - resources.SetConnected(True) - try: - libconcord.get_identity( - program_callback, - None - ) - except: - ignore = False - if type(sys.exc_value) == libconcord.LibConcordException: - # FIXME: Expose these constants in libconcord.py - ignore = sys.exc_value.result == 16 #LC_ERROR_INVALID_CONFIG - if not ignore: - raise - break - except: - if cancel_check() or (attempt == max_attempts - 1): - raise - time.sleep(1) - on_progress( - True, - 100, - cb_context - ) - -def show_modal_scrolled_msgbox(parent, title, text): - size = parent.GetClientSizeTuple() - size = (size[0] * 90 / 100, size[1] * 90 / 100) - wx.lib.dialogs.ScrolledMessageDialog( - parent, - text, - title, - (-1, -1), - size - ).ShowModal() - -ALIGN_LTA = wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.ALL -ALIGN_LCA = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL -ALIGN_LBA = wx.ALIGN_LEFT | wx.ALIGN_BOTTOM | wx.ALL - -class WrappedStaticText(wx.StaticText): - def __init__(self, parent): - self.parent = parent - wx.StaticText.__init__(self, parent, -1, "") - - def UpdateText(self, new_label): - cur_width = self.parent.GetSize().GetWidth() - self.SetLabel(new_label) - self.Wrap(cur_width) - self.parent.Layout() - -class DecoratedContainer(wx.Panel): - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.GridBagSizer(5, 5) - self.sizer.AddGrowableCol(2) - self.SetSizer(self.sizer) - - self.last_updated_dg = None - - def _DgStart(self, dg): - self._OnProgressGauge(False, 0, dg) - - def _DgUpdate(self, is_done, percent, dg): - self._OnProgressGauge(is_done, percent, dg) - - def _DgEnd(self, dg): - self._OnProgressGauge(True, 100, dg) - - def _DgFailure(self): - if self.last_updated_dg: - self.last_updated_dg.SetBitmap(self.resources.icon_failed) - - def _OnProgressGauge(self, is_done, percent, dg): - if is_done: - new_bitmap = self.resources.icon_complete - else: - new_bitmap = self.resources.icon_in_progress - dg.SetBitmap(new_bitmap) - dg.gauge.SetValue(percent) - self.last_updated_dg = dg - -class DecoratedContainerThreadMixin(object): - def __init__(self, dc): - self.dc = dc - - def _DgStart(self, dg): - wx.CallAfter(self.dc._DgStart, dg) - - def _DgUpdate(self, is_done, percent, dg): - wx.CallAfter(self.dc._DgUpdate, is_done, percent, dg) - - def _DgEnd(self, dg): - wx.CallAfter(self.dc._DgEnd, dg) - - def _DgFailure(self): - wx.CallAfter(self.dc._DgFailure) - -class DecoratedGauge(object): - def __init__(self, parent, caption, vpos): - self.current_bitmap = parent.resources.icon_unstarted - self.bitmap = wx.StaticBitmap( - parent, - -1, - self.current_bitmap, - None, - parent.resources.iwh - ) - self.text = wx.StaticText(parent, -1, caption) - self.gauge = wx.Gauge( - parent, - -1, - 100, - None, - (250, parent.resources.iwh[1]) - ) - parent.sizer.Add(self.bitmap, (vpos, 0), (1, 1), ALIGN_LBA, 5) - parent.sizer.Add(self.text, (vpos, 1), (1, 1), ALIGN_LCA, 5) - parent.sizer.Add(self.gauge, (vpos, 2), (1, 1), ALIGN_LBA, 5) - - def SetBitmap(self, new_bitmap): - if self.current_bitmap == new_bitmap: - return - self.current_bitmap = new_bitmap - self.bitmap.SetBitmap(self.current_bitmap) - -class MessagePanelBase(wx.Panel): - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.text_message = WrappedStaticText(self) - self.sizer.Add(self.text_message, 0, ALIGN_LTA, 5) - self.SetSizerAndFit(self.sizer) - -class WelcomePanel(MessagePanelBase): - _msg_welcome = ( - "Welcome to congruity; a programming application " + - "for Logitech Harmony remote controls.\n\n" - ) - - _msg_progress_parsing = ( - "Please wait while the configuration file is parsed." - ) - - _msg_status_ok = ( - "Please ensure the remote control is connected " + - "before proceeding.\n\n" + - "Click next to begin operation." - ) - - _msg_status_failure = ( - "A problem occurred. Click next for details." - ) - - _msg_failure_explanation = ( - "The configuration file cannot be read, or parsing failed.\n\n" + - "Operation cannot continue." - ) - - _msg_failure_details_unknown_op = ( - "Unrecognized file type '%d' returned by libconcord" - ) - - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - MessagePanelBase.__init__(self, parent, resources) - - self.next = None - self.initial_exception = None - - def _WorkerFunction(self): - try: - wx.CallAfter( - self.text_message.UpdateText, - self._msg_welcome + self._msg_progress_parsing - ) - - if self.initial_exception: - wx.CallAfter( - self._OnStatusFailure, - *self.initial_exception - ) - return - - self.next = self.resources.page_connect - - xml = POINTER(c_ubyte)() - xml_size = c_uint() - libconcord.read_file( - self.resources.ezhex_filename, - byref(xml), - byref(xml_size) - ) - self.resources.SetXmlData(xml, xml_size) - - type = c_int() - libconcord.identify_file(xml, xml_size, byref(type)) - - (next_page, type_text) = { - libconcord.LC_FILE_TYPE_CONNECTIVITY: - ( - self.resources.page_check_connectivity, - "Connectivity Check" - ), - libconcord.LC_FILE_TYPE_CONFIGURATION: - ( - self.resources.page_write_configuration, - "Update Configuration" - ), - libconcord.LC_FILE_TYPE_FIRMWARE: - ( - self.resources.page_update_firmware, - "Update Firmware" - ) - }.get(type.value, (None, None)) - - if not next_page: - wx.CallAfter( - self._OnStatusFailure, - self._msg_failure_explanation, - self._msg_failure_details_unknown_op % type.value - ) - return - - wx.CallAfter(self._OnStatusOk, next_page, type_text) - except: - wx.CallAfter( - self._OnStatusFailure, - self._msg_failure_explanation, - exception_message() - ) - - def _OnStatusOk(self, next_page, type_text): - self.resources.page_connect.SetNext(next_page) - self._OnStatusCommon(self._msg_status_ok) - - def _OnStatusFailure(self, failure_msg, details): - self.resources.page_failure.SetMessages( - failure_msg, - details - ) - self.next = self.resources.page_failure - self._OnStatusCommon(self._msg_status_failure) - - def _OnStatusCommon(self, message): - self.text_message.UpdateText(self._msg_welcome + message) - self.parent.ReenableCancel() - self.parent.ReenableNext() - - def SetInitialException(self, initial_exception): - self.initial_exception = initial_exception - - def OnActivated(self): - thread.start_new_thread(self._WorkerFunction, ()) - - def OnCancel(self): - self.parent.OnExit(1) - - def GetTitle(self): - return "Welcome" - - def IsTerminal(self): - return False - - def IsNextInitiallyDisabled(self): - return True - - def IsCancelInitiallyDisabled(self): - return False - - def GetNext(self): - return self.next - -class ConnectPanel(wx.Panel, DecoratedContainerThreadMixin): - _msg_ensure_connected = ( - "Please ensure your remote is correctly connected to your computer." - ) - - _msg_status_ok = ( - "Successfully connected to a remote:\n%s" - ) - - _msg_status_failure = ( - "A problem occurred. Click next for details." - ) - - _msg_failure_explanation = ( - "No remote could be found." - ) - - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - - self.text_help = WrappedStaticText(self) - self.sizer.Add(self.text_help, 0, wx.ALIGN_LEFT | wx.ALL, 5) - - self.dc = DecoratedContainer(self, resources) - DecoratedContainerThreadMixin.__init__(self, self.dc) - self.dg_connect = DecoratedGauge(self.dc, "Detect Remote", 0) - self.sizer.Add(self.dc, 0, wx.ALIGN_LEFT | wx.ALL, 5) - - self.text_info = WrappedStaticText(self) - self.sizer.Add(self.text_info, 0, wx.ALIGN_LEFT | wx.ALL, 5) - - self.SetSizerAndFit(self.sizer) - - self.next = None - self.finished = False - self.cancelled = False - - self.lock = thread.allocate_lock() - - def _WorkerFunction(self): - try: - wx.CallAfter( - self.text_help.UpdateText, - self._msg_ensure_connected - ) - - self._DgStart(self.dg_connect) - worker_body_connect( - self.resources, - self._DgUpdate, - self.dg_connect, - lambda: self.cancelled, - False - ) - self._DgEnd(self.dg_connect) - - mfg = libconcord.get_mfg() - model = libconcord.get_model() - - mfg_model = mfg + " " + model - wx.CallAfter(self._OnStatusOk, mfg_model) - except: - wx.CallAfter( - self._OnStatusFailure, - self._msg_failure_explanation, - exception_message() - ) - - self.lock.acquire() - self.finished = True - if self.cancelled: - wx.CallAfter(self.OnCancel) - self.lock.release() - - def _OnStatusOk(self, mfg_model): - self.btn_details = wx.Button(self, -1, "&Details...") - self.sizer.Add(self.btn_details, 0, wx.ALIGN_LEFT | wx.ALL, 5) - self.Bind(wx.EVT_BUTTON, self._OnDetails, self.btn_details) - self._OnStatusCommon(self._msg_status_ok % mfg_model) - - def _OnStatusFailure(self, failure_msg, details): - self.dc._DgFailure() - self.resources.page_failure.SetMessages( - failure_msg, - details - ) - self.SetNext(self.resources.page_failure) - self._OnStatusCommon(self._msg_status_failure) - - def _OnStatusCommon(self, message): - self.text_info.UpdateText(message) - self.parent.ReenableNext() - - def _OnDetails(self, event): - try: - msg = "" - - mfg = libconcord.get_mfg() - model = libconcord.get_model() - codename = libconcord.get_codename() - msg += "Model: %s %s (%s)\n" % (msg, model, codename) - - hid_mfg = libconcord.get_hid_mfg_str() - hid_prod = libconcord.get_hid_prod_str() - msg += "USB HID Model: %s %s\n" % (hid_mfg, hid_prod) - - ser_1 = libconcord.get_serial(libconcord.SERIAL_COMPONENT_1) - ser_2 = libconcord.get_serial(libconcord.SERIAL_COMPONENT_2) - ser_3 = libconcord.get_serial(libconcord.SERIAL_COMPONENT_3) - msg += "Serial:\n %s\n %s\n %s\n" % (ser_1, ser_2, ser_3) - - arch = libconcord.get_arch() - proto = libconcord.get_proto() - skin = libconcord.get_skin() - msg += "Arch:%d Proto:%d Skin:%d\n" % (arch, proto, skin) - - fw_type = libconcord.get_fw_type() - fw_ver_maj = libconcord.get_fw_ver_maj() - fw_ver_min = libconcord.get_fw_ver_min() - msg += "Firmware type:%d, version %d.%d\n" % ( - fw_type, fw_ver_maj, fw_ver_min - ) - - hw_ver_maj = libconcord.get_hw_ver_maj() - hw_ver_min = libconcord.get_hw_ver_min() - msg += "HW version %d.%d\n" % (hw_ver_maj, hw_ver_min) - - flash_mfg = libconcord.get_flash_mfg() - flash_id = libconcord.get_flash_id() - flash_part_num = libconcord.get_flash_part_num() - flash_size = libconcord.get_flash_size() - msg += "Flash Manufacturer:%d ID:%d Part:%s Size:%dK\n" % ( - flash_mfg, flash_id, flash_part_num, flash_size - ) - - hid_irl = libconcord.get_hid_irl() - hid_orl = libconcord.get_hid_orl() - hid_frl = libconcord.get_hid_frl() - msg += "USB HID Irl:%d Orl:%d Frl:%d\n" % (hid_irl, hid_orl, hid_frl) - - usb_vid = libconcord.get_usb_vid() - usb_pid = libconcord.get_usb_pid() - usb_bcd = libconcord.get_usb_bcd() - msg += "USB VID:%04x PID:%04x BCD:%04x\n" % (usb_vid, usb_pid, usb_bcd) - - config_bytes_used = libconcord.get_config_bytes_used() - config_bytes_total = libconcord.get_config_bytes_total() - config_pct_used = (config_bytes_used * 100) / config_bytes_total - msg += "Config used %d / total %d = %d%%\n" % ( - config_bytes_used, config_bytes_total, config_pct_used - ) - - fw_nondirect = libconcord.is_fw_update_supported(0) == 0 - fw_direct = libconcord.is_fw_update_supported(1) == 0 - if fw_nondirect or fw_direct: - config_safe = libconcord.is_config_safe_after_fw() == 0 - msg += "Firmware updates: Supported (%s), config%ssafe\n" % ( - fw_direct and "Direct" or "Not direct", - config_safe and " " or " NOT " - ) - else: - msg += "Firmware updates: NOT supported\n" - except: - msg = ( - "Error retrieving remote information:\n" + - exception_message() - ) - - show_modal_scrolled_msgbox(self.parent, "Remote Information", msg) - - def SetNext(self, next): - self.next = next - - def OnActivated(self): - thread.start_new_thread(self._WorkerFunction, ()) - - def OnCancel(self): - self.lock.acquire() - if self.finished: - self.lock.release() - self.parent.OnExit(1) - else: - self.cancelled = True - self.lock.release() - - def GetTitle(self): - return "Connecting" - - def IsTerminal(self): - return False - - def IsNextInitiallyDisabled(self): - return True - - def IsCancelInitiallyDisabled(self): - return False - - def GetNext(self): - return self.next - -class ProgramRemotePanelBase(wx.Panel, DecoratedContainerThreadMixin): - def __init__(self, parent, resources, file_type): - self.parent = parent - self.resources = resources - self.file_type = file_type - - wx.Panel.__init__(self, parent) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - - self.dc = DecoratedContainer(self, resources) - DecoratedContainerThreadMixin.__init__(self, self.dc) - self._AddWidgets() - self.sizer.Add(self.dc, 0, wx.ALIGN_LEFT | wx.ALL, 5) - - self.SetSizerAndFit(self.sizer) - - self.next = None - self.finished = False - - def _WorkerFunction(self): - try: - try: - self._WorkerFunctionBody() - wx.CallAfter(self._OnStatusOk) - return - except: - wx.CallAfter( - self._OnStatusFailure, - "Operation Failed", - exception_message() - ) - finally: - try: - if self.resources.connected: - self.resources.SetConnected(False) - libconcord.deinit_concord() - except: - pass - - def _OnStatusOk(self): - self.next = self.resources.page_success - self._OnStatusCommon() - - def _OnStatusFailure(self, failure_msg, details): - self.dc._DgFailure() - self.next = self.resources.page_failure - self.resources.page_failure.SetMessages( - failure_msg, - details - ) - self._OnStatusCommon() - - def _OnStatusCommon(self): - self.finished = True - self.parent.ReenableCancel() - self.parent.ReenableNext() - - def OnActivated(self): - thread.start_new_thread(self._WorkerFunction, ()) - - def OnCancel(self): - if self.finished: - self.parent.OnExit(1) - show_modal_scrolled_msgbox( - self.parent, - "Cannot Cancel", - "Cancel is disabled during programming operations, " + - "to prevent placing the remote into a state that will " + - "potentially be difficult to recover from." - ) - - def IsTerminal(self): - return False - - def IsNextInitiallyDisabled(self): - return True - - def IsCancelInitiallyDisabled(self): - return True - - def GetNext(self): - return self.next - -class CheckConnectivityPanel(ProgramRemotePanelBase): - def __init__(self, parent, resources): - ProgramRemotePanelBase.__init__( - self, - parent, - resources, - libconcord.LC_FILE_TYPE_CONNECTIVITY - ) - - def _AddWidgets(self): - vpos = counter() - self.dg_notify_website = DecoratedGauge(self.dc, "Notify Website", vpos.next()) - - def _WorkerFunctionBody(self): - self._DgUpdate( - False, - 0, - self.dg_notify_website - ) - libconcord.post_connect_test_success( - self.resources.xml, - self.resources.xml_size - ) - self._DgUpdate( - True, - 100, - self.dg_notify_website - ) - - def GetTitle(self): - return "Checking Connectivity" - -class WriteConfigurationPanel(ProgramRemotePanelBase): - def __init__(self, parent, resources): - ProgramRemotePanelBase.__init__( - self, - parent, - resources, - libconcord.LC_FILE_TYPE_CONFIGURATION - ) - - def _AddWidgets(self): - vpos = counter() - self.dg_check_website = DecoratedGauge(self.dc, "Check Website", vpos.next()) - self.dg_prepare = DecoratedGauge(self.dc, "Prepare Remote", vpos.next()) - self.dg_erase = DecoratedGauge(self.dc, "Erase Flash", vpos.next()) - self.dg_write = DecoratedGauge(self.dc, "Write Configuration", vpos.next()) - self.dg_verify = DecoratedGauge(self.dc, "Verify Upgrade", vpos.next()) - self.dg_reconnect = DecoratedGauge(self.dc, "Reconnect to Remote", vpos.next()) - self.dg_set_time = DecoratedGauge(self.dc, "Set Time", vpos.next()) - self.dg_notify_website = DecoratedGauge(self.dc, "Notify Website", vpos.next()) - - def _WorkerFunctionBody(self): - program_callback = libconcord.callback_type(program_callback_imp) - - self._DgStart(self.dg_check_website) - libconcord.post_preconfig(self.resources.xml, self.resources.xml_size) - self._DgEnd(self.dg_check_website) - - self._DgStart(self.dg_prepare) - bin_data = POINTER(c_ubyte)() - bin_size = c_uint() - libconcord.find_config_binary( - self.resources.xml, - self.resources.xml_size, - byref(bin_data), - byref(bin_size) - ) - self._DgUpdate(False, 50, self.dg_prepare) - libconcord.invalidate_flash() - self._DgEnd(self.dg_prepare) - - self._DgStart(self.dg_erase) - libconcord.erase_config( - bin_size, - program_callback, - py_object((self._DgUpdate, self.dg_erase)) - ) - self._DgEnd(self.dg_erase) - - self._DgStart(self.dg_write) - libconcord.write_config_to_remote( - bin_data, - bin_size, - program_callback, - py_object((self._DgUpdate, self.dg_write)) - ) - self._DgEnd(self.dg_write) - - self._DgStart(self.dg_verify) - libconcord.verify_remote_config( - bin_data, - bin_size, - program_callback, - py_object((self._DgUpdate, self.dg_verify)) - ) - self._DgEnd(self.dg_verify) - - self._DgStart(self.dg_reconnect) - libconcord.reset_remote() - worker_body_connect( - self.resources, - self._DgUpdate, - self.dg_reconnect, - lambda: False, - True - ) - - self._DgStart(self.dg_set_time) - libconcord.set_time() - self._DgEnd(self.dg_set_time) - - self._DgStart(self.dg_notify_website) - libconcord.post_postconfig(self.resources.xml, self.resources.xml_size) - self._DgEnd(self.dg_notify_website) - - def GetTitle(self): - return "Updating Configuration" - -class UpdateFirmwarePanel(ProgramRemotePanelBase): - def __init__(self, parent, resources): - ProgramRemotePanelBase.__init__( - self, - parent, - resources, - libconcord.LC_FILE_TYPE_FIRMWARE - ) - - def _AddWidgets(self): - vpos = counter() - self.dg_prepare = DecoratedGauge(self.dc, "Prepare Remote", vpos.next()) - self.dg_erase = DecoratedGauge(self.dc, "Erase Flash", vpos.next()) - self.dg_write = DecoratedGauge(self.dc, "Write Firmware", vpos.next()) - self.dg_finalize = DecoratedGauge(self.dc, "Finalize Programming", vpos.next()) - self.dg_reconnect = DecoratedGauge(self.dc, "Reconnect to Remote", vpos.next()) - self.dg_set_time = DecoratedGauge(self.dc, "Set Time", vpos.next()) - self.dg_notify_website = DecoratedGauge(self.dc, "Notify Website", vpos.next()) - - def _WorkerFunctionBody(self): - program_callback = libconcord.callback_type(program_callback_imp) - - self._DgStart(self.dg_prepare) - - # is_fw_update_supported returns error code; 0 OK, otherwise failure - if libconcord.is_fw_update_supported(0) == 0: - is_direct = False - elif libconcord.is_fw_update_supported(1) == 0: - is_direct = True - else: - raise Exception( - "Sorry, congruity doesn't yet support firmware update " + - "on this remote model." - ) - - self._DgUpdate(False, 25, self.dg_prepare) - - bin_data = POINTER(c_ubyte)() - bin_size = c_uint() - libconcord.extract_firmware_binary( - self.resources.xml, - self.resources.xml_size, - byref(bin_data), - byref(bin_size) - ) - - self._DgUpdate(False, 50, self.dg_prepare) - - if not is_direct: - libconcord.prep_firmware() - - self._DgUpdate(False, 75, self.dg_prepare) - - libconcord.invalidate_flash() - - self._DgEnd(self.dg_prepare) - - self._DgStart(self.dg_erase) - libconcord.erase_firmware( - is_direct, - program_callback, - py_object((self._DgUpdate, self.dg_erase)) - ) - self._DgEnd(self.dg_erase) - - self._DgStart(self.dg_write) - libconcord.write_firmware_to_remote( - bin_data, - bin_size, - c_int(is_direct and 1 or 0), - program_callback, - py_object((self._DgUpdate, self.dg_write)) - ) - self._DgEnd(self.dg_write) - - self._DgStart(self.dg_finalize) - if not is_direct: - libconcord.finish_firmware() - self._DgEnd(self.dg_finalize) - - self._DgStart(self.dg_reconnect) - libconcord.reset_remote() - worker_body_connect( - self.resources, - self._DgUpdate, - self.dg_reconnect, - lambda: False, - True - ) - - self._DgStart(self.dg_set_time) - libconcord.set_time() - self._DgEnd(self.dg_set_time) - - self._DgStart(self.dg_notify_website) - libconcord.post_postfirmware(self.resources.xml, self.resources.xml_size) - self._DgEnd(self.dg_notify_website) - - def GetTitle(self): - return "Updating Firmware" - -class SuccessPanel(MessagePanelBase): - def __init__(self, parent, resources): - MessagePanelBase.__init__( - self, - parent, - resources - ) - - def OnActivated(self): - self.text_message.UpdateText("Operation has completed successfully.") - - def OnCancel(self): - self.parent.OnExit(0) - - def GetTitle(self): - return "Success" - - def IsTerminal(self): - return True - - def GetExitCode(self): - return 0 - - def IsNextInitiallyDisabled(self): - return False - - def IsCancelInitiallyDisabled(self): - return True - -class FailurePanel(wx.Panel): - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.text_message = WrappedStaticText(self) - self.sizer.Add(self.text_message, 0, wx.ALIGN_LEFT | wx.ALL, 5) - self.btn_details = wx.Button(self, -1, "&Details...") - self.Bind(wx.EVT_BUTTON, self._OnDetails, self.btn_details) - self.sizer.Add(self.btn_details, 0, wx.ALIGN_LEFT | wx.ALL, 5) - self.SetSizerAndFit(self.sizer) - - self.message = "" - self.log_text = "" - - def _OnDetails(self, event): - show_modal_scrolled_msgbox(self.parent, "Error Log", self.log_text) - self.parent.ReenableNext() - - def SetMessages(self, message, traceback): - self.message = message - if traceback: - self.message += "\n\nSee below for details." - self.log_text = traceback - - def OnActivated(self): - if self.log_text: - self.btn_details.SetFocus() - else: - self.btn_details.Hide() - self.text_message.UpdateText(self.message) - - def OnCancel(self): - self.parent.OnExit(1) - - def GetTitle(self): - return "Failure" - - def IsTerminal(self): - return True - - def GetExitCode(self): - return 1 - - def IsNextInitiallyDisabled(self): - return False - - def IsCancelInitiallyDisabled(self): - return True - -class Wizard(wx.Dialog): - def __init__( - self, - resources, - app_finalizer, - min_page_width = 450, - min_page_height = None - ): - self.app_finalizer = app_finalizer - - self.min_page_width = min_page_width - self.min_page_height = min_page_height - - wx.Dialog.__init__(self, None, -1, 'Congruity version ' + version) - - sizer_main = wx.BoxSizer(wx.VERTICAL) - - sizer_top = wx.BoxSizer(wx.HORIZONTAL) - bitmap = wx.StaticBitmap(self, -1, resources.img_remote) - sizer_top.Add(bitmap, 0, wx.EXPAND | wx.ALL, 5) - - self.sizer_top_right = wx.BoxSizer(wx.VERTICAL) - self.title = wx.StaticText(self, -1, "Title") - font = wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD) - self.title.SetFont(font) - self.sizer_top_right.Add(self.title, 0, wx.EXPAND) - divider_top_right = wx.StaticLine(self, -1, None, None, wx.LI_HORIZONTAL) - self.sizer_top_right.Add(divider_top_right, 0, wx.EXPAND) - spacer = wx.StaticText(self, -1, "") - self.sizer_top_right.Add(spacer, 0, wx.EXPAND) - - sizer_top.Add(self.sizer_top_right, 1, wx.EXPAND | wx.ALL, 5) - sizer_main.Add(sizer_top, 1, wx.EXPAND | wx.ALL, 5) - - divider_main = wx.StaticLine(self, -1, None, None, wx.LI_HORIZONTAL) - sizer_main.Add(divider_main, 0, wx.EXPAND | wx.ALL, 5) - - sizer_buttons = wx.BoxSizer(wx.HORIZONTAL) - panel_btn_dummy = wx.Panel(self) - sizer_buttons.Add(panel_btn_dummy, 1, wx.EXPAND | wx.ALL, 5) - self.btn_next = wx.Button(self, -1, "&Next >") - self.Bind(wx.EVT_BUTTON, self._OnNext, self.btn_next) - sizer_buttons.Add(self.btn_next, 0, wx.EXPAND | wx.ALL, 5) - self.btn_cancel = wx.Button(self, -1, "&Cancel") - self.Bind(wx.EVT_BUTTON, self._OnCancel, self.btn_cancel) - self.Bind(wx.EVT_CLOSE, self._OnCancel) - sizer_buttons.Add(self.btn_cancel, 0, wx.EXPAND | wx.ALL, 5) - sizer_main.Add(sizer_buttons, 0, wx.EXPAND | wx.ALL, 5) - - self.SetSizerAndFit(sizer_main) - - self.cur_page = None - - def SetPages(self, pages): - def tuple_max(a, b): - return (max(a[0], b[0]), max(a[1], b[1])) - - self.pages = pages - - for page in self.pages: - page.Hide() - - size_wiz = self.GetSizeTuple() - for page in self.pages: - page.Show() - self.sizer_top_right.Add(page, 1, wx.EXPAND) - self.Fit() - size_page = self.GetSizeTuple() - size_wiz = tuple_max(size_wiz, size_page) - page.Hide() - self.sizer_top_right.Remove(page) - - if self.min_page_width and (size_wiz[0] < self.min_page_width): - size_wiz = (self.min_page_width, size_wiz[1]) - - if self.min_page_height and (size_wiz[1] < self.min_page_height): - size_wiz = (size_wiz[0], self.min_page_height ) - - self.SetSize(size_wiz) - - def SetInitialPage(self, page): - if self.cur_page: - raise Exception("Current page already set") - self._SetPage(page) - - def OnExit(self, retcode): - if self.app_finalizer: - self.app_finalizer() - os._exit(retcode) - - def _ReenableButton(self, button): - button.Enable(True) - button.Hide() - button.Show() - button.SetFocus() - - def ReenableNext(self): - self._ReenableButton(self.btn_next) - - def ReenableCancel(self): - self._ReenableButton(self.btn_cancel) - - def _OnNext(self, event): - if self.cur_page.IsTerminal(): - self.OnExit(self.cur_page.GetExitCode()) - next_page = self.cur_page.GetNext() - self._SetPage(next_page) - - def _OnCancel(self, event): - self.cur_page.OnCancel() - - def _SetPage(self, page): - if not page in self.pages: - raise Exception("Invalid page") - - if self.cur_page: - self.cur_page.Hide() - self.sizer_top_right.Remove(self.cur_page) - - self.cur_page = page - - self.cur_page.Show() - self.sizer_top_right.Add(self.cur_page, 1, wx.EXPAND) - - self.title.SetLabel(self.cur_page.GetTitle()) - - self.Layout() - - is_terminal = self.cur_page.IsTerminal() - if is_terminal: - self.btn_next.SetLabel("&Finish") - else: - self.btn_next.SetLabel("&Next >") - - self.btn_next.Enable(not self.cur_page.IsNextInitiallyDisabled()) - self.btn_cancel.Enable( - (not is_terminal) - and - (not self.cur_page.IsCancelInitiallyDisabled()) - ) - self.btn_next.SetFocus() - - self.cur_page.OnActivated() - -class Resources(object): - def __init__(self, appdir): - self.appdir = appdir - - self.ezhex_filename = None - self.xml = None - self.xml_size = None - self.connected = False - - def LoadImages(self): - def load(filename, appdir = self.appdir): - dirs = ['/usr/share/congruity', appdir, '.'] - for dir in dirs: - fpath = os.path.join(dir, filename) - if not os.path.isfile(fpath): - continue - return wx.Image(fpath, wx.BITMAP_TYPE_PNG).ConvertToBitmap() - raise Exception("Can't load " + filename) - - self.img_remote = load("remote.png") - self.icon_unstarted = load("icon-unstarted.png") - self.icon_in_progress = load("icon-in-progress.png") - self.icon_complete = load("icon-complete.png") - self.icon_failed = load("icon-failed.png") - - iw = max( - self.icon_in_progress.GetWidth(), - self.icon_complete.GetWidth(), - self.icon_failed.GetWidth() - ) - ih = max( - self.icon_in_progress.GetHeight(), - self.icon_complete.GetHeight(), - self.icon_failed.GetHeight() - ) - self.iwh = (iw, ih) - - def CreatePages(self, wizard): - self.page_welcome = WelcomePanel(wizard, self) - self.page_connect = ConnectPanel(wizard, self) - self.page_check_connectivity = CheckConnectivityPanel(wizard, self) - self.page_write_configuration = WriteConfigurationPanel(wizard, self) - self.page_update_firmware = UpdateFirmwarePanel(wizard, self) - self.page_success = SuccessPanel(wizard, self) - self.page_failure = FailurePanel(wizard, self) - - def SetEzHexFilename(self, ezhex_filename): - self.ezhex_filename = ezhex_filename - - def SetXmlData(self, xml, xml_size): - self.xml = xml - self.xml_size = xml_size - - def SetConnected(self, connected): - self.connected = connected - -class Finalizer(object): - def __init__(self, resources): - self.resources = resources - - def __call__(self): - if self.resources.xml: - ... [truncated message content] |
From: <srw...@us...> - 2009-06-18 03:52:47
|
Revision: 70 http://congruity.svn.sourceforge.net/congruity/?rev=70&view=rev Author: srwarren Date: 2009-06-18 03:52:41 +0000 (Thu, 18 Jun 2009) Log Message: ----------- Bump to version 11 Modified Paths: -------------- trunk/Changelog trunk/congruity Modified: trunk/Changelog =================================================================== --- trunk/Changelog 2009-06-18 03:51:12 UTC (rev 69) +++ trunk/Changelog 2009-06-18 03:52:41 UTC (rev 70) @@ -1,4 +1,5 @@ -* 2009-xx-xx Stephen Warren <s-t...@ww...> +* 2009-06-17 Stephen Warren <s-t...@ww...> +- congruity-11 is released - Fix Pronto hex import Patch by Andreas Schulz <And...@gm...> - Throw runtime error dialog if wxPython version is not at least 2.8 Modified: trunk/congruity =================================================================== --- trunk/congruity 2009-06-18 03:51:12 UTC (rev 69) +++ trunk/congruity 2009-06-18 03:52:41 UTC (rev 70) @@ -30,7 +30,7 @@ import wx import wx.lib.dialogs -version = "10+" +version = "11" try: import libconcord This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2009-06-18 03:52:00
|
Revision: 69 http://congruity.svn.sourceforge.net/congruity/?rev=69&view=rev Author: srwarren Date: 2009-06-18 03:51:12 +0000 (Thu, 18 Jun 2009) Log Message: ----------- Add .desktop file. Patch by Adam Williamson <awi...@re...> Modified Paths: -------------- trunk/Changelog trunk/Makefile Added Paths: ----------- trunk/congruity.desktop Modified: trunk/Changelog =================================================================== --- trunk/Changelog 2009-05-08 03:39:03 UTC (rev 68) +++ trunk/Changelog 2009-06-18 03:51:12 UTC (rev 69) @@ -2,6 +2,8 @@ - Fix Pronto hex import Patch by Andreas Schulz <And...@gm...> - Throw runtime error dialog if wxPython version is not at least 2.8 +- Add .desktop file + Patch by Adam Williamson <awi...@re...> * 2009-03-09 Stephen Warren <s-t...@ww...> - congruity-10 is released Modified: trunk/Makefile =================================================================== --- trunk/Makefile 2009-05-08 03:39:03 UTC (rev 68) +++ trunk/Makefile 2009-06-18 03:51:12 UTC (rev 69) @@ -1,3 +1,5 @@ +RUN_UPDATE_DESKTOP_DB ?= 1 + DESTDIR ?= PREFIX ?= /usr/local @@ -4,10 +6,12 @@ BINDIR ?= $(PREFIX)/bin SHAREDIR ?= $(PREFIX)/share APPSHAREDIR ?= $(SHAREDIR)/congruity +DESKTOPDIR ?= $(SHAREDIR)/applications MANDIR ?= $(SHAREDIR)/man MAN1DIR ?= $(MANDIR)/man1 INSTALL ?= install +UPDATE_DESKTOP_DB ?= update-desktop-database all: @echo "Nothing to build, run 'make install' as root" @@ -21,9 +25,18 @@ $(INSTALL) --mode=644 *.png $(DESTDIR)$(APPSHAREDIR) mkdir -p --mode=755 $(DESTDIR)$(MAN1DIR) $(INSTALL) --mode=644 congruity.1 $(DESTDIR)$(MAN1DIR) + mkdir -p --mode=755 $(DESTDIR)$(DESKTOPDIR) + $(INSTALL) --mode=644 congruity.desktop $(DESTDIR)$(DESKTOPDIR) +ifeq ($(RUN_UPDATE_DESKTOP_DB),1) + $(UPDATE_DESKTOP_DB) > /dev/null 2>&1 || : +endif uninstall: /bin/rm -f $(DESTDIR)$(BINDIR)/congruity /bin/rm -rf $(DESTDIR)$(APPSHAREDIR) /bin/rm -f $(DESTDIR)$(MAN1DIR)/congruity.1 + /bin/rm -f $(DESTDIR)$(DESKTOPDIR)/congruity.desktop +ifeq ($(RUN_UPDATE_DESKTOP_DB),1) + $(UPDATE_DESKTOP_DB) > /dev/null 2>&1 || : +endif Added: trunk/congruity.desktop =================================================================== --- trunk/congruity.desktop (rev 0) +++ trunk/congruity.desktop 2009-06-18 03:51:12 UTC (rev 69) @@ -0,0 +1,7 @@ +[Desktop Entry] +Name=Congruity +Exec=congruity %f +NoDisplay=true +Type=Application +MimeType=application/x-libconcord; + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2009-05-08 03:39:07
|
Revision: 68 http://congruity.svn.sourceforge.net/congruity/?rev=68&view=rev Author: srwarren Date: 2009-05-08 03:39:03 +0000 (Fri, 08 May 2009) Log Message: ----------- Throw runtime error dialog if wxPython version is not at least 2.8 Modified Paths: -------------- trunk/Changelog trunk/congruity Modified: trunk/Changelog =================================================================== --- trunk/Changelog 2009-05-08 03:21:41 UTC (rev 67) +++ trunk/Changelog 2009-05-08 03:39:03 UTC (rev 68) @@ -1,6 +1,7 @@ * 2009-xx-xx Stephen Warren <s-t...@ww...> - Fix Pronto hex import Patch by Andreas Schulz <And...@gm...> +- Throw runtime error dialog if wxPython version is not at least 2.8 * 2009-03-09 Stephen Warren <s-t...@ww...> - congruity-10 is released Modified: trunk/congruity =================================================================== --- trunk/congruity 2009-05-08 03:21:41 UTC (rev 67) +++ trunk/congruity 2009-05-08 03:39:03 UTC (rev 68) @@ -24,6 +24,9 @@ import thread import time import traceback + +import wxversion +wxversion.ensureMinimal('2.8') import wx import wx.lib.dialogs This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2009-05-08 03:21:49
|
Revision: 67 http://congruity.svn.sourceforge.net/congruity/?rev=67&view=rev Author: srwarren Date: 2009-05-08 03:21:41 +0000 (Fri, 08 May 2009) Log Message: ----------- Fix Pronto hex file import Modified Paths: -------------- trunk/Changelog trunk/congruity Modified: trunk/Changelog =================================================================== --- trunk/Changelog 2009-03-10 02:46:00 UTC (rev 66) +++ trunk/Changelog 2009-05-08 03:21:41 UTC (rev 67) @@ -1,4 +1,6 @@ * 2009-xx-xx Stephen Warren <s-t...@ww...> +- Fix Pronto hex import + Patch by Andreas Schulz <And...@gm...> * 2009-03-09 Stephen Warren <s-t...@ww...> - congruity-10 is released Modified: trunk/congruity =================================================================== --- trunk/congruity 2009-03-10 02:46:00 UTC (rev 66) +++ trunk/congruity 2009-05-08 03:21:41 UTC (rev 67) @@ -1364,7 +1364,12 @@ if bin[0] != 0: raise Exception('Not RAW') - frequency = int(1000000 / (bin[1] * 0.241246)) + pronto_clock = 4145146 + # IR carrier frequency is given as number of Pronto clock cycles + frequency = int(pronto_clock / bin[1]) + # Mark/space durations are given as a count of IR carrier cycles, + # but we need them in microseconds + carrier_cycle_us = 1000000.0 / frequency count_1 = 2 * bin[2] count_2 = 2 * bin[3] @@ -1387,12 +1392,12 @@ idx = 0 for i in range(count_1): - self.resources.cur_ir_signal[idx] = bin[start_1 + i] + self.resources.cur_ir_signal[idx] = int(bin[start_1 + i] * carrier_cycle_us) idx += 1 for j in range(repeats): for i in range(count_2): - self.resources.cur_ir_signal[idx] = bin[start_2 + i] + self.resources.cur_ir_signal[idx] = int(bin[start_2 + i] * carrier_cycle_us) idx += 1 self._OnStatusOk() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2009-03-10 02:46:10
|
Revision: 66 http://congruity.svn.sourceforge.net/congruity/?rev=66&view=rev Author: srwarren Date: 2009-03-10 02:46:00 +0000 (Tue, 10 Mar 2009) Log Message: ----------- Fix release date in trunk Modified Paths: -------------- trunk/Changelog Modified: trunk/Changelog =================================================================== --- trunk/Changelog 2009-03-10 02:20:17 UTC (rev 65) +++ trunk/Changelog 2009-03-10 02:46:00 UTC (rev 66) @@ -1,4 +1,6 @@ * 2009-xx-xx Stephen Warren <s-t...@ww...> + +* 2009-03-09 Stephen Warren <s-t...@ww...> - congruity-10 is released - Implement IR learning feature, with support for learning from the original remote using the Harmony, or reading the signal from a "Pronto Hex" file. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2009-03-10 02:20:36
|
Revision: 65 http://congruity.svn.sourceforge.net/congruity/?rev=65&view=rev Author: srwarren Date: 2009-03-10 02:20:17 +0000 (Tue, 10 Mar 2009) Log Message: ----------- Bump SVN version post release Modified Paths: -------------- trunk/congruity Modified: trunk/congruity =================================================================== --- trunk/congruity 2009-03-10 02:17:18 UTC (rev 64) +++ trunk/congruity 2009-03-10 02:20:17 UTC (rev 65) @@ -27,7 +27,7 @@ import wx import wx.lib.dialogs -version = "10" +version = "10+" try: import libconcord This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2009-03-10 02:17:45
|
Revision: 63 http://congruity.svn.sourceforge.net/congruity/?rev=63&view=rev Author: srwarren Date: 2009-03-10 02:16:20 +0000 (Tue, 10 Mar 2009) Log Message: ----------- Tag release 10, really this time\! Added Paths: ----------- tags/congruity-10/ tags/congruity-10/Changelog tags/congruity-10/Makefile tags/congruity-10/README.txt tags/congruity-10/congruity tags/congruity-10/icon-sources.txt Removed Paths: ------------- tags/congruity-10/Changelog tags/congruity-10/Makefile tags/congruity-10/README.txt tags/congruity-10/congruity Property changes on: tags/congruity-10 ___________________________________________________________________ Added: svn:mergeinfo + Deleted: tags/congruity-10/Changelog =================================================================== --- trunk/Changelog 2008-10-13 00:13:29 UTC (rev 47) +++ tags/congruity-10/Changelog 2009-03-10 02:16:20 UTC (rev 63) @@ -1,101 +0,0 @@ -* 2008-09-07 Stephen Warren <s-t...@ww...> -- congruity-9 is released -- Use a different remote.png, with a known free license. - -* 2008-07-03 Stephen Warren <s-t...@ww...> -- congruity-8 is released -- Centralize cancel/exit handling, - and clean up any libconcord resources when exiting the application. -- Add thread-safe cancelling to ConnectPanel. -- Work around a typo in libconcord 0.20's Python bindings. -- Provide a GUI message if libconcord can't be loaded, in case congruity - wasn't run from a terminal. - -* 2008-07-02 Stephen Warren <s-t...@ww...> -- Increase connect timeout after a reset operation, just to make sure - we don't miss the remote coming back. -- Fix Makefile to create all directories files are written to, and add - a few more variables that can be tweaked e.g. by packaging scripts. -* On behalf of Andreas Schulz <And...@gm...> -- Use a simpler and potentially more reliable fix for GTK buttons not - accepting clicks if the mouse was inside the widget when enabled. - -* 2008-07-01 Stephen Warren <s-t...@ww...> -- Command-line parsing errors are displayed by the GUI, instead of being - echo'd to stdout. This makes errors visible when congruity is launched - without a terminal - -* 2008-06-25..2008-07-01 Stephen Warren <s-t...@ww...> -* Inspired by Andreas Schulz <And...@gm...> -- Significant internal structural changes to the implementation, which - simplify things a lot, and make program flow far more obvious, localized, - and correctly polymorphic. -- Add a separate "connect" page, so that the other pages don't have to - re-implement this common function. - -* 2008-06-17 Stephen Warren <s-t...@ww...> -* On behalf of Andreas Schulz <And...@gm...> -- Fix issue where next button wouldn't respond to clicks if the pointer was - already within the button when it was re-enabled. - -* 2008-04-14 Stephen Warren <s-t...@ww...> -- congruity-7 is released -- Switched license to GPLv3+ to be compatible with libconcord by default. - Contact me if you want the code under a different license, but please - note that you won't be able to use relicensed code with libconcord. -- Added a Makefile for easy installation. - Thanks to Phil Dibowitz for the contribution. -- Added a manual page. -- Added a few useful URLs to README.txt. -- Fixed reliance on syntax specific to Python 2.5. - -* 2008-04-13 Stephen Warren <s-t...@ww...> -- congruity-6 is released -- Search for images in /usr/share/congruity, the source directory, then - CWD. This should allow easy system-wide installation of congruity. -- libconcord.py is no longer distributed with congruity; it is now part - of libconcord itself (see libconcord/bindings/python/). -- Apparently forgot to release LICENSE.txt before. - -* 2008-04-07 Stephen Warren <s-t...@ww...> -- congruity-5 is released -- This release solely operates using libconcord; "screen-scraping" the output - from the concordance application is no longer supported. -- Implement firmware upgrade. -- Minor tweaks for operation on MS-Windows. -- congruity now sets the time on the remote after any reboot. - -* 2008-03-29 Stephen Warren <s-t...@ww...> -- congruity-4 is released -- Renamed package from harmonygui to congruity, in line with the - coming rename of the harmonycontrol project to concordance/libconcord. -- Changes to match latest CVS libconcord API changes - -* 2008-02-24 Stephen Warren <s-t...@ww...> -- harmonygui-3 is released -- Added README.txt. -- Added LICENSING.txt, to account for images too. -- Remove GUI for initial web connection in update mode; the libharmony - branch code doesn't print this status information, so now we act like - it was never there. -- Code re-org, to allow for multiple back-ends. -- Added a back-end that calls libharmony.so directly using ctypes. - -* 2008-02-10 Stephen Warren <s-t...@ww...> -- harmonygui-2 is released -- Updated ezhexparser to recognize firmware update files. -- Updated GUI to handle firmware updates, by informing user its - not yet supported. -- Separated ezhexparser and tuiparser operation mode enumerations. -- Enhanced ptyrun error handling, so it's more obvious what happened - when the harmony application can't be found in the $PATH. -- Updated harmonyfake to use ^H characters to re-write output, not - \r. This matches the real harmony app. -- Minor typo cleanups in messages. -- Added licensing information. -- Added this Changelog - -* 2008-02-05 Stephen Warren <s-t...@ww...> -- harmonygui-1 is released -- Initial release. - Copied: tags/congruity-10/Changelog (from rev 61, trunk/Changelog) =================================================================== --- tags/congruity-10/Changelog (rev 0) +++ tags/congruity-10/Changelog 2009-03-10 02:16:20 UTC (rev 63) @@ -0,0 +1,117 @@ +* 2009-xx-xx Stephen Warren <s-t...@ww...> +- congruity-10 is released +- Implement IR learning feature, with support for learning from the original + remote using the Harmony, or reading the signal from a "Pronto Hex" file. + (Merge of /branches/irlean) + Parts based on code by Andreas Schulz <And...@gm...> +- Various internal code changes to support IR learning and general cleanup. +- Implement --no-web command-line option, which prevents posting any data + to the Harmony website. This can be useful when testing congruity. +- Change default install prefix to /usr/local; this makes typical end-user + manual installs slightly simpler. Also, automatically patch install location + into the app during installation. +- If libconcord import fails, display the entire backtrace information, to + enable easier debugging of the issue. +- Enhance README + +* 2008-09-07 Stephen Warren <s-t...@ww...> +- congruity-9 is released +- Use a different remote.png, with a known free license. + +* 2008-07-03 Stephen Warren <s-t...@ww...> +- congruity-8 is released +- Centralize cancel/exit handling, + and clean up any libconcord resources when exiting the application. +- Add thread-safe cancelling to ConnectPanel. +- Work around a typo in libconcord 0.20's Python bindings. +- Provide a GUI message if libconcord can't be loaded, in case congruity + wasn't run from a terminal. + +* 2008-07-02 Stephen Warren <s-t...@ww...> +- Increase connect timeout after a reset operation, just to make sure + we don't miss the remote coming back. +- Fix Makefile to create all directories files are written to, and add + a few more variables that can be tweaked e.g. by packaging scripts. +* On behalf of Andreas Schulz <And...@gm...> +- Use a simpler and potentially more reliable fix for GTK buttons not + accepting clicks if the mouse was inside the widget when enabled. + +* 2008-07-01 Stephen Warren <s-t...@ww...> +- Command-line parsing errors are displayed by the GUI, instead of being + echo'd to stdout. This makes errors visible when congruity is launched + without a terminal + +* 2008-06-25..2008-07-01 Stephen Warren <s-t...@ww...> +* Inspired by Andreas Schulz <And...@gm...> +- Significant internal structural changes to the implementation, which + simplify things a lot, and make program flow far more obvious, localized, + and correctly polymorphic. +- Add a separate "connect" page, so that the other pages don't have to + re-implement this common function. + +* 2008-06-17 Stephen Warren <s-t...@ww...> +* On behalf of Andreas Schulz <And...@gm...> +- Fix issue where next button wouldn't respond to clicks if the pointer was + already within the button when it was re-enabled. + +* 2008-04-14 Stephen Warren <s-t...@ww...> +- congruity-7 is released +- Switched license to GPLv3+ to be compatible with libconcord by default. + Contact me if you want the code under a different license, but please + note that you won't be able to use relicensed code with libconcord. +- Added a Makefile for easy installation. + Thanks to Phil Dibowitz for the contribution. +- Added a manual page. +- Added a few useful URLs to README.txt. +- Fixed reliance on syntax specific to Python 2.5. + +* 2008-04-13 Stephen Warren <s-t...@ww...> +- congruity-6 is released +- Search for images in /usr/share/congruity, the source directory, then + CWD. This should allow easy system-wide installation of congruity. +- libconcord.py is no longer distributed with congruity; it is now part + of libconcord itself (see libconcord/bindings/python/). +- Apparently forgot to release LICENSE.txt before. + +* 2008-04-07 Stephen Warren <s-t...@ww...> +- congruity-5 is released +- This release solely operates using libconcord; "screen-scraping" the output + from the concordance application is no longer supported. +- Implement firmware upgrade. +- Minor tweaks for operation on MS-Windows. +- congruity now sets the time on the remote after any reboot. + +* 2008-03-29 Stephen Warren <s-t...@ww...> +- congruity-4 is released +- Renamed package from harmonygui to congruity, in line with the + coming rename of the harmonycontrol project to concordance/libconcord. +- Changes to match latest CVS libconcord API changes + +* 2008-02-24 Stephen Warren <s-t...@ww...> +- harmonygui-3 is released +- Added README.txt. +- Added LICENSING.txt, to account for images too. +- Remove GUI for initial web connection in update mode; the libharmony + branch code doesn't print this status information, so now we act like + it was never there. +- Code re-org, to allow for multiple back-ends. +- Added a back-end that calls libharmony.so directly using ctypes. + +* 2008-02-10 Stephen Warren <s-t...@ww...> +- harmonygui-2 is released +- Updated ezhexparser to recognize firmware update files. +- Updated GUI to handle firmware updates, by informing user its + not yet supported. +- Separated ezhexparser and tuiparser operation mode enumerations. +- Enhanced ptyrun error handling, so it's more obvious what happened + when the harmony application can't be found in the $PATH. +- Updated harmonyfake to use ^H characters to re-write output, not + \r. This matches the real harmony app. +- Minor typo cleanups in messages. +- Added licensing information. +- Added this Changelog + +* 2008-02-05 Stephen Warren <s-t...@ww...> +- harmonygui-1 is released +- Initial release. + Deleted: tags/congruity-10/Makefile =================================================================== --- trunk/Makefile 2008-10-13 00:13:29 UTC (rev 47) +++ tags/congruity-10/Makefile 2009-03-10 02:16:20 UTC (rev 63) @@ -1,27 +0,0 @@ -DESTDIR ?= -PREFIX ?= /usr - -BINDIR ?= $(PREFIX)/bin -SHAREDIR ?= $(PREFIX)/share -APPSHAREDIR ?= $(SHAREDIR)/congruity -MANDIR ?= $(SHAREDIR)/man -MAN1DIR ?= $(MANDIR)/man1 - -INSTALL ?= /usr/bin/install - -all: - @echo "Nothing to build, run 'make install' as root" - -install: - mkdir -p --mode=755 $(DESTDIR)$(BINDIR) - $(INSTALL) --mode=755 congruity $(DESTDIR)$(BINDIR)/congruity - mkdir -p --mode=755 $(DESTDIR)$(APPSHAREDIR) - $(INSTALL) --mode=644 *.png $(DESTDIR)$(APPSHAREDIR) - mkdir -p --mode=755 $(DESTDIR)$(MAN1DIR) - $(INSTALL) --mode=644 congruity.1 $(DESTDIR)$(MAN1DIR) - -uninstall: - /bin/rm -f $(DESTDIR)$(BINDIR)/congruity - /bin/rm -rf $(DESTDIR)$(APPSHAREDIR) - /bin/rm -f $(DESTDIR)$(MAN1DIR)/congruity.1 - Copied: tags/congruity-10/Makefile (from rev 58, trunk/Makefile) =================================================================== --- tags/congruity-10/Makefile (rev 0) +++ tags/congruity-10/Makefile 2009-03-10 02:16:20 UTC (rev 63) @@ -0,0 +1,29 @@ +DESTDIR ?= +PREFIX ?= /usr/local + +BINDIR ?= $(PREFIX)/bin +SHAREDIR ?= $(PREFIX)/share +APPSHAREDIR ?= $(SHAREDIR)/congruity +MANDIR ?= $(SHAREDIR)/man +MAN1DIR ?= $(MANDIR)/man1 + +INSTALL ?= install + +all: + @echo "Nothing to build, run 'make install' as root" + +install: + mkdir -p --mode=755 $(DESTDIR)$(BINDIR) + sed -e "s:/usr/share/congruity:${APPSHAREDIR}:" < congruity > congruity.patched + $(INSTALL) --mode=755 congruity.patched $(DESTDIR)$(BINDIR)/congruity + rm -f congruity.patched + mkdir -p --mode=755 $(DESTDIR)$(APPSHAREDIR) + $(INSTALL) --mode=644 *.png $(DESTDIR)$(APPSHAREDIR) + mkdir -p --mode=755 $(DESTDIR)$(MAN1DIR) + $(INSTALL) --mode=644 congruity.1 $(DESTDIR)$(MAN1DIR) + +uninstall: + /bin/rm -f $(DESTDIR)$(BINDIR)/congruity + /bin/rm -rf $(DESTDIR)$(APPSHAREDIR) + /bin/rm -f $(DESTDIR)$(MAN1DIR)/congruity.1 + Deleted: tags/congruity-10/README.txt =================================================================== --- trunk/README.txt 2008-10-13 00:13:29 UTC (rev 47) +++ tags/congruity-10/README.txt 2009-03-10 02:16:20 UTC (rev 63) @@ -1,46 +0,0 @@ -Requirements: - -Python (tested with 2.5.1 on Fedora 8) - See http://www.python.org/ -Python ctypes library (included with Python 2.5, separate earlier) - See http://sourceforge.net/projects/ctypes/ -wxPython (tested with wxGTK-2.8.4 on Fedora 8) - See http://www.wxpython.org/ -libconcord (tested with pre-0.20 CVS snapshot on Fedora 8) - See http: http://www.phildev.net/concordance/ - -Installation/Usage: - -You may need to set up udev/similar rules so that the USB device nodes -used by the application are accessible without using root. I use -the following file: - ------ /etc/udev/rules.d/custom-concordance.rules: -SYSFS{idVendor}=="046d", SYSFS{idProduct}=="c110", MODE="666" ------ - -Note that your vendor and product ID may be different. Use lsusb to verify: - ------ -[swarren@esk ~]$ lsusb -... -Bus 005 Device 011: ID 046d:c110 Logitech, Inc. -... ------ - -Remember to differentiate between the Harmony remote and any other Logitech -peripherals you may have! - -Congruity relies on the libconcord library, which must be obtained and -installed separately. Note that you will need to install the Python bindings -for libconcord too; see libconcord/bindings/python/. - -Configure your web browser to open files of type *.EZHex and *.EZUp with the -congruity application. This is typically performed using the dialog box -that appears when a file is about to be downloaded. - -Note that in Firefox, you'll need to change a setting to see the download -action prompt; Otherwise, files will simply be saved to disk without you -being asked. Edit menu -> Preferences menu item -> Main tab -> Select -"Always ask me where to save files." - Copied: tags/congruity-10/README.txt (from rev 59, trunk/README.txt) =================================================================== --- tags/congruity-10/README.txt (rev 0) +++ tags/congruity-10/README.txt 2009-03-10 02:16:20 UTC (rev 63) @@ -0,0 +1,147 @@ +Requirements +============================================================================== + +Python (tested with 2.5.1 on Fedora 9) + See http://www.python.org/ + +Python ctypes library (included with Python 2.5, separate earlier) + See http://sourceforge.net/projects/ctypes/ + +wxPython (tested with wxGTK-2.8.7 on Fedora 9) + See http://www.wxpython.org/ + +libconcord (tested with post-0.20 CVS snapshot on Fedora 9) + See http://www.phildev.net/concordance/ + Note that the python bindings are also required; see + libconcord/bindings/python + +Python, ctypes, and wxPython are typically installed using your distribution's +package management system. If this is not the case, installation instructions +should be located in the documentation accompanying those packages. + +libconcord may be available via your distribution's package management +system. If so, please ensure that you install any sub-packages required to +provide the libconcord Python bindings, e.g. both libconcord and +libconcord-python. + +If installing libconcord from source, please follow the instructions +accompanying the source. Note that the Python bindings must be installed +separately; the bindings are found within the following sub-directory of the +libconcord source package: + + libconcord/bindings/python + +Some versions of libconcord provide a README.txt detailing the installation +process. Otherwise, the basic instructions are to run the following command as +root: + + python setup.py install + +Installation +============================================================================== + +congruity may be installed by running the following command: + + make install + +This command typically requires root access, since the default installation +location is /usr/local. + +Please read Makefile for details of variables that may be set to configure the +installation process, e.g.: + + make install DESTDIR=/tmp/pkgtmp PREFIX=/usr + +Device Node Access Setup +============================================================================== + +You may need to set up udev/similar rules so that the USB device nodes used +by the application are accessible without running congruity as root. Note that +distribution packages of libconcord typically provide these rules, so they may +already be set up for you. + +If you need to manually set up udev rules, the following file should work: + +----- /etc/udev/rules.d/custom-concordance.rules: +SYSFS{idVendor}=="046d", SYSFS{idProduct}=="c110", MODE="666" +----- + +Note that your vendor and product ID may be different. Use lsusb to verify: + +----- +[swarren@esk ~]$ lsusb +... +Bus 005 Device 011: ID 046d:c110 Logitech, Inc. +... +----- + +Remember to differentiate between the Harmony remote and any other Logitech +peripherals you may have! Note that not all Harmony-compatible remotes are +Logitech-branded in the USB listing. + +Usage Model +============================================================================== + +congruity aims to fit into the usage model implemented by the official +Logitech software. The primary differentiation is that congruity is both +open-source and more cross-platform than the official software. + +Harmony remotes are configured using the Logitech website, based at the +following URL: + + http://members.harmonyremote.com/ + +Note that other URLs may be used for remotes that are not branded as +"Harmony". However, the overall process is identical. + +The website provides a database of devices, and a set of wizards to select +which of those are present in your setup. All decisions regarding how the +remote will be configured are made through this website. + +Please note that more recent versions of the Logitech software appear to be +an application that executes locally on the user's computer. However, they are +in fact a simple wrapping of a web-browser, simply hiding the web-based nature +of the configuration process. + +Once the configuration is complete, the website will push various file +downloads to the web browser. These files contain the information required to +program the user's configuration into the remote. For each file downloaded, +the congruity application should be executed to process the instructions in +that file. + +Web Browser Setup +============================================================================== + +Configure your web browser to open files of type *.EZHex, *.EZUp, and *.EZTut +with the congruity application. + +This is typically set up using the dialog box that appears when a file is +about to be downloaded. congruity should be executed once for each file +downloaded, and should be passed the name of the saved download as a command- +line parameter, for example: + + congruity /tmp/Connectivity.EZHex + +If you're confused, the above behavior is most likely what your web browser +will do automatically when configured to open files using congruity. + +Firefox Specific Notes +============================================================================== + +You'll need to change a setting to see the download action prompt; Otherwise, +files will simply be saved to disk without you being asked. On Linux, this may +be achieved from the Edit menu -> Preferences menu item -> Main tab -> Select +"Always ask me where to save files". The exact menu location may vary slightly +on other operating systems. + +When a file download commences, a dialog will appear with the option to "Open +With", or "Save" the file. Select "Open With", and browse for the congruity +executable as the application. You may also want to select "Do this +automatically for files like this from now on". You will need to select the +path to the congruity application once for each file type (*.EZHex, *.EZUp, +*.EZTut). + +If the automatic option is not selected, the dialog will appear for every file +downloaded. Note that Firefox does remember the path to congruity for future +downloads, even though it is not displayed. + Deleted: tags/congruity-10/congruity =================================================================== --- trunk/congruity 2008-10-13 00:13:29 UTC (rev 47) +++ tags/congruity-10/congruity 2009-03-10 02:16:20 UTC (rev 63) @@ -1,1255 +0,0 @@ -#!/usr/bin/python - -# Copyright 2008 Stephen Warren -# -# This file is part of congruity. -# -# congruity 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. -# -# congruity 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 congruity. If not, see <http://www.gnu.org/licenses/>. - -from ctypes import * -import os -import os.path -import sys -import thread -import time -import traceback -import wx -import wx.lib.dialogs - -version = "9+" - -try: - import libconcord - # Fix typo in libconcord 0.20 Python bindings - try: - libconcord.delete_blob - except: - libconcord.delete_blob = libconcord.delete_block -except: - app = wx.PySimpleApp() - dlg = wx.MessageDialog( - None, - "Could not load libconcord; please ensure it, and the Python " - "bindings, are installed and in the relevant search paths.", - "congruity: Dependency Error", - wx.OK | wx.ICON_ERROR - ) - dlg.ShowModal() - os._exit(1) - -def counter(): - i=0 - while True: - yield i - i += 1 - -def program_callback_imp(count, current, total, context): - if not context: - return - - try: - (f, fcontext) = context - percent = (current * 100) / total - f(False, percent, fcontext) - except: - print - traceback.print_exc() - -class CmdLineException(Exception): - pass - -def exception_message(): - msg = '' - if type(sys.exc_value) == libconcord.LibConcordException: - try: - msg += '%s\n (libconcord function %s error %d)\n\n' % ( - sys.exc_value.result_str, - sys.exc_value.func, - sys.exc_value.result - ) - except: - pass - if type(sys.exc_value) == CmdLineException: - try: - msg += '%s\n\n' % ( - str(sys.exc_value) - ) - except: - pass - msg += traceback.format_exc() - return msg - -def worker_body_connect( - resources, - on_progress, - cb_context, - cancel_check, - after_reset -): - program_callback = libconcord.callback_type(program_callback_imp) - - max_attempts = after_reset and 180 or 60 - for attempt in range(max_attempts): - on_progress( - False, - (attempt * 100) / max_attempts, - cb_context - ) - try: - libconcord.init_concord() - resources.SetConnected(True) - try: - libconcord.get_identity( - program_callback, - None - ) - except: - ignore = False - if type(sys.exc_value) == libconcord.LibConcordException: - # FIXME: Expose these constants in libconcord.py - ignore = sys.exc_value.result == 16 #LC_ERROR_INVALID_CONFIG - if not ignore: - raise - break - except: - if cancel_check() or (attempt == max_attempts - 1): - raise - time.sleep(1) - on_progress( - True, - 100, - cb_context - ) - -def show_modal_scrolled_msgbox(parent, title, text): - size = parent.GetClientSizeTuple() - size = (size[0] * 90 / 100, size[1] * 90 / 100) - wx.lib.dialogs.ScrolledMessageDialog( - parent, - text, - title, - (-1, -1), - size - ).ShowModal() - -ALIGN_LTA = wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.ALL -ALIGN_LCA = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL -ALIGN_LBA = wx.ALIGN_LEFT | wx.ALIGN_BOTTOM | wx.ALL - -class WrappedStaticText(wx.StaticText): - def __init__(self, parent): - self.parent = parent - wx.StaticText.__init__(self, parent, -1, "") - - def UpdateText(self, new_label): - cur_width = self.parent.GetSize().GetWidth() - self.SetLabel(new_label) - self.Wrap(cur_width) - self.parent.Layout() - -class DecoratedContainer(wx.Panel): - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.GridBagSizer(5, 5) - self.sizer.AddGrowableCol(2) - self.SetSizer(self.sizer) - - self.last_updated_dg = None - - def _DgStart(self, dg): - self._OnProgressGauge(False, 0, dg) - - def _DgUpdate(self, is_done, percent, dg): - self._OnProgressGauge(is_done, percent, dg) - - def _DgEnd(self, dg): - self._OnProgressGauge(True, 100, dg) - - def _DgFailure(self): - if self.last_updated_dg: - self.last_updated_dg.SetBitmap(self.resources.icon_failed) - - def _OnProgressGauge(self, is_done, percent, dg): - if is_done: - new_bitmap = self.resources.icon_complete - else: - new_bitmap = self.resources.icon_in_progress - dg.SetBitmap(new_bitmap) - dg.gauge.SetValue(percent) - self.last_updated_dg = dg - -class DecoratedContainerThreadMixin(object): - def __init__(self, dc): - self.dc = dc - - def _DgStart(self, dg): - wx.CallAfter(self.dc._DgStart, dg) - - def _DgUpdate(self, is_done, percent, dg): - wx.CallAfter(self.dc._DgUpdate, is_done, percent, dg) - - def _DgEnd(self, dg): - wx.CallAfter(self.dc._DgEnd, dg) - - def _DgFailure(self): - wx.CallAfter(self.dc._DgFailure) - -class DecoratedGauge(object): - def __init__(self, parent, caption, vpos): - self.current_bitmap = parent.resources.icon_unstarted - self.bitmap = wx.StaticBitmap( - parent, - -1, - self.current_bitmap, - None, - parent.resources.iwh - ) - self.text = wx.StaticText(parent, -1, caption) - self.gauge = wx.Gauge( - parent, - -1, - 100, - None, - (250, parent.resources.iwh[1]) - ) - parent.sizer.Add(self.bitmap, (vpos, 0), (1, 1), ALIGN_LBA, 5) - parent.sizer.Add(self.text, (vpos, 1), (1, 1), ALIGN_LCA, 5) - parent.sizer.Add(self.gauge, (vpos, 2), (1, 1), ALIGN_LBA, 5) - - def SetBitmap(self, new_bitmap): - if self.current_bitmap == new_bitmap: - return - self.current_bitmap = new_bitmap - self.bitmap.SetBitmap(self.current_bitmap) - -class MessagePanelBase(wx.Panel): - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.text_message = WrappedStaticText(self) - self.sizer.Add(self.text_message, 0, ALIGN_LTA, 5) - self.SetSizerAndFit(self.sizer) - -class WelcomePanel(MessagePanelBase): - _msg_welcome = ( - "Welcome to congruity; a programming application " + - "for Logitech Harmony remote controls.\n\n" - ) - - _msg_progress_parsing = ( - "Please wait while the configuration file is parsed." - ) - - _msg_status_ok = ( - "Please ensure the remote control is connected " + - "before proceeding.\n\n" + - "Click next to begin operation." - ) - - _msg_status_failure = ( - "A problem occurred. Click next for details." - ) - - _msg_failure_explanation = ( - "The configuration file cannot be read, or parsing failed.\n\n" + - "Operation cannot continue." - ) - - _msg_failure_details_unknown_op = ( - "Unrecognized file type '%d' returned by libconcord" - ) - - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - MessagePanelBase.__init__(self, parent, resources) - - self.next = None - self.initial_exception = None - - def _WorkerFunction(self): - try: - wx.CallAfter( - self.text_message.UpdateText, - self._msg_welcome + self._msg_progress_parsing - ) - - if self.initial_exception: - wx.CallAfter( - self._OnStatusFailure, - *self.initial_exception - ) - return - - self.next = self.resources.page_connect - - xml = POINTER(c_ubyte)() - xml_size = c_uint() - libconcord.read_file( - self.resources.ezhex_filename, - byref(xml), - byref(xml_size) - ) - self.resources.SetXmlData(xml, xml_size) - - type = c_int() - libconcord.identify_file(xml, xml_size, byref(type)) - - (next_page, type_text) = { - libconcord.LC_FILE_TYPE_CONNECTIVITY: - ( - self.resources.page_check_connectivity, - "Connectivity Check" - ), - libconcord.LC_FILE_TYPE_CONFIGURATION: - ( - self.resources.page_write_configuration, - "Update Configuration" - ), - libconcord.LC_FILE_TYPE_FIRMWARE: - ( - self.resources.page_update_firmware, - "Update Firmware" - ) - }.get(type.value, (None, None)) - - if not next_page: - wx.CallAfter( - self._OnStatusFailure, - self._msg_failure_explanation, - self._msg_failure_details_unknown_op % type.value - ) - return - - wx.CallAfter(self._OnStatusOk, next_page, type_text) - except: - wx.CallAfter( - self._OnStatusFailure, - self._msg_failure_explanation, - exception_message() - ) - - def _OnStatusOk(self, next_page, type_text): - self.resources.page_connect.SetNext(next_page) - self._OnStatusCommon(self._msg_status_ok) - - def _OnStatusFailure(self, failure_msg, details): - self.resources.page_failure.SetMessages( - failure_msg, - details - ) - self.next = self.resources.page_failure - self._OnStatusCommon(self._msg_status_failure) - - def _OnStatusCommon(self, message): - self.text_message.UpdateText(self._msg_welcome + message) - self.parent.ReenableCancel() - self.parent.ReenableNext() - - def SetInitialException(self, initial_exception): - self.initial_exception = initial_exception - - def OnActivated(self): - thread.start_new_thread(self._WorkerFunction, ()) - - def OnCancel(self): - self.parent.OnExit(1) - - def GetTitle(self): - return "Welcome" - - def IsTerminal(self): - return False - - def IsNextInitiallyDisabled(self): - return True - - def IsCancelInitiallyDisabled(self): - return False - - def GetNext(self): - return self.next - -class ConnectPanel(wx.Panel, DecoratedContainerThreadMixin): - _msg_ensure_connected = ( - "Please ensure your remote is correctly connected to your computer." - ) - - _msg_status_ok = ( - "Successfully connected to a remote:\n%s" - ) - - _msg_status_failure = ( - "A problem occurred. Click next for details." - ) - - _msg_failure_explanation = ( - "No remote could be found." - ) - - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - - self.text_help = WrappedStaticText(self) - self.sizer.Add(self.text_help, 0, wx.ALIGN_LEFT | wx.ALL, 5) - - self.dc = DecoratedContainer(self, resources) - DecoratedContainerThreadMixin.__init__(self, self.dc) - self.dg_connect = DecoratedGauge(self.dc, "Detect Remote", 0) - self.sizer.Add(self.dc, 0, wx.ALIGN_LEFT | wx.ALL, 5) - - self.text_info = WrappedStaticText(self) - self.sizer.Add(self.text_info, 0, wx.ALIGN_LEFT | wx.ALL, 5) - - self.SetSizerAndFit(self.sizer) - - self.next = None - self.finished = False - self.cancelled = False - - self.lock = thread.allocate_lock() - - def _WorkerFunction(self): - try: - wx.CallAfter( - self.text_help.UpdateText, - self._msg_ensure_connected - ) - - self._DgStart(self.dg_connect) - worker_body_connect( - self.resources, - self._DgUpdate, - self.dg_connect, - lambda: self.cancelled, - False - ) - self._DgEnd(self.dg_connect) - - mfg = libconcord.get_mfg() - model = libconcord.get_model() - - mfg_model = mfg + " " + model - wx.CallAfter(self._OnStatusOk, mfg_model) - except: - wx.CallAfter( - self._OnStatusFailure, - self._msg_failure_explanation, - exception_message() - ) - - self.lock.acquire() - self.finished = True - if self.cancelled: - wx.CallAfter(self.OnCancel) - self.lock.release() - - def _OnStatusOk(self, mfg_model): - self.btn_details = wx.Button(self, -1, "&Details...") - self.sizer.Add(self.btn_details, 0, wx.ALIGN_LEFT | wx.ALL, 5) - self.Bind(wx.EVT_BUTTON, self._OnDetails, self.btn_details) - self._OnStatusCommon(self._msg_status_ok % mfg_model) - - def _OnStatusFailure(self, failure_msg, details): - self.dc._DgFailure() - self.resources.page_failure.SetMessages( - failure_msg, - details - ) - self.SetNext(self.resources.page_failure) - self._OnStatusCommon(self._msg_status_failure) - - def _OnStatusCommon(self, message): - self.text_info.UpdateText(message) - self.parent.ReenableNext() - - def _OnDetails(self, event): - try: - msg = "" - - mfg = libconcord.get_mfg() - model = libconcord.get_model() - codename = libconcord.get_codename() - msg += "Model: %s %s (%s)\n" % (msg, model, codename) - - hid_mfg = libconcord.get_hid_mfg_str() - hid_prod = libconcord.get_hid_prod_str() - msg += "USB HID Model: %s %s\n" % (hid_mfg, hid_prod) - - ser_1 = libconcord.get_serial(libconcord.SERIAL_COMPONENT_1) - ser_2 = libconcord.get_serial(libconcord.SERIAL_COMPONENT_2) - ser_3 = libconcord.get_serial(libconcord.SERIAL_COMPONENT_3) - msg += "Serial:\n %s\n %s\n %s\n" % (ser_1, ser_2, ser_3) - - arch = libconcord.get_arch() - proto = libconcord.get_proto() - skin = libconcord.get_skin() - msg += "Arch:%d Proto:%d Skin:%d\n" % (arch, proto, skin) - - fw_type = libconcord.get_fw_type() - fw_ver_maj = libconcord.get_fw_ver_maj() - fw_ver_min = libconcord.get_fw_ver_min() - msg += "Firmware type:%d, version %d.%d\n" % ( - fw_type, fw_ver_maj, fw_ver_min - ) - - hw_ver_maj = libconcord.get_hw_ver_maj() - hw_ver_min = libconcord.get_hw_ver_min() - msg += "HW version %d.%d\n" % (hw_ver_maj, hw_ver_min) - - flash_mfg = libconcord.get_flash_mfg() - flash_id = libconcord.get_flash_id() - flash_part_num = libconcord.get_flash_part_num() - flash_size = libconcord.get_flash_size() - msg += "Flash Manufacturer:%d ID:%d Part:%s Size:%dK\n" % ( - flash_mfg, flash_id, flash_part_num, flash_size - ) - - hid_irl = libconcord.get_hid_irl() - hid_orl = libconcord.get_hid_orl() - hid_frl = libconcord.get_hid_frl() - msg += "USB HID Irl:%d Orl:%d Frl:%d\n" % (hid_irl, hid_orl, hid_frl) - - usb_vid = libconcord.get_usb_vid() - usb_pid = libconcord.get_usb_pid() - usb_bcd = libconcord.get_usb_bcd() - msg += "USB VID:%04x PID:%04x BCD:%04x\n" % (usb_vid, usb_pid, usb_bcd) - - config_bytes_used = libconcord.get_config_bytes_used() - config_bytes_total = libconcord.get_config_bytes_total() - config_pct_used = (config_bytes_used * 100) / config_bytes_total - msg += "Config used %d / total %d = %d%%\n" % ( - config_bytes_used, config_bytes_total, config_pct_used - ) - - fw_nondirect = libconcord.is_fw_update_supported(0) == 0 - fw_direct = libconcord.is_fw_update_supported(1) == 0 - if fw_nondirect or fw_direct: - config_safe = libconcord.is_config_safe_after_fw() == 0 - msg += "Firmware updates: Supported (%s), config%ssafe\n" % ( - fw_direct and "Direct" or "Not direct", - config_safe and " " or " NOT " - ) - else: - msg += "Firmware updates: NOT supported\n" - except: - msg = ( - "Error retrieving remote information:\n" + - exception_message() - ) - - show_modal_scrolled_msgbox(self.parent, "Remote Information", msg) - - def SetNext(self, next): - self.next = next - - def OnActivated(self): - thread.start_new_thread(self._WorkerFunction, ()) - - def OnCancel(self): - self.lock.acquire() - if self.finished: - self.lock.release() - self.parent.OnExit(1) - else: - self.cancelled = True - self.lock.release() - - def GetTitle(self): - return "Connecting" - - def IsTerminal(self): - return False - - def IsNextInitiallyDisabled(self): - return True - - def IsCancelInitiallyDisabled(self): - return False - - def GetNext(self): - return self.next - -class ProgramRemotePanelBase(wx.Panel, DecoratedContainerThreadMixin): - def __init__(self, parent, resources, file_type): - self.parent = parent - self.resources = resources - self.file_type = file_type - - wx.Panel.__init__(self, parent) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - - self.dc = DecoratedContainer(self, resources) - DecoratedContainerThreadMixin.__init__(self, self.dc) - self._AddWidgets() - self.sizer.Add(self.dc, 0, wx.ALIGN_LEFT | wx.ALL, 5) - - self.SetSizerAndFit(self.sizer) - - self.next = None - self.finished = False - - def _WorkerFunction(self): - try: - try: - self._WorkerFunctionBody() - wx.CallAfter(self._OnStatusOk) - return - except: - wx.CallAfter( - self._OnStatusFailure, - "Operation Failed", - exception_message() - ) - finally: - try: - if self.resources.connected: - self.resources.SetConnected(False) - libconcord.deinit_concord() - except: - pass - - def _OnStatusOk(self): - self.next = self.resources.page_success - self._OnStatusCommon() - - def _OnStatusFailure(self, failure_msg, details): - self.dc._DgFailure() - self.next = self.resources.page_failure - self.resources.page_failure.SetMessages( - failure_msg, - details - ) - self._OnStatusCommon() - - def _OnStatusCommon(self): - self.finished = True - self.parent.ReenableCancel() - self.parent.ReenableNext() - - def OnActivated(self): - thread.start_new_thread(self._WorkerFunction, ()) - - def OnCancel(self): - if self.finished: - self.parent.OnExit(1) - show_modal_scrolled_msgbox( - self.parent, - "Cannot Cancel", - "Cancel is disabled during programming operations, " + - "to prevent placing the remote into a state that will " + - "potentially be difficult to recover from." - ) - - def IsTerminal(self): - return False - - def IsNextInitiallyDisabled(self): - return True - - def IsCancelInitiallyDisabled(self): - return True - - def GetNext(self): - return self.next - -class CheckConnectivityPanel(ProgramRemotePanelBase): - def __init__(self, parent, resources): - ProgramRemotePanelBase.__init__( - self, - parent, - resources, - libconcord.LC_FILE_TYPE_CONNECTIVITY - ) - - def _AddWidgets(self): - vpos = counter() - self.dg_notify_website = DecoratedGauge(self.dc, "Notify Website", vpos.next()) - - def _WorkerFunctionBody(self): - self._DgUpdate( - False, - 0, - self.dg_notify_website - ) - libconcord.post_connect_test_success( - self.resources.xml, - self.resources.xml_size - ) - self._DgUpdate( - True, - 100, - self.dg_notify_website - ) - - def GetTitle(self): - return "Checking Connectivity" - -class WriteConfigurationPanel(ProgramRemotePanelBase): - def __init__(self, parent, resources): - ProgramRemotePanelBase.__init__( - self, - parent, - resources, - libconcord.LC_FILE_TYPE_CONFIGURATION - ) - - def _AddWidgets(self): - vpos = counter() - self.dg_check_website = DecoratedGauge(self.dc, "Check Website", vpos.next()) - self.dg_prepare = DecoratedGauge(self.dc, "Prepare Remote", vpos.next()) - self.dg_erase = DecoratedGauge(self.dc, "Erase Flash", vpos.next()) - self.dg_write = DecoratedGauge(self.dc, "Write Configuration", vpos.next()) - self.dg_verify = DecoratedGauge(self.dc, "Verify Upgrade", vpos.next()) - self.dg_reconnect = DecoratedGauge(self.dc, "Reconnect to Remote", vpos.next()) - self.dg_set_time = DecoratedGauge(self.dc, "Set Time", vpos.next()) - self.dg_notify_website = DecoratedGauge(self.dc, "Notify Website", vpos.next()) - - def _WorkerFunctionBody(self): - program_callback = libconcord.callback_type(program_callback_imp) - - self._DgStart(self.dg_check_website) - libconcord.post_preconfig(self.resources.xml, self.resources.xml_size) - self._DgEnd(self.dg_check_website) - - self._DgStart(self.dg_prepare) - bin_data = POINTER(c_ubyte)() - bin_size = c_uint() - libconcord.find_config_binary( - self.resources.xml, - self.resources.xml_size, - byref(bin_data), - byref(bin_size) - ) - self._DgUpdate(False, 50, self.dg_prepare) - libconcord.invalidate_flash() - self._DgEnd(self.dg_prepare) - - self._DgStart(self.dg_erase) - libconcord.erase_config( - bin_size, - program_callback, - py_object((self._DgUpdate, self.dg_erase)) - ) - self._DgEnd(self.dg_erase) - - self._DgStart(self.dg_write) - libconcord.write_config_to_remote( - bin_data, - bin_size, - program_callback, - py_object((self._DgUpdate, self.dg_write)) - ) - self._DgEnd(self.dg_write) - - self._DgStart(self.dg_verify) - libconcord.verify_remote_config( - bin_data, - bin_size, - program_callback, - py_object((self._DgUpdate, self.dg_verify)) - ) - self._DgEnd(self.dg_verify) - - self._DgStart(self.dg_reconnect) - libconcord.reset_remote() - worker_body_connect( - self.resources, - self._DgUpdate, - self.dg_reconnect, - lambda: False, - True - ) - - self._DgStart(self.dg_set_time) - libconcord.set_time() - self._DgEnd(self.dg_set_time) - - self._DgStart(self.dg_notify_website) - libconcord.post_postconfig(self.resources.xml, self.resources.xml_size) - self._DgEnd(self.dg_notify_website) - - def GetTitle(self): - return "Updating Configuration" - -class UpdateFirmwarePanel(ProgramRemotePanelBase): - def __init__(self, parent, resources): - ProgramRemotePanelBase.__init__( - self, - parent, - resources, - libconcord.LC_FILE_TYPE_FIRMWARE - ) - - def _AddWidgets(self): - vpos = counter() - self.dg_prepare = DecoratedGauge(self.dc, "Prepare Remote", vpos.next()) - self.dg_erase = DecoratedGauge(self.dc, "Erase Flash", vpos.next()) - self.dg_write = DecoratedGauge(self.dc, "Write Firmware", vpos.next()) - self.dg_finalize = DecoratedGauge(self.dc, "Finalize Programming", vpos.next()) - self.dg_reconnect = DecoratedGauge(self.dc, "Reconnect to Remote", vpos.next()) - self.dg_set_time = DecoratedGauge(self.dc, "Set Time", vpos.next()) - self.dg_notify_website = DecoratedGauge(self.dc, "Notify Website", vpos.next()) - - def _WorkerFunctionBody(self): - program_callback = libconcord.callback_type(program_callback_imp) - - self._DgStart(self.dg_prepare) - - # is_fw_update_supported returns error code; 0 OK, otherwise failure - if libconcord.is_fw_update_supported(0) == 0: - is_direct = False - elif libconcord.is_fw_update_supported(1) == 0: - is_direct = True - else: - raise Exception( - "Sorry, congruity doesn't yet support firmware update " + - "on this remote model." - ) - - self._DgUpdate(False, 25, self.dg_prepare) - - bin_data = POINTER(c_ubyte)() - bin_size = c_uint() - libconcord.extract_firmware_binary( - self.resources.xml, - self.resources.xml_size, - byref(bin_data), - byref(bin_size) - ) - - self._DgUpdate(False, 50, self.dg_prepare) - - if not is_direct: - libconcord.prep_firmware() - - self._DgUpdate(False, 75, self.dg_prepare) - - libconcord.invalidate_flash() - - self._DgEnd(self.dg_prepare) - - self._DgStart(self.dg_erase) - libconcord.erase_firmware( - is_direct, - program_callback, - py_object((self._DgUpdate, self.dg_erase)) - ) - self._DgEnd(self.dg_erase) - - self._DgStart(self.dg_write) - libconcord.write_firmware_to_remote( - bin_data, - bin_size, - c_int(is_direct and 1 or 0), - program_callback, - py_object((self._DgUpdate, self.dg_write)) - ) - self._DgEnd(self.dg_write) - - self._DgStart(self.dg_finalize) - if not is_direct: - libconcord.finish_firmware() - self._DgEnd(self.dg_finalize) - - self._DgStart(self.dg_reconnect) - libconcord.reset_remote() - worker_body_connect( - self.resources, - self._DgUpdate, - self.dg_reconnect, - lambda: False, - True - ) - - self._DgStart(self.dg_set_time) - libconcord.set_time() - self._DgEnd(self.dg_set_time) - - self._DgStart(self.dg_notify_website) - libconcord.post_postfirmware(self.resources.xml, self.resources.xml_size) - self._DgEnd(self.dg_notify_website) - - def GetTitle(self): - return "Updating Firmware" - -class SuccessPanel(MessagePanelBase): - def __init__(self, parent, resources): - MessagePanelBase.__init__( - self, - parent, - resources - ) - - def OnActivated(self): - self.text_message.UpdateText("Operation has completed successfully.") - - def OnCancel(self): - self.parent.OnExit(0) - - def GetTitle(self): - return "Success" - - def IsTerminal(self): - return True - - def GetExitCode(self): - return 0 - - def IsNextInitiallyDisabled(self): - return False - - def IsCancelInitiallyDisabled(self): - return True - -class FailurePanel(wx.Panel): - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.text_message = WrappedStaticText(self) - self.sizer.Add(self.text_message, 0, wx.ALIGN_LEFT | wx.ALL, 5) - self.btn_details = wx.Button(self, -1, "&Details...") - self.Bind(wx.EVT_BUTTON, self._OnDetails, self.btn_details) - self.sizer.Add(self.btn_details, 0, wx.ALIGN_LEFT | wx.ALL, 5) - self.SetSizerAndFit(self.sizer) - - self.message = "" - self.log_text = "" - - def _OnDetails(self, event): - show_modal_scrolled_msgbox(self.parent, "Error Log", self.log_text) - self.parent.ReenableNext() - - def SetMessages(self, message, traceback): - self.message = message - if traceback: - self.message += "\n\nSee below for details." - self.log_text = traceback - - def OnActivated(self): - if self.log_text: - self.btn_details.SetFocus() - else: - self.btn_details.Hide() - self.text_message.UpdateText(self.message) - - def OnCancel(self): - self.parent.OnExit(1) - - def GetTitle(self): - return "Failure" - - def IsTerminal(self): - return True - - def GetExitCode(self): - return 1 - - def IsNextInitiallyDisabled(self): - return False - - def IsCancelInitiallyDisabled(self): - return True - -class Wizard(wx.Dialog): - def __init__( - self, - resources, - app_finalizer, - min_page_width = 450, - min_page_height = None - ): - self.app_finalizer = app_finalizer - - self.min_page_width = min_page_width - self.min_page_height = min_page_height - - wx.Dialog.__init__(self, None, -1, 'Congruity version ' + version) - - sizer_main = wx.BoxSizer(wx.VERTICAL) - - sizer_top = wx.BoxSizer(wx.HORIZONTAL) - bitmap = wx.StaticBitmap(self, -1, resources.img_remote) - sizer_top.Add(bitmap, 0, wx.EXPAND | wx.ALL, 5) - - self.sizer_top_right = wx.BoxSizer(wx.VERTICAL) - self.title = wx.StaticText(self, -1, "Title") - font = wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD) - self.title.SetFont(font) - self.sizer_top_right.Add(self.title, 0, wx.EXPAND) - divider_top_right = wx.StaticLine(self, -1, None, None, wx.LI_HORIZONTAL) - self.sizer_top_right.Add(divider_top_right, 0, wx.EXPAND) - spacer = wx.StaticText(self, -1, "") - self.sizer_top_right.Add(spacer, 0, wx.EXPAND) - - sizer_top.Add(self.sizer_top_right, 1, wx.EXPAND | wx.ALL, 5) - sizer_main.Add(sizer_top, 1, wx.EXPAND | wx.ALL, 5) - - divider_main = wx.StaticLine(self, -1, None, None, wx.LI_HORIZONTAL) - sizer_main.Add(divider_main, 0, wx.EXPAND | wx.ALL, 5) - - sizer_buttons = wx.BoxSizer(wx.HORIZONTAL) - panel_btn_dummy = wx.Panel(self) - sizer_buttons.Add(panel_btn_dummy, 1, wx.EXPAND | wx.ALL, 5) - self.btn_next = wx.Button(self, -1, "&Next >") - self.Bind(wx.EVT_BUTTON, self._OnNext, self.btn_next) - sizer_buttons.Add(self.btn_next, 0, wx.EXPAND | wx.ALL, 5) - self.btn_cancel = wx.Button(self, -1, "&Cancel") - self.Bind(wx.EVT_BUTTON, self._OnCancel, self.btn_cancel) - self.Bind(wx.EVT_CLOSE, self._OnCancel) - sizer_buttons.Add(self.btn_cancel, 0, wx.EXPAND | wx.ALL, 5) - sizer_main.Add(sizer_buttons, 0, wx.EXPAND | wx.ALL, 5) - - self.SetSizerAndFit(sizer_main) - - self.cur_page = None - - def SetPages(self, pages): - def tuple_max(a, b): - return (max(a[0], b[0]), max(a[1], b[1])) - - self.pages = pages - - for page in self.pages: - page.Hide() - - size_wiz = self.GetSizeTuple() - for page in self.pages: - page.Show() - self.sizer_top_right.Add(page, 1, wx.EXPAND) - self.Fit() - size_page = self.GetSizeTuple() - size_wiz = tuple_max(size_wiz, size_page) - page.Hide() - self.sizer_top_right.Remove(page) - - if self.min_page_width and (size_wiz[0] < self.min_page_width): - size_wiz = (self.min_page_width, size_wiz[1]) - - if self.min_page_height and (size_wiz[1] < self.min_page_height): - size_wiz = (size_wiz[0], self.min_page_height ) - - self.SetSize(size_wiz) - - def SetInitialPage(self, page): - if self.cur_page: - raise Exception("Current page already set") - self._SetPage(page) - - def OnExit(self, retcode): - if self.app_finalizer: - self.app_finalizer() - os._exit(retcode) - - def _ReenableButton(self, button): - button.Enable(True) - button.Hide() - button.Show() - button.SetFocus() - - def ReenableNext(self): - self._ReenableButton(self.btn_next) - - def ReenableCancel(self): - self._ReenableButton(self.btn_cancel) - - def _OnNext(self, event): - if self.cur_page.IsTerminal(): - self.OnExit(self.cur_page.GetExitCode()) - next_page = self.cur_page.GetNext() - self._SetPage(next_page) - - def _OnCancel(self, event): - self.cur_page.OnCancel() - - def _SetPage(self, page): - if not page in self.pages: - raise Exception("Invalid page") - - if self.cur_page: - self.cur_page.Hide() - self.sizer_top_right.Remove(self.cur_page) - - self.cur_page = page - - self.cur_page.Show() - self.sizer_top_right.Add(self.cur_page, 1, wx.EXPAND) - - self.title.SetLabel(self.cur_page.GetTitle()) - - self.Layout() - - is_terminal = self.cur_page.IsTerminal() - if is_terminal: - self.btn_next.SetLabel("&Finish") - else: - self.btn_next.SetLabel("&Next >") - - self.btn_next.Enable(not self.cur_page.IsNextInitiallyDisabled()) - self.btn_cancel.Enable( - (not is_terminal) - and - (not self.cur_page.IsCancelInitiallyDisabled()) - ) - self.btn_next.SetFocus() - - self.cur_page.OnActivated() - -class Resources(object): - def __init__(self, appdir): - self.appdir = appdir - - self.ezhex_filename = None - self.xml = None - self.xml_size = None - self.connected = False - - def LoadImages(self): - def load(filename, appdir = self.appdir): - dirs = ['/usr/share/congruity', appdir, '.'] - for dir in dirs: - fpath = os.path.join(dir, filename) - if not os.path.isfile(fpath): - continue - return wx.Image(fpath, wx.BITMAP_TYPE_PNG).ConvertToBitmap() - raise Exception("Can't load " + filename) - - self.img_remote = load("remote.png") - self.icon_unstarted = load("icon-unstarted.png") - self.icon_in_progress = load("icon-in-progress.png") - self.icon_complete = load("icon-complete.png") - self.icon_failed = load("icon-failed.png") - - iw = max( - self.icon_in_progress.GetWidth(), - self.icon_complete.GetWidth(), - self.icon_failed.GetWidth() - ) - ih = max( - self.icon_in_progress.GetHeight(), - self.icon_complete.GetHeight(), - self.icon_failed.GetHeight() - ) - self.iwh = (iw, ih) - - def CreatePages(self, wizard): - self.page_welcome = WelcomePanel(wizard, self) - self.page_connect = ConnectPanel(wizard, self) - self.page_check_connectivity = CheckConnectivityPanel(wizard, self) - self.page_write_configuration = WriteConfigurationPanel(wizard, self) - self.page_update_firmware = UpdateFirmwarePanel(wizard, self) - self.page_success = SuccessPanel(wizard, self) - self.page_failure = FailurePanel(wizard, self) - - def SetEzHexFilename(self, ezhex_filename): - self.ezhex_filename = ezhex_filename - - def SetXmlData(self, xml, xml_size): - self.xml = xml - self.xml_size = xml_size - - def SetConnected(self, connected): - self.connected = connected - -class Finalizer(object): - def __init__(self, resources): - self.resources = resources - - def __call__(self): - if self.resources.xml: - try: - xml = self.resources.xml - self.resources.xml = None - self.resources.xml_size = None - libconcord.delete_blob(xml) - except: - pass - - if self.resources.connected: - try: - self.resources.SetConnected(False) - libconcord.deinit_concord() - except: - pass - -def main(argv): - app = argv.pop(0) - appdir = os.path.dirname(app) - - try: - while len(argv) and argv[0].startswith('-'): - arg = argv.pop(0) - if arg == '--version': - print version - return - else: - raise CmdLineException("ERROR: Option '%s' not recognized" %... [truncated message content] |
From: <srw...@us...> - 2009-03-10 02:17:44
|
Revision: 62 http://congruity.svn.sourceforge.net/congruity/?rev=62&view=rev Author: srwarren Date: 2009-03-10 02:14:20 +0000 (Tue, 10 Mar 2009) Log Message: ----------- Tag release 10 Added Paths: ----------- branches/congruity-10/ branches/congruity-10/Changelog branches/congruity-10/Makefile branches/congruity-10/README.txt branches/congruity-10/congruity branches/congruity-10/icon-sources.txt Removed Paths: ------------- branches/congruity-10/Changelog branches/congruity-10/Makefile branches/congruity-10/README.txt branches/congruity-10/congruity Property changes on: branches/congruity-10 ___________________________________________________________________ Added: svn:mergeinfo + Deleted: branches/congruity-10/Changelog =================================================================== --- trunk/Changelog 2008-10-13 00:13:29 UTC (rev 47) +++ branches/congruity-10/Changelog 2009-03-10 02:14:20 UTC (rev 62) @@ -1,101 +0,0 @@ -* 2008-09-07 Stephen Warren <s-t...@ww...> -- congruity-9 is released -- Use a different remote.png, with a known free license. - -* 2008-07-03 Stephen Warren <s-t...@ww...> -- congruity-8 is released -- Centralize cancel/exit handling, - and clean up any libconcord resources when exiting the application. -- Add thread-safe cancelling to ConnectPanel. -- Work around a typo in libconcord 0.20's Python bindings. -- Provide a GUI message if libconcord can't be loaded, in case congruity - wasn't run from a terminal. - -* 2008-07-02 Stephen Warren <s-t...@ww...> -- Increase connect timeout after a reset operation, just to make sure - we don't miss the remote coming back. -- Fix Makefile to create all directories files are written to, and add - a few more variables that can be tweaked e.g. by packaging scripts. -* On behalf of Andreas Schulz <And...@gm...> -- Use a simpler and potentially more reliable fix for GTK buttons not - accepting clicks if the mouse was inside the widget when enabled. - -* 2008-07-01 Stephen Warren <s-t...@ww...> -- Command-line parsing errors are displayed by the GUI, instead of being - echo'd to stdout. This makes errors visible when congruity is launched - without a terminal - -* 2008-06-25..2008-07-01 Stephen Warren <s-t...@ww...> -* Inspired by Andreas Schulz <And...@gm...> -- Significant internal structural changes to the implementation, which - simplify things a lot, and make program flow far more obvious, localized, - and correctly polymorphic. -- Add a separate "connect" page, so that the other pages don't have to - re-implement this common function. - -* 2008-06-17 Stephen Warren <s-t...@ww...> -* On behalf of Andreas Schulz <And...@gm...> -- Fix issue where next button wouldn't respond to clicks if the pointer was - already within the button when it was re-enabled. - -* 2008-04-14 Stephen Warren <s-t...@ww...> -- congruity-7 is released -- Switched license to GPLv3+ to be compatible with libconcord by default. - Contact me if you want the code under a different license, but please - note that you won't be able to use relicensed code with libconcord. -- Added a Makefile for easy installation. - Thanks to Phil Dibowitz for the contribution. -- Added a manual page. -- Added a few useful URLs to README.txt. -- Fixed reliance on syntax specific to Python 2.5. - -* 2008-04-13 Stephen Warren <s-t...@ww...> -- congruity-6 is released -- Search for images in /usr/share/congruity, the source directory, then - CWD. This should allow easy system-wide installation of congruity. -- libconcord.py is no longer distributed with congruity; it is now part - of libconcord itself (see libconcord/bindings/python/). -- Apparently forgot to release LICENSE.txt before. - -* 2008-04-07 Stephen Warren <s-t...@ww...> -- congruity-5 is released -- This release solely operates using libconcord; "screen-scraping" the output - from the concordance application is no longer supported. -- Implement firmware upgrade. -- Minor tweaks for operation on MS-Windows. -- congruity now sets the time on the remote after any reboot. - -* 2008-03-29 Stephen Warren <s-t...@ww...> -- congruity-4 is released -- Renamed package from harmonygui to congruity, in line with the - coming rename of the harmonycontrol project to concordance/libconcord. -- Changes to match latest CVS libconcord API changes - -* 2008-02-24 Stephen Warren <s-t...@ww...> -- harmonygui-3 is released -- Added README.txt. -- Added LICENSING.txt, to account for images too. -- Remove GUI for initial web connection in update mode; the libharmony - branch code doesn't print this status information, so now we act like - it was never there. -- Code re-org, to allow for multiple back-ends. -- Added a back-end that calls libharmony.so directly using ctypes. - -* 2008-02-10 Stephen Warren <s-t...@ww...> -- harmonygui-2 is released -- Updated ezhexparser to recognize firmware update files. -- Updated GUI to handle firmware updates, by informing user its - not yet supported. -- Separated ezhexparser and tuiparser operation mode enumerations. -- Enhanced ptyrun error handling, so it's more obvious what happened - when the harmony application can't be found in the $PATH. -- Updated harmonyfake to use ^H characters to re-write output, not - \r. This matches the real harmony app. -- Minor typo cleanups in messages. -- Added licensing information. -- Added this Changelog - -* 2008-02-05 Stephen Warren <s-t...@ww...> -- harmonygui-1 is released -- Initial release. - Copied: branches/congruity-10/Changelog (from rev 61, trunk/Changelog) =================================================================== --- branches/congruity-10/Changelog (rev 0) +++ branches/congruity-10/Changelog 2009-03-10 02:14:20 UTC (rev 62) @@ -0,0 +1,117 @@ +* 2009-xx-xx Stephen Warren <s-t...@ww...> +- congruity-10 is released +- Implement IR learning feature, with support for learning from the original + remote using the Harmony, or reading the signal from a "Pronto Hex" file. + (Merge of /branches/irlean) + Parts based on code by Andreas Schulz <And...@gm...> +- Various internal code changes to support IR learning and general cleanup. +- Implement --no-web command-line option, which prevents posting any data + to the Harmony website. This can be useful when testing congruity. +- Change default install prefix to /usr/local; this makes typical end-user + manual installs slightly simpler. Also, automatically patch install location + into the app during installation. +- If libconcord import fails, display the entire backtrace information, to + enable easier debugging of the issue. +- Enhance README + +* 2008-09-07 Stephen Warren <s-t...@ww...> +- congruity-9 is released +- Use a different remote.png, with a known free license. + +* 2008-07-03 Stephen Warren <s-t...@ww...> +- congruity-8 is released +- Centralize cancel/exit handling, + and clean up any libconcord resources when exiting the application. +- Add thread-safe cancelling to ConnectPanel. +- Work around a typo in libconcord 0.20's Python bindings. +- Provide a GUI message if libconcord can't be loaded, in case congruity + wasn't run from a terminal. + +* 2008-07-02 Stephen Warren <s-t...@ww...> +- Increase connect timeout after a reset operation, just to make sure + we don't miss the remote coming back. +- Fix Makefile to create all directories files are written to, and add + a few more variables that can be tweaked e.g. by packaging scripts. +* On behalf of Andreas Schulz <And...@gm...> +- Use a simpler and potentially more reliable fix for GTK buttons not + accepting clicks if the mouse was inside the widget when enabled. + +* 2008-07-01 Stephen Warren <s-t...@ww...> +- Command-line parsing errors are displayed by the GUI, instead of being + echo'd to stdout. This makes errors visible when congruity is launched + without a terminal + +* 2008-06-25..2008-07-01 Stephen Warren <s-t...@ww...> +* Inspired by Andreas Schulz <And...@gm...> +- Significant internal structural changes to the implementation, which + simplify things a lot, and make program flow far more obvious, localized, + and correctly polymorphic. +- Add a separate "connect" page, so that the other pages don't have to + re-implement this common function. + +* 2008-06-17 Stephen Warren <s-t...@ww...> +* On behalf of Andreas Schulz <And...@gm...> +- Fix issue where next button wouldn't respond to clicks if the pointer was + already within the button when it was re-enabled. + +* 2008-04-14 Stephen Warren <s-t...@ww...> +- congruity-7 is released +- Switched license to GPLv3+ to be compatible with libconcord by default. + Contact me if you want the code under a different license, but please + note that you won't be able to use relicensed code with libconcord. +- Added a Makefile for easy installation. + Thanks to Phil Dibowitz for the contribution. +- Added a manual page. +- Added a few useful URLs to README.txt. +- Fixed reliance on syntax specific to Python 2.5. + +* 2008-04-13 Stephen Warren <s-t...@ww...> +- congruity-6 is released +- Search for images in /usr/share/congruity, the source directory, then + CWD. This should allow easy system-wide installation of congruity. +- libconcord.py is no longer distributed with congruity; it is now part + of libconcord itself (see libconcord/bindings/python/). +- Apparently forgot to release LICENSE.txt before. + +* 2008-04-07 Stephen Warren <s-t...@ww...> +- congruity-5 is released +- This release solely operates using libconcord; "screen-scraping" the output + from the concordance application is no longer supported. +- Implement firmware upgrade. +- Minor tweaks for operation on MS-Windows. +- congruity now sets the time on the remote after any reboot. + +* 2008-03-29 Stephen Warren <s-t...@ww...> +- congruity-4 is released +- Renamed package from harmonygui to congruity, in line with the + coming rename of the harmonycontrol project to concordance/libconcord. +- Changes to match latest CVS libconcord API changes + +* 2008-02-24 Stephen Warren <s-t...@ww...> +- harmonygui-3 is released +- Added README.txt. +- Added LICENSING.txt, to account for images too. +- Remove GUI for initial web connection in update mode; the libharmony + branch code doesn't print this status information, so now we act like + it was never there. +- Code re-org, to allow for multiple back-ends. +- Added a back-end that calls libharmony.so directly using ctypes. + +* 2008-02-10 Stephen Warren <s-t...@ww...> +- harmonygui-2 is released +- Updated ezhexparser to recognize firmware update files. +- Updated GUI to handle firmware updates, by informing user its + not yet supported. +- Separated ezhexparser and tuiparser operation mode enumerations. +- Enhanced ptyrun error handling, so it's more obvious what happened + when the harmony application can't be found in the $PATH. +- Updated harmonyfake to use ^H characters to re-write output, not + \r. This matches the real harmony app. +- Minor typo cleanups in messages. +- Added licensing information. +- Added this Changelog + +* 2008-02-05 Stephen Warren <s-t...@ww...> +- harmonygui-1 is released +- Initial release. + Deleted: branches/congruity-10/Makefile =================================================================== --- trunk/Makefile 2008-10-13 00:13:29 UTC (rev 47) +++ branches/congruity-10/Makefile 2009-03-10 02:14:20 UTC (rev 62) @@ -1,27 +0,0 @@ -DESTDIR ?= -PREFIX ?= /usr - -BINDIR ?= $(PREFIX)/bin -SHAREDIR ?= $(PREFIX)/share -APPSHAREDIR ?= $(SHAREDIR)/congruity -MANDIR ?= $(SHAREDIR)/man -MAN1DIR ?= $(MANDIR)/man1 - -INSTALL ?= /usr/bin/install - -all: - @echo "Nothing to build, run 'make install' as root" - -install: - mkdir -p --mode=755 $(DESTDIR)$(BINDIR) - $(INSTALL) --mode=755 congruity $(DESTDIR)$(BINDIR)/congruity - mkdir -p --mode=755 $(DESTDIR)$(APPSHAREDIR) - $(INSTALL) --mode=644 *.png $(DESTDIR)$(APPSHAREDIR) - mkdir -p --mode=755 $(DESTDIR)$(MAN1DIR) - $(INSTALL) --mode=644 congruity.1 $(DESTDIR)$(MAN1DIR) - -uninstall: - /bin/rm -f $(DESTDIR)$(BINDIR)/congruity - /bin/rm -rf $(DESTDIR)$(APPSHAREDIR) - /bin/rm -f $(DESTDIR)$(MAN1DIR)/congruity.1 - Copied: branches/congruity-10/Makefile (from rev 58, trunk/Makefile) =================================================================== --- branches/congruity-10/Makefile (rev 0) +++ branches/congruity-10/Makefile 2009-03-10 02:14:20 UTC (rev 62) @@ -0,0 +1,29 @@ +DESTDIR ?= +PREFIX ?= /usr/local + +BINDIR ?= $(PREFIX)/bin +SHAREDIR ?= $(PREFIX)/share +APPSHAREDIR ?= $(SHAREDIR)/congruity +MANDIR ?= $(SHAREDIR)/man +MAN1DIR ?= $(MANDIR)/man1 + +INSTALL ?= install + +all: + @echo "Nothing to build, run 'make install' as root" + +install: + mkdir -p --mode=755 $(DESTDIR)$(BINDIR) + sed -e "s:/usr/share/congruity:${APPSHAREDIR}:" < congruity > congruity.patched + $(INSTALL) --mode=755 congruity.patched $(DESTDIR)$(BINDIR)/congruity + rm -f congruity.patched + mkdir -p --mode=755 $(DESTDIR)$(APPSHAREDIR) + $(INSTALL) --mode=644 *.png $(DESTDIR)$(APPSHAREDIR) + mkdir -p --mode=755 $(DESTDIR)$(MAN1DIR) + $(INSTALL) --mode=644 congruity.1 $(DESTDIR)$(MAN1DIR) + +uninstall: + /bin/rm -f $(DESTDIR)$(BINDIR)/congruity + /bin/rm -rf $(DESTDIR)$(APPSHAREDIR) + /bin/rm -f $(DESTDIR)$(MAN1DIR)/congruity.1 + Deleted: branches/congruity-10/README.txt =================================================================== --- trunk/README.txt 2008-10-13 00:13:29 UTC (rev 47) +++ branches/congruity-10/README.txt 2009-03-10 02:14:20 UTC (rev 62) @@ -1,46 +0,0 @@ -Requirements: - -Python (tested with 2.5.1 on Fedora 8) - See http://www.python.org/ -Python ctypes library (included with Python 2.5, separate earlier) - See http://sourceforge.net/projects/ctypes/ -wxPython (tested with wxGTK-2.8.4 on Fedora 8) - See http://www.wxpython.org/ -libconcord (tested with pre-0.20 CVS snapshot on Fedora 8) - See http: http://www.phildev.net/concordance/ - -Installation/Usage: - -You may need to set up udev/similar rules so that the USB device nodes -used by the application are accessible without using root. I use -the following file: - ------ /etc/udev/rules.d/custom-concordance.rules: -SYSFS{idVendor}=="046d", SYSFS{idProduct}=="c110", MODE="666" ------ - -Note that your vendor and product ID may be different. Use lsusb to verify: - ------ -[swarren@esk ~]$ lsusb -... -Bus 005 Device 011: ID 046d:c110 Logitech, Inc. -... ------ - -Remember to differentiate between the Harmony remote and any other Logitech -peripherals you may have! - -Congruity relies on the libconcord library, which must be obtained and -installed separately. Note that you will need to install the Python bindings -for libconcord too; see libconcord/bindings/python/. - -Configure your web browser to open files of type *.EZHex and *.EZUp with the -congruity application. This is typically performed using the dialog box -that appears when a file is about to be downloaded. - -Note that in Firefox, you'll need to change a setting to see the download -action prompt; Otherwise, files will simply be saved to disk without you -being asked. Edit menu -> Preferences menu item -> Main tab -> Select -"Always ask me where to save files." - Copied: branches/congruity-10/README.txt (from rev 59, trunk/README.txt) =================================================================== --- branches/congruity-10/README.txt (rev 0) +++ branches/congruity-10/README.txt 2009-03-10 02:14:20 UTC (rev 62) @@ -0,0 +1,147 @@ +Requirements +============================================================================== + +Python (tested with 2.5.1 on Fedora 9) + See http://www.python.org/ + +Python ctypes library (included with Python 2.5, separate earlier) + See http://sourceforge.net/projects/ctypes/ + +wxPython (tested with wxGTK-2.8.7 on Fedora 9) + See http://www.wxpython.org/ + +libconcord (tested with post-0.20 CVS snapshot on Fedora 9) + See http://www.phildev.net/concordance/ + Note that the python bindings are also required; see + libconcord/bindings/python + +Python, ctypes, and wxPython are typically installed using your distribution's +package management system. If this is not the case, installation instructions +should be located in the documentation accompanying those packages. + +libconcord may be available via your distribution's package management +system. If so, please ensure that you install any sub-packages required to +provide the libconcord Python bindings, e.g. both libconcord and +libconcord-python. + +If installing libconcord from source, please follow the instructions +accompanying the source. Note that the Python bindings must be installed +separately; the bindings are found within the following sub-directory of the +libconcord source package: + + libconcord/bindings/python + +Some versions of libconcord provide a README.txt detailing the installation +process. Otherwise, the basic instructions are to run the following command as +root: + + python setup.py install + +Installation +============================================================================== + +congruity may be installed by running the following command: + + make install + +This command typically requires root access, since the default installation +location is /usr/local. + +Please read Makefile for details of variables that may be set to configure the +installation process, e.g.: + + make install DESTDIR=/tmp/pkgtmp PREFIX=/usr + +Device Node Access Setup +============================================================================== + +You may need to set up udev/similar rules so that the USB device nodes used +by the application are accessible without running congruity as root. Note that +distribution packages of libconcord typically provide these rules, so they may +already be set up for you. + +If you need to manually set up udev rules, the following file should work: + +----- /etc/udev/rules.d/custom-concordance.rules: +SYSFS{idVendor}=="046d", SYSFS{idProduct}=="c110", MODE="666" +----- + +Note that your vendor and product ID may be different. Use lsusb to verify: + +----- +[swarren@esk ~]$ lsusb +... +Bus 005 Device 011: ID 046d:c110 Logitech, Inc. +... +----- + +Remember to differentiate between the Harmony remote and any other Logitech +peripherals you may have! Note that not all Harmony-compatible remotes are +Logitech-branded in the USB listing. + +Usage Model +============================================================================== + +congruity aims to fit into the usage model implemented by the official +Logitech software. The primary differentiation is that congruity is both +open-source and more cross-platform than the official software. + +Harmony remotes are configured using the Logitech website, based at the +following URL: + + http://members.harmonyremote.com/ + +Note that other URLs may be used for remotes that are not branded as +"Harmony". However, the overall process is identical. + +The website provides a database of devices, and a set of wizards to select +which of those are present in your setup. All decisions regarding how the +remote will be configured are made through this website. + +Please note that more recent versions of the Logitech software appear to be +an application that executes locally on the user's computer. However, they are +in fact a simple wrapping of a web-browser, simply hiding the web-based nature +of the configuration process. + +Once the configuration is complete, the website will push various file +downloads to the web browser. These files contain the information required to +program the user's configuration into the remote. For each file downloaded, +the congruity application should be executed to process the instructions in +that file. + +Web Browser Setup +============================================================================== + +Configure your web browser to open files of type *.EZHex, *.EZUp, and *.EZTut +with the congruity application. + +This is typically set up using the dialog box that appears when a file is +about to be downloaded. congruity should be executed once for each file +downloaded, and should be passed the name of the saved download as a command- +line parameter, for example: + + congruity /tmp/Connectivity.EZHex + +If you're confused, the above behavior is most likely what your web browser +will do automatically when configured to open files using congruity. + +Firefox Specific Notes +============================================================================== + +You'll need to change a setting to see the download action prompt; Otherwise, +files will simply be saved to disk without you being asked. On Linux, this may +be achieved from the Edit menu -> Preferences menu item -> Main tab -> Select +"Always ask me where to save files". The exact menu location may vary slightly +on other operating systems. + +When a file download commences, a dialog will appear with the option to "Open +With", or "Save" the file. Select "Open With", and browse for the congruity +executable as the application. You may also want to select "Do this +automatically for files like this from now on". You will need to select the +path to the congruity application once for each file type (*.EZHex, *.EZUp, +*.EZTut). + +If the automatic option is not selected, the dialog will appear for every file +downloaded. Note that Firefox does remember the path to congruity for future +downloads, even though it is not displayed. + Deleted: branches/congruity-10/congruity =================================================================== --- trunk/congruity 2008-10-13 00:13:29 UTC (rev 47) +++ branches/congruity-10/congruity 2009-03-10 02:14:20 UTC (rev 62) @@ -1,1255 +0,0 @@ -#!/usr/bin/python - -# Copyright 2008 Stephen Warren -# -# This file is part of congruity. -# -# congruity 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. -# -# congruity 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 congruity. If not, see <http://www.gnu.org/licenses/>. - -from ctypes import * -import os -import os.path -import sys -import thread -import time -import traceback -import wx -import wx.lib.dialogs - -version = "9+" - -try: - import libconcord - # Fix typo in libconcord 0.20 Python bindings - try: - libconcord.delete_blob - except: - libconcord.delete_blob = libconcord.delete_block -except: - app = wx.PySimpleApp() - dlg = wx.MessageDialog( - None, - "Could not load libconcord; please ensure it, and the Python " - "bindings, are installed and in the relevant search paths.", - "congruity: Dependency Error", - wx.OK | wx.ICON_ERROR - ) - dlg.ShowModal() - os._exit(1) - -def counter(): - i=0 - while True: - yield i - i += 1 - -def program_callback_imp(count, current, total, context): - if not context: - return - - try: - (f, fcontext) = context - percent = (current * 100) / total - f(False, percent, fcontext) - except: - print - traceback.print_exc() - -class CmdLineException(Exception): - pass - -def exception_message(): - msg = '' - if type(sys.exc_value) == libconcord.LibConcordException: - try: - msg += '%s\n (libconcord function %s error %d)\n\n' % ( - sys.exc_value.result_str, - sys.exc_value.func, - sys.exc_value.result - ) - except: - pass - if type(sys.exc_value) == CmdLineException: - try: - msg += '%s\n\n' % ( - str(sys.exc_value) - ) - except: - pass - msg += traceback.format_exc() - return msg - -def worker_body_connect( - resources, - on_progress, - cb_context, - cancel_check, - after_reset -): - program_callback = libconcord.callback_type(program_callback_imp) - - max_attempts = after_reset and 180 or 60 - for attempt in range(max_attempts): - on_progress( - False, - (attempt * 100) / max_attempts, - cb_context - ) - try: - libconcord.init_concord() - resources.SetConnected(True) - try: - libconcord.get_identity( - program_callback, - None - ) - except: - ignore = False - if type(sys.exc_value) == libconcord.LibConcordException: - # FIXME: Expose these constants in libconcord.py - ignore = sys.exc_value.result == 16 #LC_ERROR_INVALID_CONFIG - if not ignore: - raise - break - except: - if cancel_check() or (attempt == max_attempts - 1): - raise - time.sleep(1) - on_progress( - True, - 100, - cb_context - ) - -def show_modal_scrolled_msgbox(parent, title, text): - size = parent.GetClientSizeTuple() - size = (size[0] * 90 / 100, size[1] * 90 / 100) - wx.lib.dialogs.ScrolledMessageDialog( - parent, - text, - title, - (-1, -1), - size - ).ShowModal() - -ALIGN_LTA = wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.ALL -ALIGN_LCA = wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.ALL -ALIGN_LBA = wx.ALIGN_LEFT | wx.ALIGN_BOTTOM | wx.ALL - -class WrappedStaticText(wx.StaticText): - def __init__(self, parent): - self.parent = parent - wx.StaticText.__init__(self, parent, -1, "") - - def UpdateText(self, new_label): - cur_width = self.parent.GetSize().GetWidth() - self.SetLabel(new_label) - self.Wrap(cur_width) - self.parent.Layout() - -class DecoratedContainer(wx.Panel): - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.GridBagSizer(5, 5) - self.sizer.AddGrowableCol(2) - self.SetSizer(self.sizer) - - self.last_updated_dg = None - - def _DgStart(self, dg): - self._OnProgressGauge(False, 0, dg) - - def _DgUpdate(self, is_done, percent, dg): - self._OnProgressGauge(is_done, percent, dg) - - def _DgEnd(self, dg): - self._OnProgressGauge(True, 100, dg) - - def _DgFailure(self): - if self.last_updated_dg: - self.last_updated_dg.SetBitmap(self.resources.icon_failed) - - def _OnProgressGauge(self, is_done, percent, dg): - if is_done: - new_bitmap = self.resources.icon_complete - else: - new_bitmap = self.resources.icon_in_progress - dg.SetBitmap(new_bitmap) - dg.gauge.SetValue(percent) - self.last_updated_dg = dg - -class DecoratedContainerThreadMixin(object): - def __init__(self, dc): - self.dc = dc - - def _DgStart(self, dg): - wx.CallAfter(self.dc._DgStart, dg) - - def _DgUpdate(self, is_done, percent, dg): - wx.CallAfter(self.dc._DgUpdate, is_done, percent, dg) - - def _DgEnd(self, dg): - wx.CallAfter(self.dc._DgEnd, dg) - - def _DgFailure(self): - wx.CallAfter(self.dc._DgFailure) - -class DecoratedGauge(object): - def __init__(self, parent, caption, vpos): - self.current_bitmap = parent.resources.icon_unstarted - self.bitmap = wx.StaticBitmap( - parent, - -1, - self.current_bitmap, - None, - parent.resources.iwh - ) - self.text = wx.StaticText(parent, -1, caption) - self.gauge = wx.Gauge( - parent, - -1, - 100, - None, - (250, parent.resources.iwh[1]) - ) - parent.sizer.Add(self.bitmap, (vpos, 0), (1, 1), ALIGN_LBA, 5) - parent.sizer.Add(self.text, (vpos, 1), (1, 1), ALIGN_LCA, 5) - parent.sizer.Add(self.gauge, (vpos, 2), (1, 1), ALIGN_LBA, 5) - - def SetBitmap(self, new_bitmap): - if self.current_bitmap == new_bitmap: - return - self.current_bitmap = new_bitmap - self.bitmap.SetBitmap(self.current_bitmap) - -class MessagePanelBase(wx.Panel): - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.text_message = WrappedStaticText(self) - self.sizer.Add(self.text_message, 0, ALIGN_LTA, 5) - self.SetSizerAndFit(self.sizer) - -class WelcomePanel(MessagePanelBase): - _msg_welcome = ( - "Welcome to congruity; a programming application " + - "for Logitech Harmony remote controls.\n\n" - ) - - _msg_progress_parsing = ( - "Please wait while the configuration file is parsed." - ) - - _msg_status_ok = ( - "Please ensure the remote control is connected " + - "before proceeding.\n\n" + - "Click next to begin operation." - ) - - _msg_status_failure = ( - "A problem occurred. Click next for details." - ) - - _msg_failure_explanation = ( - "The configuration file cannot be read, or parsing failed.\n\n" + - "Operation cannot continue." - ) - - _msg_failure_details_unknown_op = ( - "Unrecognized file type '%d' returned by libconcord" - ) - - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - MessagePanelBase.__init__(self, parent, resources) - - self.next = None - self.initial_exception = None - - def _WorkerFunction(self): - try: - wx.CallAfter( - self.text_message.UpdateText, - self._msg_welcome + self._msg_progress_parsing - ) - - if self.initial_exception: - wx.CallAfter( - self._OnStatusFailure, - *self.initial_exception - ) - return - - self.next = self.resources.page_connect - - xml = POINTER(c_ubyte)() - xml_size = c_uint() - libconcord.read_file( - self.resources.ezhex_filename, - byref(xml), - byref(xml_size) - ) - self.resources.SetXmlData(xml, xml_size) - - type = c_int() - libconcord.identify_file(xml, xml_size, byref(type)) - - (next_page, type_text) = { - libconcord.LC_FILE_TYPE_CONNECTIVITY: - ( - self.resources.page_check_connectivity, - "Connectivity Check" - ), - libconcord.LC_FILE_TYPE_CONFIGURATION: - ( - self.resources.page_write_configuration, - "Update Configuration" - ), - libconcord.LC_FILE_TYPE_FIRMWARE: - ( - self.resources.page_update_firmware, - "Update Firmware" - ) - }.get(type.value, (None, None)) - - if not next_page: - wx.CallAfter( - self._OnStatusFailure, - self._msg_failure_explanation, - self._msg_failure_details_unknown_op % type.value - ) - return - - wx.CallAfter(self._OnStatusOk, next_page, type_text) - except: - wx.CallAfter( - self._OnStatusFailure, - self._msg_failure_explanation, - exception_message() - ) - - def _OnStatusOk(self, next_page, type_text): - self.resources.page_connect.SetNext(next_page) - self._OnStatusCommon(self._msg_status_ok) - - def _OnStatusFailure(self, failure_msg, details): - self.resources.page_failure.SetMessages( - failure_msg, - details - ) - self.next = self.resources.page_failure - self._OnStatusCommon(self._msg_status_failure) - - def _OnStatusCommon(self, message): - self.text_message.UpdateText(self._msg_welcome + message) - self.parent.ReenableCancel() - self.parent.ReenableNext() - - def SetInitialException(self, initial_exception): - self.initial_exception = initial_exception - - def OnActivated(self): - thread.start_new_thread(self._WorkerFunction, ()) - - def OnCancel(self): - self.parent.OnExit(1) - - def GetTitle(self): - return "Welcome" - - def IsTerminal(self): - return False - - def IsNextInitiallyDisabled(self): - return True - - def IsCancelInitiallyDisabled(self): - return False - - def GetNext(self): - return self.next - -class ConnectPanel(wx.Panel, DecoratedContainerThreadMixin): - _msg_ensure_connected = ( - "Please ensure your remote is correctly connected to your computer." - ) - - _msg_status_ok = ( - "Successfully connected to a remote:\n%s" - ) - - _msg_status_failure = ( - "A problem occurred. Click next for details." - ) - - _msg_failure_explanation = ( - "No remote could be found." - ) - - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - - self.text_help = WrappedStaticText(self) - self.sizer.Add(self.text_help, 0, wx.ALIGN_LEFT | wx.ALL, 5) - - self.dc = DecoratedContainer(self, resources) - DecoratedContainerThreadMixin.__init__(self, self.dc) - self.dg_connect = DecoratedGauge(self.dc, "Detect Remote", 0) - self.sizer.Add(self.dc, 0, wx.ALIGN_LEFT | wx.ALL, 5) - - self.text_info = WrappedStaticText(self) - self.sizer.Add(self.text_info, 0, wx.ALIGN_LEFT | wx.ALL, 5) - - self.SetSizerAndFit(self.sizer) - - self.next = None - self.finished = False - self.cancelled = False - - self.lock = thread.allocate_lock() - - def _WorkerFunction(self): - try: - wx.CallAfter( - self.text_help.UpdateText, - self._msg_ensure_connected - ) - - self._DgStart(self.dg_connect) - worker_body_connect( - self.resources, - self._DgUpdate, - self.dg_connect, - lambda: self.cancelled, - False - ) - self._DgEnd(self.dg_connect) - - mfg = libconcord.get_mfg() - model = libconcord.get_model() - - mfg_model = mfg + " " + model - wx.CallAfter(self._OnStatusOk, mfg_model) - except: - wx.CallAfter( - self._OnStatusFailure, - self._msg_failure_explanation, - exception_message() - ) - - self.lock.acquire() - self.finished = True - if self.cancelled: - wx.CallAfter(self.OnCancel) - self.lock.release() - - def _OnStatusOk(self, mfg_model): - self.btn_details = wx.Button(self, -1, "&Details...") - self.sizer.Add(self.btn_details, 0, wx.ALIGN_LEFT | wx.ALL, 5) - self.Bind(wx.EVT_BUTTON, self._OnDetails, self.btn_details) - self._OnStatusCommon(self._msg_status_ok % mfg_model) - - def _OnStatusFailure(self, failure_msg, details): - self.dc._DgFailure() - self.resources.page_failure.SetMessages( - failure_msg, - details - ) - self.SetNext(self.resources.page_failure) - self._OnStatusCommon(self._msg_status_failure) - - def _OnStatusCommon(self, message): - self.text_info.UpdateText(message) - self.parent.ReenableNext() - - def _OnDetails(self, event): - try: - msg = "" - - mfg = libconcord.get_mfg() - model = libconcord.get_model() - codename = libconcord.get_codename() - msg += "Model: %s %s (%s)\n" % (msg, model, codename) - - hid_mfg = libconcord.get_hid_mfg_str() - hid_prod = libconcord.get_hid_prod_str() - msg += "USB HID Model: %s %s\n" % (hid_mfg, hid_prod) - - ser_1 = libconcord.get_serial(libconcord.SERIAL_COMPONENT_1) - ser_2 = libconcord.get_serial(libconcord.SERIAL_COMPONENT_2) - ser_3 = libconcord.get_serial(libconcord.SERIAL_COMPONENT_3) - msg += "Serial:\n %s\n %s\n %s\n" % (ser_1, ser_2, ser_3) - - arch = libconcord.get_arch() - proto = libconcord.get_proto() - skin = libconcord.get_skin() - msg += "Arch:%d Proto:%d Skin:%d\n" % (arch, proto, skin) - - fw_type = libconcord.get_fw_type() - fw_ver_maj = libconcord.get_fw_ver_maj() - fw_ver_min = libconcord.get_fw_ver_min() - msg += "Firmware type:%d, version %d.%d\n" % ( - fw_type, fw_ver_maj, fw_ver_min - ) - - hw_ver_maj = libconcord.get_hw_ver_maj() - hw_ver_min = libconcord.get_hw_ver_min() - msg += "HW version %d.%d\n" % (hw_ver_maj, hw_ver_min) - - flash_mfg = libconcord.get_flash_mfg() - flash_id = libconcord.get_flash_id() - flash_part_num = libconcord.get_flash_part_num() - flash_size = libconcord.get_flash_size() - msg += "Flash Manufacturer:%d ID:%d Part:%s Size:%dK\n" % ( - flash_mfg, flash_id, flash_part_num, flash_size - ) - - hid_irl = libconcord.get_hid_irl() - hid_orl = libconcord.get_hid_orl() - hid_frl = libconcord.get_hid_frl() - msg += "USB HID Irl:%d Orl:%d Frl:%d\n" % (hid_irl, hid_orl, hid_frl) - - usb_vid = libconcord.get_usb_vid() - usb_pid = libconcord.get_usb_pid() - usb_bcd = libconcord.get_usb_bcd() - msg += "USB VID:%04x PID:%04x BCD:%04x\n" % (usb_vid, usb_pid, usb_bcd) - - config_bytes_used = libconcord.get_config_bytes_used() - config_bytes_total = libconcord.get_config_bytes_total() - config_pct_used = (config_bytes_used * 100) / config_bytes_total - msg += "Config used %d / total %d = %d%%\n" % ( - config_bytes_used, config_bytes_total, config_pct_used - ) - - fw_nondirect = libconcord.is_fw_update_supported(0) == 0 - fw_direct = libconcord.is_fw_update_supported(1) == 0 - if fw_nondirect or fw_direct: - config_safe = libconcord.is_config_safe_after_fw() == 0 - msg += "Firmware updates: Supported (%s), config%ssafe\n" % ( - fw_direct and "Direct" or "Not direct", - config_safe and " " or " NOT " - ) - else: - msg += "Firmware updates: NOT supported\n" - except: - msg = ( - "Error retrieving remote information:\n" + - exception_message() - ) - - show_modal_scrolled_msgbox(self.parent, "Remote Information", msg) - - def SetNext(self, next): - self.next = next - - def OnActivated(self): - thread.start_new_thread(self._WorkerFunction, ()) - - def OnCancel(self): - self.lock.acquire() - if self.finished: - self.lock.release() - self.parent.OnExit(1) - else: - self.cancelled = True - self.lock.release() - - def GetTitle(self): - return "Connecting" - - def IsTerminal(self): - return False - - def IsNextInitiallyDisabled(self): - return True - - def IsCancelInitiallyDisabled(self): - return False - - def GetNext(self): - return self.next - -class ProgramRemotePanelBase(wx.Panel, DecoratedContainerThreadMixin): - def __init__(self, parent, resources, file_type): - self.parent = parent - self.resources = resources - self.file_type = file_type - - wx.Panel.__init__(self, parent) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - - self.dc = DecoratedContainer(self, resources) - DecoratedContainerThreadMixin.__init__(self, self.dc) - self._AddWidgets() - self.sizer.Add(self.dc, 0, wx.ALIGN_LEFT | wx.ALL, 5) - - self.SetSizerAndFit(self.sizer) - - self.next = None - self.finished = False - - def _WorkerFunction(self): - try: - try: - self._WorkerFunctionBody() - wx.CallAfter(self._OnStatusOk) - return - except: - wx.CallAfter( - self._OnStatusFailure, - "Operation Failed", - exception_message() - ) - finally: - try: - if self.resources.connected: - self.resources.SetConnected(False) - libconcord.deinit_concord() - except: - pass - - def _OnStatusOk(self): - self.next = self.resources.page_success - self._OnStatusCommon() - - def _OnStatusFailure(self, failure_msg, details): - self.dc._DgFailure() - self.next = self.resources.page_failure - self.resources.page_failure.SetMessages( - failure_msg, - details - ) - self._OnStatusCommon() - - def _OnStatusCommon(self): - self.finished = True - self.parent.ReenableCancel() - self.parent.ReenableNext() - - def OnActivated(self): - thread.start_new_thread(self._WorkerFunction, ()) - - def OnCancel(self): - if self.finished: - self.parent.OnExit(1) - show_modal_scrolled_msgbox( - self.parent, - "Cannot Cancel", - "Cancel is disabled during programming operations, " + - "to prevent placing the remote into a state that will " + - "potentially be difficult to recover from." - ) - - def IsTerminal(self): - return False - - def IsNextInitiallyDisabled(self): - return True - - def IsCancelInitiallyDisabled(self): - return True - - def GetNext(self): - return self.next - -class CheckConnectivityPanel(ProgramRemotePanelBase): - def __init__(self, parent, resources): - ProgramRemotePanelBase.__init__( - self, - parent, - resources, - libconcord.LC_FILE_TYPE_CONNECTIVITY - ) - - def _AddWidgets(self): - vpos = counter() - self.dg_notify_website = DecoratedGauge(self.dc, "Notify Website", vpos.next()) - - def _WorkerFunctionBody(self): - self._DgUpdate( - False, - 0, - self.dg_notify_website - ) - libconcord.post_connect_test_success( - self.resources.xml, - self.resources.xml_size - ) - self._DgUpdate( - True, - 100, - self.dg_notify_website - ) - - def GetTitle(self): - return "Checking Connectivity" - -class WriteConfigurationPanel(ProgramRemotePanelBase): - def __init__(self, parent, resources): - ProgramRemotePanelBase.__init__( - self, - parent, - resources, - libconcord.LC_FILE_TYPE_CONFIGURATION - ) - - def _AddWidgets(self): - vpos = counter() - self.dg_check_website = DecoratedGauge(self.dc, "Check Website", vpos.next()) - self.dg_prepare = DecoratedGauge(self.dc, "Prepare Remote", vpos.next()) - self.dg_erase = DecoratedGauge(self.dc, "Erase Flash", vpos.next()) - self.dg_write = DecoratedGauge(self.dc, "Write Configuration", vpos.next()) - self.dg_verify = DecoratedGauge(self.dc, "Verify Upgrade", vpos.next()) - self.dg_reconnect = DecoratedGauge(self.dc, "Reconnect to Remote", vpos.next()) - self.dg_set_time = DecoratedGauge(self.dc, "Set Time", vpos.next()) - self.dg_notify_website = DecoratedGauge(self.dc, "Notify Website", vpos.next()) - - def _WorkerFunctionBody(self): - program_callback = libconcord.callback_type(program_callback_imp) - - self._DgStart(self.dg_check_website) - libconcord.post_preconfig(self.resources.xml, self.resources.xml_size) - self._DgEnd(self.dg_check_website) - - self._DgStart(self.dg_prepare) - bin_data = POINTER(c_ubyte)() - bin_size = c_uint() - libconcord.find_config_binary( - self.resources.xml, - self.resources.xml_size, - byref(bin_data), - byref(bin_size) - ) - self._DgUpdate(False, 50, self.dg_prepare) - libconcord.invalidate_flash() - self._DgEnd(self.dg_prepare) - - self._DgStart(self.dg_erase) - libconcord.erase_config( - bin_size, - program_callback, - py_object((self._DgUpdate, self.dg_erase)) - ) - self._DgEnd(self.dg_erase) - - self._DgStart(self.dg_write) - libconcord.write_config_to_remote( - bin_data, - bin_size, - program_callback, - py_object((self._DgUpdate, self.dg_write)) - ) - self._DgEnd(self.dg_write) - - self._DgStart(self.dg_verify) - libconcord.verify_remote_config( - bin_data, - bin_size, - program_callback, - py_object((self._DgUpdate, self.dg_verify)) - ) - self._DgEnd(self.dg_verify) - - self._DgStart(self.dg_reconnect) - libconcord.reset_remote() - worker_body_connect( - self.resources, - self._DgUpdate, - self.dg_reconnect, - lambda: False, - True - ) - - self._DgStart(self.dg_set_time) - libconcord.set_time() - self._DgEnd(self.dg_set_time) - - self._DgStart(self.dg_notify_website) - libconcord.post_postconfig(self.resources.xml, self.resources.xml_size) - self._DgEnd(self.dg_notify_website) - - def GetTitle(self): - return "Updating Configuration" - -class UpdateFirmwarePanel(ProgramRemotePanelBase): - def __init__(self, parent, resources): - ProgramRemotePanelBase.__init__( - self, - parent, - resources, - libconcord.LC_FILE_TYPE_FIRMWARE - ) - - def _AddWidgets(self): - vpos = counter() - self.dg_prepare = DecoratedGauge(self.dc, "Prepare Remote", vpos.next()) - self.dg_erase = DecoratedGauge(self.dc, "Erase Flash", vpos.next()) - self.dg_write = DecoratedGauge(self.dc, "Write Firmware", vpos.next()) - self.dg_finalize = DecoratedGauge(self.dc, "Finalize Programming", vpos.next()) - self.dg_reconnect = DecoratedGauge(self.dc, "Reconnect to Remote", vpos.next()) - self.dg_set_time = DecoratedGauge(self.dc, "Set Time", vpos.next()) - self.dg_notify_website = DecoratedGauge(self.dc, "Notify Website", vpos.next()) - - def _WorkerFunctionBody(self): - program_callback = libconcord.callback_type(program_callback_imp) - - self._DgStart(self.dg_prepare) - - # is_fw_update_supported returns error code; 0 OK, otherwise failure - if libconcord.is_fw_update_supported(0) == 0: - is_direct = False - elif libconcord.is_fw_update_supported(1) == 0: - is_direct = True - else: - raise Exception( - "Sorry, congruity doesn't yet support firmware update " + - "on this remote model." - ) - - self._DgUpdate(False, 25, self.dg_prepare) - - bin_data = POINTER(c_ubyte)() - bin_size = c_uint() - libconcord.extract_firmware_binary( - self.resources.xml, - self.resources.xml_size, - byref(bin_data), - byref(bin_size) - ) - - self._DgUpdate(False, 50, self.dg_prepare) - - if not is_direct: - libconcord.prep_firmware() - - self._DgUpdate(False, 75, self.dg_prepare) - - libconcord.invalidate_flash() - - self._DgEnd(self.dg_prepare) - - self._DgStart(self.dg_erase) - libconcord.erase_firmware( - is_direct, - program_callback, - py_object((self._DgUpdate, self.dg_erase)) - ) - self._DgEnd(self.dg_erase) - - self._DgStart(self.dg_write) - libconcord.write_firmware_to_remote( - bin_data, - bin_size, - c_int(is_direct and 1 or 0), - program_callback, - py_object((self._DgUpdate, self.dg_write)) - ) - self._DgEnd(self.dg_write) - - self._DgStart(self.dg_finalize) - if not is_direct: - libconcord.finish_firmware() - self._DgEnd(self.dg_finalize) - - self._DgStart(self.dg_reconnect) - libconcord.reset_remote() - worker_body_connect( - self.resources, - self._DgUpdate, - self.dg_reconnect, - lambda: False, - True - ) - - self._DgStart(self.dg_set_time) - libconcord.set_time() - self._DgEnd(self.dg_set_time) - - self._DgStart(self.dg_notify_website) - libconcord.post_postfirmware(self.resources.xml, self.resources.xml_size) - self._DgEnd(self.dg_notify_website) - - def GetTitle(self): - return "Updating Firmware" - -class SuccessPanel(MessagePanelBase): - def __init__(self, parent, resources): - MessagePanelBase.__init__( - self, - parent, - resources - ) - - def OnActivated(self): - self.text_message.UpdateText("Operation has completed successfully.") - - def OnCancel(self): - self.parent.OnExit(0) - - def GetTitle(self): - return "Success" - - def IsTerminal(self): - return True - - def GetExitCode(self): - return 0 - - def IsNextInitiallyDisabled(self): - return False - - def IsCancelInitiallyDisabled(self): - return True - -class FailurePanel(wx.Panel): - def __init__(self, parent, resources): - self.parent = parent - self.resources = resources - - wx.Panel.__init__(self, parent) - - self.sizer = wx.BoxSizer(wx.VERTICAL) - self.text_message = WrappedStaticText(self) - self.sizer.Add(self.text_message, 0, wx.ALIGN_LEFT | wx.ALL, 5) - self.btn_details = wx.Button(self, -1, "&Details...") - self.Bind(wx.EVT_BUTTON, self._OnDetails, self.btn_details) - self.sizer.Add(self.btn_details, 0, wx.ALIGN_LEFT | wx.ALL, 5) - self.SetSizerAndFit(self.sizer) - - self.message = "" - self.log_text = "" - - def _OnDetails(self, event): - show_modal_scrolled_msgbox(self.parent, "Error Log", self.log_text) - self.parent.ReenableNext() - - def SetMessages(self, message, traceback): - self.message = message - if traceback: - self.message += "\n\nSee below for details." - self.log_text = traceback - - def OnActivated(self): - if self.log_text: - self.btn_details.SetFocus() - else: - self.btn_details.Hide() - self.text_message.UpdateText(self.message) - - def OnCancel(self): - self.parent.OnExit(1) - - def GetTitle(self): - return "Failure" - - def IsTerminal(self): - return True - - def GetExitCode(self): - return 1 - - def IsNextInitiallyDisabled(self): - return False - - def IsCancelInitiallyDisabled(self): - return True - -class Wizard(wx.Dialog): - def __init__( - self, - resources, - app_finalizer, - min_page_width = 450, - min_page_height = None - ): - self.app_finalizer = app_finalizer - - self.min_page_width = min_page_width - self.min_page_height = min_page_height - - wx.Dialog.__init__(self, None, -1, 'Congruity version ' + version) - - sizer_main = wx.BoxSizer(wx.VERTICAL) - - sizer_top = wx.BoxSizer(wx.HORIZONTAL) - bitmap = wx.StaticBitmap(self, -1, resources.img_remote) - sizer_top.Add(bitmap, 0, wx.EXPAND | wx.ALL, 5) - - self.sizer_top_right = wx.BoxSizer(wx.VERTICAL) - self.title = wx.StaticText(self, -1, "Title") - font = wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD) - self.title.SetFont(font) - self.sizer_top_right.Add(self.title, 0, wx.EXPAND) - divider_top_right = wx.StaticLine(self, -1, None, None, wx.LI_HORIZONTAL) - self.sizer_top_right.Add(divider_top_right, 0, wx.EXPAND) - spacer = wx.StaticText(self, -1, "") - self.sizer_top_right.Add(spacer, 0, wx.EXPAND) - - sizer_top.Add(self.sizer_top_right, 1, wx.EXPAND | wx.ALL, 5) - sizer_main.Add(sizer_top, 1, wx.EXPAND | wx.ALL, 5) - - divider_main = wx.StaticLine(self, -1, None, None, wx.LI_HORIZONTAL) - sizer_main.Add(divider_main, 0, wx.EXPAND | wx.ALL, 5) - - sizer_buttons = wx.BoxSizer(wx.HORIZONTAL) - panel_btn_dummy = wx.Panel(self) - sizer_buttons.Add(panel_btn_dummy, 1, wx.EXPAND | wx.ALL, 5) - self.btn_next = wx.Button(self, -1, "&Next >") - self.Bind(wx.EVT_BUTTON, self._OnNext, self.btn_next) - sizer_buttons.Add(self.btn_next, 0, wx.EXPAND | wx.ALL, 5) - self.btn_cancel = wx.Button(self, -1, "&Cancel") - self.Bind(wx.EVT_BUTTON, self._OnCancel, self.btn_cancel) - self.Bind(wx.EVT_CLOSE, self._OnCancel) - sizer_buttons.Add(self.btn_cancel, 0, wx.EXPAND | wx.ALL, 5) - sizer_main.Add(sizer_buttons, 0, wx.EXPAND | wx.ALL, 5) - - self.SetSizerAndFit(sizer_main) - - self.cur_page = None - - def SetPages(self, pages): - def tuple_max(a, b): - return (max(a[0], b[0]), max(a[1], b[1])) - - self.pages = pages - - for page in self.pages: - page.Hide() - - size_wiz = self.GetSizeTuple() - for page in self.pages: - page.Show() - self.sizer_top_right.Add(page, 1, wx.EXPAND) - self.Fit() - size_page = self.GetSizeTuple() - size_wiz = tuple_max(size_wiz, size_page) - page.Hide() - self.sizer_top_right.Remove(page) - - if self.min_page_width and (size_wiz[0] < self.min_page_width): - size_wiz = (self.min_page_width, size_wiz[1]) - - if self.min_page_height and (size_wiz[1] < self.min_page_height): - size_wiz = (size_wiz[0], self.min_page_height ) - - self.SetSize(size_wiz) - - def SetInitialPage(self, page): - if self.cur_page: - raise Exception("Current page already set") - self._SetPage(page) - - def OnExit(self, retcode): - if self.app_finalizer: - self.app_finalizer() - os._exit(retcode) - - def _ReenableButton(self, button): - button.Enable(True) - button.Hide() - button.Show() - button.SetFocus() - - def ReenableNext(self): - self._ReenableButton(self.btn_next) - - def ReenableCancel(self): - self._ReenableButton(self.btn_cancel) - - def _OnNext(self, event): - if self.cur_page.IsTerminal(): - self.OnExit(self.cur_page.GetExitCode()) - next_page = self.cur_page.GetNext() - self._SetPage(next_page) - - def _OnCancel(self, event): - self.cur_page.OnCancel() - - def _SetPage(self, page): - if not page in self.pages: - raise Exception("Invalid page") - - if self.cur_page: - self.cur_page.Hide() - self.sizer_top_right.Remove(self.cur_page) - - self.cur_page = page - - self.cur_page.Show() - self.sizer_top_right.Add(self.cur_page, 1, wx.EXPAND) - - self.title.SetLabel(self.cur_page.GetTitle()) - - self.Layout() - - is_terminal = self.cur_page.IsTerminal() - if is_terminal: - self.btn_next.SetLabel("&Finish") - else: - self.btn_next.SetLabel("&Next >") - - self.btn_next.Enable(not self.cur_page.IsNextInitiallyDisabled()) - self.btn_cancel.Enable( - (not is_terminal) - and - (not self.cur_page.IsCancelInitiallyDisabled()) - ) - self.btn_next.SetFocus() - - self.cur_page.OnActivated() - -class Resources(object): - def __init__(self, appdir): - self.appdir = appdir - - self.ezhex_filename = None - self.xml = None - self.xml_size = None - self.connected = False - - def LoadImages(self): - def load(filename, appdir = self.appdir): - dirs = ['/usr/share/congruity', appdir, '.'] - for dir in dirs: - fpath = os.path.join(dir, filename) - if not os.path.isfile(fpath): - continue - return wx.Image(fpath, wx.BITMAP_TYPE_PNG).ConvertToBitmap() - raise Exception("Can't load " + filename) - - self.img_remote = load("remote.png") - self.icon_unstarted = load("icon-unstarted.png") - self.icon_in_progress = load("icon-in-progress.png") - self.icon_complete = load("icon-complete.png") - self.icon_failed = load("icon-failed.png") - - iw = max( - self.icon_in_progress.GetWidth(), - self.icon_complete.GetWidth(), - self.icon_failed.GetWidth() - ) - ih = max( - self.icon_in_progress.GetHeight(), - self.icon_complete.GetHeight(), - self.icon_failed.GetHeight() - ) - self.iwh = (iw, ih) - - def CreatePages(self, wizard): - self.page_welcome = WelcomePanel(wizard, self) - self.page_connect = ConnectPanel(wizard, self) - self.page_check_connectivity = CheckConnectivityPanel(wizard, self) - self.page_write_configuration = WriteConfigurationPanel(wizard, self) - self.page_update_firmware = UpdateFirmwarePanel(wizard, self) - self.page_success = SuccessPanel(wizard, self) - self.page_failure = FailurePanel(wizard, self) - - def SetEzHexFilename(self, ezhex_filename): - self.ezhex_filename = ezhex_filename - - def SetXmlData(self, xml, xml_size): - self.xml = xml - self.xml_size = xml_size - - def SetConnected(self, connected): - self.connected = connected - -class Finalizer(object): - def __init__(self, resources): - self.resources = resources - - def __call__(self): - if self.resources.xml: - try: - xml = self.resources.xml - self.resources.xml = None - self.resources.xml_size = None - libconcord.delete_blob(xml) - except: - pass - - if self.resources.connected: - try: - self.resources.SetConnected(False) - libconcord.deinit_concord() - except: - pass - -def main(argv): - app = argv.pop(0) - appdir = os.path.dirname(app) - - try: - while len(argv) and argv[0].startswith('-'): - arg = argv.pop(0) - if arg == '--version': - print version - return - ... [truncated message content] |
From: <srw...@us...> - 2009-03-10 02:17:42
|
Revision: 64 http://congruity.svn.sourceforge.net/congruity/?rev=64&view=rev Author: srwarren Date: 2009-03-10 02:17:18 +0000 (Tue, 10 Mar 2009) Log Message: ----------- Delete branches/congruity-10 Removed Paths: ------------- branches/congruity-10/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2009-03-10 02:17:39
|
Revision: 61 http://congruity.svn.sourceforge.net/congruity/?rev=61&view=rev Author: srwarren Date: 2009-03-10 02:13:33 +0000 (Tue, 10 Mar 2009) Log Message: ----------- Bump version for release Modified Paths: -------------- trunk/Changelog trunk/congruity Modified: trunk/Changelog =================================================================== --- trunk/Changelog 2009-02-23 00:13:08 UTC (rev 60) +++ trunk/Changelog 2009-03-10 02:13:33 UTC (rev 61) @@ -1,4 +1,5 @@ * 2009-xx-xx Stephen Warren <s-t...@ww...> +- congruity-10 is released - Implement IR learning feature, with support for learning from the original remote using the Harmony, or reading the signal from a "Pronto Hex" file. (Merge of /branches/irlean) Modified: trunk/congruity =================================================================== --- trunk/congruity 2009-02-23 00:13:08 UTC (rev 60) +++ trunk/congruity 2009-03-10 02:13:33 UTC (rev 61) @@ -27,7 +27,7 @@ import wx import wx.lib.dialogs -version = "9+" +version = "10" try: import libconcord This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2009-02-23 00:13:12
|
Revision: 60 http://congruity.svn.sourceforge.net/congruity/?rev=60&view=rev Author: srwarren Date: 2009-02-23 00:13:08 +0000 (Mon, 23 Feb 2009) Log Message: ----------- Add icon-sources.txt Added Paths: ----------- trunk/icon-sources.txt Added: trunk/icon-sources.txt =================================================================== --- trunk/icon-sources.txt (rev 0) +++ trunk/icon-sources.txt 2009-02-23 00:13:08 UTC (rev 60) @@ -0,0 +1,20 @@ +icon-failed.png + /usr/share/icons/gnome/32x32/emblems/emblem-important.png + gnome-icon-theme-2.22.0-6.fc9.noarch + GPL+ + +icon-complete.png + /usr/share/icons/gnome/48x48/emblems/emblem-certified.png + Resized and recolored + gnome-icon-theme-2.22.0-6.fc9.noarch + GPL+ + +icon-in-progress.png + /usr/share/f-spot/icons/hicolor/32x32/emblems/emblem-event.png + f-spot-0.4.3.1-1.fc9.i386 + GPL + +icon-unstarted.png + Part of congruity + GPLv3+ + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <srw...@us...> - 2009-02-23 00:02:02
|
Revision: 59 http://congruity.svn.sourceforge.net/congruity/?rev=59&view=rev Author: srwarren Date: 2009-02-23 00:01:57 +0000 (Mon, 23 Feb 2009) Log Message: ----------- Enhance README Modified Paths: -------------- trunk/Changelog trunk/README.txt Modified: trunk/Changelog =================================================================== --- trunk/Changelog 2009-02-08 00:12:57 UTC (rev 58) +++ trunk/Changelog 2009-02-23 00:01:57 UTC (rev 59) @@ -11,6 +11,7 @@ into the app during installation. - If libconcord import fails, display the entire backtrace information, to enable easier debugging of the issue. +- Enhance README * 2008-09-07 Stephen Warren <s-t...@ww...> - congruity-9 is released Modified: trunk/README.txt =================================================================== --- trunk/README.txt 2009-02-08 00:12:57 UTC (rev 58) +++ trunk/README.txt 2009-02-23 00:01:57 UTC (rev 59) @@ -1,20 +1,67 @@ -Requirements: +Requirements +============================================================================== Python (tested with 2.5.1 on Fedora 9) See http://www.python.org/ + Python ctypes library (included with Python 2.5, separate earlier) See http://sourceforge.net/projects/ctypes/ + wxPython (tested with wxGTK-2.8.7 on Fedora 9) See http://www.wxpython.org/ + libconcord (tested with post-0.20 CVS snapshot on Fedora 9) - See http: http://www.phildev.net/concordance/ + See http://www.phildev.net/concordance/ + Note that the python bindings are also required; see + libconcord/bindings/python -Installation/Usage: +Python, ctypes, and wxPython are typically installed using your distribution's +package management system. If this is not the case, installation instructions +should be located in the documentation accompanying those packages. -You may need to set up udev/similar rules so that the USB device nodes -used by the application are accessible without using root. I use -the following file: +libconcord may be available via your distribution's package management +system. If so, please ensure that you install any sub-packages required to +provide the libconcord Python bindings, e.g. both libconcord and +libconcord-python. +If installing libconcord from source, please follow the instructions +accompanying the source. Note that the Python bindings must be installed +separately; the bindings are found within the following sub-directory of the +libconcord source package: + + libconcord/bindings/python + +Some versions of libconcord provide a README.txt detailing the installation +process. Otherwise, the basic instructions are to run the following command as +root: + + python setup.py install + +Installation +============================================================================== + +congruity may be installed by running the following command: + + make install + +This command typically requires root access, since the default installation +location is /usr/local. + +Please read Makefile for details of variables that may be set to configure the +installation process, e.g.: + + make install DESTDIR=/tmp/pkgtmp PREFIX=/usr + +Device Node Access Setup +============================================================================== + +You may need to set up udev/similar rules so that the USB device nodes used +by the application are accessible without running congruity as root. Note that +distribution packages of libconcord typically provide these rules, so they may +already be set up for you. + +If you need to manually set up udev rules, the following file should work: + ----- /etc/udev/rules.d/custom-concordance.rules: SYSFS{idVendor}=="046d", SYSFS{idProduct}=="c110", MODE="666" ----- @@ -29,18 +76,72 @@ ----- Remember to differentiate between the Harmony remote and any other Logitech -peripherals you may have! +peripherals you may have! Note that not all Harmony-compatible remotes are +Logitech-branded in the USB listing. -Congruity relies on the libconcord library, which must be obtained and -installed separately. Note that you will need to install the Python bindings -for libconcord too; see libconcord/bindings/python/. +Usage Model +============================================================================== +congruity aims to fit into the usage model implemented by the official +Logitech software. The primary differentiation is that congruity is both +open-source and more cross-platform than the official software. + +Harmony remotes are configured using the Logitech website, based at the +following URL: + + http://members.harmonyremote.com/ + +Note that other URLs may be used for remotes that are not branded as +"Harmony". However, the overall process is identical. + +The website provides a database of devices, and a set of wizards to select +which of those are present in your setup. All decisions regarding how the +remote will be configured are made through this website. + +Please note that more recent versions of the Logitech software appear to be +an application that executes locally on the user's computer. However, they are +in fact a simple wrapping of a web-browser, simply hiding the web-based nature +of the configuration process. + +Once the configuration is complete, the website will push various file +downloads to the web browser. These files contain the information required to +program the user's configuration into the remote. For each file downloaded, +the congruity application should be executed to process the instructions in +that file. + +Web Browser Setup +============================================================================== + Configure your web browser to open files of type *.EZHex, *.EZUp, and *.EZTut -with the congruity application. This is typically set up using the dialog -box that appears when a file is about to be downloaded. +with the congruity application. -Note that in Firefox, you'll need to change a setting to see the download -action prompt; Otherwise, files will simply be saved to disk without you -being asked. Edit menu -> Preferences menu item -> Main tab -> Select -"Always ask me where to save files." +This is typically set up using the dialog box that appears when a file is +about to be downloaded. congruity should be executed once for each file +downloaded, and should be passed the name of the saved download as a command- +line parameter, for example: + congruity /tmp/Connectivity.EZHex + +If you're confused, the above behavior is most likely what your web browser +will do automatically when configured to open files using congruity. + +Firefox Specific Notes +============================================================================== + +You'll need to change a setting to see the download action prompt; Otherwise, +files will simply be saved to disk without you being asked. On Linux, this may +be achieved from the Edit menu -> Preferences menu item -> Main tab -> Select +"Always ask me where to save files". The exact menu location may vary slightly +on other operating systems. + +When a file download commences, a dialog will appear with the option to "Open +With", or "Save" the file. Select "Open With", and browse for the congruity +executable as the application. You may also want to select "Do this +automatically for files like this from now on". You will need to select the +path to the congruity application once for each file type (*.EZHex, *.EZUp, +*.EZTut). + +If the automatic option is not selected, the dialog will appear for every file +downloaded. Note that Firefox does remember the path to congruity for future +downloads, even though it is not displayed. + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |