Skip to content

Commit

Permalink
Merge pull request #87 from PropGit/WiFi
Browse files Browse the repository at this point in the history
Adding PropLoader (instead of Propeller-Load)
  • Loading branch information
PropGit authored Apr 4, 2017
2 parents c0d9c6a + 58eb2fc commit 15b3fe0
Show file tree
Hide file tree
Showing 11 changed files with 172 additions and 77 deletions.
2 changes: 1 addition & 1 deletion BlocklyPropClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
# Please verify that the version number in the local about.txt and the
# ./package/win-resources/blocklypropclient-installer.iss matches this.
# -----------------------------------------------------------------------
VERSION = "0.5.4"
VERSION = "0.6.2"


# Enable logging for functions outside of the class definition
Expand Down
2 changes: 1 addition & 1 deletion BlocklyServer.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def load(self, action, binary, extension, comport=None):

self.logger.debug('Loading program to device.')

(success, out, err) = self.propellerLoad.load(action, binary_file, comport)
(success, out, err) = self.propellerLoad.download(action, binary_file, comport)
self.queue.put((10, 'INFO', 'Application loaded (%s)' % action))

self.logger.info('Application load complete.')
Expand Down
241 changes: 168 additions & 73 deletions PropellerLoad.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,121 +12,216 @@

class PropellerLoad:
loading = False
# COM & WiFi-Name ports list
ports = []
# Full WiFi ports list
wports = []


def __init__(self):

self.logger = logging.getLogger('blockly.loader')
self.logger.info('Creating loader logger.')

# Find the path from which application was launched
# realpath expands to full path if __file__ or sys.argv[0] contains just a filename
self.appdir = os.path.dirname(os.path.realpath(__file__))
self.appdir = os.path.dirname(os.path.realpath(__file__))
if self.appdir == "" or self.appdir == "/":
# launch path is blank; try extracting from argv
# launch path is blank; try extracting from argv
self.appdir = os.path.dirname(os.path.realpath(sys.argv[0]))
self.logger.debug("PropellerLoad.py: Application running from: %s", self.appdir)
self.logger.debug("Application running from: %s", self.appdir)

self.propeller_load_executables = {
"Windows": "/propeller-tools/windows/propeller-load.exe",
"Linux": "/propeller-tools/linux/propeller-load",
"MacOS": "/propeller-tools/mac/propeller-load",
"Darwin": "/propeller-tools/mac/propeller-load"
self.loaderExe = {
"Windows": "/propeller-tools/windows/proploader.exe",
"Linux": "/propeller-tools/linux/proploader",
"MacOS": "/propeller-tools/mac/proploader",
"Darwin": "/propeller-tools/mac/proploader"
}

self.load_actions = {
"RAM": {"compile-options": []},
"EEPROM": {"compile-options": ["-e"]}
self.loaderAction = {
"RAM": {"compile-options": ""},
"EEPROM": {"compile-options": "-e"}
}

if not platform.system() in self.propeller_load_executables:
if not platform.system() in self.loaderExe:
self.logger.error('The %s platform is not supported at this time.', platform.system())
print("Unsupported", platform.system() + " is currently unsupported")
print(platform.system() + " is currently unsupported")
exit(1)


def get_ports(self):
self.logger.info('Getting ports')
# Find COM/Wi-Fi serial ports
self.logger.info('Received port list request')

# Return last results if we're currently downloading
if self.loading:
return self.ports

self.logger.info("Generating ports list")

# Get COM ports
(success, out, err) = loader(self, ["-P"])
if success:
self.ports = out.splitlines()
else:
self.logger.debug('COM Port request returned %s', err)

# Get Wi-Fi ports
(success, out, err) = loader(self, ["-W"])
if success:
# Save Wi-Fi port record(s)
self.wports = out.splitlines()
# Extract Wi-Fi module names (from Wi-Fi records) and sort them
wnames = []
for i in range(len(self.wports)):
wnames.extend([getWiFiName(self.wports[i])])
wnames.sort(None, None, False)
else:
self.logger.debug('WiFi Port request returned %s', err)

# Append Wi-Fi ports to COM ports list
self.ports.extend(wnames)
self.logger.debug('Found %s ports', len(self.ports))

return self.ports


def download(self, action, file_to_load, com_port):
# Download application to Propeller
# Set loading flag to prevent interruption
self.loading = True

try:
# Patch - see if __init__ is back in full operation
if not self.appdir or self.appdir == "" or self.appdir == "/":
self.logger.info('ERROR: LOADER FOLDER NOT FOUND!')
return False, ' ', ' '
# Patch below removed temporarily during platform testing
# # Patch until we figure out why the __init__ is not getting called
# if not self.appdir or self.appdir == "" or self.appdir == "/":
# # realpath expands to full path if __file__ or sys.argv[0] contains just a filename
# self.appdir = os.path.dirname(os.path.realpath(__file__))
# if self.appdir == "" or self.appdir == "/":
# # launch path is blank; try extracting from argv
# self.appdir = os.path.dirname(os.path.realpath(sys.argv[0]))

# Set command download to RAM or EEPROM and to run afterward download
command = []
if self.loaderAction[action]["compile-options"] != "":
# if RAM/EEPROM compile-option not empty, add it to the list
command.extend([self.loaderAction[action]["compile-options"]])
command.extend(["-r"])

# Add requested port
if com_port is not None:
# Find port(s) named com_port
targetWiFi = [l for l in self.wports if isWiFiName(l, com_port)]
if len(targetWiFi) > 0:
# Found Wi-Fi match
self.logger.debug('Requested port %s is at %s', com_port, getWiFiIP(targetWiFi[0]))
command.extend(["-i"])
command.extend([getWiFiIP(targetWiFi[0]).encode('ascii', 'ignore')])
else:
# Not Wi-Fi match, should be COM port
self.logger.debug('Requested port is %s', com_port)
command.extend(["-p"])
command.extend([com_port.encode('ascii', 'ignore')])

# Add target file
command.extend([file_to_load.name.encode('ascii', 'ignore').replace('\\', '/')])

# Download
(success, out, err) = loader(self, command)

# Return results
return success, out or '', err or ''

finally:
# Done, clear loading flag to process other events
self.loading = False


def loader(self, cmdOptions):
# Launch Propeller Loader with cmdOptions and return True/False, output and error string
# cmdOptions must be a list
try:
# Form complete command line as a list: [path+exe, option {,more_options...} {, filename}]
cmdLine = [self.appdir + self.loaderExe[platform.system()]]
cmdLine.extend(cmdOptions)

self.logger.debug('Running loader command: %s', cmdLine)

# Run command
if platform.system() == "Windows":
self.logger.info("Enumerating Windows ports")
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
process = subprocess.Popen(cmdLine, stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo)
else:
process = subprocess.Popen(cmdLine, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

process = subprocess.Popen([self.appdir + self.propeller_load_executables[platform.system()], "-P"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo)
out, err = process.communicate()
self.logger.debug('Loader complete: Error code %s returned.', err)
self.ports = out.splitlines()
return self.ports
out, err = process.communicate()

# If error, log extra error detail
if process.returncode:
self.logger.error("Error result: %s - %s", process.returncode, err)
self.logger.debug("Loader response: %s", out)

if process.returncode == 0:
success = True
else:
self.logger.info("Enumerating host ports")
success = False

ports = [port for (port, driver, usb) in list_ports.comports()]
self.logger.debug('Port count: %s', len(ports))
return success, out or '', err or ''

self.ports = ports
return ports
except OSError as ex:
# Exception; log error and return fail status
self.logger.error("%s", ex.message)
return False, '', 'Exception: OSError'

def load(self, action, file_to_load, com_port):
self.loading = True

# Patch until we figure out why the __init__ is not getting called
if not self.appdir or self.appdir == '':
# realpath expands to full path if __file__ or sys.argv[0] contains just a filename
self.appdir = os.path.dirname(os.path.realpath(__file__))
if self.appdir == "" or self.appdir == "/":
# launch path is blank; try extracting from argv
self.appdir = os.path.dirname(os.path.realpath(sys.argv[0]))

executable = self.appdir + self.propeller_load_executables[platform.system()]
self.logger.debug('Loader executable path is: %s)', executable)

executing_data = [executable, "-r"]
executing_data.extend(self.load_actions[action]["compile-options"])
self.logger.debug('Loader commandline is: %s', executing_data)

if com_port is not None:
self.logger.info("Talking to com port.")
executing_data.append("-p")
executing_data.append(com_port.encode('ascii', 'ignore'))

executing_data.append(file_to_load.name.encode('ascii', 'ignore').replace('\\', '/'))

print(executing_data)
self.logger.info("Executing process %s", executing_data)
def isWiFiName(string, wifiName):
# Return True if string contains Wi-Fi Module record named wifiName
return getWiFiName(string) == wifiName

try:
if platform.system() == "Windows":
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW

process = subprocess.Popen(executing_data, stdout=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=startupinfo)
else:
process = subprocess.Popen(executing_data, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def getWiFiName(string):
# Return Wi-Fi Module Name from string, or None if not found
return strBetween(string, "Name: '", "', IP: ")

out, err = process.communicate()
self.logger.info("Load result is: %s", process.returncode)
self.logger.debug("Load error string: %s", err)
self.logger.debug("Load output string: %s", out)

if process.returncode == 0:
success = True
else:
success = False
def getWiFiIP(string):
# Return Wi-Fi Module IP address from string, or None if not found
return strBetween(string, "', IP: ", ", MAC: ")


def getWiFiMAC(string):
# Return Wi-Fi Module MAC address from string, or None if not found
return strAfter(string, ", MAC: ")

self.loading = False
return success, out or '', err or ''

except OSError as ex:
self.logger.error("%s", ex.message)
def strBetween(string, startStr, endStr):
# Return substring from string in between startStr and endStr, or None if no match
# Find startStr
sPos = string.find(startStr)
if sPos == -1: return None
sPos += len(startStr)
# Find endStr
ePos = string.find(endStr, sPos)
if ePos == -1: return None
# Return middle
return string[sPos:ePos]


def resource_path(relative):
return os.path.join(
os.environ.get(
"_MEIPASS2",
os.path.abspath(".")
),
relative
)
def strAfter(string, startStr):
# Return substring from string after startStr, or None if no match
# Find startStr
sPos = string.find(startStr)
if sPos == -1: return None
sPos += len(startStr)
# Return string after
return string[sPos:-1]
2 changes: 1 addition & 1 deletion about.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Version: v0.5.4
Version: v0.6.2

Contributors:
- Michel Lampo
Expand Down
2 changes: 1 addition & 1 deletion package/blocklypropclient-installer.iss
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "BlocklyPropClient"
#define MyAppVersion "0.5.4"
#define MyAppVersion "0.6.2"
#define MyAppPublisher "Parallax Inc."
#define MyAppURL "http://blockly.parallax.com/"
#define MyAppExeName "BlocklyPropClient.exe"
Expand Down
Binary file removed propeller-tools/linux/propeller-load
Binary file not shown.
Binary file added propeller-tools/linux/proploader
Binary file not shown.
Binary file removed propeller-tools/mac/propeller-load
Binary file not shown.
Binary file added propeller-tools/mac/proploader
Binary file not shown.
Binary file removed propeller-tools/windows/propeller-load.exe
Binary file not shown.
Binary file added propeller-tools/windows/proploader.exe
Binary file not shown.

0 comments on commit 15b3fe0

Please sign in to comment.