Redefinição de milhagem para RICOH SP 150SUw

Não acredito na teoria da conspiração dos fabricantes (eletrônicos) para reduzir o recurso do produto, é apenas buscar a melhor relação preço / qualidade para um determinado segmento de mercado. Mas há um momento em que queimo descontroladamente logo abaixo da barriga. Estes são os fabricantes da impressora. Não só os preços dos consumíveis podem ser justificados apenas pela presença de um bebê nascido de virgem no sangue, mas também pelo “lascamento” generalizado de cartuchos, que já não passaram para as unidades de laser mais orçamentárias. Mas o que realmente me "bombou" com o seguinte produto: RICOH SP 150SUw. Este dispositivo foi adquirido devido à mudança da região de Moscou para Minsk e à necessidade de copiar / imprimir um grande número de documentos para obter uma autorização de trabalho / residência.



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 PIC16F819 e PICKit 3, não, para promoção às massas - Arduino UNO / Nano, um par de resistores de 4,7k (de 3k a 10k para esta tarefa - ele servirá), um medidor MGTF ou seu fio favorito e monte o próximo "Esquema":







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 

      
      






All Articles