月(month)の値がゼロになります。

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
竜山

月(month)の値がゼロになります。

#1

投稿記事 by 竜山 » 1年前

「はやわかり」と言う電力監視モニター用のLinux(ubuntu)でフランスの人が開発したプログラムですがカレンダー変数のmonthだけが0となって取得できません。モニターに三か月分のデータが蓄積されプログラムの起動時に蓄積されたデータをすべて読み込んだのちにライブデータを取得するようになっていますがどちらのデータも月の値が0になっています。モニターを2台保有しているのでモニター本体の問題ではにのでは考えています。現状は<time.h>をインクルードして月の値だけ使っています。C言語はほとんど使ったことがないのでどなたかご教示お願いします。
以下プログラムです。
----------------------------------------------------

コード:

 
/*
 * eagle-owl application.
 *
 * Copyright (C) 2012 Philippe Cornet <phil.cornet@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <usb.h>
#include <pthread.h>
#include <fcntl.h>

#include <sys/types.h>
#include <sys/stat.h>

#include "cm160.h"
#include "usb_utils.h"
#include "db.h"
#include "demonize.h"

static char ID_MSG[11] = { 
      0xA9, 0x49, 0x44, 0x54, 0x43, 0x4D, 0x56, 0x30, 0x30, 0x31, 0x01 };
static char WAIT_MSG[11] = { 
      0xA9, 0x49, 0x44, 0x54, 0x57, 0x41, 0x49, 0x54, 0x50, 0x43, 0x52 };


#define HISTORY_SIZE 65536 // 30 * 24 * 60 = 43200 theoric history size

#define CP210X_IFC_ENABLE       0x00
#define CP210X_GET_LINE_CTL     0x04
#define CP210X_SET_MHS          0x07
#define CP210X_GET_MDMSTS       0x08
#define CP210X_GET_FLOW         0x14
#define CP210X_GET_BAUDRATE     0x1D
#define CP210X_SET_BAUDRATE     0x1E

/* CP210X_IFC_ENABLE */
#define UART_ENABLE             0x0001
#define UART_DISABLE            0x0000

struct cm160_device g_devices[MAX_DEVICES];
static unsigned char history[HISTORY_SIZE][11];

static void process_live_data(struct record_data *rec) 
{
  static double _watts = -1;
  double w = rec->watts;

  if(!rec->isLiveData) // special case: update only the time
  {
    if(_watts == -1)
      return;
    w = _watts;
  }
  else
    _watts = w;

  FILE *fp =  fopen(".live", "w");
  if(fp)
  {
    if(rec->hour!=255) // to avoid writing strange values (i.e. date 2255, hour 255:255) that sometimes I got
      fprintf(fp, "%02d/%02d/%04d %02d:%02d - %.02f kW\n", 
              rec->day, rec->month, rec->year, rec->hour, rec->min, w);
    fclose(fp);
  }
}

static void decode_frame(unsigned char *frame, struct record_data *rec)
{
  int volt = 230; // TODO: use the value from energy_param table (supply_voltage)
  rec->addr = 0; // TODO: don't use an harcoded addr value for the device...
  rec->year = frame[1]+2000;
  rec->month = frame[2];
  rec->day = frame[3];
  rec->hour = frame[4];
  rec->min = frame[5];
  rec->cost = (frame[6]+(frame[7]<<8))/100.0;
  rec->amps = (frame[8]+(frame[9]<<8))*0.07; // mean intensity during one minute
  rec->watts = rec->amps * volt; // mean power during one minute
  rec->ah = rec->amps/60; // -> we must devide by 60 to convert into ah and wh
  rec->wh = rec->watts/60;
  rec->isLiveData = (frame[0] == FRAME_ID_LIVE)? true:false;
}

// Insert history into DB worker thread
void insert_db_history(void *data)
{
  int i;
  int num_elems = (int)data;
  // For an unknown reason, the cm160 sometimes sends a value > 12 for month
  // -> in that case we use the last valid month received.
  static int last_valid_month = 0; 
  printf("insert %d elems\n", num_elems);
  printf("insert into db...\n");
  clock_t cStartClock = clock();

  db_begin_transaction();
  for(i=0; i<num_elems; i++)
  {
    unsigned char *frame = history[i];
    struct record_data rec;
    decode_frame(frame, &rec);

    if(rec.month < 0 || rec.month > 12)
      rec.month = last_valid_month;
    else
      last_valid_month = rec.month;

    db_insert_hist(&rec);
    printf("\r %.1f%%", min(100, 100*((double)i/num_elems)));
    fflush(stdout);
  }
  db_update_status();
  db_end_transaction();

  printf("\rinsert into db... 100%%\n");
  fflush(stdout);
  printf("update db in %4.2f seconds\n", 
         (clock() - cStartClock) / (double)CLOCKS_PER_SEC);
}

bool receive_history = true;
int frame_id = 0;
static int process_frame(int dev_id, unsigned char *frame)
{
  int i;
  unsigned char data[1];
  unsigned int checksum = 0;
  static int last_valid_month = 0; 
  usb_dev_handle *hdev = g_devices[dev_id].hdev;
  int epout = g_devices[dev_id].epout;

  if(strncmp((char *)frame, ID_MSG, 11) == 0)
  {
//    printf("received ID MSG\n");
    data[0]=0x5A;
    usb_bulk_write(hdev, epout, (const char *)&data, sizeof(data), 1000);
  }
  else if(strncmp((char *)frame, WAIT_MSG, 11) == 0)
  {
//    printf("received WAIT MSG\n");
    data[0]=0xA5;
    usb_bulk_write(hdev, epout, (const char *)&data, sizeof(data), 1000);
  }
  else
  {
    if(frame[0] != FRAME_ID_LIVE && frame[0] != FRAME_ID_DB)
    {
      printf("data error: invalid ID 0x%x\n", frame[0]);
      for(i=0; i<11; i++)
        printf("0x%02x - ", frame[i]);
      printf("\n");
      return -1;
    }

    for(i=0; i<10; i++)
      checksum += frame[i];
    checksum &= 0xff;
    if(checksum != frame[10])
    {
      printf("data error: invalid checksum: expected 0x%x, got 0x%x\n", 
             frame[10], checksum);
      return -1;
    }

    struct record_data rec;
    decode_frame(frame, &rec);

    if(rec.month < 0 || rec.month > 12)
      rec.month = last_valid_month;
    else
      last_valid_month = rec.month;

    if(frame[0]==FRAME_ID_DB)
    {
      if(receive_history && frame_id < HISTORY_SIZE)
      {
        if(frame_id == 0)
          printf("downloading history...\n");
        else if(frame_id%10 == 0)
        { // print progression status
          // rough estimation : we should received a month of history
          // -> 31x24x60 minute records
          printf("\r %.1f%%", min(100, 100*((double)frame_id/(31*24*60))));
          fflush(stdout);
        }
        // cache the history in a buffer, we will insert it in the db later.
        memcpy(history[frame_id++], frame, 11);
      }
      else
      {
        db_insert_hist(&rec);
        db_update_status();
        process_live_data(&rec); // the record is not live data, but we do that to
                                 // update the time in the .live file
                                 // (the cm160 send a DB frame when a new minute starts)
      }
    }
    else
    {
      if(receive_history)
      { // When we receive the first live data, 
        // we know that the history is totally downloaded
        printf("\rdownloading history... 100%%\n");
        fflush(stdout);
        receive_history = false;
        // Now, insert the history into the db
        pthread_t thread;
        pthread_create(&thread, NULL, (void *)&insert_db_history, (void *)frame_id);
      }
      
      process_live_data(&rec);
      printf("LIVE: %02d/%02d/%04d %02d:%02d : %f W\n",
             rec.day, rec.month, rec.year, rec.hour, rec.min, rec.watts);
    }
  }
  return 0;
}

static int io_loop(int dev_id)
{
  int ret;
  usb_dev_handle *hdev = g_devices[dev_id].hdev;
  int epin = g_devices[dev_id].epin;
  unsigned char buffer[512];
  unsigned char word[11];

  memset(buffer, 0, sizeof(buffer));
  memset(word, 0, sizeof(word));

  while(1)
  {
    memset(buffer, 0, sizeof(buffer));
    ret = usb_bulk_read(hdev, epin, (char*)buffer, sizeof(buffer), 10000);
    if(ret < 0)
    {
      printf("bulk_read returned %d (%s)\n", ret, usb_strerror());
      return -1;
    }
//    printf("read %d bytes: \n", ret);
    unsigned char *bufptr = (unsigned char *)buffer;
    int nb_words = ret/11; // incomplete words are resent
    while(nb_words--)
    {
      memcpy(word, bufptr, 11);
      bufptr+=11;
      process_frame(dev_id, word);
    }
  }
  return 0;
}

static int handle_device(int dev_id)
{
  int r, i;
  struct usb_device *dev = g_devices[dev_id].usb_dev;
  usb_dev_handle *hdev = g_devices[dev_id].hdev;

  usb_detach_kernel_driver_np(hdev, 0);
  
  if( 0 != (r = usb_set_configuration(hdev, dev->config[0].bConfigurationValue)) )
  {
    printf("usb_set_configuration returns %d (%s)\n", r, usb_strerror());
    return -1;
  }

  if((r = usb_claim_interface(hdev, 0)) < 0)
  {
    printf("Interface cannot be claimed: %d\n", r);
    return r;
  }

  int nep = dev->config->interface->altsetting->bNumEndpoints;
  for(i=0; i<nep; i++)
  {
    int ep = dev->config->interface->altsetting->endpoint[i].bEndpointAddress;
    if(ep&(1<<7))
      g_devices[dev_id].epin = ep;
    else
      g_devices[dev_id].epout = ep;
  }

  // Set baudrate
  int baudrate = 250000;
  r = usb_control_msg(hdev, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_ENDPOINT_OUT, 
                      CP210X_IFC_ENABLE, UART_ENABLE, 0, NULL, 0, 500);
  r = usb_control_msg(hdev, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_ENDPOINT_OUT, 
                      CP210X_SET_BAUDRATE, 0, 0, (char *)&baudrate, sizeof(baudrate), 500);
  r = usb_control_msg(hdev, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_ENDPOINT_OUT, 
                      CP210X_IFC_ENABLE, UART_DISABLE, 0, NULL, 0, 500);
  
// read/write main loop
  io_loop(dev_id);
 
  usb_release_interface(hdev, 0);
  return 0;
}


int main(int argc, char **argv)
{
  int dev_cnt;
  if(argc>1 && (strcmp(argv[1], "-d")==0) )
    demonize(argv[0]);

  while(1)
  {
    db_open();
    dev_cnt = 0;
    receive_history = true;
    frame_id = 0;
    printf("Wait for cm160 device to be connected\n");
    while((dev_cnt = scan_usb()) == 0)
      sleep(2);
    printf("Found %d compatible device%s\n", dev_cnt, dev_cnt>1?"s":"");

    // Only 1 device supported
    if(!(g_devices[0].hdev = usb_open(g_devices[0].usb_dev)))
    {
      fprintf(stderr, "failed to open device\n");
      db_close();
      break;
    }
    handle_device(0); 
    usb_close(g_devices[0].hdev);
    db_close();
  }

  return 0;
}

竜山

Re: 月(month)の値がゼロになります。

#2

投稿記事 by 竜山 » 1年前

自己解決

ルビーでプログラムを書いている人の参考にしました。

int volt = 230; // TODO: use the value from energy_param table (supply_voltage)
rec->addr = 0; // TODO: don't use an harcoded addr value for the device...
rec->year = frame[1]+2000;
rec->month = frame[2]; ⇒ rec->month = frame[2] & 0b1111 ;## XXX 0b11110000 unknown bit 
rec->day = frame[3];

。。。。。。。。。。

アバター
あたっしゅ
記事: 664
登録日時: 13年前
住所: 東京23区
連絡を取る:

Re: 月(month)の値がゼロになります。

#3

投稿記事 by あたっしゅ » 1年前

東上☆海美☆「

Linux で USB メモリにアクセスするプログラムですか ?

https://wiki.suikawiki.org/n/FAT%E3%81% ... #gsc.tab=0
> MSDOSのファイル管理システムであるFAT、およびその拡張形式であるWindows95/98/MeのVFATは更新日時を 年(7bit)月(4bit)日(5bit)時(5bit)分(6bit)秒(5bit)の合計32bitで持っています。秒が0-59のはずなのに5bitしかないのは実は偶数にまるめて記録しているためです。年は7bitで0-127年が記録できますが、FATの起点は1980年なので127は2107年に相当します。つまりFAT/VFATは2107年の年末まで正常に動作します。

で、月は 4bit( 0b1111 ) という事でしたか ?
VTuber:
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。

中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。

返信

“C言語何でも質問掲示板” へ戻る