Screen borders are changing all over.

I have a Python script running that displays basic info from Amarok (song title, time elapsed, time left, and a progress bar). When I run my script, everything works as it should, except almost randomly the side edge of the LCD shifts and text that would normally be showing up on the right side is now showing up one pixel lower on the left side. Before I modified my script to start its own instance of g15composer, I just had g15composer run as I started and stopped my scripts. When I did restart my scripts, the side-shifts stayed, so I figure this is a bug with g15composer and/or libg15render. I haven't taken the time to check the source code for these two (I will when I finish typing here), so I can't point anywhere in particular.

Just as a note (I'm not sure of the importance of this), text that disappears off the bottom does reappear at the top.

I have the version of libg15render and g15composer that were released on New Year's day installed.

Edit1: One piece that is text isn't showing up after looping back to the top from the bottom, but two other text areas are (the times) as is the progress bar.

Edit2: Immediately after posting Edit1, it seems as though the text reappears after some time (perhaps after the text resumes its original, intended, location).

Edit3: I outputted the data that I was sending g15composer to a different output so I could make sure my script wasn't screwing up somehow, and it appears to be g15composer/libg15render that are causing the issues. Either that or my method of implementing g15composer is incorrect (Though I'm not sure how?).

Re: Screen borders are changing all over.

It would appear so. Thanks again!

Re: Screen borders are changing all over.

Just wanting to check that the problem is definitely resolved now?

Re: Screen borders are changing all over.

aw, shucks. You're very kind. :oops:

If the problem doesn't re-occur within the next 24hours, I'll package up a new release of g15daemon (1.9.5.3) that includes this patch. Thanks for your patience, and for reporting this bug.

Mike

Re: Screen borders are changing all over.

I was having problems installing g15composer after patching (I'm new to patch as well as Linux in general, so it could be me), but I patched g15daemon, and so far so good! No odd movement!

One last thing,
You're amazing.

Re: Screen borders are changing all over.

Quote:
I would assume this means that g15composer is sending the M-key data followed by the screen data until the 6880 buffer is reached, and then putting the leftover screen data in the next buffer?

This appears to be the case, but it shouldn't be possible.

g15composer uses a combination of g15daemon_client calls and send(). In particular, the M key commands uses send(). The two functions may be interacting badly. The attached patch moves the last remaining send() calls to the g15daemon_client equivalents.

I'll look closer at the g15daemon net plugin. It should be picking the commands out of the data stream without affecting image buffers, but it would appear to be failing in that regard if this patch doesn't help. Other clients using the Mkey etc cmds obviously have a different usage pattern that hide this bug, if that is what is occurring.

[Update] I've also attached a patch for g15daemon-1.9.5.2/plugins/ that may have some positive affects. Please test.

Re: Screen borders are changing all over.

I commented everything except for the necessities and the M-keys and the problem persisted. I went back and commented out the M-key stuff and the screen isn't going wacko anymore. I would assume this means that g15composer is sending the M-key data followed by the screen data until the 6880 buffer is reached, and then putting the leftover screen data in the next buffer?

Re: Screen borders are changing all over.

Quote:
The clock plugin and my modified version of it don't do this.

ok, sorry for misunderstanding.

Quote:
I haven't counted the shift amount, but it definitely appears to be by a constant amount which I'm going to guess is 7 or 8.

At a guess, I would say 8, which is 1 byte. That narrows the search down a bit, thanks.

Quote:
I'm running the g15amarok-daemon.pl script as you suggested, and so far I do not see the issue I'm experiencing with my Python script. I noticed the Perl script updates every 5 seconds compared to my script which updates every second.

The timing should not matter, but if you want to be doubly sure you could edit line 86 of that script.

Does removing any non-vital commands from your script change the behaviour? In particular, does removing the 'KM' command have a positive effect?

Re: Screen borders are changing all over.

The clock plugin and my modified version of it don't do this. This thing is just when I'm running the Python script, which is why I believe the problem is in g15composer or g15render. I haven't counted the shift amount, but it definitely appears to be by a constant amount which I'm going to guess is 7 or 8. I'm running the g15amarok-daemon.pl script as you suggested, and so far I do not see the issue I'm experiencing with my Python script. I noticed the Perl script updates every 5 seconds compared to my script which updates every second.

Re: Screen borders are changing all over.

I've never seen this :-/ You mention that your modified g15daemon clock plugin (and I presume the original) does this too? That would point away from a synchronisation problem between g15composer<->g15daemon, and toward libg15render perhaps. A possible way to test this would be for you to run g15amarok-daemon.pl http://www.aaue.dk/~janoc/files/software/linux/g15amarok-daemon.pl which uses libGD for rendering and talks directly to g15daemon via the perl bindings available in g15daemon/lang-bindings/perl-G15Daemon-0.2.tar.gz. The perl module Inline::C will need to be grabbed from cpan. If the corruption still occurs, that would point to some function causing the corruption in g15daemon itself ...

Does the display appear to move horizontally in set increments, say, 8pixels or so, or is it a random placement?

Re: Screen borders are changing all over.

Your forums aren't allowing .pbm files to be uploaded. :) But here you are.

[attachment=0]g15daemon-sc-0.gif[/attachment]

Re: Screen borders are changing all over.

When the problem occurs again, would you mind pressing M1+M3 for a second and posting the resultant image to me? it will be something like /tmp/g15daemon-sc-0.pbm.

Re: Screen borders are changing all over.

I had 1.9.4 installed (for g15daemon), and updated to 1.9.5.2.
I'm running Kubuntu 7.10 with libusb-0.1-4_0.1.12-7_amd64.deb as the package file for libusb.

After updating g15daemon, I still had no luck.

Re: Screen borders are changing all over.

What version of g15daemon are you running ?
Exactly what distro, and what libusb package do you have on your system ie debian libusb-0.1.12-7.i386. ?

Re: Screen borders are changing all over.

Sadly, yes.

Re: Screen borders are changing all over.

Two questions:

- Does this still occur with G15Composer 3.2?
- What version of G15Daemon are you running?

Re: Screen borders are changing all over.

You'll have to pardon anything...wrong style-wise as well as anything unnecessarily defined, but here's the code. I plan on changing the style to something that reacts to Amarok's messages as opposed to constantly polling it for the information. Obviously I've also added in the buffer control. Thanks for the hint. After testing that, the moving appeared to be less common, but it was still there.

# LCD is 160x43 resolution</p>
<p>#The following is a list of the max widths of the screen in characters.<br />
maxWidths = ( 40,<br />
	32,<br />
	26,<br />
	)</p>
<p>import thread<br />
import os<br />
import time<br />
import sys</p>
<p>import tempfile<br />
import random</p>
<p>from dcopext import DCOPClient , DCOPApp<br />
import signal<br />
def cleanup( signum , frame ):<br />
	#Change this to something a little more useful.<br />
	output( 'Script was terminated.' , 0 )<br />
	d.close()<br />
	amarok.script.removeCustomMenuItem( scriptName , actionName )<br />
signal.signal( signal.SIGTERM , cleanup )</p>
<p>def r( number , precision ):<br />
	number_string = repr( number )<br />
	decimal_pos = number_string.index( "." )<br />
	number_string_cut = fstr[ : decimal_pos + 1 + precision ]<br />
	return number_string_cut</p>
<p>def sec_parse( seconds ):<br />
	seconds_left = seconds % 60<br />
	minutes = ( seconds - seconds_left ) / 60<br />
	time_string = ""<br />
	if minutes < 10: time_string += "0"<br />
	time_string += repr( minutes ) + ":"<br />
	if seconds_left < 10: time_string += "0"<br />
	time_string += repr( seconds_left )<br />
	return time_string</p>
<p>def output( string , style = 0 ):<br />
	#This function is for debugging purposes.  If you want to communicate with another program, use a pipe or a socket<br />
	if style == 1:<br />
		try: f = open( "/tmp/AmarokG15_error_log.log" , 'a' ) # Temporary debugging log--remove/change during debug purge<br />
		except: pass<br />
		f.write( string +  "\n" )<br />
		f.close()<br />
	else:<br />
		print string</p>
<p>def stdin_handle():<br />
	for line in sys.stdin:<br />
		if line == "configure":<br />
			thread.start_new_thread( do_config , () )</p>
<p>		else:<br />
			f = open("/tmp/AmarokG15_std_log.log",'a')<br />
			f.write( line + '\n' )<br />
			f.close()</p>
<p>def do_config():<br />
	# Configuration screen<br />
	pass</p>
<p>def text_scroll( text , sz , i ):<br />
	if sz not in ( 0 , 1 , 2 ): output( "sz not in (0,1,2) in text_scroll_list( text, sz )" , 1 ); return 0</p>
<p>	w = maxWidths[ sz ]<br />
	if i + w >= len( text ):<br />
		# past the end, start from the beginning</p>
<p>		ani = text[i - len( text ):] + text[:i - len( text ) + w]<br />
	else:<br />
		#No need for looping around<br />
		ani = text[ i : i + w ]</p>
<p>	return ani</p>
<p>class Disp( object ):<br />
	def __init__( self ):<br />
		self.__temp_dir = tempfile.mkdtemp()<br />
		self.__pipe_location = self.__temp_dir + "/g15comp0"</p>
<p> 		os.mkfifo( self.__pipe_location )</p>
<p>		os.system( "g15composer \"%s\" &" % ( self.__pipe_location ) )</p>
<p>		self.__f = open( self.__pipe_location , 'w' )<br />
		self.pos_text( "\"Loading...\"" , 80 , 19 , 2 , 1 )<br />
		self.__load()</p>
<p>	def __load( self ):<br />
		# Clear the screen, set the M keys etc.<br />
		self.clear()</p>
<p>		self.m_conf = [ 0 , 0 , 0 ]<br />
		self.set_m( 0 , 0 )</p>
<p>	def close( self ):<br />
		self.set_m( 0 , 0 )</p>
<p>		self.clear()<br />
		self.__f.write( "SC\n" )<br />
		self.__f.flush()</p>
<p>		self.__f.close()</p>
<p>		os.system( "rm -Rd " + self.__temp_dir )</p>
<p>	#Add all of the various functions here.<br />
	def write_bufs( self ):<br />
		self.__f.write( "MC 0\n" )<br />
		self.__f.write( "MC 1\n" )<br />
	def show_text( self , text , sz ):<br />
		self.__f.write( "T" + ( "S" , "M" , "L" )[ sz ] + " " + text + "\n" )<br />
		self.__f.flush()<br />
	def pos_text( self , text , x , y , sz , align ):<br />
		self.__f.write( "TO %s %s %s %s %s\n" % ( x , y , sz , align , text) )<br />
		self.__f.flush()<br />
	def set_m( self , num , state ):<br />
		if num in ( 0 , 1 , 2 , 3 ):<br />
			self.__f.write( "KM " + repr( num ) + " " + repr( state ) + "\n" )<br />
			self.__f.flush()<br />
			if num == 0:<br />
				self.m_conf[ 0 ] = state<br />
				self.m_conf[ 1 ] = state<br />
				self.m_conf[ 2 ] = state<br />
			else:<br />
				self.m_conf[ num - 1 ] = state<br />
			return 0<br />
		else:<br />
			output( "num (" + repr( num ) + ") not in legal range [0-3]" , 1 )<br />
			return 1<br />
	def draw_prog_bar( self , ( x1 , y1 ) ,( x2 , y2 ) , perc ):<br />
		self.__f.write( "DB %s %s %s %s 1 %s 100 1\n" % ( x1 , y1 , x2 , y2 , int( perc ) ) )<br />
		self.__f.flush()<br />
	def clear( self ):<br />
		self.__f.write( "PC 0\n" )</p>
<p>def main():<br />
	thread.start_new_thread( stdin_handle , () )</p>
<p>	global d<br />
	d = Disp()</p>
<p>	# aniIDict is the dictionary with a list of counters that update at the end of a loop.  Everything starts at 0.<br />
	#	You only need stuff here if your max (see aniMaxDict) is greater than 0, in which case you NEED to put things here for proper scrolling.<br />
	aniIDict = { "artist-title" : 0 ,<br />
	}<br />
	# aniMaxDict is the dictionary with a list of maxes for the counters in aniIDict.<br />
	#	the max is the len(str) - maxWidths[char_size] or 0, whichever is greater.  You don't need this if your max is 0 or less.<br />
	#	Also, don't be afraid to set these dynamically.<br />
	aniMaxDict = { "artist-title" : 1 ,<br />
	}</p>
<p>#<br />
#---Here starts where stuff can be removed for a template------------------------------------------------------------------------------------------------------<br />
#</p>
<p>	#Get the DCOP stuff started.<br />
	client = DCOPClient()<br />
	client.attach()</p>
<p>	amarok = DCOPApp( 'amarok' , client )</p>
<p>#<br />
#---Here ends where stuff can be removed for a template--------------------------------------------------------------------------------------------------------<br />
#</p>
<p>	while 1:<br />
		# This is the primary loop.<br />
		d.clear()</p>
<p>		#<br />
		#It would definitely be less CPU intensive to use a reactive style, as opposed to an always-reading style<br />
		#</p>
<p>		#This section gets a percentage of the song that has been played and displays it on the LCD.<br />
		ok1 , timeSoFar = amarok.player.trackCurrentTime()<br />
		ok2 , timeTotal = amarok.player.trackTotalTime()</p>
<p>		timeSoFar , timeTotal = float( timeSoFar ) , float( timeTotal )</p>
<p>		if not ( ok1 and ok2 ):<br />
			output( "Error getting track times" , 1 )<br />
			perc = 0<br />
			timeSoFar = 0<br />
			timeTotal = 0<br />
		else:<br />
			try: perc = timeSoFar / timeTotal * 100<br />
			except( ZeroDivisionError ): perc = 0<br />
			if perc > 100:<br />
				perc = 100.0<br />
		d.pos_text( "\"%s\"" % ( sec_parse( int( timeSoFar ) ) , ) , 0 , 37 , 0 , 0 )<br />
		d.draw_prog_bar( ( 20 , 39 ) , ( 134 , 39 ) , perc )<br />
		d.pos_text( "\"-%s\"" % ( sec_parse( int( timeTotal - timeSoFar ) ) , ) , 136 , 37 , 0 , 0 )</p>
<p>		#This section gets the artist and title of the current song and displays them on the LCD<br />
		ok1,title = amarok.player.title()<br />
		ok2,artist = amarok.player.artist()</p>
<p>		if not ok1:<br />
			output( "Error getting track title" , 1 )<br />
			title = ""<br />
		if not ok2:<br />
			output( "Error getting track artist" , 1 )<br />
			artist = ""<br />
		artist_title = "%s - %s" % ( artist.title() , title.title() )<br />
		if artist_title == " - ": artist_title = " - "<br />
		if len( artist_title ) > maxWidths[ 1 ]:<br />
			#animate<br />
			artist_title += " - " #So the looping looks good<br />
			aniMaxDict[ "artist-title" ] = len( artist_title )<br />
			artist_title_string = text_scroll( artist_title , 1 , aniIDict[ "artist-title" ] )<br />
		else:<br />
			artist_title_string = artist_title<br />
			aniMaxDict[ "artist-title" ] = 1<br />
		d.pos_text( "\"%s\"" % ( artist_title_string , ) , 80 , 26 , 1 , 1 )</p>
<p>        	# Update the dictionaries used for text scrolling (and other animations, eventually)<br />
        	for x in aniIDict.keys():<br />
				aniIDict[ x ]  = ( aniIDict[ x ] + 1 ) % ( aniMaxDict[ x ] )</p>
<p>		d.write_bufs()<br />
		time.sleep( 1 )</p>
<p>	#Closing up.<br />
	d.close()</p>
<p>if __name__ == "__main__":<br />
	try:<br />
		main()<br />
	except( KeyboardInterrupt ):<br />
		try: d.close() #Shut display down if it's up.<br />
		except: pass<br />
	except(), e:<br />
		try: d.close()<br />
		except: pass<br />
		output( "Something uncaught happened!\n" + e , 1 )<br />

Edit: I've decided to take advantage of the L-buttons for controlling Amarok, and because I can't do that with a Python script (I didn't explore the area too far, however), I've decided to modify the clock plugin to suit my needs. Since this (the text arbitrarily moving) is still an issue, I've kept my old Python script and will continue to check this thread for updates.

Re: Screen borders are changing all over.

Sure, looking at your code might help. Are you using 'MC' to cache commands to g15composer? That will let you send a series of display updates and have the final result rendered once rather than rendering each intermediate step. If you do that, it shouldn't matter when you send the rendering commands to g15composer, the contents of the canvas will only be sent to g15daemon when you send 'MC 0'.

Re: Screen borders are changing all over.

No reproducable methods other than just giving you my Python code and having you wait for it to happen, but I'm guessing you can do that yourself already. If you want my source code, I'll be glad to upload. I just checked after you mentioned the high system load, and I'm experiencing the change-age with a processor usage of about .8%. Top could just be reporting the processor usage as I have my script sleep (using time.sleep()), and there could be a large usage percentage in the short bursts that g15render goes in as it renders my stuff. I will try flushing the write buffers after I have all my output ready so that g15composer, etc. can all work at one time, as opposed to having g15composer start new g15renders after each flush. If it's a synchronization issue, that should help, right?

Re: Screen borders are changing all over.

This is something I've seen myself as well and have had trouble tracking down. It seems to happen when system load is high and so I'm thinking it might be a synchronization problem between g15composer and g15daemon. I could be wrong though. If you could provide reproduceable methods for triggering this symptom, I'll take another look at it.