writePin(CAPSENSE_SHIFT_STCP, 0);
}
-void shift_data(uint32_t data)
+void shift_data(uint32_t data, int data_idle, int shcp_idle, int stcp_idle)
{
int i;
+ writePin(CAPSENSE_SHIFT_SHCP, 0);
+ writePin(CAPSENSE_SHIFT_STCP, 0);
for (i=SHIFT_BITS-1; i>=0; i--)
{
writePin(CAPSENSE_SHIFT_DIN, (data >> (SHIFT_BITS - 1)) & 1);
writePin(CAPSENSE_SHIFT_SHCP, 1);
- writePin(CAPSENSE_SHIFT_SHCP, 0);
+ if (!((i == 0) && (shcp_idle))) {
+ writePin(CAPSENSE_SHIFT_SHCP, 0);
+ }
data <<= 1;
}
writePin(CAPSENSE_SHIFT_STCP, 1);
- writePin(CAPSENSE_SHIFT_STCP, 0);
+ if (!stcp_idle) {
+ writePin(CAPSENSE_SHIFT_STCP, 0);
+ }
+ writePin(CAPSENSE_SHIFT_DIN, !!data_idle);
}
void shift_select_col_no_strobe(uint8_t col)
extern uint16_t cal_thresholds[CAPSENSE_CAL_BINS];
extern matrix_row_t assigned_to_threshold[CAPSENSE_CAL_BINS][MATRIX_ROWS];
uint16_t measure_middle_keymap_coords(uint8_t col, uint8_t row, uint8_t time, uint8_t reps);
-void shift_data(uint32_t data);
+void shift_data(uint32_t data, int data_idle, int shcp_idle, int stcp_idle);
void dac_write_threshold(uint16_t value);
uint8_t test_single(uint8_t col, uint16_t time, uint8_t *interference_ptr);
button->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
button->setMinimumSize(20, 0);
button->setCheckable(true);
+ button->setStyleSheet(":checked {background-color: #c0FFc0; color:black }");
ui->horizontalLayout->addWidget(button);
connect(button, SIGNAL(clicked()), this, SLOT(onButtonClicked()));
}
+ connect(ui->pushButton_data, SIGNAL(clicked()), this, SLOT(onButtonClicked()));
+ connect(ui->pushButton_shcp, SIGNAL(clicked()), this, SLOT(onButtonClicked()));
+ connect(ui->pushButton_stcp, SIGNAL(clicked()), this, SLOT(onButtonClicked()));
+ connect(&thread, &HidThread::reportControlReadback, this, &ColumnTester::onReportControlState);
this->setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
this, SLOT(ShowContextMenu(const QPoint &)));
data |= 1 << i;
}
}
- thread.shiftData(path, data);
+ thread.shiftData(path, data,
+ ui->pushButton_data->isChecked(),
+ ui->pushButton_shcp->isChecked(),
+ ui->pushButton_stcp->isChecked());
+}
+
+void ColumnTester::onReportControlState(std::vector<uint8_t> readback)
+{
+ const bool enabled = readback.size() != 0;
+ ui->pushButton_data->setEnabled(enabled);
+ ui->pushButton_shcp->setEnabled(enabled);
+ ui->pushButton_stcp->setEnabled(enabled);
+ ui->label_control_set->setEnabled(enabled);
+ ui->label_control_readback->setEnabled(enabled);
+ if (enabled) {
+ if (readback[0]) ui->frame_data->setStyleSheet("background-color:#c0FFc0");
+ else ui->frame_data->setStyleSheet("background-color:");
+ if (readback[1]) ui->frame_shcp->setStyleSheet("background-color:#c0FFc0");
+ else ui->frame_shcp->setStyleSheet("background-color:");
+ if (readback[2]) ui->frame_stcp->setStyleSheet("background-color:#c0FFc0");
+ else ui->frame_stcp->setStyleSheet("background-color:");
+ }
}
private slots:
void onButtonClicked();
void ShowContextMenu(const QPoint &pos);
+ void onReportControlState(std::vector<uint8_t>);
private:
Ui::ColumnTester *ui;
<rect>
<x>0</x>
<y>0</y>
- <width>807</width>
- <height>196</height>
+ <width>664</width>
+ <height>395</height>
</rect>
</property>
<property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</size>
</property>
<property name="text">
- <string><html><head/><body><p>*NOTE1: The column tester is a debugging feature that allows you to set Low/High static output on each column pin. Pressed means logic high. This feature is most useful in conjunction with a voltmeter, to check for functional shift registers, and no broken or shorted column traces.</p><p>*NOTE2: These are physical columns, so if the keyboard skips some columns those are still listed here</p><p>*NOTE3: Normal keyboard input is disabled while this window is open.</p></body></html></string>
+ <string><html><head/><body><p>*NOTE1: The column tester is a debugging feature that allows you to set Low/High static output on each column pin. Pressed means logic high. This feature is most useful in conjunction with a voltmeter, to check for functional shift registers, and no broken or shorted column traces.</p><p>*NOTE2: These are physical columns, so if the keyboard skips some columns those are still listed here</p><p>*NOTE3: Column numbers here are not dependent on the keyboard layout. Column 1 is always the first bit of the first shift register in the chain.</p><p>*NOTE4: If readback differs from the set state of the control signals, then you might have a short on your control signals.</p><p>*NOTE5: Normal keyboard input is disabled while this window is open.</p></body></html></string>
</property>
<property name="scaledContents">
<bool>false</bool>
</widget>
</item>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout"/>
+ <widget class="QLabel" name="label_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Columns:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_control_set">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Idle Control Signal States:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QPushButton" name="pushButton_data">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">:checked {background-color: #c0FFc0; color:black}</string>
+ </property>
+ <property name="text">
+ <string>SER/DS/MOSI/SR_DS
+(Data to shift register)</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButton_shcp">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">:checked {background-color: #c0FFc0; color:black}</string>
+ </property>
+ <property name="text">
+ <string>SHCP/SRCLK/CLOCK/SR_SHCP
+(Shifting clock to shift register)</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButton_stcp">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">:checked {background-color: #c0FFc0; color:black}</string>
+ </property>
+ <property name="text">
+ <string>STCP/RCLK/LOADCOL/SR_STCP
+(Storage clock for shift register)</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_control_readback">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Idle Control Signal State Readback (only updated when you change something above):</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QFrame" name="frame_data">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QFrame" name="frame_shcp">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QFrame" name="frame_stcp">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
</item>
</layout>
</widget>
}
}
+std::vector<uint8_t> Device::shiftDataExt(uint32_t shdata, bool data_idle, bool shcp_idle, bool stcp_idle)
+{
+ uint8_t data[33];
+ {
+ QMutexLocker locker(&mutex);
+ if (xwhatsit_original_firmware)
+ {
+ throw std::runtime_error("This doesn't work with xwhatsit original firmware");
+ }
+
+ data[0] = 0;
+ memcpy(data + 1, magic, sizeof(magic));
+ data[2+1] = UTIL_COMM_SHIFT_DATA_EXT;
+ data[3+1] = shdata & 0xff;
+ data[4+1] = (shdata >> 8) & 0xff;
+ data[5+1] = (shdata >> 16) & 0xff;
+ data[6+1] = (shdata >> 24) & 0xff;
+ data[7+1] = (uint8_t)data_idle;
+ data[8+1] = (uint8_t)shcp_idle;
+ data[9+1] = (uint8_t)stcp_idle;
+ if (-1==hid_write(device, data, sizeof(data)))
+ {
+ printf("hid error: %ls\n", hid_error(device));
+ throw std::runtime_error("hid_write failed to shift data");
+ }
+ if ((sizeof(data)-1)!=hid_read_timeout(device, data, sizeof(data)-1, 1000))
+ {
+ printf("hid error: %ls\n", hid_error(device));
+ throw std::runtime_error("hid_read failed while shifting data");
+ }
+ if ((data[0] != magic[0]) || (data[1] != magic[1]))
+ {
+ throw std::runtime_error("hid_read failed while shifting data -- no magic returned");
+ }
+ }
+ std::vector<uint8_t> ret;
+ if (data[2] != UTIL_COMM_RESPONSE_OK)
+ {
+ shiftData(shdata);
+ return ret;
+ }
+ ret.push_back(data[3]);
+ ret.push_back(data[4]);
+ ret.push_back(data[5]);
+ return ret;
+}
+
void Device::disableKeyboard()
{
QMutexLocker locker(&mutex);
void assertVersionIsAtLeast(uint8_t major, uint8_t mid, uint16_t minor);
void eraseEeprom();
void shiftData(uint32_t shdata);
+ std::vector<uint8_t> shiftDataExt(uint32_t shdata, bool data_idle, bool shcp_idle, bool stcp_idle);
std::vector<std::vector<uint8_t>> getThresholds();
std::vector<uint8_t> getKeyState();
std::vector<uint8_t> getKeyboardDetails();
condition.wakeOne();
}
-void HidThread::shiftData(std::string path, uint32_t shdata)
+void HidThread::shiftData(std::string path, uint32_t shdata, bool data_idle, bool shcp_idle, bool stcp_idle)
{
QMutexLocker locker(&mutex);
this->shift_data = shdata;
+ this->shift_data_idle = data_idle;
+ this->shift_shcp_idle = shcp_idle;
+ this->shift_stcp_idle = stcp_idle;
this->shift_data_path = path;
condition.wakeOne();
}
mutex.lock();
bool l_keep_scanning, l_abort, nothing_to_do, l_autoenter_mode, l_close_monitored_device, l_set_dac;
uint32_t l_shift_data;
+ bool l_shift_data_idle, l_shift_shcp_idle, l_shift_stcp_idle;
std::string l_enter_bootloader_path, l_monitor_path, l_erase_eeprom_path, l_signal_level_path, l_shift_data_path, l_enable_keyboard_path, l_monitor_row_state_path;
uint16_t l_set_dac_value;
do {
l_erase_eeprom_path = this->erase_eeprom_path;
l_shift_data_path = shift_data_path;
l_shift_data = shift_data;
+ l_shift_data_idle = shift_data_idle;
+ l_shift_shcp_idle = shift_shcp_idle;
+ l_shift_stcp_idle = shift_stcp_idle;
l_enable_keyboard_path = enable_keyboard_path;
l_set_dac = set_dac;
l_set_dac_value = set_dac_value;
QScopedPointer<Device> dev(comm.open(l_shift_data_path));
dev.data()->disableKeyboard();
dev.data()->assertVersionIsAtLeast(2, 0, 3);
- dev.data()->shiftData(l_shift_data);
+ emit reportControlReadback(dev.data()->shiftDataExt(l_shift_data, l_shift_data_idle, l_shift_shcp_idle, l_shift_stcp_idle));
} catch (const std::runtime_error &e1) {
emit reportError(e1.what());
}
void signalLevel(std::string path);
void eraseEeprom(std::string path);
void closeMonitoredDevice();
- void shiftData(std::string path, uint32_t shdata);
+ void shiftData(std::string path, uint32_t shdata, bool data_idle, bool shcp_idle, bool stcp_idle);
void enableKeyboard(std::string path);
void setDacValue(uint16_t value);
Device *connectToDevice(std::string path);
void reportMonitorError(std::string error_message);
void reportSignalLevel(std::vector<uint16_t>);
void reportRowsAndMaxDac(uint8_t rows, uint16_t max_dac);
+ void reportControlReadback(std::vector<uint8_t>);
protected:
void run() override;
bool autoenter_mode;
bool close_monitored_device;
uint32_t shift_data;
+ bool shift_data_idle;
+ bool shift_shcp_idle;
+ bool shift_stcp_idle;
std::string shift_data_path;
std::string enter_bootloader_path;
std::string monitor_path;
ColumnTester *ctw = new ColumnTester(thread, path, this);
ctw->setAttribute(Qt::WA_DeleteOnClose);
bool previousScanning = thread.setScanning(false);
- thread.shiftData(path, 0);
+ thread.shiftData(path, 0, 0, 0 ,0);
this->setEnabled(false);
ctw->setEnabled(true);
ctw->exec();
- thread.shiftData(path, 0);
+ thread.shiftData(path, 0, 0, 0, 0);
this->setEnabled(true);
thread.enableKeyboard(path);
thread.setScanning(previousScanning);
break;
}
case UTIL_COMM_SHIFT_DATA:
+ case UTIL_COMM_SHIFT_DATA_EXT:
{
response[2] = UTIL_COMM_RESPONSE_OK;
uint32_t shdata = (((uint32_t)(data[3])) << 0) |
(((uint32_t)(data[4])) << 8) |
(((uint32_t)(data[5])) << 16) |
(((uint32_t)(data[6])) << 24);
- shift_data(shdata);
+ int data_idle = 0;
+ int shcp_idle = 0;
+ int stcp_idle = 0;
+ if (data[2] == UTIL_COMM_SHIFT_DATA_EXT)
+ {
+ data_idle = data[7];
+ shcp_idle = data[8];
+ stcp_idle = data[9];
+ }
+ shift_data(shdata, data_idle, shcp_idle, stcp_idle);
+ response[3] = readPin(CAPSENSE_SHIFT_DIN);
+ response[4] = readPin(CAPSENSE_SHIFT_SHCP);
+ response[5] = readPin(CAPSENSE_SHIFT_STCP);
break;
}
case UTIL_COMM_SET_DAC_VALUE:
UTIL_COMM_SHIFT_DATA,
UTIL_COMM_SET_DAC_VALUE,
UTIL_COMM_GET_ROW_STATE,
+ UTIL_COMM_SHIFT_DATA_EXT,
};
enum response {