A escolha foi baseada nos seguintes requisitos: MFP não é caro, compacto, impressão em rede, disponibilidade de drivers para Linux (Fedora / Mint / OpenSUSE). O herói do artigo possuía todas essas características, mas uma nuance não foi percebida. Contador de recursos curvo. Se você quer saber como curar e
(Memorando para gramática nazista de uma pessoa com disgrafia leve)
, . . / , . , . «», . , , , / . , , , , . , , . , —
Bem-vinda!
A coisa é,que o MFP não conta a quantidade de toner usado, mas o número de páginas impressas. Se eu imprimi o cartucho inicial com um grau de enchimento suficientemente grande, então aconteceu um incidente com o segundo. O fato é que minha esposa rapidamente se juntou à comunidade local de Angloms e parte do trabalho relacionado ao fornecimento de impressão recaiu sobre nós. Assim, todo tipo de desenho de contorno para recorte / coloração / origami é preenchido com toner, no máximo, 1% da folha. Como resultado, encontrei-me "vazio" no balcão, mas na verdade - um total de 70 por cento do cartucho. Não, não sou tão pobre a ponto de não ter dinheiro para comprar um novo, não sou tão educado ambientalmente para experimentar tormento moral, jogando um produto útil em um aterro sanitário, mas com a sensação de que você foi legalmente jogado para cima - a cadeira começou a fumaça, que foi um impulso para a ação ...
Honestamente, eu não esperava me tornar um "hacker de mãe", visto que essa proteção de hardware é muito difícil de quebrar. Contei, pelo menos, com algoritmos de criptografia decentes e memória OTP (uma vez programável). Mas a realidade acabou se tornando muito mais comum. Felizmente, havia muitas instruções no pedido para reiniciar o cartucho, e o "chip de proteção" acabou sendo um I2C EEPROM AT24C01 bastante comum , soldado com um "kit de corpo" mínimo, não uma placa. De modo geral, na próxima foto, você pode terminar o artigo:
Vídeo original
Com qualquer programador, lemos o conteúdo do microcircuito, "zeramos" as células contornadas em quadros vermelhos e alteramos os últimos dois dígitos do número de série. Deve-se observar que o serial é uma string de texto que termina com um espaço, portanto, você precisa alterá-lo no intervalo 0 ... 9 (0x30 ... 0x39). O endereço físico do microcircuito soldado na placa é 0x03. Mas ... Conheça um sapateiro sem botas. Não existe um programador universal, então pegamos
Montado, tem a seguinte aparência:
Retirei a placa de "proteção" do cartucho para ter certeza de que a pinagem indicada no manual corresponde à realidade e para obter o endereço físico do microcircuito no barramento:
Placas de contato, da esquerda para a direita: GND, + 5V, SCL . SDA.
Você não precisa ser esperto com a fabricação do adaptador, mas solde os fios diretamente na placa sem removê-lo do cartucho. Em seguida, copie meu código de merda para o IDE do Arduino:
Código de merda
#include <stdint.h>
#include <Wire.h>
//----------------------------------------------------------------
#define EERROM_SZ (0x80)
#define EERROM_PHY_ADDR (0x03)
#define EERROM_HEAD (0x50)
#define PRN_BUFF_SZ (0x08)
#define SER_START_ADDR (0x20)
#define SER_END_ADDR (0x2B)
#define SER_MOD_ADDR0 (0x2A)
#define SER_MOD_ADDR1 (0x29)
#define SER_MOD_ADDR2 (0x28)
//----------------------------------------------------------------
static uint8_t eeprom_data[EERROM_SZ];
static bool erased;
static bool z_filled;
//----------------------------------------------------------------
static uint8_t ee_read(uint8_t phy_addr, uint8_t addr)
{
uint8_t res;
Wire.beginTransmission(EERROM_HEAD | phy_addr);
Wire.write(addr);
Wire.endTransmission();
Wire.requestFrom(EERROM_HEAD | phy_addr, 1);
res = Wire.read();
return res;
}
//----------------------------------------------------------------
static void ee_write(uint8_t phy_addr, uint8_t addr, uint8_t data)
{
Wire.beginTransmission(EERROM_HEAD | phy_addr);
Wire.write(addr);
Wire.write(data);
Wire.endTransmission();
delay(5);
}
//----------------------------------------------------------------
static void read_data(uint8_t phy_addr)
{
uint8_t addr;
uint8_t data;
erased = true;
z_filled = true;
Serial.print("Read from phy addr ");
Serial.print(phy_addr);
for (addr = 0; addr < EERROM_SZ; addr++)
{
if (0 == (addr & 0x03))
{
Serial.print(".");
}
data = ee_read(phy_addr, addr);
eeprom_data[addr] = data;
if (0xFF != data)
{
erased = false;
}
if (0x00 != data)
{
z_filled = false;
}
}
Serial.println("Ok");
}
//----------------------------------------------------------------
static void write_data(uint8_t phy_addr)
{
uint8_t addr;
Serial.print("Write to phy addr ");
Serial.print(phy_addr);
for (addr = 0; addr < EERROM_SZ; addr++)
{
if (0 == (addr & 0x03))
{
Serial.print(".");
}
ee_write(phy_addr, addr, eeprom_data[addr]);
}
Serial.println("Ok");
}
//----------------------------------------------------------------
static bool check_data(uint8_t phy_addr)
{
uint8_t addr;
uint8_t data;
Serial.print("Check from phy addr ");
Serial.print(phy_addr);
for (addr = 0; addr < EERROM_SZ; addr++)
{
if (0 == (addr & 0x03))
{
Serial.print(".");
}
data = ee_read(phy_addr, addr);
if (eeprom_data[addr] != data)
{
Serial.println("FAILED");
return false;
}
}
Serial.println("Ok");
return true;
}
//----------------------------------------------------------------
static void print_data(void)
{
uint16_t addr;
char prn_buff[PRN_BUFF_SZ];
for(addr = 0; addr < EERROM_SZ; addr++)
{
if (0x00 == (addr & 0x0F))
{
snprintf(prn_buff, PRN_BUFF_SZ, "%4X: ", addr);
Serial.print(prn_buff);
}
snprintf(prn_buff, PRN_BUFF_SZ, "%2X ", eeprom_data[addr]);
Serial.print(prn_buff);
if (0x0F == (addr & 0x0F))
{
Serial.print("\n\r");
}
}
Serial.print("\n\r");
}
//----------------------------------------------------------------
static void prn_serial(void)
{
Serial.print("Serial #: ");
Serial.write(&eeprom_data[SER_START_ADDR], 1 + SER_END_ADDR - SER_START_ADDR);
Serial.print("\n\r");
}
//----------------------------------------------------------------
static void mod_serial(void)
{
eeprom_data[SER_MOD_ADDR0]++;
if (eeprom_data[SER_MOD_ADDR0] > '9')
{
eeprom_data[SER_MOD_ADDR0] = '2';
}
eeprom_data[SER_MOD_ADDR1]++;
if (eeprom_data[SER_MOD_ADDR1] > '9')
{
eeprom_data[SER_MOD_ADDR1] = '3';
eeprom_data[SER_MOD_ADDR2]++;
if (eeprom_data[SER_MOD_ADDR2] > '9')
{
eeprom_data[SER_MOD_ADDR2] = '1';
}
}
}
//----------------------------------------------------------------
static void reset_mileage(void)
{
uint8_t i;
for (i = 0x12; i <= 0x1F; i++)
{
eeprom_data[i] = 0;
}
for (i = 0x2C; i <= 0x7F; i++)
{
eeprom_data[i] = 0;
}
}
//----------------------------------------------------------------
static bool test_magic(void)
{
if (0x32 != eeprom_data[0]) return false;
if (0x00 != eeprom_data[1]) return false;
if (0x01 != eeprom_data[2]) return false;
if (0x03 != eeprom_data[3]) return false;
return true;
}
//----------------------------------------------------------------
void setup()
{
int key;
Serial.begin(9600);
Wire.begin();
Serial.println("\tSP 150 cartridge mileage resetter");
Serial.println("Connect like this:");
Serial.println(" TOP");
Serial.println("______________________________");
Serial.println("|o |GND| |+5V| |SCL| |SDA| <=");
Serial.println("| |GND| | 5V| | A5| | A4| ");
Serial.println("------------------------------");
Serial.println(" cartridge roller");
Serial.println("\n\r\n\r\tTo start, press 'm' or any button for test (not prog)...\n\r");
do
{
key = Serial.read();
}
while(-1 == key);
#if 0
for (uint8_t paddr = 0; paddr < 8; paddr++)
{
Serial.print("Scan phy ");
Serial.println(paddr);
for (uint8_t i = 0; i < 5; i++)
{
Serial.print("Read from ");
Serial.print(i);
Serial.print(".........");
Serial.println(ee_read(paddr, i));
}
}
return;
#endif
read_data(EERROM_PHY_ADDR);
Serial.println("Read:");
print_data();
if (true == erased)
{
Serial.println("ERROR! The EEPROM is erased or the connection / phy addr is incorrect.");
return;
}
if (true == z_filled)
{
Serial.println("ERROR! The EEPROM is Z filled.");
return;
}
if (false == test_magic())
{
Serial.println("ERROR! Invalid magic number.");
return;
}
prn_serial();
mod_serial();
reset_mileage();
Serial.println("\n\rModified:");
print_data();
prn_serial();
if ('m' != (char)key)
{
Serial.println("WARNING! The data was not modified in the EEPROM");
return;
}
write_data(EERROM_PHY_ADDR);
if (false == check_data(EERROM_PHY_ADDR))
{
return;
}
Serial.println("Fin");
}
void loop()
{
//do nothing
}
(Sobre o código de merda - sim, ele não otimizou pela memória (todos os dados são lidos em um array), ou pelo desempenho (a leitura e a gravação são realizadas byte a byte), ou pela funcionalidade, mas para uma tarefa tão simples - e assim o fará!)
Nós piscaremos Arduinka, abriremos qualquer terminal (I18n, 9600 baud), o IDE Arduino embutido fará, reinicializará a placa, pressione qualquer botão:
Depois disso, o conteúdo da EEPROM será lido, modificado, mas não escrito. Se o procedimento ocorreu sem erros, reinicie o cartão novamente, pressione m, após o que todos os passos serão executados e os dados modificados serão gravados. Se algo deu errado, verifique o diagrama novamente e tente novamente. Depois de zerar com sucesso, soldamos os fios e instalamos o cartucho no lugar. O nível de toner deve ser 100%.
Peço desculpas pela "água", pela instrução de 3 linhas - muito pouco para um post. Espero que a informação tenha sido útil, e também - o autor não se responsabiliza por possíveis danos ao equipamento, privação do serviço de garantia, tudo que você faz é por sua própria conta e risco ...
Outra atualização, um despejo recebido do meu cartucho:
Read from phy addr 3................................Ok 0: 32 0 1 3 2 1 1 0 0 0 34 30 38 30 31 30 10: 16 5 4D 4D 1 2 11 70 0 0 0 0 14 14 5 21 20: 43 37 30 36 4D 39 30 33 31 39 35 20 0 45 0 0 30: 39 1 0 0 0 0 0 0 3E 4 0 0 0 0 0 0 40: 5 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50: 0 0 0 0 0 0 0 0 14 E 5 1B 14 E 5 1B 60: 0 0 0 0 0 0 0 0 77 2 0 0 0 0 0 0 70: C3 23 2A 0 16 0 0 55 0 0 0 0 0 0 0 0