Changes relative to first patch version (20080628):
===================================================
libconcord.h
- added LC_ERROR_IR_OVERFLOW:
- fixed some spacings and line breaks

libconcord.cpp
- reverted #include <string> back to #include <string.h>
  for some reason, original <string.h> now works for both Windows and LINUX
- added message for LC_ERROR_IR_OVERFLOW
- added 'using namespace std;' to avoid 'std::list<string> key_list;'
- fixed some spacings and line breaks

remote.h
- added some constants for IR signal learning:
- timeouts in milliseconds, length in number of mark/space durations
#define IR_LEARN_START_TIMEOUT   5000
#define MAX_IR_SIGNAL_DURATION   5000
#define IR_LEARN_DONE_TIMEOUT     500
#define MAX_IR_SIGNAL_LENGTH     1000

remote.cpp
- split some long lines (mostly not my code, but I was just in the mood...)
- added calculation and check of total duration t_total of IR signal
  received so far to time out learning after 5 sec with LC_ERROR_IR_OVERFLOW
- renamed ir_signal_length to ir_count in handle_ir_response for the
  sake of shorter lines
- Hiding HID error return values in LearnIR by returning LC_ERROR_READ/_WRITE
  as appropriate
- using constants defined in remote.h for timeouts
- check for IR signal buffer overflow, returning LC_ERROR_IR_OVERFLOW
- flushing HID read buffer after learning (may still contain data when
  aborting learning because of overflow/timeout).
Index: libconcord/libconcord.cpp
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/libconcord.cpp,v
retrieving revision 1.36
diff -u -3 -p -r1.36 libconcord.cpp
--- libconcord/libconcord.cpp	13 Aug 2008 20:07:39 -0000	1.36
+++ libconcord/libconcord.cpp	10 Oct 2008 18:43:07 -0000
@@ -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
@@ -314,6 +315,11 @@ const char *lc_strerror(int err)
 			return 
 			"The configuration present on the remote is invalid";
 			break;
+
+		case LC_ERROR_IR_OVERFLOW:
+			return 
+			"Received IR signal is too long - release key earlier";
+			break;
 	}
 
 	return "Unknown error";
@@ -1165,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;
 			}
@@ -1219,41 +1225,200 @@ 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)
+{
+	using namespace std;
+	uint8_t *cursor = data;
+	uint8_t *inputparams_end;
+	uint32_t key_index = 0;
+	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());
+	}
+	/* C++ should take care of key_name and key_list deallocation */
 	return 0;
 }
 
+/*
+ * 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 -r1.19 libconcord.h
--- libconcord/libconcord.h	11 Apr 2008 05:05:26 -0000	1.19
+++ libconcord/libconcord.h	10 Oct 2008 18:43:08 -0000
@@ -55,6 +55,7 @@ typedef unsigned __int64 uint64_t;
 #define LC_ERROR_OS_FILE 14
 #define LC_ERROR_UNSUPP 15
 #define LC_ERROR_INVALID_CONFIG 16
+#define LC_ERROR_IR_OVERFLOW 17
 
 /*
  * Filetypes, used by identity_file()
@@ -382,10 +383,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.
+ */
+
+/*
+ * 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 learn_ir_commands(uint8_t *data, uint32_t size, int post);
+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 -r1.34 remote.cpp
--- libconcord/remote.cpp	14 Apr 2008 08:07:07 -0000	1.34
+++ libconcord/remote.cpp	10 Oct 2008 18:43:08 -0000
@@ -429,7 +429,8 @@ int CRemote::WriteFlash(uint32_t addr, c
 	return err;
 }
 
-int CRemote::ReadMiscByte(uint8_t addr, uint32_t len, uint8_t kind, uint8_t *rd)
+int CRemote::ReadMiscByte(uint8_t addr, uint32_t len,
+		uint8_t kind, uint8_t *rd)
 {
 	uint8_t rmb[] = { COMMAND_READ_MISC | 0x02, kind, 0 };
 
@@ -453,7 +454,8 @@ int CRemote::ReadMiscByte(uint8_t addr, 
 	return 0;
 }
 
-int CRemote::ReadMiscWord(uint16_t addr, uint32_t len, uint8_t kind, uint16_t *rd)
+int CRemote::ReadMiscWord(uint16_t addr, uint32_t len,
+		uint8_t kind, uint16_t *rd)
 {
 	uint8_t rmw[] = { COMMAND_READ_MISC | 0x03, kind, 0, 0 };
 
@@ -481,7 +483,8 @@ int CRemote::ReadMiscWord(uint16_t addr,
 	return 0;
 }
 
-int CRemote::WriteMiscByte(uint8_t addr, uint32_t len, uint8_t kind, uint8_t *wr)
+int CRemote::WriteMiscByte(uint8_t addr, uint32_t len,
+		uint8_t kind, uint8_t *wr)
 {
 	uint8_t wmb[8];
 	wmb[0] = COMMAND_WRITE_MISC | 0x03;
@@ -506,7 +509,8 @@ int CRemote::WriteMiscByte(uint8_t addr,
 	return 0;
 }
 
-int CRemote::WriteMiscWord(uint16_t addr, uint32_t len, uint8_t kind, uint16_t *wr)
+int CRemote::WriteMiscWord(uint16_t addr, uint32_t len,
+		uint8_t kind, uint16_t *wr)
 {
 	uint8_t wmw[8];
 	wmw[0] = COMMAND_WRITE_MISC | 0x05;
@@ -643,124 +647,128 @@ 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 &t_total, 
+	uint32_t &ir_count,
+	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_count < MAX_IR_SIGNAL_LENGTH) {
+						ir_signal[ir_count++] = t_off;
+					}
+					debug("+%i\n", t_on);
+					if (ir_count < MAX_IR_SIGNAL_LENGTH) {
+						ir_signal[ir_count++] = t_on;
+					}
+					t_total += t_off + 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_count++] = 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 };
+
+	if (HID_WriteReport(start_ir_learn) != 0) {
+		return LC_ERROR_WRITE;
+	}
 
 	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;
+	// total duration of received signal: 
+	// abort when > MAX_IR_SIGNAL_DURATION
+	uint32_t t_total = 0;
 
+	*ir_signal_length = 0;
+	*ir_signal = new uint32_t[MAX_IR_SIGNAL_LENGTH];
 	/*
-	 * Loop while we have no error and we haven't had 500,000us of
-	 * any pulses
+	 * Caller is responsible for deallocation of *ir_signal after use.
+	 *
+	 * Loop while we haven not:
+	 * - any error (including signal duration and buffer overflow)
+	 * - signal interrupted for IR_LEARN_DONE_TIMEOUT or longer
 	 */
-	while (err == 0 && t_off < 500000) {
-		if ((err = HID_ReadReport(rsp, ir_word ? 500 : 4000)))
+	while ((err == 0) && (t_off < IR_LEARN_DONE_TIMEOUT * 1000)) {
+		if ((err = HID_ReadReport(rsp, ir_word ? 
+			IR_LEARN_DONE_TIMEOUT : IR_LEARN_START_TIMEOUT))) {
+			err = LC_ERROR_READ;
 			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 +777,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, 
+				t_total, *ir_signal_length, *ir_signal,	*freq);
 			if (err != 0) {
 				break;
 			}
@@ -778,42 +786,37 @@ int CRemote::LearnIR(string *learn_strin
 			break;
 		} else {
 			debug("Invalid response [%02X]", rsp[1]);
-			err = 1;
+			err = LC_ERROR;
+		}
+		/* check for overflow: */
+		if ((t_total > MAX_IR_SIGNAL_DURATION * 1000)
+			|| (*ir_signal_length > MAX_IR_SIGNAL_LENGTH)) {
+			err = LC_ERROR_IR_OVERFLOW;
 		}
 	}
 
-	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;
-
-	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 ((rsp[0] & COMMAND_MASK) != RESPONSE_DONE) {
-			err = 1;
+	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;
 		}
 	}
 
-	/*
-	 * 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;
-		}
+	if (HID_WriteReport(stop_ir_learn) != 0) {
+		err = LC_ERROR_WRITE;
 	}
-	
+
+	/* flush HID buffer until empty or RESPONSE_DONE: */
+	do {
+		if (HID_ReadReport(rsp, IR_LEARN_DONE_TIMEOUT) != 0) {
+			err = LC_ERROR_READ;
+			break;
+		}
+	} while ((rsp[0] & COMMAND_MASK) != RESPONSE_DONE); 
+
 	return err;
 }
Index: libconcord/remote.h
===================================================================
RCS file: /cvsroot/concordance/concordance/libconcord/remote.h,v
retrieving revision 1.17
diff -u -3 -p -r1.17 remote.h
--- libconcord/remote.h	11 Apr 2008 05:05:26 -0000	1.17
+++ libconcord/remote.h	10 Oct 2008 18:43:08 -0000
@@ -27,7 +27,14 @@
 #define FLASH_EEPROM_ADDR 0x10
 #define FLASH_SERIAL_ADDR 0x000110
 #define FLASH_SIZE 48
-#define MAX_PULSE_COUNT 1000
+/*
+ * limits for IR signal learning, stop when any is reached:
+ * timeouts in milliseconds, length in number of mark/space durations
+ */
+#define IR_LEARN_START_TIMEOUT   5000
+#define MAX_IR_SIGNAL_DURATION   5000
+#define IR_LEARN_DONE_TIMEOUT     500
+#define MAX_IR_SIGNAL_LENGTH     1000
 
 /*
  * WARNING: Do not change this!
@@ -147,7 +154,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 +179,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 +193,8 @@ 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 +221,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 +235,8 @@ 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 -r1.18 remote_z.cpp
--- libconcord/remote_z.cpp	11 Apr 2008 05:05:26 -0000	1.18
+++ libconcord/remote_z.cpp	10 Oct 2008 18:43:08 -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 -r1.26 web.cpp
--- libconcord/web.cpp	14 Apr 2008 02:32:00 -0000	1.26
+++ libconcord/web.cpp	10 Oct 2008 18:43:08 -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 -r1.10 web.h
--- libconcord/web.h	14 Apr 2008 02:32:00 -0000	1.10
+++ libconcord/web.h	10 Oct 2008 18:43:08 -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 -r1.1 libconcord.py
--- libconcord/bindings/python/libconcord.py	8 Apr 2008 09:50:29 -0000	1.1
+++ libconcord/bindings/python/libconcord.py	10 Oct 2008 18:43:08 -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 -r1.8 libconcord.def
--- libconcord/win/libconcord.def	4 Apr 2008 05:21:03 -0000	1.8
+++ libconcord/win/libconcord.def	10 Oct 2008 18:43:08 -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
+
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
concordance-devel mailing list
concordance-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/concordance-devel

Reply via email to