(see also message:
[patch 0/2] Change of libconcord API for IR codes learning - Build 20080628)

Patch installation:
===================
This patch should be applied to libconcord CVS release 0.20.
Install via:
  cd <wherever>/libconcord
  patch -p1 < libconcord-IRLearn-20080628.patch

TODO:
=====
While I managed to adapt the python bindings on my own, I would appreciate
any support to adapt the PERL bindings as well.
Any volunteers for testing on a Macintosh?

Detailed comments on changes:
=============================

Index: libconcord.h
===================================================================
+ * IR-stuff
-int learn_ir_commands(uint8_t *data, uint32_t size, int post);
+int get_key_names(uint8_t *data, uint32_t size,
+       char ***key_names, uint32_t *key_names_length);
+void delete_key_names(char **key_names, uint32_t key_names_length);
+int learn_from_remote(uint32_t *carrier_clock,
+       uint32_t **ir_signal, uint32_t *ir_signal_length);
+void delete_ir_signal(uint32_t *ir_signal);
+int encode_for_posting(uint32_t carrier_clock,
+       uint32_t *ir_signal, uint32_t ir_signal_length,
+       char **encoded_signal);
+void delete_encoded_signal(char *encoded_signal);
+int post_new_code(uint8_t *data, uint32_t size, 
+       char *key_name, char *encoded_signal);
...
> redesign of IR learning API, see message [patch 0/2]...)

Index: libconcord.cpp
===================================================================
-#include <string.h>
+#include <string>
> fixed VC++ warning about deprecated include

-                       int u = 32;
+                       uint32_t u = 32;
> fixed VC++ warning about comparing int to unsigned values
> this is always unsigned anyway
 
-int learn_ir_commands(uint8_t *data, uint32_t size, int post)
...
> redesign of IR learning API, see libconcord.h

Index: remote.h
===================================================================
-#define MAX_PULSE_COUNT 1000
+#define MAX_IR_SIGNAL_LENGTH 1000
 
> replaced 'pulse' by 'ir_signal',  following Stephen's objection: 
> pulse = mark+space, so allocated array would actually hold only 500 
> pulses (=1000 mark/space durations). 

-       virtual int LearnIR(string *learn_string=NULL)=0;
+       virtual int LearnIR(uint32_t *freq, uint32_t **ir_signal, 
+               uint32_t *ir_signal_length)=0;

> adapted to libconcord API change: return binary data instead of
> encoded string 
 
-               lc_callback cb=0, void *cb_arg=NULL);
+               lc_callback cb=NULL, void *cb_arg=NULL);

> make clear that default for callback is _NULL pointer_

Index: remote.cpp
===================================================================
-int handle_ir_response(uint8_t rsp[64], unsigned int &ir_word,
-       unsigned int &t_on, unsigned int &t_off, unsigned int &pulse_count,
-       unsigned int *&pulses, unsigned int &freq)
+int _handle_ir_response(uint8_t rsp[64], uint32_t &ir_word,
+       uint32_t &t_on, uint32_t &t_off, uint32_t &ir_signal_length,
+       uint32_t *&ir_signal, uint32_t &freq)

> 'unsigned int' replaced by 'uint32_t' for consistency

+       if ((len & 1) != 0) {
+               return 3;       // Invalid length
+       }

> immediate return for bad length, saves one level of indent in the following
> (already deep indented) code; some linebreaks changed.

-       const static uint8_t start_ir_learn[] = { COMMAND_START_IRCAP };
+       static const uint8_t start_ir_learn[] = { COMMAND_START_IRCAP };
+       static const uint8_t stop_ir_learn[] = { COMMAND_STOP_IRCAP };
+

> swapping 'const' and 'static' made kdevelop LSE happy (marked as error)

-                       err = 1;
+                       err = LC_ERROR;

> use constant LC_ERROR

Index: web.h
===================================================================
+int encode_ir_signal(uint32_t carrier_clock, 
+       uint32_t *ir_signal, uint32_t ir_signal_length,
+       string *learn_seq);

> adapted to libconcord API change: provide encoding of binary data to
> posting format 

Index: web.cpp
===================================================================
-                       if (search - data >= data_size) {
+                       if (search >= data + data_size) {

> fixed VC++ warning about comparing signed and unsigned - for the compiler,
> in theory (search - data) might become negative...

Index: bindings/python/libconcord.py
===================================================================
> adapted to libconcord API change

+# void delete_blob(uint8_t *ptr);
+ delete_blob = _create_func(

> fixed return type (int -> void) and typo (delete_block -> _blob)

Index: win/libconcord.def
===================================================================
> adapted to libconcord API change


Index: libconcord/libconcord.cpp
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/libconcord.cpp,v
retrieving revision 1.35
diff -u -3 -p -u -p -r1.35 libconcord.cpp
--- libconcord/libconcord.cpp	14 Apr 2008 07:27:58 -0000	1.35
+++ libconcord/libconcord.cpp	28 Jun 2008 12:45:25 -0000
@@ -27,7 +27,7 @@
  */
 
 #include <stdio.h>
-#include <string.h>
+#include <string>
 #include <stdlib.h>
 #include "libconcord.h"
 #include "lc_internal.h"
@@ -39,6 +39,7 @@
 #include "protocol.h"
 #include "time.h"
 #include <errno.h>
+#include <list>
 
 #define ZWAVE_HID_PID_MIN 0xC112
 #define ZWAVE_HID_PID_MAX 0xC115
@@ -1170,7 +1171,7 @@ int write_firmware_to_file(uint8_t *in, 
 		do {
 			of.write("\t\t\t<DATA>");
 			char hex[16];
-			int u = 32;
+			uint32_t u = 32;
 			if (u > size) {
 				u = size;
 			}
@@ -1224,41 +1225,196 @@ int extract_firmware_binary(uint8_t *xml
  * IR stuff
  */
 
-int learn_ir_commands(uint8_t *data, uint32_t size, int post)
+/*
+ * List of key names to be learned is passed in section INPUTPARMS
+ * as e.g.:
+ * <PARAMETER><KEY>KeyName</KEY><VALUE>PowerToggle</VALUE></PARAMETER>
+ * First of these is repeated in section PARAMETERS, so we must
+ * concentrate on INPUTPARMS to avoid duplication.
+ */
+
+/*
+ * locate the INPUTPARMS section in *data:
+ */
+int _init_key_scan(uint8_t *data, uint32_t size, 
+	uint8_t **inputparams_start, uint8_t **inputparams_end)
 {
 	int err;
-
-	if (data) {
-		uint8_t *t = data;
-		string keyname;
-		do {
-			err = GetTag("KEY", t, size - (t - data), t, &keyname);
-			if (err != 0) {
-				return err;
-			}
-		} while (keyname != "KeyName");
-		uint8_t *n = 0;
-		err = GetTag("VALUE", t, size, n, &keyname);
+		
+	/* locating start tag "<INPUTPARMS>" */
+	err = GetTag("INPUTPARMS", data, size, *inputparams_start);
+	if (err == 0) {
+		/* locating end tag "</INPUTPARMS>" */
+		err = GetTag("/INPUTPARMS", *inputparams_start, 
+			size - (*inputparams_start-data), *inputparams_end);
+	}
+	return err;
+}
+	
+int _next_key_name(uint8_t **start, uint8_t *inputparams_end, string *keyname)
+{
+	int err;
+	/*
+	* to be really paranoid, we would have to narrow the search range
+	* further down to next <PARAMETER>...</PARAMETER>, but IMHO it
+	 * should be safe to assume that Logitech always sends sane files:
+	*/
+	do {
+		err = GetTag("KEY", *start, (inputparams_end - *start),
+			     *start, keyname);
 		if (err != 0) {
 			return err;
 		}
-		printf("Key Name: %s\n",keyname.c_str());
+	} while (*keyname != "KeyName");
 
-		string ls;
-		rmt->LearnIR(&ls);
-		debug("Learned code: %s",ls.c_str());
-
-		if (post) {
-			Post(data, size, "POSTOPTIONS", ri, true, false, &ls,
-				&keyname);
-		}
-	} else {
-		rmt->LearnIR();
+	err = GetTag("VALUE", *start, (inputparams_end - *start),
+		     *start, keyname);
+
+	if (err == 0) {
+		/* found next key name : */
+		debug("Key Name: %s\n", (*keyname).c_str());
 	}
+	return err;
+}
+
 
+int get_key_names(uint8_t *data, uint32_t size,
+	char ***key_names, uint32_t *key_names_length)
+{
+	uint8_t *cursor = data;
+	uint8_t *inputparams_end;
+	uint32_t key_index = 0;
+	std::list<string> key_list;
+	string key_name;
+	
+	if ((data == NULL) || (size == 0) || 
+		(key_names == NULL)  || (key_names_length == NULL)) {
+		return LC_ERROR;
+	}
+	/* setup data scanning, locating start and end of keynames section: */
+	if (_init_key_scan(data, size, &cursor, &inputparams_end) != 0) {
+		return LC_ERROR;
+	}
+	
+	/* scan for key names and append found names to list: */
+	while (_next_key_name(&cursor, inputparams_end, &key_name) == 0) {
+		key_list.push_back(key_name);
+	}
+	
+	if (key_list.size() == 0) {
+		return LC_ERROR;
+	}
+	
+	*key_names_length = key_list.size();
+	*key_names = new char*[*key_names_length];
+			
+	/* copy list of found names to allocated buffer: */
+	for (list<string>::const_iterator cursor = key_list.begin();
+		cursor != key_list.end(); ++cursor) {
+		(*key_names)[key_index++] = strdup((*cursor).c_str());
+	}
 	return 0;
+	/* C++ should take care of key_name and key_list */
+}
+
+/*
+ * Free memory allocated by get_key_names:
+ */
+void delete_key_names(char **key_names, uint32_t key_names_length)
+{
+	uint32_t key_count = 0;
+	if (key_names != NULL) {
+		for (key_count = 0; key_count < key_names_length; key_count++) {
+			free(key_names[key_count]);
+			/* allocated by strdup -> free() */
+		}
+		delete[](key_names); /* allocated by new[] -> delete[] */
+	}
+}
+
+/*
+ * Fill ir_data with IR code learned from other remote
+ * via Harmony IR receiver.
+ * Returns 0 for success, error code for failure.
+ */
+int learn_from_remote(uint32_t *carrier_clock,
+	uint32_t **ir_signal, uint32_t *ir_signal_length)
+{
+	if (rmt == NULL){
+		return LC_ERROR_CONNECT;
+	}
+	if ((carrier_clock == NULL) || 
+		(ir_signal == NULL) || (ir_signal_length == NULL)){
+		/* nothing to write to: */
+		return LC_ERROR;
+	}
+	
+	/* try to learn code via Harmony from original remote: */
+	return rmt->LearnIR(carrier_clock, ir_signal, ir_signal_length);
+}
+
+/*
+ * Free memory allocated by learn_from_remote:
+ */
+void delete_ir_signal(uint32_t *ir_signal)
+{
+	delete [] ir_signal;  /* allocated by new[] -> delete[] */
+}
+
+/*
+ * Fill encoded_signal with IR code encoded to Logitech
+ * posting string format.
+ * Returns 0 for success, error code in case of failure.
+ */
+int encode_for_posting(uint32_t carrier_clock,
+	uint32_t *ir_signal, uint32_t ir_signal_length,
+	char **encoded_signal)
+{
+	int err = 0;
+	string encoded;
+	if ((ir_signal == NULL) || (ir_signal_length == 0) ||
+		(encoded_signal == NULL)) {
+		return LC_ERROR;	/* cannot do anything without */
+	}
+	err = encode_ir_signal(carrier_clock, 
+		ir_signal, ir_signal_length, &encoded);
+	if (err == 0) {
+		debug("Learned code: %s",encoded.c_str());
+		*encoded_signal = strdup(encoded.c_str());
+	}
+	return err;
 }
 
+/*
+ * Free memory allocated by encode_for_posting:
+ */
+void delete_encoded_signal(char *encoded_signal)
+{
+	free(encoded_signal); /* allocated by strdup -> free() */
+}
+
+/*
+ * Post encoded IR-code with key_name and additional 
+ * information from XML data[size] to Logitech.
+ * Returns 0 for success, error code for failure.
+ */
+int post_new_code(uint8_t *data, uint32_t size, 
+	char *key_name, char *encoded_signal)
+{
+	string learn_key;
+	string learn_seq;
+
+	if ((key_name == NULL) || (encoded_signal == NULL) ||
+		(data == NULL) || (size == 0)) {
+		return LC_ERROR_POST;	/* cannot do anything without */
+	}
+	
+	learn_key = key_name;
+	learn_seq = encoded_signal;
+	
+	return Post(data, size, "POSTOPTIONS", ri, true, false,
+		&learn_seq, &learn_key);
+}
 
 /*
  * PRIVATE-SHARED INTERNAL FUNCTIONS
Index: libconcord/libconcord.h
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/libconcord.h,v
retrieving revision 1.19
diff -u -3 -p -u -p -r1.19 libconcord.h
--- libconcord/libconcord.h	11 Apr 2008 05:05:26 -0000	1.19
+++ libconcord/libconcord.h	28 Jun 2008 12:45:25 -0000
@@ -382,10 +382,85 @@ int extract_firmware_binary(uint8_t *xml
 	uint32_t *size);
 
 /*
- * IR-stuff. This stuff hasn't yet been cleaned up, you'll have to
- * dig in yourself.
+ * IR-stuff
+ * ===========================
+ * Data structure information:
+ *
+ * carrier_clock    : in Hz, usually ~36000..40000
+ * ir_signal        : IR mark/space durations (alternating) in microsconds
+ * ir_signal_length : total number of mark/space durations in ir_signal
+ *      ir_signal will start with a mark and end with a space duration,
+ *      hence ir_signal_length will always be an even number.
+ * 
+ * They are usually filled in by calling learn_from_remote(...),
+ * to learn IR signals from an existing other remote, but may also
+ * be set by the application, e.g. be derived from Pilips Pronto Hex
+ * codes or RC5/NEC/... command codes (separate conversion library required).
+ *
+ * encoded posting format : IR code data converted to Logitech 
+ *     posting string format, returned by encode_for_posting.
+ *     Having the encoding separate from the posting keeps the
+ *     parameter list of post_new_code() tidy and allows the
+ *     application to display the encoded signal when desired.
  */
-int learn_ir_commands(uint8_t *data, uint32_t size, int post);
+
+/*
+ * Scan the contents of the received LearnIR.EZTut file
+ * (read into *data[size]) for the key names to be learned.
+ *
+ * Fills key_names with the found names and key_names_length
+ * with the number of found key names.
+ * Returns 0 for success, or an error code in case of failure.
+ *
+ * Memory allocated for the strings must be freed by the caller
+ * via delete_key_names() when not needed any longer.
+ */
+int get_key_names(uint8_t *data, uint32_t size,
+	char ***key_names, uint32_t *key_names_length);
+
+void delete_key_names(char **key_names, uint32_t key_names_length);
+
+/*
+ * Fill ir_data with IR code learned from other remote
+ * via Harmony IR receiver.
+ *
+ * Returns 0 for success, error code for failure.
+ *
+ * Memory allocated for ir_signal must be freed by the caller
+ * via delete_ir_signal() when not needed any longer.
+ */
+int learn_from_remote(uint32_t *carrier_clock,
+	uint32_t **ir_signal, uint32_t *ir_signal_length);
+
+void delete_ir_signal(uint32_t *ir_signal);
+
+/*
+ * Fill encoded_signal with IR code encoded to Logitech
+ * posting string format.
+ *
+ * Returns 0 for success, error code in case of failure.
+ *
+ * Memory allocated for the string must be freed by the caller
+ * via delete_post_string() when not needed any longer.
+ */
+int encode_for_posting(uint32_t carrier_clock,
+	uint32_t *ir_signal, uint32_t ir_signal_length,
+	char **encoded_signal);
+
+void delete_encoded_signal(char *encoded_signal);
+
+/*
+ * Post encoded IR-code with key_name and additional 
+ * information from XML data[size] to Logitech.
+ *
+ * Logitech will only accept keynames already present in the
+ * database or user-defined via 'Learn new Key' web page
+ * for the current device.
+ *
+ * Returns 0 for success, error code for failure.
+ */
+int post_new_code(uint8_t *data, uint32_t size, 
+	char *key_name, char *encoded_signal);
 
 #ifdef __cplusplus
 }
Index: libconcord/remote.cpp
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/remote.cpp,v
retrieving revision 1.34
diff -u -3 -p -u -p -r1.34 remote.cpp
--- libconcord/remote.cpp	14 Apr 2008 08:07:07 -0000	1.34
+++ libconcord/remote.cpp	28 Jun 2008 12:45:25 -0000
@@ -643,124 +643,116 @@ bool check_seq(int received_seq, uint8_t
 	}
 }
 
-int handle_ir_response(uint8_t rsp[64], unsigned int &ir_word,
-	unsigned int &t_on, unsigned int &t_off, unsigned int &pulse_count,
-	unsigned int *&pulses, unsigned int &freq)
+int _handle_ir_response(uint8_t rsp[64], uint32_t &ir_word,
+	uint32_t &t_on, uint32_t &t_off, uint32_t &ir_signal_length,
+	uint32_t *&ir_signal, uint32_t &freq)
 {
-	const unsigned int len = rsp[63];
-	if ((len & 1) == 0) {
-		for (unsigned int u = 2; u < len; u += 2) {
-			const unsigned int t = rsp[u] << 8 | rsp[1+u];
-			if (ir_word > 2) {
-				/*
-				 * For ODD words, t is the total time, we'll
-				 * update the total OFF time and be done.
-				 *
-				 * For EVEN words, t is just the ON time
-				 * -- IF we have any ON time, then we go ahead
-				 * and record the off and on times we should
-				 * have now gathered.
-				 *
-				 * Why do we differentiate between even/odd?
-				 * Perhaps just to make sure we've had two
-				 * cycles, and thus have off/on?
-				 */
-				if (ir_word & 1) {
-					// t == on + off time
-					if (t_on)
-						t_off = t-t_on;
-					else
-						t_off += t;
+	const uint32_t len = rsp[63];
+	if ((len & 1) != 0) {
+		return 3;	// Invalid length
+	}
+
+	for (uint32_t u = 2; u < len; u += 2) {
+		const uint32_t t = rsp[u] << 8 | rsp[1+u];
+		if (ir_word > 2) {
+			/*
+			 * For ODD words, t is the total time, we'll
+			 * update the total OFF time and be done.
+			 *
+			 * For EVEN words, t is just the ON time
+			 * -- IF we have any ON time, then we go ahead and record the 
+			 *    off and on times we should have now gathered.
+			 *
+			 * Why do we differentiate between even/odd?
+			 * Perhaps just to make sure we've had two
+			 * cycles, and thus have off/on?
+			*/
+			if (ir_word & 1) {
+				// t == on + off time
+				if (t_on) {
+					t_off = t-t_on;
 				} else {
-					// t == on time
-					t_on = t;
-					if (t_on) {
-						debug("-%i\n", t_off);
-						if (pulse_count <
-								MAX_PULSE_COUNT)
-							pulses[pulse_count++] =
-								t_off;
-						debug("+%i\n", t_on);
-						if (pulse_count <
-								MAX_PULSE_COUNT)
-							pulses[pulse_count++] =
-								t_on;
-					}
+					t_off += t;
 				}
 			} else {
-				/*
-				 * For the first 3 words...
-				 *    the first one, we ignore, apparently
-				 *    the second one, we start keeping track
-				 *      of ON time
-				 *    the third one, we have enough data to
-				 *    	calculate the frequency and record
-				 *    	the on time we've calculated
-				 */
-				switch (ir_word) {
-					case 0:
-						// ???
-						break;
-					case 1:
-						// on time of
-						// first burst
-						t_on = t;
-						break;
-					case 2:
-						// pulse count of
-						// first burst
-						if (t_on) {
-							freq = static_cast<unsigned int>(static_cast<uint64_t>(t)*1000000/t_on);
-							debug("%i Hz",freq);
-							debug("+%i",t_on);
-							pulses[pulse_count++] =
-								t_on;
-						}
-						break;
+				// t == on time
+				t_on = t;
+				if (t_on) {
+					debug("-%i\n", t_off);
+					if (ir_signal_length < MAX_IR_SIGNAL_LENGTH) {
+						ir_signal[ir_signal_length++] = t_off;
+					}
+					debug("+%i\n", t_on);
+					if (ir_signal_length < MAX_IR_SIGNAL_LENGTH) {
+						ir_signal[ir_signal_length++] = t_on;
+					}
 				}
 			}
-			++ir_word;
+		} else {
+			/*
+			 * For the first 3 words...
+			 *    the first one, we ignore, apparently
+			 *    the second one, we start keeping track of ON time
+			 *    the third one, we have enough data to calculate the 
+			 *      frequency and record the on time we've calculated
+			 */
+			switch (ir_word) {
+				case 0:		// ???
+					break;
+				case 1:		// on time of first burst
+					t_on = t;
+					break;
+				case 2:		// carrier cycle count of first burst
+					if (t_on) {
+						freq = static_cast<uint32_t>(
+							static_cast<uint64_t>(t)*1000000/(t_on));
+						debug("%i Hz",freq);
+						debug("+%i",t_on);
+						ir_signal[ir_signal_length++] = t_on;
+					}
+					break;
+			}
 		}
-	} else {
-		// Invalid length
-		return 3;
+		++ir_word;
 	}
 	return 0;
 }
 
-int CRemote::LearnIR(string *learn_string)
+
+int CRemote::LearnIR(uint32_t *freq, uint32_t **ir_signal, uint32_t *ir_signal_length)
 {
 	int err = 0;
 	uint8_t rsp[68];
 
-	const static uint8_t start_ir_learn[] = { COMMAND_START_IRCAP };
-	if ((err = HID_WriteReport(start_ir_learn)))
-		return err;
+	static const uint8_t start_ir_learn[] = { COMMAND_START_IRCAP };
+	static const uint8_t stop_ir_learn[] = { COMMAND_STOP_IRCAP };
+
+	err = HID_WriteReport(start_ir_learn);
+	if (err != 0) { return err; }
 
 	uint8_t seq = 0;
 	// Count of how man IR words we've received.
-	unsigned int ir_word = 0;
+	uint32_t ir_word = 0;
 	// Time button is on and off
-	unsigned int t_on = 0;
-	unsigned int t_off = 0;
-
-	// Frequency button emits
-	unsigned int freq = 0;
-	// Pulse map
-	unsigned int *pulses = new unsigned int[MAX_PULSE_COUNT];
-	unsigned int pulse_count = 0;
+	uint32_t t_on = 0;
+	uint32_t t_off = 0;
 
+	*ir_signal_length = 0;
+	*ir_signal = new uint32_t[MAX_IR_SIGNAL_LENGTH];
 	/*
+	 * Caller is responsible for deallocation of *ir_signal after use.
+	 *
 	 * Loop while we have no error and we haven't had 500,000us of
-	 * any pulses
+	 * any ir_signal
 	 */
 	while (err == 0 && t_off < 500000) {
-		if ((err = HID_ReadReport(rsp, ir_word ? 500 : 4000)))
+		if ((err = HID_ReadReport(rsp, ir_word ? 500 : 4000))) {
 			break;
+		}
 		const uint8_t r = rsp[0] & COMMAND_MASK;
 		if (r == RESPONSE_IRCAP_DATA) {
 			if (!check_seq(rsp[1], seq)) {
-				err = 1;
+				err = LC_ERROR;
 				break;
  			}
 			seq += 0x10;
@@ -769,8 +761,8 @@ int CRemote::LearnIR(string *learn_strin
 			 * t_off so we can exit the loop if long enough time
 			 * goes by without action.
 			 */
-			err = handle_ir_response(rsp, ir_word, t_on, t_off,
-				pulse_count, pulses, freq);
+			err = _handle_ir_response(rsp, ir_word, t_on, t_off,
+				*ir_signal_length, *ir_signal, *freq);
 			if (err != 0) {
 				break;
 			}
@@ -778,42 +770,29 @@ int CRemote::LearnIR(string *learn_strin
 			break;
 		} else {
 			debug("Invalid response [%02X]", rsp[1]);
-			err = 1;
+			err = LC_ERROR;
 		}
 	}
 
-	if (t_off)
-		debug("-%i", t_off);
-
-	/* make sure we record a final off? */
-	if (pulse_count < MAX_PULSE_COUNT)
-		pulses[pulse_count++] = t_off;
+	if ((err == 0) && (*ir_signal_length > 0)) {
+		/* we have actually got some signal */
+		if (t_off) {
+			debug("-%i", t_off);
+		}
+		/* make sure we record a final off */
+		if (*ir_signal_length < MAX_IR_SIGNAL_LENGTH) {
+			(*ir_signal)[(*ir_signal_length)++] = t_off;
+		}
+	}
 
-	const static uint8_t stop_ir_learn[] = { COMMAND_STOP_IRCAP };
 	HID_WriteReport(stop_ir_learn);
 
 	/* read returned RESPONSE_DONE, otherwise next command wil fail! */
-	err = HID_ReadReport(rsp);
-	if (err == 0) {
+	if (HID_ReadReport(rsp) == 0) {
 		if ((rsp[0] & COMMAND_MASK) != RESPONSE_DONE) {
-			err = 1;
+			err = LC_ERROR;
 		}
 	}
 
-	/*
-	 * Encode our pulses into string
-	 */
-	if (err == 0 && learn_string != NULL) {
-		char s[32];
-		sprintf(s, "F%04X", freq);
-		*learn_string = s;
-		for (unsigned int n = 0; n < pulse_count; ) {
-			sprintf(s, "P%04X", pulses[n++]);
-			*learn_string += s;
-			sprintf(s, "S%04X", pulses[n++]);
-			*learn_string += s;
-		}
-	}
-	
 	return err;
 }
Index: libconcord/remote.h
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/remote.h,v
retrieving revision 1.17
diff -u -3 -p -u -p -r1.17 remote.h
--- libconcord/remote.h	11 Apr 2008 05:05:26 -0000	1.17
+++ libconcord/remote.h	28 Jun 2008 12:45:25 -0000
@@ -27,7 +27,7 @@
 #define FLASH_EEPROM_ADDR 0x10
 #define FLASH_SERIAL_ADDR 0x000110
 #define FLASH_SIZE 48
-#define MAX_PULSE_COUNT 1000
+#define MAX_IR_SIGNAL_LENGTH 1000
 
 /*
  * WARNING: Do not change this!
@@ -147,7 +147,8 @@ public:
 	virtual int GetTime(const TRemoteInfo &ri, THarmonyTime &ht)=0;
 	virtual int SetTime(const TRemoteInfo &ri, const THarmonyTime &ht)=0;
 
-	virtual int LearnIR(string *learn_string=NULL)=0;
+	virtual int LearnIR(uint32_t *freq, uint32_t **ir_signal, 
+		uint32_t *ir_signal_length)=0;
 };
 
 class CRemote : public CRemoteBase	// All non-Z-Wave remotes
@@ -171,7 +172,7 @@ public:
 
 	int ReadFlash(uint32_t addr, const uint32_t len, uint8_t *rd,
 		unsigned int protocol, bool verify=false,
-		lc_callback cb=0, void *cb_arg=NULL);
+		lc_callback cb=NULL, void *cb_arg=NULL);
 	int InvalidateFlash(void);
 	int EraseFlash(uint32_t addr, uint32_t len, const TRemoteInfo &ri,
 		lc_callback cb=NULL, void *cb_arg=NULL);
@@ -185,7 +186,7 @@ public:
 	int GetTime(const TRemoteInfo &ri, THarmonyTime &ht);
 	int SetTime(const TRemoteInfo &ri, const THarmonyTime &ht);
 
-	int LearnIR(string *learn_string=NULL);
+	int LearnIR(uint32_t *freq, uint32_t **ir_signal, uint32_t *ir_signal_length);
 };
 
 // Base class for all Z-Wave remotes
@@ -212,7 +213,7 @@ public:
 
 	int ReadFlash(uint32_t addr, const uint32_t len, uint8_t *rd,
 		unsigned int protocol, bool verify=false,
-		lc_callback cb=0, void *cb_arg=NULL);
+		lc_callback cb=NULL, void *cb_arg=NULL);
 	int InvalidateFlash(void);
 	int EraseFlash(uint32_t addr, uint32_t len, const TRemoteInfo &ri,
 		lc_callback cb=NULL, void *cb_arg=NULL);
@@ -226,7 +227,7 @@ public:
 	int GetTime(const TRemoteInfo &ri, THarmonyTime &ht);
 	int SetTime(const TRemoteInfo &ri, const THarmonyTime &ht);
 
-	int LearnIR(string *learn_string=NULL);
+	int LearnIR(uint32_t *freq, uint32_t **ir_signal, uint32_t *ir_signal_length);
 };
 
 // 890, 890Pro, AVL-300, RF Extender
Index: libconcord/remote_z.cpp
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/remote_z.cpp,v
retrieving revision 1.18
diff -u -3 -p -u -p -r1.18 remote_z.cpp
--- libconcord/remote_z.cpp	11 Apr 2008 05:05:26 -0000	1.18
+++ libconcord/remote_z.cpp	28 Jun 2008 12:45:25 -0000
@@ -353,7 +353,8 @@ int CRemoteZ_Base::SetTime(const TRemote
 	return 1;
 }
 
-int CRemoteZ_Base::LearnIR(string *learn_string)
+int CRemoteZ_Base::LearnIR(uint32_t *freq, 
+	uint32_t **ir_signal, uint32_t *ir_signal_length)
 {
 	return 0;
 }
Index: libconcord/web.cpp
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/web.cpp,v
retrieving revision 1.26
diff -u -3 -p -u -p -r1.26 web.cpp
--- libconcord/web.cpp	14 Apr 2008 02:32:00 -0000	1.26
+++ libconcord/web.cpp	28 Jun 2008 12:45:25 -0000
@@ -160,7 +160,7 @@ int GetTag(const char *find, uint8_t* da
 			if (*search == '<') {
 				break;
 			}
-			if (search - data >= data_size) {
+			if (search >= data + data_size) {
 				return -1;
 			}
 			search++;
@@ -194,7 +194,7 @@ int GetTag(const char *find, uint8_t* da
 				while (*search && *search != '<') {
 					*s += *search;
 					search++;
-					if (search - data >= data_size) {
+					if (search >= data + data_size) {
 						break;
 					}
 				}
@@ -207,7 +207,7 @@ int GetTag(const char *find, uint8_t* da
 			if (*search == '>') {
 				break;
 			}
-			if (search - data >= data_size) {
+			if (search >= data + data_size) {
 				return -1;
 			}
 			search++;
@@ -215,6 +215,42 @@ int GetTag(const char *find, uint8_t* da
 	}
 }
 
+int encode_ir_signal(uint32_t carrier_clock, 
+	uint32_t *ir_signal, uint32_t ir_signal_length,
+	string *learn_seq)
+{	/*
+	 * Encode ir_signal into string accepted by Logitech server
+	 */
+	char s[32];
+	
+	if ((learn_seq == NULL) || 
+		(ir_signal == NULL) || (ir_signal_length == 0)) {
+		return LC_ERROR;
+	}
+	if (carrier_clock > 0xFFFF) {
+		sprintf(s, "F%08X", carrier_clock);
+	} else {
+		sprintf(s, "F%04X", carrier_clock);
+	}
+	*learn_seq = s;
+	for (unsigned int n = 0; n < ir_signal_length; ) {
+		if (ir_signal[n] > 0xFFFF) {
+			sprintf(s, "P%08X", ir_signal[n++]);
+		} else {
+			sprintf(s, "P%04X", ir_signal[n++]);
+		}
+		*learn_seq += s;
+		if (ir_signal[n] > 0xFFFF) {
+			sprintf(s, "S%08X", ir_signal[n++]);
+		} else {
+			sprintf(s, "S%04X", ir_signal[n++]);
+		}
+		*learn_seq += s;
+	}
+	return 0;
+}
+
+
 int Post(uint8_t *xml, uint32_t xml_size, const char *root, TRemoteInfo &ri,
 	bool has_userid, bool add_cookiekeyval = false,
 	string *learn_seq = NULL, string *learn_key = NULL)
Index: libconcord/web.h
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/web.h,v
retrieving revision 1.10
diff -u -3 -p -u -p -r1.10 web.h
--- libconcord/web.h	14 Apr 2008 02:32:00 -0000	1.10
+++ libconcord/web.h	28 Jun 2008 12:45:25 -0000
@@ -25,6 +25,11 @@
 
 int GetTag(const char *find, uint8_t* data, uint32_t data_size,
 	uint8_t *&found, string *s = NULL);
+
+int encode_ir_signal(uint32_t carrier_clock, 
+	uint32_t *ir_signal, uint32_t ir_signal_length,
+	string *learn_seq);
+
 int Post(uint8_t *xml, uint32_t xml_size, const char *root, TRemoteInfo &ri,
 	bool has_userid, bool add_cookiekeyval = false,
 	string *learn_seq=NULL, string *learn_key=NULL);
Index: libconcord/bindings/python/libconcord.py
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/bindings/python/libconcord.py,v
retrieving revision 1.1
diff -u -3 -p -u -p -r1.1 libconcord.py
--- libconcord/bindings/python/libconcord.py	8 Apr 2008 09:50:29 -0000	1.1
+++ libconcord/bindings/python/libconcord.py	28 Jun 2008 12:45:26 -0000
@@ -55,7 +55,8 @@ class _CheckRetCode(object):
         result = args[0]
         if result != 0:
             raise LibConcordException(self.func_name, result)
-        
+        return result
+
 # Internal ctypes function wrapper creation
 def _create_func(
     func_name,
@@ -321,11 +322,11 @@ get_time_timezone = _create_func(
     c_char_p
 )
 
-# int delete_blob(uint8_t *ptr);
+# void delete_blob(uint8_t *ptr);
 delete_block = _create_func(
     'delete_blob',
-    _CheckRetCode,
-    c_int,
+    None,
+    None,
     POINTER(c_ubyte)
 );
 
@@ -630,13 +631,85 @@ extract_firmware_binary = _create_func(
     POINTER(c_uint)
 )
 
-# int learn_ir_commands(uint8_t *data, uint32_t size, int post);
-learn_ir_commands = _create_func(
-    'learn_ir_commands',
+#  IR-stuff
+#  ===========================
+
+# int get_key_names(uint8_t *data, uint32_t size,
+#        char ***key_names, uint32_t *key_names_length);
+
+get_key_names = _create_func(
+    'get_key_names',
     _CheckRetCode,
     c_int,
     POINTER(c_ubyte),
     c_uint,
-    c_int
+    POINTER(POINTER(c_char_p)),
+    POINTER(c_uint)
+)
+
+# void delete_key_names(char **key_names, uint32_t key_names_length);
+
+delete_key_names = _create_func(
+    'delete_key_names',
+    None,
+    None,
+    POINTER(c_char_p),
+    c_uint
+)
+
+# int learn_from_remote(uint32_t *carrier_clock,
+#        uint32_t **ir_signal, uint32_t *ir_signal_length);
+
+learn_from_remote = _create_func(
+    'learn_from_remote',
+    _CheckRetCode,
+    c_int,
+    POINTER(c_uint),
+    POINTER(POINTER(c_uint)),
+    POINTER(c_uint)
+)
+
+# void delete_ir_signal(uint32_t *ir_signal);
+
+delete_ir_signal = _create_func(
+    'delete_ir_signal',
+    None,
+    None,
+    POINTER(c_uint)
 )
 
+# int encode_for_posting(uint32_t carrier_clock,
+#        uint32_t *ir_signal, uint32_t ir_signal_length,
+#        char **encoded_signal);
+
+encode_for_posting = _create_func(
+    'encode_for_posting',
+    _CheckRetCode,
+    c_int,
+    c_uint,
+    POINTER(c_uint),
+    c_uint,
+    POINTER(c_char_p)
+)
+
+# void delete_encoded_signal(char *encoded_signal);
+
+delete_encoded_signal = _create_func(
+    'delete_encoded_signal',
+    None,
+    None,
+    c_char_p
+)
+
+# int post_new_code(uint8_t *data, uint32_t size, 
+#        char *key_name, char *encoded_signal);
+
+post_new_code = _create_func(
+    'post_new_code',
+    _CheckRetCode,
+    c_int,
+    POINTER(c_ubyte),
+    c_uint,
+    c_char_p,
+    c_char_p
+)
Index: libconcord/win/libconcord.def
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/win/libconcord.def,v
retrieving revision 1.8
diff -u -3 -p -u -p -r1.8 libconcord.def
--- libconcord/win/libconcord.def	4 Apr 2008 05:21:03 -0000	1.8
+++ libconcord/win/libconcord.def	28 Jun 2008 12:45:26 -0000
@@ -92,5 +92,14 @@ write_firmware_to_file
 extract_firmware_binary
 
 ; IR-stuff
-;
-learn_ir_commands
+get_key_names
+delete_key_names
+
+learn_from_remote
+delete_ir_signal
+
+encode_for_posting
+delete_encoded_signal
+
+post_new_code
+
-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php
_______________________________________________
concordance-devel mailing list
concordance-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/concordance-devel

Reply via email to