Skip to content

Commit

Permalink
Added log expansion to the script: only log message IDs are stored in…
Browse files Browse the repository at this point in the history
… the Arduino to save PROGMEM space.

The header file that defines these log ID's also has the full strings, but these are commented out when compiling.
The script has a local copy of the LogMessage.h file and checks the local version against the version running on Arduino at startup.
Other small changes: removed unused fixJson(), changed some print statements into logMessage() statements
  • Loading branch information
elcojacobs committed Jun 11, 2013
1 parent 7e19f28 commit 1069e2a
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 54 deletions.
99 changes: 99 additions & 0 deletions LogMessages.h
@@ -0,0 +1,99 @@
/*
* Copyright 2012-2013 BrewPi/Elco Jacobs.
*
* This file is part of BrewPi.
*
* BrewPi 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.
*
* BrewPi 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 BrewPi. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

/* Overview of debug messages and ID's
A copy of this file is included with the python script, so it can parse it to extract the log strings.
The python script receives the messages as a few IDs and values in a JSON string.
It uses this file to expand that to the full message.
Not storing the full strings, but only the ID on the Arduino saves a lot of PROGMEM space.
At startup the python script extracts the version number from this file and compares it to its own local copy.
It will give a warning when the two strings do not match.
*/

/* bump this version number when changing this file and copy the new version to the brewpi-script repository. */
#define BREWPI_LOG_MESSAGES_VERSION 1

#define MSG(errorID, errorString, ...) errorID

// Errors
enum errorMessages{
// OneWireTempSensor.cpp
MSG(ERROR_SRAM_SENSOR, "Not enough SRAM for temp sensor %s", addressString),
MSG(ERROR_SENSOR_NO_ADDRESS_ON_PIN, "Cannot find address for sensor on pin %d", pinNr),
MSG(ERROR_OUT_OF_MEMORY_FOR_DEVICE, "*** OUT OF MEMORY for device f=%d", config.deviceFunction),

// DeviceManager.cpp
MSG(ERROR_DEVICE_DEFINITION_UPDATE_SPEC_INVALID, "Device defifination update specification is invalid"),
MSG(ERROR_INVALID_CHAMBER, "Invalid chamber id %d", config.chamber),
MSG(ERROR_INVALID_BEER, "Invalid beer id %d", config.beer),
MSG(ERROR_INVALID_DEVICE_FUNCTION, "Invalid device function id %d", config.deviceFunction),
MSG(ERROR_INVALID_DEVICE_CONFIG_OWNER, "Invalid config for device owner type %d beer=%d chamber=%d", owner, config.beer, config.chamber),
MSG(ERROR_CANNOT_ASSIGN_TO_HARDWARE, "Cannot assign device type %d to hardware %d", dt, config.deviceHardware),
MSG(ERROR_NOT_ONEWIRE_BUS, "Device is onewire but pin %d is not configured as a onewire bus", pinNr),

// PiLink.cpp
MSG(ERROR_EXPECTED_BRACKET, "Expected { got %c", character),

}; // END enum errorMessages

enum warningMessages{
// PiLink.cpp
MSG(WARNING_COULD_NOT_PROCESS_SETTING, "Could not process setting"),
MSG(WARNING_INVALID_COMMAND, "Invalid command received by Arduino: %c", character),

// OneWireTempSensor.cpp
MSG(WARNING_TEMP_SENSOR_DISCONNECTED, "Temperature sensor disconnected pin %d, address %s", pinNr, addressString),

// SettingsManager.cpp
MSG(WARNING_START_IN_SAFE_MODE, "EEPROM Settings not available. Starting in safe mode.")
}; // END enum warningMessages

// Info messages
enum infoMessages{
// OneWireTempSensor.cpp
MSG(INFO_TEMP_SENSOR_CONNECTED, "Temp sensor connected on pin %d, address %s", pinNr, addressString),
MSG(INFO_TEMP_SENSOR_DISCONNECTED, "Temp sensor disconnected on pin %d, address %s", pinNr, addressString),
MSG(INFO_TEMP_SENSOR_INITIALIZED, "Sensor initialized: pin %d %s %s", pinNr, addressString, temperature),

// DeviceManager.cpp
MSG(INFO_UNINSTALL_TEMP_SENSOR, "uninstalling temperature sensor with function %d", config.deviceFunction),
MSG(INFO_UNINSTALL_ACTUATOR, "uninstalling actuator with function %d", config.deviceFunction),
MSG(INFO_UNINSTALL_SWITCH_SENSOR, "uninstalling switch sensor with function %d", config.deviceFunction),
MSG(INFO_INSTALL_TEMP_SENSOR, "installing temperature sensor with function %d", config.deviceFunction),
MSG(INFO_INSTALL_ACTUATOR, "installing actuator with function %d", config.deviceFunction),
MSG(INFO_INSTALL_SWITCH_SENSOR, "installing switch sensor with function %d", config.deviceFunction),
MSG(INFO_INSTALL_DEVICE, "Installing device f=%d", config.deviceFunction),
MSG(INFO_MATCHING_DEVICE, "Matching device at slot %d", out.slot),
MSG(INFO_SETTING_ACTIVATOR_STATE, "Setting activator state %d", state),

// PiLink.cpp
MSG(INFO_RECEIVED_SETTING, "Received new setting: %s = %s", key, val),
MSG(INFO_DEFAULT_CONSTANTS_LOADED, "Default constants loaded."),
MSG(INFO_DEFAULT_SETTINGS_LOADED, "Default settings loaded."),
MSG(INFO_EEPROM_INITIALIZED, "EEPROM initialized"),
MSG(INFO_EEPROM_ZAPPED, "EEPROM zapped!"),

// Tempcontrol.cpp
MSG(INFO_POSITIVE_PEAK, "Positive peak detected: %s, estimated: %s. Previous heat estimator: %s, New heat estimator: %s.", temperature, temperature, estimator, estimator),
MSG(INFO_NEGATIVE_PEAK, "Negative peak detected: %s, estimated: %s. Previous cool estimator: %s, New cool estimator: %s.", temperature, temperature, estimator, estimator),
MSG(INFO_POSITIVE_DRIFT, "No peak detected. Drifting up after heating, current temp: %s, estimated peak: %s. Previous heat estimator: %s, New heat estimator: %s..", temperature, temperature, estimator, estimator),
MSG(INFO_NEGATIVE_DRIFT, "No peak detected. Drifting down after cooling, current temp: %s, estimated peak: %s. Previous cool estimator: %s, New cool estimator: %s..", temperature, temperature, estimator, estimator)
}; // END enum infoMessages
45 changes: 24 additions & 21 deletions brewpi.py
Expand Up @@ -32,6 +32,7 @@
import brewpiJson
from brewpiVersion import AvrInfo
import pinList
import expandLogMessage

# Settings will be read from Arduino, initialize with same defaults as Arduino
# This is mainly to show what's expected. Will all be overwritten on the first update from the arduino
Expand Down Expand Up @@ -147,22 +148,14 @@ def startBeer(beerName):
def logMessage(message):
print >> sys.stderr, time.strftime("%b %d %Y %H:%M:%S ") + message

def fixJson(j):
j = re.sub(r"{\s*?(\w)", r'{"\1', j)
j = re.sub(r",\s*?(\w)", r',"\1', j)
j = re.sub(r"(\w)?\s*:", r'\1":', j)
j = re.sub(r":\s*(\w*)\s*([,}])", r':"\1"\2', j)
return j


ser = 0
con = 0
# open serial port
try:
port = config['port']
ser = serial.Serial(port, 57600, timeout=2) # timeout=1 is too slow when waiting on temp sensor reads
except serial.SerialException, e:
print e
print >> sys.stderr, e
exit()

dumpSerial = config.get('dumpSerial', False)
Expand Down Expand Up @@ -190,18 +183,24 @@ def writeAndDump(data):
retries = 0
while 1: # read all lines on serial interface
line = ser.readline()
if(line): # line available?
if(line[0] == 'N'):
if line: # line available?
if line[0] == 'N':
data = line.strip('\n')[2:]
avrVersion = AvrInfo(data)
brewpiVersion = avrVersion.version
print "Found Arduino " + avrVersion.board + \
" with a " + avrVersion.shield + " shield, " + \
"running BrewPi version " + brewpiVersion
if(brewpiVersion != compatibleBrewpiVersion):
logMessage( "Found Arduino " + avrVersion.board +
" with a " + avrVersion.shield + " shield, " +
"running BrewPi version " + brewpiVersion +
" build " + str(avrVersion.build))
if brewpiVersion != compatibleBrewpiVersion:
logMessage("Warning: BrewPi version compatible with this script is " +
compatibleBrewpiVersion +
" but version number received is " + brewpiVersion)
if int(avrVersion.log) != int(expandLogMessage.getVersion()):
logMessage("Warning: version number of local copy of logMessages.h " +
"does not match log version number received from Arduino." +
"Arduino version = " + str(avrVersion.log) +
", local copy version = " + str(expandLogMessage.getVersion()))
break
else:
ser.write('n')
Expand All @@ -212,7 +211,7 @@ def writeAndDump(data):
"Your Arduino is either not programmed or running a very old version of BrewPi. " +
"Please upload a new version of BrewPi to your Arduino.")
# script will continue so you can at least program the Arduino
break;
break

ser.flush()
# request settings from Arduino, processed later when reply is received
Expand All @@ -227,7 +226,7 @@ def addSlash(path):

#create a listening socket to communicate with PHP
is_windows = sys.platform.startswith('win')
useInetSocket = bool(config.get('useInetSocket', is_windows));
useInetSocket = bool(config.get('useInetSocket', is_windows))
if (useInetSocket):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Expand Down Expand Up @@ -539,7 +538,11 @@ def renameTempKey(key):
prevDataTime = time.time()
elif line[0] == 'D':
# debug message received
logMessage("Arduino debug message: " + line[2:])
try:
expandedMessage = expandLogMessage.expandLogMessage(line[2:])
except Exception, e: # catch all exceptions, because out of date file could cause errors
logMessage("Error while expanding log message: " + e)
logMessage("Arduino debug message: " + expandedMessage)
elif line[0] == 'L':
# lcd content received
lcdTextReplaced = line[2:].replace('\xb0', '&deg') # replace degree sign with &deg
Expand All @@ -562,14 +565,14 @@ def renameTempKey(key):
deviceList['available'] = json.loads(line[2:])
oldListState = deviceList['listState']
deviceList['listState'] = oldListState.strip('h') + "h"
print "Available devices received: " + str(deviceList['available'])
logMessage("Available devices received: " + str(deviceList['available']))
elif line[0] == 'd':
deviceList['installed'] = json.loads(line[2:])
oldListState = deviceList['listState']
deviceList['listState'] = oldListState.strip('d') + "d"
print "Installed devices received: " + str(deviceList['installed'])
logMessage("Installed devices received: " + str(deviceList['installed']))
elif line[0] == 'U':
print "Device updated to: " + line[2:]
logMessage("Device updated to: " + line[2:])
else:
logMessage("Cannot process line from Arduino: " + line)
# end or processing a line
Expand Down
8 changes: 8 additions & 0 deletions brewpiVersion.py
Expand Up @@ -6,9 +6,11 @@
class AvrInfo:
""" Parses and stores the version and other compile-time details reported by the Arduino """
version = "v"
build = "n"
simulator = "y"
board = "b"
shield = "s"
log = "l"

shield_revA = "revA"
shield_revC = "revC"
Expand All @@ -26,9 +28,11 @@ def __init__(self, s = None):
self.minor = 0
self.revision = 0
self.version = None
self.build = None
self.simulator = False
self.board = None
self.shield = None
self.log = None
self.parse(s)


Expand All @@ -52,6 +56,10 @@ def parseJsonVersion(self, s):
self.board = AvrInfo.boards.get(j[AvrInfo.board])
if AvrInfo.shield in j:
self.shield = AvrInfo.shields.get(j[AvrInfo.shield])
if AvrInfo.log in j:
self.log = j[AvrInfo.log]
if AvrInfo.build in j:
self.build = j[AvrInfo.build]

def parseStringVersion(self, s):
s = s.strip()
Expand Down
64 changes: 31 additions & 33 deletions expandLogMessage.py
Expand Up @@ -18,49 +18,45 @@
import simplejson as json
import parseEnum

logMessagesFile = '../brewpi-avr/brewpi_avr/logMessages.h'
logMessagesFile = 'logMessages.h'

errorDict = parseEnum.parseEnumInFile(logMessagesFile, 'errorMessages')
infoDict = parseEnum.parseEnumInFile(logMessagesFile, 'infoMessages')
warningDict = parseEnum.parseEnumInFile(logMessagesFile, 'warningMessages')

def valToFunction(val):
if val == 0:
return 'None'
elif val == 1:
return 'Chamber Door'
elif val == 2:
return 'Chamber Heater'
elif val == 3:
return 'Chamber Cooler'
elif val == 4:
return 'Chamber Light'
elif val == 5:
return 'Chamber Temp'
elif val == 6:
return 'Room Temp'
elif val == 7:
return 'Chamber Fan'
elif val == 8:
return 'Chamber Reserved 1'
elif val == 9:
return 'Beer Temp'
elif val == 10:
return 'Beer Temperature 2'
elif val == 11:
return 'Beer Heater'
elif val == 12:
return 'Beer Cooler'
elif val == 13:
return 'Beer S.G.'
elif val == 14:
return 'Beer Reserved 1'
elif val == 15:
return 'Beer Reserved 2'
functions = ['None', # 0
'Chamber Door', # 1
'Chamber Heater', # 2
'Chamber Cooler', # 3
'Chamber Light', # 4
'Chamber Temp', # 5
'Room Temp', # 6
'Chamber Fan', # 7
'Chamber Reserved 1', # 8
'Beer Temp', # 9
'Beer Temperature 2', # 10
'Beer Heater', # 11
'Beer Cooler', # 12
'Beer S.G.', # 13
'Beer Reserved 1', #14
'Beer Reserved 2'] #15
if val < len(functions):
return functions[val]
else:
return 'Unknown Device Function'


def getVersion():
hFile = open(logMessagesFile)
for line in hFile:
if 'BREWPI_LOG_MESSAGES_VERSION ' in line:
splitLine = line.split('BREWPI_LOG_MESSAGES_VERSION')
return int(splitLine[1]) # return version number
print "ERROR: could not find version number in log messages header file"
return 0


def expandLogMessage(logMessageJsonString):
expanded = ""
logMessageJson = json.loads(logMessageJsonString)
Expand Down Expand Up @@ -107,3 +103,5 @@ def expandLogMessage(logMessageJsonString):
expanded += logTypeString + " with unknown ID " + str(logId)

return expanded

getVersion()

0 comments on commit 1069e2a

Please sign in to comment.